Make setting numlock work on BSD + less homebrew interop

Signed-off-by: AnErrupTion <anerruption@disroot.org>
This commit is contained in:
AnErrupTion
2024-07-30 18:38:21 +02:00
parent b1bf89a4cf
commit 3fedb59fdb
4 changed files with 67 additions and 65 deletions

View File

@@ -65,16 +65,16 @@ pub fn authenticate(config: Config, current_environment: Desktop.Environment, lo
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
defer status = interop.pam.pam_close_session(handle, 0); defer status = interop.pam.pam_close_session(handle, 0);
var pwd: *interop.passwd = undefined; var pwd: *std.c.passwd = undefined;
{ {
defer interop.endpwent(); defer interop.endpwent();
// Get password structure from username // 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 // Set user shell if it hasn't already been set
if (pwd.pw_shell[0] == 0) { if (pwd.pw_shell == null) {
interop.setusershell(); interop.setusershell();
pwd.pw_shell = interop.getusershell(); pwd.pw_shell = interop.getusershell();
interop.endusershell(); 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 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 // Wait for the session to stop
_ = std.posix.waitpid(child_pid, 0); _ = std.posix.waitpid(child_pid, 0);
removeUtmpEntry(&entry); 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; if (shared_err.readError()) |err| return err;
} }
fn startSession( fn startSession(
config: Config, config: Config,
pwd: *interop.passwd, pwd: *std.c.passwd,
handle: ?*interop.pam.pam_handle, handle: ?*interop.pam.pam_handle,
current_environment: Desktop.Environment, current_environment: Desktop.Environment,
) !void { ) !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 (status != 0) return error.GroupInitializationFailed;
if (builtin.os.tag == .freebsd) { if (builtin.os.tag == .freebsd) {
@@ -150,22 +150,22 @@ fn startSession(
for (env_list) |env_var| _ = interop.putenv(env_var.?); for (env_list) |env_var| _ = interop.putenv(env_var.?);
// Execute what the user requested // 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) { switch (current_environment.display_server) {
.wayland => try executeWaylandCmd(pwd.pw_shell, config.wayland_cmd, current_environment.cmd), .wayland => try executeWaylandCmd(pwd.pw_shell.?, config.wayland_cmd, current_environment.cmd),
.shell => try executeShellCmd(pwd.pw_shell), .shell => try executeShellCmd(pwd.pw_shell.?),
.xinitrc, .x11 => if (build_options.enable_x11_support) { .xinitrc, .x11 => if (build_options.enable_x11_support) {
var vt_buf: [5]u8 = undefined; var vt_buf: [5]u8 = undefined;
const vt = try std.fmt.bufPrint(&vt_buf, "vt{d}", .{config.tty}); 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("HOME", pwd.pw_dir, 1);
_ = interop.setenv("PWD", pwd.pw_dir, 1); _ = interop.setenv("PWD", pwd.pw_dir, 1);
_ = interop.setenv("SHELL", pwd.pw_shell, 1); _ = interop.setenv("SHELL", pwd.pw_shell, 1);

View File

@@ -14,7 +14,7 @@ border_fg: u8 = 8,
box_title: ?[]const u8 = null, box_title: ?[]const u8 = null,
clear_password: bool = false, clear_password: bool = false,
clock: ?[:0]const u8 = null, clock: ?[:0]const u8 = null,
console_dev: [:0]const u8 = "/dev/console", console_dev: []const u8 = "/dev/console",
default_input: Input = .login, default_input: Input = .login,
error_bg: u16 = 0, error_bg: u16 = 0,
error_fg: u16 = 258, error_fg: u16 = 258,

View File

@@ -21,11 +21,25 @@ pub const unistd = @cImport({
@cInclude("unistd.h"); @cInclude("unistd.h");
}); });
// Exists for FreeBSD only // FreeBSD-specific headers
pub const logincap = @cImport({ pub const logincap = @cImport({
@cInclude("login_cap.h"); @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_size = usize;
pub const c_uid = u32; pub const c_uid = u32;
pub const c_gid = u32; pub const c_gid = u32;
@@ -41,37 +55,12 @@ pub const tm = extern struct {
tm_yday: c_int, tm_yday: c_int,
tm_isdst: 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 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 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 putenv(name: [*:0]u8) c_int;
pub extern "c" fn getuid() c_uid; 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 endpwent() void;
pub extern "c" fn setusershell() void; pub extern "c" fn setusershell() void;
pub extern "c" fn getusershell() [*:0]u8; 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]; 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, numlock: bool,
capslock: bool, capslock: bool,
} { } {
const fd = std.c.open(console_dev, .{ .ACCMODE = .RDONLY }); const fd = try std.posix.open(console_dev, .{ .ACCMODE = .RDONLY }, 0);
if (fd < 0) return error.CannotOpenConsoleDev; defer std.posix.close(fd);
defer _ = std.c.close(fd);
var numlock = false; var numlock = false;
var capslock = false; var capslock = false;
if (builtin.os.tag.isBSD()) { if (builtin.os.tag.isBSD()) {
var led: c_int = undefined; var led: c_int = undefined;
_ = std.c.ioctl(fd, KDGETLED, &led); _ = std.c.ioctl(fd, kbio.KDGETLED, &led);
numlock = (led & LED_NUM) != 0; numlock = (led & kbio.LED_NUM) != 0;
capslock = (led & LED_CAP) != 0; capslock = (led & kbio.LED_CAP) != 0;
} else { } else {
var led: c_char = undefined; var led: c_char = undefined;
_ = std.c.ioctl(fd, KDGKBLED, &led); _ = std.c.ioctl(fd, kd.KDGKBLED, &led);
numlock = (led & K_NUMLOCK) != 0; numlock = (led & kd.K_NUMLOCK) != 0;
capslock = (led & K_CAPSLOCK) != 0; capslock = (led & kd.K_CAPSLOCK) != 0;
} }
return .{ return .{
@@ -118,12 +114,25 @@ pub fn getLockState(console_dev: [:0]const u8) !struct {
} }
pub fn setNumlock(val: bool) !void { pub fn setNumlock(val: bool) !void {
var led: c_char = undefined; if (builtin.os.tag.isBSD()) {
_ = std.c.ioctl(0, KDGKBLED, &led); 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) { 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; if (status != 0) return error.FailedToSetNumlock;
} }
} }

View File

@@ -307,16 +307,9 @@ pub fn main() !void {
var auth_fails: u64 = 0; var auth_fails: u64 = 0;
// Switch to selected TTY if possible // Switch to selected TTY if possible
open_console_dev: { interop.switchTty(config.console_dev, config.tty) catch {
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);
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);
}
while (run) { while (run) {
// If there's no input or there's an animation, a resolution change needs to be checked // If there's no input or there's an animation, a resolution change needs to be checked