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.
This commit is contained in:
Isaac Freund 2022-08-11 12:02:30 +02:00
parent 600fd2e73c
commit 1a9cba2aa9
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
3 changed files with 28 additions and 18 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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 <https://www.gnu.org/licenses/>.
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);
}