Automatically detect TTY (closes #795)

Signed-off-by: AnErrupTion <anerruption@disroot.org>
This commit is contained in:
AnErrupTion 2025-09-07 17:44:50 +02:00
parent 5924db58e1
commit ee97f3b5e1
No known key found for this signature in database
4 changed files with 81 additions and 8 deletions

View File

@ -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

View File

@ -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",

View File

@ -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;

View File

@ -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,