From 83a1d783b1b826daba4583a6d181e3725fa1ff55 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 27 Feb 2023 11:44:18 -0800 Subject: [PATCH] termio: implement kill command for flatpak --- src/os/flatpak.zig | 47 ++++++++++++++++++++++++++++++++++++++++++++- src/termio/Exec.zig | 14 +++++++++++--- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/os/flatpak.zig b/src/os/flatpak.zig index f41ea22de..bcb8486f5 100644 --- a/src/os/flatpak.zig +++ b/src/os/flatpak.zig @@ -1,5 +1,6 @@ const std = @import("std"); const assert = std.debug.assert; +const Allocator = std.mem.Allocator; const builtin = @import("builtin"); const log = std.log.scoped(.flatpak); @@ -25,7 +26,6 @@ pub fn isFlatpak() bool { /// /// Requires GIO, GLib to be available and linked. pub const FlatpakHostCommand = struct { - const Allocator = std.mem.Allocator; const fd_t = std.os.fd_t; const EnvMap = std.process.EnvMap; const c = @cImport({ @@ -134,6 +134,51 @@ pub const FlatpakHostCommand = struct { } } + /// Send a signal to the started command. This does nothing if the + /// command is not in the started state. + pub fn signal(self: *FlatpakHostCommand, sig: u8, pg: bool) !void { + const pid = pid: { + self.state_mutex.lock(); + defer self.state_mutex.unlock(); + switch (self.state) { + .started => |v| break :pid v.pid, + else => return, + } + }; + + // Get our bus connection. + var g_err: [*c]c.GError = null; + const bus = c.g_bus_get_sync(c.G_BUS_TYPE_SESSION, null, &g_err) orelse { + log.warn("signal error getting bus: {s}", .{g_err.*.message}); + return Error.FlatpakSetupFail; + }; + defer c.g_object_unref(bus); + + const reply = c.g_dbus_connection_call_sync( + bus, + "org.freedesktop.Flatpak", + "/org/freedesktop/Flatpak/Development", + "org.freedesktop.Flatpak.Development", + "HostCommandSignal", + c.g_variant_new( + "(uub)", + pid, + sig, + @intCast(c_int, @boolToInt(pg)), + ), + c.G_VARIANT_TYPE("()"), + c.G_DBUS_CALL_FLAGS_NONE, + c.G_MAXINT, + null, + &g_err, + ); + if (g_err != null) { + log.warn("signal send error: {s}", .{g_err.*.message}); + return; + } + defer c.g_variant_unref(reply); + } + fn threadMain(self: *FlatpakHostCommand, alloc: Allocator) void { // Create a new thread-local context so that all our sources go // to this context and we can run our loop correctly. diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index 39cb47e4e..3f5246ab7 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -490,6 +490,11 @@ const Subprocess = struct { pid, }); + // Once started, we can close the pty child side. We do this after + // wait right now but that is fine too. This lets us read the + // parent and detect EOF. + _ = std.os.close(pty.slave); + return pty.master; } @@ -601,9 +606,10 @@ const Subprocess = struct { } } + /// Kill the underlying process started via Flatpak host command. + /// This sends a signal via the Flatpak API. fn killCommandFlatpak(command: *FlatpakHostCommand) !void { - // TODO - _ = command; + try command.signal(c.SIGHUP, true); } }; @@ -628,7 +634,9 @@ const ReadThread = struct { switch (err) { // This means our pty is closed. We're probably // gracefully shutting down. - error.NotOpenForReading => log.info("io reader exiting", .{}), + error.NotOpenForReading, + error.InputOutput, + => log.info("io reader exiting", .{}), else => { log.err("io reader error err={}", .{err});