1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1985-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> *
18da2e3ebdSchin * David Korn <dgk@research.att.com> *
19da2e3ebdSchin * Phong Vo <kpv@research.att.com> *
20da2e3ebdSchin * *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin /*
24da2e3ebdSchin * Glenn Fowler
25da2e3ebdSchin * AT&T Research
26da2e3ebdSchin *
27da2e3ebdSchin * common process execution support with
28da2e3ebdSchin * proper sfio, signal and wait() syncronization
29da2e3ebdSchin *
30da2e3ebdSchin * _ contains the process path name and is
31da2e3ebdSchin * placed at the top of the environment
32da2e3ebdSchin */
33da2e3ebdSchin
34da2e3ebdSchin #include "proclib.h"
35da2e3ebdSchin
36da2e3ebdSchin #include <ls.h>
37da2e3ebdSchin
38da2e3ebdSchin /*
39da2e3ebdSchin * not quite ready for _use_spawnveg
40da2e3ebdSchin */
41da2e3ebdSchin
42da2e3ebdSchin #if _use_spawnveg && _lib_fork
43da2e3ebdSchin #undef _use_spawnveg
44da2e3ebdSchin #endif
45da2e3ebdSchin
46da2e3ebdSchin #ifndef DEBUG_PROC
47da2e3ebdSchin #define DEBUG_PROC 1
48da2e3ebdSchin #endif
49da2e3ebdSchin
50da2e3ebdSchin #if _lib_socketpair
51da2e3ebdSchin #if _sys_socket
52da2e3ebdSchin #include <sys/types.h>
53da2e3ebdSchin #include <sys/socket.h>
54da2e3ebdSchin #else
55da2e3ebdSchin #undef _lib_socketpair
56da2e3ebdSchin #endif
57da2e3ebdSchin #endif
58da2e3ebdSchin
59da2e3ebdSchin Proc_t proc_default = { -1 };
60da2e3ebdSchin
61da2e3ebdSchin #if DEBUG_PROC
62da2e3ebdSchin
63da2e3ebdSchin #include <namval.h>
64da2e3ebdSchin
65da2e3ebdSchin #define PROC_ENV_OPTIONS "PROC_OPTIONS"
66da2e3ebdSchin
67da2e3ebdSchin #define PROC_OPT_ENVIRONMENT (1<<0)
68da2e3ebdSchin #define PROC_OPT_EXEC (1<<1)
69da2e3ebdSchin #define PROC_OPT_TRACE (1<<2)
70da2e3ebdSchin #define PROC_OPT_VERBOSE (1<<3)
71da2e3ebdSchin
72da2e3ebdSchin static const Namval_t options[] =
73da2e3ebdSchin {
74da2e3ebdSchin "debug", PROC_OPT_VERBOSE,
75da2e3ebdSchin "environment", PROC_OPT_ENVIRONMENT,
76da2e3ebdSchin "exec", PROC_OPT_EXEC,
77da2e3ebdSchin "trace", PROC_OPT_TRACE,
78da2e3ebdSchin "verbose", PROC_OPT_VERBOSE,
79da2e3ebdSchin 0, 0
80da2e3ebdSchin };
81da2e3ebdSchin
82da2e3ebdSchin /*
83da2e3ebdSchin * called by stropt() to set options
84da2e3ebdSchin */
85da2e3ebdSchin
86da2e3ebdSchin static int
setopt(register void * a,register const void * p,register int n,const char * v)87da2e3ebdSchin setopt(register void* a, register const void* p, register int n, const char* v)
88da2e3ebdSchin {
89da2e3ebdSchin NoP(v);
90da2e3ebdSchin if (p)
91da2e3ebdSchin {
92da2e3ebdSchin if (n)
93da2e3ebdSchin *((int*)a) |= ((Namval_t*)p)->value;
94da2e3ebdSchin else
95da2e3ebdSchin *((int*)a) &= ~((Namval_t*)p)->value;
96da2e3ebdSchin }
97da2e3ebdSchin return 0;
98da2e3ebdSchin }
99da2e3ebdSchin
100da2e3ebdSchin #endif
101da2e3ebdSchin
102da2e3ebdSchin #if _use_spawnveg
103da2e3ebdSchin
104da2e3ebdSchin typedef struct Fd_s
105da2e3ebdSchin {
106da2e3ebdSchin short fd;
107da2e3ebdSchin short flag;
108da2e3ebdSchin } Fd_t;
109da2e3ebdSchin
110da2e3ebdSchin typedef struct Mod_s
111da2e3ebdSchin {
112da2e3ebdSchin struct Mod_s* next;
113da2e3ebdSchin short op;
114da2e3ebdSchin short save;
115da2e3ebdSchin
116da2e3ebdSchin union
117da2e3ebdSchin {
118da2e3ebdSchin
119da2e3ebdSchin struct
120da2e3ebdSchin {
121da2e3ebdSchin Fd_t parent;
122da2e3ebdSchin Fd_t child;
123da2e3ebdSchin } fd;
124da2e3ebdSchin
125da2e3ebdSchin Handler_t handler;
126da2e3ebdSchin
127da2e3ebdSchin } arg;
128da2e3ebdSchin
129da2e3ebdSchin } Modify_t;
130da2e3ebdSchin
131da2e3ebdSchin #endif
132da2e3ebdSchin
133da2e3ebdSchin #ifdef SIGPIPE
134da2e3ebdSchin
135da2e3ebdSchin /*
136da2e3ebdSchin * catch but ignore sig
137da2e3ebdSchin * avoids SIG_IGN being passed to children
138da2e3ebdSchin */
139da2e3ebdSchin
140da2e3ebdSchin static void
ignoresig(int sig)141da2e3ebdSchin ignoresig(int sig)
142da2e3ebdSchin {
143da2e3ebdSchin signal(sig, ignoresig);
144da2e3ebdSchin }
145da2e3ebdSchin
146da2e3ebdSchin #endif
147da2e3ebdSchin
148da2e3ebdSchin /*
149da2e3ebdSchin * do modification op and save previous state for restore()
150da2e3ebdSchin */
151da2e3ebdSchin
152da2e3ebdSchin static int
modify(Proc_t * proc,int forked,int op,long arg1,long arg2)153da2e3ebdSchin modify(Proc_t* proc, int forked, int op, long arg1, long arg2)
154da2e3ebdSchin {
155da2e3ebdSchin #if _lib_fork
156da2e3ebdSchin if (forked)
157da2e3ebdSchin {
158da2e3ebdSchin switch (op)
159da2e3ebdSchin {
160da2e3ebdSchin case PROC_fd_dup:
161da2e3ebdSchin case PROC_fd_dup|PROC_FD_PARENT:
162da2e3ebdSchin case PROC_fd_dup|PROC_FD_CHILD:
163da2e3ebdSchin case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
164da2e3ebdSchin if (arg1 != arg2)
165da2e3ebdSchin {
166da2e3ebdSchin if (arg2 != PROC_ARG_NULL)
167da2e3ebdSchin {
168da2e3ebdSchin close(arg2);
169da2e3ebdSchin if (fcntl(arg1, F_DUPFD, arg2) != arg2)
170da2e3ebdSchin return -1;
171da2e3ebdSchin }
172da2e3ebdSchin if (op & PROC_FD_CHILD)
173da2e3ebdSchin close(arg1);
174da2e3ebdSchin }
175da2e3ebdSchin break;
176da2e3ebdSchin case PROC_sig_dfl:
177da2e3ebdSchin signal(arg1, SIG_DFL);
178da2e3ebdSchin break;
179da2e3ebdSchin case PROC_sig_ign:
180da2e3ebdSchin signal(arg1, SIG_IGN);
181da2e3ebdSchin break;
182da2e3ebdSchin case PROC_sys_pgrp:
183da2e3ebdSchin if (arg1 < 0)
184da2e3ebdSchin setsid();
185da2e3ebdSchin else if (arg1 > 0)
186da2e3ebdSchin {
187da2e3ebdSchin if (arg1 == 1)
188da2e3ebdSchin arg1 = 0;
189da2e3ebdSchin if (setpgid(0, arg1) < 0 && arg1 && errno == EPERM)
190da2e3ebdSchin setpgid(0, 0);
191da2e3ebdSchin }
192da2e3ebdSchin break;
193da2e3ebdSchin case PROC_sys_umask:
194da2e3ebdSchin umask(arg1);
195da2e3ebdSchin break;
196da2e3ebdSchin default:
197da2e3ebdSchin return -1;
198da2e3ebdSchin }
199da2e3ebdSchin }
200da2e3ebdSchin #if _use_spawnveg
201da2e3ebdSchin else
202da2e3ebdSchin #endif
203da2e3ebdSchin #else
204da2e3ebdSchin NoP(forked);
205da2e3ebdSchin #endif
206da2e3ebdSchin #if _use_spawnveg
207da2e3ebdSchin {
208da2e3ebdSchin register Modify_t* m;
209da2e3ebdSchin
210da2e3ebdSchin if (!(m = newof(NiL, Modify_t, 1, 0)))
211da2e3ebdSchin return -1;
212da2e3ebdSchin m->next = proc->mods;
213da2e3ebdSchin proc->mods = m;
214da2e3ebdSchin switch (m->op = op)
215da2e3ebdSchin {
216da2e3ebdSchin case PROC_fd_dup:
217da2e3ebdSchin case PROC_fd_dup|PROC_FD_PARENT:
218da2e3ebdSchin case PROC_fd_dup|PROC_FD_CHILD:
219da2e3ebdSchin case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
220da2e3ebdSchin m->arg.fd.parent.fd = (short)arg1;
221da2e3ebdSchin m->arg.fd.parent.flag = fcntl(arg1, F_GETFD, 0);
222da2e3ebdSchin if ((m->arg.fd.child.fd = (short)arg2) != arg1)
223da2e3ebdSchin {
224da2e3ebdSchin if (arg2 != PROC_ARG_NULL)
225da2e3ebdSchin {
226da2e3ebdSchin m->arg.fd.child.flag = fcntl(arg2, F_GETFD, 0);
227da2e3ebdSchin if ((m->save = fcntl(arg2, F_DUPFD, 3)) < 0)
228da2e3ebdSchin {
229da2e3ebdSchin m->op = 0;
230da2e3ebdSchin return -1;
231da2e3ebdSchin }
232da2e3ebdSchin fcntl(m->save, F_SETFD, FD_CLOEXEC);
233da2e3ebdSchin close(arg2);
234da2e3ebdSchin if (fcntl(arg1, F_DUPFD, arg2) != arg2)
235da2e3ebdSchin return -1;
236da2e3ebdSchin if (op & PROC_FD_CHILD)
237da2e3ebdSchin close(arg1);
238da2e3ebdSchin }
239da2e3ebdSchin else if (op & PROC_FD_CHILD)
240da2e3ebdSchin {
241da2e3ebdSchin if (m->arg.fd.parent.flag)
242da2e3ebdSchin break;
243da2e3ebdSchin fcntl(arg1, F_SETFD, FD_CLOEXEC);
244da2e3ebdSchin }
245da2e3ebdSchin else if (!m->arg.fd.parent.flag)
246da2e3ebdSchin break;
247da2e3ebdSchin else
248da2e3ebdSchin fcntl(arg1, F_SETFD, 0);
249da2e3ebdSchin return 0;
250da2e3ebdSchin }
251da2e3ebdSchin break;
252da2e3ebdSchin case PROC_sig_dfl:
253da2e3ebdSchin if ((m->arg.handler = signal(arg1, SIG_DFL)) == SIG_DFL)
254da2e3ebdSchin break;
255da2e3ebdSchin m->save = (short)arg1;
256da2e3ebdSchin return 0;
257da2e3ebdSchin case PROC_sig_ign:
258da2e3ebdSchin if ((m->arg.handler = signal(arg1, SIG_IGN)) == SIG_IGN)
259da2e3ebdSchin break;
260da2e3ebdSchin m->save = (short)arg1;
261da2e3ebdSchin return 0;
262da2e3ebdSchin case PROC_sys_pgrp:
263da2e3ebdSchin proc->pgrp = arg1;
264da2e3ebdSchin break;
265da2e3ebdSchin case PROC_sys_umask:
266da2e3ebdSchin if ((m->save = (short)umask(arg1)) == arg1)
267da2e3ebdSchin break;
268da2e3ebdSchin return 0;
269da2e3ebdSchin default:
270da2e3ebdSchin proc->mods = m->next;
271da2e3ebdSchin free(m);
272da2e3ebdSchin return -1;
273da2e3ebdSchin }
274da2e3ebdSchin proc->mods = m->next;
275da2e3ebdSchin free(m);
276da2e3ebdSchin }
277da2e3ebdSchin #else
278da2e3ebdSchin NoP(proc);
279da2e3ebdSchin #endif
280da2e3ebdSchin return 0;
281da2e3ebdSchin }
282da2e3ebdSchin
283da2e3ebdSchin #if _use_spawnveg
284da2e3ebdSchin
285da2e3ebdSchin /*
286da2e3ebdSchin * restore modifications
287da2e3ebdSchin */
288da2e3ebdSchin
289da2e3ebdSchin static void
restore(Proc_t * proc)290da2e3ebdSchin restore(Proc_t* proc)
291da2e3ebdSchin {
292da2e3ebdSchin register Modify_t* m;
293da2e3ebdSchin register Modify_t* p;
294da2e3ebdSchin int oerrno;
295da2e3ebdSchin
296da2e3ebdSchin NoP(proc);
297da2e3ebdSchin oerrno = errno;
298da2e3ebdSchin m = proc->mods;
299da2e3ebdSchin proc->mods = 0;
300da2e3ebdSchin while (m)
301da2e3ebdSchin {
302da2e3ebdSchin switch (m->op)
303da2e3ebdSchin {
304da2e3ebdSchin case PROC_fd_dup:
305da2e3ebdSchin case PROC_fd_dup|PROC_FD_PARENT:
306da2e3ebdSchin case PROC_fd_dup|PROC_FD_CHILD:
307da2e3ebdSchin case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
308da2e3ebdSchin if (m->op & PROC_FD_PARENT)
309da2e3ebdSchin close(m->arg.fd.parent.fd);
310da2e3ebdSchin if (m->arg.fd.child.fd != m->arg.fd.parent.fd && m->arg.fd.child.fd != PROC_ARG_NULL)
311da2e3ebdSchin {
312da2e3ebdSchin if (!(m->op & PROC_FD_PARENT))
313da2e3ebdSchin {
314da2e3ebdSchin if (m->op & PROC_FD_CHILD)
315da2e3ebdSchin {
316da2e3ebdSchin close(m->arg.fd.parent.fd);
317da2e3ebdSchin fcntl(m->arg.fd.child.fd, F_DUPFD, m->arg.fd.parent.fd);
318da2e3ebdSchin }
319da2e3ebdSchin fcntl(m->arg.fd.parent.fd, F_SETFD, m->arg.fd.parent.flag);
320da2e3ebdSchin }
321da2e3ebdSchin close(m->arg.fd.child.fd);
322da2e3ebdSchin fcntl(m->save, F_DUPFD, m->arg.fd.child.fd);
323da2e3ebdSchin close(m->save);
324da2e3ebdSchin if (m->arg.fd.child.flag)
325da2e3ebdSchin fcntl(m->arg.fd.child.fd, F_SETFD, FD_CLOEXEC);
326da2e3ebdSchin }
327da2e3ebdSchin else if ((m->op & (PROC_FD_PARENT|PROC_FD_CHILD)) == PROC_FD_CHILD)
328da2e3ebdSchin fcntl(m->arg.fd.parent.fd, F_SETFD, 0);
329da2e3ebdSchin break;
330da2e3ebdSchin case PROC_sig_dfl:
331da2e3ebdSchin case PROC_sig_ign:
332da2e3ebdSchin signal(m->save, m->arg.handler);
333da2e3ebdSchin break;
334da2e3ebdSchin case PROC_sys_umask:
335da2e3ebdSchin umask(m->save);
336da2e3ebdSchin break;
337da2e3ebdSchin }
338da2e3ebdSchin p = m;
339da2e3ebdSchin m = m->next;
340da2e3ebdSchin free(p);
341da2e3ebdSchin }
342da2e3ebdSchin errno = oerrno;
343da2e3ebdSchin }
344da2e3ebdSchin
345da2e3ebdSchin #else
346da2e3ebdSchin
347da2e3ebdSchin #define restore(p)
348da2e3ebdSchin
349da2e3ebdSchin #endif
350da2e3ebdSchin
351da2e3ebdSchin /*
352da2e3ebdSchin * fork and exec or spawn proc(argv) and return a Proc_t handle
353da2e3ebdSchin *
354da2e3ebdSchin * pipe not used when PROC_READ|PROC_WRITE omitted
355da2e3ebdSchin * argv==0 duplicates current process if possible
356da2e3ebdSchin * cmd==0 names the current shell
357da2e3ebdSchin * cmd=="" does error cleanup
358da2e3ebdSchin * envv is the child environment
359da2e3ebdSchin * modv is the child modification vector of PROC_*() ops
360da2e3ebdSchin */
361da2e3ebdSchin
362da2e3ebdSchin Proc_t*
procopen(const char * cmd,char ** argv,char ** envv,long * modv,int flags)3637c2fbfb3SApril Chin procopen(const char* cmd, char** argv, char** envv, long* modv, int flags)
364da2e3ebdSchin {
365da2e3ebdSchin register Proc_t* proc = 0;
366da2e3ebdSchin register int procfd;
367da2e3ebdSchin register char** p;
368da2e3ebdSchin char** v;
369da2e3ebdSchin int i;
370da2e3ebdSchin int forked = 0;
3717c2fbfb3SApril Chin int signalled = 0;
372da2e3ebdSchin long n;
373da2e3ebdSchin char path[PATH_MAX];
374da2e3ebdSchin char env[PATH_MAX + 2];
375da2e3ebdSchin int pio[2];
376da2e3ebdSchin #if !_pipe_rw && !_lib_socketpair
377da2e3ebdSchin int poi[2];
378da2e3ebdSchin #endif
379da2e3ebdSchin #if defined(SIGCHLD) && ( _lib_sigprocmask || _lib_sigsetmask )
380da2e3ebdSchin Sig_mask_t mask;
381da2e3ebdSchin #endif
382da2e3ebdSchin #if _use_spawnveg
383da2e3ebdSchin int newenv = 0;
384da2e3ebdSchin #endif
385da2e3ebdSchin #if DEBUG_PROC
386da2e3ebdSchin int debug = PROC_OPT_EXEC;
387da2e3ebdSchin #endif
388da2e3ebdSchin
389da2e3ebdSchin #if _lib_fork
390da2e3ebdSchin if (!argv && (flags & PROC_OVERLAY))
391da2e3ebdSchin #else
392da2e3ebdSchin if (!argv)
393da2e3ebdSchin #endif
394da2e3ebdSchin {
395da2e3ebdSchin errno = ENOEXEC;
396da2e3ebdSchin return 0;
397da2e3ebdSchin }
398da2e3ebdSchin pio[0] = pio[1] = -1;
399da2e3ebdSchin #if !_pipe_rw && !_lib_socketpair
400da2e3ebdSchin poi[0] = poi[1] = -1;
401da2e3ebdSchin #endif
402da2e3ebdSchin if (cmd && (!*cmd || !pathpath(path, cmd, NiL, PATH_REGULAR|PATH_EXECUTE)))
403da2e3ebdSchin goto bad;
404da2e3ebdSchin switch (flags & (PROC_READ|PROC_WRITE))
405da2e3ebdSchin {
406da2e3ebdSchin case 0:
407da2e3ebdSchin procfd = -1;
408da2e3ebdSchin break;
409da2e3ebdSchin case PROC_READ:
410da2e3ebdSchin procfd = 1;
411da2e3ebdSchin break;
412da2e3ebdSchin case PROC_WRITE:
413da2e3ebdSchin procfd = 0;
414da2e3ebdSchin break;
415da2e3ebdSchin case PROC_READ|PROC_WRITE:
416da2e3ebdSchin procfd = 2;
417da2e3ebdSchin break;
418da2e3ebdSchin }
419da2e3ebdSchin if (proc_default.pid == -1)
420da2e3ebdSchin proc = &proc_default;
421da2e3ebdSchin else if (!(proc = newof(0, Proc_t, 1, 0)))
422da2e3ebdSchin goto bad;
423da2e3ebdSchin proc->pid = -1;
424da2e3ebdSchin proc->pgrp = 0;
425da2e3ebdSchin proc->rfd = -1;
426da2e3ebdSchin proc->wfd = -1;
427da2e3ebdSchin proc->flags = flags;
428da2e3ebdSchin sfsync(NiL);
429da2e3ebdSchin if (environ && envv != (char**)environ && (envv || (flags & PROC_PARANOID) || argv && (environ[0][0] != '_' || environ[0][1] != '=')))
430da2e3ebdSchin {
431da2e3ebdSchin if (!setenviron(NiL))
432da2e3ebdSchin goto bad;
433da2e3ebdSchin #if _use_spawnveg
434da2e3ebdSchin newenv = 1;
435da2e3ebdSchin #endif
436da2e3ebdSchin }
437da2e3ebdSchin if (procfd >= 0)
438da2e3ebdSchin {
439da2e3ebdSchin #if _pipe_rw
440da2e3ebdSchin if (pipe(pio))
441da2e3ebdSchin goto bad;
442da2e3ebdSchin #else
443da2e3ebdSchin if (procfd > 1)
444da2e3ebdSchin {
445da2e3ebdSchin #if _lib_socketpair
446da2e3ebdSchin if (socketpair(AF_UNIX, SOCK_STREAM, 0, pio))
447da2e3ebdSchin goto bad;
448da2e3ebdSchin #else
449da2e3ebdSchin if (pipe(pio) || pipe(poi))
450da2e3ebdSchin goto bad;
451da2e3ebdSchin #endif
452da2e3ebdSchin }
453da2e3ebdSchin else if (pipe(pio))
454da2e3ebdSchin goto bad;
455da2e3ebdSchin #endif
456da2e3ebdSchin }
457da2e3ebdSchin if (flags & PROC_OVERLAY)
458da2e3ebdSchin {
459da2e3ebdSchin proc->pid = 0;
460da2e3ebdSchin forked = 1;
461da2e3ebdSchin }
462da2e3ebdSchin #if _use_spawnveg
463da2e3ebdSchin else if (argv)
464da2e3ebdSchin proc->pid = 0;
465da2e3ebdSchin #endif
466da2e3ebdSchin #if _lib_fork
467da2e3ebdSchin else
468da2e3ebdSchin {
469da2e3ebdSchin if (!(flags & PROC_FOREGROUND))
470da2e3ebdSchin sigcritical(SIG_REG_EXEC|SIG_REG_PROC);
471da2e3ebdSchin else
472da2e3ebdSchin {
4737c2fbfb3SApril Chin signalled = 1;
474da2e3ebdSchin proc->sigint = signal(SIGINT, SIG_IGN);
475da2e3ebdSchin proc->sigquit = signal(SIGQUIT, SIG_IGN);
476da2e3ebdSchin #if defined(SIGCHLD)
477da2e3ebdSchin #if _lib_sigprocmask
478da2e3ebdSchin sigemptyset(&mask);
479da2e3ebdSchin sigaddset(&mask, SIGCHLD);
480da2e3ebdSchin sigprocmask(SIG_BLOCK, &mask, &proc->mask);
481da2e3ebdSchin #else
482da2e3ebdSchin #if _lib_sigsetmask
483da2e3ebdSchin mask = sigmask(SIGCHLD);
484da2e3ebdSchin proc->mask = sigblock(mask);
4857c2fbfb3SApril Chin #else
4867c2fbfb3SApril Chin proc->sigchld = signal(SIGCHLD, SIG_DFL);
487da2e3ebdSchin #endif
488da2e3ebdSchin #endif
489da2e3ebdSchin #endif
490da2e3ebdSchin }
491da2e3ebdSchin proc->pid = fork();
492da2e3ebdSchin if (!(flags & PROC_FOREGROUND))
493da2e3ebdSchin sigcritical(0);
494da2e3ebdSchin else if (!proc->pid)
495da2e3ebdSchin {
496da2e3ebdSchin if (proc->sigint != SIG_IGN)
4977c2fbfb3SApril Chin {
498da2e3ebdSchin proc->sigint = SIG_DFL;
499da2e3ebdSchin signal(SIGINT, proc->sigint);
5007c2fbfb3SApril Chin }
501da2e3ebdSchin if (proc->sigquit != SIG_IGN)
5027c2fbfb3SApril Chin {
503da2e3ebdSchin proc->sigquit = SIG_DFL;
504da2e3ebdSchin signal(SIGQUIT, proc->sigquit);
5057c2fbfb3SApril Chin }
506da2e3ebdSchin #if defined(SIGCHLD)
5077c2fbfb3SApril Chin #if _lib_sigprocmask
5087c2fbfb3SApril Chin sigprocmask(SIG_SETMASK, &proc->mask, NiL);
5097c2fbfb3SApril Chin #else
5107c2fbfb3SApril Chin #if _lib_sigsetmask
5117c2fbfb3SApril Chin sigsetmask(proc->mask);
5127c2fbfb3SApril Chin #else
513da2e3ebdSchin if (proc->sigchld != SIG_IGN)
5147c2fbfb3SApril Chin signal(SIGCHLD, SIG_DFL);
5157c2fbfb3SApril Chin #endif
5167c2fbfb3SApril Chin #endif
517da2e3ebdSchin #endif
518da2e3ebdSchin }
5197c2fbfb3SApril Chin else if (proc->pid == -1)
520da2e3ebdSchin goto bad;
521da2e3ebdSchin forked = 1;
522da2e3ebdSchin }
523da2e3ebdSchin #endif
524da2e3ebdSchin if (!proc->pid)
525da2e3ebdSchin {
526da2e3ebdSchin #if _use_spawnveg
527da2e3ebdSchin char** oenviron = 0;
528da2e3ebdSchin char* oenviron0 = 0;
529da2e3ebdSchin
530da2e3ebdSchin v = 0;
531da2e3ebdSchin #endif
532da2e3ebdSchin #if DEBUG_PROC
533da2e3ebdSchin stropt(getenv(PROC_ENV_OPTIONS), options, sizeof(*options), setopt, &debug);
534da2e3ebdSchin #if _lib_fork
535da2e3ebdSchin if (debug & PROC_OPT_TRACE)
536da2e3ebdSchin {
537da2e3ebdSchin if (!fork())
538da2e3ebdSchin {
539da2e3ebdSchin sfsprintf(path, sizeof(path), "%d", getppid());
540da2e3ebdSchin execlp("trace", "trace", "-p", path, NiL);
541da2e3ebdSchin _exit(EXIT_NOTFOUND);
542da2e3ebdSchin }
543da2e3ebdSchin sleep(2);
544da2e3ebdSchin }
545da2e3ebdSchin #endif
546da2e3ebdSchin #endif
547da2e3ebdSchin if (flags & PROC_DAEMON)
548da2e3ebdSchin {
549da2e3ebdSchin #ifdef SIGHUP
550da2e3ebdSchin modify(proc, forked, PROC_sig_ign, SIGHUP, 0);
551da2e3ebdSchin #endif
552da2e3ebdSchin modify(proc, forked, PROC_sig_dfl, SIGTERM, 0);
553da2e3ebdSchin #ifdef SIGTSTP
554da2e3ebdSchin modify(proc, forked, PROC_sig_ign, SIGTSTP, 0);
555da2e3ebdSchin #endif
556da2e3ebdSchin #ifdef SIGTTIN
557da2e3ebdSchin modify(proc, forked, PROC_sig_ign, SIGTTIN, 0);
558da2e3ebdSchin #endif
559da2e3ebdSchin #ifdef SIGTTOU
560da2e3ebdSchin modify(proc, forked, PROC_sig_ign, SIGTTOU, 0);
561da2e3ebdSchin #endif
562da2e3ebdSchin }
563da2e3ebdSchin if (flags & (PROC_BACKGROUND|PROC_DAEMON))
564da2e3ebdSchin {
565da2e3ebdSchin modify(proc, forked, PROC_sig_ign, SIGINT, 0);
566da2e3ebdSchin #ifdef SIGQUIT
567da2e3ebdSchin modify(proc, forked, PROC_sig_ign, SIGQUIT, 0);
568da2e3ebdSchin #endif
569da2e3ebdSchin }
570da2e3ebdSchin if (flags & (PROC_DAEMON|PROC_SESSION))
571da2e3ebdSchin modify(proc, forked, PROC_sys_pgrp, -1, 0);
572da2e3ebdSchin if (forked || (flags & PROC_OVERLAY))
573da2e3ebdSchin {
574da2e3ebdSchin if ((flags & PROC_PRIVELEGED) && !geteuid())
575da2e3ebdSchin {
576da2e3ebdSchin setuid(geteuid());
577da2e3ebdSchin setgid(getegid());
578da2e3ebdSchin }
579da2e3ebdSchin if (flags & (PROC_PARANOID|PROC_GID))
580da2e3ebdSchin setgid(getgid());
581da2e3ebdSchin if (flags & (PROC_PARANOID|PROC_UID))
582da2e3ebdSchin setuid(getuid());
583da2e3ebdSchin }
584da2e3ebdSchin if (procfd > 1)
585da2e3ebdSchin {
586da2e3ebdSchin if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[0], PROC_ARG_NULL))
587da2e3ebdSchin goto cleanup;
588da2e3ebdSchin if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[1], 1))
589da2e3ebdSchin goto cleanup;
590da2e3ebdSchin #if _pipe_rw || _lib_socketpair
591da2e3ebdSchin if (modify(proc, forked, PROC_fd_dup, 1, 0))
592da2e3ebdSchin goto cleanup;
593da2e3ebdSchin #else
594da2e3ebdSchin if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[0], 0))
595da2e3ebdSchin goto cleanup;
596da2e3ebdSchin if (poi[1] != 0 && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[1], PROC_ARG_NULL))
597da2e3ebdSchin goto cleanup;
598da2e3ebdSchin #endif
599da2e3ebdSchin }
600da2e3ebdSchin else if (procfd >= 0)
601da2e3ebdSchin {
602da2e3ebdSchin if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!!procfd], !!procfd))
603da2e3ebdSchin goto cleanup;
604da2e3ebdSchin if (pio[!procfd] != !!procfd && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!procfd], PROC_ARG_NULL))
605da2e3ebdSchin goto cleanup;
606da2e3ebdSchin }
607da2e3ebdSchin if (modv)
608da2e3ebdSchin for (i = 0; n = modv[i]; i++)
609da2e3ebdSchin switch (PROC_OP(n))
610da2e3ebdSchin {
611da2e3ebdSchin case PROC_fd_dup:
612da2e3ebdSchin case PROC_fd_dup|PROC_FD_PARENT:
613da2e3ebdSchin case PROC_fd_dup|PROC_FD_CHILD:
614da2e3ebdSchin case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
615da2e3ebdSchin if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), PROC_ARG(n, 2)))
616da2e3ebdSchin goto cleanup;
617da2e3ebdSchin break;
618da2e3ebdSchin default:
619da2e3ebdSchin if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), 0))
620da2e3ebdSchin goto cleanup;
621da2e3ebdSchin break;
622da2e3ebdSchin }
623da2e3ebdSchin #if _lib_fork
624da2e3ebdSchin if (forked && (flags & PROC_ENVCLEAR))
625da2e3ebdSchin environ = 0;
626da2e3ebdSchin #if _use_spawnveg
627da2e3ebdSchin else
628da2e3ebdSchin #endif
629da2e3ebdSchin #endif
630da2e3ebdSchin #if _use_spawnveg
631da2e3ebdSchin if (newenv)
632da2e3ebdSchin {
633da2e3ebdSchin p = environ;
634da2e3ebdSchin while (*p++);
635da2e3ebdSchin if (!(oenviron = (char**)memdup(environ, (p - environ) * sizeof(char*))))
636da2e3ebdSchin goto cleanup;
637da2e3ebdSchin }
638da2e3ebdSchin #endif
639da2e3ebdSchin if (argv && envv != (char**)environ)
640da2e3ebdSchin {
641da2e3ebdSchin #if _use_spawnveg
642da2e3ebdSchin if (!newenv && environ[0][0] == '_' && environ[0][1] == '=')
643da2e3ebdSchin oenviron0 = environ[0];
644da2e3ebdSchin #endif
645da2e3ebdSchin env[0] = '_';
646da2e3ebdSchin env[1] = '=';
647da2e3ebdSchin env[2] = 0;
648da2e3ebdSchin if (!setenviron(env))
649da2e3ebdSchin goto cleanup;
650da2e3ebdSchin }
651da2e3ebdSchin if ((flags & PROC_PARANOID) && setenv("PATH", astconf("PATH", NiL, NiL), 1))
652da2e3ebdSchin goto cleanup;
653da2e3ebdSchin if ((p = envv) && p != (char**)environ)
654da2e3ebdSchin while (*p)
655da2e3ebdSchin if (!setenviron(*p++))
656da2e3ebdSchin goto cleanup;
657da2e3ebdSchin p = argv;
658da2e3ebdSchin #if _lib_fork
659da2e3ebdSchin if (forked && !p)
660da2e3ebdSchin return proc;
661da2e3ebdSchin #endif
662da2e3ebdSchin #if DEBUG_PROC
663da2e3ebdSchin if (!(debug & PROC_OPT_EXEC) || (debug & PROC_OPT_VERBOSE))
664da2e3ebdSchin {
665da2e3ebdSchin if ((debug & PROC_OPT_ENVIRONMENT) && (p = environ))
666da2e3ebdSchin while (*p)
667da2e3ebdSchin sfprintf(sfstderr, "%s\n", *p++);
668da2e3ebdSchin sfprintf(sfstderr, "+ %s", cmd ? path : "sh");
669da2e3ebdSchin if ((p = argv) && *p)
670da2e3ebdSchin while (*++p)
671da2e3ebdSchin sfprintf(sfstderr, " %s", *p);
672da2e3ebdSchin sfprintf(sfstderr, "\n");
673da2e3ebdSchin sfsync(sfstderr);
674da2e3ebdSchin if (!(debug & PROC_OPT_EXEC))
675da2e3ebdSchin _exit(0);
676da2e3ebdSchin p = argv;
677da2e3ebdSchin }
678da2e3ebdSchin #endif
679da2e3ebdSchin if (cmd)
680da2e3ebdSchin {
681da2e3ebdSchin strcpy(env + 2, path);
682da2e3ebdSchin if (forked || (flags & PROC_OVERLAY))
683da2e3ebdSchin execve(path, p, environ);
684da2e3ebdSchin #if _use_spawnveg
685da2e3ebdSchin else if ((proc->pid = spawnveg(path, p, environ, proc->pgrp)) != -1)
686da2e3ebdSchin goto cleanup;
687da2e3ebdSchin #endif
688da2e3ebdSchin if (errno != ENOEXEC)
689da2e3ebdSchin goto cleanup;
690da2e3ebdSchin
691da2e3ebdSchin /*
692da2e3ebdSchin * try cmd as a shell script
693da2e3ebdSchin */
694da2e3ebdSchin
695da2e3ebdSchin if (!(flags & PROC_ARGMOD))
696da2e3ebdSchin {
697da2e3ebdSchin while (*p++);
698da2e3ebdSchin if (!(v = newof(0, char*, p - argv + 2, 0)))
699da2e3ebdSchin goto cleanup;
700da2e3ebdSchin p = v + 2;
701da2e3ebdSchin if (*argv)
702da2e3ebdSchin argv++;
703da2e3ebdSchin while (*p++ = *argv++);
704da2e3ebdSchin p = v + 1;
705da2e3ebdSchin }
706da2e3ebdSchin *p = path;
707da2e3ebdSchin *--p = "sh";
708da2e3ebdSchin }
709da2e3ebdSchin strcpy(env + 2, (flags & PROC_PARANOID) ? astconf("SH", NiL, NiL) : pathshell());
710da2e3ebdSchin if (forked || (flags & PROC_OVERLAY))
711da2e3ebdSchin execve(env + 2, p, environ);
712da2e3ebdSchin #if _use_spawnveg
713da2e3ebdSchin else
714da2e3ebdSchin proc->pid = spawnveg(env + 2, p, environ, proc->pgrp);
715da2e3ebdSchin #endif
716da2e3ebdSchin cleanup:
717da2e3ebdSchin if (forked)
718da2e3ebdSchin {
719da2e3ebdSchin if (!(flags & PROC_OVERLAY))
720da2e3ebdSchin _exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC);
721da2e3ebdSchin goto bad;
722da2e3ebdSchin }
723da2e3ebdSchin #if _use_spawnveg
724da2e3ebdSchin if (v)
725da2e3ebdSchin free(v);
726da2e3ebdSchin if (p = oenviron)
727da2e3ebdSchin {
728da2e3ebdSchin environ = 0;
729da2e3ebdSchin while (*p)
730da2e3ebdSchin if (!setenviron(*p++))
731da2e3ebdSchin goto bad;
732da2e3ebdSchin free(oenviron);
733da2e3ebdSchin }
734da2e3ebdSchin else if (oenviron0)
735da2e3ebdSchin environ[0] = oenviron0;
736da2e3ebdSchin restore(proc);
737da2e3ebdSchin if (flags & PROC_OVERLAY)
738da2e3ebdSchin exit(0);
739da2e3ebdSchin #endif
740da2e3ebdSchin }
741da2e3ebdSchin if (proc->pid != -1)
742da2e3ebdSchin {
743da2e3ebdSchin if (!forked)
744da2e3ebdSchin {
745da2e3ebdSchin if (flags & PROC_FOREGROUND)
746da2e3ebdSchin {
7477c2fbfb3SApril Chin signalled = 1;
748da2e3ebdSchin proc->sigint = signal(SIGINT, SIG_IGN);
749da2e3ebdSchin proc->sigquit = signal(SIGQUIT, SIG_IGN);
750da2e3ebdSchin #if defined(SIGCHLD)
7517c2fbfb3SApril Chin #if _lib_sigprocmask
7527c2fbfb3SApril Chin sigemptyset(&mask);
7537c2fbfb3SApril Chin sigaddset(&mask, SIGCHLD);
7547c2fbfb3SApril Chin sigprocmask(SIG_BLOCK, &mask, &proc->mask);
7557c2fbfb3SApril Chin #else
7567c2fbfb3SApril Chin #if _lib_sigsetmask
7577c2fbfb3SApril Chin mask = sigmask(SIGCHLD);
7587c2fbfb3SApril Chin proc->mask = sigblock(mask);
7597c2fbfb3SApril Chin #else
760da2e3ebdSchin proc->sigchld = signal(SIGCHLD, SIG_DFL);
761da2e3ebdSchin #endif
7627c2fbfb3SApril Chin #endif
7637c2fbfb3SApril Chin #endif
764da2e3ebdSchin }
765da2e3ebdSchin }
766da2e3ebdSchin else if (modv)
767da2e3ebdSchin for (i = 0; n = modv[i]; i++)
768da2e3ebdSchin switch (PROC_OP(n))
769da2e3ebdSchin {
770da2e3ebdSchin case PROC_fd_dup|PROC_FD_PARENT:
771da2e3ebdSchin case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
772da2e3ebdSchin close(PROC_ARG(n, 1));
773da2e3ebdSchin break;
774da2e3ebdSchin case PROC_sys_pgrp:
775da2e3ebdSchin if (proc->pgrp < 0)
776da2e3ebdSchin proc->pgrp = proc->pid;
777da2e3ebdSchin else if (proc->pgrp > 0)
778da2e3ebdSchin {
779da2e3ebdSchin if (proc->pgrp == 1)
780da2e3ebdSchin proc->pgrp = proc->pid;
781da2e3ebdSchin if (setpgid(proc->pid, proc->pgrp) < 0 && proc->pid != proc->pgrp && errno == EPERM)
782da2e3ebdSchin setpgid(proc->pid, proc->pid);
783da2e3ebdSchin }
784da2e3ebdSchin break;
785da2e3ebdSchin }
786da2e3ebdSchin if (procfd >= 0)
787da2e3ebdSchin {
788da2e3ebdSchin #ifdef SIGPIPE
789da2e3ebdSchin if ((flags & (PROC_WRITE|PROC_IGNORE)) == (PROC_WRITE|PROC_IGNORE))
790da2e3ebdSchin {
791da2e3ebdSchin Handler_t handler;
792da2e3ebdSchin
793da2e3ebdSchin if ((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL && handler != ignoresig)
794da2e3ebdSchin signal(SIGPIPE, handler);
795da2e3ebdSchin }
796da2e3ebdSchin #endif
797da2e3ebdSchin switch (procfd)
798da2e3ebdSchin {
799da2e3ebdSchin case 0:
800da2e3ebdSchin proc->wfd = pio[1];
801da2e3ebdSchin close(pio[0]);
802da2e3ebdSchin break;
803da2e3ebdSchin default:
804da2e3ebdSchin #if _pipe_rw || _lib_socketpair
805da2e3ebdSchin proc->wfd = pio[0];
806da2e3ebdSchin #else
807da2e3ebdSchin proc->wfd = poi[1];
808da2e3ebdSchin close(poi[0]);
809da2e3ebdSchin #endif
810da2e3ebdSchin /*FALLTHROUGH*/
811da2e3ebdSchin case 1:
812da2e3ebdSchin proc->rfd = pio[0];
813da2e3ebdSchin close(pio[1]);
814da2e3ebdSchin break;
815da2e3ebdSchin }
816da2e3ebdSchin if (proc->rfd > 2)
817da2e3ebdSchin fcntl(proc->rfd, F_SETFD, FD_CLOEXEC);
818da2e3ebdSchin if (proc->wfd > 2)
819da2e3ebdSchin fcntl(proc->wfd, F_SETFD, FD_CLOEXEC);
820da2e3ebdSchin }
821da2e3ebdSchin if (!proc->pid)
822da2e3ebdSchin proc->pid = getpid();
823da2e3ebdSchin return proc;
824da2e3ebdSchin }
825da2e3ebdSchin bad:
8267c2fbfb3SApril Chin if (signalled)
8277c2fbfb3SApril Chin {
8287c2fbfb3SApril Chin if (proc->sigint != SIG_IGN)
8297c2fbfb3SApril Chin signal(SIGINT, proc->sigint);
8307c2fbfb3SApril Chin if (proc->sigquit != SIG_IGN)
8317c2fbfb3SApril Chin signal(SIGQUIT, proc->sigquit);
8327c2fbfb3SApril Chin #if defined(SIGCHLD)
8337c2fbfb3SApril Chin #if _lib_sigprocmask
8347c2fbfb3SApril Chin sigprocmask(SIG_SETMASK, &proc->mask, NiL);
8357c2fbfb3SApril Chin #else
8367c2fbfb3SApril Chin #if _lib_sigsetmask
8377c2fbfb3SApril Chin sigsetmask(proc->mask);
8387c2fbfb3SApril Chin #else
8397c2fbfb3SApril Chin if (proc->sigchld != SIG_DFL)
8407c2fbfb3SApril Chin signal(SIGCHLD, proc->sigchld);
8417c2fbfb3SApril Chin #endif
8427c2fbfb3SApril Chin #endif
8437c2fbfb3SApril Chin #endif
8447c2fbfb3SApril Chin }
845da2e3ebdSchin if ((flags & PROC_CLEANUP) && modv)
846da2e3ebdSchin for (i = 0; n = modv[i]; i++)
847da2e3ebdSchin switch (PROC_OP(n))
848da2e3ebdSchin {
849da2e3ebdSchin case PROC_fd_dup:
850da2e3ebdSchin case PROC_fd_dup|PROC_FD_PARENT:
851da2e3ebdSchin case PROC_fd_dup|PROC_FD_CHILD:
852da2e3ebdSchin case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
853da2e3ebdSchin if (PROC_ARG(n, 2) != PROC_ARG_NULL)
854da2e3ebdSchin close(PROC_ARG(n, 1));
855da2e3ebdSchin break;
856da2e3ebdSchin }
857da2e3ebdSchin if (pio[0] >= 0)
858da2e3ebdSchin close(pio[0]);
859da2e3ebdSchin if (pio[1] >= 0)
860da2e3ebdSchin close(pio[1]);
861da2e3ebdSchin #if !_pipe_rw && !_lib_socketpair
862da2e3ebdSchin if (poi[0] >= 0)
863da2e3ebdSchin close(poi[0]);
864da2e3ebdSchin if (poi[1] >= 0)
865da2e3ebdSchin close(poi[1]);
866da2e3ebdSchin #endif
867da2e3ebdSchin procfree(proc);
868da2e3ebdSchin return 0;
869da2e3ebdSchin }
870