summaryrefslogtreecommitdiff
path: root/src/host_io.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/host_io.zig')
-rw-r--r--src/host_io.zig43
1 files changed, 40 insertions, 3 deletions
diff --git a/src/host_io.zig b/src/host_io.zig
index 9d4b27c2..bbd664a9 100644
--- a/src/host_io.zig
+++ b/src/host_io.zig
@@ -1075,6 +1075,45 @@ pub const Shell = struct {
}
};
+/// In a child between fork and exec: every signal back to its default and
+/// none blocked, whatever this process ignores or blocks (the tty's SIGWINCH,
+/// a SIGHUP nohup ignored). A handler resets at exec by itself; an ignored
+/// signal and the mask do not. Async-signal-safe: sigaction and sigprocmask.
+pub fn resetChildSignals() void {
+ const default: posix.Sigaction = .{ .handler = .{ .handler = posix.SIG.DFL }, .mask = posix.sigemptyset(), .flags = 0 };
+ var sig: u8 = 1;
+ while (sig < 65) : (sig += 1) {
+ if (sig == @intFromEnum(posix.SIG.KILL) or sig == @intFromEnum(posix.SIG.STOP)) continue;
+ _ = std.c.sigaction(@enumFromInt(sig), &default, null);
+ }
+ const none = posix.sigemptyset();
+ posix.sigprocmask(posix.SIG.SETMASK, &none, null);
+}
+
+test "a child starts with every signal at its default and none blocked" {
+ var blocked = posix.sigemptyset();
+ posix.sigaddset(&blocked, posix.SIG.WINCH);
+ posix.sigprocmask(posix.SIG.BLOCK, &blocked, null);
+ defer posix.sigprocmask(posix.SIG.UNBLOCK, &blocked, null);
+ const ignore: posix.Sigaction = .{ .handler = .{ .handler = posix.SIG.IGN }, .mask = posix.sigemptyset(), .flags = 0 };
+ var was: posix.Sigaction = undefined;
+ posix.sigaction(posix.SIG.HUP, &ignore, &was);
+ defer posix.sigaction(posix.SIG.HUP, &was, null);
+ const pid = libc.fork();
+ if (pid == 0) {
+ resetChildSignals();
+ var now: posix.Sigaction = undefined;
+ posix.sigaction(posix.SIG.HUP, null, &now);
+ var mask = posix.sigemptyset();
+ posix.sigprocmask(posix.SIG.BLOCK, null, &mask);
+ const ok = now.handler.handler == posix.SIG.DFL and !posix.sigismember(&mask, posix.SIG.WINCH);
+ libc._exit(if (ok) 0 else 1);
+ }
+ var status: c_int = 0;
+ _ = libc.waitpid(pid, &status, 0);
+ try std.testing.expectEqual(@as(c_int, 0), status);
+}
+
extern "c" fn forkpty(amaster: *c_int, name: ?[*:0]u8, termp: ?*const anyopaque, winp: ?*const posix.winsize) c_int;
extern "c" fn execv(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8) c_int;
extern "c" fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) c_int;
@@ -1278,9 +1317,7 @@ pub fn forkShell(
return error.ForkFailed;
}
if (pid == 0) {
- var set = posix.sigemptyset();
- posix.sigaddset(&set, posix.SIG.WINCH);
- posix.sigprocmask(posix.SIG.UNBLOCK, &set, null);
+ resetChildSignals();
if (cwd_z) |path| if (chdir(path.ptr) != 0) {
const why = [_]u8{ 'c', @truncate(@intFromEnum(libc.errno(@as(c_int, -1)))) };
_ = libc.write(told[1], &why, why.len);