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