8 Commits

Author SHA1 Message Date
AnErrupTion
edbb982c91 [Backport] Recursively create xauth file directory if non-existent
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2025-12-30 20:55:41 +01:00
AnErrupTion
80fb07daa8 [Backport] Fix invalid XDG_RUNTIME_DIR if D-Bus isn't used
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2025-12-30 20:54:47 +01:00
AnErrupTion
93388159bc [Backport] Clamp user session index if invalid
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2025-12-30 18:12:28 +01:00
AnErrupTion
08b4a49729 [Backport] Check for session file name in autologin
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2025-12-30 17:45:29 +01:00
AnErrupTion
066acf91e6 [Backport] Create session log directory if non-existent
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2025-12-30 17:29:31 +01:00
AnErrupTion
2660486fde [Backport] Escape TTY in systemd service
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2025-12-30 17:28:50 +01:00
AnErrupTion
a3b249ded8 [Backport] Fix session not being saved correctly
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2025-12-30 17:27:04 +01:00
AnErrupTion
3c22597054 Start Ly v1.3.1 development cycle
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2025-12-30 17:26:53 +01:00
9 changed files with 49 additions and 34 deletions

View File

@@ -23,7 +23,7 @@ comptime {
}
}
const ly_version = std.SemanticVersion{ .major = 1, .minor = 3, .patch = 0 };
const ly_version = std.SemanticVersion{ .major = 1, .minor = 3, .patch = 1 };
var dest_directory: []const u8 = undefined;
var config_directory: []const u8 = undefined;

View File

@@ -1,6 +1,6 @@
.{
.name = .ly,
.version = "1.3.0",
.version = "1.3.1",
.fingerprint = 0xa148ffcc5dc2cb59,
.minimum_zig_version = "0.15.0",
.dependencies = .{

View File

@@ -121,9 +121,15 @@ that Ly will run on, otherwise bad things will happen. For example, to disable `
# systemctl disable getty@tty2.service
```
You can change the TTY Ly will run on by editing the corresponding
service file for your platform, or on systemd, by enabling the service on
different TTYs, as is done above.
On platforms that use systemd-logind to dynamically start `autovt@.service` instances when the switch to a new tty occurs, any ly instances for ttys *except the default tty* need to be enabled using a different mechanism: To autostart ly on switch to `tty2`, do not enable any `ly` unit directly, instead symlink `autovt@tty2.service` to `ly@tty2.service` within `/usr/lib/systemd/system/` (analogous for every other tty you want to enable ly on).
The target of the symlink, `ly@ttyN.service`, does not actually exist, but systemd nevertheless recognizes that the instanciation of `autovt@.service` with `%I` equal to `ttyN` now points to an instanciation of `ly@.service` with `%I` set to `ttyN`.
Compare to `man 5 logind.conf`, especially regarding the `NAutoVTs=` and `ReserveVT=` parameters.
On non-systemd systems, you can change the TTY Ly will run on by editing the corresponding
service file for your platform.
### OpenRC

View File

@@ -1,8 +1,8 @@
[Unit]
Description=TUI display manager
After=systemd-user-sessions.service plymouth-quit-wait.service
After=getty@%I.service
Conflicts=getty@%I.service
After=getty@%i.service
Conflicts=getty@%i.service
[Service]
Type=idle

View File

@@ -14,9 +14,9 @@ pub const DesktopEntry = struct {
pub const Entry = struct { @"Desktop Entry": DesktopEntry = .{} };
entry_ini: ?Ini(Entry) = null,
file_name: []const u8 = "",
name: []const u8 = "",
xdg_session_desktop: ?[]const u8 = null,
xdg_session_desktop_owned: bool = false,
xdg_desktop_names: ?[]const u8 = null,
cmd: ?[]const u8 = null,
specifier: []const u8 = "",

View File

@@ -169,6 +169,7 @@ fn startSession(
// Reset the XDG environment variables
try setXdgEnv(allocator, tty_str, current_environment);
try setXdgRuntimeDir(allocator);
// Set the PAM variables
const pam_env_vars: ?[*:null]?[*:0]u8 = interop.pam.pam_getenvlist(handle);
@@ -217,6 +218,15 @@ fn setXdgEnv(allocator: std.mem.Allocator, tty_str: []u8, environment: Environme
.custom => if (environment.is_terminal) "tty" else "unspecified",
}, false);
if (environment.xdg_desktop_names) |xdg_desktop_names| try interop.setEnvironmentVariable(allocator, "XDG_CURRENT_DESKTOP", xdg_desktop_names, false);
try interop.setEnvironmentVariable(allocator, "XDG_SESSION_CLASS", "user", false);
try interop.setEnvironmentVariable(allocator, "XDG_SESSION_ID", "1", false);
if (environment.xdg_session_desktop) |desktop_name| try interop.setEnvironmentVariable(allocator, "XDG_SESSION_DESKTOP", desktop_name, false);
try interop.setEnvironmentVariable(allocator, "XDG_SEAT", "seat0", false);
try interop.setEnvironmentVariable(allocator, "XDG_VTNR", tty_str, false);
}
fn setXdgRuntimeDir(allocator: std.mem.Allocator) !void {
// The "/run/user/%d" directory is not available on FreeBSD. It is much
// better to stick to the defaults and let applications using
// XDG_RUNTIME_DIR to fall back to directories inside user's home
@@ -228,13 +238,6 @@ fn setXdgEnv(allocator: std.mem.Allocator, tty_str: []u8, environment: Environme
try interop.setEnvironmentVariable(allocator, "XDG_RUNTIME_DIR", uid_str, false);
}
if (environment.xdg_desktop_names) |xdg_desktop_names| try interop.setEnvironmentVariable(allocator, "XDG_CURRENT_DESKTOP", xdg_desktop_names, false);
try interop.setEnvironmentVariable(allocator, "XDG_SESSION_CLASS", "user", false);
try interop.setEnvironmentVariable(allocator, "XDG_SESSION_ID", "1", false);
if (environment.xdg_session_desktop) |desktop_name| try interop.setEnvironmentVariable(allocator, "XDG_SESSION_DESKTOP", desktop_name, false);
try interop.setEnvironmentVariable(allocator, "XDG_SEAT", "seat0", false);
try interop.setEnvironmentVariable(allocator, "XDG_VTNR", tty_str, false);
}
fn loginConv(
@@ -366,7 +369,7 @@ fn createXauthFile(pwd: []const u8, buffer: []u8) ![]const u8 {
const xauthority: []u8 = try std.fmt.bufPrint(buffer, "{s}/{s}", .{ trimmed_xauth_dir, xauth_file });
std.fs.makeDirAbsolute(trimmed_xauth_dir) catch {};
std.fs.cwd().makePath(trimmed_xauth_dir) catch {};
const file = try std.fs.createFileAbsolute(xauthority, .{});
file.close();
@@ -502,6 +505,14 @@ fn executeCmd(global_log_file: *LogFile, allocator: std.mem.Allocator, shell: []
}
fn redirectStandardStreams(global_log_file: *LogFile, session_log: []const u8, create: bool) !std.fs.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.file_writer.interface.print("failed to create session log file directory: {s}\n", .{@errorName(err)});
return err;
};
}
const log_file = if (create) (std.fs.cwd().createFile(session_log, .{ .mode = 0o666 }) catch |err| {
try global_log_file.file_writer.interface.print("failed to create new session log file: {s}\n", .{@errorName(err)});
return err;

View File

@@ -529,7 +529,7 @@ pub fn main() !void {
active_input = .password;
if (user.session_index < session.label.list.items.len) session.label.current = user.session_index;
session.label.current = @min(user.session_index, session.label.list.items.len - 1);
}
}
@@ -1251,10 +1251,10 @@ fn crawl(session: *Session, lang: Lang, path: []const u8, display_server: Displa
});
errdefer entry_ini.deinit();
const file_name = try session.label.allocator.dupe(u8, std.fs.path.stem(item.name));
const entry = entry_ini.data.@"Desktop Entry";
var maybe_xdg_session_desktop: ?[]const u8 = null;
var maybe_xdg_desktop_names: ?[]const u8 = null;
var xdg_session_desktop_owned = false;
// Prepare the XDG_SESSION_DESKTOP and XDG_CURRENT_DESKTOP environment
// variables here
@@ -1268,18 +1268,14 @@ fn crawl(session: *Session, lang: Lang, path: []const u8, display_server: Displa
} else if (display_server != .custom) {
// If DesktopNames is empty, and this isn't a custom session entry,
// we'll take the name of the session file
const stem = std.fs.path.stem(item.name);
if (stem.len > 0) {
maybe_xdg_session_desktop = try session.label.allocator.dupe(u8, stem);
xdg_session_desktop_owned = true;
}
if (file_name.len > 0) maybe_xdg_session_desktop = file_name;
}
try session.addEnvironment(.{
.entry_ini = entry_ini,
.file_name = file_name,
.name = entry.Name,
.xdg_session_desktop = maybe_xdg_session_desktop,
.xdg_session_desktop_owned = xdg_session_desktop_owned,
.xdg_desktop_names = maybe_xdg_desktop_names,
.cmd = entry.Exec,
.specifier = switch (display_server) {
@@ -1310,6 +1306,7 @@ fn findSessionByName(session: *Session, name: []const u8) ?usize {
if (std.ascii.eqlIgnoreCase(session_desktop_name, name)) return i;
}
if (std.ascii.eqlIgnoreCase(env.environment.name, name)) return i;
if (std.ascii.eqlIgnoreCase(env.environment.file_name, name)) return i;
}
return null;
}

View File

@@ -29,9 +29,7 @@ pub fn init(allocator: Allocator, buffer: *TerminalBuffer, user_list: *UserList)
pub fn deinit(self: *Session) void {
for (self.label.list.items) |*env| {
if (env.environment.entry_ini) |*entry_ini| entry_ini.deinit();
if (env.environment.xdg_session_desktop_owned) {
self.label.allocator.free(env.environment.xdg_session_desktop.?);
}
self.label.allocator.free(env.environment.file_name);
}
self.label.deinit();
@@ -41,15 +39,19 @@ pub fn addEnvironment(self: *Session, environment: Environment) !void {
const env = Env{ .environment = environment, .index = self.label.list.items.len };
try self.label.addItem(env);
sessionChanged(env, self.user_list);
addedSession(env, self.user_list);
}
fn addedSession(env: Env, user_list: *UserList) void {
const user = user_list.label.list.items[user_list.label.current];
if (!user.first_run) return;
user.session_index.* = env.index;
}
fn sessionChanged(env: Env, maybe_user_list: ?*UserList) void {
if (maybe_user_list) |user_list| {
const user = user_list.label.list.items[user_list.label.current];
if (!user.first_run) return;
user.session_index.* = env.index;
user_list.label.list.items[user_list.label.current].session_index.* = env.index;
}
}

View File

@@ -71,8 +71,7 @@ pub fn getCurrentUsername(self: UserList) []const u8 {
fn usernameChanged(user: User, maybe_session: ?*Session) void {
if (maybe_session) |session| {
if (user.session_index.* >= session.label.list.items.len) return;
session.label.current = user.session_index.*;
session.label.current = @min(user.session_index.*, session.label.list.items.len - 1);
}
}