From f711da9081fdf936dc788511261ba85b45f3d42a Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Tue, 11 Jan 2022 13:11:43 +0000 Subject: [PATCH] Make process substitutions work on Haiku On Haiku: # /bin/cat <(echo hi) # no redirection cat: /tmp/ksh.f29pd8f: No such file or directory Whereas this works fine: # /bin/cat < <(echo hi) # with redirection hi # /opt/ast/bin/cat <(echo hi) # no redirection; use built-in hi Haiku does not have /dev/fd, so uses the FIFO (named pipe) fallback mechanism. See also: c3eac977 Analysis: In the TFORK part of sh_exec(), forked branch (child), the FIFO (sh.fifo) is unlinked immediately after opening it. This is not a problem if the process substitution is used in combination with a redirection, but if not, then the FIFO is passed on to the command as a file name argument. This creates a race condition: ksh was counting on the external 'cat' command opening the FIFO before the child could unlink it. Whether that race is won depends on operating system implementation details. When invoking an external command on Haiku, the race is lost. src/cmd/ksh93/sh/xec.c: sh_exec(): TFORK: child branch: - Delay unlinking the FIFO until after executing the process substitution, when we're about to exit from the child process. --- src/cmd/ksh93/sh/xec.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/cmd/ksh93/sh/xec.c b/src/cmd/ksh93/sh/xec.c index fcd54da5a..d0e16e4e2 100644 --- a/src/cmd/ksh93/sh/xec.c +++ b/src/cmd/ksh93/sh/xec.c @@ -1688,6 +1688,7 @@ int sh_exec(register const Shnode_t *t, int flags) struct ionod *iop; int rewrite=0; #if !SHOPT_DEVFD + char *save_sh_fifo = sh.fifo; if(sh.fifo_tree) { /* do not clean up process substitution FIFOs in child; parent handles this */ @@ -1727,8 +1728,6 @@ int sh_exec(register const Shnode_t *t, int flags) fn = sh_open(sh.fifo,fd?O_WRONLY:O_RDONLY); save_errno = errno; timerdel(fifo_timer); - unlink(sh.fifo); - free(sh.fifo); sh.fifo = 0; if(fn<0) { @@ -1803,6 +1802,13 @@ int sh_exec(register const Shnode_t *t, int flags) path_exec(com0,com,t->com.comset); } done: +#if !SHOPT_DEVFD + if(save_sh_fifo) + { + unlink(save_sh_fifo); + free(save_sh_fifo); + } +#endif sh_popcontext(&sh,buffp); if(jmpval>SH_JMPEXIT) siglongjmp(*sh.jmplist,jmpval);