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