From 51f74e37b80d86046a68e0d9929ca6bf104e321f Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 24 Nov 2025 13:01:15 +0100 Subject: [PATCH] feat: add restart with sudo capability --- src/main.zig | 43 ++++++++++++++++++++++++++++++++----------- src/soft_root.zig | 4 ++++ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/main.zig b/src/main.zig index 7e30ebe..7a73f41 100644 --- a/src/main.zig +++ b/src/main.zig @@ -385,12 +385,13 @@ pub fn main() anyerror!void { ctx.run(); - if (want_restart) restart(); + if (want_restart) if (want_restart_with_sudo) restart_with_sudo() else restart(); exit(final_exit_status); } var final_exit_status: u8 = 0; var want_restart: bool = false; +var want_restart_with_sudo: bool = false; pub fn print_exit_status(_: void, msg: []const u8) void { if (std.mem.eql(u8, msg, "normal")) { @@ -406,6 +407,10 @@ pub fn print_exit_status(_: void, msg: []const u8) void { } } +pub fn set_restart_with_sudo() void { + want_restart_with_sudo = true; +} + fn count_args() usize { var args = std.process.args(); _ = args.next(); @@ -1107,25 +1112,41 @@ pub fn get_theme_file_name(theme_name: []const u8) ![]const u8 { return try std.fmt.bufPrint(&local.file_buffer, "{s}{c}{s}.json", .{ dir, sep, theme_name }); } +fn resolve_executable(executable: [:0]const u8) [:0]const u8 { + return for (executable) |char| { + if (std.fs.path.isSep(char)) break executable; + } else bin_path.find_binary_in_path(std.heap.c_allocator, executable) catch executable orelse executable; +} + fn restart() noreturn { - var executable: [:0]const u8 = std.mem.span(std.os.argv[0]); - var is_basename = true; - for (executable) |char| if (std.fs.path.isSep(char)) { - is_basename = false; - }; - if (is_basename) { - const a = std.heap.c_allocator; - executable = bin_path.find_binary_in_path(a, executable) catch executable orelse executable; - } + const executable = resolve_executable(std.mem.span(std.os.argv[0])); const argv = [_]?[*:0]const u8{ executable, "--restore-session", null, }; const ret = std.c.execve(executable, @ptrCast(&argv), @ptrCast(std.os.environ)); + restart_failed(ret); +} + +fn restart_with_sudo() noreturn { + const sudo_executable = resolve_executable("sudo"); + const flow_executable = resolve_executable(std.mem.span(std.os.argv[0])); + const argv = [_]?[*:0]const u8{ + sudo_executable, + "--preserve-env", + flow_executable, + "--restore-session", + null, + }; + const ret = std.c.execve(sudo_executable, @ptrCast(&argv), @ptrCast(std.os.environ)); + restart_failed(ret); +} + +fn restart_failed(ret: c_int) noreturn { var stderr_buffer: [1024]u8 = undefined; var stderr_writer = std.fs.File.stderr().writer(&stderr_buffer); - stderr_writer.interface.print("\nrestart failed: {d}", .{ret}) catch {}; + stderr_writer.interface.print("\nrestart failed: {s}", .{@tagName(std.posix.errno(ret))}) catch {}; stderr_writer.interface.flush() catch {}; exit(234); } diff --git a/src/soft_root.zig b/src/soft_root.zig index b19caae..a792e73 100644 --- a/src/soft_root.zig +++ b/src/soft_root.zig @@ -33,6 +33,7 @@ pub const root = struct { pub const exit = if (@hasDecl(hard_root, "exit")) hard_root.exit else dummy.exit; pub const print_exit_status = if (@hasDecl(hard_root, "print_exit_status")) hard_root.print_exit_status else dummy.print_exit_status; + pub const set_restart_with_sudo = if (@hasDecl(hard_root, "set_restart_with_sudo")) hard_root.set_restart_with_sudo else dummy.set_restart_with_sudo; pub const is_directory = if (@hasDecl(hard_root, "is_directory")) hard_root.is_directory else dummy.is_directory; pub const is_file = if (@hasDecl(hard_root, "is_file")) hard_root.is_file else dummy.is_file; @@ -118,6 +119,9 @@ const dummy = struct { pub fn print_exit_status(_: void, _: []const u8) void { @panic("dummy print_exit_status call"); } + pub fn set_restart_with_sudo() void { + @panic("dummy set_restart_with_sudo call"); + } pub fn is_directory(_: []const u8) bool { @panic("dummy is_directory call");