From b66e7f09d29c9adc72ac681c2232ef253e627776 Mon Sep 17 00:00:00 2001 From: Kinzie Date: Thu, 18 Apr 2024 15:56:43 +0100 Subject: [PATCH] less alloc, update migrator, get DesktopNames from .desktop --- changelog.md | 4 +- res/config.ini | 3 ++ src/auth.zig | 58 ++++++++----------------- src/config/Config.zig | 6 +-- src/config/Lang.zig | 4 +- src/config/migrator.zig | 34 +++++++++------ src/main.zig | 79 +++++++++++++++++++++------------- src/tui/TerminalBuffer.zig | 1 - src/tui/components/Desktop.zig | 34 +++++++-------- src/tui/components/Text.zig | 1 - 10 files changed, 112 insertions(+), 112 deletions(-) diff --git a/changelog.md b/changelog.md index c1bf64d..2a1be49 100644 --- a/changelog.md +++ b/changelog.md @@ -17,6 +17,7 @@ Note: `sleep_cmd` is unset by default, meaning it's hidden and has no effect. + xinitrc can be set to null to hide it. + `blank_password` has been renamed to `clear_password`. ++ `save_file` has been deprecated and will be removed in a future version. ### Removals @@ -24,7 +25,8 @@ Note: `sleep_cmd` is unset by default, meaning it's hidden and has no effect. ## Save File -The save file is now in .ini format. +The save file is now in .ini format and stored in the same directory as the config. +Older save files will be migrated to the new format. Example: diff --git a/res/config.ini b/res/config.ini index 9d8fcd6..65c6baa 100644 --- a/res/config.ini +++ b/res/config.ini @@ -76,6 +76,9 @@ load = true # Save the current desktop and login as defaults save = true +# Deprecated - Will be removed in a future version +# New save files are now loaded from the same directory as the config +# Currently used to migrate old save files to the new version # File in which to save and load the default desktop and login save_file = /etc/ly/save diff --git a/src/auth.zig b/src/auth.zig index 07fa1fa..3b11b47 100644 --- a/src/auth.zig +++ b/src/auth.zig @@ -20,38 +20,25 @@ pub fn sessionSignalHandler(i: c_int) callconv(.C) void { if (child_pid > 0) _ = std.c.kill(child_pid, i); } -pub fn authenticate(allocator: Allocator, config: Config, desktop: Desktop, login: Text, password: *Text) !void { +pub fn authenticate(config: Config, desktop: Desktop, login: [:0]const u8, password: [:0]const u8) !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]; // Set the XDG environment variables setXdgSessionEnv(current_environment.display_server); - try setXdgEnv(allocator, tty_str, current_environment.xdg_name); + try setXdgEnv(tty_str, current_environment.name, current_environment.xdg_name); // Open the PAM session - const login_text_z = try allocator.dupeZ(u8, login.text.items); - defer allocator.free(login_text_z); - - const password_text_z = try allocator.dupeZ(u8, password.text.items); - defer allocator.free(password_text_z); - - var credentials = try allocator.allocSentinel([*c]const u8, 2, 0); - defer allocator.free(credentials); - - credentials[0] = login_text_z.ptr; - credentials[1] = password_text_z.ptr; + var credentials = [2:null][*c]const u8{ login, password }; const conv = interop.pam.pam_conv{ .conv = loginConv, - .appdata_ptr = @ptrCast(credentials.ptr), + .appdata_ptr = @ptrCast(&credentials), }; var handle: ?*interop.pam.pam_handle = undefined; - const service_name_z = try allocator.dupeZ(u8, config.service_name); - defer allocator.free(service_name_z); - - var status = interop.pam.pam_start(service_name_z.ptr, null, &conv, &handle); + var status = interop.pam.pam_start(config.service_name.ptr, null, &conv, &handle); if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); // Do the PAM routine @@ -68,7 +55,7 @@ pub fn authenticate(allocator: Allocator, config: Config, desktop: Desktop, logi if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); // Get password structure from username - const maybe_pwd = interop.getpwnam(login_text_z.ptr); + const maybe_pwd = interop.getpwnam(login.ptr); interop.endpwent(); if (maybe_pwd == null) return error.GetPasswordNameFailed; @@ -118,7 +105,7 @@ pub fn authenticate(allocator: Allocator, config: Config, desktop: Desktop, logi } // Set up the environment - initEnv(allocator, pwd, config.path) catch |e| { + initEnv(pwd, config.path) catch |e| { shared_err.writeError(e); std.os.exit(1); }; @@ -141,7 +128,7 @@ pub fn authenticate(allocator: Allocator, config: Config, desktop: Desktop, logi std.os.exit(1); } - resetTerminal(allocator, pwd.pw_shell, config.term_reset_cmd) catch |e| { + resetTerminal(pwd.pw_shell, config.term_reset_cmd) catch |e| { shared_err.writeError(e); std.os.exit(1); }; @@ -184,7 +171,7 @@ pub fn authenticate(allocator: Allocator, config: Config, desktop: Desktop, logi removeUtmpEntry(&entry); - try resetTerminal(allocator, pwd.pw_shell, config.term_reset_cmd); + try resetTerminal(pwd.pw_shell, config.term_reset_cmd); // Close the PAM session status = interop.pam.pam_close_session(handle, 0); @@ -199,7 +186,7 @@ pub fn authenticate(allocator: Allocator, config: Config, desktop: Desktop, logi if (shared_err.readError()) |err| return err; } -fn initEnv(allocator: Allocator, pwd: *interop.passwd, path: ?[]const u8) !void { +fn initEnv(pwd: *interop.passwd, path_env: ?[:0]const u8) !void { const term_env = std.os.getenv("TERM"); if (term_env) |term| _ = interop.setenv("TERM", term, 1); @@ -209,11 +196,8 @@ fn initEnv(allocator: Allocator, pwd: *interop.passwd, path: ?[]const u8) !void _ = interop.setenv("USER", pwd.pw_name, 1); _ = interop.setenv("LOGNAME", pwd.pw_name, 1); - if (path != null) { - const path_z = try allocator.dupeZ(u8, path.?); - defer allocator.free(path_z); - - const status = interop.setenv("PATH", path_z, 1); + if (path_env) |path| { + const status = interop.setenv("PATH", path, 1); if (status != 0) return error.SetPathFailed; } } @@ -226,19 +210,16 @@ fn setXdgSessionEnv(display_server: enums.DisplayServer) void { }, 0); } -fn setXdgEnv(allocator: Allocator, tty_str: [:0]u8, desktop_name: []const u8) !void { - const desktop_name_z = try allocator.dupeZ(u8, desktop_name); - defer allocator.free(desktop_name_z); - +fn setXdgEnv(tty_str: [:0]u8, desktop_name: [:0]const u8, desktop_names: [:0]const u8) !void { const uid = interop.getuid(); var uid_buffer: [10 + @sizeOf(u32) + 1]u8 = undefined; const uid_str = try std.fmt.bufPrintZ(&uid_buffer, "/run/user/{d}", .{uid}); - _ = interop.setenv("XDG_CURRENT_DESKTOP", desktop_name_z.ptr, 0); + _ = interop.setenv("XDG_CURRENT_DESKTOP", desktop_names.ptr, 0); _ = interop.setenv("XDG_RUNTIME_DIR", uid_str.ptr, 0); _ = interop.setenv("XDG_SESSION_CLASS", "user", 0); _ = interop.setenv("XDG_SESSION_ID", "1", 0); - _ = interop.setenv("XDG_SESSION_DESKTOP", desktop_name_z.ptr, 0); + _ = interop.setenv("XDG_SESSION_DESKTOP", desktop_name.ptr, 0); _ = interop.setenv("XDG_SEAT", "seat0", 0); _ = interop.setenv("XDG_VTNR", tty_str.ptr, 0); } @@ -291,14 +272,11 @@ fn loginConv( return status; } -fn resetTerminal(allocator: Allocator, shell: [*:0]const u8, term_reset_cmd: []const u8) !void { - const term_reset_cmd_z = try allocator.dupeZ(u8, term_reset_cmd); - defer allocator.free(term_reset_cmd_z); - +fn resetTerminal(shell: [*:0]const u8, term_reset_cmd: [:0]const u8) !void { const pid = try std.os.fork(); if (pid == 0) { - _ = interop.execl(shell, shell, "-c", term_reset_cmd_z.ptr, @as([*c]const u8, 0)); + _ = interop.execl(shell, shell, "-c", term_reset_cmd.ptr, @as([*c]const u8, 0)); std.os.exit(0); } @@ -380,7 +358,7 @@ fn createXauthFile(pwd: [:0]const u8) ![:0]const u8 { 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}); + var pwd = try std.fmt.bufPrintZ(&pwd_buf, "{s}", .{pw_dir}); const xauthority = try createXauthFile(pwd); _ = interop.setenv("XAUTHORITY", xauthority, 1); diff --git a/src/config/Config.zig b/src/config/Config.zig index 8b21dee..b5fdeda 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -27,17 +27,17 @@ max_login_len: u8 = 255, max_password_len: u8 = 255, mcookie_cmd: []const u8 = "/usr/bin/mcookie", min_refresh_delta: u16 = 5, -path: ?[]const u8 = "/sbin:/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin", +path: ?[:0]const u8 = "/sbin:/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin", restart_cmd: []const u8 = "/sbin/shutdown -r now", restart_key: []const u8 = "F2", save: bool = true, save_file: []const u8 = "/etc/ly/save", -service_name: []const u8 = "ly", +service_name: [:0]const u8 = "ly", shutdown_cmd: []const u8 = "/sbin/shutdown -a now", shutdown_key: []const u8 = "F1", sleep_cmd: ?[]const u8 = null, sleep_key: []const u8 = "F3", -term_reset_cmd: []const u8 = "/usr/bin/tput reset", +term_reset_cmd: [:0]const u8 = "/usr/bin/tput reset", term_restore_cursor_cmd: []const u8 = "/usr/bin/tput cnorm", tty: u8 = 2, vi_mode: bool = false, diff --git a/src/config/Lang.zig b/src/config/Lang.zig index 9f199c0..7ebe0b0 100644 --- a/src/config/Lang.zig +++ b/src/config/Lang.zig @@ -42,9 +42,9 @@ numlock: []const u8 = "numlock", other: []const u8 = "other", password: []const u8 = "password:", restart: []const u8 = "reboot", -shell: []const u8 = "shell", +shell: [:0]const u8 = "shell", shutdown: []const u8 = "shutdown", sleep: []const u8 = "sleep", wayland: []const u8 = "wayland", -xinitrc: []const u8 = "xinitrc", +xinitrc: [:0]const u8 = "xinitrc", x11: []const u8 = "x11", diff --git a/src/config/migrator.zig b/src/config/migrator.zig index 9ce5673..9df0078 100644 --- a/src/config/migrator.zig +++ b/src/config/migrator.zig @@ -2,29 +2,35 @@ const std = @import("std"); const ini = @import("zigini"); const Save = @import("Save.zig"); -const Allocator = std.mem.Allocator; +pub fn tryMigrateSaveFile(user_buf: *[32]u8, old_path: []const u8, new_path: []const u8) Save { + var save = Save{}; -pub fn tryMigrateSaveFile(allocator: Allocator, path: []const u8) Save { - var file = std.fs.openFileAbsolute(path, .{ .mode = .read_write }) catch return .{}; + var file = std.fs.openFileAbsolute(old_path, .{ .mode = .read_only }) catch return save; defer file.close(); const reader = file.reader(); - const user_length = reader.readIntLittle(u64) catch return .{}; - const user_buffer = allocator.alloc(u8, user_length) catch return .{}; - defer allocator.free(user_buffer); + var user_fbs = std.io.fixedBufferStream(user_buf); + reader.streamUntilDelimiter(user_fbs.writer(), '\n', 32) catch return save; + var user = user_fbs.getWritten(); + if (user.len > 0) save.user = user; - const read_user_length = reader.read(user_buffer) catch return .{}; - if (read_user_length != user_length) return .{}; + var session_buf: [20]u8 = undefined; + var session_fbs = std.io.fixedBufferStream(&session_buf); + reader.streamUntilDelimiter(session_fbs.writer(), '\n', 20) catch {}; - const session_index = reader.readIntLittle(u64) catch return .{}; + const session_index_str = session_fbs.getWritten(); + var session_index: ?u64 = null; + if (session_index_str.len > 0) { + session_index = std.fmt.parseUnsigned(u64, session_index_str, 10) catch return save; + } + save.session_index = session_index; - const save = .{ - .user = user_buffer, - .session_index = session_index, - }; + const new_save_file = std.fs.cwd().createFile(new_path, .{}) catch return save; + ini.writeFromStruct(save, new_save_file.writer(), null) catch return save; - ini.writeFromStruct(save, file.writer(), null) catch return save; + // Delete old save file + std.fs.deleteFileAbsolute(old_path) catch {}; return save; } diff --git a/src/main.zig b/src/main.zig index 07bd6e8..a57eb98 100644 --- a/src/main.zig +++ b/src/main.zig @@ -16,7 +16,6 @@ const Config = @import("config/Config.zig"); const Lang = @import("config/Lang.zig"); const Save = @import("config/Save.zig"); const migrator = @import("config/migrator.zig"); -const ViMode = @import("enums.zig").ViMode; const SharedError = @import("SharedError.zig"); const utils = @import("tui/utils.zig"); @@ -61,6 +60,7 @@ pub fn main() !void { var config: Config = undefined; var lang: Lang = undefined; + var save: Save = undefined; var info_line = InfoLine{}; if (res.args.help != 0) { @@ -81,6 +81,15 @@ pub fn main() !void { var lang_ini = Ini(Lang).init(allocator); defer lang_ini.deinit(); + var save_ini = Ini(Save).init(allocator); + defer save_ini.deinit(); + + var save_path: []const u8 = build_options.data_directory ++ "/save.ini"; + var save_path_alloc = false; + defer { + if (save_path_alloc) allocator.free(save_path); + } + if (res.args.config) |s| { const trailing_slash = if (s[s.len - 1] != '/') "/" else ""; @@ -93,6 +102,14 @@ pub fn main() !void { defer allocator.free(lang_path); lang = lang_ini.readToStruct(lang_path) catch Lang{}; + + if (config.load) { + save_path = try std.fmt.allocPrint(allocator, "{s}{s}save.ini", .{ s, trailing_slash }); + save_path_alloc = true; + + var user_buf: [32]u8 = undefined; + save = save_ini.readToStruct(save_path) catch migrator.tryMigrateSaveFile(&user_buf, config.save_file, save_path); + } } else { config = config_ini.readToStruct(build_options.data_directory ++ "/config.ini") catch Config{}; @@ -100,6 +117,11 @@ pub fn main() !void { defer allocator.free(lang_path); lang = lang_ini.readToStruct(lang_path) catch Lang{}; + + if (config.load) { + var user_buf: [32]u8 = undefined; + save = save_ini.readToStruct(save_path) catch migrator.tryMigrateSaveFile(&user_buf, config.save_file, save_path); + } } // Initialize information line with host name @@ -151,11 +173,11 @@ pub fn main() !void { var desktop = try Desktop.init(allocator, &buffer, config.max_desktop_len, lang); defer desktop.deinit(); - desktop.addEnvironment(lang.shell, "", .shell) catch { + desktop.addEnvironment(.{ .Name = lang.shell }, .shell) catch { try info_line.setText(lang.err_alloc); }; if (config.xinitrc) |xinitrc| { - desktop.addEnvironment(lang.xinitrc, xinitrc, .xinitrc) catch { + desktop.addEnvironment(.{ .Name = lang.xinitrc, .Exec = xinitrc }, .xinitrc) catch { try info_line.setText(lang.err_alloc); }; } @@ -174,16 +196,10 @@ pub fn main() !void { // Load last saved username and desktop selection, if any if (config.load) { - var save_ini = Ini(Save).init(allocator); - defer save_ini.deinit(); - - // If it fails, we try to migrate the potentially old save file. And if we can't do that, we just create - // a new save file - const save = save_ini.readToStruct(config.save_file) catch migrator.tryMigrateSaveFile(allocator, config.save_file); - if (save.user) |user| { try login.text.appendSlice(user); login.end = user.len; + login.cursor = login.end; active_input = .password; } @@ -487,11 +503,8 @@ pub fn main() !void { run = false; } else if (pressed_key == sleep_key) { if (config.sleep_cmd) |sleep_cmd| { - const pid = try std.os.fork(); - if (pid == 0) { - std.process.execv(allocator, &[_][]const u8{ "/bin/sh", "-c", sleep_cmd }) catch std.os.exit(1); - std.os.exit(0); - } + var sleep = std.ChildProcess.init(&[_][]const u8{ "/bin/sh", "-c", sleep_cmd }, allocator); + _ = sleep.spawnAndWait() catch .{}; } } }, @@ -529,7 +542,7 @@ pub fn main() !void { }, termbox.TB_KEY_ENTER => { if (config.save) save_last_settings: { - var file = std.fs.createFileAbsolute(config.save_file, .{}) catch break :save_last_settings; + var file = std.fs.createFileAbsolute(save_path, .{}) catch break :save_last_settings; defer file.close(); const save_data = Save{ @@ -542,17 +555,24 @@ pub fn main() !void { var shared_err = try SharedError.init(); defer shared_err.deinit(); - session_pid = try std.os.fork(); - if (session_pid == 0) { - auth.authenticate(allocator, config, desktop, login, &password) catch |err| { - shared_err.writeError(err); - std.os.exit(1); - }; - std.os.exit(0); - } + { + const login_text = try allocator.dupeZ(u8, login.text.items); + defer allocator.free(login_text); + const password_text = try allocator.dupeZ(u8, password.text.items); + defer allocator.free(password_text); - _ = std.os.waitpid(session_pid, 0); - session_pid = -1; + session_pid = try std.os.fork(); + if (session_pid == 0) { + auth.authenticate(config, desktop, login_text, password_text) catch |err| { + shared_err.writeError(err); + std.os.exit(1); + }; + std.os.exit(0); + } + + _ = std.os.waitpid(session_pid, 0); + session_pid = -1; + } var auth_err = shared_err.readError(); if (auth_err) |err| { @@ -571,11 +591,8 @@ pub fn main() !void { update = true; - const pid = try std.os.fork(); - if (pid == 0) { - std.process.execv(allocator, &[_][]const u8{ "/bin/sh", "-c", config.term_restore_cursor_cmd }) catch std.os.exit(1); - std.os.exit(0); - } + var restore_cursor = std.ChildProcess.init(&[_][]const u8{ "/bin/sh", "-c", config.term_restore_cursor_cmd }, allocator); + _ = restore_cursor.spawnAndWait() catch .{}; }, else => { if (!insert_mode) { diff --git a/src/tui/TerminalBuffer.zig b/src/tui/TerminalBuffer.zig index fd3d11f..8e95886 100644 --- a/src/tui/TerminalBuffer.zig +++ b/src/tui/TerminalBuffer.zig @@ -4,7 +4,6 @@ const interop = @import("../interop.zig"); const utils = @import("utils.zig"); const Config = @import("../config/Config.zig"); -const Allocator = std.mem.Allocator; const Random = std.rand.Random; const termbox = interop.termbox; diff --git a/src/tui/components/Desktop.zig b/src/tui/components/Desktop.zig index 80e7666..b830eab 100644 --- a/src/tui/components/Desktop.zig +++ b/src/tui/components/Desktop.zig @@ -9,7 +9,6 @@ const Allocator = std.mem.Allocator; const EnvironmentList = std.ArrayList(Environment); const DisplayServer = enums.DisplayServer; -const ViMode = enums.ViMode; const termbox = interop.termbox; @@ -17,8 +16,8 @@ const Desktop = @This(); pub const Environment = struct { entry_ini: ?Ini(Entry) = null, - name: []const u8 = "", - xdg_name: []const u8 = "", + name: [:0]const u8 = "", + xdg_name: [:0]const u8 = "", cmd: []const u8 = "", specifier: []const u8 = "", display_server: DisplayServer = .wayland, @@ -26,7 +25,8 @@ pub const Environment = struct { const DesktopEntry = struct { Exec: []const u8 = "", - Name: []const u8 = "", + Name: [:0]const u8 = "", + DesktopNames: [:0]const u8 = "", }; pub const Entry = struct { Desktop_Entry: DesktopEntry = DesktopEntry{} }; @@ -67,12 +67,12 @@ pub fn position(self: *Desktop, x: u64, y: u64, visible_length: u64) void { self.visible_length = visible_length; } -pub fn addEnvironment(self: *Desktop, name: []const u8, cmd: []const u8, display_server: DisplayServer) !void { +pub fn addEnvironment(self: *Desktop, entry: DesktopEntry, display_server: DisplayServer) !void { try self.environments.append(.{ .entry_ini = null, - .name = name, - .xdg_name = getXdgName(name), - .cmd = cmd, + .name = entry.Name, + .xdg_name = entry.DesktopNames, + .cmd = entry.Exec, .specifier = switch (display_server) { .wayland => self.lang.wayland, .x11 => self.lang.x11, @@ -84,12 +84,13 @@ pub fn addEnvironment(self: *Desktop, name: []const u8, cmd: []const u8, display self.current = self.environments.items.len - 1; } -pub fn addEnvironmentWithIni(self: *Desktop, entry_ini: Ini(Entry), name: []const u8, cmd: []const u8, display_server: DisplayServer) !void { +pub fn addEnvironmentWithIni(self: *Desktop, entry_ini: Ini(Entry), display_server: DisplayServer) !void { + const entry = entry_ini.data.Desktop_Entry; try self.environments.append(.{ .entry_ini = entry_ini, - .name = name, - .xdg_name = getXdgName(name), - .cmd = cmd, + .name = entry.Name, + .xdg_name = entry.DesktopNames, + .cmd = entry.Exec, .specifier = switch (display_server) { .wayland => self.lang.wayland, .x11 => self.lang.x11, @@ -112,9 +113,9 @@ pub fn crawl(self: *Desktop, path: []const u8, display_server: DisplayServer) !v const entry_path = try std.fmt.allocPrint(self.allocator, "{s}/{s}", .{ path, item.name }); defer self.allocator.free(entry_path); var entry_ini = Ini(Entry).init(self.allocator); - var entry = try entry_ini.readToStruct(entry_path); + _ = try entry_ini.readToStruct(entry_path); - try self.addEnvironmentWithIni(entry_ini, entry.Desktop_Entry.Name, entry.Desktop_Entry.Exec, display_server); + try self.addEnvironmentWithIni(entry_ini, display_server); } } @@ -173,8 +174,3 @@ fn goRight(self: *Desktop) void { self.current += 1; } - -fn getXdgName(name: []const u8) []const u8 { - // TODO - return name; -} diff --git a/src/tui/components/Text.zig b/src/tui/components/Text.zig index 934e97e..22c0fc4 100644 --- a/src/tui/components/Text.zig +++ b/src/tui/components/Text.zig @@ -2,7 +2,6 @@ const std = @import("std"); const interop = @import("../../interop.zig"); const TerminalBuffer = @import("../TerminalBuffer.zig"); const utils = @import("../utils.zig"); -const ViMode = @import("../../enums.zig").ViMode; const Allocator = std.mem.Allocator; const DynamicString = std.ArrayList(u8);