1 /* ISC license. */
2
3 /* MT-unsafe */
4
5 #include <skalibs/sysdeps.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 #include <sys/wait.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include <signal.h>
12
13 #ifdef SKALIBS_HASPOSIXSPAWN
14
15 #include <stdlib.h>
16 #include <spawn.h>
17 #include <skalibs/config.h>
18
19 #else
20
21 #include <string.h>
22 #include <skalibs/allreadwrite.h>
23 #include <skalibs/sig.h>
24 #include <skalibs/strerr2.h>
25 #include <skalibs/exec.h>
26
27 #endif
28
29 #include <skalibs/djbunix.h>
30
child_spawn2(char const * prog,char const * const * argv,char const * const * envp,int * fds)31 pid_t child_spawn2 (char const *prog, char const *const *argv, char const *const *envp, int *fds)
32 {
33 pid_t pid ;
34 #ifdef SKALIBS_HASPOSIXSPAWN
35 posix_spawn_file_actions_t actions ;
36 posix_spawnattr_t attr ;
37 int e ;
38 #else
39 int syncpipe[2] ;
40 #endif
41 int p[2][2] ;
42 if (pipe(p[0]) < 0) return 0 ;
43 if (ndelay_on(p[0][0]) < 0 || coe(p[0][0]) < 0 || pipe(p[1]) < 0) goto errp ;
44 if (ndelay_on(p[1][1]) < 0 || coe(p[1][1]) < 0) goto errp1 ;
45
46 #ifdef SKALIBS_HASPOSIXSPAWN
47
48 e = posix_spawnattr_init(&attr) ;
49 if (e) goto erre ;
50 {
51 sigset_t set ;
52 sigemptyset(&set) ;
53 e = posix_spawnattr_setsigmask(&attr, &set) ;
54 if (e) goto errattr ;
55 e = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK) ;
56 if (e) goto errattr ;
57 }
58 e = posix_spawn_file_actions_init(&actions) ;
59 if (e) goto errattr ;
60 if (p[1][0] != fds[0])
61 {
62 e = posix_spawn_file_actions_adddup2(&actions, p[1][0], fds[0]) ;
63 if (e) goto erractions ;
64 e = posix_spawn_file_actions_addclose(&actions, p[1][0]) ;
65 if (e) goto erractions ;
66 }
67 if (p[0][1] != fds[1])
68 {
69 e = posix_spawn_file_actions_adddup2(&actions, p[0][1], fds[1]) ;
70 if (e) goto erractions ;
71 e = posix_spawn_file_actions_addclose(&actions, p[0][1]) ;
72 if (e) goto erractions ;
73 }
74 {
75 int nopath = !getenv("PATH") ;
76 if (nopath && (setenv("PATH", SKALIBS_DEFAULTPATH, 0) < 0))
77 {
78 e = errno ; goto erractions ;
79 }
80 e = posix_spawnp(&pid, prog, &actions, &attr, (char *const *)argv, (char *const *)envp) ;
81 if (nopath) unsetenv("PATH") ;
82 if (e) goto erractions ;
83 }
84
85 posix_spawn_file_actions_destroy(&actions) ;
86 posix_spawnattr_destroy(&attr) ;
87
88 #else
89 if (pipecoe(syncpipe) < 0) goto errp1 ;
90
91 pid = fork() ;
92 if (pid < 0) goto errsp ;
93 else if (!pid)
94 {
95 size_t len = strlen(PROG) ;
96 char name[len + 9] ;
97 memcpy(name, PROG, len) ;
98 memcpy(name + len, " (child)", 9) ;
99 PROG = name ;
100 if (fd_move2(fds[0], p[1][0], fds[1], p[0][1]) < 0) goto syncdie ;
101 sig_blocknone() ;
102 exec_ae(prog, argv, envp) ;
103
104 syncdie:
105 {
106 char c = errno ;
107 fd_write(syncpipe[1], &c, 1) ;
108 }
109 _exit(127) ;
110 }
111
112 fd_close(syncpipe[1]) ;
113 {
114 char c ;
115 syncpipe[1] = fd_read(syncpipe[0], &c, 1) ;
116 if (syncpipe[1])
117 {
118 int e = c ;
119 if (syncpipe[1] < 0) e = errno ;
120 if (wait_pid(pid, &syncpipe[1]) < 0) e = errno ;
121 errno = e ;
122 goto errsp0 ;
123 }
124 }
125 fd_close(syncpipe[0]) ;
126 #endif
127
128 fd_close(p[0][1]) ; fds[0] = p[0][0] ;
129 fd_close(p[1][0]) ; fds[1] = p[1][1] ;
130 return pid ;
131
132 #ifdef SKALIBS_HASPOSIXSPAWN
133 erractions:
134 posix_spawn_file_actions_destroy(&actions) ;
135 errattr:
136 posix_spawnattr_destroy(&attr) ;
137 erre:
138 errno = e ;
139 #endif
140 #ifndef SKALIBS_HASPOSIXSPAWN
141 errsp:
142 fd_close(syncpipe[1]) ;
143 errsp0:
144 fd_close(syncpipe[0]) ;
145 #endif
146 errp1:
147 fd_close(p[1][1]) ;
148 fd_close(p[1][0]) ;
149 errp:
150 fd_close(p[0][1]) ;
151 fd_close(p[0][0]) ;
152 return 0 ;
153 }
154