get errors from child process and (hopefully) fix some other things

This commit is contained in:
Kinzie 2024-03-28 05:24:13 +00:00
parent ad87a96dec
commit 07cbc1564d
3 changed files with 134 additions and 53 deletions

39
src/SharedError.zig Normal file
View File

@ -0,0 +1,39 @@
const std = @import("std");
const ErrInt = std.meta.Int(.unsigned, @bitSizeOf(anyerror));
const ErrorHandler = packed struct {
has_error: bool = false,
err_int: ErrInt = 0,
};
const SharedError = @This();
data: []align(std.mem.page_size) u8,
pub fn init() !SharedError {
const data = try std.os.mmap(null, @sizeOf(ErrorHandler), std.os.PROT.READ | std.os.PROT.WRITE, std.os.MAP.SHARED | std.os.MAP.ANONYMOUS, -1, 0);
return .{ .data = data };
}
pub fn deinit(self: *SharedError) void {
defer std.os.munmap(self.data);
}
pub fn writeError(self: SharedError, err: anyerror) void {
var buf_stream = std.io.fixedBufferStream(self.data);
const writer = buf_stream.writer();
writer.writeStruct(ErrorHandler{ .has_error = true, .err_int = @intFromError(err) }) catch {};
}
pub fn readError(self: SharedError) ?anyerror {
var buf_stream = std.io.fixedBufferStream(self.data);
const reader = buf_stream.reader();
const err_handler = try reader.readStruct(ErrorHandler);
if (err_handler.has_error)
return @errorFromInt(err_handler.err_int);
return null;
}

View File

@ -8,15 +8,10 @@ const Config = @import("config/Config.zig");
const Allocator = std.mem.Allocator;
const utmp = interop.utmp;
const Utmp = utmp.utmp;
const SharedError = @import("SharedError.zig");
pub fn authenticate(
allocator: Allocator,
config: Config,
desktop: Desktop,
login: Text,
password: *Text,
) !void {
var tty_buffer = std.mem.zeroes([@sizeOf(u8) + 1]u8);
pub fn authenticate(allocator: Allocator, config: Config, desktop: Desktop, login: Text, password: *Text) !void {
var tty_buffer: [2]u8 = undefined;
const tty_str = try std.fmt.bufPrintZ(&tty_buffer, "{d}", .{config.tty});
const current_environment = desktop.environments.items[desktop.current];
@ -47,7 +42,6 @@ pub fn authenticate(
defer allocator.free(service_name_z);
var status = interop.pam.pam_start(service_name_z.ptr, null, &conv, &handle);
defer status = interop.pam.pam_end(handle, status);
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
@ -98,25 +92,42 @@ pub fn authenticate(
interop.termbox.tb_present();
interop.termbox.tb_shutdown();
const pid = std.c.fork();
var shared_err = try SharedError.init();
defer shared_err.deinit();
const pid = try std.os.fork();
if (pid == 0) {
// Set the user information
status = interop.initgroups(pwd.pw_name, pwd.pw_gid);
if (status != 0) return error.GroupInitializationFailed;
if (status != 0) {
shared_err.writeError(error.GroupInitializationFailed);
std.os.exit(1);
}
status = std.c.setgid(pwd.pw_gid);
if (status != 0) return error.SetUserGidFailed;
if (status != 0) {
shared_err.writeError(error.SetUserGidFailed);
std.os.exit(1);
}
status = std.c.setuid(pwd.pw_uid);
if (status != 0) return error.SetUserUidFailed;
if (status != 0) {
shared_err.writeError(error.SetUserUidFailed);
std.os.exit(1);
}
// Set up the environment (this clears the currently set one)
try initEnv(allocator, pwd, config.path);
initEnv(allocator, pwd, config.path) catch |e| {
shared_err.writeError(e);
std.os.exit(1);
};
// Reset the XDG environment variables from before
setXdgSessionEnv(current_environment.display_server);
try setXdgEnv(allocator, tty_str, current_environment.xdg_name);
setXdgEnv(allocator, tty_str, current_environment.xdg_name) catch |e| {
shared_err.writeError(e);
std.os.exit(1);
};
// Set the PAM variables
const pam_env_vars = interop.pam.pam_getenvlist(handle);
@ -131,27 +142,47 @@ pub fn authenticate(
// Execute what the user requested
status = interop.chdir(pwd.pw_dir);
if (status != 0) return error.ChangeDirectoryFailed;
if (status != 0) {
shared_err.writeError(error.ChangeDirectoryFailed);
std.os.exit(1);
}
try resetTerminal(allocator, pwd.pw_shell, config.term_reset_cmd);
resetTerminal(allocator, pwd.pw_shell, config.term_reset_cmd) catch |e| {
shared_err.writeError(e);
std.os.exit(1);
};
switch (current_environment.display_server) {
.wayland => try executeWaylandCmd(pwd.pw_shell, config.wayland_cmd, current_environment.cmd),
.wayland => executeWaylandCmd(pwd.pw_shell, config.wayland_cmd, current_environment.cmd) catch |e| {
shared_err.writeError(e);
std.os.exit(1);
},
.shell => executeShellCmd(pwd.pw_shell),
.xinitrc, .x11 => {
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);
const vt = std.fmt.bufPrint(&vt_buf, "vt{d}", .{config.tty}) catch |e| {
shared_err.writeError(e);
std.os.exit(1);
};
executeX11Cmd(pwd.pw_shell, pwd.pw_dir, config, current_environment.cmd, vt) catch |e| {
shared_err.writeError(e);
std.os.exit(1);
};
},
}
std.os.exit(0);
}
var entry: Utmp = std.mem.zeroes(Utmp);
try addUtmpEntry(&entry, pwd.pw_name, pid);
addUtmpEntry(&entry, pwd.pw_name, pid) catch {};
// Wait for the session to stop
_ = std.c.waitpid(pid, &status, 0);
const ch_proc = std.os.waitpid(pid, 0);
var err = shared_err.readError();
if (ch_proc.status != 0 and err == null)
err = error.UnknownError;
removeUtmpEntry(&entry);
@ -167,14 +198,20 @@ pub fn authenticate(
status = interop.pam.pam_setcred(handle, 0);
if (status != 0) return pamDiagnose(status);
status = interop.pam.pam_end(handle, status);
if (status != 0) return pamDiagnose(status);
if (err != null)
return err.?;
}
fn initEnv(allocator: Allocator, pwd: *interop.passwd, path: ?[]const u8) !void {
const term = interop.getenv("TERM");
const term_env = std.os.getenv("TERM");
_ = interop.clearenv();
std.c.environ[0] = null;
if (term[0] != 0) _ = interop.setenv("TERM", term, 1);
if (term_env) |term| _ = interop.setenv("TERM", term, 1);
_ = interop.setenv("HOME", pwd.pw_dir, 1);
_ = interop.setenv("PWD", pwd.pw_dir, 1);
_ = interop.setenv("SHELL", pwd.pw_shell, 1);
@ -303,19 +340,17 @@ fn getXPid(display_num: u8) !i32 {
return std.fmt.parseInt(i32, std.mem.trim(u8, line, " "), 10);
}
fn xauth(display_name: [:0]u8, shell: [*:0]const u8, pw_dir: [*:0]const u8, xauth_cmd: []const u8, mcookie_cmd: []const u8) !void {
var pwd_buf: [100]u8 = undefined;
var pwd: [:0]u8 = try std.fmt.bufPrintZ(&pwd_buf, "{s}", .{pw_dir});
fn createXauthFile(pwd: [:0]const u8) ![:0]const u8 {
var xauth_buf: [100]u8 = undefined;
var xauth_dir: [:0]u8 = std.mem.span(interop.getenv("XDG_RUNTIME_DIR"));
var xauth_dir: [:0]const u8 = undefined;
var xdg_rt_dir = std.os.getenv("XDG_RUNTIME_DIR");
var xauth_file: []const u8 = "lyxauth";
if (xauth_dir[0] == 0) {
xauth_dir = std.mem.span(interop.getenv("XDG_CONFIG_HOME"));
if (xdg_rt_dir == null) {
const xdg_cfg_home = std.os.getenv("XDG_CONFIG_HOME");
var sb: std.c.Stat = std.mem.zeroes(std.c.Stat);
if (xauth_dir[0] == 0) {
xauth_dir = try std.fmt.bufPrintZ(&xauth_buf, "{s}/.config", .{xauth_dir});
if (xdg_cfg_home == null) {
xauth_dir = try std.fmt.bufPrintZ(&xauth_buf, "{s}/.config", .{pwd});
_ = std.c.stat(xauth_dir, &sb);
const mode = sb.mode & std.os.S.IFMT;
if (mode == std.os.S.IFDIR) {
@ -325,7 +360,7 @@ fn xauth(display_name: [:0]u8, shell: [*:0]const u8, pw_dir: [*:0]const u8, xaut
xauth_file = ".lyxauth";
}
} else {
xauth_dir = try std.fmt.bufPrintZ(&xauth_buf, "{s}/ly", .{xauth_dir});
xauth_dir = try std.fmt.bufPrintZ(&xauth_buf, "{s}/ly", .{xdg_cfg_home.?});
}
_ = std.c.stat(xauth_dir, &sb);
@ -336,27 +371,37 @@ fn xauth(display_name: [:0]u8, shell: [*:0]const u8, pw_dir: [*:0]const u8, xaut
xauth_file = ".lyxauth";
};
}
} else {
xauth_dir = xdg_rt_dir.?;
}
// Trim trailing slashes
var i = xauth_dir.len - 1;
while (xauth_dir[i] == '/') : (i -= 1) {}
xauth_dir[i + 1] = 0;
xauth_dir = xauth_dir[0 .. i + 1 :0];
const trimmed_xauth_dir = xauth_dir[0 .. i + 1];
var buf: [256]u8 = undefined;
const xauthority: [:0]u8 = try std.fmt.bufPrintZ(&buf, "{s}/{s}", .{ xauth_dir, xauth_file });
_ = interop.setenv("XAUTHORITY", xauthority, 1);
_ = interop.setenv("DISPLAY", display_name, 1);
const xauthority: [:0]u8 = try std.fmt.bufPrintZ(&buf, "{s}/{s}", .{ trimmed_xauth_dir, xauth_file });
const createFlags = std.fs.File.CreateFlags{};
const file = try std.fs.createFileAbsolute(xauthority, createFlags);
file.close();
return xauthority;
}
fn xauth(display_name: [:0]u8, shell: [*:0]const u8, pw_dir: [*:0]const u8, xauth_cmd: []const u8, mcookie_cmd: []const u8) !void {
var pwd_buf: [100]u8 = undefined;
var pwd: [:0]u8 = try std.fmt.bufPrintZ(&pwd_buf, "{s}", .{pw_dir});
const xauthority = try createXauthFile(pwd);
_ = interop.setenv("XAUTHORITY", xauthority, 1);
_ = interop.setenv("DISPLAY", display_name, 1);
const pid = std.c.fork();
if (pid == 0) {
var cmd_buffer: [1024]u8 = undefined;
const cmd_str = try std.fmt.bufPrintZ(&cmd_buffer, "{s} add {s} . $({s})", .{ xauth_cmd, display_name, mcookie_cmd });
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} add {s} . $({s})", .{ xauth_cmd, display_name, mcookie_cmd }) catch std.os.exit(1);
_ = interop.execl(shell, shell, "-c", cmd_str.ptr, @as([*c]const u8, 0));
std.os.exit(0);
}
@ -381,7 +426,7 @@ fn executeX11Cmd(shell: [*:0]const u8, pw_dir: [*:0]const u8, config: Config, de
const pid = std.c.fork();
if (pid == 0) {
var cmd_buffer: [1024]u8 = undefined;
const cmd_str = try std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s}", .{ config.x_cmd, display_name, vt });
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s}", .{ config.x_cmd, display_name, vt }) catch std.os.exit(1);
_ = interop.execl(shell, shell, "-c", cmd_str.ptr, @as([*c]const u8, 0));
std.os.exit(0);
}
@ -406,7 +451,7 @@ fn executeX11Cmd(shell: [*:0]const u8, pw_dir: [*:0]const u8, config: Config, de
const xorg_pid = std.c.fork();
if (xorg_pid == 0) {
var cmd_buffer: [1024]u8 = undefined;
const cmd_str = try std.fmt.bufPrintZ(&cmd_buffer, "{s} {s}", .{ config.x_cmd_setup, desktop_cmd });
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} {s}", .{ config.x_cmd_setup, desktop_cmd }) catch std.os.exit(1);
_ = interop.execl(shell, shell, "-c", cmd_str.ptr, @as([*c]const u8, 0));
std.os.exit(0);
}

View File

@ -464,7 +464,8 @@ pub fn main() !void {
} else if (pressed_key == sleep_key and config.sleep_cmd != null) {
const pid = try std.os.fork();
if (pid == 0) {
std.process.execv(allocator, &[_][]const u8{ "/bin/sh", "-c", config.sleep_cmd.? }) catch {};
std.process.execv(allocator, &[_][]const u8{ "/bin/sh", "-c", config.sleep_cmd.? }) catch std.os.exit(1);
std.os.exit(0);
}
}
},
@ -500,7 +501,7 @@ pub fn main() !void {
};
update = true;
},
termbox.TB_KEY_ENTER => authenticate: {
termbox.TB_KEY_ENTER => {
if (config.save) save_last_settings: {
var file = std.fs.createFileAbsolute(config.save_file, .{}) catch break :save_last_settings;
defer file.close();
@ -514,13 +515,7 @@ pub fn main() !void {
var has_error = false;
auth.authenticate(
allocator,
config,
desktop,
login,
&password,
) catch |err| {
auth.authenticate(allocator, config, desktop, login, &password) catch |err| {
has_error = true;
auth_fails += 1;
active_input = .password;
@ -532,9 +527,11 @@ pub fn main() !void {
update = true;
if (!has_error) info_line = lang.logout;
const pid = try std.os.fork();
if (pid == 0) {
std.process.execv(allocator, &[_][]const u8{ "/bin/sh", "-c", config.term_restore_cursor_cmd }) catch break :authenticate;
std.process.execv(allocator, &[_][]const u8{ "/bin/sh", "-c", config.term_restore_cursor_cmd }) catch std.os.exit(1);
std.os.exit(0);
}
},
else => {