From 3fedb59fdb9d9c12eb75a7a2703c9915eabdcaab Mon Sep 17 00:00:00 2001 From: AnErrupTion Date: Tue, 30 Jul 2024 18:38:21 +0200 Subject: [PATCH] Make setting numlock work on BSD + less homebrew interop Signed-off-by: AnErrupTion --- src/auth.zig | 26 ++++++------- src/config/Config.zig | 2 +- src/interop.zig | 91 ++++++++++++++++++++++++------------------- src/main.zig | 13 ++----- 4 files changed, 67 insertions(+), 65 deletions(-) diff --git a/src/auth.zig b/src/auth.zig index 33b16f1..9f295af 100644 --- a/src/auth.zig +++ b/src/auth.zig @@ -65,16 +65,16 @@ pub fn authenticate(config: Config, current_environment: Desktop.Environment, lo if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); defer status = interop.pam.pam_close_session(handle, 0); - var pwd: *interop.passwd = undefined; + var pwd: *std.c.passwd = undefined; { defer interop.endpwent(); // Get password structure from username - pwd = interop.getpwnam(login.ptr) orelse return error.GetPasswordNameFailed; + pwd = std.c.getpwnam(login.ptr) orelse return error.GetPasswordNameFailed; } // Set user shell if it hasn't already been set - if (pwd.pw_shell[0] == 0) { + if (pwd.pw_shell == null) { interop.setusershell(); pwd.pw_shell = interop.getusershell(); interop.endusershell(); @@ -109,25 +109,25 @@ pub fn authenticate(config: Config, current_environment: Desktop.Environment, lo }; try std.posix.sigaction(std.posix.SIG.TERM, &act, null); - try addUtmpEntry(&entry, pwd.pw_name, child_pid); + try addUtmpEntry(&entry, pwd.pw_name.?, child_pid); } // Wait for the session to stop _ = std.posix.waitpid(child_pid, 0); removeUtmpEntry(&entry); - try resetTerminal(pwd.pw_shell, config.term_reset_cmd); + try resetTerminal(pwd.pw_shell.?, config.term_reset_cmd); if (shared_err.readError()) |err| return err; } fn startSession( config: Config, - pwd: *interop.passwd, + pwd: *std.c.passwd, handle: ?*interop.pam.pam_handle, current_environment: Desktop.Environment, ) !void { - const status = interop.initgroups(pwd.pw_name, pwd.pw_gid); + const status = interop.initgroups(pwd.pw_name.?, pwd.pw_gid); if (status != 0) return error.GroupInitializationFailed; if (builtin.os.tag == .freebsd) { @@ -150,22 +150,22 @@ fn startSession( for (env_list) |env_var| _ = interop.putenv(env_var.?); // Execute what the user requested - std.posix.chdirZ(pwd.pw_dir) catch return error.ChangeDirectoryFailed; + std.posix.chdirZ(pwd.pw_dir.?) catch return error.ChangeDirectoryFailed; - try resetTerminal(pwd.pw_shell, config.term_reset_cmd); + try resetTerminal(pwd.pw_shell.?, config.term_reset_cmd); switch (current_environment.display_server) { - .wayland => try executeWaylandCmd(pwd.pw_shell, config.wayland_cmd, current_environment.cmd), - .shell => try executeShellCmd(pwd.pw_shell), + .wayland => try executeWaylandCmd(pwd.pw_shell.?, config.wayland_cmd, current_environment.cmd), + .shell => try executeShellCmd(pwd.pw_shell.?), .xinitrc, .x11 => if (build_options.enable_x11_support) { var vt_buf: [5]u8 = undefined; const vt = try std.fmt.bufPrint(&vt_buf, "vt{d}", .{config.tty}); - try executeX11Cmd(pwd.pw_shell, pwd.pw_dir, config, current_environment.cmd, vt); + try executeX11Cmd(pwd.pw_shell.?, pwd.pw_dir.?, config, current_environment.cmd, vt); }, } } -fn initEnv(pwd: *interop.passwd, path_env: ?[:0]const u8) !void { +fn initEnv(pwd: *std.c.passwd, path_env: ?[:0]const u8) !void { _ = interop.setenv("HOME", pwd.pw_dir, 1); _ = interop.setenv("PWD", pwd.pw_dir, 1); _ = interop.setenv("SHELL", pwd.pw_shell, 1); diff --git a/src/config/Config.zig b/src/config/Config.zig index 0274ce5..11006d7 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -14,7 +14,7 @@ border_fg: u8 = 8, box_title: ?[]const u8 = null, clear_password: bool = false, clock: ?[:0]const u8 = null, -console_dev: [:0]const u8 = "/dev/console", +console_dev: []const u8 = "/dev/console", default_input: Input = .login, error_bg: u16 = 0, error_fg: u16 = 258, diff --git a/src/interop.zig b/src/interop.zig index 23bb83e..beba61c 100644 --- a/src/interop.zig +++ b/src/interop.zig @@ -21,11 +21,25 @@ pub const unistd = @cImport({ @cInclude("unistd.h"); }); -// Exists for FreeBSD only +// FreeBSD-specific headers pub const logincap = @cImport({ @cInclude("login_cap.h"); }); +// BSD-specific headers +pub const kbio = @cImport({ + @cInclude("sys/kbio.h"); +}); + +// Linux-specific headers +pub const kd = @cImport({ + @cInclude("sys/kd.h"); +}); + +pub const vt = @cImport({ + @cInclude("sys/vt.h"); +}); + pub const c_size = usize; pub const c_uid = u32; pub const c_gid = u32; @@ -41,37 +55,12 @@ pub const tm = extern struct { tm_yday: c_int, tm_isdst: c_int, }; -pub const passwd = extern struct { - pw_name: [*:0]u8, - pw_passwd: [*:0]u8, - - pw_uid: c_uid, - pw_gid: c_gid, - pw_gecos: [*:0]u8, - pw_dir: [*:0]u8, - pw_shell: [*:0]u8, -}; - -pub const VT_ACTIVATE: c_int = 0x5606; -pub const VT_WAITACTIVE: c_int = 0x5607; - -pub const KDGETLED: c_int = 0x4B31; -pub const KDSETLED: c_int = 0x4B32; -pub const KDGKBLED: c_int = 0x4B64; -pub const KDSKBLED: c_int = 0x4B65; - -pub const LED_NUM: c_int = 0x02; -pub const LED_CAP: c_int = 0x04; - -pub const K_NUMLOCK: c_int = 0x02; -pub const K_CAPSLOCK: c_int = 0x04; pub extern "c" fn localtime(timer: *const c_time) *tm; pub extern "c" fn strftime(str: [*:0]u8, maxsize: c_size, format: [*:0]const u8, timeptr: *const tm) c_size; -pub extern "c" fn setenv(name: [*:0]const u8, value: [*:0]const u8, overwrite: c_int) c_int; +pub extern "c" fn setenv(name: [*:0]const u8, value: ?[*:0]const u8, overwrite: c_int) c_int; pub extern "c" fn putenv(name: [*:0]u8) c_int; pub extern "c" fn getuid() c_uid; -pub extern "c" fn getpwnam(name: [*:0]const u8) ?*passwd; pub extern "c" fn endpwent() void; pub extern "c" fn setusershell() void; pub extern "c" fn getusershell() [*:0]u8; @@ -88,27 +77,34 @@ pub fn timeAsString(buf: [:0]u8, format: [:0]const u8) ![]u8 { return buf[0..len]; } -pub fn getLockState(console_dev: [:0]const u8) !struct { +pub fn switchTty(console_dev: []const u8, tty: u8) !void { + const fd = try std.posix.open(console_dev, .{ .ACCMODE = .WRONLY }, 0); + defer std.posix.close(fd); + + _ = std.c.ioctl(fd, vt.VT_ACTIVATE, tty); + _ = std.c.ioctl(fd, vt.VT_WAITACTIVE, tty); +} + +pub fn getLockState(console_dev: []const u8) !struct { numlock: bool, capslock: bool, } { - const fd = std.c.open(console_dev, .{ .ACCMODE = .RDONLY }); - if (fd < 0) return error.CannotOpenConsoleDev; - defer _ = std.c.close(fd); + const fd = try std.posix.open(console_dev, .{ .ACCMODE = .RDONLY }, 0); + defer std.posix.close(fd); var numlock = false; var capslock = false; if (builtin.os.tag.isBSD()) { var led: c_int = undefined; - _ = std.c.ioctl(fd, KDGETLED, &led); - numlock = (led & LED_NUM) != 0; - capslock = (led & LED_CAP) != 0; + _ = std.c.ioctl(fd, kbio.KDGETLED, &led); + numlock = (led & kbio.LED_NUM) != 0; + capslock = (led & kbio.LED_CAP) != 0; } else { var led: c_char = undefined; - _ = std.c.ioctl(fd, KDGKBLED, &led); - numlock = (led & K_NUMLOCK) != 0; - capslock = (led & K_CAPSLOCK) != 0; + _ = std.c.ioctl(fd, kd.KDGKBLED, &led); + numlock = (led & kd.K_NUMLOCK) != 0; + capslock = (led & kd.K_CAPSLOCK) != 0; } return .{ @@ -118,12 +114,25 @@ pub fn getLockState(console_dev: [:0]const u8) !struct { } pub fn setNumlock(val: bool) !void { - var led: c_char = undefined; - _ = std.c.ioctl(0, KDGKBLED, &led); + if (builtin.os.tag.isBSD()) { + var led: c_int = undefined; + _ = std.c.ioctl(0, kbio.KDGETLED, &led); - const numlock = (led & K_NUMLOCK) != 0; + const numlock = (led & kbio.LED_NUM) != 0; + if (numlock != val) { + const status = std.c.ioctl(std.posix.STDIN_FILENO, kbio.KDSETLED, led ^ kbio.LED_NUM); + if (status != 0) return error.FailedToSetNumlock; + } + + return; + } + + var led: c_char = undefined; + _ = std.c.ioctl(0, kd.KDGKBLED, &led); + + const numlock = (led & kd.K_NUMLOCK) != 0; if (numlock != val) { - const status = std.c.ioctl(std.posix.STDIN_FILENO, KDSKBLED, led ^ K_NUMLOCK); + const status = std.c.ioctl(std.posix.STDIN_FILENO, kd.KDSKBLED, led ^ kd.K_NUMLOCK); if (status != 0) return error.FailedToSetNumlock; } } diff --git a/src/main.zig b/src/main.zig index 160087f..60d4f3c 100644 --- a/src/main.zig +++ b/src/main.zig @@ -307,16 +307,9 @@ pub fn main() !void { var auth_fails: u64 = 0; // Switch to selected TTY if possible - open_console_dev: { - const fd = std.posix.open(config.console_dev, .{ .ACCMODE = .WRONLY }, 0) catch { - try info_line.addMessage(lang.err_console_dev, config.error_bg, config.error_fg); - break :open_console_dev; - }; - defer std.posix.close(fd); - - _ = std.c.ioctl(fd, interop.VT_ACTIVATE, config.tty); - _ = std.c.ioctl(fd, interop.VT_WAITACTIVE, config.tty); - } + interop.switchTty(config.console_dev, config.tty) catch { + try info_line.addMessage(lang.err_console_dev, config.error_bg, config.error_fg); + }; while (run) { // If there's no input or there's an animation, a resolution change needs to be checked