mirror of https://github.com/fairyglade/ly.git
242 lines
7.5 KiB
Zig
242 lines
7.5 KiB
Zig
const std = @import("std");
|
|
const builtin = @import("builtin");
|
|
|
|
pub const termbox = @import("termbox2");
|
|
|
|
pub const pam = @cImport({
|
|
@cInclude("security/pam_appl.h");
|
|
});
|
|
|
|
pub const utmp = @cImport({
|
|
@cInclude("utmpx.h");
|
|
});
|
|
|
|
// Exists for X11 support only
|
|
pub const xcb = @cImport({
|
|
@cInclude("xcb/xcb.h");
|
|
});
|
|
|
|
const pwd = @cImport({
|
|
@cInclude("pwd.h");
|
|
// We include a FreeBSD-specific header here since login_cap.h references
|
|
// the passwd struct directly, so we can't import it separately
|
|
if (builtin.os.tag == .freebsd) @cInclude("login_cap.h");
|
|
});
|
|
|
|
const stdlib = @cImport({
|
|
@cInclude("stdlib.h");
|
|
});
|
|
|
|
const unistd = @cImport({
|
|
@cInclude("unistd.h");
|
|
});
|
|
|
|
const grp = @cImport({
|
|
@cInclude("grp.h");
|
|
});
|
|
|
|
const system_time = @cImport({
|
|
@cInclude("sys/time.h");
|
|
});
|
|
|
|
const time = @cImport({
|
|
@cInclude("time.h");
|
|
});
|
|
|
|
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,
|
|
passwd_struct: [*c]pwd.passwd,
|
|
};
|
|
|
|
// Contains the platform-specific code
|
|
fn PlatformStruct() type {
|
|
return switch (builtin.os.tag) {
|
|
.linux => struct {
|
|
pub const kd = @cImport({
|
|
@cInclude("sys/kd.h");
|
|
});
|
|
|
|
pub const vt = @cImport({
|
|
@cInclude("sys/vt.h");
|
|
});
|
|
|
|
pub const LedState = c_char;
|
|
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 {
|
|
return builtin.os.tag == .linux or builtin.os.tag == .freebsd;
|
|
}
|
|
|
|
pub fn timeAsString(buf: [:0]u8, format: [:0]const u8) []u8 {
|
|
const timer = std.time.timestamp();
|
|
const tm_info = time.localtime(&timer);
|
|
const len = time.strftime(buf, buf.len, format, tm_info);
|
|
|
|
return buf[0..len];
|
|
}
|
|
|
|
pub fn getTimeOfDay() !TimeOfDay {
|
|
var tv: system_time.timeval = undefined;
|
|
const status = system_time.gettimeofday(&tv, null);
|
|
|
|
if (status != 0) return error.FailedToGetTimeOfDay;
|
|
|
|
return .{
|
|
.seconds = @intCast(tv.tv_sec),
|
|
.microseconds = @intCast(tv.tv_usec),
|
|
};
|
|
}
|
|
|
|
pub fn switchTty(tty: u8) !void {
|
|
var status = std.c.ioctl(std.posix.STDIN_FILENO, platform_struct.vt_activate, tty);
|
|
if (status != 0) return error.FailedToActivateTty;
|
|
|
|
status = std.c.ioctl(std.posix.STDIN_FILENO, platform_struct.vt_waitactive, tty);
|
|
if (status != 0) return error.FailedToWaitForActiveTty;
|
|
}
|
|
|
|
pub fn getLockState() !struct {
|
|
numlock: bool,
|
|
capslock: bool,
|
|
} {
|
|
var led: platform_struct.LedState = undefined;
|
|
const status = std.c.ioctl(std.posix.STDIN_FILENO, platform_struct.get_led_state, &led);
|
|
if (status != 0) return error.FailedToGetLockState;
|
|
|
|
return .{
|
|
.numlock = (led & platform_struct.numlock_led) != 0,
|
|
.capslock = (led & platform_struct.capslock_led) != 0,
|
|
};
|
|
}
|
|
|
|
pub fn setNumlock(val: bool) !void {
|
|
var led: platform_struct.LedState = undefined;
|
|
var status = std.c.ioctl(std.posix.STDIN_FILENO, platform_struct.get_led_state, &led);
|
|
if (status != 0) return error.FailedToGetNumlock;
|
|
|
|
const numlock = (led & platform_struct.numlock_led) != 0;
|
|
if (numlock != val) {
|
|
status = std.c.ioctl(std.posix.STDIN_FILENO, platform_struct.set_led_state, led ^ platform_struct.numlock_led);
|
|
if (status != 0) return error.FailedToSetNumlock;
|
|
}
|
|
}
|
|
|
|
pub fn setUserContext(allocator: std.mem.Allocator, entry: UsernameEntry) !void {
|
|
const username_z = try allocator.dupeZ(u8, entry.username.?);
|
|
defer allocator.free(username_z);
|
|
|
|
return platform_struct.setUserContextImpl(username_z.ptr, entry);
|
|
}
|
|
|
|
pub fn setUserShell(entry: *UsernameEntry) void {
|
|
unistd.setusershell();
|
|
|
|
const shell = unistd.getusershell();
|
|
entry.shell = shell[0..std.mem.len(shell)];
|
|
|
|
unistd.endusershell();
|
|
}
|
|
|
|
pub fn setEnvironmentVariable(allocator: std.mem.Allocator, name: []const u8, value: []const u8, replace: bool) !void {
|
|
const name_z = try allocator.dupeZ(u8, name);
|
|
defer allocator.free(name_z);
|
|
|
|
const value_z = try allocator.dupeZ(u8, value);
|
|
defer allocator.free(value_z);
|
|
|
|
const status = stdlib.setenv(name_z.ptr, value_z.ptr, @intFromBool(replace));
|
|
if (status != 0) return error.SetEnvironmentVariableFailed;
|
|
}
|
|
|
|
pub fn putEnvironmentVariable(name_and_value: [*c]u8) !void {
|
|
const status = stdlib.putenv(name_and_value);
|
|
if (status != 0) return error.PutEnvironmentVariableFailed;
|
|
}
|
|
|
|
pub fn getNextUsernameEntry() ?UsernameEntry {
|
|
const entry = pwd.getpwent();
|
|
if (entry == null) return null;
|
|
|
|
return .{
|
|
.username = if (entry.*.pw_name) |name| name[0..std.mem.len(name)] else null,
|
|
.uid = @intCast(entry.*.pw_uid),
|
|
.gid = @intCast(entry.*.pw_gid),
|
|
.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,
|
|
.passwd_struct = entry,
|
|
};
|
|
}
|
|
|
|
pub fn getUsernameEntry(username: [:0]const u8) ?UsernameEntry {
|
|
const entry = pwd.getpwnam(username);
|
|
if (entry == null) return null;
|
|
|
|
return .{
|
|
.username = if (entry.*.pw_name) |name| name[0..std.mem.len(name)] else null,
|
|
.uid = @intCast(entry.*.pw_uid),
|
|
.gid = @intCast(entry.*.pw_gid),
|
|
.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,
|
|
.passwd_struct = entry,
|
|
};
|
|
}
|
|
|
|
pub fn closePasswordDatabase() void {
|
|
pwd.endpwent();
|
|
}
|