From 28888bbf9f43ec3626bdc1064bd706cdd06f9b1d Mon Sep 17 00:00:00 2001 From: "Jeffrey C. Ollie" Date: Mon, 29 Jul 2024 10:47:10 -0500 Subject: [PATCH] make systemd launch detection smarter --- src/os/systemd.zig | 51 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/src/os/systemd.zig b/src/os/systemd.zig index e4b9c479c..22aec57f7 100644 --- a/src/os/systemd.zig +++ b/src/os/systemd.zig @@ -1,6 +1,12 @@ const std = @import("std"); const builtin = @import("builtin"); +const log = std.log.scoped(.systemd); + +const c = @cImport({ + @cInclude("unistd.h"); +}); + /// Returns true if the program was launched as a systemd service. /// /// On Linux, this returns true if the program was launched as a systemd @@ -9,12 +15,45 @@ const builtin = @import("builtin"); /// For other platforms and app runtimes, this returns false. pub fn launchedBySystemd() bool { return switch (builtin.os.tag) { - // On Linux, systemd sets the `INVOCATION_ID` (v232+) and the - // `JOURNAL_STREAM` (v231+) enviroment variables. If these environment - // variables are present (no matter the value) we were launched by - // systemd. This can be fooled if Ghostty is launched from another - // terminal that does not clean up these environment variables. - .linux => std.posix.getenv("INVOCATION_ID") != null and std.posix.getenv("JOURNAL_STREAM") != null, + .linux => linux: { + // On Linux, systemd sets the `INVOCATION_ID` (v232+) and the + // `JOURNAL_STREAM` (v231+) enviroment variables. If these + // environment variables are not present we were not launched by + // systemd. + + if (std.posix.getenv("INVOCATION_ID") == null) break :linux false; + if (std.posix.getenv("JOURNAL_STREAM") == null) break :linux false; + + // If `INVOCATION_ID` and `JOURNAL_STREAM` are present, check to make sure + // that our parent process is actually `systemd`, not some other terminal + // emulator that doesn't clean up those environment variables. + + const ppid = c.getppid(); + + // If the parent PID is 1 we'll assume that it's `systemd` as other init systems + // are unlikely. + + if (ppid == 1) break :linux true; + + // If the parent PID is not 1 we need to check to see if we were launched by + // a user systemd daemon. Do that by checking the `/proc//exe` symlink + // to see if it ends with `/systemd`. + + var path_buf: [std.fs.max_path_bytes]u8 = undefined; + const path = std.fmt.bufPrint(&path_buf, "/proc/{d}/exe", .{ppid}) catch { + log.err("unable to format path to exe {d}", .{ppid}); + break :linux false; + }; + var link_buf: [std.fs.max_path_bytes]u8 = undefined; + const link = std.fs.readLinkAbsolute(path, &link_buf) catch { + log.err("unable to read link '{s}'", .{path}); + break :linux false; + }; + + if (std.mem.endsWith(u8, link, "/systemd")) break :linux true; + + break :linux false; + }, // No other system supports systemd so always return false. else => false,