X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fprocess%2Fposix_spawn.c;h=29652197c58cbff007a3251b89a699e69dbbb2f7;hb=1ef37aa00ea830dfda76e04e3d941cafa74d8b76;hp=68cf795c5b2c267ea1361a5f526129c7a9f3c389;hpb=b06dc6663989f8b3c141e439fe89036a44eb7552;p=musl diff --git a/src/process/posix_spawn.c b/src/process/posix_spawn.c index 68cf795c..29652197 100644 --- a/src/process/posix_spawn.c +++ b/src/process/posix_spawn.c @@ -8,50 +8,73 @@ #include "syscall.h" #include "pthread_impl.h" #include "fdop.h" -#include "libc.h" struct args { int p[2]; sigset_t oldmask; const char *path; - int (*exec)(const char *, char *const *, char *const *); const posix_spawn_file_actions_t *fa; const posix_spawnattr_t *restrict attr; char *const *argv, *const *envp; }; +static int __sys_dup2(int old, int new) +{ +#ifdef SYS_dup2 + return __syscall(SYS_dup2, old, new); +#else + return __syscall(SYS_dup3, old, new, 0); +#endif +} + static int child(void *args_vp) { int i, ret; - struct sigaction sa; + struct sigaction sa = {0}; struct args *args = args_vp; int p = args->p[1]; const posix_spawn_file_actions_t *fa = args->fa; const posix_spawnattr_t *restrict attr = args->attr; + sigset_t hset; close(args->p[0]); /* All signal dispositions must be either SIG_DFL or SIG_IGN * before signals are unblocked. Otherwise a signal handler * from the parent might get run in the child while sharing - * memory, with unpredictable and dangerous results. */ + * memory, with unpredictable and dangerous results. To + * reduce overhead, sigaction has tracked for us which signals + * potentially have a signal handler. */ + __get_handler_set(&hset); for (i=1; i<_NSIG; i++) { - __libc_sigaction(i, 0, &sa); - if (sa.sa_handler!=SIG_DFL && (sa.sa_handler!=SIG_IGN || - ((attr->__flags & POSIX_SPAWN_SETSIGDEF) - && sigismember(&attr->__def, i) ))) { + if ((attr->__flags & POSIX_SPAWN_SETSIGDEF) + && sigismember(&attr->__def, i)) { sa.sa_handler = SIG_DFL; - __libc_sigaction(i, &sa, 0); + } else if (sigismember(&hset, i)) { + if (i-32<3U) { + sa.sa_handler = SIG_IGN; + } else { + __libc_sigaction(i, 0, &sa); + if (sa.sa_handler==SIG_IGN) continue; + sa.sa_handler = SIG_DFL; + } + } else { + continue; } + __libc_sigaction(i, &sa, 0); } + if (attr->__flags & POSIX_SPAWN_SETSID) + if ((ret=__syscall(SYS_setsid)) < 0) + goto fail; + if (attr->__flags & POSIX_SPAWN_SETPGROUP) if ((ret=__syscall(SYS_setpgid, 0, attr->__pgrp))) goto fail; - /* Use syscalls directly because pthread state because the - * library functions attempt to do a multi-threaded synchronized - * id-change, which would trash the parent's state. */ + /* Use syscalls directly because the library functions attempt + * to do a multi-threaded synchronized id-change, which would + * trash the parent's state. */ if (attr->__flags & POSIX_SPAWN_RESETIDS) if ((ret=__syscall(SYS_setgid, __syscall(SYS_getgid))) || (ret=__syscall(SYS_setuid, __syscall(SYS_getuid))) ) @@ -74,23 +97,42 @@ static int child(void *args_vp) } switch(op->cmd) { case FDOP_CLOSE: - if ((ret=__syscall(SYS_close, op->fd))) - goto fail; + __syscall(SYS_close, op->fd); break; case FDOP_DUP2: - if ((ret=__syscall(SYS_dup2, op->srcfd, op->fd))<0) + fd = op->srcfd; + if (fd == p) { + ret = -EBADF; goto fail; + } + if (fd != op->fd) { + if ((ret=__sys_dup2(fd, op->fd))<0) + goto fail; + } else { + ret = __syscall(SYS_fcntl, fd, F_GETFD); + ret = __syscall(SYS_fcntl, fd, F_SETFD, + ret & ~FD_CLOEXEC); + if (ret<0) + goto fail; + } break; case FDOP_OPEN: - fd = __syscall(SYS_open, op->path, - op->oflag | O_LARGEFILE, op->mode); + fd = __sys_open(op->path, op->oflag, op->mode); if ((ret=fd) < 0) goto fail; if (fd != op->fd) { - if ((ret=__syscall(SYS_dup2, fd, op->fd))<0) + if ((ret=__sys_dup2(fd, op->fd))<0) goto fail; __syscall(SYS_close, fd); } break; + case FDOP_CHDIR: + ret = __syscall(SYS_chdir, op->path); + if (ret<0) goto fail; + break; + case FDOP_FCHDIR: + ret = __syscall(SYS_fchdir, op->fd); + if (ret<0) goto fail; + break; } } } @@ -104,24 +146,27 @@ static int child(void *args_vp) pthread_sigmask(SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK) ? &attr->__mask : &args->oldmask, 0); - args->exec(args->path, args->argv, args->envp); + int (*exec)(const char *, char *const *, char *const *) = + attr->__fn ? (int (*)())attr->__fn : execve; + + exec(args->path, args->argv, args->envp); + ret = -errno; fail: /* Since sizeof errno < PIPE_BUF, the write is atomic. */ ret = -ret; - if (ret) while (write(p, &ret, sizeof ret) < 0); + if (ret) while (__syscall(SYS_write, p, &ret, sizeof ret) < 0); _exit(127); } -int __posix_spawnx(pid_t *restrict res, const char *restrict path, - int (*exec)(const char *, char *const *, char *const *), +int posix_spawn(pid_t *restrict res, const char *restrict path, const posix_spawn_file_actions_t *fa, const posix_spawnattr_t *restrict attr, char *const argv[restrict], char *const envp[restrict]) { pid_t pid; - char stack[1024]; + char stack[1024+PATH_MAX]; int ec=0, cs; struct args args; @@ -131,7 +176,6 @@ int __posix_spawnx(pid_t *restrict res, const char *restrict path, pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); args.path = path; - args.exec = exec; args.fa = fa; args.attr = attr ? attr : &(const posix_spawnattr_t){0}; args.argv = argv; @@ -151,18 +195,10 @@ int __posix_spawnx(pid_t *restrict res, const char *restrict path, close(args.p[0]); - if (!ec) *res = pid; + if (!ec && res) *res = pid; pthread_sigmask(SIG_SETMASK, &args.oldmask, 0); pthread_setcancelstate(cs, 0); return ec; } - -int posix_spawn(pid_t *restrict res, const char *restrict path, - const posix_spawn_file_actions_t *fa, - const posix_spawnattr_t *restrict attr, - char *const argv[restrict], char *const envp[restrict]) -{ - return __posix_spawnx(res, path, execve, fa, attr, argv, envp); -}