Update to Zig 0.16.0 (#962)

Signed-off-by: AnErrupTion <anerruption@disroot.org>

## What are the changes about?

Ports the code base to Zig 0.16.0.

## What existing issue does this resolve?

N/A

## Pre-requisites

- [x] I have tested & confirmed the changes work locally
- [x] I have run `zig fmt` throughout my changes

Reviewed-on: https://codeberg.org/fairyglade/ly/pulls/962
This commit is contained in:
AnErrupTion
2026-04-25 17:37:34 +02:00
committed by AnErrupTion
parent eec83179b9
commit 5edf5251f6
26 changed files with 751 additions and 587 deletions

View File

@@ -27,16 +27,16 @@ pub const AuthOptions = struct {
};
var xorg_pid: std.posix.pid_t = 0;
pub fn xorgSignalHandler(i: c_int) callconv(.c) void {
if (xorg_pid > 0) _ = std.c.kill(xorg_pid, i);
pub fn xorgSignalHandler(sig: std.posix.SIG) callconv(.c) void {
if (xorg_pid > 0) _ = std.c.kill(xorg_pid, sig);
}
var child_pid: std.posix.pid_t = 0;
pub fn sessionSignalHandler(i: c_int) callconv(.c) void {
if (child_pid > 0) _ = std.c.kill(child_pid, i);
pub fn sessionSignalHandler(sig: std.posix.SIG) callconv(.c) void {
if (child_pid > 0) _ = std.c.kill(child_pid, sig);
}
pub fn authenticate(allocator: std.mem.Allocator, log_file: *LogFile, options: AuthOptions, current_environment: Environment, login: []const u8, password: []const u8) !void {
pub fn authenticate(allocator: std.mem.Allocator, io: std.Io, log_file: *LogFile, options: AuthOptions, current_environment: Environment, login: []const u8, password: []const u8) !void {
var tty_buffer: [3]u8 = undefined;
const tty_str = try std.fmt.bufPrint(&tty_buffer, "{d}", .{options.tty});
@@ -44,11 +44,11 @@ pub fn authenticate(allocator: std.mem.Allocator, log_file: *LogFile, options: A
const pam_tty_str = try std.fmt.bufPrintZ(&pam_tty_buffer, "tty{d}", .{options.tty});
// Set the XDG environment variables
try log_file.info("auth/env", "setting xdg environment variables", .{});
try log_file.info(io, "auth/env", "setting xdg environment variables", .{});
try setXdgEnv(allocator, tty_str, current_environment);
// Open the PAM session
try log_file.info("auth/pam", "encoding credentials", .{});
try log_file.info(io, "auth/pam", "encoding credentials", .{});
const login_z = try allocator.dupeZ(u8, login);
defer allocator.free(login_z);
@@ -63,36 +63,36 @@ pub fn authenticate(allocator: std.mem.Allocator, log_file: *LogFile, options: A
};
var handle: ?*interop.pam.pam_handle = undefined;
try log_file.info("auth/pam", "starting session", .{});
try log_file.info(io, "auth/pam", "starting session", .{});
var status = interop.pam.pam_start(options.service_name, null, &conv, &handle);
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
defer _ = interop.pam.pam_end(handle, status);
// Set PAM_TTY as the current TTY. This is required in case it isn't being set by another PAM module
try log_file.info("auth/pam", "setting tty", .{});
try log_file.info(io, "auth/pam", "setting tty", .{});
status = interop.pam.pam_set_item(handle, interop.pam.PAM_TTY, pam_tty_str.ptr);
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
// Do the PAM routine
try log_file.info("auth/pam", "authenticating", .{});
try log_file.info(io, "auth/pam", "authenticating", .{});
status = interop.pam.pam_authenticate(handle, 0);
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
try log_file.info("auth/pam", "validating account", .{});
try log_file.info(io, "auth/pam", "validating account", .{});
status = interop.pam.pam_acct_mgmt(handle, 0);
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
try log_file.info("auth/pam", "setting credentials", .{});
try log_file.info(io, "auth/pam", "setting credentials", .{});
status = interop.pam.pam_setcred(handle, interop.pam.PAM_ESTABLISH_CRED);
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
defer status = interop.pam.pam_setcred(handle, interop.pam.PAM_DELETE_CRED);
try log_file.info("auth/pam", "opening session", .{});
try log_file.info(io, "auth/pam", "opening session", .{});
status = interop.pam.pam_open_session(handle, 0);
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
defer status = interop.pam.pam_close_session(handle, 0);
try log_file.info("auth/passwd", "getting struct", .{});
try log_file.info(io, "auth/passwd", "getting struct", .{});
var user_entry: interop.UsernameEntry = undefined;
{
defer interop.closePasswordDatabase();
@@ -102,27 +102,27 @@ pub fn authenticate(allocator: std.mem.Allocator, log_file: *LogFile, options: A
}
// Set user shell if it hasn't already been set
try log_file.info("auth/passwd", "setting user shell", .{});
try log_file.info(io, "auth/passwd", "setting user shell", .{});
if (user_entry.shell == null) interop.setUserShell(&user_entry);
var shared_err = try SharedError.init(null, null);
defer shared_err.deinit();
log_file.deinit();
log_file.deinit(io);
child_pid = try std.posix.fork();
child_pid = std.posix.system.fork();
if (child_pid == 0) {
try log_file.reinit();
try log_file.info("auth/sys", "starting session", .{});
try log_file.reinit(io);
try log_file.info(io, "auth/sys", "starting session", .{});
startSession(log_file, allocator, options, tty_str, user_entry, handle, current_environment) catch |e| {
startSession(log_file, allocator, io, options, tty_str, user_entry, handle, current_environment) catch |e| {
shared_err.writeError(e);
log_file.deinit();
log_file.deinit(io);
std.process.exit(1);
};
log_file.deinit();
log_file.deinit(io);
std.process.exit(0);
}
@@ -132,7 +132,8 @@ pub fn authenticate(allocator: std.mem.Allocator, log_file: *LogFile, options: A
// If an error occurs here, we can send SIGTERM to the session
errdefer cleanup: {
std.posix.kill(child_pid, std.posix.SIG.TERM) catch break :cleanup;
_ = std.posix.waitpid(child_pid, 0);
var child_status: c_int = undefined;
_ = std.posix.system.waitpid(child_pid, &child_status, 0);
}
// If we receive SIGTERM, forward it to child_pid
@@ -143,14 +144,15 @@ pub fn authenticate(allocator: std.mem.Allocator, log_file: *LogFile, options: A
};
std.posix.sigaction(std.posix.SIG.TERM, &act, null);
try addUtmpEntry(&entry, user_entry.username.?, child_pid);
try addUtmpEntry(io, &entry, user_entry.username.?, child_pid);
}
// Wait for the session to stop
_ = std.posix.waitpid(child_pid, 0);
var child_status: c_int = undefined;
_ = std.posix.system.waitpid(child_pid, &child_status, 0);
try log_file.reinit();
try log_file.reinit(io);
try log_file.info("auth/utmp", "removing utmp entry", .{});
try log_file.info(io, "auth/utmp", "removing utmp entry", .{});
removeUtmpEntry(&entry);
if (shared_err.readError()) |err| return err;
@@ -159,6 +161,7 @@ pub fn authenticate(allocator: std.mem.Allocator, log_file: *LogFile, options: A
fn startSession(
log_file: *LogFile,
allocator: std.mem.Allocator,
io: std.Io,
options: AuthOptions,
tty_str: []u8,
user_entry: interop.UsernameEntry,
@@ -166,15 +169,15 @@ fn startSession(
current_environment: Environment,
) !void {
// Set the user's GID & PID
try log_file.info("auth/passwd", "setting user context", .{});
try log_file.info(io, "auth/passwd", "setting user context", .{});
try interop.setUserContext(allocator, user_entry);
// Set up the environment
try log_file.info("auth/env", "setting environment variables", .{});
try log_file.info(io, "auth/env", "setting environment variables", .{});
try initEnv(allocator, user_entry, options.path);
// Reset the XDG environment variables
try log_file.info("auth/env", "resetting xdg environment variables", .{});
try log_file.info(io, "auth/env", "resetting xdg environment variables", .{});
try setXdgEnv(allocator, tty_str, current_environment);
try setXdgRuntimeDir(allocator);
@@ -185,27 +188,30 @@ fn startSession(
const env_list = std.mem.span(pam_env_vars.?);
for (env_list) |env_var| {
if (env_var == null) continue;
try log_file.info("auth/env", "setting pam environment variable: {s}", .{std.mem.span(env_var.?)});
try log_file.info(io, "auth/env", "setting pam environment variable: {s}", .{std.mem.span(env_var.?)});
try interop.putEnvironmentVariable(env_var);
}
const home_z = try allocator.dupeZ(u8, user_entry.home.?);
defer allocator.free(home_z);
// Change to the user's home directory
try log_file.info("auth/sys", "changing cwd to user home", .{});
std.posix.chdir(user_entry.home.?) catch return error.ChangeDirectoryFailed;
try log_file.info(io, "auth/sys", "changing cwd to user home", .{});
if (std.posix.system.chdir(home_z.ptr) < 0) return error.ChangeDirectoryFailed;
// Signal to the session process to give up control on the TTY
try log_file.info("auth/sys", "releasing tty", .{});
try log_file.info(io, "auth/sys", "releasing tty", .{});
std.posix.kill(options.session_pid, std.posix.SIG.CHLD) catch return error.TtyControlTransferFailed;
// Execute what the user requested
switch (current_environment.display_server) {
.wayland, .shell, .custom => try executeCmd(log_file, allocator, user_entry.shell.?, options, current_environment.is_terminal, current_environment.cmd),
.wayland, .shell, .custom => try executeCmd(log_file, allocator, io, user_entry.shell.?, options, current_environment.is_terminal, current_environment.cmd),
.xinitrc, .x11 => if (build_options.enable_x11_support) {
var vt_buf: [5]u8 = undefined;
const vt = try std.fmt.bufPrint(&vt_buf, "vt{d}", .{options.x_vt orelse options.tty});
try log_file.info("auth/x11", "setting vt to {s}", .{vt});
try executeX11Cmd(log_file, allocator, user_entry.shell.?, user_entry.home.?, options, current_environment.cmd orelse "", vt);
try log_file.info(io, "auth/x11", "setting vt to {s}", .{vt});
try executeX11Cmd(log_file, allocator, io, user_entry.shell.?, user_entry.home.?, options, current_environment.cmd orelse "", vt);
},
}
}
@@ -247,7 +253,7 @@ fn setXdgRuntimeDir(allocator: std.mem.Allocator) !void {
// XDG_RUNTIME_DIR to fall back to directories inside user's home
// directory.
if (builtin.os.tag != .freebsd) {
const uid = std.posix.getuid();
const uid = std.posix.system.getuid();
var uid_buffer: [32]u8 = undefined; // No UID can be larger than this
const uid_str = try std.fmt.bufPrint(&uid_buffer, "/run/user/{d}", .{uid});
@@ -317,20 +323,20 @@ fn getFreeDisplay() !u8 {
var buf: [15]u8 = undefined;
var i: u8 = 0;
while (i < 200) : (i += 1) {
const xlock = try std.fmt.bufPrint(&buf, "/tmp/.X{d}-lock", .{i});
std.posix.access(xlock, std.posix.F_OK) catch break;
const xlock = try std.fmt.bufPrintZ(&buf, "/tmp/.X{d}-lock", .{i});
if (interop.isError(std.posix.system.access(xlock.ptr, std.posix.F_OK))) break;
}
return i;
}
fn getXPid(display_num: u8) !i32 {
fn getXPid(io: std.Io, display_num: u8) !i32 {
var buf: [15]u8 = undefined;
const file_name = try std.fmt.bufPrint(&buf, "/tmp/.X{d}-lock", .{display_num});
const file = try std.fs.openFileAbsolute(file_name, .{});
defer file.close();
const file = try std.Io.Dir.openFileAbsolute(io, file_name, .{});
defer file.close(io);
var file_buffer: [32]u8 = undefined;
var file_reader = file.reader(&file_buffer);
var file_reader = file.reader(io, &file_buffer);
var reader = &file_reader.interface;
var buffer: [20]u8 = undefined;
@@ -340,41 +346,41 @@ fn getXPid(display_num: u8) !i32 {
return std.fmt.parseInt(i32, std.mem.trim(u8, buffer[0..written], " "), 10);
}
fn createXauthFile(log_file: *LogFile, pwd: []const u8, buffer: []u8) ![]const u8 {
fn createXauthFile(log_file: *LogFile, io: std.Io, pwd: []const u8, buffer: []u8) ![]const u8 {
var xauth_buf: [100]u8 = undefined;
var xauth_dir: []const u8 = undefined;
const xdg_rt_dir = std.posix.getenv("XDG_RUNTIME_DIR");
const xdg_rt_dir = std.posix.system.getenv("XDG_RUNTIME_DIR");
var xauth_file: []const u8 = "lyxauth";
if (xdg_rt_dir == null) no_rt_dir: {
const xdg_cfg_home = std.posix.getenv("XDG_CONFIG_HOME");
const xdg_cfg_home = std.posix.system.getenv("XDG_CONFIG_HOME");
if (xdg_cfg_home == null) no_cfg_home: {
xauth_dir = try std.fmt.bufPrint(&xauth_buf, "{s}/.config", .{pwd});
var dir = std.fs.cwd().openDir(xauth_dir, .{}) catch {
var dir = std.Io.Dir.cwd().openDir(io, xauth_dir, .{}) catch {
// xauth_dir isn't a directory
xauth_dir = pwd;
xauth_file = ".lyxauth";
break :no_cfg_home;
};
dir.close();
dir.close(io);
// xauth_dir is a directory, use it to store Xauthority
xauth_dir = try std.fmt.bufPrint(&xauth_buf, "{s}/.config/ly", .{pwd});
} else {
xauth_dir = try std.fmt.bufPrint(&xauth_buf, "{s}/ly", .{xdg_cfg_home.?});
xauth_dir = try std.fmt.bufPrint(&xauth_buf, "{s}/ly", .{std.mem.span(xdg_cfg_home.?)});
}
const file = std.fs.cwd().openFile(xauth_dir, .{}) catch break :no_rt_dir;
file.close();
const file = std.Io.Dir.cwd().openFile(io, xauth_dir, .{}) catch break :no_rt_dir;
file.close(io);
// xauth_dir is a file, create the parent directory
std.posix.mkdir(xauth_dir, 777) catch {
std.Io.Dir.createDirAbsolute(io, xauth_dir, .fromMode(777)) catch {
xauth_dir = pwd;
xauth_file = ".lyxauth";
};
} else {
xauth_dir = xdg_rt_dir.?;
xauth_dir = std.mem.span(xdg_rt_dir.?);
}
// Trim trailing slashes
@@ -384,19 +390,19 @@ fn createXauthFile(log_file: *LogFile, pwd: []const u8, buffer: []u8) ![]const u
const xauthority: []u8 = try std.fmt.bufPrint(buffer, "{s}/{s}", .{ trimmed_xauth_dir, xauth_file });
std.fs.cwd().makePath(trimmed_xauth_dir) catch {};
std.Io.Dir.cwd().createDirPath(io, trimmed_xauth_dir) catch {};
try log_file.info("auth/x11", "creating xauth file: {s}", .{xauthority});
try log_file.info(io, "auth/x11", "creating xauth file: {s}", .{xauthority});
const file = try std.fs.createFileAbsolute(xauthority, .{});
file.close();
const file = try std.Io.Dir.createFileAbsolute(io, xauthority, .{});
file.close(io);
return xauthority;
}
fn mcookie() [Md5.digest_length * 2]u8 {
fn mcookie(io: std.Io) [Md5.digest_length * 2]u8 {
var buf: [4096]u8 = undefined;
std.crypto.random.bytes(&buf);
io.random(&buf);
var out: [Md5.digest_length]u8 = undefined;
Md5.hash(&buf, &out, .{});
@@ -404,86 +410,87 @@ fn mcookie() [Md5.digest_length * 2]u8 {
return std.fmt.bytesToHex(&out, .lower);
}
fn xauth(log_file: *LogFile, allocator: std.mem.Allocator, display_name: []u8, shell: [*:0]const u8, home: []const u8, xauth_buffer: []u8, options: AuthOptions) ![]const u8 {
const xauthority = try createXauthFile(log_file, home, xauth_buffer);
fn xauth(log_file: *LogFile, allocator: std.mem.Allocator, io: std.Io, display_name: []u8, shell: [*:0]const u8, home: []const u8, xauth_buffer: []u8, options: AuthOptions) ![]const u8 {
const xauthority = try createXauthFile(log_file, io, home, xauth_buffer);
try interop.setEnvironmentVariable(allocator, "XAUTHORITY", xauthority, true);
try interop.setEnvironmentVariable(allocator, "DISPLAY", display_name, true);
const magic_cookie = mcookie();
const magic_cookie = mcookie(io);
const pid = try std.posix.fork();
const pid = std.posix.system.fork();
if (pid == 0) {
var cmd_buffer: [1024]u8 = undefined;
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} add {s} . {s}", .{ options.xauth_cmd, display_name, magic_cookie }) catch std.process.exit(1);
try log_file.info("auth/x11", "executing: {s} -c {s}", .{ shell, cmd_str });
try log_file.info(io, "auth/x11", "executing: {s} -c {s}", .{ shell, cmd_str });
const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str };
std.posix.execveZ(shell, &args, std.c.environ) catch {};
_ = std.posix.system.execve(shell, &args, std.c.environ);
std.process.exit(1);
}
const status = std.posix.waitpid(pid, 0);
if (status.status != 0) {
try log_file.file_writer.interface.print("xauth command failed with status {d}\n", .{status.status});
var status: c_int = undefined;
const result = std.posix.system.waitpid(pid, &status, 0);
if (interop.isError(result) or status != 0) {
try log_file.file_writer.interface.print("xauth command failed with status {d}\n", .{status});
return error.XauthFailed;
}
return xauthority;
}
fn executeX11Cmd(log_file: *LogFile, allocator: std.mem.Allocator, shell: []const u8, home: []const u8, options: AuthOptions, desktop_cmd: []const u8, vt: []const u8) !void {
fn executeX11Cmd(log_file: *LogFile, allocator: std.mem.Allocator, io: std.Io, shell: []const u8, home: []const u8, options: AuthOptions, desktop_cmd: []const u8, vt: []const u8) !void {
var xauth_buffer: [256]u8 = undefined;
try log_file.info("auth/x11", "getting free display", .{});
try log_file.info(io, "auth/x11", "getting free display", .{});
const display_num = try getFreeDisplay();
var buf: [4]u8 = undefined;
const display_name = try std.fmt.bufPrint(&buf, ":{d}", .{display_num});
try log_file.info("auth/x11", "got free display: {d}", .{display_num});
try log_file.info(io, "auth/x11", "got free display: {d}", .{display_num});
const shell_z = try allocator.dupeZ(u8, shell);
defer allocator.free(shell_z);
try log_file.info("auth/x11", "creating xauth file", .{});
const xauthority = try xauth(log_file, allocator, display_name, shell_z, home, &xauth_buffer, options);
try log_file.info(io, "auth/x11", "creating xauth file", .{});
const xauthority = try xauth(log_file, allocator, io, display_name, shell_z, home, &xauth_buffer, options);
try log_file.info("auth/x11", "starting x server", .{});
const pid = try std.posix.fork();
try log_file.info(io, "auth/x11", "starting x server", .{});
const pid = std.posix.system.fork();
if (pid == 0) {
var cmd_buffer: [1024]u8 = undefined;
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s} -auth {s}", .{ options.x_cmd, display_name, vt, xauthority }) catch std.process.exit(1);
try log_file.info("auth/x11", "executing: {s} -c {s} -auth {s}", .{ shell, cmd_str, xauthority });
try log_file.info(io, "auth/x11", "executing: {s} -c {s} -auth {s}", .{ shell, cmd_str, xauthority });
const args = [_:null]?[*:0]const u8{ shell_z, "-c", cmd_str };
std.posix.execveZ(shell_z, &args, std.c.environ) catch {};
_ = std.posix.system.execve(shell_z, &args, std.c.environ);
std.process.exit(1);
}
try log_file.info("auth/x11", "waiting for xcb connection", .{});
try log_file.info(io, "auth/x11", "waiting for xcb connection", .{});
var ok: c_int = -1;
var xcb: ?*interop.xcb.xcb_connection_t = null;
while (ok != 0) {
xcb = interop.xcb.xcb_connect(null, null);
ok = interop.xcb.xcb_connection_has_error(xcb);
std.posix.kill(pid, 0) catch |e| {
std.posix.kill(pid, @enumFromInt(0)) catch |e| {
if (e == error.ProcessNotFound and ok != 0) return error.XcbConnectionFailed;
};
}
// X Server detaches from the process.
// PID can be fetched from /tmp/X{d}.lock
try log_file.info("auth/x11", "getting x server pid", .{});
const x_pid = try getXPid(display_num);
try log_file.info("auth/x11", "got x server pid: {d}", .{x_pid});
try log_file.info(io, "auth/x11", "getting x server pid", .{});
const x_pid = try getXPid(io, display_num);
try log_file.info(io, "auth/x11", "got x server pid: {d}", .{x_pid});
try log_file.info("auth/x11", "launching environment", .{});
xorg_pid = try std.posix.fork();
try log_file.info(io, "auth/x11", "launching environment", .{});
xorg_pid = std.posix.system.fork();
if (xorg_pid == 0) {
var cmd_buffer: [1024]u8 = undefined;
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s} {s}", .{ if (options.use_kmscon_vt) "kmscon-launch-gui" else "", options.setup_cmd, options.login_cmd orelse "", desktop_cmd }) catch std.process.exit(1);
try log_file.info("auth/x11", "executing: {s} -c {s}", .{ shell, cmd_str });
try log_file.info(io, "auth/x11", "executing: {s} -c {s}", .{ shell, cmd_str });
const args = [_:null]?[*:0]const u8{ shell_z, "-c", cmd_str };
std.posix.execveZ(shell_z, &args, std.c.environ) catch {};
_ = std.posix.system.execve(shell_z, &args, std.c.environ);
std.process.exit(1);
}
@@ -495,26 +502,28 @@ fn executeX11Cmd(log_file: *LogFile, allocator: std.mem.Allocator, shell: []cons
};
std.posix.sigaction(std.posix.SIG.TERM, &act, null);
_ = std.posix.waitpid(xorg_pid, 0);
var xorg_status: c_int = undefined;
_ = std.posix.system.waitpid(xorg_pid, &xorg_status, 0);
try log_file.info("auth/x11", "disconnecting xcb", .{});
try log_file.info(io, "auth/x11", "disconnecting xcb", .{});
interop.xcb.xcb_disconnect(xcb);
// TODO: Find a more robust way to ensure that X has been terminated (pidfds?)
std.posix.kill(x_pid, std.posix.SIG.TERM) catch {};
std.Thread.sleep(std.time.ns_per_s * 1); // Wait 1 second before sending SIGKILL
io.sleep(.fromSeconds(1), .real) catch {}; // Wait 1 second before sending SIGKILL
std.posix.kill(x_pid, std.posix.SIG.KILL) catch return;
_ = std.posix.waitpid(x_pid, 0);
var x_status: c_int = undefined;
_ = std.posix.system.waitpid(x_pid, &x_status, 0);
}
fn executeCmd(global_log_file: *LogFile, allocator: std.mem.Allocator, shell: []const u8, options: AuthOptions, is_terminal: bool, exec_cmd: ?[]const u8) !void {
try global_log_file.info("auth/sys", "launching wayland/shell/custom session", .{});
fn executeCmd(global_log_file: *LogFile, allocator: std.mem.Allocator, io: std.Io, shell: []const u8, options: AuthOptions, is_terminal: bool, exec_cmd: ?[]const u8) !void {
try global_log_file.info(io, "auth/sys", "launching wayland/shell/custom session", .{});
var maybe_log_file: ?std.fs.File = null;
var maybe_log_file: ?std.Io.File = null;
if (!is_terminal) redirect_streams: {
if (options.use_kmscon_vt) {
try global_log_file.err("auth/sys", "cannot redirect stdio & stderr with kmscon", .{});
try global_log_file.err(io, "auth/sys", "cannot redirect stdio & stderr with kmscon", .{});
break :redirect_streams;
}
@@ -522,11 +531,11 @@ fn executeCmd(global_log_file: *LogFile, allocator: std.mem.Allocator, shell: []
// we redirect standard output & error or not. That is, we redirect only
// if it's equal to false (so if it's not running in a TTY).
if (options.session_log) |log_path| {
try global_log_file.info("auth/sys", "setting up stdio & stderr redirection", .{});
maybe_log_file = try redirectStandardStreams(global_log_file, log_path, true);
try global_log_file.info(io, "auth/sys", "setting up stdio & stderr redirection", .{});
maybe_log_file = try redirectStandardStreams(global_log_file, io, log_path, true);
}
}
defer if (maybe_log_file) |log_file| log_file.close();
defer if (maybe_log_file) |log_file| log_file.close(io);
const shell_z = try allocator.dupeZ(u8, shell);
defer allocator.free(shell_z);
@@ -534,40 +543,42 @@ fn executeCmd(global_log_file: *LogFile, allocator: std.mem.Allocator, shell: []
var cmd_buffer: [1024]u8 = undefined;
const cmd_str = try std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s} {s}", .{ if (!is_terminal and options.use_kmscon_vt) "kmscon-launch-gui" else "", options.setup_cmd, options.login_cmd orelse "", exec_cmd orelse shell });
try global_log_file.info("auth/sys", "executing: {s} -c {s}", .{ shell, cmd_str });
try global_log_file.info(io, "auth/sys", "executing: {s} -c {s}", .{ shell, cmd_str });
const args = [_:null]?[*:0]const u8{ shell_z, "-c", cmd_str };
return std.posix.execveZ(shell_z, &args, std.c.environ);
_ = std.posix.system.execve(shell_z, &args, std.c.environ);
return error.CmdExecveFailed;
}
fn redirectStandardStreams(global_log_file: *LogFile, session_log: []const u8, create: bool) !std.fs.File {
fn redirectStandardStreams(global_log_file: *LogFile, io: std.Io, session_log: []const u8, create: bool) !std.Io.File {
create_session_log_dir: {
const session_log_dir = std.fs.path.dirname(session_log) orelse break :create_session_log_dir;
std.fs.cwd().makePath(session_log_dir) catch |err| {
try global_log_file.err("auth/sys", "failed to create session log file directory: {s}", .{@errorName(err)});
const session_log_dir = std.Io.Dir.path.dirname(session_log) orelse break :create_session_log_dir;
std.Io.Dir.cwd().createDirPath(io, session_log_dir) catch |err| {
try global_log_file.err(io, "auth/sys", "failed to create session log file directory: {s}", .{@errorName(err)});
return err;
};
}
const log_file = if (create) (std.fs.cwd().createFile(session_log, .{ .mode = 0o666 }) catch |err| {
try global_log_file.err("auth/sys", "failed to create new session log file: {s}", .{@errorName(err)});
const log_file = if (create) (std.Io.Dir.cwd().createFile(io, session_log, .{ .permissions = .fromMode(0o666) }) catch |err| {
try global_log_file.err(io, "auth/sys", "failed to create new session log file: {s}", .{@errorName(err)});
return err;
}) else (std.fs.cwd().openFile(session_log, .{ .mode = .read_write }) catch |err| {
try global_log_file.err("auth/sys", "failed to open existing session log file: {s}", .{@errorName(err)});
}) else (std.Io.Dir.cwd().openFile(io, session_log, .{ .mode = .read_write }) catch |err| {
try global_log_file.err(io, "auth/sys", "failed to open existing session log file: {s}", .{@errorName(err)});
return err;
});
try std.posix.dup2(std.posix.STDOUT_FILENO, std.posix.STDERR_FILENO);
try std.posix.dup2(log_file.handle, std.posix.STDOUT_FILENO);
if (interop.isError(std.posix.system.dup2(std.posix.STDOUT_FILENO, std.posix.STDERR_FILENO))) return error.StdoutDup2Failed;
if (interop.isError(std.posix.system.dup2(log_file.handle, std.posix.STDOUT_FILENO))) return error.LogFileDup2Failed;
return log_file;
}
fn addUtmpEntry(entry: *Utmp, username: []const u8, pid: c_int) !void {
fn addUtmpEntry(io: std.Io, entry: *Utmp, username: []const u8, pid: c_int) !void {
entry.ut_type = utmp.USER_PROCESS;
entry.ut_pid = pid;
var buf: [std.fs.max_path_bytes]u8 = undefined;
const tty_path = try std.os.getFdPath(std.posix.STDIN_FILENO, &buf);
var buf: [std.Io.Dir.max_path_bytes]u8 = undefined;
const length = try std.Io.File.stdin().realPath(io, &buf);
const tty_path = buf[0..length];
// Get the TTY name (i.e. without the /dev/ prefix)
var ttyname_buf: [@sizeOf(@TypeOf(entry.ut_line))]u8 = undefined;