diff --git a/res/config.ini b/res/config.ini index 3efc716..539a425 100644 --- a/res/config.ini +++ b/res/config.ini @@ -272,9 +272,6 @@ sleep_key = F3 # Center the session name. text_in_center = false -# TTY in use -tty = $DEFAULT_TTY - # Default vi mode # normal -> normal mode # insert -> insert mode diff --git a/src/config/Config.zig b/src/config/Config.zig index 26eb29a..fb782ac 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -72,7 +72,6 @@ shutdown_key: []const u8 = "F1", sleep_cmd: ?[]const u8 = null, sleep_key: []const u8 = "F3", text_in_center: bool = false, -tty: u8 = build_options.tty, vi_default_mode: ViMode = .normal, vi_mode: bool = false, waylandsessions: []const u8 = build_options.prefix_directory ++ "/share/wayland-sessions", diff --git a/src/interop.zig b/src/interop.zig index 940c297..0c30be7 100644 --- a/src/interop.zig +++ b/src/interop.zig @@ -84,6 +84,73 @@ fn PlatformStruct() type { std.posix.setgid(@intCast(entry.gid)) catch return error.SetUserGidFailed; std.posix.setuid(@intCast(entry.uid)) catch return error.SetUserUidFailed; } + + // Procedure: + // 1. Open /proc/self/stat to retrieve the tty_nr field + // 2. Parse the tty_nr field to extract the major and minor device + // numbers + // 3. Then, read every /sys/class/tty/[dir]/dev, where [dir] is every + // sub-directory + // 4. Finally, compare the major and minor device numbers with the + // extracted values. If they correspond, parse [dir] to get the + // TTY ID + pub fn getActiveTtyImpl(allocator: std.mem.Allocator) !u8 { + var file_buffer: [256]u8 = undefined; + var tty_major: u16 = undefined; + var tty_minor: u16 = undefined; + + { + var file = try std.fs.openFileAbsolute("/proc/self/stat", .{}); + defer file.close(); + + var reader = file.reader(&file_buffer); + var buffer: [1024]u8 = undefined; + const read = try reader.read(&buffer); + + var iterator = std.mem.splitScalar(u8, buffer[0..read], ' '); + var fields: [52][]const u8 = undefined; + var index: usize = 0; + + while (iterator.next()) |field| { + fields[index] = field; + index += 1; + } + + const tty_nr = try std.fmt.parseInt(u16, fields[6], 10); + tty_major = tty_nr / 256; + tty_minor = tty_nr % 256; + } + + var directory = try std.fs.openDirAbsolute("/sys/class/tty", .{ .iterate = true }); + defer directory.close(); + + var iterator = directory.iterate(); + while (try iterator.next()) |entry| { + const path = try std.fmt.allocPrint(allocator, "/sys/class/tty/{s}/dev", .{entry.name}); + defer allocator.free(path); + + var file = try std.fs.openFileAbsolute(path, .{}); + defer file.close(); + + var reader = file.reader(&file_buffer); + var buffer: [16]u8 = undefined; + const read = try reader.read(&buffer); + + var device_iterator = std.mem.splitScalar(u8, buffer[0..(read - 1)], ':'); + const device_major_str = device_iterator.next() orelse continue; + const device_minor_str = device_iterator.next() orelse continue; + + const device_major = try std.fmt.parseInt(u8, device_major_str, 10); + const device_minor = try std.fmt.parseInt(u8, device_minor_str, 10); + + if (device_major == tty_major and device_minor == tty_minor) { + const tty_id_str = entry.name["tty".len..]; + return try std.fmt.parseInt(u8, tty_id_str, 10); + } + } + + return error.NoTtyFound; + } }, .freebsd => struct { pub const kbio = @cImport({ @@ -142,6 +209,10 @@ pub fn getTimeOfDay() !TimeOfDay { }; } +pub fn getActiveTty(allocator: std.mem.Allocator) !u8 { + return platform_struct.getActiveTtyImpl(allocator); +} + 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; diff --git a/src/main.zig b/src/main.zig index 2abce0b..65298ac 100644 --- a/src/main.zig +++ b/src/main.zig @@ -58,6 +58,7 @@ pub fn main() !void { var restart = false; var shutdown_cmd: []const u8 = undefined; var restart_cmd: []const u8 = undefined; + var commands_allocated = false; var stderr_buffer: [128]u8 = undefined; var stderr_writer = std.fs.File.stderr().writer(&stderr_buffer); @@ -75,8 +76,11 @@ pub fn main() !void { stderr.flush() catch std.process.exit(1); } else { // The user has quit Ly using Ctrl+C - temporary_allocator.free(shutdown_cmd); - temporary_allocator.free(restart_cmd); + if (commands_allocated) { + // Necessary if we error out before allocating + temporary_allocator.free(shutdown_cmd); + temporary_allocator.free(restart_cmd); + } } } @@ -242,6 +246,7 @@ pub fn main() !void { // we end up shutting down or restarting the system shutdown_cmd = try temporary_allocator.dupe(u8, config.shutdown_cmd); restart_cmd = try temporary_allocator.dupe(u8, config.restart_cmd); + commands_allocated = true; // Initialize termbox try log_writer.writeAll("initializing termbox2\n"); @@ -478,7 +483,8 @@ pub fn main() !void { var auth_fails: u64 = 0; // Switch to selected TTY - interop.switchTty(config.tty) catch |err| { + const active_tty = try interop.getActiveTty(allocator); + interop.switchTty(active_tty) catch |err| { try info_line.addMessage(lang.err_switch_tty, config.error_bg, config.error_fg); try log_writer.print("failed to switch tty: {s}\n", .{@errorName(err)}); }; @@ -843,7 +849,7 @@ pub fn main() !void { if (session_pid == 0) { const current_environment = session.label.list.items[session.label.current]; const auth_options = auth.AuthOptions{ - .tty = config.tty, + .tty = active_tty, .service_name = config.service_name, .path = config.path, .session_log = config.session_log,