11 #include "pthread_impl.h"
18 const posix_spawn_file_actions_t
*fa
;
19 const posix_spawnattr_t
*restrict attr
;
20 char *const *argv
, *const *envp
;
23 static int __sys_dup2(int old
, int new)
26 return __syscall(SYS_dup2
, old
, new);
28 return __syscall(SYS_dup3
, old
, new, 0);
32 static int child(void *args_vp
)
35 struct sigaction sa
= {0};
36 struct args
*args
= args_vp
;
38 const posix_spawn_file_actions_t
*fa
= args
->fa
;
39 const posix_spawnattr_t
*restrict attr
= args
->attr
;
44 /* All signal dispositions must be either SIG_DFL or SIG_IGN
45 * before signals are unblocked. Otherwise a signal handler
46 * from the parent might get run in the child while sharing
47 * memory, with unpredictable and dangerous results. To
48 * reduce overhead, sigaction has tracked for us which signals
49 * potentially have a signal handler. */
50 __get_handler_set(&hset
);
51 for (i
=1; i
<_NSIG
; i
++) {
52 if ((attr
->__flags
& POSIX_SPAWN_SETSIGDEF
)
53 && sigismember(&attr
->__def
, i
)) {
54 sa
.sa_handler
= SIG_DFL
;
55 } else if (sigismember(&hset
, i
)) {
57 sa
.sa_handler
= SIG_IGN
;
59 __libc_sigaction(i
, 0, &sa
);
60 if (sa
.sa_handler
==SIG_IGN
) continue;
61 sa
.sa_handler
= SIG_DFL
;
66 __libc_sigaction(i
, &sa
, 0);
69 if (attr
->__flags
& POSIX_SPAWN_SETSID
)
70 if ((ret
=__syscall(SYS_setsid
)) < 0)
73 if (attr
->__flags
& POSIX_SPAWN_SETPGROUP
)
74 if ((ret
=__syscall(SYS_setpgid
, 0, attr
->__pgrp
)))
77 /* Use syscalls directly because the library functions attempt
78 * to do a multi-threaded synchronized id-change, which would
79 * trash the parent's state. */
80 if (attr
->__flags
& POSIX_SPAWN_RESETIDS
)
81 if ((ret
=__syscall(SYS_setgid
, __syscall(SYS_getgid
))) ||
82 (ret
=__syscall(SYS_setuid
, __syscall(SYS_getuid
))) )
85 if (fa
&& fa
->__actions
) {
88 for (op
= fa
->__actions
; op
->next
; op
= op
->next
);
89 for (; op
; op
= op
->prev
) {
90 /* It's possible that a file operation would clobber
91 * the pipe fd used for synchronizing with the
92 * parent. To avoid that, we dup the pipe onto
93 * an unoccupied fd. */
95 ret
= __syscall(SYS_dup
, p
);
96 if (ret
< 0) goto fail
;
97 __syscall(SYS_close
, p
);
102 __syscall(SYS_close
, op
->fd
);
111 if ((ret
=__sys_dup2(fd
, op
->fd
))<0)
114 ret
= __syscall(SYS_fcntl
, fd
, F_GETFD
);
115 ret
= __syscall(SYS_fcntl
, fd
, F_SETFD
,
122 fd
= __sys_open(op
->path
, op
->oflag
, op
->mode
);
123 if ((ret
=fd
) < 0) goto fail
;
125 if ((ret
=__sys_dup2(fd
, op
->fd
))<0)
127 __syscall(SYS_close
, fd
);
131 ret
= __syscall(SYS_chdir
, op
->path
);
132 if (ret
<0) goto fail
;
135 ret
= __syscall(SYS_fchdir
, op
->fd
);
136 if (ret
<0) goto fail
;
142 /* Close-on-exec flag may have been lost if we moved the pipe
143 * to a different fd. We don't use F_DUPFD_CLOEXEC above because
144 * it would fail on older kernels and atomicity is not needed --
145 * in this process there are no threads or signal handlers. */
146 __syscall(SYS_fcntl
, p
, F_SETFD
, FD_CLOEXEC
);
148 pthread_sigmask(SIG_SETMASK
, (attr
->__flags
& POSIX_SPAWN_SETSIGMASK
)
149 ? &attr
->__mask
: &args
->oldmask
, 0);
151 int (*exec
)(const char *, char *const *, char *const *) =
152 attr
->__fn
? (int (*)())attr
->__fn
: execve
;
154 exec(args
->path
, args
->argv
, args
->envp
);
158 /* Since sizeof errno < PIPE_BUF, the write is atomic. */
162 do r
= __syscall(SYS_write
, p
, &ret
, sizeof ret
);
163 while (r
<0 && r
!=-EPIPE
);
169 int posix_spawn(pid_t
*restrict res
, const char *restrict path
,
170 const posix_spawn_file_actions_t
*fa
,
171 const posix_spawnattr_t
*restrict attr
,
172 char *const argv
[restrict
], char *const envp
[restrict
])
175 char stack
[1024+PATH_MAX
];
179 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, &cs
);
183 args
.attr
= attr
? attr
: &(const posix_spawnattr_t
){0};
186 pthread_sigmask(SIG_BLOCK
, SIGALL_SET
, &args
.oldmask
);
188 /* The lock guards both against seeing a SIGABRT disposition change
189 * by abort and against leaking the pipe fd to fork-without-exec. */
192 if (pipe2(args
.p
, O_CLOEXEC
)) {
193 UNLOCK(__abort_lock
);
198 pid
= __clone(child
, stack
+sizeof stack
,
199 CLONE_VM
|CLONE_VFORK
|SIGCHLD
, &args
);
201 UNLOCK(__abort_lock
);
204 if (read(args
.p
[0], &ec
, sizeof ec
) != sizeof ec
) ec
= 0;
205 else waitpid(pid
, &(int){0}, 0);
212 if (!ec
&& res
) *res
= pid
;
215 pthread_sigmask(SIG_SETMASK
, &args
.oldmask
, 0);
216 pthread_setcancelstate(cs
, 0);