mirror of https://github.com/fairyglade/ly.git
Zig 0.12.0 and more! (#599)
* less alloc, update migrator, get DesktopNames from .desktop * small cleanup * Update zigini to improve compatibility with old config * Code improvements * Update to zig version 0.12.0 * Some fixes * tiny changes * remove useless comment * migrator changes, and small things * set XDG env vars differently * free memory on error when appending environments
This commit is contained in:
parent
0803de8ad3
commit
5a9cc881fe
|
|
@ -35,12 +35,12 @@ pub fn build(b: *std.Build) void {
|
||||||
});
|
});
|
||||||
|
|
||||||
const zigini = b.dependency("zigini", .{ .target = target, .optimize = optimize });
|
const zigini = b.dependency("zigini", .{ .target = target, .optimize = optimize });
|
||||||
exe.addModule("zigini", zigini.module("zigini"));
|
exe.root_module.addImport("zigini", zigini.module("zigini"));
|
||||||
|
|
||||||
exe.addOptions("build_options", build_options);
|
exe.root_module.addOptions("build_options", build_options);
|
||||||
|
|
||||||
const clap = b.dependency("clap", .{ .target = target, .optimize = optimize });
|
const clap = b.dependency("clap", .{ .target = target, .optimize = optimize });
|
||||||
exe.addModule("clap", clap.module("clap"));
|
exe.root_module.addImport("clap", clap.module("clap"));
|
||||||
|
|
||||||
exe.linkSystemLibrary("pam");
|
exe.linkSystemLibrary("pam");
|
||||||
exe.linkSystemLibrary("xcb");
|
exe.linkSystemLibrary("xcb");
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,13 @@
|
||||||
.version = "1.0.0",
|
.version = "1.0.0",
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
.clap = .{
|
.clap = .{
|
||||||
.url = "https://github.com/Hejsil/zig-clap/archive/f49b94700e0761b7514abdca0e4f0e7f3f938a93.tar.gz",
|
.url = "https://github.com/Hejsil/zig-clap/archive/8c98e6404b22aafc0184e999d8f068b81cc22fa1.tar.gz",
|
||||||
.hash = "1220f48518ce22882e102255ed3bcdb7aeeb4891f50b2cdd3bd74b5b2e24d3149ba2",
|
.hash = "122014e73fd712190e109950837b97f6143f02d7e2b6986e1db70b6f4aadb5ba6a0d",
|
||||||
},
|
},
|
||||||
.zigini = .{
|
.zigini = .{
|
||||||
.url = "https://github.com/Kawaii-Ash/zigini/archive/91f47e46591982fc559afa3248749c1d29a0fa2a.tar.gz",
|
.url = "https://github.com/Kawaii-Ash/zigini/archive/a5b5caf43f0a0246a242df4aebd00a0649deebad.tar.gz",
|
||||||
.hash = "12209908f2773f730fbca024c80dc7f48dce15a6527b2387f3768968f5bae0d3931e",
|
.hash = "12202e097a54cbb7c002a2a5b3a3435939fa3902cd14308b7b66ab710e3d88d76e94",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
.paths = .{""},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
+ xinitrc can be set to null to hide it.
|
||||||
+ `blank_password` has been renamed to `clear_password`.
|
+ `blank_password` has been renamed to `clear_password`.
|
||||||
|
+ `save_file` has been deprecated and will be removed in a future version.
|
||||||
|
|
||||||
### Removals
|
### Removals
|
||||||
|
|
||||||
|
|
@ -24,7 +25,8 @@ Note: `sleep_cmd` is unset by default, meaning it's hidden and has no effect.
|
||||||
|
|
||||||
## Save File
|
## 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:
|
Example:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,9 @@ load = true
|
||||||
# Save the current desktop and login as defaults
|
# Save the current desktop and login as defaults
|
||||||
save = true
|
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
|
# File in which to save and load the default desktop and login
|
||||||
save_file = /etc/ly/save
|
save_file = /etc/ly/save
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ err_perm_dir = failed to change current directory
|
||||||
err_perm_group = failed to downgrade group permissions
|
err_perm_group = failed to downgrade group permissions
|
||||||
err_perm_user = failed to downgrade user permissions
|
err_perm_user = failed to downgrade user permissions
|
||||||
err_pwnam = failed to get user info
|
err_pwnam = failed to get user info
|
||||||
|
err_unknown = an unknown error occurred
|
||||||
err_user_gid = failed to set user GID
|
err_user_gid = failed to set user GID
|
||||||
err_user_init = failed to initialize user
|
err_user_init = failed to initialize user
|
||||||
err_user_uid = failed to set user UID
|
err_user_uid = failed to set user UID
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,13 @@ const SharedError = @This();
|
||||||
data: []align(std.mem.page_size) u8,
|
data: []align(std.mem.page_size) u8,
|
||||||
|
|
||||||
pub fn init() !SharedError {
|
pub fn init() !SharedError {
|
||||||
const data = try std.os.mmap(null, @sizeOf(ErrorHandler), std.os.PROT.READ | std.os.PROT.WRITE, std.os.MAP.SHARED | std.os.MAP.ANONYMOUS, -1, 0);
|
const data = try std.posix.mmap(null, @sizeOf(ErrorHandler), std.posix.PROT.READ | std.posix.PROT.WRITE, .{ .TYPE = .SHARED, .ANONYMOUS = true }, -1, 0);
|
||||||
|
|
||||||
return .{ .data = data };
|
return .{ .data = data };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *SharedError) void {
|
pub fn deinit(self: *SharedError) void {
|
||||||
defer std.os.munmap(self.data);
|
std.posix.munmap(self.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeError(self: SharedError, err: anyerror) void {
|
pub fn writeError(self: SharedError, err: anyerror) void {
|
||||||
|
|
|
||||||
306
src/auth.zig
306
src/auth.zig
|
|
@ -10,52 +10,35 @@ const utmp = interop.utmp;
|
||||||
const Utmp = utmp.utmp;
|
const Utmp = utmp.utmp;
|
||||||
const SharedError = @import("SharedError.zig");
|
const SharedError = @import("SharedError.zig");
|
||||||
|
|
||||||
var xorg_pid: std.os.pid_t = 0;
|
var xorg_pid: std.posix.pid_t = 0;
|
||||||
pub fn xorgSignalHandler(i: c_int) callconv(.C) void {
|
pub fn xorgSignalHandler(i: c_int) callconv(.C) void {
|
||||||
if (xorg_pid > 0) _ = std.c.kill(xorg_pid, i);
|
if (xorg_pid > 0) _ = std.c.kill(xorg_pid, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
var child_pid: std.os.pid_t = 0;
|
var child_pid: std.posix.pid_t = 0;
|
||||||
pub fn sessionSignalHandler(i: c_int) callconv(.C) void {
|
pub fn sessionSignalHandler(i: c_int) callconv(.C) void {
|
||||||
if (child_pid > 0) _ = std.c.kill(child_pid, i);
|
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;
|
var tty_buffer: [2]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});
|
||||||
const current_environment = desktop.environments.items[desktop.current];
|
const current_environment = desktop.environments.items[desktop.current];
|
||||||
|
|
||||||
// Set the XDG environment variables
|
// Set the XDG environment variables
|
||||||
setXdgSessionEnv(current_environment.display_server);
|
setXdgSessionEnv(current_environment.display_server);
|
||||||
if (current_environment.entry_ini) |entry| {
|
try setXdgEnv(tty_str, current_environment.xdg_session_desktop, current_environment.xdg_desktop_names orelse "");
|
||||||
try setXdgEnv(allocator, tty_str, entry.DesktopNames);
|
|
||||||
} else {
|
|
||||||
try setXdgEnv(allocator, tty_str, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the PAM session
|
// Open the PAM session
|
||||||
const login_text_z = try allocator.dupeZ(u8, login.text.items);
|
var credentials = [_:null]?[*:0]const u8{ login, password };
|
||||||
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;
|
|
||||||
|
|
||||||
const conv = interop.pam.pam_conv{
|
const conv = interop.pam.pam_conv{
|
||||||
.conv = loginConv,
|
.conv = loginConv,
|
||||||
.appdata_ptr = @ptrCast(credentials.ptr),
|
.appdata_ptr = @ptrCast(&credentials),
|
||||||
};
|
};
|
||||||
var handle: ?*interop.pam.pam_handle = undefined;
|
var handle: ?*interop.pam.pam_handle = undefined;
|
||||||
|
|
||||||
const service_name_z = try allocator.dupeZ(u8, config.service_name);
|
var status = interop.pam.pam_start(config.service_name.ptr, null, &conv, &handle);
|
||||||
defer allocator.free(service_name_z);
|
|
||||||
|
|
||||||
var status = interop.pam.pam_start(service_name_z.ptr, null, &conv, &handle);
|
|
||||||
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
|
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
|
||||||
|
|
||||||
// Do the PAM routine
|
// Do the PAM routine
|
||||||
|
|
@ -71,124 +54,50 @@ pub fn authenticate(allocator: Allocator, config: Config, desktop: Desktop, logi
|
||||||
status = interop.pam.pam_open_session(handle, 0);
|
status = interop.pam.pam_open_session(handle, 0);
|
||||||
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
|
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
|
||||||
|
|
||||||
// Get password structure from username
|
var pwd: *interop.passwd = undefined;
|
||||||
const maybe_pwd = interop.getpwnam(login_text_z.ptr);
|
{
|
||||||
interop.endpwent();
|
defer interop.endpwent();
|
||||||
|
|
||||||
if (maybe_pwd == null) return error.GetPasswordNameFailed;
|
// Get password structure from username
|
||||||
const pwd = maybe_pwd.?;
|
pwd = interop.getpwnam(login.ptr) orelse return error.GetPasswordNameFailed;
|
||||||
|
}
|
||||||
|
|
||||||
// Set user shell if it hasn't already been set
|
// Set user shell if it hasn't already been set
|
||||||
if (pwd.pw_shell[0] == 0) {
|
if (pwd.pw_shell[0] == 0) {
|
||||||
interop.setusershell();
|
interop.setusershell();
|
||||||
defer interop.endusershell();
|
pwd.pw_shell = interop.getusershell();
|
||||||
|
interop.endusershell();
|
||||||
const shell = interop.getusershell();
|
|
||||||
|
|
||||||
if (shell[0] != 0) {
|
|
||||||
var index: usize = 0;
|
|
||||||
|
|
||||||
while (true) : (index += 1) {
|
|
||||||
const char = shell[index];
|
|
||||||
pwd.pw_shell[index] = char;
|
|
||||||
|
|
||||||
if (char == 0) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var shared_err = try SharedError.init();
|
var shared_err = try SharedError.init();
|
||||||
defer shared_err.deinit();
|
defer shared_err.deinit();
|
||||||
|
|
||||||
child_pid = try std.os.fork();
|
child_pid = try std.posix.fork();
|
||||||
if (child_pid == 0) {
|
if (child_pid == 0) {
|
||||||
// Set the user information
|
startSession(config, pwd, handle, current_environment) catch |e| {
|
||||||
status = interop.initgroups(pwd.pw_name, pwd.pw_gid);
|
|
||||||
if (status != 0) {
|
|
||||||
shared_err.writeError(error.GroupInitializationFailed);
|
|
||||||
std.os.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = std.c.setgid(pwd.pw_gid);
|
|
||||||
if (status != 0) {
|
|
||||||
shared_err.writeError(error.SetUserGidFailed);
|
|
||||||
std.os.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = std.c.setuid(pwd.pw_uid);
|
|
||||||
if (status != 0) {
|
|
||||||
shared_err.writeError(error.SetUserUidFailed);
|
|
||||||
std.os.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up the environment
|
|
||||||
initEnv(allocator, pwd, config.path) catch |e| {
|
|
||||||
shared_err.writeError(e);
|
shared_err.writeError(e);
|
||||||
std.os.exit(1);
|
std.process.exit(1);
|
||||||
};
|
};
|
||||||
|
std.process.exit(0);
|
||||||
// Set the PAM variables
|
|
||||||
const pam_env_vars = interop.pam.pam_getenvlist(handle);
|
|
||||||
var index: usize = 0;
|
|
||||||
|
|
||||||
while (true) : (index += 1) {
|
|
||||||
const pam_env_var = pam_env_vars[index];
|
|
||||||
if (pam_env_var == null) break;
|
|
||||||
|
|
||||||
_ = interop.putenv(pam_env_var);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute what the user requested
|
|
||||||
status = interop.chdir(pwd.pw_dir);
|
|
||||||
if (status != 0) {
|
|
||||||
shared_err.writeError(error.ChangeDirectoryFailed);
|
|
||||||
std.os.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
resetTerminal(allocator, pwd.pw_shell, config.term_reset_cmd) catch |e| {
|
|
||||||
shared_err.writeError(e);
|
|
||||||
std.os.exit(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (current_environment.display_server) {
|
|
||||||
.wayland => executeWaylandCmd(pwd.pw_shell, config.wayland_cmd, current_environment.cmd) catch |e| {
|
|
||||||
shared_err.writeError(e);
|
|
||||||
std.os.exit(1);
|
|
||||||
},
|
|
||||||
.shell => executeShellCmd(pwd.pw_shell),
|
|
||||||
.xinitrc, .x11 => {
|
|
||||||
var vt_buf: [5]u8 = undefined;
|
|
||||||
const vt = std.fmt.bufPrint(&vt_buf, "vt{d}", .{config.tty}) catch |e| {
|
|
||||||
shared_err.writeError(e);
|
|
||||||
std.os.exit(1);
|
|
||||||
};
|
|
||||||
executeX11Cmd(pwd.pw_shell, pwd.pw_dir, config, current_environment.cmd, vt) catch |e| {
|
|
||||||
shared_err.writeError(e);
|
|
||||||
std.os.exit(1);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
std.os.exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var entry: Utmp = std.mem.zeroes(Utmp);
|
var entry: Utmp = std.mem.zeroes(Utmp);
|
||||||
addUtmpEntry(&entry, pwd.pw_name, child_pid) catch {};
|
addUtmpEntry(&entry, pwd.pw_name, child_pid) catch {};
|
||||||
|
|
||||||
// If we receive SIGTERM, forward it to child_pid
|
// If we receive SIGTERM, forward it to child_pid
|
||||||
const act = std.os.Sigaction{
|
const act = std.posix.Sigaction{
|
||||||
.handler = .{ .handler = &sessionSignalHandler },
|
.handler = .{ .handler = &sessionSignalHandler },
|
||||||
.mask = std.os.empty_sigset,
|
.mask = std.posix.empty_sigset,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
};
|
};
|
||||||
try std.os.sigaction(std.os.SIG.TERM, &act, null);
|
try std.posix.sigaction(std.posix.SIG.TERM, &act, null);
|
||||||
|
|
||||||
// Wait for the session to stop
|
// Wait for the session to stop
|
||||||
_ = std.os.waitpid(child_pid, 0);
|
_ = std.posix.waitpid(child_pid, 0);
|
||||||
|
|
||||||
removeUtmpEntry(&entry);
|
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
|
// Close the PAM session
|
||||||
status = interop.pam.pam_close_session(handle, 0);
|
status = interop.pam.pam_close_session(handle, 0);
|
||||||
|
|
@ -203,8 +112,51 @@ pub fn authenticate(allocator: Allocator, config: Config, desktop: Desktop, logi
|
||||||
if (shared_err.readError()) |err| return err;
|
if (shared_err.readError()) |err| return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initEnv(allocator: Allocator, pwd: *interop.passwd, path: ?[]const u8) !void {
|
fn startSession(
|
||||||
const term_env = std.os.getenv("TERM");
|
config: Config,
|
||||||
|
pwd: *interop.passwd,
|
||||||
|
handle: ?*interop.pam.pam_handle,
|
||||||
|
current_environment: Desktop.Environment,
|
||||||
|
) !void {
|
||||||
|
var status: c_int = 0;
|
||||||
|
status = interop.initgroups(pwd.pw_name, pwd.pw_gid);
|
||||||
|
if (status != 0) return error.GroupInitializationFailed;
|
||||||
|
|
||||||
|
std.posix.setgid(pwd.pw_gid) catch return error.SetUserGidFailed;
|
||||||
|
std.posix.setuid(pwd.pw_uid) catch return error.SetUserUidFailed;
|
||||||
|
|
||||||
|
// Set up the environment
|
||||||
|
try initEnv(pwd, config.path);
|
||||||
|
|
||||||
|
// Set the PAM variables
|
||||||
|
const pam_env_vars = interop.pam.pam_getenvlist(handle);
|
||||||
|
|
||||||
|
var index: usize = 0;
|
||||||
|
while (true) : (index += 1) {
|
||||||
|
const pam_env_var = pam_env_vars[index];
|
||||||
|
if (pam_env_var == null) break;
|
||||||
|
|
||||||
|
_ = interop.putenv(pam_env_var);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute what the user requested
|
||||||
|
std.posix.chdirZ(pwd.pw_dir) catch return error.ChangeDirectoryFailed;
|
||||||
|
|
||||||
|
try resetTerminal(pwd.pw_shell, config.term_reset_cmd);
|
||||||
|
|
||||||
|
switch (current_environment.display_server) {
|
||||||
|
.wayland => try executeWaylandCmd(pwd.pw_shell, config.wayland_cmd, current_environment.cmd),
|
||||||
|
.shell => try executeShellCmd(pwd.pw_shell),
|
||||||
|
.xinitrc, .x11 => {
|
||||||
|
var vt_buf: [5]u8 = undefined;
|
||||||
|
const vt = try std.fmt.bufPrint(&vt_buf, "vt{d}", .{config.tty});
|
||||||
|
try executeX11Cmd(pwd.pw_shell, pwd.pw_dir, config, current_environment.cmd, vt);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initEnv(pwd: *interop.passwd, path_env: ?[:0]const u8) !void {
|
||||||
|
const term_env = std.posix.getenv("TERM");
|
||||||
|
|
||||||
if (term_env) |term| _ = interop.setenv("TERM", term, 1);
|
if (term_env) |term| _ = interop.setenv("TERM", term, 1);
|
||||||
_ = interop.setenv("HOME", pwd.pw_dir, 1);
|
_ = interop.setenv("HOME", pwd.pw_dir, 1);
|
||||||
|
|
@ -213,11 +165,8 @@ fn initEnv(allocator: Allocator, pwd: *interop.passwd, path: ?[]const u8) !void
|
||||||
_ = interop.setenv("USER", pwd.pw_name, 1);
|
_ = interop.setenv("USER", pwd.pw_name, 1);
|
||||||
_ = interop.setenv("LOGNAME", pwd.pw_name, 1);
|
_ = interop.setenv("LOGNAME", pwd.pw_name, 1);
|
||||||
|
|
||||||
if (path != null) {
|
if (path_env) |path| {
|
||||||
const path_z = try allocator.dupeZ(u8, path.?);
|
const status = interop.setenv("PATH", path, 1);
|
||||||
defer allocator.free(path_z);
|
|
||||||
|
|
||||||
const status = interop.setenv("PATH", path_z, 1);
|
|
||||||
if (status != 0) return error.SetPathFailed;
|
if (status != 0) return error.SetPathFailed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -230,22 +179,16 @@ fn setXdgSessionEnv(display_server: enums.DisplayServer) void {
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setXdgEnv(allocator: Allocator, tty_str: [:0]u8, desktop_name: []const u8) !void {
|
fn setXdgEnv(tty_str: [:0]u8, desktop_name: [:0]const u8, xdg_desktop_names: [:0]const u8) !void {
|
||||||
const uid = interop.getuid();
|
const uid = interop.getuid();
|
||||||
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});
|
||||||
|
|
||||||
if (desktop_name.len > 0) {
|
_ = interop.setenv("XDG_CURRENT_DESKTOP", xdg_desktop_names.ptr, 0);
|
||||||
const desktop_name_z = try allocator.dupeZ(u8, desktop_name);
|
|
||||||
defer allocator.free(desktop_name_z);
|
|
||||||
|
|
||||||
_ = interop.setenv("XDG_CURRENT_DESKTOP", desktop_name_z.ptr, 0);
|
|
||||||
_ = interop.setenv("XDG_SESSION_DESKTOP", desktop_name_z.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);
|
||||||
_ = 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);
|
||||||
}
|
}
|
||||||
|
|
@ -298,18 +241,15 @@ fn loginConv(
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resetTerminal(allocator: Allocator, shell: [*:0]const u8, term_reset_cmd: []const u8) !void {
|
fn resetTerminal(shell: [*:0]const u8, term_reset_cmd: [:0]const u8) !void {
|
||||||
const term_reset_cmd_z = try allocator.dupeZ(u8, term_reset_cmd);
|
const pid = try std.posix.fork();
|
||||||
defer allocator.free(term_reset_cmd_z);
|
|
||||||
|
|
||||||
const pid = try std.os.fork();
|
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
_ = interop.execl(shell, shell, "-c", term_reset_cmd_z.ptr, @as([*c]const u8, 0));
|
const args = [_:null]?[*:0]const u8{ shell, "-c", term_reset_cmd };
|
||||||
std.os.exit(0);
|
std.posix.execveZ(shell, &args, std.c.environ) catch {};
|
||||||
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = std.os.waitpid(pid, 0);
|
_ = std.posix.waitpid(pid, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getFreeDisplay() !u8 {
|
fn getFreeDisplay() !u8 {
|
||||||
|
|
@ -317,7 +257,7 @@ fn getFreeDisplay() !u8 {
|
||||||
var i: u8 = 0;
|
var i: u8 = 0;
|
||||||
while (i < 200) : (i += 1) {
|
while (i < 200) : (i += 1) {
|
||||||
const xlock = try std.fmt.bufPrint(&buf, "/tmp/.X{d}-lock", .{i});
|
const xlock = try std.fmt.bufPrint(&buf, "/tmp/.X{d}-lock", .{i});
|
||||||
std.os.access(xlock, std.os.F_OK) catch break;
|
std.posix.access(xlock, std.posix.F_OK) catch break;
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
@ -340,17 +280,17 @@ fn getXPid(display_num: u8) !i32 {
|
||||||
fn createXauthFile(pwd: [:0]const u8) ![:0]const u8 {
|
fn createXauthFile(pwd: [:0]const u8) ![:0]const u8 {
|
||||||
var xauth_buf: [100]u8 = undefined;
|
var xauth_buf: [100]u8 = undefined;
|
||||||
var xauth_dir: [:0]const u8 = undefined;
|
var xauth_dir: [:0]const u8 = undefined;
|
||||||
var xdg_rt_dir = std.os.getenv("XDG_RUNTIME_DIR");
|
const xdg_rt_dir = std.posix.getenv("XDG_RUNTIME_DIR");
|
||||||
var xauth_file: []const u8 = "lyxauth";
|
var xauth_file: []const u8 = "lyxauth";
|
||||||
|
|
||||||
if (xdg_rt_dir == null) {
|
if (xdg_rt_dir == null) {
|
||||||
const xdg_cfg_home = std.os.getenv("XDG_CONFIG_HOME");
|
const xdg_cfg_home = std.posix.getenv("XDG_CONFIG_HOME");
|
||||||
var sb: std.c.Stat = undefined;
|
var sb: std.c.Stat = undefined;
|
||||||
if (xdg_cfg_home == null) {
|
if (xdg_cfg_home == null) {
|
||||||
xauth_dir = try std.fmt.bufPrintZ(&xauth_buf, "{s}/.config", .{pwd});
|
xauth_dir = try std.fmt.bufPrintZ(&xauth_buf, "{s}/.config", .{pwd});
|
||||||
_ = std.c.stat(xauth_dir, &sb);
|
_ = std.c.stat(xauth_dir, &sb);
|
||||||
const mode = sb.mode & std.os.S.IFMT;
|
const mode = sb.mode & std.posix.S.IFMT;
|
||||||
if (mode == std.os.S.IFDIR) {
|
if (mode == std.posix.S.IFDIR) {
|
||||||
xauth_dir = try std.fmt.bufPrintZ(&xauth_buf, "{s}/ly", .{xauth_dir});
|
xauth_dir = try std.fmt.bufPrintZ(&xauth_buf, "{s}/ly", .{xauth_dir});
|
||||||
} else {
|
} else {
|
||||||
xauth_dir = pwd;
|
xauth_dir = pwd;
|
||||||
|
|
@ -361,9 +301,9 @@ fn createXauthFile(pwd: [:0]const u8) ![:0]const u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = std.c.stat(xauth_dir, &sb);
|
_ = std.c.stat(xauth_dir, &sb);
|
||||||
const mode = sb.mode & std.os.S.IFMT;
|
const mode = sb.mode & std.posix.S.IFMT;
|
||||||
if (mode != std.os.S.IFDIR) {
|
if (mode != std.posix.S.IFDIR) {
|
||||||
std.os.mkdir(xauth_dir, 777) catch {
|
std.posix.mkdir(xauth_dir, 777) catch {
|
||||||
xauth_dir = pwd;
|
xauth_dir = pwd;
|
||||||
xauth_file = ".lyxauth";
|
xauth_file = ".lyxauth";
|
||||||
};
|
};
|
||||||
|
|
@ -379,7 +319,7 @@ fn createXauthFile(pwd: [:0]const u8) ![:0]const u8 {
|
||||||
|
|
||||||
var buf: [256]u8 = undefined;
|
var buf: [256]u8 = undefined;
|
||||||
const xauthority: [:0]u8 = try std.fmt.bufPrintZ(&buf, "{s}/{s}", .{ trimmed_xauth_dir, xauth_file });
|
const xauthority: [:0]u8 = try std.fmt.bufPrintZ(&buf, "{s}/{s}", .{ trimmed_xauth_dir, xauth_file });
|
||||||
const file = try std.fs.createFileAbsolute(xauthority, .{});
|
const file = try std.fs.createFileAbsoluteZ(xauthority, .{});
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
return xauthority;
|
return xauthority;
|
||||||
|
|
@ -387,86 +327,90 @@ 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 {
|
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_buf: [100]u8 = undefined;
|
||||||
var pwd: [:0]u8 = try std.fmt.bufPrintZ(&pwd_buf, "{s}", .{pw_dir});
|
const pwd = try std.fmt.bufPrintZ(&pwd_buf, "{s}", .{pw_dir});
|
||||||
|
|
||||||
const xauthority = try createXauthFile(pwd);
|
const xauthority = try createXauthFile(pwd);
|
||||||
_ = interop.setenv("XAUTHORITY", xauthority, 1);
|
_ = interop.setenv("XAUTHORITY", xauthority, 1);
|
||||||
_ = interop.setenv("DISPLAY", display_name, 1);
|
_ = interop.setenv("DISPLAY", display_name, 1);
|
||||||
|
|
||||||
const pid = try std.os.fork();
|
const pid = try std.posix.fork();
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
var cmd_buffer: [1024]u8 = undefined;
|
var cmd_buffer: [1024]u8 = undefined;
|
||||||
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} add {s} . $({s})", .{ xauth_cmd, display_name, mcookie_cmd }) catch std.os.exit(1);
|
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} add {s} . $({s})", .{ xauth_cmd, display_name, mcookie_cmd }) catch std.process.exit(1);
|
||||||
_ = interop.execl(shell, shell, "-c", cmd_str.ptr, @as([*c]const u8, 0));
|
const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str };
|
||||||
std.os.exit(0);
|
std.posix.execveZ(shell, &args, std.c.environ) catch {};
|
||||||
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = std.os.waitpid(pid, 0);
|
_ = std.posix.waitpid(pid, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn executeShellCmd(shell: [*:0]const u8) !void {
|
||||||
|
const args = [_:null]?[*:0]const u8{shell};
|
||||||
|
return std.posix.execveZ(shell, &args, std.c.environ);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn executeWaylandCmd(shell: [*:0]const u8, wayland_cmd: []const u8, desktop_cmd: []const u8) !void {
|
fn executeWaylandCmd(shell: [*:0]const u8, wayland_cmd: []const u8, desktop_cmd: []const u8) !void {
|
||||||
var cmd_buffer: [1024]u8 = undefined;
|
var cmd_buffer: [1024]u8 = undefined;
|
||||||
|
|
||||||
const cmd_str = try std.fmt.bufPrintZ(&cmd_buffer, "{s} {s}", .{ wayland_cmd, desktop_cmd });
|
const cmd_str = try std.fmt.bufPrintZ(&cmd_buffer, "{s} {s}", .{ wayland_cmd, desktop_cmd });
|
||||||
_ = interop.execl(shell, shell, "-c", cmd_str.ptr, @as([*c]const u8, 0));
|
const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str };
|
||||||
|
return std.posix.execveZ(shell, &args, std.c.environ);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn executeX11Cmd(shell: [*:0]const u8, pw_dir: [*:0]const u8, config: Config, desktop_cmd: []const u8, vt: []const u8) !void {
|
fn executeX11Cmd(shell: [*:0]const u8, pw_dir: [*:0]const u8, config: Config, desktop_cmd: []const u8, vt: []const u8) !void {
|
||||||
const display_num = try getFreeDisplay();
|
const display_num = try getFreeDisplay();
|
||||||
var buf: [5]u8 = undefined;
|
var buf: [5]u8 = undefined;
|
||||||
var display_name = try std.fmt.bufPrintZ(&buf, ":{d}", .{display_num});
|
const display_name = try std.fmt.bufPrintZ(&buf, ":{d}", .{display_num});
|
||||||
try xauth(display_name, shell, pw_dir, config.xauth_cmd, config.mcookie_cmd);
|
try xauth(display_name, shell, pw_dir, config.xauth_cmd, config.mcookie_cmd);
|
||||||
|
|
||||||
const pid = try std.os.fork();
|
const pid = try std.posix.fork();
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
var cmd_buffer: [1024]u8 = undefined;
|
var cmd_buffer: [1024]u8 = undefined;
|
||||||
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s}", .{ config.x_cmd, display_name, vt }) catch std.os.exit(1);
|
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s}", .{ config.x_cmd, display_name, vt }) catch std.process.exit(1);
|
||||||
_ = interop.execl(shell, shell, "-c", cmd_str.ptr, @as([*c]const u8, 0));
|
const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str };
|
||||||
std.os.exit(0);
|
std.posix.execveZ(shell, &args, std.c.environ) catch {};
|
||||||
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var status: c_int = 0;
|
|
||||||
var ok: c_int = undefined;
|
var ok: c_int = undefined;
|
||||||
var xcb: ?*interop.xcb.xcb_connection_t = null;
|
var xcb: ?*interop.xcb.xcb_connection_t = null;
|
||||||
while (ok != 0) {
|
while (ok != 0) {
|
||||||
xcb = interop.xcb.xcb_connect(null, null);
|
xcb = interop.xcb.xcb_connect(null, null);
|
||||||
ok = interop.xcb.xcb_connection_has_error(xcb);
|
ok = interop.xcb.xcb_connection_has_error(xcb);
|
||||||
status = std.c.kill(pid, 0);
|
std.posix.kill(pid, 0) catch |e| {
|
||||||
if (std.os.errno(status) == .SRCH and ok != 0) return;
|
if (e == error.ProcessNotFound and ok != 0) return;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// X Server detaches from the process.
|
// X Server detaches from the process.
|
||||||
// PID can be fetched from /tmp/X{d}.lock
|
// PID can be fetched from /tmp/X{d}.lock
|
||||||
const x_pid = try getXPid(display_num);
|
const x_pid = try getXPid(display_num);
|
||||||
|
|
||||||
xorg_pid = try std.os.fork();
|
xorg_pid = try std.posix.fork();
|
||||||
if (xorg_pid == 0) {
|
if (xorg_pid == 0) {
|
||||||
var cmd_buffer: [1024]u8 = undefined;
|
var cmd_buffer: [1024]u8 = undefined;
|
||||||
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} {s}", .{ config.x_cmd_setup, desktop_cmd }) catch std.os.exit(1);
|
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} {s}", .{ config.x_cmd_setup, desktop_cmd }) catch std.process.exit(1);
|
||||||
_ = interop.execl(shell, shell, "-c", cmd_str.ptr, @as([*c]const u8, 0));
|
const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str };
|
||||||
std.os.exit(0);
|
std.posix.execveZ(shell, &args, std.c.environ) catch {};
|
||||||
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we receive SIGTERM, clean up by killing the xorg_pid process
|
// If we receive SIGTERM, clean up by killing the xorg_pid process
|
||||||
const act = std.os.Sigaction{
|
const act = std.posix.Sigaction{
|
||||||
.handler = .{ .handler = &xorgSignalHandler },
|
.handler = .{ .handler = &xorgSignalHandler },
|
||||||
.mask = std.os.empty_sigset,
|
.mask = std.posix.empty_sigset,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
};
|
};
|
||||||
try std.os.sigaction(std.os.SIG.TERM, &act, null);
|
try std.posix.sigaction(std.posix.SIG.TERM, &act, null);
|
||||||
|
|
||||||
_ = std.os.waitpid(xorg_pid, 0);
|
_ = std.posix.waitpid(xorg_pid, 0);
|
||||||
interop.xcb.xcb_disconnect(xcb);
|
interop.xcb.xcb_disconnect(xcb);
|
||||||
|
|
||||||
status = std.c.kill(x_pid, 0);
|
std.posix.kill(x_pid, 0) catch return;
|
||||||
if (std.os.errno(status) != .SRCH) {
|
std.posix.kill(x_pid, std.posix.SIG.TERM) catch {};
|
||||||
_ = std.c.kill(x_pid, std.os.SIG.TERM);
|
|
||||||
_ = std.c.waitpid(x_pid, &status, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn executeShellCmd(shell: [*:0]const u8) void {
|
var status: c_int = 0;
|
||||||
_ = interop.execl(shell, shell, @as([*c]const u8, 0));
|
_ = std.c.waitpid(x_pid, &status, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addUtmpEntry(entry: *Utmp, username: [*:0]const u8, pid: c_int) !void {
|
fn addUtmpEntry(entry: *Utmp, username: [*:0]const u8, pid: c_int) !void {
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ pub fn clockCell(animate: bool, char: u8, fg: u8, bg: u8) [SIZE]termbox.tb_cell
|
||||||
return cells;
|
return cells;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn alphaBlit(buffer: [*c]termbox.tb_cell, x: u64, y: u64, tb_width: u64, tb_height: u64, cells: [SIZE]termbox.tb_cell) void {
|
pub fn alphaBlit(buffer: [*]termbox.tb_cell, x: u64, y: u64, tb_width: u64, tb_height: u64, cells: [SIZE]termbox.tb_cell) void {
|
||||||
if (x + WIDTH >= tb_width or y + HEIGHT >= tb_height) return;
|
if (x + WIDTH >= tb_width or y + HEIGHT >= tb_height) return;
|
||||||
|
|
||||||
for (0..HEIGHT) |yy| {
|
for (0..HEIGHT) |yy| {
|
||||||
|
|
|
||||||
|
|
@ -27,17 +27,17 @@ max_login_len: u8 = 255,
|
||||||
max_password_len: u8 = 255,
|
max_password_len: u8 = 255,
|
||||||
mcookie_cmd: []const u8 = "/usr/bin/mcookie",
|
mcookie_cmd: []const u8 = "/usr/bin/mcookie",
|
||||||
min_refresh_delta: u16 = 5,
|
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_cmd: []const u8 = "/sbin/shutdown -r now",
|
||||||
restart_key: []const u8 = "F2",
|
restart_key: []const u8 = "F2",
|
||||||
save: bool = true,
|
save: bool = true,
|
||||||
save_file: []const u8 = "/etc/ly/save",
|
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_cmd: []const u8 = "/sbin/shutdown -a now",
|
||||||
shutdown_key: []const u8 = "F1",
|
shutdown_key: []const u8 = "F1",
|
||||||
sleep_cmd: ?[]const u8 = null,
|
sleep_cmd: ?[]const u8 = null,
|
||||||
sleep_key: []const u8 = "F3",
|
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",
|
term_restore_cursor_cmd: []const u8 = "/usr/bin/tput cnorm",
|
||||||
tty: u8 = 2,
|
tty: u8 = 2,
|
||||||
vi_mode: bool = false,
|
vi_mode: bool = false,
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ err_perm_dir: []const u8 = "failed to change current directory",
|
||||||
err_perm_group: []const u8 = "failed to downgrade group permissions",
|
err_perm_group: []const u8 = "failed to downgrade group permissions",
|
||||||
err_perm_user: []const u8 = "failed to downgrade user permissions",
|
err_perm_user: []const u8 = "failed to downgrade user permissions",
|
||||||
err_pwnam: []const u8 = "failed to get user info",
|
err_pwnam: []const u8 = "failed to get user info",
|
||||||
|
err_unknown: []const u8 = "an unknown error occurred",
|
||||||
err_user_gid: []const u8 = "failed to set user GID",
|
err_user_gid: []const u8 = "failed to set user GID",
|
||||||
err_user_init: []const u8 = "failed to initialize user",
|
err_user_init: []const u8 = "failed to initialize user",
|
||||||
err_user_uid: []const u8 = "failed to set user UID",
|
err_user_uid: []const u8 = "failed to set user UID",
|
||||||
|
|
@ -42,9 +43,9 @@ numlock: []const u8 = "numlock",
|
||||||
other: []const u8 = "other",
|
other: []const u8 = "other",
|
||||||
password: []const u8 = "password:",
|
password: []const u8 = "password:",
|
||||||
restart: []const u8 = "reboot",
|
restart: []const u8 = "reboot",
|
||||||
shell: []const u8 = "shell",
|
shell: [:0]const u8 = "shell",
|
||||||
shutdown: []const u8 = "shutdown",
|
shutdown: []const u8 = "shutdown",
|
||||||
sleep: []const u8 = "sleep",
|
sleep: []const u8 = "sleep",
|
||||||
wayland: []const u8 = "wayland",
|
wayland: []const u8 = "wayland",
|
||||||
xinitrc: []const u8 = "xinitrc",
|
xinitrc: [:0]const u8 = "xinitrc",
|
||||||
x11: []const u8 = "x11",
|
x11: []const u8 = "x11",
|
||||||
|
|
|
||||||
|
|
@ -2,29 +2,29 @@ const std = @import("std");
|
||||||
const ini = @import("zigini");
|
const ini = @import("zigini");
|
||||||
const Save = @import("Save.zig");
|
const Save = @import("Save.zig");
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
pub fn tryMigrateSaveFile(user_buf: *[32]u8, path: []const u8) Save {
|
||||||
|
var save = Save{};
|
||||||
|
|
||||||
pub fn tryMigrateSaveFile(allocator: Allocator, path: []const u8) Save {
|
var file = std.fs.openFileAbsolute(path, .{}) catch return save;
|
||||||
var file = std.fs.openFileAbsolute(path, .{ .mode = .read_write }) catch return .{};
|
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
const reader = file.reader();
|
const reader = file.reader();
|
||||||
const user_length = reader.readIntLittle(u64) catch return .{};
|
|
||||||
|
|
||||||
const user_buffer = allocator.alloc(u8, user_length) catch return .{};
|
var user_fbs = std.io.fixedBufferStream(user_buf);
|
||||||
defer allocator.free(user_buffer);
|
reader.streamUntilDelimiter(user_fbs.writer(), '\n', 32) catch return save;
|
||||||
|
const user = user_fbs.getWritten();
|
||||||
|
if (user.len > 0) save.user = user;
|
||||||
|
|
||||||
const read_user_length = reader.read(user_buffer) catch return .{};
|
var session_buf: [20]u8 = undefined;
|
||||||
if (read_user_length != user_length) return .{};
|
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;
|
||||||
const save = .{
|
if (session_index_str.len > 0) {
|
||||||
.user = user_buffer,
|
session_index = std.fmt.parseUnsigned(u64, session_index_str, 10) catch return save;
|
||||||
.session_index = session_index,
|
}
|
||||||
};
|
save.session_index = session_index;
|
||||||
|
|
||||||
ini.writeFromStruct(save, file.writer(), null) catch return save;
|
|
||||||
|
|
||||||
return save;
|
return save;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,9 +44,6 @@ pub const passwd = extern struct {
|
||||||
pw_shell: [*:0]u8,
|
pw_shell: [*:0]u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const _POSIX_HOST_NAME_MAX: c_int = 0xFF;
|
|
||||||
pub const _SC_HOST_NAME_MAX: c_int = 0xB4;
|
|
||||||
|
|
||||||
pub const VT_ACTIVATE: c_int = 0x5606;
|
pub const VT_ACTIVATE: c_int = 0x5606;
|
||||||
pub const VT_WAITACTIVE: c_int = 0x5607;
|
pub const VT_WAITACTIVE: c_int = 0x5607;
|
||||||
|
|
||||||
|
|
@ -59,19 +56,10 @@ pub const LED_CAP: c_int = 0x04;
|
||||||
pub const K_NUMLOCK: c_int = 0x02;
|
pub const K_NUMLOCK: c_int = 0x02;
|
||||||
pub const K_CAPSLOCK: c_int = 0x04;
|
pub const K_CAPSLOCK: c_int = 0x04;
|
||||||
|
|
||||||
pub const O_RDONLY: c_uint = 0x00;
|
|
||||||
pub const O_WRONLY: c_uint = 0x01;
|
|
||||||
pub const O_RDWR: c_uint = 0x02;
|
|
||||||
|
|
||||||
pub extern "c" fn fileno(stream: *std.c.FILE) c_int;
|
|
||||||
pub extern "c" fn sysconf(name: c_int) c_long;
|
|
||||||
pub extern "c" fn time(second: ?*c_time) c_time;
|
|
||||||
pub extern "c" fn localtime(timer: *const c_time) *tm;
|
pub extern "c" fn localtime(timer: *const c_time) *tm;
|
||||||
pub extern "c" fn strftime(str: [*:0]u8, maxsize: c_size, format: [*:0]const u8, timeptr: *const tm) c_size;
|
pub extern "c" fn strftime(str: [*:0]u8, maxsize: c_size, format: [*:0]const u8, timeptr: *const tm) c_size;
|
||||||
pub extern "c" fn setenv(name: [*:0]const u8, value: [*:0]const u8, overwrite: c_int) c_int;
|
pub extern "c" fn setenv(name: [*:0]const u8, value: [*:0]const u8, overwrite: c_int) c_int;
|
||||||
pub extern "c" fn getenv(name: [*:0]const u8) [*:0]u8;
|
|
||||||
pub extern "c" fn putenv(name: [*:0]u8) c_int;
|
pub extern "c" fn putenv(name: [*:0]u8) c_int;
|
||||||
pub extern "c" fn clearenv() c_int;
|
|
||||||
pub extern "c" fn getuid() c_uid;
|
pub extern "c" fn getuid() c_uid;
|
||||||
pub extern "c" fn getpwnam(name: [*:0]const u8) ?*passwd;
|
pub extern "c" fn getpwnam(name: [*:0]const u8) ?*passwd;
|
||||||
pub extern "c" fn endpwent() void;
|
pub extern "c" fn endpwent() void;
|
||||||
|
|
@ -79,53 +67,24 @@ pub extern "c" fn setusershell() void;
|
||||||
pub extern "c" fn getusershell() [*:0]u8;
|
pub extern "c" fn getusershell() [*:0]u8;
|
||||||
pub extern "c" fn endusershell() void;
|
pub extern "c" fn endusershell() void;
|
||||||
pub extern "c" fn initgroups(user: [*:0]const u8, group: c_gid) c_int;
|
pub extern "c" fn initgroups(user: [*:0]const u8, group: c_gid) c_int;
|
||||||
pub extern "c" fn chdir(path: [*:0]const u8) c_int;
|
|
||||||
pub extern "c" fn execl(path: [*:0]const u8, arg: [*:0]const u8, ...) c_int;
|
|
||||||
|
|
||||||
pub fn getHostName(allocator: Allocator) !struct {
|
pub fn timeAsString(buf: [:0]u8, format: [:0]const u8) ![]u8 {
|
||||||
buffer: []u8,
|
const timer = std.time.timestamp();
|
||||||
slice: []const u8,
|
|
||||||
} {
|
|
||||||
const hostname_sysconf = sysconf(_SC_HOST_NAME_MAX);
|
|
||||||
const hostname_max_length: u64 = if (hostname_sysconf < 0) @intCast(_POSIX_HOST_NAME_MAX) else @intCast(hostname_sysconf);
|
|
||||||
|
|
||||||
const buffer = try allocator.alloc(u8, hostname_max_length);
|
|
||||||
errdefer allocator.free(buffer);
|
|
||||||
|
|
||||||
const error_code = std.c.gethostname(buffer.ptr, hostname_max_length);
|
|
||||||
if (error_code < 0) return error.CannotGetHostName;
|
|
||||||
|
|
||||||
var hostname_length: u64 = 0;
|
|
||||||
for (buffer, 0..) |char, i| {
|
|
||||||
if (char == 0) {
|
|
||||||
hostname_length = i + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return .{
|
|
||||||
.buffer = buffer,
|
|
||||||
.slice = buffer[0..hostname_length],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn timeAsString(allocator: Allocator, format: [:0]const u8, max_length: u64) ![:0]u8 {
|
|
||||||
const timer = time(null);
|
|
||||||
const tm_info = localtime(&timer);
|
const tm_info = localtime(&timer);
|
||||||
const buffer = try allocator.allocSentinel(u8, max_length, 0);
|
|
||||||
errdefer allocator.free(buffer);
|
|
||||||
|
|
||||||
if (strftime(buffer, max_length, format, tm_info) < 0) return error.CannotGetFormattedTime;
|
const len = strftime(buf, buf.len, format, tm_info);
|
||||||
|
if (len < 0) return error.CannotGetFormattedTime;
|
||||||
|
|
||||||
return buffer;
|
return buf[0..len];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getLockState(console_dev: [:0]const u8) !struct {
|
pub fn getLockState(console_dev: [:0]const u8) !struct {
|
||||||
numlock: bool,
|
numlock: bool,
|
||||||
capslock: bool,
|
capslock: bool,
|
||||||
} {
|
} {
|
||||||
const fd = std.c.open(console_dev, O_RDONLY);
|
const fd = std.c.open(console_dev, .{ .ACCMODE = .RDONLY });
|
||||||
if (fd < 0) return error.CannotOpenConsoleDev;
|
if (fd < 0) return error.CannotOpenConsoleDev;
|
||||||
|
defer _ = std.c.close(fd);
|
||||||
|
|
||||||
var numlock = false;
|
var numlock = false;
|
||||||
var capslock = false;
|
var capslock = false;
|
||||||
|
|
@ -142,8 +101,6 @@ pub fn getLockState(console_dev: [:0]const u8) !struct {
|
||||||
capslock = (led & K_CAPSLOCK) != 0;
|
capslock = (led & K_CAPSLOCK) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = std.c.close(fd);
|
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.numlock = numlock,
|
.numlock = numlock,
|
||||||
.capslock = capslock,
|
.capslock = capslock,
|
||||||
|
|
|
||||||
178
src/main.zig
178
src/main.zig
|
|
@ -16,14 +16,13 @@ const Config = @import("config/Config.zig");
|
||||||
const Lang = @import("config/Lang.zig");
|
const Lang = @import("config/Lang.zig");
|
||||||
const Save = @import("config/Save.zig");
|
const Save = @import("config/Save.zig");
|
||||||
const migrator = @import("config/migrator.zig");
|
const migrator = @import("config/migrator.zig");
|
||||||
const ViMode = @import("enums.zig").ViMode;
|
|
||||||
const SharedError = @import("SharedError.zig");
|
const SharedError = @import("SharedError.zig");
|
||||||
const utils = @import("tui/utils.zig");
|
const utils = @import("tui/utils.zig");
|
||||||
|
|
||||||
const Ini = ini.Ini;
|
const Ini = ini.Ini;
|
||||||
const termbox = interop.termbox;
|
const termbox = interop.termbox;
|
||||||
|
|
||||||
var session_pid: std.os.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 {
|
||||||
if (session_pid == 0) return;
|
if (session_pid == 0) return;
|
||||||
|
|
||||||
|
|
@ -53,7 +52,7 @@ pub fn main() !void {
|
||||||
);
|
);
|
||||||
|
|
||||||
var diag = clap.Diagnostic{};
|
var diag = clap.Diagnostic{};
|
||||||
var res = clap.parse(clap.Help, ¶ms, clap.parsers.default, .{ .diagnostic = &diag }) catch |err| {
|
var res = clap.parse(clap.Help, ¶ms, clap.parsers.default, .{ .diagnostic = &diag, .allocator = allocator }) catch |err| {
|
||||||
diag.report(stderr, err) catch {};
|
diag.report(stderr, err) catch {};
|
||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
|
|
@ -61,17 +60,18 @@ pub fn main() !void {
|
||||||
|
|
||||||
var config: Config = undefined;
|
var config: Config = undefined;
|
||||||
var lang: Lang = undefined;
|
var lang: Lang = undefined;
|
||||||
|
var save: Save = undefined;
|
||||||
var info_line = InfoLine{};
|
var info_line = InfoLine{};
|
||||||
|
|
||||||
if (res.args.help != 0) {
|
if (res.args.help != 0) {
|
||||||
try clap.help(stderr, clap.Help, ¶ms, .{});
|
try clap.help(stderr, clap.Help, ¶ms, .{});
|
||||||
|
|
||||||
_ = try stderr.write("Note: if you want to configure Ly, please check the config file, which is usually located at /etc/ly/config.ini.\n");
|
_ = try stderr.write("Note: if you want to configure Ly, please check the config file, which is usually located at /etc/ly/config.ini.\n");
|
||||||
std.os.exit(0);
|
std.process.exit(0);
|
||||||
}
|
}
|
||||||
if (res.args.version != 0) {
|
if (res.args.version != 0) {
|
||||||
_ = try stderr.write("Ly version " ++ build_options.version ++ "\n");
|
_ = try stderr.write("Ly version " ++ build_options.version ++ "\n");
|
||||||
std.os.exit(0);
|
std.process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load configuration file
|
// Load configuration file
|
||||||
|
|
@ -81,66 +81,78 @@ pub fn main() !void {
|
||||||
var lang_ini = Ini(Lang).init(allocator);
|
var lang_ini = Ini(Lang).init(allocator);
|
||||||
defer lang_ini.deinit();
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compatibility with v0.6.0
|
||||||
|
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 "";
|
||||||
|
|
||||||
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.readToStruct(config_path) catch Config{};
|
config = config_ini.readFileToStructWithMap(config_path, mapped_config_fields) 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.readToStruct(lang_path) catch Lang{};
|
lang = lang_ini.readFileToStruct(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.readFileToStruct(save_path) catch migrator.tryMigrateSaveFile(&user_buf, config.save_file);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
config = config_ini.readToStruct(build_options.data_directory ++ "/config.ini") catch Config{};
|
config = config_ini.readFileToStructWithMap(build_options.data_directory ++ "/config.ini", mapped_config_fields) 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.readToStruct(lang_path) catch Lang{};
|
lang = lang_ini.readFileToStruct(lang_path) catch Lang{};
|
||||||
|
|
||||||
|
if (config.load) {
|
||||||
|
var user_buf: [32]u8 = undefined;
|
||||||
|
save = save_ini.readFileToStruct(save_path) catch migrator.tryMigrateSaveFile(&user_buf, config.save_file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize information line with host name
|
// Initialize information line with host name
|
||||||
var got_host_name = false;
|
|
||||||
var host_name_buffer: []u8 = undefined;
|
|
||||||
|
|
||||||
get_host_name: {
|
get_host_name: {
|
||||||
const host_name_struct = interop.getHostName(allocator) catch |err| {
|
var name_buf: [std.posix.HOST_NAME_MAX]u8 = undefined;
|
||||||
if (err == error.CannotGetHostName) {
|
const hostname = std.posix.gethostname(&name_buf) catch {
|
||||||
try info_line.setText(lang.err_hostname);
|
try info_line.setText(lang.err_hostname);
|
||||||
} else {
|
|
||||||
try info_line.setText(lang.err_alloc);
|
|
||||||
}
|
|
||||||
break :get_host_name;
|
break :get_host_name;
|
||||||
};
|
};
|
||||||
|
try info_line.setText(hostname);
|
||||||
got_host_name = true;
|
|
||||||
host_name_buffer = host_name_struct.buffer;
|
|
||||||
try info_line.setText(host_name_struct.slice);
|
|
||||||
}
|
|
||||||
|
|
||||||
defer {
|
|
||||||
if (got_host_name) allocator.free(host_name_buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize termbox
|
// Initialize termbox
|
||||||
_ = termbox.tb_init();
|
_ = termbox.tb_init();
|
||||||
defer termbox.tb_shutdown();
|
defer termbox.tb_shutdown();
|
||||||
|
|
||||||
const act = std.os.Sigaction{
|
const act = std.posix.Sigaction{
|
||||||
.handler = .{ .handler = &signalHandler },
|
.handler = .{ .handler = &signalHandler },
|
||||||
.mask = std.os.empty_sigset,
|
.mask = std.posix.empty_sigset,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
};
|
};
|
||||||
try std.os.sigaction(std.os.SIG.TERM, &act, null);
|
try std.posix.sigaction(std.posix.SIG.TERM, &act, null);
|
||||||
|
|
||||||
_ = termbox.tb_select_output_mode(termbox.TB_OUTPUT_NORMAL);
|
_ = termbox.tb_select_output_mode(termbox.TB_OUTPUT_NORMAL);
|
||||||
termbox.tb_clear();
|
termbox.tb_clear();
|
||||||
|
|
||||||
// Needed to reset termbox after auth
|
// Needed to reset termbox after auth
|
||||||
const tb_termios = try std.os.tcgetattr(std.os.STDIN_FILENO);
|
const tb_termios = try std.posix.tcgetattr(std.posix.STDIN_FILENO);
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
@ -151,11 +163,11 @@ pub fn main() !void {
|
||||||
var desktop = try Desktop.init(allocator, &buffer, config.max_desktop_len, lang);
|
var desktop = try Desktop.init(allocator, &buffer, config.max_desktop_len, lang);
|
||||||
defer desktop.deinit();
|
defer desktop.deinit();
|
||||||
|
|
||||||
desktop.addEnvironment(lang.shell, "", .shell) catch {
|
desktop.addEnvironment(.{ .Name = lang.shell }, "", .shell) catch {
|
||||||
try info_line.setText(lang.err_alloc);
|
try info_line.setText(lang.err_alloc);
|
||||||
};
|
};
|
||||||
if (config.xinitrc) |xinitrc| {
|
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);
|
try info_line.setText(lang.err_alloc);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -174,16 +186,10 @@ pub fn main() !void {
|
||||||
|
|
||||||
// Load last saved username and desktop selection, if any
|
// Load last saved username and desktop selection, if any
|
||||||
if (config.load) {
|
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| {
|
if (save.user) |user| {
|
||||||
try login.text.appendSlice(user);
|
try login.text.appendSlice(user);
|
||||||
login.end = user.len;
|
login.end = user.len;
|
||||||
|
login.cursor = login.end;
|
||||||
active_input = .password;
|
active_input = .password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,13 +252,7 @@ pub fn main() !void {
|
||||||
|
|
||||||
// Switch to selected TTY if possible
|
// Switch to selected TTY if possible
|
||||||
open_console_dev: {
|
open_console_dev: {
|
||||||
const console_dev_z = allocator.dupeZ(u8, config.console_dev) catch {
|
const fd = std.c.open(config.console_dev, .{ .ACCMODE = .WRONLY });
|
||||||
try info_line.setText(lang.err_alloc);
|
|
||||||
break :open_console_dev;
|
|
||||||
};
|
|
||||||
defer allocator.free(console_dev_z);
|
|
||||||
|
|
||||||
const fd = std.c.open(console_dev_z, interop.O_WRONLY);
|
|
||||||
defer _ = std.c.close(fd);
|
defer _ = std.c.close(fd);
|
||||||
|
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
|
|
@ -328,14 +328,13 @@ pub fn main() !void {
|
||||||
const xo = buffer.width / 2 - (format.len * (bigclock.WIDTH + 1)) / 2;
|
const xo = buffer.width / 2 - (format.len * (bigclock.WIDTH + 1)) / 2;
|
||||||
const yo = (buffer.height - buffer.box_height) / 2 - bigclock.HEIGHT - 2;
|
const yo = (buffer.height - buffer.box_height) / 2 - bigclock.HEIGHT - 2;
|
||||||
|
|
||||||
const clock_str = interop.timeAsString(allocator, format, format.len + 1) catch {
|
var clock_buf: [format.len + 1:0]u8 = undefined;
|
||||||
try info_line.setText(lang.err_alloc);
|
const clock_str = interop.timeAsString(&clock_buf, format) catch {
|
||||||
break :draw_big_clock;
|
break :draw_big_clock;
|
||||||
};
|
};
|
||||||
defer allocator.free(clock_str);
|
|
||||||
|
|
||||||
for (0..format.len) |i| {
|
for (clock_str, 0..) |c, i| {
|
||||||
const clock_cell = bigclock.clockCell(animate, clock_str[i], buffer.fg, buffer.bg);
|
const clock_cell = bigclock.clockCell(animate, c, buffer.fg, buffer.bg);
|
||||||
bigclock.alphaBlit(buffer.buffer, xo + i * (bigclock.WIDTH + 1), yo, buffer.width, buffer.height, clock_cell);
|
bigclock.alphaBlit(buffer.buffer, xo + i * (bigclock.WIDTH + 1), yo, buffer.width, buffer.height, clock_cell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -343,23 +342,14 @@ pub fn main() !void {
|
||||||
buffer.drawBoxCenter(!config.hide_borders, config.blank_box);
|
buffer.drawBoxCenter(!config.hide_borders, config.blank_box);
|
||||||
|
|
||||||
if (config.clock) |clock| draw_clock: {
|
if (config.clock) |clock| draw_clock: {
|
||||||
const clock_buffer = interop.timeAsString(allocator, clock, 32) catch {
|
var clock_buf: [32:0]u8 = undefined;
|
||||||
try info_line.setText(lang.err_alloc);
|
const clock_str = interop.timeAsString(&clock_buf, clock) catch {
|
||||||
break :draw_clock;
|
break :draw_clock;
|
||||||
};
|
};
|
||||||
defer allocator.free(clock_buffer);
|
|
||||||
|
|
||||||
var clock_str_length: u64 = 0;
|
if (clock_str.len == 0) return error.FormattedTimeEmpty;
|
||||||
for (clock_buffer, 0..) |char, i| {
|
|
||||||
if (char == 0) {
|
|
||||||
clock_str_length = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clock_str_length == 0) return error.FormattedTimeEmpty;
|
buffer.drawLabel(clock_str, buffer.width - clock_str.len, 0);
|
||||||
|
|
||||||
buffer.drawLabel(clock_buffer[0..clock_str_length], buffer.width - clock_str_length, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const label_x = buffer.box_x + buffer.margin_box_h;
|
const label_x = buffer.box_x + buffer.margin_box_h;
|
||||||
|
|
@ -405,12 +395,8 @@ pub fn main() !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_lock_state: {
|
draw_lock_state: {
|
||||||
const lock_state = interop.getLockState(config.console_dev) catch |err| {
|
const lock_state = interop.getLockState(config.console_dev) catch {
|
||||||
if (err == error.CannotOpenConsoleDev) {
|
try info_line.setText(lang.err_console_dev);
|
||||||
try info_line.setText(lang.err_console_dev);
|
|
||||||
} else {
|
|
||||||
try info_line.setText(lang.err_alloc);
|
|
||||||
}
|
|
||||||
break :draw_lock_state;
|
break :draw_lock_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -487,11 +473,8 @@ 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| {
|
||||||
const pid = try std.os.fork();
|
var sleep = std.ChildProcess.init(&[_][]const u8{ "/bin/sh", "-c", sleep_cmd }, allocator);
|
||||||
if (pid == 0) {
|
_ = sleep.spawnAndWait() catch .{};
|
||||||
std.process.execv(allocator, &[_][]const u8{ "/bin/sh", "-c", sleep_cmd }) catch std.os.exit(1);
|
|
||||||
std.os.exit(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -529,7 +512,7 @@ pub fn main() !void {
|
||||||
},
|
},
|
||||||
termbox.TB_KEY_ENTER => {
|
termbox.TB_KEY_ENTER => {
|
||||||
if (config.save) save_last_settings: {
|
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();
|
defer file.close();
|
||||||
|
|
||||||
const save_data = Save{
|
const save_data = Save{
|
||||||
|
|
@ -542,19 +525,26 @@ pub fn main() !void {
|
||||||
var shared_err = try SharedError.init();
|
var shared_err = try SharedError.init();
|
||||||
defer shared_err.deinit();
|
defer shared_err.deinit();
|
||||||
|
|
||||||
session_pid = try std.os.fork();
|
{
|
||||||
if (session_pid == 0) {
|
const login_text = try allocator.dupeZ(u8, login.text.items);
|
||||||
auth.authenticate(allocator, config, desktop, login, &password) catch |err| {
|
defer allocator.free(login_text);
|
||||||
shared_err.writeError(err);
|
const password_text = try allocator.dupeZ(u8, password.text.items);
|
||||||
std.os.exit(1);
|
defer allocator.free(password_text);
|
||||||
};
|
|
||||||
std.os.exit(0);
|
session_pid = try std.posix.fork();
|
||||||
|
if (session_pid == 0) {
|
||||||
|
auth.authenticate(config, desktop, login_text, password_text) catch |err| {
|
||||||
|
shared_err.writeError(err);
|
||||||
|
std.process.exit(1);
|
||||||
|
};
|
||||||
|
std.process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = std.posix.waitpid(session_pid, 0);
|
||||||
|
session_pid = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = std.os.waitpid(session_pid, 0);
|
const auth_err = shared_err.readError();
|
||||||
session_pid = -1;
|
|
||||||
|
|
||||||
var auth_err = shared_err.readError();
|
|
||||||
if (auth_err) |err| {
|
if (auth_err) |err| {
|
||||||
auth_fails += 1;
|
auth_fails += 1;
|
||||||
active_input = .password;
|
active_input = .password;
|
||||||
|
|
@ -565,17 +555,15 @@ pub fn main() !void {
|
||||||
try info_line.setText(lang.logout);
|
try info_line.setText(lang.logout);
|
||||||
}
|
}
|
||||||
|
|
||||||
try std.os.tcsetattr(std.os.STDIN_FILENO, .FLUSH, tb_termios);
|
try std.posix.tcsetattr(std.posix.STDIN_FILENO, .FLUSH, tb_termios);
|
||||||
termbox.tb_clear();
|
termbox.tb_clear();
|
||||||
termbox.tb_present();
|
|
||||||
|
|
||||||
update = true;
|
update = true;
|
||||||
|
|
||||||
const pid = try std.os.fork();
|
var restore_cursor = std.ChildProcess.init(&[_][]const u8{ "/bin/sh", "-c", config.term_restore_cursor_cmd }, allocator);
|
||||||
if (pid == 0) {
|
_ = restore_cursor.spawnAndWait() catch .{};
|
||||||
std.process.execv(allocator, &[_][]const u8{ "/bin/sh", "-c", config.term_restore_cursor_cmd }) catch std.os.exit(1);
|
|
||||||
std.os.exit(0);
|
termbox.tb_present();
|
||||||
}
|
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
if (!insert_mode) {
|
if (!insert_mode) {
|
||||||
|
|
@ -649,6 +637,6 @@ fn getAuthErrorMsg(err: anyerror, lang: Lang) []const u8 {
|
||||||
error.PamSystemError => lang.err_pam_sys,
|
error.PamSystemError => lang.err_pam_sys,
|
||||||
error.PamUserUnknown => lang.err_pam_user_unknown,
|
error.PamUserUnknown => lang.err_pam_user_unknown,
|
||||||
error.PamAbort => lang.err_pam_abort,
|
error.PamAbort => lang.err_pam_abort,
|
||||||
else => "An unknown error occurred",
|
else => lang.err_unknown,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ 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 Allocator = std.mem.Allocator;
|
|
||||||
const Random = std.rand.Random;
|
const Random = std.rand.Random;
|
||||||
|
|
||||||
const termbox = interop.termbox;
|
const termbox = interop.termbox;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ const Allocator = std.mem.Allocator;
|
||||||
const EnvironmentList = std.ArrayList(Environment);
|
const EnvironmentList = std.ArrayList(Environment);
|
||||||
|
|
||||||
const DisplayServer = enums.DisplayServer;
|
const DisplayServer = enums.DisplayServer;
|
||||||
const ViMode = enums.ViMode;
|
|
||||||
|
|
||||||
const termbox = interop.termbox;
|
const termbox = interop.termbox;
|
||||||
|
|
||||||
|
|
@ -17,7 +16,9 @@ const Desktop = @This();
|
||||||
|
|
||||||
pub const Environment = struct {
|
pub const Environment = struct {
|
||||||
entry_ini: ?Ini(Entry) = null,
|
entry_ini: ?Ini(Entry) = null,
|
||||||
name: []const u8 = "",
|
name: [:0]const u8 = "",
|
||||||
|
xdg_session_desktop: [:0]const u8 = "",
|
||||||
|
xdg_desktop_names: ?[:0]const u8 = "",
|
||||||
cmd: []const u8 = "",
|
cmd: []const u8 = "",
|
||||||
specifier: []const u8 = "",
|
specifier: []const u8 = "",
|
||||||
display_server: DisplayServer = .wayland,
|
display_server: DisplayServer = .wayland,
|
||||||
|
|
@ -25,11 +26,11 @@ pub const Environment = struct {
|
||||||
|
|
||||||
const DesktopEntry = struct {
|
const DesktopEntry = struct {
|
||||||
Exec: []const u8 = "",
|
Exec: []const u8 = "",
|
||||||
Name: []const u8 = "",
|
Name: [:0]const u8 = "",
|
||||||
DesktopNames: []const u8 = "",
|
DesktopNames: ?[]const u8 = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Entry = struct { Desktop_Entry: DesktopEntry = DesktopEntry{} };
|
pub const Entry = struct { @"Desktop Entry": DesktopEntry = DesktopEntry{} };
|
||||||
|
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
buffer: *TerminalBuffer,
|
buffer: *TerminalBuffer,
|
||||||
|
|
@ -56,6 +57,8 @@ pub fn init(allocator: Allocator, buffer: *TerminalBuffer, max_length: u64, lang
|
||||||
pub fn deinit(self: Desktop) void {
|
pub fn deinit(self: Desktop) void {
|
||||||
for (self.environments.items) |*environment| {
|
for (self.environments.items) |*environment| {
|
||||||
if (environment.entry_ini) |*entry_ini| entry_ini.deinit();
|
if (environment.entry_ini) |*entry_ini| entry_ini.deinit();
|
||||||
|
if (environment.xdg_desktop_names) |desktop_name| self.allocator.free(desktop_name);
|
||||||
|
self.allocator.free(environment.xdg_session_desktop);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.environments.deinit();
|
self.environments.deinit();
|
||||||
|
|
@ -67,11 +70,29 @@ pub fn position(self: *Desktop, x: u64, y: u64, visible_length: u64) void {
|
||||||
self.visible_length = visible_length;
|
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, xdg_session_desktop: []const u8, display_server: DisplayServer) !void {
|
||||||
|
var xdg_desktop_names: ?[:0]const u8 = null;
|
||||||
|
if (entry.DesktopNames) |desktop_names| {
|
||||||
|
const desktop_names_z = try self.allocator.dupeZ(u8, desktop_names);
|
||||||
|
for (desktop_names_z) |*c| {
|
||||||
|
if (c.* == ';') c.* = ':';
|
||||||
|
}
|
||||||
|
xdg_desktop_names = desktop_names_z;
|
||||||
|
}
|
||||||
|
|
||||||
|
errdefer {
|
||||||
|
if (xdg_desktop_names) |desktop_names| self.allocator.free(desktop_names);
|
||||||
|
}
|
||||||
|
|
||||||
|
const session_desktop = try self.allocator.dupeZ(u8, xdg_session_desktop);
|
||||||
|
errdefer self.allocator.free(session_desktop);
|
||||||
|
|
||||||
try self.environments.append(.{
|
try self.environments.append(.{
|
||||||
.entry_ini = null,
|
.entry_ini = null,
|
||||||
.name = name,
|
.name = entry.Name,
|
||||||
.cmd = cmd,
|
.xdg_session_desktop = session_desktop,
|
||||||
|
.xdg_desktop_names = xdg_desktop_names,
|
||||||
|
.cmd = entry.Exec,
|
||||||
.specifier = switch (display_server) {
|
.specifier = switch (display_server) {
|
||||||
.wayland => self.lang.wayland,
|
.wayland => self.lang.wayland,
|
||||||
.x11 => self.lang.x11,
|
.x11 => self.lang.x11,
|
||||||
|
|
@ -83,11 +104,30 @@ pub fn addEnvironment(self: *Desktop, name: []const u8, cmd: []const u8, display
|
||||||
self.current = self.environments.items.len - 1;
|
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), xdg_session_desktop: []const u8, display_server: DisplayServer) !void {
|
||||||
|
const entry = entry_ini.data.@"Desktop Entry";
|
||||||
|
var xdg_desktop_names: ?[:0]const u8 = null;
|
||||||
|
if (entry.DesktopNames) |desktop_names| {
|
||||||
|
const desktop_names_z = try self.allocator.dupeZ(u8, desktop_names);
|
||||||
|
for (desktop_names_z) |*c| {
|
||||||
|
if (c.* == ';') c.* = ':';
|
||||||
|
}
|
||||||
|
xdg_desktop_names = desktop_names_z;
|
||||||
|
}
|
||||||
|
|
||||||
|
errdefer {
|
||||||
|
if (xdg_desktop_names) |desktop_names| self.allocator.free(desktop_names);
|
||||||
|
}
|
||||||
|
|
||||||
|
const session_desktop = try self.allocator.dupeZ(u8, xdg_session_desktop);
|
||||||
|
errdefer self.allocator.free(session_desktop);
|
||||||
|
|
||||||
try self.environments.append(.{
|
try self.environments.append(.{
|
||||||
.entry_ini = entry_ini,
|
.entry_ini = entry_ini,
|
||||||
.name = name,
|
.name = entry.Name,
|
||||||
.cmd = cmd,
|
.xdg_session_desktop = session_desktop,
|
||||||
|
.xdg_desktop_names = xdg_desktop_names,
|
||||||
|
.cmd = entry.Exec,
|
||||||
.specifier = switch (display_server) {
|
.specifier = switch (display_server) {
|
||||||
.wayland => self.lang.wayland,
|
.wayland => self.lang.wayland,
|
||||||
.x11 => self.lang.x11,
|
.x11 => self.lang.x11,
|
||||||
|
|
@ -100,7 +140,7 @@ pub fn addEnvironmentWithIni(self: *Desktop, entry_ini: Ini(Entry), name: []cons
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn crawl(self: *Desktop, path: []const u8, display_server: DisplayServer) !void {
|
pub fn crawl(self: *Desktop, path: []const u8, display_server: DisplayServer) !void {
|
||||||
var iterable_directory = std.fs.openIterableDirAbsolute(path, .{}) catch return;
|
var iterable_directory = std.fs.openDirAbsolute(path, .{ .iterate = true }) catch return;
|
||||||
defer iterable_directory.close();
|
defer iterable_directory.close();
|
||||||
|
|
||||||
var iterator = iterable_directory.iterate();
|
var iterator = iterable_directory.iterate();
|
||||||
|
|
@ -110,9 +150,19 @@ 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);
|
||||||
var entry = try entry_ini.readToStruct(entry_path);
|
_ = try entry_ini.readFileToStruct(entry_path);
|
||||||
|
errdefer entry_ini.deinit();
|
||||||
|
|
||||||
try self.addEnvironmentWithIni(entry_ini, entry.Desktop_Entry.Name, entry.Desktop_Entry.Exec, display_server);
|
var xdg_session_desktop: []const u8 = undefined;
|
||||||
|
const maybe_desktop_names = entry_ini.data.@"Desktop Entry".DesktopNames;
|
||||||
|
if (maybe_desktop_names) |desktop_names| {
|
||||||
|
xdg_session_desktop = std.mem.sliceTo(desktop_names, ';');
|
||||||
|
} else {
|
||||||
|
// if DesktopNames is empty, we'll take the name of the session file
|
||||||
|
xdg_session_desktop = std.fs.path.stem(item.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
try self.addEnvironmentWithIni(entry_ini, xdg_session_desktop, display_server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ const std = @import("std");
|
||||||
const interop = @import("../../interop.zig");
|
const interop = @import("../../interop.zig");
|
||||||
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
||||||
const utils = @import("../utils.zig");
|
const utils = @import("../utils.zig");
|
||||||
const ViMode = @import("../../enums.zig").ViMode;
|
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const DynamicString = std.ArrayList(u8);
|
const DynamicString = std.ArrayList(u8);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue