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) { | ||||
|         // 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); | ||||
|  | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user