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:
		@ -40,10 +40,7 @@ pub fn spawn(
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pid == 0) {
 | 
					    if (pid == 0) {
 | 
				
			||||||
        // Clean things up for the child in an intermediate fork
 | 
					        util.post_fork_pre_execve();
 | 
				
			||||||
        if (c.setsid() < 0) unreachable;
 | 
					 | 
				
			||||||
        if (os.system.sigprocmask(os.SIG.SETMASK, &os.empty_sigset, null) < 0) unreachable;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const pid2 = os.fork() catch c._exit(1);
 | 
					        const pid2 = os.fork() catch c._exit(1);
 | 
				
			||||||
        if (pid2 == 0) os.execveZ("/bin/sh", &child_args, std.c.environ) catch c._exit(1);
 | 
					        if (pid2 == 0) os.execveZ("/bin/sh", &child_args, std.c.environ) catch c._exit(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -41,18 +41,7 @@ const usage: []const u8 =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub var server: Server = undefined;
 | 
					pub var server: Server = undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn sa_handler(_: c_int) callconv(.C) void {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn main() anyerror!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
 | 
					    // This line is here because of https://github.com/ziglang/zig/issues/7807
 | 
				
			||||||
    const argv: [][*:0]const u8 = os.argv;
 | 
					    const argv: [][*:0]const u8 = os.argv;
 | 
				
			||||||
    const result = flags.parse(argv[1..], &[_]flags.Flag{
 | 
					    const result = flags.parse(argv[1..], &[_]flags.Flag{
 | 
				
			||||||
@ -107,6 +96,16 @@ pub fn main() anyerror!void {
 | 
				
			|||||||
        .warn, .err => .err,
 | 
					        .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", .{});
 | 
					    std.log.info("initializing server", .{});
 | 
				
			||||||
    try server.init();
 | 
					    try server.init();
 | 
				
			||||||
    defer server.deinit();
 | 
					    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 child_args = [_:null]?[*:0]const u8{ "/bin/sh", "-c", cmd, null };
 | 
				
			||||||
        const pid = try os.fork();
 | 
					        const pid = try os.fork();
 | 
				
			||||||
        if (pid == 0) {
 | 
					        if (pid == 0) {
 | 
				
			||||||
            if (c.setsid() < 0) unreachable;
 | 
					            util.post_fork_pre_execve();
 | 
				
			||||||
            if (os.system.sigprocmask(os.SIG.SETMASK, &os.empty_sigset, null) < 0) unreachable;
 | 
					 | 
				
			||||||
            os.execveZ("/bin/sh", &child_args, std.c.environ) catch c._exit(1);
 | 
					            os.execveZ("/bin/sh", &child_args, std.c.environ) catch c._exit(1);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        util.gpa.free(cmd);
 | 
					        util.gpa.free(cmd);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
// This file is part of river, a dynamic tiling wayland compositor.
 | 
					// 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
 | 
					// 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
 | 
					// 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/>.
 | 
					// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const std = @import("std");
 | 
					const std = @import("std");
 | 
				
			||||||
 | 
					const os = std.os;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const c = @import("c.zig");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The global general-purpose allocator used throughout river's code
 | 
					/// The global general-purpose allocator used throughout river's code
 | 
				
			||||||
pub const gpa = std.heap.c_allocator;
 | 
					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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user