Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
build: update to Zig 0.16
.builds/alpine.yml | 8 ++---
.builds/archlinux.yml | 8 ++---
.builds/freebsd.yml | 8 ++---
.gitignore | 1 +
README.md | 2 +-
build.zig | 10 +++---
build.zig.zon | 4 +--
common/flags.zig | 66 ++++++++++++-----------------------
river/InputPopup.zig | 2 +-
river/Output.zig | 2 +-
river/Server.zig | 20 ++---------
river/Window.zig | 2 +-
river/XkbConfig.zig | 17 +++++----
river/c.zig | 6 ----
river/main.zig | 95 ++++++++++++++++++++++++++++++++++++---------------
river/process.zig | 4 +--
river/util.zig | 11 +++++-
17 files changed, 135 insertions(+), 131 deletions(-)
diff --git a/.builds/alpine.yml b/.builds/alpine.yml
index 16f1257..f7886d0 100644
--- a/.builds/alpine.yml
+++ b/.builds/alpine.yml
@@ -45,10 +45,10 @@ tasks:
cd ..
# Eat Github's resources rather than the Zig Software Foundation's resources!
- wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.15.1/zig-x86_64-linux-0.15.1.tar.xz
- tar xf zig-x86_64-linux-0.15.1.tar.xz
- sudo mv zig-x86_64-linux-0.15.1/zig /usr/bin/
- sudo mv zig-x86_64-linux-0.15.1/lib /usr/lib/zig
+ wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.16.0/zig-x86_64-linux-0.16.0.tar.xz
+ tar xf zig-x86_64-linux-0.16.0.tar.xz
+ sudo mv zig-x86_64-linux-0.16.0/zig /usr/bin/
+ sudo mv zig-x86_64-linux-0.16.0/lib /usr/lib/zig
- build: |
cd river
zig build --summary all
diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml
index 521daca..86bdc89 100644
--- a/.builds/archlinux.yml
+++ b/.builds/archlinux.yml
@@ -42,10 +42,10 @@ tasks:
cd ..
# Eat Github's resources rather than the Zig Software Foundation's resources!
- wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.15.1/zig-x86_64-linux-0.15.1.tar.xz
- tar xf zig-x86_64-linux-0.15.1.tar.xz
- sudo mv zig-x86_64-linux-0.15.1/zig /usr/bin/
- sudo mv zig-x86_64-linux-0.15.1/lib /usr/lib/zig
+ wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.16.0/zig-x86_64-linux-0.16.0.tar.xz
+ tar xf zig-x86_64-linux-0.16.0.tar.xz
+ sudo mv zig-x86_64-linux-0.16.0/zig /usr/bin/
+ sudo mv zig-x86_64-linux-0.16.0/lib /usr/lib/zig
- build: |
cd river
zig build --summary all
diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml
index ac7d064..7d9087f 100644
--- a/.builds/freebsd.yml
+++ b/.builds/freebsd.yml
@@ -48,10 +48,10 @@ tasks:
cd ..
# Eat Github's resources rather than the Zig Software Foundation's resources!
- wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.15.1/zig-x86_64-freebsd-0.15.1.tar.xz
- tar xf zig-x86_64-freebsd-0.15.1.tar.xz
- sudo mv zig-x86_64-freebsd-0.15.1/zig /usr/bin/
- sudo mv zig-x86_64-freebsd-0.15.1/lib /usr/lib/zig
+ wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.16.0/zig-x86_64-freebsd-0.16.0.tar.xz
+ tar xf zig-x86_64-freebsd-0.16.0.tar.xz
+ sudo mv zig-x86_64-freebsd-0.16.0/zig /usr/bin/
+ sudo mv zig-x86_64-freebsd-0.16.0/lib /usr/lib/zig
- build: |
cd river
zig build --summary all
diff --git a/.gitignore b/.gitignore
index ca6f198..f6ce2cb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
.zig-cache/
zig-out/
+zig-pkg/
diff --git a/README.md b/README.md
index bf898af..5e94c53 100644
--- a/README.md
+++ b/README.md
@@ -66,7 +66,7 @@ To compile river first ensure that you have the following dependencies
installed. The "development" versions are required if applicable to your
distribution.
-- [zig](https://ziglang.org/download/) 0.15
+- [zig](https://ziglang.org/download/) 0.16
- wayland
- wayland-protocols
- [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) 0.20
diff --git a/build.zig b/build.zig
index 46b515b..b9e4931 100644
--- a/build.zig
+++ b/build.zig
@@ -31,7 +31,6 @@ pub fn build(b: *Build) !void {
) orelse scdoc_found: {
_ = b.findProgram(&.{"scdoc"}, &.{}) catch |err| switch (err) {
error.FileNotFound => break :scdoc_found false,
- else => return err,
};
break :scdoc_found true;
};
@@ -51,7 +50,7 @@ pub fn build(b: *Build) !void {
const git_describe_long = b.runAllowFail(
&.{ "git", "-C", b.build_root.path orelse ".", "describe", "--long" },
&ret,
- .Ignore,
+ .ignore,
) catch break :blk version;
var it = mem.splitSequence(u8, mem.trim(u8, git_describe_long, &std.ascii.whitespace), "-");
@@ -158,12 +157,13 @@ pub fn build(b: *Build) !void {
.root_source_file = b.path("river/main.zig"),
.target = target,
.optimize = optimize,
+
.strip = strip,
+ .link_libc = true,
}),
});
river.root_module.addOptions("build_options", options);
- river.root_module.link_libc = true;
river.root_module.linkSystemLibrary("libevdev", .{});
river.root_module.linkSystemLibrary("libinput", .{});
river.root_module.linkSystemLibrary("wayland-server", .{});
@@ -179,7 +179,7 @@ pub fn build(b: *Build) !void {
river.root_module.addImport("slotmap", slotmap);
river.root_module.addImport("deque", deque);
- river.addCSourceFile(.{
+ river.root_module.addCSourceFile(.{
.file = b.path("river/wlroots_log_wrapper.c"),
.flags = &.{ "-std=c99", "-O2" },
});
@@ -223,7 +223,7 @@ pub fn build(b: *Build) !void {
// This makes the caching work for the Workaround, and the extra argument is ignored by /bin/sh.
scdoc.addFileArg(b.path("doc/" ++ page ++ ".1.scd"));
- const stdout = scdoc.captureStdOut();
+ const stdout = scdoc.captureStdOut(.{});
b.getInstallStep().dependOn(&b.addInstallFile(stdout, "share/man/man1/" ++ page ++ ".1").step);
}
}
diff --git a/build.zig.zon b/build.zig.zon
index 32e1b64..5918d5d 100644
--- a/build.zig.zon
+++ b/build.zig.zon
@@ -16,8 +16,8 @@
.hash = "pixman-0.3.0-LClMnz2VAAAs7QSCGwLimV5VUYx0JFnX5xWU6HwtMuDX",
},
.wayland = .{
- .url = "https://codeberg.org/ifreund/zig-wayland/archive/v0.5.0.tar.gz",
- .hash = "wayland-0.5.0-lQa1knz8AQCh08NA8BeQrwJB9U3CfqcVAdHZYGRKIGuu",
+ .url = "git+https://codeberg.org/ifreund/zig-wayland#4a150a04f76f7329e80280661355c04328369d1f",
+ .hash = "wayland-0.6.0-dev-lQa1krD8AQBlMqwuhAMJjPQKXvpRByZBxxqMVAZ7yzbG",
},
.wlroots = .{
.url = "https://codeberg.org/ifreund/zig-wlroots/archive/v0.20.0.tar.gz",
diff --git a/common/flags.zig b/common/flags.zig
index f7f9536..72f197f 100644
--- a/common/flags.zig
+++ b/common/flags.zig
@@ -1,71 +1,51 @@
// SPDX-FileCopyrightText: © 2023 Isaac Freund
// SPDX-License-Identifier: 0BSD
-//! Zero allocation argument parsing for unix-like systems.
-
const std = @import("std");
const mem = std.mem;
pub const Flag = struct {
- name: [:0]const u8,
+ name: []const u8,
kind: enum { boolean, arg },
};
-pub fn parser(comptime Arg: type, comptime flags: []const Flag) type {
- switch (Arg) {
- // TODO consider allowing []const u8
- [:0]const u8, [*:0]const u8 => {}, // ok
- else => @compileError("invalid argument type: " ++ @typeName(Arg)),
- }
+pub fn parser(comptime flags: []const Flag) type {
return struct {
pub const Result = struct {
/// Remaining args after the recognized flags
- args: []const Arg,
+ args: []const [:0]const u8,
/// Data obtained from parsed flags
flags: Flags,
pub const Flags = flags_type: {
- var fields: []const std.builtin.Type.StructField = &.{};
- for (flags) |flag| {
- const field: std.builtin.Type.StructField = switch (flag.kind) {
- .boolean => .{
- .name = flag.name,
- .type = bool,
- .default_value_ptr = &false,
- .is_comptime = false,
- .alignment = @alignOf(bool),
+ const Attributes = std.builtin.Type.StructField.Attributes;
+ var names: [flags.len][]const u8 = undefined;
+ var types: [flags.len]type = undefined;
+ var attrs: [flags.len]Attributes = undefined;
+ for (flags, &names, &types, &attrs) |flag, *name, *ty, *attr| {
+ name.* = flag.name;
+ switch (flag.kind) {
+ .boolean => {
+ ty.* = bool;
+ attr.* = .{ .default_value_ptr = &false };
},
- .arg => .{
- .name = flag.name,
- .type = ?[:0]const u8,
- .default_value_ptr = &@as(?[:0]const u8, null),
- .is_comptime = false,
- .alignment = @alignOf(?[:0]const u8),
+ .arg => {
+ ty.* = ?[:0]const u8;
+ attr.* = .{ .default_value_ptr = &@as(ty.*, null) };
},
- };
- fields = fields ++ [_]std.builtin.Type.StructField{field};
+ }
}
- break :flags_type @Type(.{ .@"struct" = .{
- .layout = .auto,
- .fields = fields,
- .decls = &.{},
- .is_tuple = false,
- } });
+ break :flags_type @Struct(.auto, null, &names, &types, &attrs);
};
};
- pub fn parse(args: []const Arg) !Result {
+ pub fn parse(args: []const [:0]const u8) error{MissingFlagArgument}!Result {
var result_flags: Result.Flags = .{};
var i: usize = 0;
outer: while (i < args.len) : (i += 1) {
- const arg = switch (Arg) {
- [*:0]const u8 => mem.sliceTo(args[i], 0),
- [:0]const u8 => args[i],
- else => unreachable,
- };
inline for (flags) |flag| {
- if (mem.eql(u8, "-" ++ flag.name, arg)) {
+ if (mem.eql(u8, "-" ++ flag.name, args[i])) {
switch (flag.kind) {
.boolean => @field(result_flags, flag.name) = true,
.arg => {
@@ -75,11 +55,7 @@ pub fn parser(comptime Arg: type, comptime flags: []const Flag) type {
"' requires an argument but none was provided!", .{});
return error.MissingFlagArgument;
}
- @field(result_flags, flag.name) = switch (Arg) {
- [*:0]const u8 => mem.sliceTo(args[i], 0),
- [:0]const u8 => args[i],
- else => unreachable,
- };
+ @field(result_flags, flag.name) = args[i];
},
}
continue :outer;
diff --git a/river/InputPopup.zig b/river/InputPopup.zig
index 7e5adc1..c7c5dc2 100644
--- a/river/InputPopup.zig
+++ b/river/InputPopup.zig
@@ -97,7 +97,7 @@ pub fn update(input_popup: *InputPopup) void {
.window => |window| window.popup_tree,
.shell_surface => |shell_surface| shell_surface.popup_tree,
// TODO fix positioning for lock surfaces not at 0,0 in layout coords
- .lock_surface => |_| server.scene.layers.popups,
+ .lock_surface => server.scene.layers.popups,
.layer_surface => |layer_surface| layer_surface.popup_tree,
// Xwayland doesn't use the text-input protocol
.override_redirect => unreachable,
diff --git a/river/Output.zig b/river/Output.zig
index 9d56930..2ed7273 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -449,7 +449,7 @@ fn handleFrame(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) voi
error.CommitFailed => log.err("output commit failed for {s}", .{wlr_output.name}),
};
- var now = posix.clock_gettime(posix.CLOCK.MONOTONIC) catch @panic("CLOCK_MONOTONIC not supported");
+ var now = util.timestamp();
output.scene_output.?.sendFrameDone(&now);
}
diff --git a/river/Server.zig b/river/Server.zig
index 592b915..31f9a6d 100644
--- a/river/Server.zig
+++ b/river/Server.zig
@@ -128,8 +128,8 @@ pub fn init(server: *Server, runtime_xwayland: bool) !void {
server.* = .{
.wl_server = wl_server,
- .sigint_source = try loop.addSignal(*wl.Server, posix.SIG.INT, terminate, wl_server),
- .sigterm_source = try loop.addSignal(*wl.Server, posix.SIG.TERM, terminate, wl_server),
+ .sigint_source = try loop.addSignal(*wl.Server, @intFromEnum(posix.SIG.INT), terminate, wl_server),
+ .sigterm_source = try loop.addSignal(*wl.Server, @intFromEnum(posix.SIG.TERM), terminate, wl_server),
.fixes = try wlr.Fixes.create(wl_server, 1),
@@ -281,20 +281,6 @@ pub fn deinit(server: *Server) void {
server.wl_server.destroy();
}
-/// Create the socket, start the backend, and setup the environment
-pub fn start(server: Server) !void {
- var buf: [11]u8 = undefined;
- const socket = try server.wl_server.addSocketAuto(&buf);
- try server.backend.start();
- // TODO: don't use libc's setenv
- if (c.setenv("WAYLAND_DISPLAY", socket.ptr, 1) < 0) return error.SetenvError;
- if (build_options.xwayland) {
- if (server.xwayland) |xwayland| {
- if (c.setenv("DISPLAY", xwayland.display_name, 1) < 0) return error.SetenvError;
- }
- }
-}
-
fn globalFilter(client: *const wl.Client, global: *const wl.Global, server: *Server) bool {
// Only expose the xwalyand_shell_v1 global to the Xwayland process.
if (build_options.xwayland) {
@@ -507,7 +493,7 @@ fn handleRequestActivate(
) void {
const node_data = SceneNodeData.fromSurface(event.surface) orelse return;
switch (node_data.data) {
- .window => |_| {}, // TODO support xdg-activation with a rwm extension protocol
+ .window => {}, // TODO support xdg-activation with a rwm extension protocol
else => |tag| {
log.info("ignoring xdg-activation-v1 activate request of {s} surface", .{@tagName(tag)});
},
diff --git a/river/Window.zig b/river/Window.zig
index 45037b9..fb91514 100644
--- a/river/Window.zig
+++ b/river/Window.zig
@@ -1083,7 +1083,7 @@ pub fn sendFrameDone(window: Window) void {
assert(window.state == .mapped);
assert(window.impl != .destroying);
- var now = posix.clock_gettime(posix.CLOCK.MONOTONIC) catch @panic("CLOCK_MONOTONIC not supported");
+ var now = util.timestamp();
window.rootSurface().?.sendFrameDone(&now);
}
diff --git a/river/XkbConfig.zig b/river/XkbConfig.zig
index cc81cdc..159604e 100644
--- a/river/XkbConfig.zig
+++ b/river/XkbConfig.zig
@@ -125,14 +125,13 @@ fn handleRequest(
fn createKeymap(object: *river.XkbConfigV1, id: u32, format: xkb.Keymap.Format, fd: i32) !void {
defer _ = std.c.close(fd);
- var stat: std.c.Stat = std.mem.zeroes(std.c.Stat);
- switch (std.posix.errno(std.c.fstat(fd, &stat))) {
- .SUCCESS => {},
- else => |e| {
- log.err("failed to fstat() keymap fd: E{s}", .{@tagName(e)});
- return XkbKeymap.createFailed(object.getClient(), object.getVersion(), id, "failed to fstat() keymap fd");
- },
- }
+ const io = std.Io.Threaded.global_single_threaded.io();
+ var file: std.Io.File = .{ .handle = fd, .flags = .{ .nonblocking = false } };
+ const stat = file.stat(io) catch |err| {
+ log.err("failed to stat keymap fd: {}", .{err});
+ return XkbKeymap.createFailed(object.getClient(), object.getVersion(), id, "failed to stat keymap fd");
+ };
+
// Must be zero terminated
if (stat.size < 1) {
log.err("keymap too small", .{});
@@ -144,7 +143,7 @@ fn createKeymap(object: *river.XkbConfigV1, id: u32, format: xkb.Keymap.Format,
}
const keymap_len: usize = @intCast(stat.size - 1);
- const keymap_ptr = std.c.mmap(null, keymap_len, std.c.PROT.READ, .{ .TYPE = .PRIVATE }, fd, 0);
+ const keymap_ptr = std.c.mmap(null, keymap_len, .{ .READ = true }, .{ .TYPE = .PRIVATE }, fd, 0);
if (keymap_ptr == std.c.MAP_FAILED) {
log.err("failed to mmap() keymap fd: {s}", .{@tagName(@as(std.c.E, @enumFromInt(std.c._errno().*)))});
return XkbKeymap.createFailed(object.getClient(), object.getVersion(), id, "failed to mmap() keymap fd");
diff --git a/river/c.zig b/river/c.zig
index 590de7a..aead518 100644
--- a/river/c.zig
+++ b/river/c.zig
@@ -2,13 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-only
pub const c = @cImport({
- @cDefine("_POSIX_C_SOURCE", "200809L");
-
- @cInclude("stdlib.h");
- @cInclude("unistd.h");
-
@cInclude("linux/input-event-codes.h");
@cInclude("libevdev/libevdev.h");
-
@cInclude("libinput.h");
});
diff --git a/river/main.zig b/river/main.zig
index a0966b7..195fa06 100644
--- a/river/main.zig
+++ b/river/main.zig
@@ -5,9 +5,11 @@ const build_options = @import("build_options");
const std = @import("std");
const mem = std.mem;
const fs = std.fs;
-const io = std.io;
+const Io = std.Io;
const log = std.log;
const posix = std.posix;
+const exit = std.process.exit;
+
const builtin = @import("builtin");
const wlr = @import("wlroots");
const flags = @import("flags");
@@ -18,6 +20,8 @@ const process = @import("process.zig");
const Server = @import("Server.zig");
+const io = Io.Threaded.global_single_threaded.io();
+
const usage: []const u8 =
\\usage: river [options]
\\
@@ -36,35 +40,41 @@ const full_version = std.fmt.comptimePrint("{s} {c}xwayland", .{
pub var server: Server = undefined;
-pub fn main() anyerror!void {
- const result = flags.parser([*:0]const u8, &.{
+pub fn main(init: std.process.Init.Minimal) anyerror!void {
+ var arena_alloc = std.heap.ArenaAllocator.init(util.gpa);
+ defer arena_alloc.deinit();
+ const arena = arena_alloc.allocator();
+
+ const args = try init.args.toSlice(arena);
+
+ const result = flags.parser(&.{
.{ .name = "h", .kind = .boolean },
.{ .name = "version", .kind = .boolean },
.{ .name = "c", .kind = .arg },
.{ .name = "log-level", .kind = .arg },
.{ .name = "log-scopes", .kind = .arg },
.{ .name = "no-xwayland", .kind = .boolean },
- }).parse(std.os.argv[1..]) catch {
+ }).parse(args[1..]) catch {
try stderr.writeAll(usage);
try stderr.flush();
- posix.exit(1);
+ exit(1);
};
if (result.flags.h) {
try stdout.writeAll(usage);
try stdout.flush();
- posix.exit(0);
+ exit(0);
}
if (result.args.len != 0) {
log.err("unknown option '{s}'", .{result.args[0]});
try stderr.writeAll(usage);
try stderr.flush();
- posix.exit(1);
+ exit(1);
}
if (result.flags.version) {
try stdout.writeAll(full_version ++ "\n");
try stdout.flush();
- posix.exit(0);
+ exit(0);
}
if (result.flags.@"log-level") |level| {
if (mem.eql(u8, level, "error")) {
@@ -77,7 +87,7 @@ pub fn main() anyerror!void {
runtime_log_level = .debug;
} else {
log.err("invalid log level '{s}'", .{level});
- posix.exit(1);
+ exit(1);
}
}
if (result.flags.@"log-scopes") |scopes| {
@@ -94,13 +104,13 @@ pub fn main() anyerror!void {
// former requires quoting in most shells.
const scope = std.meta.stringToEnum(LogScope, raw[1..]) orelse {
log.err("invalid log scope '{s}'", .{raw});
- posix.exit(1);
+ exit(1);
};
log_scopes.remove(scope);
} else {
const scope = std.meta.stringToEnum(LogScope, raw) orelse {
log.err("invalid log scope '{s}'", .{raw});
- posix.exit(1);
+ exit(1);
};
log_scopes.insert(scope);
}
@@ -111,9 +121,10 @@ pub fn main() anyerror!void {
if (result.flags.c) |command| {
break :blk try util.gpa.dupeZ(u8, command);
} else {
- break :blk try defaultInitPath();
+ break :blk try defaultInitPath(init.environ);
}
};
+ defer if (startup_command) |cmd| util.gpa.free(cmd);
try detectClassic(startup_command);
@@ -141,17 +152,47 @@ pub fn main() anyerror!void {
process.setup();
- try server.start();
+ var buf: [11]u8 = undefined;
+ const socket = try server.wl_server.addSocketAuto(&buf);
+ try server.backend.start();
// Run the child in a new process group so that we can send SIGTERM to all
// descendants on exit.
const child_pgid = if (startup_command) |cmd| blk: {
log.info("running init executable '{s}'", .{cmd});
+
+ var env_map = try init.environ.createMap(util.gpa);
+ defer env_map.deinit();
+
+ try env_map.put("WAYLAND_DISPLAY", socket);
+
+ if (build_options.xwayland) {
+ if (server.xwayland) |xwayland| {
+ try env_map.put("DISPLAY", mem.sliceTo(xwayland.display_name, 0));
+ }
+ }
+
+ const env_block = try env_map.createPosixBlock(util.gpa, .{});
+ defer env_block.deinit(util.gpa);
+
const child_args = [_:null]?[*:0]const u8{ "/bin/sh", "-c", cmd, null };
- const pid = try posix.fork();
+
+ const pid: posix.pid_t = fork: {
+ const rc = posix.system.fork();
+ switch (posix.errno(rc)) {
+ .SUCCESS => break :fork @intCast(rc),
+ .AGAIN => return error.SystemResources,
+ .NOMEM => return error.SystemResources,
+ .NOSYS => return error.OperationUnsupported,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ };
+
if (pid == 0) {
process.cleanupChild();
- posix.execveZ("/bin/sh", &child_args, std.c.environ) catch c._exit(1);
+ if (posix.errno(posix.system.execve("/bin/sh", &child_args, env_block.slice.ptr)) != .SUCCESS) {
+ posix.system.exit(1);
+ }
}
util.gpa.free(cmd);
// Since the child has called setsid, the pid is the pgid
@@ -166,22 +207,22 @@ pub fn main() anyerror!void {
server.wl_server.run();
}
-fn defaultInitPath() !?[:0]const u8 {
+fn defaultInitPath(environ: std.process.Environ) !?[:0]const u8 {
const path = blk: {
- if (posix.getenv("XDG_CONFIG_HOME")) |xdg_config_home| {
+ if (environ.getPosix("XDG_CONFIG_HOME")) |xdg_config_home| {
break :blk try fs.path.joinZ(util.gpa, &[_][]const u8{ xdg_config_home, "river/init" });
- } else if (posix.getenv("HOME")) |home| {
+ } else if (environ.getPosix("HOME")) |home| {
break :blk try fs.path.joinZ(util.gpa, &[_][]const u8{ home, ".config/river/init" });
} else {
return null;
}
};
- posix.accessZ(path, posix.X_OK) catch |err| {
+ Io.Dir.cwd().access(io, path, .{ .execute = true }) catch |err| {
if (err == error.PermissionDenied) {
- if (posix.accessZ(path, posix.R_OK)) {
+ if (Io.Dir.cwd().access(io, path, .{})) {
log.err("failed to run init executable {s}: the file is not executable", .{path});
- posix.exit(1);
+ exit(1);
} else |_| {}
}
log.err("failed to run init executable {s}: {s}", .{ path, @errorName(err) });
@@ -215,15 +256,15 @@ fn detectClassic(startup_command: ?[:0]const u8) !void {
.version = build_options.version,
});
try stderr.flush();
- posix.exit(1);
+ exit(1);
}
}
fn grepRiverctl(path: [:0]const u8) !bool {
- var file = try std.fs.cwd().openFileZ(path, .{});
- defer file.close();
+ var file = try Io.Dir.cwd().openFile(io, path, .{});
+ defer file.close(io);
var buffer: [1024]u8 = undefined;
- var file_reader = file.reader(&buffer);
+ var file_reader = file.reader(io, &buffer);
const reader = &file_reader.interface;
while (true) {
_ = try reader.discardDelimiterExclusive('r');
@@ -239,11 +280,11 @@ fn grepRiverctl(path: [:0]const u8) !bool {
}
var stderr_buffer: [1024]u8 = undefined;
-var stderr_writer = fs.File.stderr().writer(&stderr_buffer);
+var stderr_writer = Io.File.stderr().writer(io, &stderr_buffer);
const stderr = &stderr_writer.interface;
var stdout_buffer: [1024]u8 = undefined;
-var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
+var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
const stdout = &stdout_writer.interface;
// Scopes should be added to this list sparingly.
diff --git a/river/process.zig b/river/process.zig
index 809b89f..d6e8793 100644
--- a/river/process.zig
+++ b/river/process.zig
@@ -4,8 +4,6 @@
const std = @import("std");
const posix = std.posix;
-const c = @import("c.zig").c;
-
var original_rlimit: ?posix.rlimit = null;
pub fn setup() void {
@@ -47,7 +45,7 @@ pub fn setup() void {
}
pub fn cleanupChild() void {
- if (c.setsid() < 0) unreachable;
+ if (std.c.setsid() < 0) unreachable;
if (posix.system.sigprocmask(posix.SIG.SETMASK, &posix.sigemptyset(), null) < 0) unreachable;
const sig_dfl = posix.Sigaction{
diff --git a/river/util.zig b/river/util.zig
index a713e46..79679b9 100644
--- a/river/util.zig
+++ b/river/util.zig
@@ -2,12 +2,21 @@
// SPDX-License-Identifier: GPL-3.0-only
const std = @import("std");
+const posix = std.posix;
/// The global general-purpose allocator used throughout river's code
pub const gpa = std.heap.c_allocator;
+pub fn timestamp() posix.timespec {
+ var timespec: posix.timespec = undefined;
+ switch (posix.errno(posix.system.clock_gettime(posix.CLOCK.MONOTONIC, ×pec))) {
+ .SUCCESS => return timespec,
+ else => @panic("CLOCK_MONOTONIC not supported"),
+ }
+}
+
pub fn msecTimestamp() u32 {
- const now = std.posix.clock_gettime(.MONOTONIC) catch @panic("CLOCK_MONOTONIC not supported");
+ const now = timestamp();
// 2^32-1 milliseconds is ~50 days, which is a realistic uptime.
// This means that we must wrap if the monotonic time is greater than
// 2^32-1 milliseconds and hope that clients don't get too confused.