X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;ds=sidebyside;f=src%2Fprocess%2Fposix_spawn.c;h=728551b367926610c2fda6824a13d215c76dbecf;hb=90ff016996753d83263445940710c87d9afa71f3;hp=0849c71fb504b0dbf85373f93d05ebc1ae1f5a39;hpb=004dc9549b8003288e635ba5aa91e3353e1974c4;p=musl diff --git a/src/process/posix_spawn.c b/src/process/posix_spawn.c index 0849c71f..728551b3 100644 --- a/src/process/posix_spawn.c +++ b/src/process/posix_spawn.c @@ -6,33 +6,25 @@ #include #include #include "syscall.h" +#include "lock.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; }; -void __get_handler_set(sigset_t *); - static int __sys_dup2(int old, int new) { #ifdef SYS_dup2 return __syscall(SYS_dup2, old, new); #else - if (old==new) { - int r = __syscall(SYS_fcntl, old, F_GETFD); - return r<0 ? r : old; - } else { - return __syscall(SYS_dup3, old, new, 0); - } + return __syscall(SYS_dup3, old, new, 0); #endif } @@ -109,8 +101,21 @@ static int child(void *args_vp) __syscall(SYS_close, op->fd); break; case FDOP_DUP2: - if ((ret=__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 = __sys_open(op->path, op->oflag, op->mode); @@ -121,6 +126,14 @@ static int child(void *args_vp) __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; } } } @@ -134,7 +147,10 @@ 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: @@ -145,8 +161,7 @@ fail: } -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]) @@ -156,22 +171,29 @@ int __posix_spawnx(pid_t *restrict res, const char *restrict path, int ec=0, cs; struct args args; - if (pipe2(args.p, O_CLOEXEC)) - return errno; - 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; args.envp = envp; pthread_sigmask(SIG_BLOCK, SIGALL_SET, &args.oldmask); + /* The lock guards both against seeing a SIGABRT disposition change + * by abort and against leaking the pipe fd to fork-without-exec. */ + LOCK(__abort_lock); + + if (pipe2(args.p, O_CLOEXEC)) { + UNLOCK(__abort_lock); + ec = errno; + goto fail; + } + pid = __clone(child, stack+sizeof stack, CLONE_VM|CLONE_VFORK|SIGCHLD, &args); close(args.p[1]); + UNLOCK(__abort_lock); if (pid > 0) { if (read(args.p[0], &ec, sizeof ec) != sizeof ec) ec = 0; @@ -184,16 +206,9 @@ int __posix_spawnx(pid_t *restrict res, const char *restrict path, if (!ec && res) *res = pid; +fail: 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); -}