From a8b88afcba1344ca8526bd88bc3877e66de37c6a Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Thu, 20 Aug 2026 17:39:06 +0900 Subject: [PATCH] ww: give captured actions null stdin --- lib/os/exec/exec.ww | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/lib/os/exec/exec.ww b/lib/os/exec/exec.ww index ecd5bd9a..ea8baf6a 100644 --- a/lib/os/exec/exec.ww +++ b/lib/os/exec/exec.ww @@ -28,13 +28,14 @@ export type result = struct { // command is deliberately concrete. argv includes argv[0], env is the full // environment, and an empty dir inherits the caller's working directory. -// stdoutpath and stderrpath are created exclusively with mode 0600. A zero -// deadline means no timeout. +// An empty stdinpath selects the null device; stdoutpath and stderrpath are +// created exclusively with mode 0600. A zero deadline means no timeout. export type command = struct { path: str, argv: []str, env: []str, dir: str, + stdinpath: str, stdoutpath: str, stderrpath: str, deadline: time.instant, @@ -124,7 +125,8 @@ fn valid(c: *command) bool = { return false; }; if ((c.grace: i64) < 0i64) { return false; }; - if (hasnul(c.path) || hasnul(c.dir) || hasnul(c.stdoutpath) + if (hasnul(c.path) || hasnul(c.dir) || hasnul(c.stdinpath) + || hasnul(c.stdoutpath) || hasnul(c.stderrpath)) { return false; }; @@ -209,8 +211,8 @@ fn childclose(fd: i32, markerfd: i32) void = { if (rc < 0) { childmark(markerfd, rc); }; }; -fn child(c: *command, av: []*u8, ep: []*u8, outfd: i32, - errfd: i32, markerread: i32, markerwrite: i32) void = { +fn child(c: *command, av: []*u8, ep: []*u8, infd: i32, + outfd: i32, errfd: i32, markerread: i32, markerwrite: i32) void = { let rc: i32 = os.setpgid(0, 0); if (rc < 0) { childmark(markerwrite, rc); }; if (launchmaskactive) { @@ -218,6 +220,9 @@ fn child(c: *command, av: []*u8, ep: []*u8, outfd: i32, if (rc < 0) { childmark(markerwrite, rc); }; }; childclose(markerread, markerwrite); + rc = os.dup2(infd, os.STDIN_FILENO); + if (rc < 0) { childmark(markerwrite, rc); }; + childclose(infd, markerwrite); rc = os.dup2(outfd, os.STDOUT_FILENO); if (rc < 0) { childmark(markerwrite, rc); }; rc = os.dup2(errfd, os.STDERR_FILENO); @@ -238,21 +243,37 @@ export fn start(p: *process, c: *command) void = { p.hasdeadline = c.deadline.sec != 0i64 || c.deadline.nsec != 0i64; p.grace = c.grace; if (!valid(c)) { fail(p, 22); return; }; + let stdinpath: str = c.stdinpath; + if (stdinpath.len == 0) { stdinpath = "/dev/null"; }; + let infd: i32 = os.open(stdinpath, os.flag.RDONLY, 0i32); + if (infd < 0) { fail(p, infd); return; }; + infd = safefd(&p.result, infd); + if (infd < 0) { fail(p, infd); return; }; let outfd: i32 = os.open(c.stdoutpath, os.flag.WRONLY | os.flag.CREATE | os.flag.EXCL, 384); - if (outfd < 0) { fail(p, outfd); return; }; + if (outfd < 0) { + fail(p, outfd); + closefd(&p.result, infd); + return; + }; outfd = safefd(&p.result, outfd); - if (outfd < 0) { fail(p, outfd); return; }; + if (outfd < 0) { + fail(p, outfd); + closefd(&p.result, infd); + return; + }; let errfd: i32 = os.open(c.stderrpath, os.flag.WRONLY | os.flag.CREATE | os.flag.EXCL, 384); if (errfd < 0) { fail(p, errfd); + closefd(&p.result, infd); closefd(&p.result, outfd); return; }; errfd = safefd(&p.result, errfd); if (errfd < 0) { fail(p, errfd); + closefd(&p.result, infd); closefd(&p.result, outfd); return; }; @@ -260,6 +281,7 @@ export fn start(p: *process, c: *command) void = { let rc: i32 = os.pipe2(&marker, os.O_CLOEXEC | os.O_NONBLOCK); if (rc < 0) { fail(p, rc); + closefd(&p.result, infd); closefd(&p.result, outfd); closefd(&p.result, errfd); return; @@ -267,6 +289,7 @@ export fn start(p: *process, c: *command) void = { marker[0] = safefd(&p.result, marker[0]); if (marker[0] < 0) { fail(p, marker[0]); + closefd(&p.result, infd); closefd(&p.result, outfd); closefd(&p.result, errfd); closefd(&p.result, marker[1]); @@ -275,6 +298,7 @@ export fn start(p: *process, c: *command) void = { marker[1] = safefd(&p.result, marker[1]); if (marker[1] < 0) { fail(p, marker[1]); + closefd(&p.result, infd); closefd(&p.result, outfd); closefd(&p.result, errfd); closefd(&p.result, marker[0]); @@ -285,16 +309,20 @@ export fn start(p: *process, c: *command) void = { let pid: i32 = os.fork(); if (pid < 0) { fail(p, pid); + closefd(&p.result, infd); closefd(&p.result, outfd); closefd(&p.result, errfd); closefd(&p.result, marker[0]); closefd(&p.result, marker[1]); return; }; - if (pid == 0) { child(c, av, ep, outfd, errfd, marker[0], marker[1]); }; + if (pid == 0) { + child(c, av, ep, infd, outfd, errfd, marker[0], marker[1]); + }; p.pid = pid; p.state = state.RUNNING as i32; p.markerfd = marker[0]; + closefd(&p.result, infd); closefd(&p.result, outfd); closefd(&p.result, errfd); closefd(&p.result, marker[1]);