mirror of
https://github.com/qwibitai/nanoclaw.git
synced 2026-06-04 10:14:47 +08:00
1512e3f19e
`setup/service.ts` decides between a real systemd user unit and the nohup fallback by running `systemctl --user daemon-reload` and watching for the call to succeed. In contexts that bypass pam_systemd — `su -`, `pct enter`, headless containers — `XDG_RUNTIME_DIR` and `DBUS_SESSION_BUS_ADDRESS` are not exported, the probe fails with `Failed to connect to bus: No medium found`, and we install nohup despite the user manager being healthy on disk. Before the probe, check whether linger is enabled for the current user and `/run/user/<uid>` exists; if so, re-derive the env vars from disk and let them propagate to subsequent `systemctl --user` calls via `process.env` (execSync inherits by default). If the probe still fails after that, the existing nohup fallback runs unchanged — and the warning log now records *which* precondition failed so the cause is visible without grepping setup.log. The pure decision function lives in `setup/systemd-user-env.ts` so it can be tested without execSync. New regression test in `setup/systemd-user-env.test.ts` covers the #2482 repro plus the already_set / no_linger / no_runtime_dir / no_user / no_uid branches. Closes #1981 Closes #2482
39 lines
1.0 KiB
TypeScript
39 lines
1.0 KiB
TypeScript
export interface SystemdUserEnvDeps {
|
|
uid: number | undefined;
|
|
user: string | undefined;
|
|
env: { XDG_RUNTIME_DIR?: string };
|
|
exists: (path: string) => boolean;
|
|
}
|
|
|
|
export type SystemdUserEnvReason =
|
|
| 'already_set'
|
|
| 'no_user'
|
|
| 'no_uid'
|
|
| 'no_linger'
|
|
| 'no_runtime_dir'
|
|
| 'populated';
|
|
|
|
export interface SystemdUserEnvResult {
|
|
reason: SystemdUserEnvReason;
|
|
XDG_RUNTIME_DIR?: string;
|
|
DBUS_SESSION_BUS_ADDRESS?: string;
|
|
}
|
|
|
|
export function computeUserSystemdEnv(
|
|
deps: SystemdUserEnvDeps,
|
|
): SystemdUserEnvResult {
|
|
if (deps.env.XDG_RUNTIME_DIR) return { reason: 'already_set' };
|
|
if (!deps.user) return { reason: 'no_user' };
|
|
if (typeof deps.uid !== 'number') return { reason: 'no_uid' };
|
|
if (!deps.exists(`/var/lib/systemd/linger/${deps.user}`)) {
|
|
return { reason: 'no_linger' };
|
|
}
|
|
const runtimeDir = `/run/user/${deps.uid}`;
|
|
if (!deps.exists(runtimeDir)) return { reason: 'no_runtime_dir' };
|
|
return {
|
|
reason: 'populated',
|
|
XDG_RUNTIME_DIR: runtimeDir,
|
|
DBUS_SESSION_BUS_ADDRESS: `unix:path=${runtimeDir}/bus`,
|
|
};
|
|
}
|