mirror of
https://github.com/fairyglade/ly.git
synced 2026-05-06 07:10:36 +00:00
Update to Zig 0.16.0 (#962)
Signed-off-by: AnErrupTion <anerruption@disroot.org> ## What are the changes about? Ports the code base to Zig 0.16.0. ## What existing issue does this resolve? N/A ## Pre-requisites - [x] I have tested & confirmed the changes work locally - [x] I have run `zig fmt` throughout my changes Reviewed-on: https://codeberg.org/fairyglade/ly/pulls/962
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,3 +3,4 @@ zig-cache/
|
|||||||
zig-out/
|
zig-out/
|
||||||
valgrind.log
|
valgrind.log
|
||||||
.zig-cache
|
.zig-cache
|
||||||
|
zig-pkg
|
||||||
|
|||||||
271
build.zig
271
build.zig
@@ -12,7 +12,7 @@ const InitSystem = enum {
|
|||||||
freebsd,
|
freebsd,
|
||||||
};
|
};
|
||||||
|
|
||||||
const min_zig_string = "0.15.0";
|
const min_zig_string = "0.16.0";
|
||||||
const current_zig = builtin.zig_version;
|
const current_zig = builtin.zig_version;
|
||||||
|
|
||||||
// Implementing zig version detection through compile time
|
// Implementing zig version detection through compile time
|
||||||
@@ -67,8 +67,8 @@ pub fn build(b: *std.Build) !void {
|
|||||||
.root_source_file = b.path("src/main.zig"),
|
.root_source_file = b.path("src/main.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
|
.link_libc = true,
|
||||||
}),
|
}),
|
||||||
// Here until the native backend matures in terms of performance
|
|
||||||
.use_llvm = true,
|
.use_llvm = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -80,9 +80,8 @@ 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.linkSystemLibrary("pam");
|
exe.root_module.linkSystemLibrary("pam", .{});
|
||||||
if (enable_x11_support) exe.linkSystemLibrary("xcb");
|
if (enable_x11_support) exe.root_module.linkSystemLibrary("xcb", .{});
|
||||||
exe.linkLibC();
|
|
||||||
|
|
||||||
b.installArtifact(exe);
|
b.installArtifact(exe);
|
||||||
|
|
||||||
@@ -113,6 +112,8 @@ pub fn build(b: *std.Build) !void {
|
|||||||
pub fn Installer(install_config: bool) type {
|
pub fn Installer(install_config: bool) type {
|
||||||
return struct {
|
return struct {
|
||||||
pub fn make(step: *std.Build.Step, _: std.Build.Step.MakeOptions) !void {
|
pub fn make(step: *std.Build.Step, _: std.Build.Step.MakeOptions) !void {
|
||||||
|
var threaded: std.Io.Threaded = .init_single_threaded;
|
||||||
|
const io = threaded.io();
|
||||||
const allocator = step.owner.allocator;
|
const allocator = step.owner.allocator;
|
||||||
|
|
||||||
var patch_map = PatchMap.init(allocator);
|
var patch_map = PatchMap.init(allocator);
|
||||||
@@ -127,75 +128,75 @@ pub fn Installer(install_config: bool) type {
|
|||||||
// instead to shutdown the system.
|
// instead to shutdown the system.
|
||||||
try patch_map.put("$PLATFORM_SHUTDOWN_ARG", if (init_system == .freebsd) "-p" else "-a");
|
try patch_map.put("$PLATFORM_SHUTDOWN_ARG", if (init_system == .freebsd) "-p" else "-a");
|
||||||
|
|
||||||
try install_ly(allocator, patch_map, install_config);
|
try install_ly(allocator, io, patch_map, install_config);
|
||||||
try install_service(allocator, patch_map);
|
try install_service(allocator, io, patch_map);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install_ly(allocator: std.mem.Allocator, patch_map: PatchMap, install_config: bool) !void {
|
fn install_ly(allocator: std.mem.Allocator, io: std.Io, patch_map: PatchMap, install_config: bool) !void {
|
||||||
const ly_config_directory = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/ly" });
|
const ly_config_directory = try std.Io.Dir.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/ly" });
|
||||||
|
|
||||||
std.fs.cwd().makePath(ly_config_directory) catch {
|
std.Io.Dir.cwd().createDirPath(io, ly_config_directory) catch {
|
||||||
std.debug.print("warn: {s} already exists as a directory.\n", .{ly_config_directory});
|
std.debug.print("warn: {s} already exists as a directory.\n", .{ly_config_directory});
|
||||||
};
|
};
|
||||||
|
|
||||||
const ly_custom_sessions_directory = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/ly/custom-sessions" });
|
const ly_custom_sessions_directory = try std.Io.Dir.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/ly/custom-sessions" });
|
||||||
|
|
||||||
std.fs.cwd().makePath(ly_custom_sessions_directory) catch {
|
std.Io.Dir.cwd().createDirPath(io, ly_custom_sessions_directory) catch {
|
||||||
std.debug.print("warn: {s} already exists as a directory.\n", .{ly_custom_sessions_directory});
|
std.debug.print("warn: {s} already exists as a directory.\n", .{ly_custom_sessions_directory});
|
||||||
};
|
};
|
||||||
|
|
||||||
const ly_lang_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/ly/lang" });
|
const ly_lang_path = try std.Io.Dir.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/ly/lang" });
|
||||||
std.fs.cwd().makePath(ly_lang_path) catch {
|
std.Io.Dir.cwd().createDirPath(io, ly_lang_path) catch {
|
||||||
std.debug.print("warn: {s} already exists as a directory.\n", .{ly_lang_path});
|
std.debug.print("warn: {s} already exists as a directory.\n", .{ly_lang_path});
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
const exe_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, prefix_directory, "/bin" });
|
const exe_path = try std.Io.Dir.path.join(allocator, &[_][]const u8{ dest_directory, prefix_directory, "/bin" });
|
||||||
std.fs.cwd().makePath(exe_path) catch {
|
std.Io.Dir.cwd().createDirPath(io, exe_path) catch {
|
||||||
if (!std.mem.eql(u8, dest_directory, "")) {
|
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.Io.Dir.cwd().openDir(io, exe_path, .{}) catch unreachable;
|
||||||
defer executable_dir.close();
|
defer executable_dir.close(io);
|
||||||
|
|
||||||
try installFile("zig-out/bin/ly", executable_dir, exe_path, executable_name, .{});
|
try installFile(io, "zig-out/bin/ly", executable_dir, exe_path, executable_name, .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var config_dir = std.fs.cwd().openDir(ly_config_directory, .{}) catch unreachable;
|
var config_dir = std.Io.Dir.cwd().openDir(io, ly_config_directory, .{}) catch unreachable;
|
||||||
defer config_dir.close();
|
defer config_dir.close(io);
|
||||||
|
|
||||||
if (install_config) {
|
if (install_config) {
|
||||||
const patched_config = try patchFile(allocator, "res/config.ini", patch_map);
|
const patched_config = try patchFile(allocator, io, "res/config.ini", patch_map);
|
||||||
try installText(patched_config, config_dir, ly_config_directory, "config.ini", .{});
|
try installText(io, patched_config, config_dir, ly_config_directory, "config.ini", .{});
|
||||||
|
|
||||||
try installFile("res/startup.sh", config_dir, ly_config_directory, "startup.sh", .{ .override_mode = 0o755 });
|
try installFile(io, "res/startup.sh", config_dir, ly_config_directory, "startup.sh", .{ .permissions = .fromMode(0o755) });
|
||||||
}
|
}
|
||||||
|
|
||||||
const patched_example_config = try patchFile(allocator, "res/config.ini", patch_map);
|
const patched_example_config = try patchFile(allocator, io, "res/config.ini", patch_map);
|
||||||
try installText(patched_example_config, config_dir, ly_config_directory, "config.ini.example", .{});
|
try installText(io, patched_example_config, config_dir, ly_config_directory, "config.ini.example", .{});
|
||||||
|
|
||||||
const patched_setup = try patchFile(allocator, "res/setup.sh", patch_map);
|
const patched_setup = try patchFile(allocator, io, "res/setup.sh", patch_map);
|
||||||
try installText(patched_setup, config_dir, ly_config_directory, "setup.sh", .{ .mode = 0o755 });
|
try installText(io, patched_setup, config_dir, ly_config_directory, "setup.sh", .{ .permissions = .fromMode(0o755) });
|
||||||
|
|
||||||
try installFile("res/example.dur", config_dir, ly_config_directory, "example.dur", .{ .override_mode = 0o755 });
|
try installFile(io, "res/example.dur", config_dir, ly_config_directory, "example.dur", .{ .permissions = .fromMode(0o755) });
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var custom_sessions_dir = std.fs.cwd().openDir(ly_custom_sessions_directory, .{}) catch unreachable;
|
var custom_sessions_dir = std.Io.Dir.cwd().openDir(io, ly_custom_sessions_directory, .{}) catch unreachable;
|
||||||
defer custom_sessions_dir.close();
|
defer custom_sessions_dir.close(io);
|
||||||
|
|
||||||
const patched_readme = try patchFile(allocator, "res/custom-sessions/README", patch_map);
|
const patched_readme = try patchFile(allocator, io, "res/custom-sessions/README", patch_map);
|
||||||
try installText(patched_readme, custom_sessions_dir, ly_custom_sessions_directory, "README", .{});
|
try installText(io, patched_readme, custom_sessions_dir, ly_custom_sessions_directory, "README", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var lang_dir = std.fs.cwd().openDir(ly_lang_path, .{}) catch unreachable;
|
var lang_dir = std.Io.Dir.cwd().openDir(io, ly_lang_path, .{}) catch unreachable;
|
||||||
defer lang_dir.close();
|
defer lang_dir.close(io);
|
||||||
|
|
||||||
const languages = [_][]const u8{
|
const languages = [_][]const u8{
|
||||||
"ar.ini",
|
"ar.ini",
|
||||||
@@ -221,66 +222,66 @@ fn install_ly(allocator: std.mem.Allocator, patch_map: PatchMap, install_config:
|
|||||||
};
|
};
|
||||||
|
|
||||||
inline for (languages) |language| {
|
inline for (languages) |language| {
|
||||||
try installFile("res/lang/" ++ language, lang_dir, ly_lang_path, language, .{});
|
try installFile(io, "res/lang/" ++ language, lang_dir, ly_lang_path, language, .{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const pam_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/pam.d" });
|
const pam_path = try std.Io.Dir.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/pam.d" });
|
||||||
std.fs.cwd().makePath(pam_path) catch {
|
std.Io.Dir.cwd().createDirPath(io, pam_path) catch {
|
||||||
if (!std.mem.eql(u8, dest_directory, "")) {
|
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.Io.Dir.cwd().openDir(io, pam_path, .{}) catch unreachable;
|
||||||
defer pam_dir.close();
|
defer pam_dir.close(io);
|
||||||
|
|
||||||
try installFile(if (init_system == .freebsd) "res/pam.d/ly-freebsd" else "res/pam.d/ly-linux", pam_dir, pam_path, "ly", .{ .override_mode = 0o644 });
|
try installFile(io, if (init_system == .freebsd) "res/pam.d/ly-freebsd" else "res/pam.d/ly-linux", pam_dir, pam_path, "ly", .{ .permissions = .fromMode(0o644) });
|
||||||
try installFile(if (init_system == .freebsd) "res/pam.d/ly-freebsd-autologin" else "res/pam.d/ly-linux-autologin", pam_dir, pam_path, "ly-autologin", .{ .override_mode = 0o644 });
|
try installFile(io, if (init_system == .freebsd) "res/pam.d/ly-freebsd-autologin" else "res/pam.d/ly-linux-autologin", pam_dir, pam_path, "ly-autologin", .{ .permissions = .fromMode(0o644) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install_service(allocator: std.mem.Allocator, patch_map: PatchMap) !void {
|
fn install_service(allocator: std.mem.Allocator, io: std.Io, patch_map: PatchMap) !void {
|
||||||
switch (init_system) {
|
switch (init_system) {
|
||||||
.systemd => {
|
.systemd => {
|
||||||
const service_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, prefix_directory, "/lib/systemd/system" });
|
const service_path = try std.Io.Dir.path.join(allocator, &[_][]const u8{ dest_directory, prefix_directory, "/lib/systemd/system" });
|
||||||
std.fs.cwd().makePath(service_path) catch {};
|
std.Io.Dir.cwd().createDirPath(io, service_path) catch {};
|
||||||
var service_dir = std.fs.cwd().openDir(service_path, .{}) catch unreachable;
|
var service_dir = std.Io.Dir.cwd().openDir(io, service_path, .{}) catch unreachable;
|
||||||
defer service_dir.close();
|
defer service_dir.close(io);
|
||||||
|
|
||||||
const patched_service = try patchFile(allocator, "res/ly@.service", patch_map);
|
const patched_service = try patchFile(allocator, io, "res/ly@.service", patch_map);
|
||||||
try installText(patched_service, service_dir, service_path, "ly@.service", .{ .mode = 0o644 });
|
try installText(io, patched_service, service_dir, service_path, "ly@.service", .{ .permissions = .fromMode(0o644) });
|
||||||
|
|
||||||
const patched_kmsconvt_service = try patchFile(allocator, "res/ly-kmsconvt@.service", patch_map);
|
const patched_kmsconvt_service = try patchFile(allocator, io, "res/ly-kmsconvt@.service", patch_map);
|
||||||
try installText(patched_kmsconvt_service, service_dir, service_path, "ly-kmsconvt@.service", .{ .mode = 0o644 });
|
try installText(io, patched_kmsconvt_service, service_dir, service_path, "ly-kmsconvt@.service", .{ .permissions = .fromMode(0o644) });
|
||||||
},
|
},
|
||||||
.openrc => {
|
.openrc => {
|
||||||
const service_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/init.d" });
|
const service_path = try std.Io.Dir.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/init.d" });
|
||||||
std.fs.cwd().makePath(service_path) catch {};
|
std.Io.Dir.cwd().createDirPath(io, service_path) catch {};
|
||||||
var service_dir = std.fs.cwd().openDir(service_path, .{}) catch unreachable;
|
var service_dir = std.Io.Dir.cwd().openDir(io, service_path, .{}) catch unreachable;
|
||||||
defer service_dir.close();
|
defer service_dir.close(io);
|
||||||
|
|
||||||
const patched_service = try patchFile(allocator, "res/ly-openrc", patch_map);
|
const patched_service = try patchFile(allocator, io, "res/ly-openrc", patch_map);
|
||||||
try installText(patched_service, service_dir, service_path, executable_name, .{ .mode = 0o755 });
|
try installText(io, patched_service, service_dir, service_path, executable_name, .{ .permissions = .fromMode(0o755) });
|
||||||
},
|
},
|
||||||
.runit => {
|
.runit => {
|
||||||
const service_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/sv/ly" });
|
const service_path = try std.Io.Dir.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/sv/ly" });
|
||||||
std.fs.cwd().makePath(service_path) catch {};
|
std.Io.Dir.cwd().createDirPath(io, service_path) catch {};
|
||||||
var service_dir = std.fs.cwd().openDir(service_path, .{}) catch unreachable;
|
var service_dir = std.Io.Dir.cwd().openDir(io, service_path, .{}) catch unreachable;
|
||||||
defer service_dir.close();
|
defer service_dir.close(io);
|
||||||
|
|
||||||
const supervise_path = try std.fs.path.join(allocator, &[_][]const u8{ service_path, "supervise" });
|
const supervise_path = try std.Io.Dir.path.join(allocator, &[_][]const u8{ service_path, "supervise" });
|
||||||
|
|
||||||
const patched_conf = try patchFile(allocator, "res/ly-runit-service/conf", patch_map);
|
const patched_conf = try patchFile(allocator, io, "res/ly-runit-service/conf", patch_map);
|
||||||
try installText(patched_conf, service_dir, service_path, "conf", .{});
|
try installText(io, patched_conf, service_dir, service_path, "conf", .{});
|
||||||
|
|
||||||
try installFile("res/ly-runit-service/finish", service_dir, service_path, "finish", .{ .override_mode = 0o755 });
|
try installFile(io, "res/ly-runit-service/finish", service_dir, service_path, "finish", .{ .permissions = .fromMode(0o755) });
|
||||||
|
|
||||||
const patched_run = try patchFile(allocator, "res/ly-runit-service/run", patch_map);
|
const patched_run = try patchFile(allocator, io, "res/ly-runit-service/run", patch_map);
|
||||||
try installText(patched_run, service_dir, service_path, "run", .{ .mode = 0o755 });
|
try installText(io, patched_run, service_dir, service_path, "run", .{ .permissions = .fromMode(0o755) });
|
||||||
|
|
||||||
std.fs.cwd().symLink("/run/runit/supervise.ly", supervise_path, .{}) catch |err| {
|
std.Io.Dir.cwd().symLink(io, "/run/runit/supervise.ly", supervise_path, .{}) catch |err| {
|
||||||
if (err == error.PathAlreadyExists) {
|
if (err == error.PathAlreadyExists) {
|
||||||
std.debug.print("warn: /run/runit/supervise.ly already exists as a symbolic link.\n", .{});
|
std.debug.print("warn: /run/runit/supervise.ly already exists as a symbolic link.\n", .{});
|
||||||
} else {
|
} else {
|
||||||
@@ -290,49 +291,49 @@ fn install_service(allocator: std.mem.Allocator, patch_map: PatchMap) !void {
|
|||||||
std.debug.print("info: installed symlink /run/runit/supervise.ly\n", .{});
|
std.debug.print("info: installed symlink /run/runit/supervise.ly\n", .{});
|
||||||
},
|
},
|
||||||
.s6 => {
|
.s6 => {
|
||||||
const admin_service_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/s6/adminsv/default/contents.d" });
|
const admin_service_path = try std.Io.Dir.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/s6/adminsv/default/contents.d" });
|
||||||
std.fs.cwd().makePath(admin_service_path) catch {};
|
std.Io.Dir.cwd().createDirPath(io, admin_service_path) catch {};
|
||||||
var admin_service_dir = std.fs.cwd().openDir(admin_service_path, .{}) catch unreachable;
|
var admin_service_dir = std.Io.Dir.cwd().openDir(io, admin_service_path, .{}) catch unreachable;
|
||||||
defer admin_service_dir.close();
|
defer admin_service_dir.close(io);
|
||||||
|
|
||||||
const file = try admin_service_dir.createFile("ly-srv", .{});
|
const file = try admin_service_dir.createFile(io, "ly-srv", .{});
|
||||||
file.close();
|
file.close(io);
|
||||||
|
|
||||||
const service_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/s6/sv/ly-srv" });
|
const service_path = try std.Io.Dir.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/s6/sv/ly-srv" });
|
||||||
std.fs.cwd().makePath(service_path) catch {};
|
std.Io.Dir.cwd().createDirPath(io, service_path) catch {};
|
||||||
var service_dir = std.fs.cwd().openDir(service_path, .{}) catch unreachable;
|
var service_dir = std.Io.Dir.cwd().openDir(io, service_path, .{}) catch unreachable;
|
||||||
defer service_dir.close();
|
defer service_dir.close(io);
|
||||||
|
|
||||||
const patched_run = try patchFile(allocator, "res/ly-s6/run", patch_map);
|
const patched_run = try patchFile(allocator, io, "res/ly-s6/run", patch_map);
|
||||||
try installText(patched_run, service_dir, service_path, "run", .{ .mode = 0o755 });
|
try installText(io, patched_run, service_dir, service_path, "run", .{ .permissions = .fromMode(0o755) });
|
||||||
|
|
||||||
try installFile("res/ly-s6/type", service_dir, service_path, "type", .{});
|
try installFile(io, "res/ly-s6/type", service_dir, service_path, "type", .{});
|
||||||
},
|
},
|
||||||
.dinit => {
|
.dinit => {
|
||||||
const service_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/dinit.d" });
|
const service_path = try std.Io.Dir.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/dinit.d" });
|
||||||
std.fs.cwd().makePath(service_path) catch {};
|
std.Io.Dir.cwd().createDirPath(io, service_path) catch {};
|
||||||
var service_dir = std.fs.cwd().openDir(service_path, .{}) catch unreachable;
|
var service_dir = std.Io.Dir.cwd().openDir(io, service_path, .{}) catch unreachable;
|
||||||
defer service_dir.close();
|
defer service_dir.close(io);
|
||||||
|
|
||||||
const patched_service = try patchFile(allocator, "res/ly-dinit", patch_map);
|
const patched_service = try patchFile(allocator, io, "res/ly-dinit", patch_map);
|
||||||
try installText(patched_service, service_dir, service_path, "ly", .{});
|
try installText(io, patched_service, service_dir, service_path, "ly", .{});
|
||||||
},
|
},
|
||||||
.sysvinit => {
|
.sysvinit => {
|
||||||
const service_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/init.d" });
|
const service_path = try std.Io.Dir.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/init.d" });
|
||||||
std.fs.cwd().makePath(service_path) catch {};
|
std.Io.Dir.cwd().createDirPath(io, service_path) catch {};
|
||||||
var service_dir = std.fs.cwd().openDir(service_path, .{}) catch unreachable;
|
var service_dir = std.Io.Dir.cwd().openDir(io, service_path, .{}) catch unreachable;
|
||||||
defer service_dir.close();
|
defer service_dir.close(io);
|
||||||
|
|
||||||
const patched_service = try patchFile(allocator, "res/ly-sysvinit", patch_map);
|
const patched_service = try patchFile(allocator, io, "res/ly-sysvinit", patch_map);
|
||||||
try installText(patched_service, service_dir, service_path, "ly", .{ .mode = 0o755 });
|
try installText(io, patched_service, service_dir, service_path, "ly", .{ .permissions = .fromMode(0o755) });
|
||||||
},
|
},
|
||||||
.freebsd => {
|
.freebsd => {
|
||||||
const exe_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, prefix_directory, "/bin" });
|
const exe_path = try std.Io.Dir.path.join(allocator, &[_][]const u8{ dest_directory, prefix_directory, "/bin" });
|
||||||
var executable_dir = std.fs.cwd().openDir(exe_path, .{}) catch unreachable;
|
var executable_dir = std.Io.Dir.cwd().openDir(io, exe_path, .{}) catch unreachable;
|
||||||
defer executable_dir.close();
|
defer executable_dir.close(io);
|
||||||
|
|
||||||
const patched_wrapper = try patchFile(allocator, "res/ly-freebsd-wrapper", patch_map);
|
const patched_wrapper = try patchFile(allocator, io, "res/ly-freebsd-wrapper", patch_map);
|
||||||
try installText(patched_wrapper, executable_dir, exe_path, "ly_wrapper", .{ .mode = 0o755 });
|
try installText(io, patched_wrapper, executable_dir, exe_path, "ly_wrapper", .{ .permissions = .fromMode(0o755) });
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -340,33 +341,35 @@ fn install_service(allocator: std.mem.Allocator, patch_map: PatchMap) !void {
|
|||||||
pub fn Uninstaller(uninstall_config: bool) type {
|
pub fn Uninstaller(uninstall_config: bool) type {
|
||||||
return struct {
|
return struct {
|
||||||
pub fn make(step: *std.Build.Step, _: std.Build.Step.MakeOptions) !void {
|
pub fn make(step: *std.Build.Step, _: std.Build.Step.MakeOptions) !void {
|
||||||
|
var threaded: std.Io.Threaded = .init_single_threaded;
|
||||||
|
const io = threaded.io();
|
||||||
const allocator = step.owner.allocator;
|
const allocator = step.owner.allocator;
|
||||||
|
|
||||||
if (uninstall_config) {
|
if (uninstall_config) {
|
||||||
try deleteTree(allocator, config_directory, "/ly", "ly config directory not found");
|
try deleteTree(allocator, io, config_directory, "/ly", "ly config directory not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const exe_path = try std.fs.path.join(allocator, &[_][]const u8{ prefix_directory, "/bin/", executable_name });
|
const exe_path = try std.Io.Dir.path.join(allocator, &[_][]const u8{ prefix_directory, "/bin/", executable_name });
|
||||||
var success = true;
|
var success = true;
|
||||||
std.fs.cwd().deleteFile(exe_path) catch {
|
std.Io.Dir.cwd().deleteFile(io, exe_path) catch {
|
||||||
std.debug.print("warn: ly executable not found\n", .{});
|
std.debug.print("warn: ly executable not found\n", .{});
|
||||||
success = false;
|
success = false;
|
||||||
};
|
};
|
||||||
if (success) std.debug.print("info: deleted {s}\n", .{exe_path});
|
if (success) std.debug.print("info: deleted {s}\n", .{exe_path});
|
||||||
|
|
||||||
try deleteFile(allocator, config_directory, "/pam.d/ly", "ly pam file not found");
|
try deleteFile(allocator, io, config_directory, "/pam.d/ly", "ly pam file not found");
|
||||||
|
|
||||||
switch (init_system) {
|
switch (init_system) {
|
||||||
.systemd => try deleteFile(allocator, prefix_directory, "/lib/systemd/system/ly@.service", "systemd service not found"),
|
.systemd => try deleteFile(allocator, io, prefix_directory, "/lib/systemd/system/ly@.service", "systemd service not found"),
|
||||||
.openrc => try deleteFile(allocator, config_directory, "/init.d/ly", "openrc service not found"),
|
.openrc => try deleteFile(allocator, io, config_directory, "/init.d/ly", "openrc service not found"),
|
||||||
.runit => try deleteTree(allocator, config_directory, "/sv/ly", "runit service not found"),
|
.runit => try deleteTree(allocator, io, config_directory, "/sv/ly", "runit service not found"),
|
||||||
.s6 => {
|
.s6 => {
|
||||||
try deleteTree(allocator, config_directory, "/s6/sv/ly-srv", "s6 service not found");
|
try deleteTree(allocator, io, config_directory, "/s6/sv/ly-srv", "s6 service not found");
|
||||||
try deleteFile(allocator, config_directory, "/s6/adminsv/default/contents.d/ly-srv", "s6 admin service not found");
|
try deleteFile(allocator, io, config_directory, "/s6/adminsv/default/contents.d/ly-srv", "s6 admin service not found");
|
||||||
},
|
},
|
||||||
.dinit => try deleteFile(allocator, config_directory, "/dinit.d/ly", "dinit service not found"),
|
.dinit => try deleteFile(allocator, io, config_directory, "/dinit.d/ly", "dinit service not found"),
|
||||||
.sysvinit => try deleteFile(allocator, config_directory, "/init.d/ly", "sysvinit service not found"),
|
.sysvinit => try deleteFile(allocator, io, config_directory, "/init.d/ly", "sysvinit service not found"),
|
||||||
.freebsd => try deleteFile(allocator, prefix_directory, "/bin/ly_wrapper", "freebsd wrapper not found"),
|
.freebsd => try deleteFile(allocator, io, prefix_directory, "/bin/ly_wrapper", "freebsd wrapper not found"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -384,11 +387,11 @@ fn getVersionStr(b: *std.Build, name: []const u8, version: std.SemanticVersion)
|
|||||||
"--match",
|
"--match",
|
||||||
"*.*.*",
|
"*.*.*",
|
||||||
"--tags",
|
"--tags",
|
||||||
}, &status, .Ignore) catch {
|
}, &status, .ignore) catch {
|
||||||
return version_str;
|
return version_str;
|
||||||
};
|
};
|
||||||
var git_describe = std.mem.trim(u8, git_describe_raw, " \n\r");
|
var git_describe = std.mem.trim(u8, git_describe_raw, " \n\r");
|
||||||
git_describe = std.mem.trimLeft(u8, git_describe, "v");
|
git_describe = std.mem.trimStart(u8, git_describe, "v");
|
||||||
|
|
||||||
switch (std.mem.count(u8, git_describe, "-")) {
|
switch (std.mem.count(u8, git_describe, "-")) {
|
||||||
0 => {
|
0 => {
|
||||||
@@ -401,7 +404,7 @@ fn getVersionStr(b: *std.Build, name: []const u8, version: std.SemanticVersion)
|
|||||||
2 => {
|
2 => {
|
||||||
// Untagged development build (e.g. 0.10.0-dev.2025+ecf0050a9).
|
// Untagged development build (e.g. 0.10.0-dev.2025+ecf0050a9).
|
||||||
var it = std.mem.splitScalar(u8, git_describe, '-');
|
var it = std.mem.splitScalar(u8, git_describe, '-');
|
||||||
const tagged_ancestor = std.mem.trimLeft(u8, it.first(), "v");
|
const tagged_ancestor = std.mem.trimStart(u8, it.first(), "v");
|
||||||
const commit_height = it.next().?;
|
const commit_height = it.next().?;
|
||||||
const commit_id = it.next().?;
|
const commit_id = it.next().?;
|
||||||
|
|
||||||
@@ -428,24 +431,25 @@ fn getVersionStr(b: *std.Build, name: []const u8, version: std.SemanticVersion)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn installFile(
|
fn installFile(
|
||||||
|
io: std.Io,
|
||||||
source_file: []const u8,
|
source_file: []const u8,
|
||||||
destination_directory: std.fs.Dir,
|
destination_directory: std.Io.Dir,
|
||||||
destination_directory_path: []const u8,
|
destination_directory_path: []const u8,
|
||||||
destination_file: []const u8,
|
destination_file: []const u8,
|
||||||
options: std.fs.Dir.CopyFileOptions,
|
options: std.Io.Dir.CopyFileOptions,
|
||||||
) !void {
|
) !void {
|
||||||
try std.fs.cwd().copyFile(source_file, destination_directory, destination_file, options);
|
try std.Io.Dir.cwd().copyFile(source_file, destination_directory, destination_file, io, options);
|
||||||
std.debug.print("info: installed {s}/{s}\n", .{ destination_directory_path, destination_file });
|
std.debug.print("info: installed {s}/{s}\n", .{ destination_directory_path, destination_file });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn patchFile(allocator: std.mem.Allocator, source_file: []const u8, patch_map: PatchMap) ![]const u8 {
|
fn patchFile(allocator: std.mem.Allocator, io: std.Io, source_file: []const u8, patch_map: PatchMap) ![]const u8 {
|
||||||
var file = try std.fs.cwd().openFile(source_file, .{});
|
var file = try std.Io.Dir.cwd().openFile(io, source_file, .{});
|
||||||
defer file.close();
|
defer file.close(io);
|
||||||
|
|
||||||
const stat = try file.stat();
|
const stat = try file.stat(io);
|
||||||
|
|
||||||
var buffer: [4096]u8 = undefined;
|
var buffer: [4096]u8 = undefined;
|
||||||
var reader = file.reader(&buffer);
|
var reader = file.reader(io, &buffer);
|
||||||
var text = try reader.interface.readAlloc(allocator, stat.size);
|
var text = try reader.interface.readAlloc(allocator, stat.size);
|
||||||
|
|
||||||
var iterator = patch_map.iterator();
|
var iterator = patch_map.iterator();
|
||||||
@@ -459,17 +463,18 @@ fn patchFile(allocator: std.mem.Allocator, source_file: []const u8, patch_map: P
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn installText(
|
fn installText(
|
||||||
|
io: std.Io,
|
||||||
text: []const u8,
|
text: []const u8,
|
||||||
destination_directory: std.fs.Dir,
|
destination_directory: std.Io.Dir,
|
||||||
destination_directory_path: []const u8,
|
destination_directory_path: []const u8,
|
||||||
destination_file: []const u8,
|
destination_file: []const u8,
|
||||||
options: std.fs.File.CreateFlags,
|
options: std.Io.File.CreateFlags,
|
||||||
) !void {
|
) !void {
|
||||||
var file = try destination_directory.createFile(destination_file, options);
|
var file = try destination_directory.createFile(io, destination_file, options);
|
||||||
defer file.close();
|
defer file.close(io);
|
||||||
|
|
||||||
var buffer: [1024]u8 = undefined;
|
var buffer: [1024]u8 = undefined;
|
||||||
var writer = file.writer(&buffer);
|
var writer = file.writer(io, &buffer);
|
||||||
try writer.interface.writeAll(text);
|
try writer.interface.writeAll(text);
|
||||||
try writer.interface.flush();
|
try writer.interface.flush();
|
||||||
|
|
||||||
@@ -478,13 +483,14 @@ fn installText(
|
|||||||
|
|
||||||
fn deleteFile(
|
fn deleteFile(
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
|
io: std.Io,
|
||||||
prefix: []const u8,
|
prefix: []const u8,
|
||||||
file: []const u8,
|
file: []const u8,
|
||||||
warning: []const u8,
|
warning: []const u8,
|
||||||
) !void {
|
) !void {
|
||||||
const path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, prefix, file });
|
const path = try std.Io.Dir.path.join(allocator, &[_][]const u8{ dest_directory, prefix, file });
|
||||||
|
|
||||||
std.fs.cwd().deleteFile(path) catch |err| {
|
std.Io.Dir.cwd().deleteFile(io, path) catch |err| {
|
||||||
if (err == error.FileNotFound) {
|
if (err == error.FileNotFound) {
|
||||||
std.debug.print("warn: {s}\n", .{warning});
|
std.debug.print("warn: {s}\n", .{warning});
|
||||||
return;
|
return;
|
||||||
@@ -498,13 +504,14 @@ fn deleteFile(
|
|||||||
|
|
||||||
fn deleteTree(
|
fn deleteTree(
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
|
io: std.Io,
|
||||||
prefix: []const u8,
|
prefix: []const u8,
|
||||||
directory: []const u8,
|
directory: []const u8,
|
||||||
warning: []const u8,
|
warning: []const u8,
|
||||||
) !void {
|
) !void {
|
||||||
const path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, prefix, directory });
|
const path = try std.Io.Dir.path.join(allocator, &[_][]const u8{ dest_directory, prefix, directory });
|
||||||
|
|
||||||
var dir = std.fs.cwd().openDir(path, .{}) catch |err| {
|
var dir = std.Io.Dir.cwd().openDir(io, path, .{}) catch |err| {
|
||||||
if (err == error.FileNotFound) {
|
if (err == error.FileNotFound) {
|
||||||
std.debug.print("warn: {s}\n", .{warning});
|
std.debug.print("warn: {s}\n", .{warning});
|
||||||
return;
|
return;
|
||||||
@@ -512,9 +519,9 @@ fn deleteTree(
|
|||||||
|
|
||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
dir.close();
|
dir.close(io);
|
||||||
|
|
||||||
try std.fs.cwd().deleteTree(path);
|
try std.Io.Dir.cwd().deleteTree(io, path);
|
||||||
|
|
||||||
std.debug.print("info: deleted {s}\n", .{path});
|
std.debug.print("info: deleted {s}\n", .{path});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,19 @@
|
|||||||
.name = .ly,
|
.name = .ly,
|
||||||
.version = "1.4.0",
|
.version = "1.4.0",
|
||||||
.fingerprint = 0xa148ffcc5dc2cb59,
|
.fingerprint = 0xa148ffcc5dc2cb59,
|
||||||
.minimum_zig_version = "0.15.0",
|
.minimum_zig_version = "0.16.0",
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
.ly_ui = .{
|
.ly_ui = .{
|
||||||
.path = "ly-ui",
|
.path = "ly-ui",
|
||||||
},
|
},
|
||||||
.clap = .{
|
.clap = .{
|
||||||
.url = "git+https://github.com/Hejsil/zig-clap#5289e0753cd274d65344bef1c114284c633536ea",
|
.url = "git+https://github.com/Hejsil/zig-clap#fc1e5cc3f6d9d3001112385ee6256d694e959d2f",
|
||||||
.hash = "clap-0.11.0-oBajB-HnAQDPCKYzwF7rO3qDFwRcD39Q0DALlTSz5H7e",
|
.hash = "clap-0.11.0-oBajB7foAQC3Iyn4IVCkUdYaOVVng5IZkSncySTjNig1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.paths = .{""},
|
.paths = .{
|
||||||
|
"build.zig",
|
||||||
|
"build.zig.zon",
|
||||||
|
"src",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
2
create_vendor_tarball.sh
Executable file
2
create_vendor_tarball.sh
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
tar --zstd -cvf vendor.tar.zst zig-pkg ly-ui/zig-pkg ly-core/zig-pkg
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const Translator = @import("translate_c").Translator;
|
||||||
|
|
||||||
pub fn build(b: *std.Build) void {
|
pub fn build(b: *std.Build) void {
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
@@ -12,6 +13,29 @@ 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 });
|
||||||
mod.addImport("zigini", zigini.module("zigini"));
|
mod.addImport("zigini", zigini.module("zigini"));
|
||||||
|
|
||||||
|
const translate_c = b.dependency("translate_c", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
addCImport(b, mod, translate_c, target, optimize, "pam", "#include <security/pam_appl.h>");
|
||||||
|
addCImport(b, mod, translate_c, target, optimize, "utmp", "#include <utmpx.h>");
|
||||||
|
addCImport(b, mod, translate_c, target, optimize, "xcb", "#include <xcb/xcb.h>");
|
||||||
|
if (target.result.os.tag == .freebsd) {
|
||||||
|
addCImport(b, mod, translate_c, target, optimize, "pwd",
|
||||||
|
\\#include <pwd.h>
|
||||||
|
\\#include <sys/types.h>
|
||||||
|
\\#include <login_cap.h>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
addCImport(b, mod, translate_c, target, optimize, "pwd", "#include <pwd.h>");
|
||||||
|
}
|
||||||
|
addCImport(b, mod, translate_c, target, optimize, "stdlib", "#include <stdlib.h>");
|
||||||
|
addCImport(b, mod, translate_c, target, optimize, "unistd", "#include <unistd.h>");
|
||||||
|
addCImport(b, mod, translate_c, target, optimize, "grp", "#include <grp.h>");
|
||||||
|
addCImport(b, mod, translate_c, target, optimize, "system_time", "#include <sys/time.h>");
|
||||||
|
addCImport(b, mod, translate_c, target, optimize, "time", "#include <time.h>");
|
||||||
|
|
||||||
const mod_tests = b.addTest(.{
|
const mod_tests = b.addTest(.{
|
||||||
.root_module = mod,
|
.root_module = mod,
|
||||||
});
|
});
|
||||||
@@ -20,3 +44,20 @@ pub fn build(b: *std.Build) void {
|
|||||||
const test_step = b.step("test", "Run tests");
|
const test_step = b.step("test", "Run tests");
|
||||||
test_step.dependOn(&run_mod_tests.step);
|
test_step.dependOn(&run_mod_tests.step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn addCImport(
|
||||||
|
b: *std.Build,
|
||||||
|
mod: *std.Build.Module,
|
||||||
|
translate_c: *std.Build.Dependency,
|
||||||
|
target: std.Build.ResolvedTarget,
|
||||||
|
optimize: std.builtin.OptimizeMode,
|
||||||
|
comptime name: []const u8,
|
||||||
|
comptime bytes: []const u8,
|
||||||
|
) void {
|
||||||
|
const pam: Translator = .init(translate_c, .{
|
||||||
|
.c_source_file = b.addWriteFiles().add(name ++ ".h", bytes),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
mod.addImport(name, pam.mod);
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,11 +2,15 @@
|
|||||||
.name = .ly_core,
|
.name = .ly_core,
|
||||||
.version = "1.0.0",
|
.version = "1.0.0",
|
||||||
.fingerprint = 0xddda7afda795472,
|
.fingerprint = 0xddda7afda795472,
|
||||||
.minimum_zig_version = "0.15.0",
|
.minimum_zig_version = "0.16.0",
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
.zigini = .{
|
.zigini = .{
|
||||||
.url = "git+https://github.com/AshAmetrine/zigini?ref=master#831f6aff55703b7fa34b43c972d60eb3d5d6f4a4",
|
.url = "git+https://github.com/AshAmetrine/zigini?ref=master#a665d081dda42664a96da2840ea09c5ccf9d0692",
|
||||||
.hash = "zigini-0.3.2-BSkB7UVDAAAErcEC6s7zF9bKTe7CjdBgrV35K3DGHpbr",
|
.hash = "zigini-0.5.0-BSkB7e9WAACfyCBABNZiWL3gFMw18GKn3qBcPs8L1Ec1",
|
||||||
|
},
|
||||||
|
.translate_c = .{
|
||||||
|
.url = "git+https://codeberg.org/ziglang/translate-c#7a1a9fdc4ab00835748a6657ecbb835e3d5d45f7",
|
||||||
|
.hash = "translate_c-0.0.0-Q_BUWvP1BgCjAk6PWv5286tOlvzD9-X-NkuTzh0KxY0Q",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.paths = .{
|
.paths = .{
|
||||||
|
|||||||
@@ -5,27 +5,27 @@ const LogFile = @This();
|
|||||||
|
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
could_open_log_file: bool = undefined,
|
could_open_log_file: bool = undefined,
|
||||||
file: std.fs.File = undefined,
|
file: std.Io.File = undefined,
|
||||||
buffer: []u8,
|
buffer: []u8,
|
||||||
file_writer: std.fs.File.Writer = undefined,
|
file_writer: std.Io.File.Writer = undefined,
|
||||||
|
|
||||||
pub fn init(path: []const u8, buffer: []u8) !LogFile {
|
pub fn init(io: std.Io, path: []const u8, buffer: []u8) !LogFile {
|
||||||
var log_file = LogFile{ .path = path, .buffer = buffer };
|
var log_file = LogFile{ .path = path, .buffer = buffer };
|
||||||
log_file.could_open_log_file = try openLogFile(path, &log_file);
|
log_file.could_open_log_file = try openLogFile(io, path, &log_file);
|
||||||
return log_file;
|
return log_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reinit(self: *LogFile) !void {
|
pub fn reinit(self: *LogFile, io: std.Io) !void {
|
||||||
self.could_open_log_file = try openLogFile(self.path, self);
|
self.could_open_log_file = try openLogFile(io, self.path, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *LogFile) void {
|
pub fn deinit(self: *LogFile, io: std.Io) void {
|
||||||
self.file.close();
|
self.file.close(io);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn info(self: *LogFile, category: []const u8, comptime message: []const u8, args: anytype) !void {
|
pub fn info(self: *LogFile, io: std.Io, category: []const u8, comptime message: []const u8, args: anytype) !void {
|
||||||
var buffer: [128:0]u8 = undefined;
|
var buffer: [128:0]u8 = undefined;
|
||||||
const time = interop.timeAsString(&buffer, "%Y-%m-%d %H:%M:%S");
|
const time = interop.timeAsString(io, &buffer, "%Y-%m-%d %H:%M:%S");
|
||||||
|
|
||||||
try self.file_writer.interface.print("{s} [info/{s}] ", .{ time, category });
|
try self.file_writer.interface.print("{s} [info/{s}] ", .{ time, category });
|
||||||
try self.file_writer.interface.print(message, args);
|
try self.file_writer.interface.print(message, args);
|
||||||
@@ -33,9 +33,9 @@ pub fn info(self: *LogFile, category: []const u8, comptime message: []const u8,
|
|||||||
try self.file_writer.interface.flush();
|
try self.file_writer.interface.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn err(self: *LogFile, category: []const u8, comptime message: []const u8, args: anytype) !void {
|
pub fn err(self: *LogFile, io: std.Io, category: []const u8, comptime message: []const u8, args: anytype) !void {
|
||||||
var buffer: [128:0]u8 = undefined;
|
var buffer: [128:0]u8 = undefined;
|
||||||
const time = interop.timeAsString(&buffer, "%Y-%m-%d %H:%M:%S");
|
const time = interop.timeAsString(io, &buffer, "%Y-%m-%d %H:%M:%S");
|
||||||
|
|
||||||
try self.file_writer.interface.print("{s} [err/{s}] ", .{ time, category });
|
try self.file_writer.interface.print("{s} [err/{s}] ", .{ time, category });
|
||||||
try self.file_writer.interface.print(message, args);
|
try self.file_writer.interface.print(message, args);
|
||||||
@@ -43,10 +43,10 @@ pub fn err(self: *LogFile, category: []const u8, comptime message: []const u8, a
|
|||||||
try self.file_writer.interface.flush();
|
try self.file_writer.interface.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn openLogFile(path: []const u8, log_file: *LogFile) !bool {
|
fn openLogFile(io: std.Io, path: []const u8, log_file: *LogFile) !bool {
|
||||||
var could_open_log_file = true;
|
var could_open_log_file = true;
|
||||||
open_log_file: {
|
open_log_file: {
|
||||||
log_file.file = std.fs.cwd().openFile(path, .{ .mode = .write_only }) catch std.fs.cwd().createFile(path, .{ .mode = 0o666 }) catch {
|
log_file.file = std.Io.Dir.cwd().openFile(io, path, .{ .mode = .write_only }) catch std.Io.Dir.cwd().createFile(io, path, .{ .permissions = .fromMode(0o666) }) catch {
|
||||||
// If we could neither open an existing log file nor create a new
|
// If we could neither open an existing log file nor create a new
|
||||||
// one, abort.
|
// one, abort.
|
||||||
could_open_log_file = false;
|
could_open_log_file = false;
|
||||||
@@ -55,14 +55,14 @@ fn openLogFile(path: []const u8, log_file: *LogFile) !bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!could_open_log_file) {
|
if (!could_open_log_file) {
|
||||||
log_file.file = try std.fs.openFileAbsolute("/dev/null", .{ .mode = .write_only });
|
log_file.file = try std.Io.Dir.openFileAbsolute(io, "/dev/null", .{ .mode = .write_only });
|
||||||
}
|
}
|
||||||
|
|
||||||
var log_file_writer = log_file.file.writer(log_file.buffer);
|
var log_file_writer = log_file.file.writer(io, log_file.buffer);
|
||||||
|
|
||||||
// Seek to the end of the log file
|
// Seek to the end of the log file
|
||||||
if (could_open_log_file) {
|
if (could_open_log_file) {
|
||||||
const stat = try log_file.file.stat();
|
const stat = try log_file.file.stat(io);
|
||||||
try log_file_writer.seekTo(stat.size);
|
try log_file_writer.seekTo(stat.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const ErrInt = std.meta.Int(.unsigned, @bitSizeOf(anyerror));
|
const ErrInt = std.meta.Int(.unsigned, @bitSizeOf(anyerror));
|
||||||
|
const PaddingInt = std.meta.Int(.unsigned, 8 - (@bitSizeOf(ErrInt) + @bitSizeOf(bool)) % 8);
|
||||||
|
|
||||||
const ErrorHandler = packed struct {
|
const ErrorHandler = packed struct {
|
||||||
has_error: bool = false,
|
has_error: bool = false,
|
||||||
err_int: ErrInt = 0,
|
err_int: ErrInt = 0,
|
||||||
|
padding: PaddingInt = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const SharedError = @This();
|
const SharedError = @This();
|
||||||
@@ -17,7 +19,7 @@ pub fn init(
|
|||||||
write_error_event_fn: ?*const fn (anyerror, *anyopaque) anyerror!void,
|
write_error_event_fn: ?*const fn (anyerror, *anyopaque) anyerror!void,
|
||||||
ctx: ?*anyopaque,
|
ctx: ?*anyopaque,
|
||||||
) !SharedError {
|
) !SharedError {
|
||||||
const data = try std.posix.mmap(null, @sizeOf(ErrorHandler), std.posix.PROT.READ | std.posix.PROT.WRITE, .{ .TYPE = .SHARED, .ANONYMOUS = true }, -1, 0);
|
const data = try std.posix.mmap(null, @sizeOf(ErrorHandler), .{ .READ = true, .WRITE = true }, .{ .TYPE = .SHARED, .ANONYMOUS = true }, -1, 0);
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.data = data,
|
.data = data,
|
||||||
@@ -31,9 +33,8 @@ pub fn deinit(self: *SharedError) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeError(self: SharedError, err: anyerror) void {
|
pub fn writeError(self: SharedError, err: anyerror) void {
|
||||||
var buf_stream = std.io.fixedBufferStream(self.data);
|
var writer: std.Io.Writer = .fixed(self.data);
|
||||||
const writer = buf_stream.writer();
|
writer.writeStruct(ErrorHandler{ .has_error = true, .err_int = @intFromError(err) }, .native) catch {};
|
||||||
writer.writeStruct(ErrorHandler{ .has_error = true, .err_int = @intFromError(err) }) catch {};
|
|
||||||
|
|
||||||
if (self.write_error_event_fn) |write_error_event_fn| {
|
if (self.write_error_event_fn) |write_error_event_fn| {
|
||||||
@call(.auto, write_error_event_fn, .{ err, self.ctx.? }) catch {};
|
@call(.auto, write_error_event_fn, .{ err, self.ctx.? }) catch {};
|
||||||
@@ -41,9 +42,8 @@ pub fn writeError(self: SharedError, err: anyerror) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn readError(self: SharedError) ?anyerror {
|
pub fn readError(self: SharedError) ?anyerror {
|
||||||
var buf_stream = std.io.fixedBufferStream(self.data);
|
var reader: std.Io.Reader = .fixed(self.data);
|
||||||
const reader = buf_stream.reader();
|
const err_handler = try reader.takeStruct(ErrorHandler, .native);
|
||||||
const err_handler = try reader.readStruct(ErrorHandler);
|
|
||||||
|
|
||||||
if (err_handler.has_error)
|
if (err_handler.has_error)
|
||||||
return @errorFromInt(err_handler.err_int);
|
return @errorFromInt(err_handler.err_int);
|
||||||
|
|||||||
@@ -1,49 +1,17 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const UidRange = @import("UidRange.zig");
|
const UidRange = @import("UidRange.zig");
|
||||||
|
const pwd = @import("pwd");
|
||||||
|
const stdlib = @import("stdlib");
|
||||||
|
const unistd = @import("unistd");
|
||||||
|
const grp = @import("grp");
|
||||||
|
const system_time = @import("system_time");
|
||||||
|
const time = @import("time");
|
||||||
|
|
||||||
pub const pam = @cImport({
|
pub const pam = @import("pam");
|
||||||
@cInclude("security/pam_appl.h");
|
pub const utmp = @import("utmp");
|
||||||
});
|
|
||||||
|
|
||||||
pub const utmp = @cImport({
|
|
||||||
@cInclude("utmpx.h");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Exists for X11 support only
|
// Exists for X11 support only
|
||||||
pub const xcb = @cImport({
|
pub const xcb = @import("xcb");
|
||||||
@cInclude("xcb/xcb.h");
|
|
||||||
});
|
|
||||||
|
|
||||||
const pwd = @cImport({
|
|
||||||
@cInclude("pwd.h");
|
|
||||||
// We include a FreeBSD-specific header here since login_cap.h references
|
|
||||||
// the passwd struct directly, so we can't import it separately
|
|
||||||
if (builtin.os.tag == .freebsd) {
|
|
||||||
@cInclude("sys/types.h");
|
|
||||||
@cInclude("login_cap.h");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const stdlib = @cImport({
|
|
||||||
@cInclude("stdlib.h");
|
|
||||||
});
|
|
||||||
|
|
||||||
const unistd = @cImport({
|
|
||||||
@cInclude("unistd.h");
|
|
||||||
});
|
|
||||||
|
|
||||||
const grp = @cImport({
|
|
||||||
@cInclude("grp.h");
|
|
||||||
});
|
|
||||||
|
|
||||||
const system_time = @cImport({
|
|
||||||
@cInclude("sys/time.h");
|
|
||||||
});
|
|
||||||
|
|
||||||
const time = @cImport({
|
|
||||||
@cInclude("time.h");
|
|
||||||
});
|
|
||||||
|
|
||||||
pub const TimeOfDay = struct {
|
pub const TimeOfDay = struct {
|
||||||
seconds: i64,
|
seconds: i64,
|
||||||
@@ -83,8 +51,8 @@ fn PlatformStruct() type {
|
|||||||
const status = grp.initgroups(username, @intCast(entry.gid));
|
const status = grp.initgroups(username, @intCast(entry.gid));
|
||||||
if (status != 0) return error.GroupInitializationFailed;
|
if (status != 0) return error.GroupInitializationFailed;
|
||||||
|
|
||||||
std.posix.setgid(@intCast(entry.gid)) catch return error.SetUserGidFailed;
|
if (isError(std.posix.system.setgid(@intCast(entry.gid)))) return error.SetUserGidFailed;
|
||||||
std.posix.setuid(@intCast(entry.uid)) catch return error.SetUserUidFailed;
|
if (isError(std.posix.system.setuid(@intCast(entry.uid)))) return error.SetUserUidFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Procedure:
|
// Procedure:
|
||||||
@@ -96,14 +64,14 @@ fn PlatformStruct() type {
|
|||||||
// 4. Finally, compare the major and minor device numbers with the
|
// 4. Finally, compare the major and minor device numbers with the
|
||||||
// extracted values. If they correspond, parse [dir] to get the
|
// extracted values. If they correspond, parse [dir] to get the
|
||||||
// TTY ID
|
// TTY ID
|
||||||
pub fn getActiveTtyImpl(allocator: std.mem.Allocator, use_kmscon_vt: bool) !u8 {
|
pub fn getActiveTtyImpl(allocator: std.mem.Allocator, io: std.Io, use_kmscon_vt: bool) !u8 {
|
||||||
var file_buffer: [256]u8 = undefined;
|
var file_buffer: [256]u8 = undefined;
|
||||||
|
|
||||||
if (use_kmscon_vt) {
|
if (use_kmscon_vt) {
|
||||||
var file = try std.fs.openFileAbsolute("/sys/class/tty/tty0/active", .{});
|
var file = try std.Io.Dir.openFileAbsolute(io, "/sys/class/tty/tty0/active", .{});
|
||||||
defer file.close();
|
defer file.close(io);
|
||||||
|
|
||||||
var reader = file.reader(&file_buffer);
|
var reader = file.reader(io, &file_buffer);
|
||||||
var buffer: [16]u8 = undefined;
|
var buffer: [16]u8 = undefined;
|
||||||
const read = try readBuffer(&reader.interface, &buffer);
|
const read = try readBuffer(&reader.interface, &buffer);
|
||||||
|
|
||||||
@@ -115,10 +83,10 @@ fn PlatformStruct() type {
|
|||||||
var tty_minor: u16 = undefined;
|
var tty_minor: u16 = undefined;
|
||||||
|
|
||||||
{
|
{
|
||||||
var file = try std.fs.openFileAbsolute("/proc/self/stat", .{});
|
var file = try std.Io.Dir.openFileAbsolute(io, "/proc/self/stat", .{});
|
||||||
defer file.close();
|
defer file.close(io);
|
||||||
|
|
||||||
var reader = file.reader(&file_buffer);
|
var reader = file.reader(io, &file_buffer);
|
||||||
var buffer: [1024]u8 = undefined;
|
var buffer: [1024]u8 = undefined;
|
||||||
const read = try readBuffer(&reader.interface, &buffer);
|
const read = try readBuffer(&reader.interface, &buffer);
|
||||||
|
|
||||||
@@ -136,18 +104,18 @@ fn PlatformStruct() type {
|
|||||||
tty_minor = tty_nr % 256;
|
tty_minor = tty_nr % 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
var directory = try std.fs.openDirAbsolute("/sys/class/tty", .{ .iterate = true });
|
var directory = try std.Io.Dir.openDirAbsolute(io, "/sys/class/tty", .{ .iterate = true });
|
||||||
defer directory.close();
|
defer directory.close(io);
|
||||||
|
|
||||||
var iterator = directory.iterate();
|
var iterator = directory.iterate();
|
||||||
while (try iterator.next()) |entry| {
|
while (try iterator.next(io)) |entry| {
|
||||||
const path = try std.fmt.allocPrint(allocator, "/sys/class/tty/{s}/dev", .{entry.name});
|
const path = try std.fmt.allocPrint(allocator, "/sys/class/tty/{s}/dev", .{entry.name});
|
||||||
defer allocator.free(path);
|
defer allocator.free(path);
|
||||||
|
|
||||||
var file = try std.fs.openFileAbsolute(path, .{});
|
var file = try std.Io.Dir.openFileAbsolute(io, path, .{});
|
||||||
defer file.close();
|
defer file.close(io);
|
||||||
|
|
||||||
var reader = file.reader(&file_buffer);
|
var reader = file.reader(io, &file_buffer);
|
||||||
var buffer: [16]u8 = undefined;
|
var buffer: [16]u8 = undefined;
|
||||||
const read = try readBuffer(&reader.interface, &buffer);
|
const read = try readBuffer(&reader.interface, &buffer);
|
||||||
|
|
||||||
@@ -170,11 +138,14 @@ fn PlatformStruct() type {
|
|||||||
// This is very bad parsing, but we only need to get 2 values..
|
// This is very bad parsing, but we only need to get 2 values..
|
||||||
// and the format of the file seems to be standard? So this should
|
// and the format of the file seems to be standard? So this should
|
||||||
// be fine...
|
// be fine...
|
||||||
pub fn getUserIdRange(allocator: std.mem.Allocator, file_path: []const u8) !UidRange {
|
pub fn getUserIdRange(allocator: std.mem.Allocator, io: std.Io, file_path: []const u8) !UidRange {
|
||||||
const login_defs_file = try std.fs.cwd().openFile(file_path, .{});
|
const login_defs_file = try std.Io.Dir.cwd().openFile(io, file_path, .{});
|
||||||
defer login_defs_file.close();
|
defer login_defs_file.close(io);
|
||||||
|
|
||||||
const login_defs_buffer = try login_defs_file.readToEndAlloc(allocator, std.math.maxInt(u16));
|
var buffer: [4096]u8 = undefined;
|
||||||
|
var reader = login_defs_file.reader(io, &buffer);
|
||||||
|
|
||||||
|
const login_defs_buffer = try reader.interface.allocRemaining(allocator, .unlimited);
|
||||||
defer allocator.free(login_defs_buffer);
|
defer allocator.free(login_defs_buffer);
|
||||||
|
|
||||||
var iterator = std.mem.splitScalar(u8, login_defs_buffer, '\n');
|
var iterator = std.mem.splitScalar(u8, login_defs_buffer, '\n');
|
||||||
@@ -255,11 +226,11 @@ fn PlatformStruct() type {
|
|||||||
if (result != 0) return error.SetUserUidFailed;
|
if (result != 0) return error.SetUserUidFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getActiveTtyImpl(_: std.mem.Allocator, _: bool) !u8 {
|
pub fn getActiveTtyImpl(_: std.mem.Allocator, _: std.Io, _: bool) !u8 {
|
||||||
return error.FeatureUnimplemented;
|
return error.FeatureUnimplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getUserIdRange(_: std.mem.Allocator, _: []const u8) !UidRange {
|
pub fn getUserIdRange(_: std.mem.Allocator, _: std.Io, _: []const u8) !UidRange {
|
||||||
return .{
|
return .{
|
||||||
// Hardcoded default values chosen from
|
// Hardcoded default values chosen from
|
||||||
// /usr/src/usr.sbin/pw/pw_conf.c
|
// /usr/src/usr.sbin/pw/pw_conf.c
|
||||||
@@ -274,12 +245,28 @@ fn PlatformStruct() type {
|
|||||||
|
|
||||||
const platform_struct = PlatformStruct();
|
const platform_struct = PlatformStruct();
|
||||||
|
|
||||||
|
// TODO 0.16.0: Can we get away with this?
|
||||||
|
pub fn isError(result: anytype) bool {
|
||||||
|
if (@typeInfo(@TypeOf(result)).int.signedness == .signed) {
|
||||||
|
return result < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (@typeInfo(@TypeOf(result)).int.signedness == .unsigned) {
|
||||||
|
return switch (builtin.os.tag) {
|
||||||
|
.linux => std.os.linux.errno(result) != .SUCCESS,
|
||||||
|
else => @compileError("interop.isError() not implemented for current target!"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn supportsUnicode() bool {
|
pub fn supportsUnicode() bool {
|
||||||
return builtin.os.tag == .linux or builtin.os.tag == .freebsd;
|
return builtin.os.tag == .linux or builtin.os.tag == .freebsd;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn timeAsString(buf: [:0]u8, format: [:0]const u8) []u8 {
|
pub fn timeAsString(io: std.Io, buf: [:0]u8, format: [:0]const u8) []u8 {
|
||||||
const timer = std.time.timestamp();
|
const timer = std.Io.Timestamp.now(io, .real).toSeconds();
|
||||||
const tm_info = time.localtime(&timer);
|
const tm_info = time.localtime(&timer);
|
||||||
const len = time.strftime(buf, buf.len, format, tm_info);
|
const len = time.strftime(buf, buf.len, format, tm_info);
|
||||||
|
|
||||||
@@ -298,8 +285,8 @@ pub fn getTimeOfDay() !TimeOfDay {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getActiveTty(allocator: std.mem.Allocator, use_kmscon_vt: bool) !u8 {
|
pub fn getActiveTty(allocator: std.mem.Allocator, io: std.Io, use_kmscon_vt: bool) !u8 {
|
||||||
return platform_struct.getActiveTtyImpl(allocator, use_kmscon_vt);
|
return platform_struct.getActiveTtyImpl(allocator, io, use_kmscon_vt);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn switchTty(tty: u8) !void {
|
pub fn switchTty(tty: u8) !void {
|
||||||
@@ -402,6 +389,6 @@ pub fn closePasswordDatabase() void {
|
|||||||
|
|
||||||
// This is very bad parsing, but we only need to get 2 values... and the format
|
// This is very bad parsing, but we only need to get 2 values... and the format
|
||||||
// of the file doesn't seem to be standard? So this should be fine...
|
// of the file doesn't seem to be standard? So this should be fine...
|
||||||
pub fn getUserIdRange(allocator: std.mem.Allocator, file_path: []const u8) !UidRange {
|
pub fn getUserIdRange(allocator: std.mem.Allocator, io: std.Io, file_path: []const u8) !UidRange {
|
||||||
return platform_struct.getUserIdRange(allocator, file_path);
|
return platform_struct.getUserIdRange(allocator, io, file_path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ pub fn IniParser(comptime Struct: type) type {
|
|||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
|
io: std.Io,
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
field_handler: ?fn (allocator: std.mem.Allocator, field: ini.IniField) ?ini.IniField,
|
field_handler: ?fn (allocator: std.mem.Allocator, field: ini.IniField) ?ini.IniField,
|
||||||
) !Self {
|
) !Self {
|
||||||
@@ -35,7 +36,7 @@ pub fn IniParser(comptime Struct: type) type {
|
|||||||
|
|
||||||
var maybe_load_error: ?anyerror = null;
|
var maybe_load_error: ?anyerror = null;
|
||||||
|
|
||||||
const structure = ini_struct.readFileToStruct(path, .{
|
const structure = ini_struct.readFileToStruct(io, path, .{
|
||||||
.fieldHandler = field_handler,
|
.fieldHandler = field_handler,
|
||||||
.errorHandler = errorHandler,
|
.errorHandler = errorHandler,
|
||||||
.comment_characters = "#",
|
.comment_characters = "#",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const Translator = @import("translate_c").Translator;
|
||||||
|
|
||||||
pub fn build(b: *std.Build) void {
|
pub fn build(b: *std.Build) void {
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
@@ -17,15 +18,30 @@ pub fn build(b: *std.Build) void {
|
|||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
|
||||||
const translate_c = b.addTranslateC(.{
|
const translate_c_dep = b.dependency("translate_c", .{
|
||||||
.root_source_file = termbox_dep.path("termbox2.h"),
|
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
translate_c.defineCMacroRaw("TB_IMPL");
|
|
||||||
translate_c.defineCMacro("TB_OPT_ATTR_W", "32"); // Enable 24-bit color support + styling (32-bit)
|
const termbox2: Translator = .init(translate_c_dep, .{
|
||||||
const termbox2 = translate_c.addModule("termbox2");
|
.c_source_file = termbox_dep.path("termbox2.h"),
|
||||||
mod.addImport("termbox2", termbox2);
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
termbox2.defineCMacro("TB_IMPL", null);
|
||||||
|
// TODO 0.16.0: Workaround until Aro gets better...
|
||||||
|
// https://codeberg.org/ziglang/translate-c/issues/319
|
||||||
|
termbox2.defineCMacro("_XOPEN_SOURCE", "700");
|
||||||
|
termbox2.defineCMacro("TB_OPT_ATTR_W", "32"); // Enable 24-bit color support + styling (32-bit)
|
||||||
|
// TODO 0.16.0: Including <fcntl.h> with -OReleaseSafe causes
|
||||||
|
// __attribute__(__error__()) to be called. Below
|
||||||
|
// is the workaround.
|
||||||
|
termbox2.defineCMacro("_FORTIFY_SOURCE", "0");
|
||||||
|
// TODO 0.16.0: Needed for now
|
||||||
|
if (target.result.os.tag == .freebsd) {
|
||||||
|
termbox2.defineCMacro("__BSD_VISIBLE", "1");
|
||||||
|
}
|
||||||
|
mod.addImport("termbox2", termbox2.mod);
|
||||||
|
|
||||||
const mod_tests = b.addTest(.{
|
const mod_tests = b.addTest(.{
|
||||||
.root_module = mod,
|
.root_module = mod,
|
||||||
|
|||||||
@@ -2,14 +2,18 @@
|
|||||||
.name = .ly_ui,
|
.name = .ly_ui,
|
||||||
.version = "1.0.0",
|
.version = "1.0.0",
|
||||||
.fingerprint = 0x8d11bf85a74ec803,
|
.fingerprint = 0x8d11bf85a74ec803,
|
||||||
.minimum_zig_version = "0.15.0",
|
.minimum_zig_version = "0.16.0",
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
.ly_core = .{
|
.ly_core = .{
|
||||||
.path = "../ly-core",
|
.path = "../ly-core",
|
||||||
},
|
},
|
||||||
.termbox2 = .{
|
.termbox2 = .{
|
||||||
.url = "git+https://github.com/AnErrupTion/termbox2?ref=master#496730697c662893eec43192f48ff616c2539da6",
|
.url = "git+https://github.com/AnErrupTion/termbox2?ref=master#c7f241e8888ce243e1748b05c26a42fcfaaad936",
|
||||||
.hash = "N-V-__8AAOEWBQDt5tNdIzIFY6n8DdZsCP-6MyLoNS20wgpA",
|
.hash = "N-V-__8AAAUXBQD6Fwpi9m0MBqWXFFaqW5l1lVrJC2Ynj7a-",
|
||||||
|
},
|
||||||
|
.translate_c = .{
|
||||||
|
.url = "git+https://codeberg.org/ziglang/translate-c#7a1a9fdc4ab00835748a6657ecbb835e3d5d45f7",
|
||||||
|
.hash = "translate_c-0.0.0-Q_BUWvP1BgCjAk6PWv5286tOlvzD9-X-NkuTzh0KxY0Q",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.paths = .{
|
.paths = .{
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ active_widget_index: usize,
|
|||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
|
io: std.Io,
|
||||||
options: InitOptions,
|
options: InitOptions,
|
||||||
log_file: *LogFile,
|
log_file: *LogFile,
|
||||||
random: Random,
|
random: Random,
|
||||||
@@ -106,9 +107,9 @@ pub fn init(
|
|||||||
|
|
||||||
if (options.full_color) {
|
if (options.full_color) {
|
||||||
_ = termbox.tb_set_output_mode(termbox.TB_OUTPUT_TRUECOLOR);
|
_ = termbox.tb_set_output_mode(termbox.TB_OUTPUT_TRUECOLOR);
|
||||||
try log_file.info("tui", "termbox2 set to 24-bit color output mode", .{});
|
try log_file.info(io, "tui", "termbox2 set to 24-bit color output mode", .{});
|
||||||
} else {
|
} else {
|
||||||
try log_file.info("tui", "termbox2 set to eight-color output mode", .{});
|
try log_file.info(io, "tui", "termbox2 set to eight-color output mode", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = termbox.tb_clear();
|
_ = termbox.tb_clear();
|
||||||
@@ -119,7 +120,7 @@ pub fn init(
|
|||||||
const width: usize = @intCast(termbox.tb_width());
|
const width: usize = @intCast(termbox.tb_width());
|
||||||
const height: usize = @intCast(termbox.tb_height());
|
const height: usize = @intCast(termbox.tb_height());
|
||||||
|
|
||||||
try log_file.info("tui", "screen resolution is {d}x{d}", .{ width, height });
|
try log_file.info(io, "tui", "screen resolution is {d}x{d}", .{ width, height });
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.log_file = log_file,
|
.log_file = log_file,
|
||||||
@@ -168,6 +169,7 @@ pub fn deinit(self: *TerminalBuffer) void {
|
|||||||
pub fn runEventLoop(
|
pub fn runEventLoop(
|
||||||
self: *TerminalBuffer,
|
self: *TerminalBuffer,
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
|
io: std.Io,
|
||||||
shared_error: SharedError,
|
shared_error: SharedError,
|
||||||
layers: [][]*Widget,
|
layers: [][]*Widget,
|
||||||
active_widget: *Widget,
|
active_widget: *Widget,
|
||||||
@@ -176,14 +178,14 @@ pub fn runEventLoop(
|
|||||||
inactivity_event_fn: ?*const fn (*anyopaque) anyerror!void,
|
inactivity_event_fn: ?*const fn (*anyopaque) anyerror!void,
|
||||||
context: *anyopaque,
|
context: *anyopaque,
|
||||||
) !void {
|
) !void {
|
||||||
try self.registerGlobalKeybind("Ctrl+K", &moveCursorUp, self);
|
try self.registerGlobalKeybind(io, "Ctrl+K", &moveCursorUp, self);
|
||||||
try self.registerGlobalKeybind("Up", &moveCursorUp, self);
|
try self.registerGlobalKeybind(io, "Up", &moveCursorUp, self);
|
||||||
|
|
||||||
try self.registerGlobalKeybind("Ctrl+J", &moveCursorDown, self);
|
try self.registerGlobalKeybind(io, "Ctrl+J", &moveCursorDown, self);
|
||||||
try self.registerGlobalKeybind("Down", &moveCursorDown, self);
|
try self.registerGlobalKeybind(io, "Down", &moveCursorDown, self);
|
||||||
|
|
||||||
try self.registerGlobalKeybind("Tab", &wrapCursor, self);
|
try self.registerGlobalKeybind(io, "Tab", &wrapCursor, self);
|
||||||
try self.registerGlobalKeybind("Shift+Tab", &wrapCursorReverse, self);
|
try self.registerGlobalKeybind(io, "Shift+Tab", &wrapCursorReverse, self);
|
||||||
|
|
||||||
defer self.handlable_widgets.deinit(allocator);
|
defer self.handlable_widgets.deinit(allocator);
|
||||||
|
|
||||||
@@ -218,6 +220,7 @@ pub fn runEventLoop(
|
|||||||
current_widget.handle(null) catch |err| {
|
current_widget.handle(null) catch |err| {
|
||||||
shared_error.writeError(error.SetCursorFailed);
|
shared_error.writeError(error.SetCursorFailed);
|
||||||
try self.log_file.err(
|
try self.log_file.err(
|
||||||
|
io,
|
||||||
"tui",
|
"tui",
|
||||||
"failed to set cursor in active widget '{s}': {s}",
|
"failed to set cursor in active widget '{s}': {s}",
|
||||||
.{ current_widget.display_name, @errorName(err) },
|
.{ current_widget.display_name, @errorName(err) },
|
||||||
@@ -261,6 +264,7 @@ pub fn runEventLoop(
|
|||||||
self.height = TerminalBuffer.getHeight();
|
self.height = TerminalBuffer.getHeight();
|
||||||
|
|
||||||
try self.log_file.info(
|
try self.log_file.info(
|
||||||
|
io,
|
||||||
"tui",
|
"tui",
|
||||||
"screen resolution updated to {d}x{d}",
|
"screen resolution updated to {d}x{d}",
|
||||||
.{ self.width, self.height },
|
.{ self.width, self.height },
|
||||||
@@ -271,6 +275,7 @@ pub fn runEventLoop(
|
|||||||
widget.realloc() catch |err| {
|
widget.realloc() catch |err| {
|
||||||
shared_error.writeError(error.WidgetReallocationFailed);
|
shared_error.writeError(error.WidgetReallocationFailed);
|
||||||
try self.log_file.err(
|
try self.log_file.err(
|
||||||
|
io,
|
||||||
"tui",
|
"tui",
|
||||||
"failed to reallocate widget '{s}': {s}",
|
"failed to reallocate widget '{s}': {s}",
|
||||||
.{ widget.display_name, @errorName(err) },
|
.{ widget.display_name, @errorName(err) },
|
||||||
@@ -294,6 +299,7 @@ pub fn runEventLoop(
|
|||||||
current_widget.handle(key) catch |err| {
|
current_widget.handle(key) catch |err| {
|
||||||
shared_error.writeError(error.CurrentWidgetHandlingFailed);
|
shared_error.writeError(error.CurrentWidgetHandlingFailed);
|
||||||
try self.log_file.err(
|
try self.log_file.err(
|
||||||
|
io,
|
||||||
"tui",
|
"tui",
|
||||||
"failed to handle active widget '{s}': {s}",
|
"failed to handle active widget '{s}': {s}",
|
||||||
.{ current_widget.display_name, @errorName(err) },
|
.{ current_widget.display_name, @errorName(err) },
|
||||||
@@ -390,18 +396,20 @@ pub fn reclaim(self: TerminalBuffer) !void {
|
|||||||
|
|
||||||
pub fn registerKeybind(
|
pub fn registerKeybind(
|
||||||
self: *TerminalBuffer,
|
self: *TerminalBuffer,
|
||||||
|
io: std.Io,
|
||||||
keybinds: *KeybindMap,
|
keybinds: *KeybindMap,
|
||||||
keybind: []const u8,
|
keybind: []const u8,
|
||||||
callback: KeybindCallbackFn,
|
callback: KeybindCallbackFn,
|
||||||
context: *anyopaque,
|
context: *anyopaque,
|
||||||
) !void {
|
) !void {
|
||||||
const key = try self.parseKeybind(keybind);
|
const key = try self.parseKeybind(io, keybind);
|
||||||
|
|
||||||
keybinds.put(key, .{
|
keybinds.put(key, .{
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
.context = context,
|
.context = context,
|
||||||
}) catch |err| {
|
}) catch |err| {
|
||||||
try self.log_file.err(
|
try self.log_file.err(
|
||||||
|
io,
|
||||||
"tui",
|
"tui",
|
||||||
"failed to register keybind {s}: {s}",
|
"failed to register keybind {s}: {s}",
|
||||||
.{ keybind, @errorName(err) },
|
.{ keybind, @errorName(err) },
|
||||||
@@ -411,15 +419,16 @@ pub fn registerKeybind(
|
|||||||
|
|
||||||
pub fn registerGlobalKeybind(
|
pub fn registerGlobalKeybind(
|
||||||
self: *TerminalBuffer,
|
self: *TerminalBuffer,
|
||||||
|
io: std.Io,
|
||||||
keybind: []const u8,
|
keybind: []const u8,
|
||||||
callback: KeybindCallbackFn,
|
callback: KeybindCallbackFn,
|
||||||
context: *anyopaque,
|
context: *anyopaque,
|
||||||
) !void {
|
) !void {
|
||||||
try self.registerKeybind(&self.keybinds, keybind, callback, context);
|
try self.registerKeybind(io, &self.keybinds, keybind, callback, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn simulateKeybind(self: *TerminalBuffer, keybind: []const u8) !bool {
|
pub fn simulateKeybind(self: *TerminalBuffer, io: std.Io, keybind: []const u8) !bool {
|
||||||
const key = try self.parseKeybind(keybind);
|
const key = try self.parseKeybind(io, keybind);
|
||||||
|
|
||||||
if (self.keybinds.get(key)) |binding| {
|
if (self.keybinds.get(key)) |binding| {
|
||||||
return try @call(
|
return try @call(
|
||||||
@@ -509,10 +518,13 @@ fn clearBackBuffer() !void {
|
|||||||
// Clear the TTY because termbox2 doesn't seem to do it properly
|
// Clear the TTY because termbox2 doesn't seem to do it properly
|
||||||
const capability = termbox.global.caps[termbox.TB_CAP_CLEAR_SCREEN];
|
const capability = termbox.global.caps[termbox.TB_CAP_CLEAR_SCREEN];
|
||||||
const capability_slice = std.mem.span(capability);
|
const capability_slice = std.mem.span(capability);
|
||||||
_ = try std.posix.write(termbox.global.ttyfd, capability_slice);
|
const result = std.posix.system.write(termbox.global.ttyfd, capability_slice.ptr, capability_slice.len);
|
||||||
|
|
||||||
|
if (result != capability_slice.len) return error.PartialClearBackBuffer;
|
||||||
|
if (result < 0) return error.ClearBackBufferFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseKeybind(self: *TerminalBuffer, keybind: []const u8) !keyboard.Key {
|
fn parseKeybind(self: *TerminalBuffer, io: std.Io, keybind: []const u8) !keyboard.Key {
|
||||||
var key = std.mem.zeroes(keyboard.Key);
|
var key = std.mem.zeroes(keyboard.Key);
|
||||||
var iterator = std.mem.splitScalar(u8, keybind, '+');
|
var iterator = std.mem.splitScalar(u8, keybind, '+');
|
||||||
|
|
||||||
@@ -529,6 +541,7 @@ fn parseKeybind(self: *TerminalBuffer, keybind: []const u8) !keyboard.Key {
|
|||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
try self.log_file.err(
|
try self.log_file.err(
|
||||||
|
io,
|
||||||
"tui",
|
"tui",
|
||||||
"failed to parse key {s} of keybind {s}",
|
"failed to parse key {s} of keybind {s}",
|
||||||
.{ item, keybind },
|
.{ item, keybind },
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ keybinds: TerminalBuffer.KeybindMap,
|
|||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
|
io: std.Io,
|
||||||
buffer: *TerminalBuffer,
|
buffer: *TerminalBuffer,
|
||||||
should_insert: bool,
|
should_insert: bool,
|
||||||
masked: bool,
|
masked: bool,
|
||||||
@@ -57,11 +58,11 @@ pub fn init(
|
|||||||
.keybinds = .init(allocator),
|
.keybinds = .init(allocator),
|
||||||
};
|
};
|
||||||
|
|
||||||
try buffer.registerKeybind(&self.keybinds, "Left", &goLeft, self);
|
try buffer.registerKeybind(io, &self.keybinds, "Left", &goLeft, self);
|
||||||
try buffer.registerKeybind(&self.keybinds, "Right", &goRight, self);
|
try buffer.registerKeybind(io, &self.keybinds, "Right", &goRight, self);
|
||||||
try buffer.registerKeybind(&self.keybinds, "Delete", &delete, self);
|
try buffer.registerKeybind(io, &self.keybinds, "Delete", &delete, self);
|
||||||
try buffer.registerKeybind(&self.keybinds, "Backspace", &backspace, self);
|
try buffer.registerKeybind(io, &self.keybinds, "Backspace", &backspace, self);
|
||||||
try buffer.registerKeybind(&self.keybinds, "Ctrl+U", &clearTextEntry, self);
|
try buffer.registerKeybind(io, &self.keybinds, "Ctrl+U", &clearTextEntry, self);
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ pub fn CyclableLabel(comptime ItemType: type, comptime ChangeItemType: type) typ
|
|||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
|
io: std.Io,
|
||||||
buffer: *TerminalBuffer,
|
buffer: *TerminalBuffer,
|
||||||
draw_item_fn: DrawItemFn,
|
draw_item_fn: DrawItemFn,
|
||||||
change_item_fn: ?ChangeItemFn,
|
change_item_fn: ?ChangeItemFn,
|
||||||
@@ -60,10 +61,10 @@ pub fn CyclableLabel(comptime ItemType: type, comptime ChangeItemType: type) typ
|
|||||||
.keybinds = .init(allocator),
|
.keybinds = .init(allocator),
|
||||||
};
|
};
|
||||||
|
|
||||||
try buffer.registerKeybind(&self.keybinds, "Left", &goLeft, self);
|
try buffer.registerKeybind(io, &self.keybinds, "Left", &goLeft, self);
|
||||||
try buffer.registerKeybind(&self.keybinds, "Ctrl+H", &goLeft, self);
|
try buffer.registerKeybind(io, &self.keybinds, "Ctrl+H", &goLeft, self);
|
||||||
try buffer.registerKeybind(&self.keybinds, "Right", &goRight, self);
|
try buffer.registerKeybind(io, &self.keybinds, "Right", &goRight, self);
|
||||||
try buffer.registerKeybind(&self.keybinds, "Ctrl+L", &goRight, self);
|
try buffer.registerKeybind(io, &self.keybinds, "Ctrl+L", &goRight, self);
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ Join us on Matrix over at [#ly-dm:matrix.org](https://matrix.to/#/#ly-dm:matrix.
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
- Compile-time:
|
- Compile-time:
|
||||||
- zig 0.15.x
|
- zig 0.16.x
|
||||||
|
|
||||||
- libc
|
- libc
|
||||||
|
|
||||||
|
|||||||
@@ -8,17 +8,20 @@ const Widget = ly_ui.Widget;
|
|||||||
|
|
||||||
const Cascade = @This();
|
const Cascade = @This();
|
||||||
|
|
||||||
|
io: std.Io,
|
||||||
instance: ?Widget = null,
|
instance: ?Widget = null,
|
||||||
buffer: *TerminalBuffer,
|
buffer: *TerminalBuffer,
|
||||||
current_auth_fails: *usize,
|
current_auth_fails: *usize,
|
||||||
max_auth_fails: usize,
|
max_auth_fails: usize,
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
|
io: std.Io,
|
||||||
buffer: *TerminalBuffer,
|
buffer: *TerminalBuffer,
|
||||||
current_auth_fails: *usize,
|
current_auth_fails: *usize,
|
||||||
max_auth_fails: usize,
|
max_auth_fails: usize,
|
||||||
) Cascade {
|
) Cascade {
|
||||||
return .{
|
return .{
|
||||||
|
.io = io,
|
||||||
.instance = null,
|
.instance = null,
|
||||||
.buffer = buffer,
|
.buffer = buffer,
|
||||||
.current_auth_fails = current_auth_fails,
|
.current_auth_fails = current_auth_fails,
|
||||||
@@ -44,7 +47,7 @@ pub fn widget(self: *Cascade) *Widget {
|
|||||||
|
|
||||||
fn draw(self: *Cascade) void {
|
fn draw(self: *Cascade) void {
|
||||||
while (self.current_auth_fails.* >= self.max_auth_fails) {
|
while (self.current_auth_fails.* >= self.max_auth_fails) {
|
||||||
std.Thread.sleep(std.time.ns_per_ms * 10);
|
self.io.sleep(.fromMilliseconds(10), .real) catch {};
|
||||||
|
|
||||||
var changed = false;
|
var changed = false;
|
||||||
var y = self.buffer.height - 2;
|
var y = self.buffer.height - 2;
|
||||||
@@ -80,7 +83,7 @@ fn draw(self: *Cascade) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!changed) {
|
if (!changed) {
|
||||||
std.Thread.sleep(std.time.ns_per_s * 7);
|
self.io.sleep(.fromSeconds(7), .real) catch {};
|
||||||
self.current_auth_fails.* = 0;
|
self.current_auth_fails.* = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ fn draw(self: *ColorMix) void {
|
|||||||
uv -= @splat(1.0 * math.cos(uv[0] + uv[1]) - math.sin(uv[0] * 0.7 - uv[1]));
|
uv -= @splat(1.0 * math.cos(uv[0] + uv[1]) - math.sin(uv[0] * 0.7 - uv[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
const cell = self.palette[@as(usize, @intFromFloat(math.floor(length(uv) * 5.0))) % palette_len];
|
const cell = self.palette[@as(usize, @trunc(math.floor(length(uv) * 5.0))) % palette_len];
|
||||||
cell.put(x, y);
|
cell.put(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,16 +19,16 @@ const LogFile = ly_core.LogFile;
|
|||||||
const enums = @import("../enums.zig");
|
const enums = @import("../enums.zig");
|
||||||
const DurOffsetAlignment = enums.DurOffsetAlignment;
|
const DurOffsetAlignment = enums.DurOffsetAlignment;
|
||||||
|
|
||||||
fn read_decompress_file(allocator: Allocator, file_path: []const u8) ![]u8 {
|
fn read_decompress_file(allocator: Allocator, io: std.Io, file_path: []const u8) ![]u8 {
|
||||||
const file_buffer = std.fs.cwd().openFile(file_path, .{}) catch {
|
const file_buffer = std.Io.Dir.cwd().openFile(io, file_path, .{}) catch {
|
||||||
return error.FileNotFound;
|
return error.FileNotFound;
|
||||||
};
|
};
|
||||||
defer file_buffer.close();
|
defer file_buffer.close(io);
|
||||||
|
|
||||||
var file_reader_buffer: [4096]u8 = undefined;
|
var file_reader_buffer: [4096]u8 = undefined;
|
||||||
var decompress_buffer: [flate.max_window_len]u8 = undefined;
|
var decompress_buffer: [flate.max_window_len]u8 = undefined;
|
||||||
|
|
||||||
var file_reader = file_buffer.reader(&file_reader_buffer);
|
var file_reader = file_buffer.reader(io, &file_reader_buffer);
|
||||||
var decompress: flate.Decompress = .init(&file_reader.interface, .gzip, &decompress_buffer);
|
var decompress: flate.Decompress = .init(&file_reader.interface, .gzip, &decompress_buffer);
|
||||||
|
|
||||||
const file_decompressed = decompress.reader.allocRemaining(allocator, .unlimited) catch {
|
const file_decompressed = decompress.reader.allocRemaining(allocator, .unlimited) catch {
|
||||||
@@ -150,8 +150,8 @@ const DurFormat = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_from_file(self: *DurFormat, allocator: Allocator, file_path: []const u8) !void {
|
pub fn create_from_file(self: *DurFormat, allocator: Allocator, io: std.Io, file_path: []const u8) !void {
|
||||||
const file_decompressed = try read_decompress_file(allocator, file_path);
|
const file_decompressed = try read_decompress_file(allocator, io, file_path);
|
||||||
defer allocator.free(file_decompressed);
|
defer allocator.free(file_decompressed);
|
||||||
|
|
||||||
const parsed = try Json.parseFromSlice(Json.Value, allocator, file_decompressed, .{});
|
const parsed = try Json.parseFromSlice(Json.Value, allocator, file_decompressed, .{});
|
||||||
@@ -307,6 +307,7 @@ const DurFile = @This();
|
|||||||
instance: ?Widget = null,
|
instance: ?Widget = null,
|
||||||
start_time: TimeOfDay,
|
start_time: TimeOfDay,
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
|
io: std.Io,
|
||||||
terminal_buffer: *TerminalBuffer,
|
terminal_buffer: *TerminalBuffer,
|
||||||
dur_movie: DurFormat,
|
dur_movie: DurFormat,
|
||||||
frames: u64,
|
frames: u64,
|
||||||
@@ -368,6 +369,7 @@ fn calc_frame_size(terminal_buffer: *TerminalBuffer, dur_movie: *DurFormat) UVec
|
|||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
|
io: std.Io,
|
||||||
terminal_buffer: *TerminalBuffer,
|
terminal_buffer: *TerminalBuffer,
|
||||||
log_file: *LogFile,
|
log_file: *LogFile,
|
||||||
file_path: []const u8,
|
file_path: []const u8,
|
||||||
@@ -381,13 +383,13 @@ pub fn init(
|
|||||||
) !DurFile {
|
) !DurFile {
|
||||||
var dur_movie: DurFormat = .init(allocator);
|
var dur_movie: DurFormat = .init(allocator);
|
||||||
|
|
||||||
dur_movie.create_from_file(allocator, file_path) catch |err| switch (err) {
|
dur_movie.create_from_file(allocator, io, file_path) catch |err| switch (err) {
|
||||||
error.FileNotFound => {
|
error.FileNotFound => {
|
||||||
try log_file.err("tui", "dur_file was not found at: {s}", .{file_path});
|
try log_file.err(io, "tui", "dur_file was not found at: {s}", .{file_path});
|
||||||
return err;
|
return err;
|
||||||
},
|
},
|
||||||
error.NotValidFile => {
|
error.NotValidFile => {
|
||||||
try log_file.err("tui", "dur_file loaded was invalid or not a dur file!", .{});
|
try log_file.err(io, "tui", "dur_file loaded was invalid or not a dur file!", .{});
|
||||||
return err;
|
return err;
|
||||||
},
|
},
|
||||||
else => return err,
|
else => return err,
|
||||||
@@ -395,7 +397,7 @@ pub fn init(
|
|||||||
|
|
||||||
// 4 bit mode with 256 color is unsupported
|
// 4 bit mode with 256 color is unsupported
|
||||||
if (!full_color and eql(u8, dur_movie.colorFormat.?, "256")) {
|
if (!full_color and eql(u8, dur_movie.colorFormat.?, "256")) {
|
||||||
try log_file.err("tui", "dur_file can not be 256 color encoded when not using full_color option!", .{});
|
try log_file.err(io, "tui", "dur_file can not be 256 color encoded when not using full_color option!", .{});
|
||||||
dur_movie.deinit();
|
dur_movie.deinit();
|
||||||
return error.InvalidColorFormat;
|
return error.InvalidColorFormat;
|
||||||
}
|
}
|
||||||
@@ -406,15 +408,16 @@ pub fn init(
|
|||||||
const frame_size = calc_frame_size(terminal_buffer, &dur_movie);
|
const frame_size = calc_frame_size(terminal_buffer, &dur_movie);
|
||||||
|
|
||||||
// Convert dur fps to frames per ms
|
// Convert dur fps to frames per ms
|
||||||
const frame_time: u32 = @intFromFloat(1000 / dur_movie.framerate.?);
|
const frame_time: u32 = @trunc(1000 / dur_movie.framerate.?);
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.instance = null,
|
.instance = null,
|
||||||
.start_time = try interop.getTimeOfDay(),
|
.start_time = try interop.getTimeOfDay(),
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
|
.io = io,
|
||||||
.terminal_buffer = terminal_buffer,
|
.terminal_buffer = terminal_buffer,
|
||||||
.frames = 0,
|
.frames = 0,
|
||||||
.time_previous = std.time.milliTimestamp(),
|
.time_previous = std.Io.Timestamp.now(io, .real).toMilliseconds(),
|
||||||
.frame_size = frame_size,
|
.frame_size = frame_size,
|
||||||
.start_pos = start_pos,
|
.start_pos = start_pos,
|
||||||
.full_color = full_color,
|
.full_color = full_color,
|
||||||
@@ -499,11 +502,11 @@ fn draw(self: *DurFile) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const time_current = std.time.milliTimestamp();
|
const time_current = std.Io.Timestamp.now(self.io, .real).toMilliseconds();
|
||||||
const delta_time = time_current - self.time_previous;
|
const delta_time = time_current - self.time_previous;
|
||||||
|
|
||||||
// Convert delay from sec to ms
|
// Convert delay from sec to ms
|
||||||
const delay_time: u32 = @intFromFloat(current_frame.delay * 1000);
|
const delay_time: u32 = @trunc(current_frame.delay * 1000);
|
||||||
if (delta_time > (self.frame_time + delay_time)) {
|
if (delta_time > (self.frame_time + delay_time)) {
|
||||||
self.time_previous = time_current;
|
self.time_previous = time_current;
|
||||||
|
|
||||||
|
|||||||
237
src/auth.zig
237
src/auth.zig
@@ -27,16 +27,16 @@ pub const AuthOptions = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var xorg_pid: std.posix.pid_t = 0;
|
var xorg_pid: std.posix.pid_t = 0;
|
||||||
pub fn xorgSignalHandler(i: c_int) callconv(.c) void {
|
pub fn xorgSignalHandler(sig: std.posix.SIG) callconv(.c) void {
|
||||||
if (xorg_pid > 0) _ = std.c.kill(xorg_pid, i);
|
if (xorg_pid > 0) _ = std.c.kill(xorg_pid, sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
var child_pid: std.posix.pid_t = 0;
|
var child_pid: std.posix.pid_t = 0;
|
||||||
pub fn sessionSignalHandler(i: c_int) callconv(.c) void {
|
pub fn sessionSignalHandler(sig: std.posix.SIG) callconv(.c) void {
|
||||||
if (child_pid > 0) _ = std.c.kill(child_pid, i);
|
if (child_pid > 0) _ = std.c.kill(child_pid, sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn authenticate(allocator: std.mem.Allocator, log_file: *LogFile, options: AuthOptions, current_environment: Environment, login: []const u8, password: []const u8) !void {
|
pub fn authenticate(allocator: std.mem.Allocator, io: std.Io, log_file: *LogFile, options: AuthOptions, current_environment: Environment, login: []const u8, password: []const u8) !void {
|
||||||
var tty_buffer: [3]u8 = undefined;
|
var tty_buffer: [3]u8 = undefined;
|
||||||
const tty_str = try std.fmt.bufPrint(&tty_buffer, "{d}", .{options.tty});
|
const tty_str = try std.fmt.bufPrint(&tty_buffer, "{d}", .{options.tty});
|
||||||
|
|
||||||
@@ -44,11 +44,11 @@ pub fn authenticate(allocator: std.mem.Allocator, log_file: *LogFile, options: A
|
|||||||
const pam_tty_str = try std.fmt.bufPrintZ(&pam_tty_buffer, "tty{d}", .{options.tty});
|
const pam_tty_str = try std.fmt.bufPrintZ(&pam_tty_buffer, "tty{d}", .{options.tty});
|
||||||
|
|
||||||
// Set the XDG environment variables
|
// Set the XDG environment variables
|
||||||
try log_file.info("auth/env", "setting xdg environment variables", .{});
|
try log_file.info(io, "auth/env", "setting xdg environment variables", .{});
|
||||||
try setXdgEnv(allocator, tty_str, current_environment);
|
try setXdgEnv(allocator, tty_str, current_environment);
|
||||||
|
|
||||||
// Open the PAM session
|
// Open the PAM session
|
||||||
try log_file.info("auth/pam", "encoding credentials", .{});
|
try log_file.info(io, "auth/pam", "encoding credentials", .{});
|
||||||
const login_z = try allocator.dupeZ(u8, login);
|
const login_z = try allocator.dupeZ(u8, login);
|
||||||
defer allocator.free(login_z);
|
defer allocator.free(login_z);
|
||||||
|
|
||||||
@@ -63,36 +63,36 @@ pub fn authenticate(allocator: std.mem.Allocator, log_file: *LogFile, options: A
|
|||||||
};
|
};
|
||||||
var handle: ?*interop.pam.pam_handle = undefined;
|
var handle: ?*interop.pam.pam_handle = undefined;
|
||||||
|
|
||||||
try log_file.info("auth/pam", "starting session", .{});
|
try log_file.info(io, "auth/pam", "starting session", .{});
|
||||||
var status = interop.pam.pam_start(options.service_name, null, &conv, &handle);
|
var status = interop.pam.pam_start(options.service_name, null, &conv, &handle);
|
||||||
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
|
// Set PAM_TTY as the current TTY. This is required in case it isn't being set by another PAM module
|
||||||
try log_file.info("auth/pam", "setting tty", .{});
|
try log_file.info(io, "auth/pam", "setting tty", .{});
|
||||||
status = interop.pam.pam_set_item(handle, interop.pam.PAM_TTY, pam_tty_str.ptr);
|
status = interop.pam.pam_set_item(handle, interop.pam.PAM_TTY, pam_tty_str.ptr);
|
||||||
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
|
||||||
try log_file.info("auth/pam", "authenticating", .{});
|
try log_file.info(io, "auth/pam", "authenticating", .{});
|
||||||
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);
|
||||||
|
|
||||||
try log_file.info("auth/pam", "validating account", .{});
|
try log_file.info(io, "auth/pam", "validating account", .{});
|
||||||
status = interop.pam.pam_acct_mgmt(handle, 0);
|
status = interop.pam.pam_acct_mgmt(handle, 0);
|
||||||
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
|
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
|
||||||
|
|
||||||
try log_file.info("auth/pam", "setting credentials", .{});
|
try log_file.info(io, "auth/pam", "setting credentials", .{});
|
||||||
status = interop.pam.pam_setcred(handle, interop.pam.PAM_ESTABLISH_CRED);
|
status = interop.pam.pam_setcred(handle, interop.pam.PAM_ESTABLISH_CRED);
|
||||||
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
|
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
|
||||||
defer status = interop.pam.pam_setcred(handle, interop.pam.PAM_DELETE_CRED);
|
defer status = interop.pam.pam_setcred(handle, interop.pam.PAM_DELETE_CRED);
|
||||||
|
|
||||||
try log_file.info("auth/pam", "opening session", .{});
|
try log_file.info(io, "auth/pam", "opening session", .{});
|
||||||
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);
|
||||||
defer status = interop.pam.pam_close_session(handle, 0);
|
defer status = interop.pam.pam_close_session(handle, 0);
|
||||||
|
|
||||||
try log_file.info("auth/passwd", "getting struct", .{});
|
try log_file.info(io, "auth/passwd", "getting struct", .{});
|
||||||
var user_entry: interop.UsernameEntry = undefined;
|
var user_entry: interop.UsernameEntry = undefined;
|
||||||
{
|
{
|
||||||
defer interop.closePasswordDatabase();
|
defer interop.closePasswordDatabase();
|
||||||
@@ -102,27 +102,27 @@ pub fn authenticate(allocator: std.mem.Allocator, log_file: *LogFile, options: A
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set user shell if it hasn't already been set
|
// Set user shell if it hasn't already been set
|
||||||
try log_file.info("auth/passwd", "setting user shell", .{});
|
try log_file.info(io, "auth/passwd", "setting user shell", .{});
|
||||||
if (user_entry.shell == null) interop.setUserShell(&user_entry);
|
if (user_entry.shell == null) interop.setUserShell(&user_entry);
|
||||||
|
|
||||||
var shared_err = try SharedError.init(null, null);
|
var shared_err = try SharedError.init(null, null);
|
||||||
defer shared_err.deinit();
|
defer shared_err.deinit();
|
||||||
|
|
||||||
log_file.deinit();
|
log_file.deinit(io);
|
||||||
|
|
||||||
child_pid = try std.posix.fork();
|
child_pid = std.posix.system.fork();
|
||||||
if (child_pid == 0) {
|
if (child_pid == 0) {
|
||||||
try log_file.reinit();
|
try log_file.reinit(io);
|
||||||
try log_file.info("auth/sys", "starting session", .{});
|
try log_file.info(io, "auth/sys", "starting session", .{});
|
||||||
|
|
||||||
startSession(log_file, allocator, options, tty_str, user_entry, handle, current_environment) catch |e| {
|
startSession(log_file, allocator, io, options, tty_str, user_entry, handle, current_environment) catch |e| {
|
||||||
shared_err.writeError(e);
|
shared_err.writeError(e);
|
||||||
|
|
||||||
log_file.deinit();
|
log_file.deinit(io);
|
||||||
std.process.exit(1);
|
std.process.exit(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
log_file.deinit();
|
log_file.deinit(io);
|
||||||
std.process.exit(0);
|
std.process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +132,8 @@ pub fn authenticate(allocator: std.mem.Allocator, log_file: *LogFile, options: A
|
|||||||
// If an error occurs here, we can send SIGTERM to the session
|
// If an error occurs here, we can send SIGTERM to the session
|
||||||
errdefer cleanup: {
|
errdefer cleanup: {
|
||||||
std.posix.kill(child_pid, std.posix.SIG.TERM) catch break :cleanup;
|
std.posix.kill(child_pid, std.posix.SIG.TERM) catch break :cleanup;
|
||||||
_ = std.posix.waitpid(child_pid, 0);
|
var child_status: c_int = undefined;
|
||||||
|
_ = std.posix.system.waitpid(child_pid, &child_status, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we receive SIGTERM, forward it to child_pid
|
// If we receive SIGTERM, forward it to child_pid
|
||||||
@@ -143,14 +144,15 @@ pub fn authenticate(allocator: std.mem.Allocator, log_file: *LogFile, options: A
|
|||||||
};
|
};
|
||||||
std.posix.sigaction(std.posix.SIG.TERM, &act, null);
|
std.posix.sigaction(std.posix.SIG.TERM, &act, null);
|
||||||
|
|
||||||
try addUtmpEntry(&entry, user_entry.username.?, child_pid);
|
try addUtmpEntry(io, &entry, user_entry.username.?, child_pid);
|
||||||
}
|
}
|
||||||
// Wait for the session to stop
|
// Wait for the session to stop
|
||||||
_ = std.posix.waitpid(child_pid, 0);
|
var child_status: c_int = undefined;
|
||||||
|
_ = std.posix.system.waitpid(child_pid, &child_status, 0);
|
||||||
|
|
||||||
try log_file.reinit();
|
try log_file.reinit(io);
|
||||||
|
|
||||||
try log_file.info("auth/utmp", "removing utmp entry", .{});
|
try log_file.info(io, "auth/utmp", "removing utmp entry", .{});
|
||||||
removeUtmpEntry(&entry);
|
removeUtmpEntry(&entry);
|
||||||
|
|
||||||
if (shared_err.readError()) |err| return err;
|
if (shared_err.readError()) |err| return err;
|
||||||
@@ -159,6 +161,7 @@ pub fn authenticate(allocator: std.mem.Allocator, log_file: *LogFile, options: A
|
|||||||
fn startSession(
|
fn startSession(
|
||||||
log_file: *LogFile,
|
log_file: *LogFile,
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
|
io: std.Io,
|
||||||
options: AuthOptions,
|
options: AuthOptions,
|
||||||
tty_str: []u8,
|
tty_str: []u8,
|
||||||
user_entry: interop.UsernameEntry,
|
user_entry: interop.UsernameEntry,
|
||||||
@@ -166,15 +169,15 @@ fn startSession(
|
|||||||
current_environment: Environment,
|
current_environment: Environment,
|
||||||
) !void {
|
) !void {
|
||||||
// Set the user's GID & PID
|
// Set the user's GID & PID
|
||||||
try log_file.info("auth/passwd", "setting user context", .{});
|
try log_file.info(io, "auth/passwd", "setting user context", .{});
|
||||||
try interop.setUserContext(allocator, user_entry);
|
try interop.setUserContext(allocator, user_entry);
|
||||||
|
|
||||||
// Set up the environment
|
// Set up the environment
|
||||||
try log_file.info("auth/env", "setting environment variables", .{});
|
try log_file.info(io, "auth/env", "setting environment variables", .{});
|
||||||
try initEnv(allocator, user_entry, options.path);
|
try initEnv(allocator, user_entry, options.path);
|
||||||
|
|
||||||
// Reset the XDG environment variables
|
// Reset the XDG environment variables
|
||||||
try log_file.info("auth/env", "resetting xdg environment variables", .{});
|
try log_file.info(io, "auth/env", "resetting xdg environment variables", .{});
|
||||||
try setXdgEnv(allocator, tty_str, current_environment);
|
try setXdgEnv(allocator, tty_str, current_environment);
|
||||||
try setXdgRuntimeDir(allocator);
|
try setXdgRuntimeDir(allocator);
|
||||||
|
|
||||||
@@ -185,27 +188,30 @@ fn startSession(
|
|||||||
const env_list = std.mem.span(pam_env_vars.?);
|
const env_list = std.mem.span(pam_env_vars.?);
|
||||||
for (env_list) |env_var| {
|
for (env_list) |env_var| {
|
||||||
if (env_var == null) continue;
|
if (env_var == null) continue;
|
||||||
try log_file.info("auth/env", "setting pam environment variable: {s}", .{std.mem.span(env_var.?)});
|
try log_file.info(io, "auth/env", "setting pam environment variable: {s}", .{std.mem.span(env_var.?)});
|
||||||
try interop.putEnvironmentVariable(env_var);
|
try interop.putEnvironmentVariable(env_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const home_z = try allocator.dupeZ(u8, user_entry.home.?);
|
||||||
|
defer allocator.free(home_z);
|
||||||
|
|
||||||
// Change to the user's home directory
|
// Change to the user's home directory
|
||||||
try log_file.info("auth/sys", "changing cwd to user home", .{});
|
try log_file.info(io, "auth/sys", "changing cwd to user home", .{});
|
||||||
std.posix.chdir(user_entry.home.?) catch return error.ChangeDirectoryFailed;
|
if (std.posix.system.chdir(home_z.ptr) < 0) return error.ChangeDirectoryFailed;
|
||||||
|
|
||||||
// Signal to the session process to give up control on the TTY
|
// Signal to the session process to give up control on the TTY
|
||||||
try log_file.info("auth/sys", "releasing tty", .{});
|
try log_file.info(io, "auth/sys", "releasing tty", .{});
|
||||||
std.posix.kill(options.session_pid, std.posix.SIG.CHLD) catch return error.TtyControlTransferFailed;
|
std.posix.kill(options.session_pid, std.posix.SIG.CHLD) catch return error.TtyControlTransferFailed;
|
||||||
|
|
||||||
// Execute what the user requested
|
// Execute what the user requested
|
||||||
switch (current_environment.display_server) {
|
switch (current_environment.display_server) {
|
||||||
.wayland, .shell, .custom => try executeCmd(log_file, allocator, user_entry.shell.?, options, current_environment.is_terminal, current_environment.cmd),
|
.wayland, .shell, .custom => try executeCmd(log_file, allocator, io, user_entry.shell.?, options, current_environment.is_terminal, current_environment.cmd),
|
||||||
.xinitrc, .x11 => if (build_options.enable_x11_support) {
|
.xinitrc, .x11 => if (build_options.enable_x11_support) {
|
||||||
var vt_buf: [5]u8 = undefined;
|
var vt_buf: [5]u8 = undefined;
|
||||||
const vt = try std.fmt.bufPrint(&vt_buf, "vt{d}", .{options.x_vt orelse options.tty});
|
const vt = try std.fmt.bufPrint(&vt_buf, "vt{d}", .{options.x_vt orelse options.tty});
|
||||||
|
|
||||||
try log_file.info("auth/x11", "setting vt to {s}", .{vt});
|
try log_file.info(io, "auth/x11", "setting vt to {s}", .{vt});
|
||||||
try executeX11Cmd(log_file, allocator, user_entry.shell.?, user_entry.home.?, options, current_environment.cmd orelse "", vt);
|
try executeX11Cmd(log_file, allocator, io, user_entry.shell.?, user_entry.home.?, options, current_environment.cmd orelse "", vt);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,7 +253,7 @@ fn setXdgRuntimeDir(allocator: std.mem.Allocator) !void {
|
|||||||
// XDG_RUNTIME_DIR to fall back to directories inside user's home
|
// XDG_RUNTIME_DIR to fall back to directories inside user's home
|
||||||
// directory.
|
// directory.
|
||||||
if (builtin.os.tag != .freebsd) {
|
if (builtin.os.tag != .freebsd) {
|
||||||
const uid = std.posix.getuid();
|
const uid = std.posix.system.getuid();
|
||||||
var uid_buffer: [32]u8 = undefined; // No UID can be larger than this
|
var uid_buffer: [32]u8 = undefined; // No UID can be larger than this
|
||||||
const uid_str = try std.fmt.bufPrint(&uid_buffer, "/run/user/{d}", .{uid});
|
const uid_str = try std.fmt.bufPrint(&uid_buffer, "/run/user/{d}", .{uid});
|
||||||
|
|
||||||
@@ -317,20 +323,20 @@ fn getFreeDisplay() !u8 {
|
|||||||
var buf: [15]u8 = undefined;
|
var buf: [15]u8 = undefined;
|
||||||
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.bufPrintZ(&buf, "/tmp/.X{d}-lock", .{i});
|
||||||
std.posix.access(xlock, std.posix.F_OK) catch break;
|
if (interop.isError(std.posix.system.access(xlock.ptr, std.posix.F_OK))) break;
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getXPid(display_num: u8) !i32 {
|
fn getXPid(io: std.Io, display_num: u8) !i32 {
|
||||||
var buf: [15]u8 = undefined;
|
var buf: [15]u8 = undefined;
|
||||||
const file_name = try std.fmt.bufPrint(&buf, "/tmp/.X{d}-lock", .{display_num});
|
const file_name = try std.fmt.bufPrint(&buf, "/tmp/.X{d}-lock", .{display_num});
|
||||||
const file = try std.fs.openFileAbsolute(file_name, .{});
|
const file = try std.Io.Dir.openFileAbsolute(io, file_name, .{});
|
||||||
defer file.close();
|
defer file.close(io);
|
||||||
|
|
||||||
var file_buffer: [32]u8 = undefined;
|
var file_buffer: [32]u8 = undefined;
|
||||||
var file_reader = file.reader(&file_buffer);
|
var file_reader = file.reader(io, &file_buffer);
|
||||||
var reader = &file_reader.interface;
|
var reader = &file_reader.interface;
|
||||||
|
|
||||||
var buffer: [20]u8 = undefined;
|
var buffer: [20]u8 = undefined;
|
||||||
@@ -340,41 +346,41 @@ fn getXPid(display_num: u8) !i32 {
|
|||||||
return std.fmt.parseInt(i32, std.mem.trim(u8, buffer[0..written], " "), 10);
|
return std.fmt.parseInt(i32, std.mem.trim(u8, buffer[0..written], " "), 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createXauthFile(log_file: *LogFile, pwd: []const u8, buffer: []u8) ![]const u8 {
|
fn createXauthFile(log_file: *LogFile, io: std.Io, pwd: []const u8, buffer: []u8) ![]const u8 {
|
||||||
var xauth_buf: [100]u8 = undefined;
|
var xauth_buf: [100]u8 = undefined;
|
||||||
var xauth_dir: []const u8 = undefined;
|
var xauth_dir: []const u8 = undefined;
|
||||||
const xdg_rt_dir = std.posix.getenv("XDG_RUNTIME_DIR");
|
const xdg_rt_dir = std.posix.system.getenv("XDG_RUNTIME_DIR");
|
||||||
var xauth_file: []const u8 = "lyxauth";
|
var xauth_file: []const u8 = "lyxauth";
|
||||||
|
|
||||||
if (xdg_rt_dir == null) no_rt_dir: {
|
if (xdg_rt_dir == null) no_rt_dir: {
|
||||||
const xdg_cfg_home = std.posix.getenv("XDG_CONFIG_HOME");
|
const xdg_cfg_home = std.posix.system.getenv("XDG_CONFIG_HOME");
|
||||||
if (xdg_cfg_home == null) no_cfg_home: {
|
if (xdg_cfg_home == null) no_cfg_home: {
|
||||||
xauth_dir = try std.fmt.bufPrint(&xauth_buf, "{s}/.config", .{pwd});
|
xauth_dir = try std.fmt.bufPrint(&xauth_buf, "{s}/.config", .{pwd});
|
||||||
|
|
||||||
var dir = std.fs.cwd().openDir(xauth_dir, .{}) catch {
|
var dir = std.Io.Dir.cwd().openDir(io, xauth_dir, .{}) catch {
|
||||||
// xauth_dir isn't a directory
|
// xauth_dir isn't a directory
|
||||||
xauth_dir = pwd;
|
xauth_dir = pwd;
|
||||||
xauth_file = ".lyxauth";
|
xauth_file = ".lyxauth";
|
||||||
break :no_cfg_home;
|
break :no_cfg_home;
|
||||||
};
|
};
|
||||||
dir.close();
|
dir.close(io);
|
||||||
|
|
||||||
// xauth_dir is a directory, use it to store Xauthority
|
// xauth_dir is a directory, use it to store Xauthority
|
||||||
xauth_dir = try std.fmt.bufPrint(&xauth_buf, "{s}/.config/ly", .{pwd});
|
xauth_dir = try std.fmt.bufPrint(&xauth_buf, "{s}/.config/ly", .{pwd});
|
||||||
} else {
|
} else {
|
||||||
xauth_dir = try std.fmt.bufPrint(&xauth_buf, "{s}/ly", .{xdg_cfg_home.?});
|
xauth_dir = try std.fmt.bufPrint(&xauth_buf, "{s}/ly", .{std.mem.span(xdg_cfg_home.?)});
|
||||||
}
|
}
|
||||||
|
|
||||||
const file = std.fs.cwd().openFile(xauth_dir, .{}) catch break :no_rt_dir;
|
const file = std.Io.Dir.cwd().openFile(io, xauth_dir, .{}) catch break :no_rt_dir;
|
||||||
file.close();
|
file.close(io);
|
||||||
|
|
||||||
// xauth_dir is a file, create the parent directory
|
// xauth_dir is a file, create the parent directory
|
||||||
std.posix.mkdir(xauth_dir, 777) catch {
|
std.Io.Dir.createDirAbsolute(io, xauth_dir, .fromMode(777)) catch {
|
||||||
xauth_dir = pwd;
|
xauth_dir = pwd;
|
||||||
xauth_file = ".lyxauth";
|
xauth_file = ".lyxauth";
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
xauth_dir = xdg_rt_dir.?;
|
xauth_dir = std.mem.span(xdg_rt_dir.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim trailing slashes
|
// Trim trailing slashes
|
||||||
@@ -384,19 +390,19 @@ fn createXauthFile(log_file: *LogFile, pwd: []const u8, buffer: []u8) ![]const u
|
|||||||
|
|
||||||
const xauthority: []u8 = try std.fmt.bufPrint(buffer, "{s}/{s}", .{ trimmed_xauth_dir, xauth_file });
|
const xauthority: []u8 = try std.fmt.bufPrint(buffer, "{s}/{s}", .{ trimmed_xauth_dir, xauth_file });
|
||||||
|
|
||||||
std.fs.cwd().makePath(trimmed_xauth_dir) catch {};
|
std.Io.Dir.cwd().createDirPath(io, trimmed_xauth_dir) catch {};
|
||||||
|
|
||||||
try log_file.info("auth/x11", "creating xauth file: {s}", .{xauthority});
|
try log_file.info(io, "auth/x11", "creating xauth file: {s}", .{xauthority});
|
||||||
|
|
||||||
const file = try std.fs.createFileAbsolute(xauthority, .{});
|
const file = try std.Io.Dir.createFileAbsolute(io, xauthority, .{});
|
||||||
file.close();
|
file.close(io);
|
||||||
|
|
||||||
return xauthority;
|
return xauthority;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mcookie() [Md5.digest_length * 2]u8 {
|
fn mcookie(io: std.Io) [Md5.digest_length * 2]u8 {
|
||||||
var buf: [4096]u8 = undefined;
|
var buf: [4096]u8 = undefined;
|
||||||
std.crypto.random.bytes(&buf);
|
io.random(&buf);
|
||||||
|
|
||||||
var out: [Md5.digest_length]u8 = undefined;
|
var out: [Md5.digest_length]u8 = undefined;
|
||||||
Md5.hash(&buf, &out, .{});
|
Md5.hash(&buf, &out, .{});
|
||||||
@@ -404,86 +410,87 @@ fn mcookie() [Md5.digest_length * 2]u8 {
|
|||||||
return std.fmt.bytesToHex(&out, .lower);
|
return std.fmt.bytesToHex(&out, .lower);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xauth(log_file: *LogFile, allocator: std.mem.Allocator, display_name: []u8, shell: [*:0]const u8, home: []const u8, xauth_buffer: []u8, options: AuthOptions) ![]const u8 {
|
fn xauth(log_file: *LogFile, allocator: std.mem.Allocator, io: std.Io, display_name: []u8, shell: [*:0]const u8, home: []const u8, xauth_buffer: []u8, options: AuthOptions) ![]const u8 {
|
||||||
const xauthority = try createXauthFile(log_file, home, xauth_buffer);
|
const xauthority = try createXauthFile(log_file, io, home, xauth_buffer);
|
||||||
try interop.setEnvironmentVariable(allocator, "XAUTHORITY", xauthority, true);
|
try interop.setEnvironmentVariable(allocator, "XAUTHORITY", xauthority, true);
|
||||||
try interop.setEnvironmentVariable(allocator, "DISPLAY", display_name, true);
|
try interop.setEnvironmentVariable(allocator, "DISPLAY", display_name, true);
|
||||||
|
|
||||||
const magic_cookie = mcookie();
|
const magic_cookie = mcookie(io);
|
||||||
|
|
||||||
const pid = try std.posix.fork();
|
const pid = std.posix.system.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}", .{ options.xauth_cmd, display_name, magic_cookie }) catch std.process.exit(1);
|
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} add {s} . {s}", .{ options.xauth_cmd, display_name, magic_cookie }) catch std.process.exit(1);
|
||||||
|
|
||||||
try log_file.info("auth/x11", "executing: {s} -c {s}", .{ shell, cmd_str });
|
try log_file.info(io, "auth/x11", "executing: {s} -c {s}", .{ shell, cmd_str });
|
||||||
const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str };
|
const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str };
|
||||||
std.posix.execveZ(shell, &args, std.c.environ) catch {};
|
_ = std.posix.system.execve(shell, &args, std.c.environ);
|
||||||
std.process.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const status = std.posix.waitpid(pid, 0);
|
var status: c_int = undefined;
|
||||||
if (status.status != 0) {
|
const result = std.posix.system.waitpid(pid, &status, 0);
|
||||||
try log_file.file_writer.interface.print("xauth command failed with status {d}\n", .{status.status});
|
if (interop.isError(result) or status != 0) {
|
||||||
|
try log_file.file_writer.interface.print("xauth command failed with status {d}\n", .{status});
|
||||||
return error.XauthFailed;
|
return error.XauthFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return xauthority;
|
return xauthority;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn executeX11Cmd(log_file: *LogFile, allocator: std.mem.Allocator, shell: []const u8, home: []const u8, options: AuthOptions, desktop_cmd: []const u8, vt: []const u8) !void {
|
fn executeX11Cmd(log_file: *LogFile, allocator: std.mem.Allocator, io: std.Io, shell: []const u8, home: []const u8, options: AuthOptions, desktop_cmd: []const u8, vt: []const u8) !void {
|
||||||
var xauth_buffer: [256]u8 = undefined;
|
var xauth_buffer: [256]u8 = undefined;
|
||||||
|
|
||||||
try log_file.info("auth/x11", "getting free display", .{});
|
try log_file.info(io, "auth/x11", "getting free display", .{});
|
||||||
const display_num = try getFreeDisplay();
|
const display_num = try getFreeDisplay();
|
||||||
var buf: [4]u8 = undefined;
|
var buf: [4]u8 = undefined;
|
||||||
const display_name = try std.fmt.bufPrint(&buf, ":{d}", .{display_num});
|
const display_name = try std.fmt.bufPrint(&buf, ":{d}", .{display_num});
|
||||||
try log_file.info("auth/x11", "got free display: {d}", .{display_num});
|
try log_file.info(io, "auth/x11", "got free display: {d}", .{display_num});
|
||||||
|
|
||||||
const shell_z = try allocator.dupeZ(u8, shell);
|
const shell_z = try allocator.dupeZ(u8, shell);
|
||||||
defer allocator.free(shell_z);
|
defer allocator.free(shell_z);
|
||||||
|
|
||||||
try log_file.info("auth/x11", "creating xauth file", .{});
|
try log_file.info(io, "auth/x11", "creating xauth file", .{});
|
||||||
const xauthority = try xauth(log_file, allocator, display_name, shell_z, home, &xauth_buffer, options);
|
const xauthority = try xauth(log_file, allocator, io, display_name, shell_z, home, &xauth_buffer, options);
|
||||||
|
|
||||||
try log_file.info("auth/x11", "starting x server", .{});
|
try log_file.info(io, "auth/x11", "starting x server", .{});
|
||||||
const pid = try std.posix.fork();
|
const pid = std.posix.system.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} -auth {s}", .{ options.x_cmd, display_name, vt, xauthority }) catch std.process.exit(1);
|
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s} -auth {s}", .{ options.x_cmd, display_name, vt, xauthority }) catch std.process.exit(1);
|
||||||
try log_file.info("auth/x11", "executing: {s} -c {s} -auth {s}", .{ shell, cmd_str, xauthority });
|
try log_file.info(io, "auth/x11", "executing: {s} -c {s} -auth {s}", .{ shell, cmd_str, xauthority });
|
||||||
|
|
||||||
const args = [_:null]?[*:0]const u8{ shell_z, "-c", cmd_str };
|
const args = [_:null]?[*:0]const u8{ shell_z, "-c", cmd_str };
|
||||||
std.posix.execveZ(shell_z, &args, std.c.environ) catch {};
|
_ = std.posix.system.execve(shell_z, &args, std.c.environ);
|
||||||
std.process.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
try log_file.info("auth/x11", "waiting for xcb connection", .{});
|
try log_file.info(io, "auth/x11", "waiting for xcb connection", .{});
|
||||||
var ok: c_int = -1;
|
var ok: c_int = -1;
|
||||||
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);
|
||||||
std.posix.kill(pid, 0) catch |e| {
|
std.posix.kill(pid, @enumFromInt(0)) catch |e| {
|
||||||
if (e == error.ProcessNotFound and ok != 0) return error.XcbConnectionFailed;
|
if (e == error.ProcessNotFound and ok != 0) return error.XcbConnectionFailed;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
try log_file.info("auth/x11", "getting x server pid", .{});
|
try log_file.info(io, "auth/x11", "getting x server pid", .{});
|
||||||
const x_pid = try getXPid(display_num);
|
const x_pid = try getXPid(io, display_num);
|
||||||
try log_file.info("auth/x11", "got x server pid: {d}", .{x_pid});
|
try log_file.info(io, "auth/x11", "got x server pid: {d}", .{x_pid});
|
||||||
|
|
||||||
try log_file.info("auth/x11", "launching environment", .{});
|
try log_file.info(io, "auth/x11", "launching environment", .{});
|
||||||
xorg_pid = try std.posix.fork();
|
xorg_pid = std.posix.system.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} {s} {s}", .{ if (options.use_kmscon_vt) "kmscon-launch-gui" else "", options.setup_cmd, options.login_cmd orelse "", desktop_cmd }) catch std.process.exit(1);
|
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s} {s}", .{ if (options.use_kmscon_vt) "kmscon-launch-gui" else "", options.setup_cmd, options.login_cmd orelse "", desktop_cmd }) catch std.process.exit(1);
|
||||||
try log_file.info("auth/x11", "executing: {s} -c {s}", .{ shell, cmd_str });
|
try log_file.info(io, "auth/x11", "executing: {s} -c {s}", .{ shell, cmd_str });
|
||||||
|
|
||||||
const args = [_:null]?[*:0]const u8{ shell_z, "-c", cmd_str };
|
const args = [_:null]?[*:0]const u8{ shell_z, "-c", cmd_str };
|
||||||
std.posix.execveZ(shell_z, &args, std.c.environ) catch {};
|
_ = std.posix.system.execve(shell_z, &args, std.c.environ);
|
||||||
std.process.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,26 +502,28 @@ fn executeX11Cmd(log_file: *LogFile, allocator: std.mem.Allocator, shell: []cons
|
|||||||
};
|
};
|
||||||
std.posix.sigaction(std.posix.SIG.TERM, &act, null);
|
std.posix.sigaction(std.posix.SIG.TERM, &act, null);
|
||||||
|
|
||||||
_ = std.posix.waitpid(xorg_pid, 0);
|
var xorg_status: c_int = undefined;
|
||||||
|
_ = std.posix.system.waitpid(xorg_pid, &xorg_status, 0);
|
||||||
|
|
||||||
try log_file.info("auth/x11", "disconnecting xcb", .{});
|
try log_file.info(io, "auth/x11", "disconnecting xcb", .{});
|
||||||
interop.xcb.xcb_disconnect(xcb);
|
interop.xcb.xcb_disconnect(xcb);
|
||||||
|
|
||||||
// TODO: Find a more robust way to ensure that X has been terminated (pidfds?)
|
// TODO: Find a more robust way to ensure that X has been terminated (pidfds?)
|
||||||
std.posix.kill(x_pid, std.posix.SIG.TERM) catch {};
|
std.posix.kill(x_pid, std.posix.SIG.TERM) catch {};
|
||||||
std.Thread.sleep(std.time.ns_per_s * 1); // Wait 1 second before sending SIGKILL
|
io.sleep(.fromSeconds(1), .real) catch {}; // Wait 1 second before sending SIGKILL
|
||||||
std.posix.kill(x_pid, std.posix.SIG.KILL) catch return;
|
std.posix.kill(x_pid, std.posix.SIG.KILL) catch return;
|
||||||
|
|
||||||
_ = std.posix.waitpid(x_pid, 0);
|
var x_status: c_int = undefined;
|
||||||
|
_ = std.posix.system.waitpid(x_pid, &x_status, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn executeCmd(global_log_file: *LogFile, allocator: std.mem.Allocator, shell: []const u8, options: AuthOptions, is_terminal: bool, exec_cmd: ?[]const u8) !void {
|
fn executeCmd(global_log_file: *LogFile, allocator: std.mem.Allocator, io: std.Io, shell: []const u8, options: AuthOptions, is_terminal: bool, exec_cmd: ?[]const u8) !void {
|
||||||
try global_log_file.info("auth/sys", "launching wayland/shell/custom session", .{});
|
try global_log_file.info(io, "auth/sys", "launching wayland/shell/custom session", .{});
|
||||||
|
|
||||||
var maybe_log_file: ?std.fs.File = null;
|
var maybe_log_file: ?std.Io.File = null;
|
||||||
if (!is_terminal) redirect_streams: {
|
if (!is_terminal) redirect_streams: {
|
||||||
if (options.use_kmscon_vt) {
|
if (options.use_kmscon_vt) {
|
||||||
try global_log_file.err("auth/sys", "cannot redirect stdio & stderr with kmscon", .{});
|
try global_log_file.err(io, "auth/sys", "cannot redirect stdio & stderr with kmscon", .{});
|
||||||
break :redirect_streams;
|
break :redirect_streams;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,11 +531,11 @@ fn executeCmd(global_log_file: *LogFile, allocator: std.mem.Allocator, shell: []
|
|||||||
// we redirect standard output & error or not. That is, we redirect only
|
// we redirect standard output & error or not. That is, we redirect only
|
||||||
// if it's equal to false (so if it's not running in a TTY).
|
// if it's equal to false (so if it's not running in a TTY).
|
||||||
if (options.session_log) |log_path| {
|
if (options.session_log) |log_path| {
|
||||||
try global_log_file.info("auth/sys", "setting up stdio & stderr redirection", .{});
|
try global_log_file.info(io, "auth/sys", "setting up stdio & stderr redirection", .{});
|
||||||
maybe_log_file = try redirectStandardStreams(global_log_file, log_path, true);
|
maybe_log_file = try redirectStandardStreams(global_log_file, io, log_path, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defer if (maybe_log_file) |log_file| log_file.close();
|
defer if (maybe_log_file) |log_file| log_file.close(io);
|
||||||
|
|
||||||
const shell_z = try allocator.dupeZ(u8, shell);
|
const shell_z = try allocator.dupeZ(u8, shell);
|
||||||
defer allocator.free(shell_z);
|
defer allocator.free(shell_z);
|
||||||
@@ -534,40 +543,42 @@ fn executeCmd(global_log_file: *LogFile, allocator: std.mem.Allocator, shell: []
|
|||||||
var cmd_buffer: [1024]u8 = undefined;
|
var cmd_buffer: [1024]u8 = undefined;
|
||||||
const cmd_str = try std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s} {s}", .{ if (!is_terminal and options.use_kmscon_vt) "kmscon-launch-gui" else "", options.setup_cmd, options.login_cmd orelse "", exec_cmd orelse shell });
|
const cmd_str = try std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s} {s}", .{ if (!is_terminal and options.use_kmscon_vt) "kmscon-launch-gui" else "", options.setup_cmd, options.login_cmd orelse "", exec_cmd orelse shell });
|
||||||
|
|
||||||
try global_log_file.info("auth/sys", "executing: {s} -c {s}", .{ shell, cmd_str });
|
try global_log_file.info(io, "auth/sys", "executing: {s} -c {s}", .{ shell, cmd_str });
|
||||||
const args = [_:null]?[*:0]const u8{ shell_z, "-c", cmd_str };
|
const args = [_:null]?[*:0]const u8{ shell_z, "-c", cmd_str };
|
||||||
return std.posix.execveZ(shell_z, &args, std.c.environ);
|
_ = std.posix.system.execve(shell_z, &args, std.c.environ);
|
||||||
|
return error.CmdExecveFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn redirectStandardStreams(global_log_file: *LogFile, session_log: []const u8, create: bool) !std.fs.File {
|
fn redirectStandardStreams(global_log_file: *LogFile, io: std.Io, session_log: []const u8, create: bool) !std.Io.File {
|
||||||
create_session_log_dir: {
|
create_session_log_dir: {
|
||||||
const session_log_dir = std.fs.path.dirname(session_log) orelse break :create_session_log_dir;
|
const session_log_dir = std.Io.Dir.path.dirname(session_log) orelse break :create_session_log_dir;
|
||||||
std.fs.cwd().makePath(session_log_dir) catch |err| {
|
std.Io.Dir.cwd().createDirPath(io, session_log_dir) catch |err| {
|
||||||
try global_log_file.err("auth/sys", "failed to create session log file directory: {s}", .{@errorName(err)});
|
try global_log_file.err(io, "auth/sys", "failed to create session log file directory: {s}", .{@errorName(err)});
|
||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const log_file = if (create) (std.fs.cwd().createFile(session_log, .{ .mode = 0o666 }) catch |err| {
|
const log_file = if (create) (std.Io.Dir.cwd().createFile(io, session_log, .{ .permissions = .fromMode(0o666) }) catch |err| {
|
||||||
try global_log_file.err("auth/sys", "failed to create new session log file: {s}", .{@errorName(err)});
|
try global_log_file.err(io, "auth/sys", "failed to create new session log file: {s}", .{@errorName(err)});
|
||||||
return err;
|
return err;
|
||||||
}) else (std.fs.cwd().openFile(session_log, .{ .mode = .read_write }) catch |err| {
|
}) else (std.Io.Dir.cwd().openFile(io, session_log, .{ .mode = .read_write }) catch |err| {
|
||||||
try global_log_file.err("auth/sys", "failed to open existing session log file: {s}", .{@errorName(err)});
|
try global_log_file.err(io, "auth/sys", "failed to open existing session log file: {s}", .{@errorName(err)});
|
||||||
return err;
|
return err;
|
||||||
});
|
});
|
||||||
|
|
||||||
try std.posix.dup2(std.posix.STDOUT_FILENO, std.posix.STDERR_FILENO);
|
if (interop.isError(std.posix.system.dup2(std.posix.STDOUT_FILENO, std.posix.STDERR_FILENO))) return error.StdoutDup2Failed;
|
||||||
try std.posix.dup2(log_file.handle, std.posix.STDOUT_FILENO);
|
if (interop.isError(std.posix.system.dup2(log_file.handle, std.posix.STDOUT_FILENO))) return error.LogFileDup2Failed;
|
||||||
|
|
||||||
return log_file;
|
return log_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addUtmpEntry(entry: *Utmp, username: []const u8, pid: c_int) !void {
|
fn addUtmpEntry(io: std.Io, entry: *Utmp, username: []const u8, pid: c_int) !void {
|
||||||
entry.ut_type = utmp.USER_PROCESS;
|
entry.ut_type = utmp.USER_PROCESS;
|
||||||
entry.ut_pid = pid;
|
entry.ut_pid = pid;
|
||||||
|
|
||||||
var buf: [std.fs.max_path_bytes]u8 = undefined;
|
var buf: [std.Io.Dir.max_path_bytes]u8 = undefined;
|
||||||
const tty_path = try std.os.getFdPath(std.posix.STDIN_FILENO, &buf);
|
const length = try std.Io.File.stdin().realPath(io, &buf);
|
||||||
|
const tty_path = buf[0..length];
|
||||||
|
|
||||||
// Get the TTY name (i.e. without the /dev/ prefix)
|
// Get the TTY name (i.e. without the /dev/ prefix)
|
||||||
var ttyname_buf: [@sizeOf(@TypeOf(entry.ut_line))]u8 = undefined;
|
var ttyname_buf: [@sizeOf(@TypeOf(entry.ut_line))]u8 = undefined;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ label: *MessageLabel,
|
|||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
|
io: std.Io,
|
||||||
buffer: *TerminalBuffer,
|
buffer: *TerminalBuffer,
|
||||||
width: usize,
|
width: usize,
|
||||||
arrow_fg: u32,
|
arrow_fg: u32,
|
||||||
@@ -32,6 +33,7 @@ pub fn init(
|
|||||||
.instance = null,
|
.instance = null,
|
||||||
.label = try MessageLabel.init(
|
.label = try MessageLabel.init(
|
||||||
allocator,
|
allocator,
|
||||||
|
io,
|
||||||
buffer,
|
buffer,
|
||||||
drawItem,
|
drawItem,
|
||||||
null,
|
null,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ user_list: *UserList,
|
|||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
|
io: std.Io,
|
||||||
buffer: *TerminalBuffer,
|
buffer: *TerminalBuffer,
|
||||||
user_list: *UserList,
|
user_list: *UserList,
|
||||||
width: usize,
|
width: usize,
|
||||||
@@ -35,6 +36,7 @@ pub fn init(
|
|||||||
.instance = null,
|
.instance = null,
|
||||||
.label = try EnvironmentLabel.init(
|
.label = try EnvironmentLabel.init(
|
||||||
allocator,
|
allocator,
|
||||||
|
io,
|
||||||
buffer,
|
buffer,
|
||||||
drawItem,
|
drawItem,
|
||||||
sessionChanged,
|
sessionChanged,
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ label: *UserLabel,
|
|||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
|
io: std.Io,
|
||||||
buffer: *TerminalBuffer,
|
buffer: *TerminalBuffer,
|
||||||
usernames: StringList,
|
usernames: StringList,
|
||||||
saved_users: *SavedUsers,
|
saved_users: *SavedUsers,
|
||||||
@@ -39,6 +40,7 @@ pub fn init(
|
|||||||
.instance = null,
|
.instance = null,
|
||||||
.label = try UserLabel.init(
|
.label = try UserLabel.init(
|
||||||
allocator,
|
allocator,
|
||||||
|
io,
|
||||||
buffer,
|
buffer,
|
||||||
drawItem,
|
drawItem,
|
||||||
usernameChanged,
|
usernameChanged,
|
||||||
|
|||||||
@@ -21,5 +21,5 @@ pub const CustomCommandInfo = struct {
|
|||||||
counter: u32 = 0,
|
counter: u32 = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub var binds: std.StringArrayHashMap(CustomCommandBind) = undefined;
|
pub var binds: std.array_hash_map.String(CustomCommandBind) = undefined;
|
||||||
pub var labels: std.StringArrayHashMap(CustomCommandInfo) = undefined;
|
pub var labels: std.array_hash_map.String(CustomCommandInfo) = undefined;
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ pub fn configFieldHandler(_: std.mem.Allocator, field: ini.IniField) ?ini.IniFie
|
|||||||
const key = field.header["cmd:".len..];
|
const key = field.header["cmd:".len..];
|
||||||
const keyZ = temporary_allocator.dupe(u8, key) catch "";
|
const keyZ = temporary_allocator.dupe(u8, key) catch "";
|
||||||
if (!custom.binds.contains(key)) {
|
if (!custom.binds.contains(key)) {
|
||||||
custom.binds.put(keyZ, .{}) catch {};
|
custom.binds.put(temporary_allocator, keyZ, .{}) catch {};
|
||||||
}
|
}
|
||||||
if (custom.binds.getPtr(keyZ)) |command| {
|
if (custom.binds.getPtr(keyZ)) |command| {
|
||||||
if (std.mem.eql(u8, field.key, "name")) {
|
if (std.mem.eql(u8, field.key, "name")) {
|
||||||
@@ -206,7 +206,7 @@ pub fn configFieldHandler(_: std.mem.Allocator, field: ini.IniField) ?ini.IniFie
|
|||||||
const key = field.header["lbl:".len..];
|
const key = field.header["lbl:".len..];
|
||||||
const keyZ = temporary_allocator.dupe(u8, key) catch "";
|
const keyZ = temporary_allocator.dupe(u8, key) catch "";
|
||||||
if (!custom.labels.contains(keyZ)) {
|
if (!custom.labels.contains(keyZ)) {
|
||||||
custom.labels.put(keyZ, .{ .name = keyZ }) catch {};
|
custom.labels.put(temporary_allocator, keyZ, .{ .name = keyZ }) catch {};
|
||||||
}
|
}
|
||||||
if (custom.labels.getPtr(keyZ)) |label| {
|
if (custom.labels.getPtr(keyZ)) |label| {
|
||||||
if (std.mem.eql(u8, field.key, "cmd")) {
|
if (std.mem.eql(u8, field.key, "cmd")) {
|
||||||
@@ -254,12 +254,12 @@ pub fn lateConfigFieldHandler(config: *Config) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tryMigrateIniSaveFile(allocator: std.mem.Allocator, path: []const u8, saved_users: *SavedUsers, usernames: [][]const u8) !?IniParser(OldSave) {
|
pub fn tryMigrateIniSaveFile(allocator: std.mem.Allocator, io: std.Io, path: []const u8, saved_users: *SavedUsers, usernames: [][]const u8) !?IniParser(OldSave) {
|
||||||
var save_parser = try IniParser(OldSave).init(allocator, path, null);
|
var save_parser = try IniParser(OldSave).init(allocator, io, path, null);
|
||||||
errdefer save_parser.deinit();
|
errdefer save_parser.deinit();
|
||||||
|
|
||||||
var user_buf: [32]u8 = undefined;
|
var user_buf: [32]u8 = undefined;
|
||||||
const maybe_save = if (save_parser.maybe_load_error == null) save_parser.structure else tryMigrateFirstSaveFile(&user_buf);
|
const maybe_save = if (save_parser.maybe_load_error == null) save_parser.structure else tryMigrateFirstSaveFile(io, &user_buf);
|
||||||
|
|
||||||
if (maybe_save) |save| {
|
if (maybe_save) |save| {
|
||||||
// Add all other users to the list
|
// Add all other users to the list
|
||||||
@@ -282,16 +282,16 @@ pub fn tryMigrateIniSaveFile(allocator: std.mem.Allocator, path: []const u8, sav
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tryMigrateFirstSaveFile(user_buf: *[32]u8) ?OldSave {
|
fn tryMigrateFirstSaveFile(io: std.Io, user_buf: *[32]u8) ?OldSave {
|
||||||
if (maybe_save_file) |path| {
|
if (maybe_save_file) |path| {
|
||||||
defer temporary_allocator.free(path);
|
defer temporary_allocator.free(path);
|
||||||
|
|
||||||
var save = OldSave{};
|
var save = OldSave{};
|
||||||
var file = std.fs.openFileAbsolute(path, .{}) catch return null;
|
var file = std.Io.Dir.openFileAbsolute(io, path, .{}) catch return null;
|
||||||
defer file.close();
|
defer file.close(io);
|
||||||
|
|
||||||
var file_buffer: [64]u8 = undefined;
|
var file_buffer: [64]u8 = undefined;
|
||||||
var file_reader = file.reader(&file_buffer);
|
var file_reader = file.reader(io, &file_buffer);
|
||||||
var reader = &file_reader.interface;
|
var reader = &file_reader.interface;
|
||||||
|
|
||||||
var user_writer = std.Io.Writer.fixed(user_buf);
|
var user_writer = std.Io.Writer.fixed(user_buf);
|
||||||
|
|||||||
419
src/main.zig
419
src/main.zig
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user