9 #include "pthread_impl.h"
16 const posix_spawn_file_actions_t
*fa
;
17 const posix_spawnattr_t
*restrict attr
;
18 char *const *argv
, *const *envp
;
21 static int __sys_dup2(int old
, int new)
24 return __syscall(SYS_dup2
, old
, new);
26 return __syscall(SYS_dup3
, old
, new, 0);
30 static int child(void *args_vp
)
33 struct sigaction sa
= {0};
34 struct args
*args
= args_vp
;
36 const posix_spawn_file_actions_t
*fa
= args
->fa
;
37 const posix_spawnattr_t
*restrict attr
= args
->attr
;
42 /* All signal dispositions must be either SIG_DFL or SIG_IGN
43 * before signals are unblocked. Otherwise a signal handler
44 * from the parent might get run in the child while sharing
45 * memory, with unpredictable and dangerous results. To
46 * reduce overhead, sigaction has tracked for us which signals
47 * potentially have a signal handler. */
48 __get_handler_set(&hset
);
49 for (i
=1; i
<_NSIG
; i
++) {
50 if ((attr
->__flags
& POSIX_SPAWN_SETSIGDEF
)
51 && sigismember(&attr
->__def
, i
)) {
52 sa
.sa_handler
= SIG_DFL
;
53 } else if (sigismember(&hset
, i
)) {
55 sa
.sa_handler
= SIG_IGN
;
57 __libc_sigaction(i
, 0, &sa
);
58 if (sa
.sa_handler
==SIG_IGN
) continue;
59 sa
.sa_handler
= SIG_DFL
;
64 __libc_sigaction(i
, &sa
, 0);
67 if (attr
->__flags
& POSIX_SPAWN_SETSID
)
68 if ((ret
=__syscall(SYS_setsid
)) < 0)
71 if (attr
->__flags
& POSIX_SPAWN_SETPGROUP
)
72 if ((ret
=__syscall(SYS_setpgid
, 0, attr
->__pgrp
)))
75 /* Use syscalls directly because the library functions attempt
76 * to do a multi-threaded synchronized id-change, which would
77 * trash the parent's state. */
78 if (attr
->__flags
& POSIX_SPAWN_RESETIDS
)
79 if ((ret
=__syscall(SYS_setgid
, __syscall(SYS_getgid
))) ||
80 (ret
=__syscall(SYS_setuid
, __syscall(SYS_getuid
))) )
83 if (fa
&& fa
->__actions
) {
86 for (op
= fa
->__actions
; op
->next
; op
= op
->next
);
87 for (; op
; op
= op
->prev
) {
88 /* It's possible that a file operation would clobber
89 * the pipe fd used for synchronizing with the
90 * parent. To avoid that, we dup the pipe onto
91 * an unoccupied fd. */
93 ret
= __syscall(SYS_dup
, p
);
94 if (ret
< 0) goto fail
;
95 __syscall(SYS_close
, p
);
100 __syscall(SYS_close
, op
->fd
);
105 if ((ret
=__sys_dup2(fd
, op
->fd
))<0)
108 ret
= __syscall(SYS_fcntl
, fd
, F_GETFD
);
109 ret
= __syscall(SYS_fcntl
, fd
, F_SETFD
,
116 fd
= __sys_open(op
->path
, op
->oflag
, op
->mode
);
117 if ((ret
=fd
) < 0) goto fail
;
119 if ((ret
=__sys_dup2(fd
, op
->fd
))<0)
121 __syscall(SYS_close
, fd
);
128 /* Close-on-exec flag may have been lost if we moved the pipe
129 * to a different fd. We don't use F_DUPFD_CLOEXEC above because
130 * it would fail on older kernels and atomicity is not needed --
131 * in this process there are no threads or signal handlers. */
132 __syscall(SYS_fcntl
, p
, F_SETFD
, FD_CLOEXEC
);
134 pthread_sigmask(SIG_SETMASK
, (attr
->__flags
& POSIX_SPAWN_SETSIGMASK
)
135 ? &attr
->__mask
: &args
->oldmask
, 0);
137 int (*exec
)(const char *, char *const *, char *const *) =
138 attr
->__fn
? (int (*)())attr
->__fn
: execve
;
140 exec(args
->path
, args
->argv
, args
->envp
);
144 /* Since sizeof errno < PIPE_BUF, the write is atomic. */
146 if (ret
) while (__syscall(SYS_write
, p
, &ret
, sizeof ret
) < 0);
151 int posix_spawn(pid_t
*restrict res
, const char *restrict path
,
152 const posix_spawn_file_actions_t
*fa
,
153 const posix_spawnattr_t
*restrict attr
,
154 char *const argv
[restrict
], char *const envp
[restrict
])
157 char stack
[1024+PATH_MAX
];
161 if (pipe2(args
.p
, O_CLOEXEC
))
164 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, &cs
);
168 args
.attr
= attr
? attr
: &(const posix_spawnattr_t
){0};
171 pthread_sigmask(SIG_BLOCK
, SIGALL_SET
, &args
.oldmask
);
173 pid
= __clone(child
, stack
+sizeof stack
,
174 CLONE_VM
|CLONE_VFORK
|SIGCHLD
, &args
);
178 if (read(args
.p
[0], &ec
, sizeof ec
) != sizeof ec
) ec
= 0;
179 else waitpid(pid
, &(int){0}, 0);
186 if (!ec
&& res
) *res
= pid
;
188 pthread_sigmask(SIG_SETMASK
, &args
.oldmask
, 0);
189 pthread_setcancelstate(cs
, 0);