ReviewOS

also looking at this

pantry-pm/pantry

fix(services): launch postgres from a script, and find libs where they are

#258
Merged glennmichael123 wants to merge fix/243-systemd-user-unit into main
3 files +189 -29
packages/zig/src/services/platform.zigmodified+38-0
Changes to packages/zig/src/services/platform.zig
@@ -3,6 +3,7 @@ const builtin = ;
33const definitions = ;
44const lib = ;
55const io_helper = lib.io_helper;
6const style = ;
67
78/// Whether services are managed in the per-user systemd instance (`systemctl
89/// --user`, units under `~/.config/systemd/user`, `WantedBy=default.target`) or
@@ -375,9 +376,46 @@ pub const ServiceController = struct {
375376 } catch return;
376377 }
377378
379 /// Is there a systemd user manager for this user to talk to?
380 ///
381 /// `systemctl --user` needs a per-user bus, which exists only while the
382 /// user has a login session or lingering is enabled. Without it every
383 /// call fails with "Failed to connect to bus: No medium found", which
384 /// names neither the cause nor the fix (#243). Checked by looking for the
385 /// runtime dir the bus socket lives in, so no process is spawned.
386 fn userBusAvailable() bool {
387 if (io_helper.getenv("XDG_RUNTIME_DIR")) |dir| {
388 var buf: [std.fs.max_path_bytes]u8 = undefined;
389 const socket = std.fmt.bufPrint(&buf, "{s}/systemd/private", .{dir}) catch return true;
390 io_helper.accessAbsolute(socket, .{}) catch return false;
391 return true;
392 }
393 return false;
394 }
395
396 /// What to do about a missing user bus, in the operator's own terms.
397 pub fn userBusHint(allocator: std.mem.Allocator) ![]const u8 {
398 const user = io_helper.getenv("USER") orelse io_helper.getenv("LOGNAME") orelse "$USER";
399 return std.fmt.allocPrint(
400 allocator,
401 "No systemd user manager is running for this session, so `systemctl --user` cannot be reached.\n" ++
402 " Enable it for this user: loginctl enable-linger {s}\n" ++
403 " Or run the service in system scope instead (as root).",
404 .{user},
405 );
406 }
407
378408 fn systemdStart(self: *ServiceController, service_name: []const u8, project_id: ?[]const u8) !void {
379409 const service_unit = try self.getSystemdUnit(service_name, project_id);
380410 defer self.allocator.free(service_unit);
411 // Reported before the attempt: the raw failure is a bus error that
412 // says nothing about lingering, and it is the same for every verb.
413 if (self.scope == .user and !userBusAvailable()) {
414 const hint = userBusHint(self.allocator) catch return error.ServiceStartFailed;
415 defer self.allocator.free(hint);
416 style.printWarn("{s}\n", .{hint});
417 return error.ServiceStartFailed;
418 }
381419 if (!try self.runSystemctl("start", service_unit)) return error.ServiceStartFailed;
382420 }
383421