skalibs

Mirror/fork of https://skarnet.org/software/skalibs/
git clone https://ccx.te2000.cz/git/skalibs
Log | Files | Refs | README | LICENSE

commit 28e09b5eb76919122f8baf57899154b3dd5fdaa0
parent d64a3751ca805c08bfda6a330d73a09e87e993c0
Author: Laurent Bercot <ska-skaware@skarnet.org>
Date:   Wed, 28 Jun 2023 21:27:29 +0000

 Add workaround for bad QoI posix_spawn()

Signed-off-by: Laurent Bercot <ska@appnovation.com>

Diffstat:
Mconfigure | 7+++++--
Mpackage/deps.mak | 14++++++++------
Asrc/libstddjb/child_spawn-internal.h | 16++++++++++++++++
Msrc/libstddjb/child_spawn.c | 170++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Msrc/libstddjb/child_spawn0.c | 56+++++++++++++++++++++++++++++++++-----------------------
Msrc/libstddjb/child_spawn1_internal.c | 79+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/libstddjb/child_spawn2.c | 165++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/libstddjb/child_spawn3.c | 159+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Asrc/libstddjb/child_spawn_workaround.c | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sysdeps/tryposixspawnearlyreturn.c | 24++++++++++++++++++++++++
10 files changed, 462 insertions(+), 276 deletions(-)

diff --git a/configure b/configure @@ -47,8 +47,10 @@ $package options: Sysdeps autodetection override: --with-sysdep-K=V assume sysdep K has the value V [autodetected] -List of mandatory K for cross-compiling: devurandom (V=yes|no) - + +List of mandatory sysdeps for cross-compiling: + devurandom (yes|no): =yes if you have a working /dev/urandom + posixspawnearlyreturn (yes|no): =yes if you have an old glibc or otherwise bad posix_spawn EOF exit 0 } @@ -641,6 +643,7 @@ choose cl chroot 'chroot()' # Here are the evil irreducible run-time sysdeps. choose clr devurandom '/dev/urandom' +choose clr posixspawnearlyreturn 'posix_spawn() returning early' # Finally, produce config.mak and config.h diff --git a/package/deps.mak b/package/deps.mak @@ -63,6 +63,7 @@ src/libstdcrypto/sha1-internal.h: src/include/skalibs/sha1.h src/libstdcrypto/sha256-internal.h: src/include/skalibs/sha256.h src/libstdcrypto/sha512-internal.h: src/include/skalibs/sha512.h src/libstddjb/cdb-internal.h: src/include/skalibs/cdb.h src/include/skalibs/gccattributes.h +src/libstddjb/child_spawn-internal.h: src/include/skalibs/sysdeps.h src/libstddjb/djbtime-internal.h: src/include/skalibs/uint64.h src/libstddjb/fmtscan-internal.h: src/include/skalibs/fmtscan.h src/include/skalibs/uint64.h src/libunixonacid/skaclient-internal.h: src/include/skalibs/kolbak.h src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h @@ -236,7 +237,7 @@ src/libstddjb/buffer_2.o src/libstddjb/buffer_2.lo: src/libstddjb/buffer_2.c src src/libstddjb/buffer_fill.o src/libstddjb/buffer_fill.lo: src/libstddjb/buffer_fill.c src/include/skalibs/buffer.h src/libstddjb/buffer_flush.o src/libstddjb/buffer_flush.lo: src/libstddjb/buffer_flush.c src/include/skalibs/buffer.h src/include/skalibs/cbuffer.h src/libstddjb/buffer_flush1read.o src/libstddjb/buffer_flush1read.lo: src/libstddjb/buffer_flush1read.c src/include/skalibs/allreadwrite.h src/include/skalibs/buffer.h -src/libstddjb/buffer_get.o src/libstddjb/buffer_get.lo: src/libstddjb/buffer_get.c src/include/skalibs/buffer.h +src/libstddjb/buffer_get.o src/libstddjb/buffer_get.lo: src/libstddjb/buffer_get.c src/include/skalibs/allreadwrite.h src/include/skalibs/buffer.h src/libstddjb/buffer_getall.o src/libstddjb/buffer_getall.lo: src/libstddjb/buffer_getall.c src/include/skalibs/allreadwrite.h src/include/skalibs/buffer.h src/libstddjb/buffer_getallnf.o src/libstddjb/buffer_getallnf.lo: src/libstddjb/buffer_getallnf.c src/include/skalibs/buffer.h src/libstddjb/buffer_getfd.o src/libstddjb/buffer_getfd.lo: src/libstddjb/buffer_getfd.c src/include/skalibs/buffer.h @@ -293,13 +294,14 @@ src/libstddjb/cdb_p.o src/libstddjb/cdb_p.lo: src/libstddjb/cdb_p.c src/libstddj src/libstddjb/cdb_traverse_next.o src/libstddjb/cdb_traverse_next.lo: src/libstddjb/cdb_traverse_next.c src/libstddjb/cdb-internal.h src/include/skalibs/cdb.h src/include/skalibs/uint32.h src/libstddjb/cdb_zero.o src/libstddjb/cdb_zero.lo: src/libstddjb/cdb_zero.c src/include/skalibs/cdb.h src/libstddjb/cdbmake.o src/libstddjb/cdbmake.lo: src/libstddjb/cdbmake.c src/include/skalibs/buffer.h src/libstddjb/cdb-internal.h src/include/skalibs/cdbmake.h src/include/skalibs/diuint32.h src/include/skalibs/genalloc.h src/include/skalibs/uint32.h -src/libstddjb/child_spawn.o src/libstddjb/child_spawn.lo: src/libstddjb/child_spawn.c src/include/skalibs/allreadwrite.h src/include/skalibs/config.h src/include/skalibs/djbunix.h src/include/skalibs/env.h src/include/skalibs/exec.h src/include/skalibs/sig.h src/include/skalibs/strerr.h src/include/skalibs/sysdeps.h src/include/skalibs/types.h -src/libstddjb/child_spawn0.o src/libstddjb/child_spawn0.lo: src/libstddjb/child_spawn0.c src/include/skalibs/allreadwrite.h src/include/skalibs/config.h src/include/skalibs/djbunix.h src/include/skalibs/exec.h src/include/skalibs/sig.h src/include/skalibs/strerr.h src/include/skalibs/sysdeps.h -src/libstddjb/child_spawn1_internal.o src/libstddjb/child_spawn1_internal.lo: src/libstddjb/child_spawn1_internal.c src/include/skalibs/allreadwrite.h src/include/skalibs/config.h src/include/skalibs/djbunix.h src/include/skalibs/exec.h src/include/skalibs/sig.h src/include/skalibs/strerr.h src/include/skalibs/sysdeps.h +src/libstddjb/child_spawn.o src/libstddjb/child_spawn.lo: src/libstddjb/child_spawn.c src/include/skalibs/allreadwrite.h src/include/skalibs/config.h src/include/skalibs/djbunix.h src/include/skalibs/env.h src/include/skalibs/exec.h src/include/skalibs/sig.h src/include/skalibs/sysdeps.h src/include/skalibs/types.h +src/libstddjb/child_spawn0.o src/libstddjb/child_spawn0.lo: src/libstddjb/child_spawn0.c src/include/skalibs/allreadwrite.h src/include/skalibs/config.h src/include/skalibs/djbunix.h src/include/skalibs/exec.h src/include/skalibs/sig.h src/include/skalibs/sysdeps.h +src/libstddjb/child_spawn1_internal.o src/libstddjb/child_spawn1_internal.lo: src/libstddjb/child_spawn1_internal.c src/include/skalibs/allreadwrite.h src/include/skalibs/config.h src/include/skalibs/djbunix.h src/include/skalibs/exec.h src/include/skalibs/sig.h src/include/skalibs/sysdeps.h src/libstddjb/child_spawn1_pipe.o src/libstddjb/child_spawn1_pipe.lo: src/libstddjb/child_spawn1_pipe.c src/libstddjb/djbunix-internal.h src/include/skalibs/djbunix.h src/libstddjb/child_spawn1_socket.o src/libstddjb/child_spawn1_socket.lo: src/libstddjb/child_spawn1_socket.c src/libstddjb/djbunix-internal.h src/include/skalibs/djbunix.h src/include/skalibs/socket.h -src/libstddjb/child_spawn2.o src/libstddjb/child_spawn2.lo: src/libstddjb/child_spawn2.c src/include/skalibs/allreadwrite.h src/include/skalibs/config.h src/include/skalibs/djbunix.h src/include/skalibs/exec.h src/include/skalibs/sig.h src/include/skalibs/strerr.h src/include/skalibs/sysdeps.h -src/libstddjb/child_spawn3.o src/libstddjb/child_spawn3.lo: src/libstddjb/child_spawn3.c src/include/skalibs/allreadwrite.h src/include/skalibs/config.h src/include/skalibs/djbunix.h src/include/skalibs/env.h src/include/skalibs/exec.h src/include/skalibs/sig.h src/include/skalibs/strerr.h src/include/skalibs/sysdeps.h src/include/skalibs/types.h +src/libstddjb/child_spawn2.o src/libstddjb/child_spawn2.lo: src/libstddjb/child_spawn2.c src/include/skalibs/allreadwrite.h src/include/skalibs/config.h src/include/skalibs/djbunix.h src/include/skalibs/exec.h src/include/skalibs/sig.h src/include/skalibs/sysdeps.h +src/libstddjb/child_spawn3.o src/libstddjb/child_spawn3.lo: src/libstddjb/child_spawn3.c src/include/skalibs/allreadwrite.h src/include/skalibs/config.h src/include/skalibs/djbunix.h src/include/skalibs/env.h src/include/skalibs/exec.h src/include/skalibs/sig.h src/include/skalibs/sysdeps.h src/include/skalibs/types.h +src/libstddjb/child_spawn_workaround.o src/libstddjb/child_spawn_workaround.lo: src/libstddjb/child_spawn_workaround.c src/include/skalibs/allreadwrite.h src/libstddjb/child_spawn-internal.h src/include/skalibs/djbunix.h src/include/skalibs/sysdeps.h src/libstddjb/coe.o src/libstddjb/coe.lo: src/libstddjb/coe.c src/include/skalibs/djbunix.h src/libstddjb/deepsleepuntil.o src/libstddjb/deepsleepuntil.lo: src/libstddjb/deepsleepuntil.c src/include/skalibs/iopause.h src/include/skalibs/tai.h src/libstddjb/devino_cmp.o src/libstddjb/devino_cmp.lo: src/libstddjb/devino_cmp.c src/include/skalibs/devino.h diff --git a/src/libstddjb/child_spawn-internal.h b/src/libstddjb/child_spawn-internal.h @@ -0,0 +1,16 @@ +/* ISC license. */ + +#ifndef CHILD_SPAWN_INTERNAL_H +#define CHILD_SPAWN_INTERNAL_H + +#include <skalibs/sysdeps.h> + +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN + +#include <sys/types.h> + +extern pid_t child_spawn_workaround (pid_t, int const *) ; /* closes the pipe */ + +#endif + +#endif diff --git a/src/libstddjb/child_spawn.c b/src/libstddjb/child_spawn.c @@ -3,58 +3,48 @@ /* MT-unsafe */ #include <skalibs/sysdeps.h> + #include <string.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/wait.h> -#include <unistd.h> #include <errno.h> -#include <signal.h> +#include <unistd.h> + +#include <skalibs/types.h> +#include <skalibs/djbunix.h> #ifdef SKALIBS_HASPOSIXSPAWN +#include <signal.h> #include <stdlib.h> #include <spawn.h> -#include <skalibs/config.h> - -#else - -#include <skalibs/sig.h> -#include <skalibs/strerr.h> -#include <skalibs/exec.h> - -#endif -#include <skalibs/types.h> -#include <skalibs/allreadwrite.h> +#include <skalibs/config.h> #include <skalibs/env.h> -#include <skalibs/djbunix.h> - /* - If n = 0 : child's stdin and stdout are the same as the parent's - If n >= 1 : pipes between parent and child. - Parent reads on even ones, writes on odd ones. - */ +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN +# include "child_spawn-internal.h" +#endif pid_t child_spawn (char const *prog, char const *const *argv, char const *const *envp, int *fds, unsigned int n) { pid_t pid ; -#ifdef SKALIBS_HASPOSIXSPAWN posix_spawn_file_actions_t actions ; posix_spawnattr_t attr ; + sigset_t set ; int e ; -#else - int syncpipe[2] ; -#endif int p[n ? n : 1][2] ; size_t m = sizeof(SKALIBS_CHILD_SPAWN_FDS_ENVVAR) ; unsigned int i = 0 ; char modifs[m + 1 + n * UINT_FMT] ; +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN + int syncpipe[2] ; + if (pipecoe(syncpipe) == -1) return 0 ; +#endif + memcpy(modifs, SKALIBS_CHILD_SPAWN_FDS_ENVVAR "=", sizeof(SKALIBS_CHILD_SPAWN_FDS_ENVVAR)) ; for (; i < n ; i++) { - if (pipe(p[i]) < 0) goto errpi ; - if ((ndelay_on(p[i][i & 1]) < 0) || (coe(p[i][i & 1]) < 0)) + if (pipe(p[i]) == -1) goto errpi ; + if ((ndelay_on(p[i][i & 1]) == -1) || (coe(p[i][i & 1]) == -1)) { i++ ; goto errpi ; } @@ -66,18 +56,13 @@ pid_t child_spawn (char const *prog, char const *const *argv, char const *const } modifs[m++] = 0 ; -#ifdef SKALIBS_HASPOSIXSPAWN - e = posix_spawnattr_init(&attr) ; if (e) goto erre ; - { - sigset_t set ; - sigemptyset(&set) ; - e = posix_spawnattr_setsigmask(&attr, &set) ; - if (e) goto errattr ; - e = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK) ; - if (e) goto errattr ; - } + sigemptyset(&set) ; + e = posix_spawnattr_setsigmask(&attr, &set) ; + if (e) goto errattr ; + e = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK) ; + if (e) goto errattr ; e = posix_spawn_file_actions_init(&actions) ; if (e) goto errattr ; if (n >= 2 && p[1][0]) @@ -110,53 +95,104 @@ pid_t child_spawn (char const *prog, char const *const *argv, char const *const posix_spawn_file_actions_destroy(&actions) ; posix_spawnattr_destroy(&attr) ; + for (i = 0 ; i < n ; i++) fd_close(p[i][!(i & 1)]) ; + +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN + pid = child_spawn_workaround(pid, syncpipe) ; + if (!pid) + { + for (i = 0 ; i < n ; i++) fd_close(p[i][i & 1]) ; + return 0 ; + } +#endif + for (i = 0 ; i < n ; i++) fds[i] = p[i][i & 1] ; + return pid ; + + erractions: + posix_spawn_file_actions_destroy(&actions) ; + errattr: + posix_spawnattr_destroy(&attr) ; + erre: + errno = e ; + i = n ; + errpi: + while (i--) + { + fd_close(p[i][1]) ; + fd_close(p[i][0]) ; + } +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN + fd_close(syncpipe[1]) ; + fd_close(syncpipe[0]) ; +#endif + return 0 ; +} #else + +#include <skalibs/allreadwrite.h> +#include <skalibs/sig.h> +#include <skalibs/exec.h> + +pid_t child_spawn (char const *prog, char const *const *argv, char const *const *envp, int *fds, unsigned int n) +{ + pid_t pid ; + int syncpipe[2] ; + int p[n ? n : 1][2] ; + size_t m = sizeof(SKALIBS_CHILD_SPAWN_FDS_ENVVAR) ; + unsigned int i = 0 ; + char modifs[m + 1 + n * UINT_FMT] ; + char c ; + + memcpy(modifs, SKALIBS_CHILD_SPAWN_FDS_ENVVAR "=", sizeof(SKALIBS_CHILD_SPAWN_FDS_ENVVAR)) ; + for (; i < n ; i++) + { + if (pipe(p[i]) == -1) goto errpi ; + if ((ndelay_on(p[i][i & 1]) == -1) || (coe(p[i][i & 1]) == -1)) + { + i++ ; goto errpi ; + } + } + for (i = 2 ; i < n ; i++) + { + m += uint_fmt(modifs + m, p[i][!(i & 1)]) ; + if (i+1 < n) modifs[m++] = ',' ; + } + modifs[m++] = 0 ; + if (pipecoe(syncpipe) < 0) goto errp ; pid = fork() ; if (pid < 0) goto errsp ; else if (!pid) { - size_t len = strlen(PROG) ; - char name[len + 9] ; - memcpy(name, PROG, len) ; - memcpy(name + len, " (child)", 9) ; - PROG = name ; if (n >= 2) { - if (fd_move2(0, p[1][0], 1, p[0][1]) < 0) goto syncdie ; + if (fd_move2(0, p[1][0], 1, p[0][1]) == -1) goto syncdie ; } else if (n) { - if (fd_move(1, p[0][1]) < 0) goto syncdie ; + if (fd_move(1, p[0][1]) == -1) goto syncdie ; } sig_blocknone() ; mexec_aen(prog, argv, envp, modifs, m, 1) ; - syncdie: - { - unsigned char c = errno ; - fd_write(syncpipe[1], (char *)&c, 1) ; - } + c = errno ; + fd_write(syncpipe[1], &c, 1) ; _exit(127) ; } fd_close(syncpipe[1]) ; + syncpipe[1] = fd_read(syncpipe[0], &c, 1) ; + if (syncpipe[1]) { - unsigned char c ; - syncpipe[1] = fd_read(syncpipe[0], (char *)&c, 1) ; - if (syncpipe[1]) - { - int e = c ; - if (syncpipe[1] < 0) e = errno ; - if (wait_pid(pid, &syncpipe[1]) < 0) e = errno ; - errno = e ; - goto errsp0 ; - } + int e = (unsigned char)c ; + if (syncpipe[1] == -1) e = errno ; + if (wait_pid(pid, 0) == -1) e = errno ; + errno = e ; + goto errsp0 ; } fd_close(syncpipe[0]) ; -#endif for (i = n ; i ; i--) { @@ -165,21 +201,11 @@ pid_t child_spawn (char const *prog, char const *const *argv, char const *const } return pid ; -#ifdef SKALIBS_HASPOSIXSPAWN - erractions: - posix_spawn_file_actions_destroy(&actions) ; - errattr: - posix_spawnattr_destroy(&attr) ; - erre: - errno = e ; -#endif -#ifndef SKALIBS_HASPOSIXSPAWN errsp: fd_close(syncpipe[1]) ; errsp0: fd_close(syncpipe[0]) ; errp: -#endif i = n ; errpi: while (i--) @@ -189,3 +215,5 @@ pid_t child_spawn (char const *prog, char const *const *argv, char const *const } return 0 ; } + +#endif diff --git a/src/libstddjb/child_spawn0.c b/src/libstddjb/child_spawn0.c @@ -1,42 +1,59 @@ /* ISC license. */ #include <skalibs/sysdeps.h> + #include <errno.h> #ifdef SKALIBS_HASPOSIXSPAWN #include <signal.h> -#include <spawn.h> #include <stdlib.h> +#include <spawn.h> #include <skalibs/config.h> +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN +# include <skalibs/djbunix.h> +# include "child_spawn-internal.h" +#endif + pid_t child_spawn0 (char const *prog, char const *const *argv, char const *const *envp) { pid_t pid ; posix_spawnattr_t attr ; + sigset_t set ; int e ; int nopath = !getenv("PATH") ; +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN + int p[2] ; + if (pipecoe(p) == -1) return 0 ; +#endif e = posix_spawnattr_init(&attr) ; if (e) goto err ; - { - sigset_t set ; - sigemptyset(&set) ; - e = posix_spawnattr_setsigmask(&attr, &set) ; - if (e) goto errattr ; - e = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK) ; - if (e) goto errattr ; - } + sigemptyset(&set) ; + e = posix_spawnattr_setsigmask(&attr, &set) ; + if (e) goto errattr ; + e = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK) ; + if (e) goto errattr ; if (nopath && (setenv("PATH", SKALIBS_DEFAULTPATH, 0) < 0)) { e = errno ; goto errattr ; } e = posix_spawnp(&pid, prog, 0, &attr, (char *const *)argv, (char *const *)envp) ; if (nopath) unsetenv("PATH") ; + if (e) goto errattr ; + posix_spawnattr_destroy(&attr) ; - if (e) goto err ; +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN + return child_spawn_workaround(pid, p) ; +#else return pid ; +#endif errattr: posix_spawnattr_destroy(&attr) ; err: +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN + fd_close(p[1]) ; + fd_close(p[0]) ; +#endif errno = e ; return 0 ; } @@ -44,10 +61,8 @@ pid_t child_spawn0 (char const *prog, char const *const *argv, char const *const #else #include <unistd.h> -#include <string.h> #include <skalibs/allreadwrite.h> -#include <skalibs/strerr.h> #include <skalibs/sig.h> #include <skalibs/djbunix.h> #include <skalibs/exec.h> @@ -56,8 +71,9 @@ pid_t child_spawn0 (char const *prog, char const *const *argv, char const *const { pid_t pid ; int p[2] ; - unsigned char c ; - if (pipecoe(p) < 0) return 0 ; + char c ; + + if (pipecoe(p) == -1) return 0 ; pid = fork() ; if (pid < 0) { @@ -67,20 +83,14 @@ pid_t child_spawn0 (char const *prog, char const *const *argv, char const *const } if (!pid) { - size_t len = strlen(PROG) ; - char name[len + 9] ; - memcpy(name, PROG, len) ; - memcpy(name + len, " (child)", 9) ; - PROG = name ; - fd_close(p[0]) ; sig_blocknone() ; exec_ae(prog, argv, envp) ; c = errno ; - fd_write(p[1], (char *)&c, 1) ; + fd_write(p[1], &c, 1) ; _exit(127) ; } fd_close(p[1]) ; - p[1] = fd_read(p[0], (char *)&c, 1) ; + p[1] = fd_read(p[0], &c, 1) ; if (p[1] < 0) { fd_close(p[0]) ; @@ -90,7 +100,7 @@ pid_t child_spawn0 (char const *prog, char const *const *argv, char const *const if (p[1]) { wait_pid(pid, &p[0]) ; - errno = c ; + errno = (unsigned char)c ; return 0 ; } return pid ; diff --git a/src/libstddjb/child_spawn1_internal.c b/src/libstddjb/child_spawn1_internal.c @@ -1,9 +1,11 @@ /* ISC license. */ #include <skalibs/sysdeps.h> -#include <unistd.h> + #include <errno.h> +#include <skalibs/djbunix.h> + #ifdef SKALIBS_HASPOSIXSPAWN #include <signal.h> @@ -11,26 +13,33 @@ #include <stdlib.h> #include <skalibs/config.h> -#include <skalibs/djbunix.h> + +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN +# include "child_spawn-internal.h" +#endif pid_t child_spawn1_internal (char const *prog, char const *const *argv, char const *const *envp, int *p, int to) { pid_t pid ; posix_spawn_file_actions_t actions ; posix_spawnattr_t attr ; + sigset_t set ; int e ; int nopath = !getenv("PATH") ; - if (coe(p[!(to & 1)]) < 0) goto err ; + +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN + int syncpipe[2] ; + if (pipecoe(syncpipe) == -1) goto err ; +#endif + + if (coe(p[!(to & 1)]) == -1) goto errp ; e = posix_spawnattr_init(&attr) ; if (e) goto erre ; - { - sigset_t set ; - sigemptyset(&set) ; - e = posix_spawnattr_setsigmask(&attr, &set) ; - if (e) goto errattr ; - e = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK) ; - if (e) goto errattr ; - } + sigemptyset(&set) ; + e = posix_spawnattr_setsigmask(&attr, &set) ; + if (e) goto errattr ; + e = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK) ; + if (e) goto errattr ; e = posix_spawn_file_actions_init(&actions) ; if (e) goto errattr ; if (p[to & 1] != (to & 1)) @@ -49,10 +58,16 @@ pid_t child_spawn1_internal (char const *prog, char const *const *argv, char con e = posix_spawnp(&pid, prog, &actions, &attr, (char *const *)argv, (char *const *)envp) ; if (nopath) unsetenv("PATH") ; if (e) goto erractions ; + posix_spawn_file_actions_destroy(&actions) ; posix_spawnattr_destroy(&attr) ; fd_close(p[to & 1]) ; + +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN + return child_spawn_workaround(pid, syncpipe) ; +#else return pid ; +#endif erractions: posix_spawn_file_actions_destroy(&actions) ; @@ -60,7 +75,12 @@ pid_t child_spawn1_internal (char const *prog, char const *const *argv, char con posix_spawnattr_destroy(&attr) ; erre: errno = e ; + errp: +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN + fd_close(syncpipe[1]) ; + fd_close(syncpipe[0]) ; err: +#endif fd_close(p[1]) ; fd_close(p[0]) ; return 0 ; @@ -68,59 +88,46 @@ pid_t child_spawn1_internal (char const *prog, char const *const *argv, char con #else -#include <string.h> +#include <unistd.h> #include <skalibs/allreadwrite.h> -#include <skalibs/strerr.h> #include <skalibs/sig.h> -#include <skalibs/djbunix.h> #include <skalibs/exec.h> pid_t child_spawn1_internal (char const *prog, char const *const *argv, char const *const *envp, int *p, int to) { pid_t pid ; int syncpipe[2] ; + char c ; + if (coe(p[0]) < 0 || pipecoe(syncpipe) < 0) goto err ; pid = fork() ; if (pid < 0) goto errsp ; if (!pid) { - size_t len = strlen(PROG) ; - char name[len + 9] ; - memcpy(name, PROG, len) ; - memcpy(name + len, " (child)", 9) ; - PROG = name ; fd_close(p[!(to & 1)]) ; if (fd_move(to & 1, p[to & 1]) < 0) goto syncdie ; if ((to & 2) && (fd_copy(!(to & 1), to & 1) < 0)) goto syncdie ; sig_blocknone() ; exec_ae(prog, argv, envp) ; - syncdie: - { - unsigned char c = errno ; - fd_write(syncpipe[1], (char *)&c, 1) ; - } + c = errno ; + fd_write(syncpipe[1], &c, 1) ; _exit(127) ; } fd_close(syncpipe[1]) ; - + syncpipe[1] = fd_read(syncpipe[0], &c, 1) ; + if (syncpipe[1]) { - unsigned char c ; - syncpipe[1] = fd_read(syncpipe[0], (char *)&c, 1) ; - if (syncpipe[1]) - { - int e = c ; - if (syncpipe[1] < 0) e = errno ; - if (wait_pid(pid, &syncpipe[1]) < 0) e = errno ; - errno = e ; - goto errsp0 ; - } + int e = (unsigned char)c ; + if (syncpipe[1] == -1) e = errno ; + if (wait_pid(pid, 0) == -1) e = errno ; + errno = e ; + goto errsp0 ; } fd_close(syncpipe[0]) ; - fd_close(p[to & 1]) ; return pid ; diff --git a/src/libstddjb/child_spawn2.c b/src/libstddjb/child_spawn2.c @@ -3,58 +3,48 @@ /* MT-unsafe */ #include <skalibs/sysdeps.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/wait.h> + #include <unistd.h> #include <errno.h> -#include <signal.h> + +#include <skalibs/djbunix.h> #ifdef SKALIBS_HASPOSIXSPAWN +#include <signal.h> #include <stdlib.h> #include <spawn.h> -#include <skalibs/config.h> -#else - -#include <string.h> -#include <skalibs/allreadwrite.h> -#include <skalibs/sig.h> -#include <skalibs/strerr.h> -#include <skalibs/exec.h> +#include <skalibs/config.h> +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN +# include "child_spawn-internal.h" #endif -#include <skalibs/djbunix.h> - pid_t child_spawn2 (char const *prog, char const *const *argv, char const *const *envp, int *fds) { pid_t pid ; -#ifdef SKALIBS_HASPOSIXSPAWN posix_spawn_file_actions_t actions ; posix_spawnattr_t attr ; + int p[2][2] ; int e ; -#else + int nopath = !getenv("PATH") ; + sigset_t set ; +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN int syncpipe[2] ; + if (pipecoe(syncpipe) == -1) return 0 ; #endif - int p[2][2] ; - if (pipe(p[0]) < 0) return 0 ; - if (ndelay_on(p[0][0]) < 0 || coe(p[0][0]) < 0 || pipe(p[1]) < 0) goto errp ; - if (ndelay_on(p[1][1]) < 0 || coe(p[1][1]) < 0) goto errp1 ; - -#ifdef SKALIBS_HASPOSIXSPAWN + if (pipe(p[0]) == -1) goto err ; + if (ndelay_on(p[0][0]) == -1 || coe(p[0][0]) == -1 || pipe(p[1]) == -1) goto errp ; + if (ndelay_on(p[1][1]) == -1 || coe(p[1][1]) == -1) goto errp1 ; e = posix_spawnattr_init(&attr) ; if (e) goto erre ; - { - sigset_t set ; - sigemptyset(&set) ; - e = posix_spawnattr_setsigmask(&attr, &set) ; - if (e) goto errattr ; - e = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK) ; - if (e) goto errattr ; - } + sigemptyset(&set) ; + e = posix_spawnattr_setsigmask(&attr, &set) ; + if (e) goto errattr ; + e = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK) ; + if (e) goto errattr ; e = posix_spawn_file_actions_init(&actions) ; if (e) goto errattr ; if (p[1][0] != fds[0]) @@ -71,78 +61,105 @@ pid_t child_spawn2 (char const *prog, char const *const *argv, char const *const e = posix_spawn_file_actions_addclose(&actions, p[0][1]) ; if (e) goto erractions ; } + if (nopath && (setenv("PATH", SKALIBS_DEFAULTPATH, 0) == -1)) { - int nopath = !getenv("PATH") ; - if (nopath && (setenv("PATH", SKALIBS_DEFAULTPATH, 0) < 0)) - { - e = errno ; goto erractions ; - } - e = posix_spawnp(&pid, prog, &actions, &attr, (char *const *)argv, (char *const *)envp) ; - if (nopath) unsetenv("PATH") ; - if (e) goto erractions ; + e = errno ; goto erractions ; + } + e = posix_spawnp(&pid, prog, &actions, &attr, (char *const *)argv, (char *const *)envp) ; + if (nopath) unsetenv("PATH") ; + if (e) goto erractions ; + + posix_spawn_file_actions_destroy(&actions) ; + posix_spawnattr_destroy(&attr) ; + fd_close(p[0][1]) ; + fd_close(p[1][0]) ; + +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN + pid = child_spawn_workaround(pid, syncpipe) ; + if (!pid) + { + fd_close(p[1][1]) ; + fd_close(p[0][0]) ; + return 0 ; } +#endif + fds[0] = p[0][0] ; + fds[1] = p[1][1] ; + return pid ; + erractions: posix_spawn_file_actions_destroy(&actions) ; + errattr: posix_spawnattr_destroy(&attr) ; + erre: + errno = e ; + errp1: + fd_close(p[1][1]) ; + fd_close(p[1][0]) ; + errp: + fd_close(p[0][1]) ; + fd_close(p[0][0]) ; + err: +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN + fd_close(syncpipe[1]) ; + fd_close(syncpipe[0]) ; +#endif + return 0 ; +} #else + +#include <skalibs/allreadwrite.h> +#include <skalibs/sig.h> +#include <skalibs/exec.h> + +pid_t child_spawn2 (char const *prog, char const *const *argv, char const *const *envp, int *fds) +{ + pid_t pid ; + int syncpipe[2] ; + int p[2][2] ; + char c ; + + if (pipe(p[0]) < 0) return 0 ; + if (ndelay_on(p[0][0]) < 0 || coe(p[0][0]) < 0 || pipe(p[1]) < 0) goto errp ; + if (ndelay_on(p[1][1]) < 0 || coe(p[1][1]) < 0) goto errp1 ; if (pipecoe(syncpipe) < 0) goto errp1 ; pid = fork() ; - if (pid < 0) goto errsp ; + if (pid == -1) goto errsp ; else if (!pid) { - size_t len = strlen(PROG) ; - char name[len + 9] ; - memcpy(name, PROG, len) ; - memcpy(name + len, " (child)", 9) ; - PROG = name ; if (fd_move2(fds[0], p[1][0], fds[1], p[0][1]) < 0) goto syncdie ; sig_blocknone() ; exec_ae(prog, argv, envp) ; - - syncdie: - { - unsigned char c = errno ; - fd_write(syncpipe[1], (char *)&c, 1) ; - } + syncdie: + c = errno ; + fd_write(syncpipe[1], &c, 1) ; _exit(127) ; } fd_close(syncpipe[1]) ; + syncpipe[1] = fd_read(syncpipe[0], &c, 1) ; + if (syncpipe[1]) { - unsigned char c ; - syncpipe[1] = fd_read(syncpipe[0], (char *)&c, 1) ; - if (syncpipe[1]) - { - int e = c ; - if (syncpipe[1] < 0) e = errno ; - if (wait_pid(pid, &syncpipe[1]) < 0) e = errno ; - errno = e ; - goto errsp0 ; - } + int e = (unsigned char)c ; + if (syncpipe[1] == -1) e = errno ; + if (wait_pid(pid, &syncpipe[1]) == -1) e = errno ; + errno = e ; + goto errsp0 ; } fd_close(syncpipe[0]) ; -#endif + fd_close(p[0][1]) ; + fd_close(p[1][0]) ; - fd_close(p[0][1]) ; fds[0] = p[0][0] ; - fd_close(p[1][0]) ; fds[1] = p[1][1] ; + fds[0] = p[0][0] ; + fds[1] = p[1][1] ; return pid ; -#ifdef SKALIBS_HASPOSIXSPAWN - erractions: - posix_spawn_file_actions_destroy(&actions) ; - errattr: - posix_spawnattr_destroy(&attr) ; - erre: - errno = e ; -#endif -#ifndef SKALIBS_HASPOSIXSPAWN errsp: fd_close(syncpipe[1]) ; errsp0: fd_close(syncpipe[0]) ; -#endif errp1: fd_close(p[1][1]) ; fd_close(p[1][0]) ; @@ -151,3 +168,5 @@ pid_t child_spawn2 (char const *prog, char const *const *argv, char const *const fd_close(p[0][0]) ; return 0 ; } + +#endif diff --git a/src/libstddjb/child_spawn3.c b/src/libstddjb/child_spawn3.c @@ -3,64 +3,54 @@ /* MT-unsafe */ #include <skalibs/sysdeps.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/wait.h> + #include <unistd.h> #include <errno.h> -#include <signal.h> + +#include <skalibs/types.h> +#include <skalibs/djbunix.h> #ifdef SKALIBS_HASPOSIXSPAWN +#include <signal.h> #include <stdlib.h> #include <spawn.h> -#include <skalibs/config.h> - -#else -#include <string.h> -#include <skalibs/sig.h> -#include <skalibs/strerr.h> -#include <skalibs/exec.h> +#include <skalibs/config.h> +#include <skalibs/env.h> +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN +# include "child_spawn-internal.h" #endif -#include <skalibs/types.h> -#include <skalibs/allreadwrite.h> -#include <skalibs/env.h> -#include <skalibs/djbunix.h> - pid_t child_spawn3 (char const *prog, char const *const *argv, char const *const *envp, int *fds) { pid_t pid ; -#ifdef SKALIBS_HASPOSIXSPAWN posix_spawn_file_actions_t actions ; posix_spawnattr_t attr ; + sigset_t set ; int e ; -#else - int syncpipe[2] ; -#endif int p[3][2] ; size_t m = sizeof(SKALIBS_CHILD_SPAWN_FDS_ENVVAR) ; char modifs[sizeof(SKALIBS_CHILD_SPAWN_FDS_ENVVAR) + UINT_FMT] = SKALIBS_CHILD_SPAWN_FDS_ENVVAR "=" ; - if (pipe(p[0]) < 0 || ndelay_on(p[0][0]) < 0 || coe(p[0][0]) < 0) return 0 ; +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN + int syncpipe[2] ; + if (pipecoe(syncpipe) == -1) return 0 ; +#endif + + if (pipe(p[0]) < 0 || ndelay_on(p[0][0]) < 0 || coe(p[0][0]) < 0) goto err ; if (pipe(p[1]) < 0 || ndelay_on(p[1][1]) < 0 || coe(p[1][1]) < 0) goto errp0 ; if (pipe(p[2]) < 0 || ndelay_on(p[2][0]) < 0 || coe(p[2][0]) < 0) goto errp1 ; m += uint_fmt(modifs + sizeof(SKALIBS_CHILD_SPAWN_FDS_ENVVAR), p[2][1]) ; modifs[m++] = 0 ; -#ifdef SKALIBS_HASPOSIXSPAWN - e = posix_spawnattr_init(&attr) ; if (e) goto erre ; - { - sigset_t set ; - sigemptyset(&set) ; - e = posix_spawnattr_setsigmask(&attr, &set) ; - if (e) goto errattr ; - e = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK) ; - if (e) goto errattr ; - } + sigemptyset(&set) ; + e = posix_spawnattr_setsigmask(&attr, &set) ; + if (e) goto errattr ; + e = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK) ; + if (e) goto errattr ; e = posix_spawn_file_actions_init(&actions) ; if (e) goto errattr ; if (p[1][0] != fds[0]) @@ -77,7 +67,7 @@ pid_t child_spawn3 (char const *prog, char const *const *argv, char const *const e = posix_spawn_file_actions_addclose(&actions, p[0][1]) ; if (e) goto erractions ; } - { + { int nopath = !getenv("PATH") ; size_t envlen = env_len(envp) ; char const *newenv[envlen + 2] ; @@ -93,46 +83,93 @@ pid_t child_spawn3 (char const *prog, char const *const *argv, char const *const posix_spawn_file_actions_destroy(&actions) ; posix_spawnattr_destroy(&attr) ; + fd_close(p[2][1]) ; + fd_close(p[1][0]) ; + fd_close(p[0][1]) ; + +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN + pid = child_spawn_workaround(pid, syncpipe) ; + if (!pid) + { + fd_close(p[2][0]) ; + fd_close(p[1][1]) ; + fd_close(p[0][0]) ; + return 0 ; + } +#endif + fds[0] = p[0][0] ; + fds[1] = p[1][1] ; + fds[2] = p[2][0] ; + return pid ; + + erractions: + posix_spawn_file_actions_destroy(&actions) ; + errattr: + posix_spawnattr_destroy(&attr) ; + erre: + errno = e ; + fd_close(p[2][1]) ; + fd_close(p[2][0]) ; + errp1: + fd_close(p[1][1]) ; + fd_close(p[1][0]) ; + errp0: + fd_close(p[0][1]) ; + fd_close(p[0][0]) ; + err: +#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN + fd_close(syncpipe[1]) ; + fd_close(syncpipe[0]) ; +#endif + return 0 ; +} #else + +#include <skalibs/allreadwrite.h> +#include <skalibs/sig.h> +#include <skalibs/exec.h> + +pid_t child_spawn3 (char const *prog, char const *const *argv, char const *const *envp, int *fds) +{ + pid_t pid ; + int syncpipe[2] ; + int p[3][2] ; + size_t m = sizeof(SKALIBS_CHILD_SPAWN_FDS_ENVVAR) ; + char modifs[sizeof(SKALIBS_CHILD_SPAWN_FDS_ENVVAR) + UINT_FMT] = SKALIBS_CHILD_SPAWN_FDS_ENVVAR "=" ; + char c ; + + if (pipe(p[0]) == -1 || ndelay_on(p[0][0]) == -1 || coe(p[0][0]) == -1) return 0 ; + if (pipe(p[1]) == -1 || ndelay_on(p[1][1]) == -1 || coe(p[1][1]) == -1) goto errp0 ; + if (pipe(p[2]) == -1 || ndelay_on(p[2][0]) == -1 || coe(p[2][0]) == -1) goto errp1 ; + m += uint_fmt(modifs + sizeof(SKALIBS_CHILD_SPAWN_FDS_ENVVAR), p[2][1]) ; + modifs[m++] = 0 ; if (pipecoe(syncpipe) < 0) goto errp2 ; pid = fork() ; if (pid < 0) goto errsp ; else if (!pid) { - size_t len = strlen(PROG) ; - char name[len + 9] ; - memcpy(name, PROG, len) ; - memcpy(name + len, " (child)", 9) ; - PROG = name ; - if (fd_move2(fds[0], p[1][0], fds[1], p[0][1]) < 0) goto syncdie ; + if (fd_move2(fds[0], p[1][0], fds[1], p[0][1]) == -1) goto syncdie ; sig_blocknone() ; mexec_aen(prog, argv, envp, modifs, m, 1) ; - - syncdie: - { - unsigned char c = errno ; - fd_write(syncpipe[1], (char *)&c, 1) ; - } + syncdie: + c = errno ; + fd_write(syncpipe[1], &c, 1) ; _exit(127) ; } fd_close(syncpipe[1]) ; + syncpipe[1] = fd_read(syncpipe[0], &c, 1) ; + if (syncpipe[1]) { - unsigned char c ; - syncpipe[1] = fd_read(syncpipe[0], (char *)&c, 1) ; - if (syncpipe[1]) - { - int e = c ; - if (syncpipe[1] < 0) e = errno ; - if (wait_pid(pid, &syncpipe[1]) < 0) e = errno ; - errno = e ; - goto errsp0 ; - } + int e = (unsigned char)c ; + if (syncpipe[1] == -1) e = errno ; + if (wait_pid(pid, &syncpipe[1]) == -1) e = errno ; + errno = e ; + goto errsp0 ; } fd_close(syncpipe[0]) ; -#endif fd_close(p[2][1]) ; fd_close(p[1][0]) ; @@ -142,21 +179,11 @@ pid_t child_spawn3 (char const *prog, char const *const *argv, char const *const fds[2] = p[2][0] ; return pid ; -#ifdef SKALIBS_HASPOSIXSPAWN - erractions: - posix_spawn_file_actions_destroy(&actions) ; - errattr: - posix_spawnattr_destroy(&attr) ; - erre: - errno = e ; -#endif -#ifndef SKALIBS_HASPOSIXSPAWN errsp: fd_close(syncpipe[1]) ; errsp0: fd_close(syncpipe[0]) ; errp2: -#endif fd_close(p[2][1]) ; fd_close(p[2][0]) ; errp1: @@ -167,3 +194,5 @@ pid_t child_spawn3 (char const *prog, char const *const *argv, char const *const fd_close(p[0][0]) ; return 0 ; } + +#endif diff --git a/src/libstddjb/child_spawn_workaround.c b/src/libstddjb/child_spawn_workaround.c @@ -0,0 +1,48 @@ +/* ISC license. */ + +#include <skalibs/sysdeps.h> + +#if defined(SKALIBS_HASPOSIXSPAWN) && defined(SKALIBS_HASPOSIXSPAWNEARLYRETURN) + +#include <errno.h> +#include <signal.h> +#include <sys/wait.h> + +#include <skalibs/allreadwrite.h> +#include <skalibs/djbunix.h> +#include "child_spawn-internal.h" + +pid_t child_spawn_workaround (pid_t pid, int const *p) +{ + siginfo_t si ; + int e ; + ssize_t r ; + char c ; + + fd_close(p[1]) ; + r = fd_read(p[0], &c, 1) ; + fd_close(p[0]) ; + if (r == -1) return 0 ; + if (r) return (errno = EILSEQ, 0) ; /* child wrote, wtf */ + + do e = waitid(P_PID, pid, &si, WNOHANG | WNOWAIT) ; + while (e == -1 && errno == EINTR) ; + if (e == -1) return pid ; /* we're in trouble, but don't leak a child */ + if (!si.si_pid) return pid ; /* child is running */ + if (si.si_code != CLD_EXITED || si.si_status != 127) return pid ; /* child died after execve(), let caller handle it */ + /* + child exited 127, so either execve() failed, which is what we want to catch, + or it raced like a mofo, execve()d and then exited 127 on its own, in which + case, tough luck, it never existed. + */ + wait_pid(pid, 0) ; + return (errno = 0, 0) ; +} + +#else + + /* avoid empty TUs */ + +extern int skalibs_child_spawn_workaround_dummy_ ; + +#endif diff --git a/src/sysdeps/tryposixspawnearlyreturn.c b/src/sysdeps/tryposixspawnearlyreturn.c @@ -0,0 +1,24 @@ +/* ISC license. */ + +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <spawn.h> + +int main (void) +{ + posix_spawnattr_t attr ; + int e ; + char tmp[40] = "./tryposixspawnearlyreturn child:XXXXXX" ; + char *argv[2] = { tmp, 0 } ; + char *env = 0 ; + int fd = mkstemp(tmp) ; + if (fd == -1) return 111 ; + e = posix_spawnattr_init(&attr) ; + if (e) return 111 ; + e = posix_spawnattr_setflags(&attr, 0) ; + if (e) return 111 ; + if (close(fd) == -1 || unlink(tmp) == -1) return 111 ; + e = posix_spawn(0, argv[0], 0, &attrp, argv, &env) ; + return e ? e == ENOENT ? 1 : 111 : 0 ; +}