From 1a9cba2aa91a1ab4085aa5670644ee9349d0595a Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Thu, 11 Aug 2022 12:02:30 +0200 Subject: [PATCH] river: fix SIGPIPE handling, cleanup fork/execve Installing an empty handler does not have the same effect as using SIG_IGN as the failing write syscall will not return EPIPE. --- river/command/spawn.zig | 5 +---- river/main.zig | 24 +++++++++++------------- river/util.zig | 17 ++++++++++++++++- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/river/command/spawn.zig b/river/command/spawn.zig index 1bc5c42..ced3922 100644 --- a/river/command/spawn.zig +++ b/river/command/spawn.zig @@ -40,10 +40,7 @@ pub fn spawn( }; if (pid == 0) { - // Clean things up for the child in an intermediate fork - if (c.setsid() < 0) unreachable; - if (os.system.sigprocmask(os.SIG.SETMASK, &os.empty_sigset, null) < 0) unreachable; - + util.post_fork_pre_execve(); const pid2 = os.fork() catch c._exit(1); if (pid2 == 0) os.execveZ("/bin/sh", &child_args, std.c.environ) catch c._exit(1); diff --git a/river/main.zig b/river/main.zig index 53a17e5..d9fc443 100644 --- a/river/main.zig +++ b/river/main.zig @@ -41,18 +41,7 @@ const usage: []const u8 = pub var server: Server = undefined; -fn sa_handler(_: c_int) callconv(.C) void {} - pub fn main() anyerror!void { - // ignore SIGPIPE so we don't get killed when socket unexpectedly closes (thanks xwayland) - // use our own handler instead of SIG_IGN so we don't leak this when execve() - const act = os.Sigaction{ - .handler = .{ .handler = sa_handler }, - .mask = os.empty_sigset, - .flags = 0, - }; - os.sigaction(os.SIG.PIPE, &act, null); - // This line is here because of https://github.com/ziglang/zig/issues/7807 const argv: [][*:0]const u8 = os.argv; const result = flags.parse(argv[1..], &[_]flags.Flag{ @@ -107,6 +96,16 @@ pub fn main() anyerror!void { .warn, .err => .err, }); + // Ignore SIGPIPE so we don't get killed when writing to a socket that + // has had its read end closed by another process. + const sig_ign = os.Sigaction{ + // TODO(zig): Remove this casting after https://github.com/ziglang/zig/pull/12410 + .handler = .{ .handler = @intToPtr(os.Sigaction.handler_fn, @ptrToInt(os.SIG.IGN)) }, + .mask = os.empty_sigset, + .flags = 0, + }; + os.sigaction(os.SIG.PIPE, &sig_ign, null); + std.log.info("initializing server", .{}); try server.init(); defer server.deinit(); @@ -120,8 +119,7 @@ pub fn main() anyerror!void { const child_args = [_:null]?[*:0]const u8{ "/bin/sh", "-c", cmd, null }; const pid = try os.fork(); if (pid == 0) { - if (c.setsid() < 0) unreachable; - if (os.system.sigprocmask(os.SIG.SETMASK, &os.empty_sigset, null) < 0) unreachable; + util.post_fork_pre_execve(); os.execveZ("/bin/sh", &child_args, std.c.environ) catch c._exit(1); } util.gpa.free(cmd); diff --git a/river/util.zig b/river/util.zig index 2cd8874..13976df 100644 --- a/river/util.zig +++ b/river/util.zig @@ -1,6 +1,6 @@ // This file is part of river, a dynamic tiling wayland compositor. // -// Copyright 2020 The River Developers +// Copyright 2022 The River Developers // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -15,6 +15,21 @@ // along with this program. If not, see . const std = @import("std"); +const os = std.os; + +const c = @import("c.zig"); /// The global general-purpose allocator used throughout river's code pub const gpa = std.heap.c_allocator; + +pub fn post_fork_pre_execve() void { + if (c.setsid() < 0) unreachable; + if (os.system.sigprocmask(os.SIG.SETMASK, &os.empty_sigset, null) < 0) unreachable; + const sig_dfl = os.Sigaction{ + // TODO(zig): Remove this casting after https://github.com/ziglang/zig/pull/12410 + .handler = .{ .handler = @intToPtr(?os.Sigaction.handler_fn, @ptrToInt(os.SIG.DFL)) }, + .mask = os.empty_sigset, + .flags = 0, + }; + os.sigaction(os.SIG.PIPE, &sig_dfl, null); +}