overhaul system() and popen() to use vfork; fix various related bugs
[musl] / src / process / posix_spawn.c
1 #include <spawn.h>
2 #include <unistd.h>
3 #include <signal.h>
4 #include <stdint.h>
5 #include <fcntl.h>
6 #include "syscall.h"
7 #include "pthread_impl.h"
8 #include "fdop.h"
9 #include "libc.h"
10
11 extern char **environ;
12
13 static void dummy_0()
14 {
15 }
16 weak_alias(dummy_0, __acquire_ptc);
17 weak_alias(dummy_0, __release_ptc);
18
19 pid_t __vfork(void);
20
21 int __posix_spawnx(pid_t *restrict res, const char *restrict path,
22         int (*exec)(const char *, char *const *),
23         const posix_spawn_file_actions_t *fa,
24         const posix_spawnattr_t *restrict attr,
25         char *const argv[restrict], char *const envp[restrict])
26 {
27         pid_t pid;
28         sigset_t oldmask;
29         int i;
30         posix_spawnattr_t dummy_attr = { 0 };
31
32         if (!attr) attr = &dummy_attr;
33
34         sigprocmask(SIG_BLOCK, SIGALL_SET, &oldmask);
35
36         __acquire_ptc();
37         pid = __vfork();
38         __release_ptc();
39
40         if (pid) {
41                 sigprocmask(SIG_SETMASK, &oldmask, 0);
42                 if (pid < 0) return -pid;
43                 *res = pid;
44                 return 0;
45         }
46
47         for (i=1; i<=8*__SYSCALL_SSLEN; i++) {
48                 struct sigaction sa;
49                 __libc_sigaction(i, 0, &sa);
50                 if (sa.sa_handler!=SIG_DFL && (sa.sa_handler!=SIG_IGN ||
51                     ((attr->__flags & POSIX_SPAWN_SETSIGDEF)
52                      && sigismember(&attr->__def, i) ))) {
53                         sa.sa_handler = SIG_DFL;
54                         __libc_sigaction(i, &sa, 0);
55                 }
56         }
57
58         if ((attr->__flags&POSIX_SPAWN_SETPGROUP) && setpgid(0, attr->__pgrp))
59                 _exit(127);
60
61         /* Use syscalls directly because pthread state is not consistent
62          * for making calls to the library wrappers... */
63         if ((attr->__flags&POSIX_SPAWN_RESETIDS) && (
64                 __syscall(SYS_setgid, __syscall(SYS_getgid)) ||
65                 __syscall(SYS_setuid, __syscall(SYS_getuid)) ))
66                 _exit(127);
67
68         if (fa && fa->__actions) {
69                 struct fdop *op;
70                 int ret, fd;
71                 for (op = fa->__actions; op->next; op = op->next);
72                 for (; op; op = op->prev) {
73                         switch(op->cmd) {
74                         case FDOP_CLOSE:
75                                 ret = __syscall(SYS_close, op->fd);
76                                 break;
77                         case FDOP_DUP2:
78                                 ret = __syscall(SYS_dup2, op->fd, op->newfd)<0;
79                                 break;
80                         case FDOP_OPEN:
81                                 fd = __syscall(SYS_open, op->path,
82                                         op->oflag | O_LARGEFILE, op->mode);
83                                 if (fd == op->fd) {
84                                         ret = 0;
85                                 } else {
86                                         ret = __syscall(SYS_dup2, fd, op->fd)<0;
87                                         __syscall(SYS_close, fd);
88                                 }
89                                 break;
90                         }
91                         if (ret) _exit(127);
92                 }
93         }
94
95         sigprocmask(SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK)
96                 ? &attr->__mask : &oldmask, 0);
97
98         if (envp) environ = (char **)envp;
99         exec(path, argv);
100         _exit(127);
101
102         return 0;
103 }
104
105 int posix_spawn(pid_t *restrict res, const char *restrict path,
106         const posix_spawn_file_actions_t *fa,
107         const posix_spawnattr_t *restrict attr,
108         char *const argv[restrict], char *const envp[restrict])
109 {
110         return __posix_spawnx(res, path, execv, fa, attr, argv, envp);
111 }