1/// Very limited implementation. Half of code from Musl was cut.
2/// This is Ok, because for now, this function is used only from clang driver.
3
4#define _GNU_SOURCE
5#include <spawn.h>
6#include <sched.h>
7#include <unistd.h>
8#include <signal.h>
9#include <fcntl.h>
10#include <sys/wait.h>
11#include <syscall.h>
12#include <sys/signal.h>
13#include <pthread.h>
14#include <spawn.h>
15#include <errno.h>
16#include "syscall.h"
17
18struct args {
19 int p[2];
20 sigset_t oldmask;
21 const char *path;
22 int (*exec)(const char *, char *const *, char *const *);
23 const posix_spawn_file_actions_t *fa;
24 const posix_spawnattr_t *restrict attr;
25 char *const *argv, *const *envp;
26};
27
28void __get_handler_set(sigset_t *);
29
30static int child(void *args_vp)
31{
32 int ret;
33 struct args *args = args_vp;
34 int p = args->p[1];
35 const posix_spawnattr_t *restrict attr = args->attr;
36
37 close(args->p[0]);
38
39 /* Close-on-exec flag may have been lost if we moved the pipe
40 * to a different fd. We don't use F_DUPFD_CLOEXEC above because
41 * it would fail on older kernels and atomicity is not needed --
42 * in this process there are no threads or signal handlers. */
43 __syscall(SYS_fcntl, p, F_SETFD, FD_CLOEXEC);
44
45 pthread_sigmask(SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK)
46 ? &attr->__ss : &args->oldmask, 0);
47
48 args->exec(args->path, args->argv, args->envp);
49 ret = -errno;
50
51 /* Since sizeof errno < PIPE_BUF, the write is atomic. */
52 ret = -ret;
53 if (ret) while (__syscall(SYS_write, p, &ret, sizeof ret) < 0);
54 _exit(127);
55}
56
57
58int __posix_spawnx(pid_t *restrict res, const char *restrict path,
59 int (*exec)(const char *, char *const *, char *const *),
60 const posix_spawn_file_actions_t *fa,
61 const posix_spawnattr_t *restrict attr,
62 char *const argv[restrict], char *const envp[restrict])
63{
64 pid_t pid;
65 char stack[1024];
66 int ec=0, cs;
67 struct args args;
68
69 if (pipe2(args.p, O_CLOEXEC))
70 return errno;
71
72 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
73
74 args.path = path;
75 args.exec = exec;
76 args.fa = fa;
77 args.attr = attr ? attr : &(const posix_spawnattr_t){0};
78 args.argv = argv;
79 args.envp = envp;
80
81 pid = clone(child, stack+sizeof stack,
82 CLONE_VM|CLONE_VFORK|SIGCHLD, &args);
83 close(args.p[1]);
84
85 if (pid > 0) {
86 if (read(args.p[0], &ec, sizeof ec) != sizeof ec) ec = 0;
87 else waitpid(pid, &(int){0}, 0);
88 } else {
89 ec = -pid;
90 }
91
92 close(args.p[0]);
93
94 if (!ec && res) *res = pid;
95
96 pthread_setcancelstate(cs, 0);
97
98 return ec;
99}
100
101int posix_spawn(pid_t *restrict res, const char *restrict path,
102 const posix_spawn_file_actions_t *fa,
103 const posix_spawnattr_t *restrict attr,
104 char *const argv[restrict], char *const envp[restrict])
105{
106 return __posix_spawnx(res, path, execve, fa, attr, argv, envp);
107}
108