Separate platform code from C interop code

Also, don't use isBSD() because we'll only support FreeBSD for
now. Other BSDs may not necessarily support Unicode characters
or the same ioctl constants as we do (or even ioctl at all).

Signed-off-by: AnErrupTion <anerruption@disroot.org>
This commit is contained in:
AnErrupTion 2025-08-30 00:27:04 +02:00
parent 230874abd1
commit f9553655a3
No known key found for this signature in database
1 changed files with 85 additions and 58 deletions

View File

@ -1,19 +1,5 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const Allocator = std.mem.Allocator;
pub const TimeOfDay = struct {
seconds: i64,
microseconds: i64,
};
pub const UsernameEntry = struct {
username: ?[]const u8,
uid: std.posix.uid_t,
gid: std.posix.gid_t,
home: ?[]const u8,
shell: ?[]const u8,
};
pub const termbox = @import("termbox2"); pub const termbox = @import("termbox2");
@ -57,29 +43,83 @@ const time = @cImport({
@cInclude("time.h"); @cInclude("time.h");
}); });
// BSD-specific headers pub const TimeOfDay = struct {
const kbio = @cImport({ seconds: i64,
@cInclude("sys/kbio.h"); microseconds: i64,
}); };
// Linux-specific headers pub const UsernameEntry = struct {
const kd = @cImport({ username: ?[]const u8,
@cInclude("sys/kd.h"); uid: std.posix.uid_t,
}); gid: std.posix.gid_t,
home: ?[]const u8,
shell: ?[]const u8,
passwd_struct: [*c]pwd.passwd,
};
const vt = @cImport({ // Contains the platform-specific code
@cInclude("sys/vt.h"); fn PlatformStruct() type {
}); return switch (builtin.os.tag) {
.linux => struct {
pub const kd = @cImport({
@cInclude("sys/kd.h");
});
// Used for getting & setting the lock state pub const vt = @cImport({
const LedState = if (builtin.os.tag.isBSD()) c_int else c_char; @cInclude("sys/vt.h");
const get_led_state = if (builtin.os.tag.isBSD()) kbio.KDGETLED else kd.KDGKBLED; });
const set_led_state = if (builtin.os.tag.isBSD()) kbio.KDSETLED else kd.KDSKBLED;
const numlock_led = if (builtin.os.tag.isBSD()) kbio.LED_NUM else kd.K_NUMLOCK; pub const LedState = c_char;
const capslock_led = if (builtin.os.tag.isBSD()) kbio.LED_CAP else kd.K_CAPSLOCK; pub const get_led_state = kd.KDGKBLED;
pub const set_led_state = kd.KDSKBLED;
pub const numlock_led = kd.K_NUMLOCK;
pub const capslock_led = kd.K_CAPSLOCK;
pub const vt_activate = vt.VT_ACTIVATE;
pub const vt_waitactive = vt.VT_WAITACTIVE;
pub fn setUserContextImpl(username: [*:0]const u8, entry: UsernameEntry) !void {
const status = grp.initgroups(username, @intCast(entry.gid));
if (status != 0) return error.GroupInitializationFailed;
std.posix.setgid(@intCast(entry.gid)) catch return error.SetUserGidFailed;
std.posix.setuid(@intCast(entry.uid)) catch return error.SetUserUidFailed;
}
},
.freebsd => struct {
pub const kbio = @cImport({
@cInclude("sys/kbio.h");
});
pub const consio = @cImport({
@cInclude("sys/consio.h");
});
pub const LedState = c_int;
pub const get_led_state = kbio.KDGETLED;
pub const set_led_state = kbio.KDSETLED;
pub const numlock_led = kbio.LED_NUM;
pub const capslock_led = kbio.LED_CAP;
pub const vt_activate = consio.VT_ACTIVATE;
pub const vt_waitactive = consio.VT_WAITACTIVE;
pub fn setUserContextImpl(username: [*:0]const u8, entry: UsernameEntry) !void {
// FreeBSD has initgroups() in unistd
const status = unistd.initgroups(username, @intCast(entry.gid));
if (status != 0) return error.GroupInitializationFailed;
// FreeBSD sets the GID and UID with setusercontext()
const result = pwd.setusercontext(null, entry.passwd_struct, @intCast(entry.uid), pwd.LOGIN_SETALL);
if (result != 0) return error.SetUserUidFailed;
}
},
else => @compileError("Unsupported target: " ++ builtin.os.tag),
};
}
const platform_struct = PlatformStruct();
pub fn supportsUnicode() bool { pub fn supportsUnicode() bool {
return builtin.os.tag == .linux or builtin.os.tag.isBSD(); return builtin.os.tag == .linux or builtin.os.tag == .freebsd;
} }
pub fn timeAsString(buf: [:0]u8, format: [:0]const u8) []u8 { pub fn timeAsString(buf: [:0]u8, format: [:0]const u8) []u8 {
@ -103,10 +143,10 @@ pub fn getTimeOfDay() !TimeOfDay {
} }
pub fn switchTty(tty: u8) !void { pub fn switchTty(tty: u8) !void {
var status = std.c.ioctl(std.posix.STDIN_FILENO, vt.VT_ACTIVATE, tty); var status = std.c.ioctl(std.posix.STDIN_FILENO, platform_struct.vt_activate, tty);
if (status != 0) return error.FailedToActivateTty; if (status != 0) return error.FailedToActivateTty;
status = std.c.ioctl(std.posix.STDIN_FILENO, vt.VT_WAITACTIVE, tty); status = std.c.ioctl(std.posix.STDIN_FILENO, platform_struct.vt_waitactive, tty);
if (status != 0) return error.FailedToWaitForActiveTty; if (status != 0) return error.FailedToWaitForActiveTty;
} }
@ -114,24 +154,24 @@ pub fn getLockState() !struct {
numlock: bool, numlock: bool,
capslock: bool, capslock: bool,
} { } {
var led: LedState = undefined; var led: platform_struct.LedState = undefined;
const status = std.c.ioctl(std.posix.STDIN_FILENO, get_led_state, &led); const status = std.c.ioctl(std.posix.STDIN_FILENO, platform_struct.get_led_state, &led);
if (status != 0) return error.FailedToGetLockState; if (status != 0) return error.FailedToGetLockState;
return .{ return .{
.numlock = (led & numlock_led) != 0, .numlock = (led & platform_struct.numlock_led) != 0,
.capslock = (led & capslock_led) != 0, .capslock = (led & platform_struct.capslock_led) != 0,
}; };
} }
pub fn setNumlock(val: bool) !void { pub fn setNumlock(val: bool) !void {
var led: LedState = undefined; var led: platform_struct.LedState = undefined;
var status = std.c.ioctl(std.posix.STDIN_FILENO, get_led_state, &led); var status = std.c.ioctl(std.posix.STDIN_FILENO, platform_struct.get_led_state, &led);
if (status != 0) return error.FailedToGetNumlock; if (status != 0) return error.FailedToGetNumlock;
const numlock = (led & numlock_led) != 0; const numlock = (led & platform_struct.numlock_led) != 0;
if (numlock != val) { if (numlock != val) {
status = std.c.ioctl(std.posix.STDIN_FILENO, set_led_state, led ^ numlock_led); status = std.c.ioctl(std.posix.STDIN_FILENO, platform_struct.set_led_state, led ^ platform_struct.numlock_led);
if (status != 0) return error.FailedToSetNumlock; if (status != 0) return error.FailedToSetNumlock;
} }
} }
@ -140,22 +180,7 @@ pub fn setUserContext(allocator: std.mem.Allocator, entry: UsernameEntry) !void
const username_z = try allocator.dupeZ(u8, entry.username.?); const username_z = try allocator.dupeZ(u8, entry.username.?);
defer allocator.free(username_z); defer allocator.free(username_z);
if (builtin.os.tag == .freebsd) { return platform_struct.setUserContextImpl(username_z.ptr, entry);
// FreeBSD has initgroups() in unistd
const status = unistd.initgroups(username_z.ptr, @intCast(entry.gid));
if (status != 0) return error.GroupInitializationFailed;
// FreeBSD sets the GID and UID with setusercontext()
// TODO
const result = pwd.setusercontext(null, entry, @intCast(entry.uid), pwd.LOGIN_SETALL);
if (result != 0) return error.SetUserUidFailed;
} else {
const status = grp.initgroups(username_z.ptr, @intCast(entry.gid));
if (status != 0) return error.GroupInitializationFailed;
std.posix.setgid(@intCast(entry.gid)) catch return error.SetUserGidFailed;
std.posix.setuid(@intCast(entry.uid)) catch return error.SetUserUidFailed;
}
} }
pub fn setUserShell(entry: *UsernameEntry) void { pub fn setUserShell(entry: *UsernameEntry) void {
@ -193,6 +218,7 @@ pub fn getNextUsernameEntry() ?UsernameEntry {
.gid = @intCast(entry.*.pw_gid), .gid = @intCast(entry.*.pw_gid),
.home = if (entry.*.pw_dir) |dir| dir[0..std.mem.len(dir)] else null, .home = if (entry.*.pw_dir) |dir| dir[0..std.mem.len(dir)] else null,
.shell = if (entry.*.pw_shell) |shell| shell[0..std.mem.len(shell)] else null, .shell = if (entry.*.pw_shell) |shell| shell[0..std.mem.len(shell)] else null,
.passwd_struct = entry,
}; };
} }
@ -206,6 +232,7 @@ pub fn getUsernameEntry(username: [:0]const u8) ?UsernameEntry {
.gid = @intCast(entry.*.pw_gid), .gid = @intCast(entry.*.pw_gid),
.home = if (entry.*.pw_dir) |dir| dir[0..std.mem.len(dir)] else null, .home = if (entry.*.pw_dir) |dir| dir[0..std.mem.len(dir)] else null,
.shell = if (entry.*.pw_shell) |shell| shell[0..std.mem.len(shell)] else null, .shell = if (entry.*.pw_shell) |shell| shell[0..std.mem.len(shell)] else null,
.passwd_struct = entry,
}; };
} }