19 Commits

Author SHA1 Message Date
AnErrupTion
4b9ea3d7cb Backport: Possibly fix .Xresources not being loaded
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2025-03-06 21:18:33 +01:00
AnErrupTion
83984dc493 Backport: Don't set XDG_CURRENT_DESKTOP and XDG_SESSION_DESKTOP if they're empty
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2025-03-05 22:54:34 +01:00
AnErrupTion
a9449742d6 Backport: Try to create /etc/pam.d and /usr/bin everytime when installing
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2025-03-05 22:52:34 +01:00
AnErrupTion
ea2dec50f5 Update README.md
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2024-08-02 19:40:25 +02:00
AnErrupTion
fadbbf676a Support Zig 0.13.0
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2024-08-02 19:40:09 +02:00
AnErrupTion
042aa50ff0 Start Ly v1.0.3 development cycle
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2024-08-02 19:37:11 +02:00
AnErrupTion
56202bc30e Backport: Swap /usr/bin and /usr/sbin in PATH
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2024-08-01 18:02:03 +02:00
AnErrupTion
7300247e57 Backport: Update zigini (fixes an escaping bug)
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2024-08-01 13:29:34 +02:00
AnErrupTion
3ca2e8524b Fix mcookie usage (fixes #669)
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2024-08-01 13:20:23 +02:00
AnErrupTion
40d180da63 Backport: Only shutdown or restart after deinitializing everything
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2024-07-30 12:04:25 +02:00
AnErrupTion
75cc971f9c Backport: Update zigini (fixes incorrect comment parsing)
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2024-07-30 09:51:42 +02:00
AnErrupTion
9374d2df32 Backport: Fix clock & bigclock not updating without input
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2024-07-29 14:19:47 +02:00
AnErrupTion
67fd024f6a Revert "Redirect stderr to systemd journal in service (#621)"
This reverts commit 3d8d8d67df.

Signed-off-by: AnErrupTion <anerruption@disroot.org>
2024-07-29 13:35:04 +02:00
AnErrupTion
5796720a9c Backport: Add missing supervise symlink on runit
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2024-07-28 11:35:23 +02:00
AnErrupTion
802ad6bbed Backport: Set PAM_TTY
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2024-07-27 22:45:20 +02:00
AnErrupTion
7ece95965b Backport: Fix ~/.profile not being loaded with Fish
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2024-07-27 22:44:35 +02:00
AnErrupTion
10cd9615ef Backport: Fix possible overflow with TTY ID
Co-authored-by: Kevin Morris <kevr@0cost.org>
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2024-07-27 21:07:41 +02:00
AnErrupTion
a807e8e11c Backport: Use default PRNG and retrieve better seed
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2024-07-27 14:25:30 +02:00
AnErrupTion
d87344330a Start Ly v1.0.2 development cycle
Signed-off-by: AnErrupTion <anerruption@disroot.org>
2024-07-27 14:18:09 +02:00
14 changed files with 134 additions and 70 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@
zig-cache/ zig-cache/
zig-out/ zig-out/
valgrind.log valgrind.log
.zig-cache

View File

@@ -1,10 +1,24 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin");
const ly_version = std.SemanticVersion{ .major = 1, .minor = 0, .patch = 1 }; const min_zig_string = "0.12.0";
const current_zig = builtin.zig_version;
// Implementing zig version detection through compile time
comptime {
const min_zig = std.SemanticVersion.parse(min_zig_string) catch unreachable;
if (current_zig.order(min_zig) == .lt) {
@compileError(std.fmt.comptimePrint("Your Zig version v{} does not meet the minimum build requirement of v{}", .{ current_zig, min_zig }));
}
}
const ly_version = std.SemanticVersion{ .major = 1, .minor = 0, .patch = 3 };
var dest_directory: []const u8 = undefined; var dest_directory: []const u8 = undefined;
var data_directory: []const u8 = undefined; var data_directory: []const u8 = undefined;
var exe_name: []const u8 = undefined; var exe_name: []const u8 = undefined;
const ProgressNode = if (current_zig.minor == 12) *std.Progress.Node else std.Progress.Node;
pub fn build(b: *std.Build) !void { pub fn build(b: *std.Build) !void {
dest_directory = b.option([]const u8, "dest_directory", "Specify a destination directory for installation") orelse ""; dest_directory = b.option([]const u8, "dest_directory", "Specify a destination directory for installation") orelse "";
data_directory = b.option([]const u8, "data_directory", "Specify a default data directory (default is /etc/ly). This path gets embedded into the binary") orelse "/etc/ly"; data_directory = b.option([]const u8, "data_directory", "Specify a default data directory (default is /etc/ly). This path gets embedded into the binary") orelse "/etc/ly";
@@ -25,7 +39,7 @@ pub fn build(b: *std.Build) !void {
const exe = b.addExecutable(.{ const exe = b.addExecutable(.{
.name = "ly", .name = "ly",
.root_source_file = .{ .path = "src/main.zig" }, .root_source_file = b.path("src/main.zig"),
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
}); });
@@ -38,14 +52,14 @@ pub fn build(b: *std.Build) !void {
const clap = b.dependency("clap", .{ .target = target, .optimize = optimize }); const clap = b.dependency("clap", .{ .target = target, .optimize = optimize });
exe.root_module.addImport("clap", clap.module("clap")); exe.root_module.addImport("clap", clap.module("clap"));
exe.addIncludePath(.{ .path = "include" }); exe.addIncludePath(b.path("include"));
exe.linkSystemLibrary("pam"); exe.linkSystemLibrary("pam");
exe.linkSystemLibrary("xcb"); exe.linkSystemLibrary("xcb");
exe.linkLibC(); exe.linkLibC();
// HACK: Only fails with ReleaseSafe, so we'll override it. // HACK: Only fails with ReleaseSafe, so we'll override it.
const translate_c = b.addTranslateC(.{ const translate_c = b.addTranslateC(.{
.root_source_file = .{ .path = "include/termbox2.h" }, .root_source_file = b.path("include/termbox2.h"),
.target = target, .target = target,
.optimize = if (optimize == .ReleaseSafe) .ReleaseFast else optimize, .optimize = if (optimize == .ReleaseSafe) .ReleaseFast else optimize,
}); });
@@ -94,7 +108,7 @@ pub fn build(b: *std.Build) !void {
pub fn ExeInstaller(install_conf: bool) type { pub fn ExeInstaller(install_conf: bool) type {
return struct { return struct {
pub fn make(step: *std.Build.Step, progress: *std.Progress.Node) !void { pub fn make(step: *std.Build.Step, progress: ProgressNode) !void {
_ = progress; _ = progress;
try install_ly(step.owner.allocator, install_conf); try install_ly(step.owner.allocator, install_conf);
} }
@@ -108,7 +122,7 @@ const InitSystem = enum {
}; };
pub fn ServiceInstaller(comptime init_system: InitSystem) type { pub fn ServiceInstaller(comptime init_system: InitSystem) type {
return struct { return struct {
pub fn make(step: *std.Build.Step, progress: *std.Progress.Node) !void { pub fn make(step: *std.Build.Step, progress: ProgressNode) !void {
_ = progress; _ = progress;
const allocator = step.owner.allocator; const allocator = step.owner.allocator;
switch (init_system) { switch (init_system) {
@@ -126,9 +140,12 @@ pub fn ServiceInstaller(comptime init_system: InitSystem) type {
var service_dir = std.fs.cwd().openDir(service_path, .{}) catch unreachable; var service_dir = std.fs.cwd().openDir(service_path, .{}) catch unreachable;
defer service_dir.close(); defer service_dir.close();
const supervise_path = try std.fs.path.join(allocator, &[_][]const u8{ service_path, "supervise" });
try std.fs.cwd().copyFile("res/ly-runit-service/conf", service_dir, "conf", .{}); try std.fs.cwd().copyFile("res/ly-runit-service/conf", service_dir, "conf", .{});
try std.fs.cwd().copyFile("res/ly-runit-service/finish", service_dir, "finish", .{ .override_mode = 0o755 }); try std.fs.cwd().copyFile("res/ly-runit-service/finish", service_dir, "finish", .{ .override_mode = 0o755 });
try std.fs.cwd().copyFile("res/ly-runit-service/run", service_dir, "run", .{ .override_mode = 0o755 }); try std.fs.cwd().copyFile("res/ly-runit-service/run", service_dir, "run", .{ .override_mode = 0o755 });
try std.fs.cwd().symLink("/run/runit/supervise.ly", supervise_path, .{});
}, },
.Systemd => { .Systemd => {
const service_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, "/usr/lib/systemd/system" }); const service_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, "/usr/lib/systemd/system" });
@@ -157,11 +174,11 @@ fn install_ly(allocator: std.mem.Allocator, install_config: bool) !void {
{ {
const exe_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, "/usr/bin" }); const exe_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, "/usr/bin" });
if (!std.mem.eql(u8, dest_directory, "")) { std.fs.cwd().makePath(exe_path) catch {
std.fs.cwd().makePath(exe_path) catch { if (!std.mem.eql(u8, dest_directory, "")) {
std.debug.print("warn: {s} already exists as a directory.\n", .{exe_path}); std.debug.print("warn: {s} already exists as a directory.\n", .{exe_path});
}; }
} };
var executable_dir = std.fs.cwd().openDir(exe_path, .{}) catch unreachable; var executable_dir = std.fs.cwd().openDir(exe_path, .{}) catch unreachable;
defer executable_dir.close(); defer executable_dir.close();
@@ -204,11 +221,12 @@ fn install_ly(allocator: std.mem.Allocator, install_config: bool) !void {
{ {
const pam_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, "/etc/pam.d" }); const pam_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, "/etc/pam.d" });
if (!std.mem.eql(u8, dest_directory, "")) {
std.fs.cwd().makePath(pam_path) catch { std.fs.cwd().makePath(pam_path) catch {
if (!std.mem.eql(u8, dest_directory, "")) {
std.debug.print("warn: {s} already exists as a directory.\n", .{pam_path}); std.debug.print("warn: {s} already exists as a directory.\n", .{pam_path});
}; }
} };
var pam_dir = std.fs.cwd().openDir(pam_path, .{}) catch unreachable; var pam_dir = std.fs.cwd().openDir(pam_path, .{}) catch unreachable;
defer pam_dir.close(); defer pam_dir.close();
@@ -217,7 +235,7 @@ fn install_ly(allocator: std.mem.Allocator, install_config: bool) !void {
} }
} }
pub fn uninstallall(step: *std.Build.Step, progress: *std.Progress.Node) !void { pub fn uninstallall(step: *std.Build.Step, progress: ProgressNode) !void {
_ = progress; _ = progress;
try std.fs.cwd().deleteTree(data_directory); try std.fs.cwd().deleteTree(data_directory);
const allocator = step.owner.allocator; const allocator = step.owner.allocator;

View File

@@ -4,12 +4,12 @@
.minimum_zig_version = "0.12.0", .minimum_zig_version = "0.12.0",
.dependencies = .{ .dependencies = .{
.clap = .{ .clap = .{
.url = "https://github.com/Hejsil/zig-clap/archive/8c98e6404b22aafc0184e999d8f068b81cc22fa1.tar.gz", .url = "https://github.com/Hejsil/zig-clap/archive/refs/tags/0.9.1.tar.gz",
.hash = "122014e73fd712190e109950837b97f6143f02d7e2b6986e1db70b6f4aadb5ba6a0d", .hash = "122062d301a203d003547b414237229b09a7980095061697349f8bef41be9c30266b",
}, },
.zigini = .{ .zigini = .{
.url = "https://github.com/Kawaii-Ash/zigini/archive/ce1f322482099db058f5d9fdd05fbfa255d79723.tar.gz", .url = "https://github.com/Kawaii-Ash/zigini/archive/0bba97a12582928e097f4074cc746c43351ba4c8.tar.gz",
.hash = "1220e7a99793a0430e0a7c0b938cb3c98321035bc297e21cd0e2413cf740b4923b9f", .hash = "12209b971367b4066d40ecad4728e6fdffc4cc4f19356d424c2de57f5b69ac7a619a",
}, },
}, },
.paths = .{""}, .paths = .{""},

View File

@@ -6,7 +6,7 @@ Ly is a lightweight TUI (ncurses-like) display manager for Linux and BSD.
## Dependencies ## Dependencies
- Compile-time: - Compile-time:
- zig 0.12.0 - zig 0.12.0 or 0.13.0
- a C standard library - a C standard library
- pam - pam
- xcb - xcb

View File

@@ -120,7 +120,7 @@ tty = 2
console_dev = /dev/console console_dev = /dev/console
# Default path. If null, ly doesn't set a path. # Default path. If null, ly doesn't set a path.
path = /sbin:/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin path = /sbin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
# Event timeout in milliseconds # Event timeout in milliseconds
min_refresh_delta = 5 min_refresh_delta = 5

View File

@@ -7,7 +7,6 @@ Conflicts=getty@tty2.service
[Service] [Service]
Type=idle Type=idle
ExecStart=/usr/bin/ly ExecStart=/usr/bin/ly
StandardError=journal
StandardInput=tty StandardInput=tty
TTYPath=/dev/tty2 TTYPath=/dev/tty2
TTYReset=yes TTYReset=yes

View File

@@ -40,6 +40,7 @@ case $SHELL in
;; ;;
*/fish) */fish)
[ -f /etc/profile ] && . /etc/profile [ -f /etc/profile ] && . /etc/profile
[ -f $HOME/.profile ] && . $HOME/.profile
xsess_tmp=`mktemp /tmp/xsess-env-XXXXXX` xsess_tmp=`mktemp /tmp/xsess-env-XXXXXX`
$SHELL --login -c "/bin/sh -c 'export -p' > $xsess_tmp" $SHELL --login -c "/bin/sh -c 'export -p' > $xsess_tmp"
. $xsess_tmp . $xsess_tmp

View File

@@ -40,6 +40,7 @@ case $SHELL in
;; ;;
*/fish) */fish)
[ -f /etc/profile ] && . /etc/profile [ -f /etc/profile ] && . /etc/profile
[ -f $HOME/.profile ] && . $HOME/.profile
xsess_tmp=`mktemp /tmp/xsess-env-XXXXXX` xsess_tmp=`mktemp /tmp/xsess-env-XXXXXX`
$SHELL --login -c "/bin/sh -c 'export -p' > $xsess_tmp" $SHELL --login -c "/bin/sh -c 'export -p' > $xsess_tmp"
. $xsess_tmp . $xsess_tmp
@@ -82,6 +83,10 @@ if [ -d "$xsessionddir" ]; then
done done
fi fi
if [ -f "$USERXSESSION" ]; then
. "$USERXSESSION"
fi
if [ -d /etc/X11/Xresources ]; then if [ -d /etc/X11/Xresources ]; then
for i in /etc/X11/Xresources/*; do for i in /etc/X11/Xresources/*; do
[ -f $i ] && xrdb -merge $i [ -f $i ] && xrdb -merge $i
@@ -92,10 +97,6 @@ fi
[ -f $HOME/.Xresources ] && xrdb -merge $HOME/.Xresources [ -f $HOME/.Xresources ] && xrdb -merge $HOME/.Xresources
[ -f $XDG_CONFIG_HOME/X11/Xresources ] && xrdb -merge $XDG_CONFIG_HOME/X11/Xresources [ -f $XDG_CONFIG_HOME/X11/Xresources ] && xrdb -merge $XDG_CONFIG_HOME/X11/Xresources
if [ -f "$USERXSESSION" ]; then
. "$USERXSESSION"
fi
if [ -z "$*" ]; then if [ -z "$*" ]; then
exec xmessage -center -buttons OK:0 -default OK "Sorry, $DESKTOP_SESSION is no valid session." exec xmessage -center -buttons OK:0 -default OK "Sorry, $DESKTOP_SESSION is no valid session."
else else

View File

@@ -21,9 +21,12 @@ pub fn sessionSignalHandler(i: c_int) callconv(.C) void {
} }
pub fn authenticate(config: Config, current_environment: Desktop.Environment, login: [:0]const u8, password: [:0]const u8) !void { pub fn authenticate(config: Config, current_environment: Desktop.Environment, login: [:0]const u8, password: [:0]const u8) !void {
var tty_buffer: [2]u8 = undefined; var tty_buffer: [3]u8 = undefined;
const tty_str = try std.fmt.bufPrintZ(&tty_buffer, "{d}", .{config.tty}); const tty_str = try std.fmt.bufPrintZ(&tty_buffer, "{d}", .{config.tty});
var pam_tty_buffer: [6]u8 = undefined;
const pam_tty_str = try std.fmt.bufPrintZ(&pam_tty_buffer, "tty{d}", .{config.tty});
// Set the XDG environment variables // Set the XDG environment variables
setXdgSessionEnv(current_environment.display_server); setXdgSessionEnv(current_environment.display_server);
try setXdgEnv(tty_str, current_environment.xdg_session_desktop, current_environment.xdg_desktop_names orelse ""); try setXdgEnv(tty_str, current_environment.xdg_session_desktop, current_environment.xdg_desktop_names orelse "");
@@ -41,6 +44,10 @@ pub fn authenticate(config: Config, current_environment: Desktop.Environment, lo
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
defer _ = interop.pam.pam_end(handle, status); defer _ = interop.pam.pam_end(handle, status);
// Set PAM_TTY as the current TTY. This is required in case it isn't being set by another PAM module
status = interop.pam.pam_set_item(handle, interop.pam.PAM_TTY, pam_tty_str.ptr);
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
// Do the PAM routine // Do the PAM routine
status = interop.pam.pam_authenticate(handle, 0); status = interop.pam.pam_authenticate(handle, 0);
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
@@ -176,11 +183,11 @@ fn setXdgEnv(tty_str: [:0]u8, desktop_name: [:0]const u8, xdg_desktop_names: [:0
var uid_buffer: [10 + @sizeOf(u32) + 1]u8 = undefined; var uid_buffer: [10 + @sizeOf(u32) + 1]u8 = undefined;
const uid_str = try std.fmt.bufPrintZ(&uid_buffer, "/run/user/{d}", .{uid}); const uid_str = try std.fmt.bufPrintZ(&uid_buffer, "/run/user/{d}", .{uid});
_ = interop.setenv("XDG_CURRENT_DESKTOP", xdg_desktop_names.ptr, 0); if (!std.mem.eql(u8, xdg_desktop_names, "")) _ = interop.setenv("XDG_CURRENT_DESKTOP", xdg_desktop_names.ptr, 0);
_ = interop.setenv("XDG_RUNTIME_DIR", uid_str.ptr, 0); _ = interop.setenv("XDG_RUNTIME_DIR", uid_str.ptr, 0);
_ = interop.setenv("XDG_SESSION_CLASS", "user", 0); _ = interop.setenv("XDG_SESSION_CLASS", "user", 0);
_ = interop.setenv("XDG_SESSION_ID", "1", 0); _ = interop.setenv("XDG_SESSION_ID", "1", 0);
_ = interop.setenv("XDG_SESSION_DESKTOP", desktop_name.ptr, 0); if (!std.mem.eql(u8, desktop_name, "")) _ = interop.setenv("XDG_SESSION_DESKTOP", desktop_name.ptr, 0);
_ = interop.setenv("XDG_SEAT", "seat0", 0); _ = interop.setenv("XDG_SEAT", "seat0", 0);
_ = interop.setenv("XDG_VTNR", tty_str.ptr, 0); _ = interop.setenv("XDG_VTNR", tty_str.ptr, 0);
} }
@@ -327,7 +334,7 @@ fn createXauthFile(pwd: [:0]const u8) ![:0]const u8 {
return xauthority; return xauthority;
} }
pub fn mcookie(cmd: [:0]const u8) ![32]u8 { pub fn mcookie(shell: [*:0]const u8, cmd: [:0]const u8) ![32]u8 {
const pipe = try std.posix.pipe(); const pipe = try std.posix.pipe();
defer std.posix.close(pipe[1]); defer std.posix.close(pipe[1]);
@@ -341,8 +348,8 @@ pub fn mcookie(cmd: [:0]const u8) ![32]u8 {
std.posix.dup2(pipe[1], std.posix.STDOUT_FILENO) catch std.process.exit(1); std.posix.dup2(pipe[1], std.posix.STDOUT_FILENO) catch std.process.exit(1);
std.posix.close(pipe[1]); std.posix.close(pipe[1]);
const args = [_:null]?[*:0]u8{}; const args = [_:null]?[*:0]const u8{ shell, "-c", cmd };
std.posix.execveZ(cmd.ptr, &args, std.c.environ) catch {}; std.posix.execveZ(shell, &args, std.c.environ) catch {};
std.process.exit(1); std.process.exit(1);
} }
@@ -364,7 +371,7 @@ fn xauth(display_name: [:0]u8, shell: [*:0]const u8, pw_dir: [*:0]const u8, xaut
_ = interop.setenv("XAUTHORITY", xauthority, 1); _ = interop.setenv("XAUTHORITY", xauthority, 1);
_ = interop.setenv("DISPLAY", display_name, 1); _ = interop.setenv("DISPLAY", display_name, 1);
const mcookie_output = try mcookie(mcookie_cmd); const mcookie_output = try mcookie(shell, mcookie_cmd);
const pid = try std.posix.fork(); const pid = try std.posix.fork();
if (pid == 0) { if (pid == 0) {

View File

@@ -30,7 +30,7 @@ max_password_len: u8 = 255,
mcookie_cmd: [:0]const u8 = "/usr/bin/mcookie", mcookie_cmd: [:0]const u8 = "/usr/bin/mcookie",
min_refresh_delta: u16 = 5, min_refresh_delta: u16 = 5,
numlock: bool = false, numlock: bool = false,
path: ?[:0]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/sbin:/usr/bin",
restart_cmd: []const u8 = "/sbin/shutdown -r now", restart_cmd: []const u8 = "/sbin/shutdown -r now",
restart_key: []const u8 = "F2", restart_key: []const u8 = "F2",
save: bool = true, save: bool = true,

View File

@@ -1,7 +1,19 @@
// The migrator ensures compatibility with <=0.6.0 configuration files
const std = @import("std"); const std = @import("std");
const ini = @import("zigini"); const ini = @import("zigini");
const Save = @import("Save.zig"); const Save = @import("Save.zig");
pub fn configFieldHandler(_: std.mem.Allocator, field: ini.IniField) ?ini.IniField {
var mapped_field = field;
if (std.mem.eql(u8, field.key, "blank_password")) {
mapped_field.key = "clear_password";
}
return mapped_field;
}
pub fn tryMigrateSaveFile(user_buf: *[32]u8, path: []const u8) Save { pub fn tryMigrateSaveFile(user_buf: *[32]u8, path: []const u8) Save {
var save = Save{}; var save = Save{};

View File

@@ -21,6 +21,7 @@ const utils = @import("tui/utils.zig");
const Ini = ini.Ini; const Ini = ini.Ini;
const termbox = interop.termbox; const termbox = interop.termbox;
const temporary_allocator = std.heap.page_allocator;
var session_pid: std.posix.pid_t = -1; var session_pid: std.posix.pid_t = -1;
pub fn signalHandler(i: c_int) callconv(.C) void { pub fn signalHandler(i: c_int) callconv(.C) void {
@@ -38,11 +39,32 @@ pub fn signalHandler(i: c_int) callconv(.C) void {
} }
pub fn main() !void { pub fn main() !void {
var shutdown = false;
var restart = false;
var shutdown_cmd: []const u8 = undefined;
var restart_cmd: []const u8 = undefined;
const stderr = std.io.getStdErr().writer();
defer {
// If we can't shutdown or restart due to an error, we print it to standard error. If that fails, just bail out
if (shutdown) {
const shutdown_error = std.process.execv(temporary_allocator, &[_][]const u8{ "/bin/sh", "-c", shutdown_cmd });
stderr.print("error: couldn't shutdown: {any}\n", .{shutdown_error}) catch std.process.exit(1);
} else if (restart) {
const restart_error = std.process.execv(temporary_allocator, &[_][]const u8{ "/bin/sh", "-c", restart_cmd });
stderr.print("error: couldn't restart: {any}\n", .{restart_error}) catch std.process.exit(1);
} else {
// The user has quit Ly using Ctrl+C
temporary_allocator.free(shutdown_cmd);
temporary_allocator.free(restart_cmd);
}
}
var gpa = std.heap.GeneralPurposeAllocator(.{}){}; var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit(); defer _ = gpa.deinit();
const allocator = gpa.allocator(); const allocator = gpa.allocator();
const stderr = std.io.getStdErr().writer();
// Load arguments // Load arguments
const params = comptime clap.parseParamsComptime( const params = comptime clap.parseParamsComptime(
@@ -90,8 +112,7 @@ pub fn main() !void {
if (save_path_alloc) allocator.free(save_path); if (save_path_alloc) allocator.free(save_path);
} }
// Compatibility with v0.6.0 const comment_characters = "#";
const mapped_config_fields = .{.{ "blank_password", "clear_password" }};
if (res.args.config) |s| { if (res.args.config) |s| {
const trailing_slash = if (s[s.len - 1] != '/') "/" else ""; const trailing_slash = if (s[s.len - 1] != '/') "/" else "";
@@ -99,34 +120,41 @@ pub fn main() !void {
const config_path = try std.fmt.allocPrint(allocator, "{s}{s}config.ini", .{ s, trailing_slash }); const config_path = try std.fmt.allocPrint(allocator, "{s}{s}config.ini", .{ s, trailing_slash });
defer allocator.free(config_path); defer allocator.free(config_path);
config = config_ini.readFileToStructWithMap(config_path, mapped_config_fields) catch Config{}; config = config_ini.readFileToStruct(config_path, comment_characters, migrator.configFieldHandler) catch Config{};
const lang_path = try std.fmt.allocPrint(allocator, "{s}{s}lang/{s}.ini", .{ s, trailing_slash, config.lang }); const lang_path = try std.fmt.allocPrint(allocator, "{s}{s}lang/{s}.ini", .{ s, trailing_slash, config.lang });
defer allocator.free(lang_path); defer allocator.free(lang_path);
lang = lang_ini.readFileToStruct(lang_path) catch Lang{}; lang = lang_ini.readFileToStruct(lang_path, comment_characters, null) catch Lang{};
if (config.load) { if (config.load) {
save_path = try std.fmt.allocPrint(allocator, "{s}{s}save.ini", .{ s, trailing_slash }); save_path = try std.fmt.allocPrint(allocator, "{s}{s}save.ini", .{ s, trailing_slash });
save_path_alloc = true; save_path_alloc = true;
var user_buf: [32]u8 = undefined; var user_buf: [32]u8 = undefined;
save = save_ini.readFileToStruct(save_path) catch migrator.tryMigrateSaveFile(&user_buf, config.save_file); save = save_ini.readFileToStruct(save_path, comment_characters, null) catch migrator.tryMigrateSaveFile(&user_buf, config.save_file);
} }
} else { } else {
config = config_ini.readFileToStructWithMap(build_options.data_directory ++ "/config.ini", mapped_config_fields) catch Config{}; const config_path = build_options.data_directory ++ "/config.ini";
config = config_ini.readFileToStruct(config_path, comment_characters, migrator.configFieldHandler) catch Config{};
const lang_path = try std.fmt.allocPrint(allocator, "{s}/lang/{s}.ini", .{ build_options.data_directory, config.lang }); const lang_path = try std.fmt.allocPrint(allocator, "{s}/lang/{s}.ini", .{ build_options.data_directory, config.lang });
defer allocator.free(lang_path); defer allocator.free(lang_path);
lang = lang_ini.readFileToStruct(lang_path) catch Lang{}; lang = lang_ini.readFileToStruct(lang_path, comment_characters, null) catch Lang{};
if (config.load) { if (config.load) {
var user_buf: [32]u8 = undefined; var user_buf: [32]u8 = undefined;
save = save_ini.readFileToStruct(save_path) catch migrator.tryMigrateSaveFile(&user_buf, config.save_file); save = save_ini.readFileToStruct(save_path, comment_characters, null) catch migrator.tryMigrateSaveFile(&user_buf, config.save_file);
} }
} }
// These strings only end up getting freed if the user quits Ly using Ctrl+C, which is fine since in the other cases
// 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);
interop.setNumlock(config.numlock) catch {}; interop.setNumlock(config.numlock) catch {};
if (config.initial_info_text) |text| { if (config.initial_info_text) |text| {
@@ -161,7 +189,14 @@ pub fn main() !void {
// Initialize terminal buffer // Initialize terminal buffer
const labels_max_length = @max(lang.login.len, lang.password.len); const labels_max_length = @max(lang.login.len, lang.password.len);
var buffer = TerminalBuffer.init(config, labels_max_length); // Get a random seed for the PRNG (used by animations)
var seed: u64 = undefined;
try std.posix.getrandom(std.mem.asBytes(&seed));
var prng = std.Random.DefaultPrng.init(seed);
const random = prng.random();
var buffer = TerminalBuffer.init(config, labels_max_length, random);
// Initialize components // Initialize components
var desktop = try Desktop.init(allocator, &buffer, config.max_desktop_len, lang); var desktop = try Desktop.init(allocator, &buffer, config.max_desktop_len, lang);
@@ -250,8 +285,6 @@ pub fn main() !void {
var run = true; var run = true;
var update = true; var update = true;
var resolution_changed = false; var resolution_changed = false;
var shutdown = false;
var restart = false;
var auth_fails: u64 = 0; var auth_fails: u64 = 0;
// Switch to selected TTY if possible // Switch to selected TTY if possible
@@ -426,8 +459,6 @@ pub fn main() !void {
desktop.draw(); desktop.draw();
login.draw(); login.draw();
password.drawMasked(config.asterisk); password.drawMasked(config.asterisk);
update = animate;
} else { } else {
std.time.sleep(std.time.ns_per_ms * 10); std.time.sleep(std.time.ns_per_ms * 10);
update = buffer.cascade(); update = buffer.cascade();
@@ -460,6 +491,8 @@ pub fn main() !void {
const event_error = if (timeout == -1) termbox.tb_poll_event(&event) else termbox.tb_peek_event(&event, timeout); const event_error = if (timeout == -1) termbox.tb_poll_event(&event) else termbox.tb_peek_event(&event, timeout);
update = timeout != -1;
if (event_error < 0 or event.type != termbox.TB_EVENT_KEY) continue; if (event_error < 0 or event.type != termbox.TB_EVENT_KEY) continue;
switch (event.key) { switch (event.key) {
@@ -479,7 +512,7 @@ pub fn main() !void {
run = false; run = false;
} else if (pressed_key == sleep_key) { } else if (pressed_key == sleep_key) {
if (config.sleep_cmd) |sleep_cmd| { if (config.sleep_cmd) |sleep_cmd| {
var sleep = std.ChildProcess.init(&[_][]const u8{ "/bin/sh", "-c", sleep_cmd }, allocator); var sleep = std.process.Child.init(&[_][]const u8{ "/bin/sh", "-c", sleep_cmd }, allocator);
_ = sleep.spawnAndWait() catch .{}; _ = sleep.spawnAndWait() catch .{};
} }
} }
@@ -534,7 +567,7 @@ pub fn main() !void {
.user = login.text.items, .user = login.text.items,
.session_index = desktop.current, .session_index = desktop.current,
}; };
ini.writeFromStruct(save_data, file.writer(), null) catch break :save_last_settings; ini.writeFromStruct(save_data, file.writer(), null, true, .{}) catch break :save_last_settings;
} }
var shared_err = try SharedError.init(); var shared_err = try SharedError.init();
@@ -584,7 +617,7 @@ pub fn main() !void {
update = true; update = true;
var restore_cursor = std.ChildProcess.init(&[_][]const u8{ "/bin/sh", "-c", config.term_restore_cursor_cmd }, allocator); var restore_cursor = std.process.Child.init(&[_][]const u8{ "/bin/sh", "-c", config.term_restore_cursor_cmd }, allocator);
_ = restore_cursor.spawnAndWait() catch .{}; _ = restore_cursor.spawnAndWait() catch .{};
}, },
else => { else => {
@@ -628,12 +661,6 @@ pub fn main() !void {
}, },
} }
} }
if (shutdown) {
return std.process.execv(allocator, &[_][]const u8{ "/bin/sh", "-c", config.shutdown_cmd });
} else if (restart) {
return std.process.execv(allocator, &[_][]const u8{ "/bin/sh", "-c", config.restart_cmd });
}
} }
fn getAuthErrorMsg(err: anyerror, lang: Lang) []const u8 { fn getAuthErrorMsg(err: anyerror, lang: Lang) []const u8 {

View File

@@ -4,7 +4,7 @@ const interop = @import("../interop.zig");
const utils = @import("utils.zig"); const utils = @import("utils.zig");
const Config = @import("../config/Config.zig"); const Config = @import("../config/Config.zig");
const Random = std.rand.Random; const Random = std.Random;
const termbox = interop.termbox; const termbox = interop.termbox;
@@ -35,11 +35,9 @@ box_height: u64,
margin_box_v: u8, margin_box_v: u8,
margin_box_h: u8, margin_box_h: u8,
pub fn init(config: Config, labels_max_length: u64) TerminalBuffer { pub fn init(config: Config, labels_max_length: u64, random: Random) TerminalBuffer {
var prng = std.rand.Isaac64.init(@intCast(std.time.timestamp()));
return .{ return .{
.random = prng.random(), .random = random,
.width = @intCast(termbox.tb_width()), .width = @intCast(termbox.tb_width()),
.height = @intCast(termbox.tb_height()), .height = @intCast(termbox.tb_height()),
.buffer = termbox.tb_cell_buffer(), .buffer = termbox.tb_cell_buffer(),

View File

@@ -150,7 +150,7 @@ 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 }); const entry_path = try std.fmt.allocPrint(self.allocator, "{s}/{s}", .{ path, item.name });
defer self.allocator.free(entry_path); defer self.allocator.free(entry_path);
var entry_ini = Ini(Entry).init(self.allocator); var entry_ini = Ini(Entry).init(self.allocator);
_ = try entry_ini.readFileToStruct(entry_path); _ = try entry_ini.readFileToStruct(entry_path, "#", null);
errdefer entry_ini.deinit(); errdefer entry_ini.deinit();
var xdg_session_desktop: []const u8 = undefined; var xdg_session_desktop: []const u8 = undefined;