From 5fc5fd62a075635ac7119dd07a3fb90a5501c83a Mon Sep 17 00:00:00 2001 From: AnErrupTion Date: Mon, 6 Jul 2026 19:44:10 +0200 Subject: [PATCH] Remove shutdown_cmd & restart_cmd + sleep & hibernate Signed-off-by: AnErrupTion --- build.zig | 4 -- ly-core/src/interop.zig | 35 +++++++++++ res/config.ini | 18 ------ src/config/Config.zig | 6 -- src/config/migrator.zig | 48 ++++++++++++++- src/main.zig | 130 ++-------------------------------------- 6 files changed, 85 insertions(+), 156 deletions(-) diff --git a/build.zig b/build.zig index a3a5f22..b4f216c 100644 --- a/build.zig +++ b/build.zig @@ -136,10 +136,6 @@ pub fn Installer(install_config: bool) type { try patch_map.put("$PREFIX_DIRECTORY", prefix_directory); try patch_map.put("$EXECUTABLE_NAME", executable_name); - // The "-a" argument doesn't exist on FreeBSD, so we use "-p" - // instead to shutdown the system. - try patch_map.put("$PLATFORM_SHUTDOWN_ARG", if (init_system == .freebsd) "-p" else "-a"); - try install_ly(allocator, io, patch_map, install_config); try install_service(allocator, io, patch_map); } diff --git a/ly-core/src/interop.zig b/ly-core/src/interop.zig index 736d8ca..873db15 100644 --- a/ly-core/src/interop.zig +++ b/ly-core/src/interop.zig @@ -179,6 +179,20 @@ fn PlatformStruct() type { return uid_range; } + pub fn shutdownSystemImpl() !void { + std.posix.system.sync(); + if (isError(std.os.linux.reboot(.MAGIC1, .MAGIC2, .POWER_OFF, null))) { + return error.CouldntShutdown; + } + } + + pub fn rebootSystemImpl() !void { + std.posix.system.sync(); + if (isError(std.os.linux.reboot(.MAGIC1, .MAGIC2, .RESTART, null))) { + return error.CouldntShutdown; + } + } + fn parseValue(comptime T: type, name: []const u8, buffer: []const u8) !T { var iterator = std.mem.splitAny(u8, buffer, " \t"); var maybe_value: ?T = null; @@ -209,6 +223,7 @@ fn PlatformStruct() type { .freebsd => struct { pub const kbio = @import("kbio"); pub const consio = @import("consio"); + pub const reboot = @import("reboot"); pub const LedState = c_int; pub const get_led_state = kbio.KDGETLED; @@ -243,6 +258,18 @@ fn PlatformStruct() type { .uid_max = FREEBSD_UID_MAX, }; } + + pub fn shutdownSystemImpl() !void { + if (isError(reboot.reboot(reboot.RB_POWEROFF))) { + return error.CouldntShutdown; + } + } + + pub fn rebootSystemImpl() !void { + if (isError(reboot.reboot(reboot.RB_AUTOBOOT))) { + return error.CouldntReboot; + } + } }, else => @compileError("Unsupported target: " ++ builtin.os.tag), }; @@ -396,3 +423,11 @@ pub fn closePasswordDatabase() void { pub fn getUserIdRange(allocator: std.mem.Allocator, io: std.Io, file_path: []const u8) !UidRange { return platform_struct.getUserIdRange(allocator, io, file_path); } + +pub fn shutdownSystem() !void { + try platform_struct.shutdownSystemImpl(); +} + +pub fn rebootSystem() !void { + try platform_struct.rebootSystemImpl(); +} diff --git a/res/config.ini b/res/config.ini index ae63e6f..0ae21b7 100644 --- a/res/config.ini +++ b/res/config.ini @@ -281,12 +281,6 @@ gameoflife_frame_delay = 6 # 0.7+ -> Dense, chaotic patterns gameoflife_initial_density = 0.4 -# Command executed when pressing hibernate key (can be null) -hibernate_cmd = null - -# Specifies the key combination used for hibernate -hibernate_key = F4 - # Remove main box borders hide_borders = false @@ -344,9 +338,6 @@ numlock = false # If null, ly doesn't set a path path = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -# Command executed when pressing restart_key -restart_cmd = /sbin/shutdown -r now - # Specifies the key combination used for restart restart_key = F2 @@ -375,18 +366,9 @@ shell = true # Specifies the key combination used for showing the password show_password_key = F7 -# Command executed when pressing shutdown_key -shutdown_cmd = /sbin/shutdown $PLATFORM_SHUTDOWN_ARG now - # Specifies the key combination used for shutdown shutdown_key = F1 -# Command executed when pressing sleep key (can be null) -sleep_cmd = null - -# Specifies the key combination used for sleep -sleep_key = F3 - # Command executed when starting Ly (before the TTY is taken control of) # See file at path below for an example of changing the default TTY colors start_cmd = $CONFIG_DIRECTORY/ly/startup.sh diff --git a/src/config/Config.zig b/src/config/Config.zig index 8ad10ae..f78c169 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -64,8 +64,6 @@ gameoflife_fg: u32 = 0x0000FF00, gameoflife_entropy_interval: usize = 10, gameoflife_frame_delay: usize = 6, gameoflife_initial_density: f32 = 0.4, -hibernate_cmd: ?[]const u8 = null, -hibernate_key: []const u8 = "F4", hide_borders: bool = false, inactivity_cmd: ?[]const u8 = null, inactivity_delay: u16 = 0, @@ -81,7 +79,6 @@ margin_box_h: u8 = 2, margin_box_v: u8 = 1, numlock: bool = false, path: ?[]const u8 = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", -restart_cmd: []const u8 = "/sbin/shutdown -r now", restart_key: []const u8 = "F2", save: bool = true, service_name: [:0]const u8 = "ly", @@ -89,10 +86,7 @@ session_log: ?[]const u8 = "ly-session.log", setup_cmd: []const u8 = build_options.config_directory ++ "/ly/setup.sh", shell: bool = true, show_password_key: []const u8 = "F7", -shutdown_cmd: []const u8 = "/sbin/shutdown -a now", shutdown_key: []const u8 = "F1", -sleep_cmd: ?[]const u8 = null, -sleep_key: []const u8 = "F3", start_cmd: ?[]const u8 = null, text_in_center: bool = false, type_username: bool = false, diff --git a/src/config/migrator.zig b/src/config/migrator.zig index a2659ef..758f44f 100644 --- a/src/config/migrator.zig +++ b/src/config/migrator.zig @@ -14,6 +14,7 @@ const IniParser = ly_core.IniParser; const ini = ly_core.ini; const Config = @import("Config.zig"); +const Lang = @import("Lang.zig"); const OldSave = @import("OldSave.zig"); const SavedUsers = @import("SavedUsers.zig"); const custom = @import("custom.zig"); @@ -45,6 +46,8 @@ const removed_properties = [_][]const u8{ "wayland_cmd", "console_dev", "load", + "shutdown_cmd", + "restart_cmd", // Migrating these isn't worth the effort so just say we removed them "hide_key_hints", "hide_keyboard_locks", @@ -56,6 +59,10 @@ pub var auto_eight_colors: bool = true; pub var maybe_animate: ?bool = null; pub var maybe_save_file: ?[]const u8 = null; +pub var maybe_sleep_key: ?[]const u8 = null; +pub var maybe_sleep_cmd: ?[]const u8 = null; +pub var maybe_hibernate_key: ?[]const u8 = null; +pub var maybe_hibernate_cmd: ?[]const u8 = null; pub fn configFieldHandler(_: std.mem.Allocator, field: ini.IniField) ?ini.IniField { if (std.mem.eql(u8, field.key, "animate")) { @@ -129,7 +136,6 @@ pub fn configFieldHandler(_: std.mem.Allocator, field: ini.IniField) ?ini.IniFie if (std.mem.eql(u8, field.key, "save_file")) { // The option doesn't exist anymore, but we save its value for migration later on maybe_save_file = temporary_allocator.dupe(u8, field.value) catch return null; - return null; } @@ -168,6 +174,26 @@ pub fn configFieldHandler(_: std.mem.Allocator, field: ini.IniField) ?ini.IniFie return mapped_field; } + if (std.mem.eql(u8, field.key, "sleep_key")) { + maybe_sleep_key = temporary_allocator.dupe(u8, field.value) catch return null; + return null; + } + + if (std.mem.eql(u8, field.key, "sleep_cmd")) { + maybe_sleep_cmd = temporary_allocator.dupe(u8, field.value) catch return null; + return null; + } + + if (std.mem.eql(u8, field.key, "hibernate_key")) { + maybe_hibernate_key = temporary_allocator.dupe(u8, field.value) catch return null; + return null; + } + + if (std.mem.eql(u8, field.key, "hibernate_cmd")) { + maybe_hibernate_cmd = temporary_allocator.dupe(u8, field.value) catch return null; + return null; + } + // TODO: Dearest Melpert, // I pray this message finds you well, as daylight dwindles and the witching hour // approaches, I find it more and more imperative as time continues that I place @@ -228,7 +254,7 @@ pub fn configFieldHandler(_: std.mem.Allocator, field: ini.IniField) ?ini.IniFie // This is the stuff we only handle after reading the config. // For example, the "animate" field could come after "animation" -pub fn lateConfigFieldHandler(config: *Config) void { +pub fn lateConfigFieldHandler(config: *Config, lang: Lang) void { if (maybe_animate) |animate| { if (!animate) config.*.animation = .none; } @@ -257,6 +283,24 @@ pub fn lateConfigFieldHandler(config: *Config) void { if (!set_color_properties[7]) config.error_fg = Styling.BOLD | Color.ECOL_RED; if (!set_color_properties[8]) config.fg = Color.ECOL_WHITE; } + + if (maybe_sleep_key) |key| { + if (maybe_sleep_cmd) |cmd| { + custom.binds.put(temporary_allocator, key, .{ + .name = temporary_allocator.dupe(u8, lang.sleep) catch "", + .cmd = cmd, + }) catch {}; + } + } + + if (maybe_hibernate_key) |key| { + if (maybe_hibernate_cmd) |cmd| { + custom.binds.put(temporary_allocator, key, .{ + .name = temporary_allocator.dupe(u8, lang.hibernate) catch "", + .cmd = cmd, + }) catch {}; + } + } } pub fn tryMigrateIniSaveFile(allocator: std.mem.Allocator, io: std.Io, path: []const u8, saved_users: *SavedUsers, usernames: [][]const u8) !?IniParser(OldSave) { diff --git a/src/main.zig b/src/main.zig index 83aa008..8ae1227 100644 --- a/src/main.zig +++ b/src/main.zig @@ -88,8 +88,6 @@ const UiState = struct { labels_max_length: usize, shutdown_label: Label, restart_label: Label, - sleep_label: Label, - hibernate_label: Label, toggle_password_label: Label, brightness_down_label: Label, brightness_up_label: Label, @@ -141,9 +139,6 @@ var shutdown = false; var restart = false; pub fn main(init: std.process.Init) !void { - var shutdown_cmd: []const u8 = undefined; - var restart_cmd: []const u8 = undefined; - var commands_allocated = false; var state: UiState = undefined; state.io = init.io; @@ -152,21 +147,12 @@ pub fn main(init: std.process.Init) !void { var stderr_writer = std.Io.File.stderr().writer(state.io, &stderr_buffer); var stderr = &stderr_writer.interface; + // If we can't shutdown or restart due to an error, we print it to standard error. If that fails, just bail out defer { - // If we can't shutdown or restart due to an error, we print it to standard error. If that fails, just bail out if (shutdown) { - const shutdown_error = std.process.replace(state.io, .{ .argv = &[_][]const u8{ "/bin/sh", "-c", shutdown_cmd } }); - std.log.err("couldn't shutdown: {s}", .{@errorName(shutdown_error)}); + interop.shutdownSystem() catch std.log.err("whoopsie doodle, couldn't shutdown system!", .{}); } else if (restart) { - const restart_error = std.process.replace(state.io, .{ .argv = &[_][]const u8{ "/bin/sh", "-c", restart_cmd } }); - std.log.err("couldn't restart: {s}", .{@errorName(restart_error)}); - } else { - // The user has quit Ly using Ctrl+C - if (commands_allocated) { - // Necessary if we error out before allocating - temporary_allocator.free(shutdown_cmd); - temporary_allocator.free(restart_cmd); - } + interop.rebootSystem() catch std.log.err("whoopsie doodle, couldn't restart system!", .{}); } } @@ -293,7 +279,7 @@ pub fn main(init: std.process.Init) !void { } if (config_parser.maybe_load_error == null) { - migrator.lateConfigFieldHandler(&state.config); + migrator.lateConfigFieldHandler(&state.config, state.lang); } var maybe_uid_range_error: ?anyerror = null; @@ -374,12 +360,6 @@ pub fn main(init: std.process.Init) !void { try state.log_file.info(state.io, "tui", "using {s} vt", .{if (state.use_kmscon_vt) "kmscon" else "default"}); - // These strings only end up getting freed if the user quits Ly using Ctrl+C, which is fine since in the other cases - // we end up shutting down or restarting the system - shutdown_cmd = try temporary_allocator.dupe(u8, state.config.shutdown_cmd); - restart_cmd = try temporary_allocator.dupe(u8, state.config.restart_cmd); - commands_allocated = true; - if (state.config.start_cmd) |start_cmd| handle_start_cmd: { var process = std.process.spawn(state.io, .{ .argv = &[_][]const u8{ "/bin/sh", "-c", start_cmd }, @@ -469,26 +449,6 @@ pub fn main(init: std.process.Init) !void { ); defer state.restart_label.deinit(); - state.sleep_label = Label.init( - "", - null, - state.buffer.fg, - state.buffer.bg, - null, - null, - ); - defer state.sleep_label.deinit(); - - state.hibernate_label = Label.init( - "", - null, - state.buffer.fg, - state.buffer.bg, - null, - null, - ); - defer state.hibernate_label.deinit(); - state.toggle_password_label = Label.init( "", null, @@ -535,20 +495,6 @@ pub fn main(init: std.process.Init) !void { "{s} {s}", .{ state.config.show_password_key, state.lang.toggle_password }, ); - if (state.config.sleep_cmd != null) { - try state.sleep_label.setTextAlloc( - state.allocator, - "{s} {s}", - .{ state.config.sleep_key, state.lang.sleep }, - ); - } - if (state.config.hibernate_cmd != null) { - try state.hibernate_label.setTextAlloc( - state.allocator, - "{s} {s}", - .{ state.config.hibernate_key, state.lang.hibernate }, - ); - } if (state.config.brightness_down_key) |key| { try state.brightness_down_label.setTextAlloc( state.allocator, @@ -1296,12 +1242,6 @@ pub fn main(init: std.process.Init) !void { if (!state.hide_key_hints) { try layer2.append(state.allocator, state.shutdown_label.widget()); try layer2.append(state.allocator, state.restart_label.widget()); - if (state.config.sleep_cmd != null) { - try layer2.append(state.allocator, state.sleep_label.widget()); - } - if (state.config.hibernate_cmd != null) { - try layer2.append(state.allocator, state.hibernate_label.widget()); - } try layer2.append(state.allocator, state.toggle_password_label.widget()); if (state.config.brightness_down_key != null) { try layer2.append(state.allocator, state.brightness_down_label.widget()); @@ -1372,8 +1312,6 @@ pub fn main(init: std.process.Init) !void { try state.buffer.registerGlobalKeybind(state.io, state.config.shutdown_key, &shutdownCmd, &state); try state.buffer.registerGlobalKeybind(state.io, state.config.restart_key, &restartCmd, &state); try state.buffer.registerGlobalKeybind(state.io, state.config.show_password_key, &togglePasswordMask, &state); - if (state.config.sleep_cmd != null) try state.buffer.registerGlobalKeybind(state.io, state.config.sleep_key, &sleepCmd, &state); - if (state.config.hibernate_cmd != null) try state.buffer.registerGlobalKeybind(state.io, state.config.hibernate_key, &hibernateCmd, &state); if (state.config.brightness_down_key) |key| try state.buffer.registerGlobalKeybind(state.io, key, &decreaseBrightnessCmd, &state); if (state.config.brightness_up_key) |key| try state.buffer.registerGlobalKeybind(state.io, key, &increaseBrightnessCmd, &state); @@ -1787,62 +1725,6 @@ fn restartCmd(ptr: *anyopaque) !bool { return false; } -fn sleepCmd(ptr: *anyopaque) !bool { - var state: *UiState = @ptrCast(@alignCast(ptr)); - - if (state.config.sleep_cmd) |sleep_cmd| { - var process = std.process.spawn(state.io, .{ - .argv = &[_][]const u8{ "/bin/sh", "-c", sleep_cmd }, - .stdout = .ignore, - .stderr = .ignore, - }) catch return false; - - const process_result = process.wait(state.io) catch return false; - if (process_result.exited != 0) { - try state.info_line.addMessage( - state.lang.err_sleep, - state.config.error_bg, - state.config.error_fg, - ); - try state.log_file.err( - state.io, - "sys", - "failed to execute sleep command: exit code {d}", - .{process_result.exited}, - ); - } - } - return false; -} - -fn hibernateCmd(ptr: *anyopaque) !bool { - var state: *UiState = @ptrCast(@alignCast(ptr)); - - if (state.config.hibernate_cmd) |hibernate_cmd| { - var process = std.process.spawn(state.io, .{ - .argv = &[_][]const u8{ "/bin/sh", "-c", hibernate_cmd }, - .stdout = .ignore, - .stderr = .ignore, - }) catch return false; - - const process_result = process.wait(state.io) catch return false; - if (process_result.exited != 0) { - try state.info_line.addMessage( - state.lang.err_hibernate, - state.config.error_bg, - state.config.error_fg, - ); - try state.log_file.err( - state.io, - "sys", - "failed to execute hibernate command: exit code {d}", - .{process_result.exited}, - ); - } - } - return false; -} - fn decreaseBrightnessCmd(ptr: *anyopaque) !bool { var state: *UiState = @ptrCast(@alignCast(ptr)); @@ -2114,8 +1996,6 @@ fn positionSingleWidget(state: *UiState, item: []const u8, current_x: *usize, cu const labels = [_]?*Label{ &state.shutdown_label, &state.restart_label, - if (state.config.sleep_cmd != null) &state.sleep_label else null, - if (state.config.hibernate_cmd != null) &state.hibernate_label else null, &state.toggle_password_label, if (state.config.brightness_down_key != null) &state.brightness_down_label else null, if (state.config.brightness_up_key != null) &state.brightness_up_label else null, @@ -2347,8 +2227,6 @@ fn positionWidgets(ptr: *anyopaque) !void { // Reset all potential corner widgets to offscreen state.shutdown_label.positionXY(offscreen); state.restart_label.positionXY(offscreen); - state.sleep_label.positionXY(offscreen); - state.hibernate_label.positionXY(offscreen); state.toggle_password_label.positionXY(offscreen); state.brightness_down_label.positionXY(offscreen); state.brightness_up_label.positionXY(offscreen);