1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00

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.
This commit is contained in:
Martijn Dekker 2022-01-11 13:11:43 +00:00
parent de5bdd12a4
commit f711da9081

View file

@ -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);