10 #include "pthread_impl.h"
17 const posix_spawn_file_actions_t
*fa
;
18 const posix_spawnattr_t
*restrict attr
;
19 char *const *argv
, *const *envp
;
22 static int __sys_dup2(int old
, int new)
25 return __syscall(SYS_dup2
, old
, new);
27 return __syscall(SYS_dup3
, old
, new, 0);
31 static int child(void *args_vp
)
34 struct sigaction sa
= {0};
35 struct args
*args
= args_vp
;
37 const posix_spawn_file_actions_t
*fa
= args
->fa
;
38 const posix_spawnattr_t
*restrict attr
= args
->attr
;
43 /* All signal dispositions must be either SIG_DFL or SIG_IGN
44 * before signals are unblocked. Otherwise a signal handler
45 * from the parent might get run in the child while sharing
46 * memory, with unpredictable and dangerous results. To
47 * reduce overhead, sigaction has tracked for us which signals
48 * potentially have a signal handler. */
49 __get_handler_set(&hset
);
50 for (i
=1; i
<_NSIG
; i
++) {
51 if ((attr
->__flags
& POSIX_SPAWN_SETSIGDEF
)
52 && sigismember(&attr
->__def
, i
)) {
53 sa
.sa_handler
= SIG_DFL
;
54 } else if (sigismember(&hset
, i
)) {
56 sa
.sa_handler
= SIG_IGN
;
58 __libc_sigaction(i
, 0, &sa
);
59 if (sa
.sa_handler
==SIG_IGN
) continue;
60 sa
.sa_handler
= SIG_DFL
;
65 __libc_sigaction(i
, &sa
, 0);
68 if (attr
->__flags
& POSIX_SPAWN_SETSID
)
69 if ((ret
=__syscall(SYS_setsid
)) < 0)
72 if (attr
->__flags
& POSIX_SPAWN_SETPGROUP
)
73 if ((ret
=__syscall(SYS_setpgid
, 0, attr
->__pgrp
)))
76 /* Use syscalls directly because the library functions attempt
77 * to do a multi-threaded synchronized id-change, which would
78 * trash the parent's state. */
79 if (attr
->__flags
& POSIX_SPAWN_RESETIDS
)
80 if ((ret
=__syscall(SYS_setgid
, __syscall(SYS_getgid
))) ||
81 (ret
=__syscall(SYS_setuid
, __syscall(SYS_getuid
))) )
84 if (fa
&& fa
->__actions
) {
87 for (op
= fa
->__actions
; op
->next
; op
= op
->next
);
88 for (; op
; op
= op
->prev
) {
89 /* It's possible that a file operation would clobber
90 * the pipe fd used for synchronizing with the
91 * parent. To avoid that, we dup the pipe onto
92 * an unoccupied fd. */
94 ret
= __syscall(SYS_dup
, p
);
95 if (ret
< 0) goto fail
;
96 __syscall(SYS_close
, p
);
101 __syscall(SYS_close
, op
->fd
);
110 if ((ret
=__sys_dup2(fd
, op
->fd
))<0)
113 ret
= __syscall(SYS_fcntl
, fd
, F_GETFD
);
114 ret
= __syscall(SYS_fcntl
, fd
, F_SETFD
,
121 fd
= __sys_open(op
->path
, op
->oflag
, op
->mode
);
122 if ((ret
=fd
) < 0) goto fail
;
124 if ((ret
=__sys_dup2(fd
, op
->fd
))<0)
126 __syscall(SYS_close
, fd
);
130 ret
= __syscall(SYS_chdir
, op
->path
);
131 if (ret
<0) goto fail
;
134 ret
= __syscall(SYS_fchdir
, op
->fd
);
135 if (ret
<0) goto fail
;
141 /* Close-on-exec flag may have been lost if we moved the pipe
142 * to a different fd. We don't use F_DUPFD_CLOEXEC above because
143 * it would fail on older kernels and atomicity is not needed --
144 * in this process there are no threads or signal handlers. */
145 __syscall(SYS_fcntl
, p
, F_SETFD
, FD_CLOEXEC
);
147 pthread_sigmask(SIG_SETMASK
, (attr
->__flags
& POSIX_SPAWN_SETSIGMASK
)
148 ? &attr
->__mask
: &args
->oldmask
, 0);
150 int (*exec
)(const char *, char *const *, char *const *) =
151 attr
->__fn
? (int (*)())attr
->__fn
: execve
;
153 exec(args
->path
, args
->argv
, args
->envp
);
157 /* Since sizeof errno < PIPE_BUF, the write is atomic. */
159 if (ret
) while (__syscall(SYS_write
, p
, &ret
, sizeof ret
) < 0);
164 int posix_spawn(pid_t
*restrict res
, const char *restrict path
,
165 const posix_spawn_file_actions_t
*fa
,
166 const posix_spawnattr_t
*restrict attr
,
167 char *const argv
[restrict
], char *const envp
[restrict
])
170 char stack
[1024+PATH_MAX
];
174 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, &cs
);
178 args
.attr
= attr
? attr
: &(const posix_spawnattr_t
){0};
181 pthread_sigmask(SIG_BLOCK
, SIGALL_SET
, &args
.oldmask
);
183 /* The lock guards both against seeing a SIGABRT disposition change
184 * by abort and against leaking the pipe fd to fork-without-exec. */
187 if (pipe2(args
.p
, O_CLOEXEC
)) {
188 UNLOCK(__abort_lock
);
193 pid
= __clone(child
, stack
+sizeof stack
,
194 CLONE_VM
|CLONE_VFORK
|SIGCHLD
, &args
);
196 UNLOCK(__abort_lock
);
199 if (read(args
.p
[0], &ec
, sizeof ec
) != sizeof ec
) ec
= 0;
200 else waitpid(pid
, &(int){0}, 0);
207 if (!ec
&& res
) *res
= pid
;
210 pthread_sigmask(SIG_SETMASK
, &args
.oldmask
, 0);
211 pthread_setcancelstate(cs
, 0);