import less(1)
[unleashed/tickless.git] / usr / src / lib / libast / common / misc / procopen.c
blobb943c96af144a7cdcdea3db2d9e58d104b1a8d26
1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
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
24 * Glenn Fowler
25 * AT&T Research
27 * common process execution support with
28 * proper sfio, signal and wait() syncronization
30 * _ contains the process path name and is
31 * placed at the top of the environment
34 #include "proclib.h"
36 #include <ls.h>
39 * not quite ready for _use_spawnveg
42 #if _use_spawnveg && _lib_fork
43 #undef _use_spawnveg
44 #endif
46 #ifndef DEBUG_PROC
47 #define DEBUG_PROC 1
48 #endif
50 #if _lib_socketpair
51 #if _sys_socket
52 #include <sys/types.h>
53 #include <sys/socket.h>
54 #else
55 #undef _lib_socketpair
56 #endif
57 #endif
59 Proc_t proc_default = { -1 };
61 #if DEBUG_PROC
63 #include <namval.h>
65 #define PROC_ENV_OPTIONS "PROC_OPTIONS"
67 #define PROC_OPT_ENVIRONMENT (1<<0)
68 #define PROC_OPT_EXEC (1<<1)
69 #define PROC_OPT_TRACE (1<<2)
70 #define PROC_OPT_VERBOSE (1<<3)
72 static const Namval_t options[] =
74 "debug", PROC_OPT_VERBOSE,
75 "environment", PROC_OPT_ENVIRONMENT,
76 "exec", PROC_OPT_EXEC,
77 "trace", PROC_OPT_TRACE,
78 "verbose", PROC_OPT_VERBOSE,
79 0, 0
83 * called by stropt() to set options
86 static int
87 setopt(register void* a, register const void* p, register int n, const char* v)
89 NoP(v);
90 if (p)
92 if (n)
93 *((int*)a) |= ((Namval_t*)p)->value;
94 else
95 *((int*)a) &= ~((Namval_t*)p)->value;
97 return 0;
100 #endif
102 #if _use_spawnveg
104 typedef struct Fd_s
106 short fd;
107 short flag;
108 } Fd_t;
110 typedef struct Mod_s
112 struct Mod_s* next;
113 short op;
114 short save;
116 union
119 struct
121 Fd_t parent;
122 Fd_t child;
123 } fd;
125 Handler_t handler;
127 } arg;
129 } Modify_t;
131 #endif
133 #ifdef SIGPIPE
136 * catch but ignore sig
137 * avoids SIG_IGN being passed to children
140 static void
141 ignoresig(int sig)
143 signal(sig, ignoresig);
146 #endif
149 * do modification op and save previous state for restore()
152 static int
153 modify(Proc_t* proc, int forked, int op, long arg1, long arg2)
155 #if _lib_fork
156 if (forked)
158 switch (op)
160 case PROC_fd_dup:
161 case PROC_fd_dup|PROC_FD_PARENT:
162 case PROC_fd_dup|PROC_FD_CHILD:
163 case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
164 if (arg1 != arg2)
166 if (arg2 != PROC_ARG_NULL)
168 close(arg2);
169 if (fcntl(arg1, F_DUPFD, arg2) != arg2)
170 return -1;
172 if (op & PROC_FD_CHILD)
173 close(arg1);
175 break;
176 case PROC_sig_dfl:
177 signal(arg1, SIG_DFL);
178 break;
179 case PROC_sig_ign:
180 signal(arg1, SIG_IGN);
181 break;
182 case PROC_sys_pgrp:
183 if (arg1 < 0)
184 setsid();
185 else if (arg1 > 0)
187 if (arg1 == 1)
188 arg1 = 0;
189 if (setpgid(0, arg1) < 0 && arg1 && errno == EPERM)
190 setpgid(0, 0);
192 break;
193 case PROC_sys_umask:
194 umask(arg1);
195 break;
196 default:
197 return -1;
200 #if _use_spawnveg
201 else
202 #endif
203 #else
204 NoP(forked);
205 #endif
206 #if _use_spawnveg
208 register Modify_t* m;
210 if (!(m = newof(NiL, Modify_t, 1, 0)))
211 return -1;
212 m->next = proc->mods;
213 proc->mods = m;
214 switch (m->op = op)
216 case PROC_fd_dup:
217 case PROC_fd_dup|PROC_FD_PARENT:
218 case PROC_fd_dup|PROC_FD_CHILD:
219 case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
220 m->arg.fd.parent.fd = (short)arg1;
221 m->arg.fd.parent.flag = fcntl(arg1, F_GETFD, 0);
222 if ((m->arg.fd.child.fd = (short)arg2) != arg1)
224 if (arg2 != PROC_ARG_NULL)
226 m->arg.fd.child.flag = fcntl(arg2, F_GETFD, 0);
227 if ((m->save = fcntl(arg2, F_DUPFD, 3)) < 0)
229 m->op = 0;
230 return -1;
232 fcntl(m->save, F_SETFD, FD_CLOEXEC);
233 close(arg2);
234 if (fcntl(arg1, F_DUPFD, arg2) != arg2)
235 return -1;
236 if (op & PROC_FD_CHILD)
237 close(arg1);
239 else if (op & PROC_FD_CHILD)
241 if (m->arg.fd.parent.flag)
242 break;
243 fcntl(arg1, F_SETFD, FD_CLOEXEC);
245 else if (!m->arg.fd.parent.flag)
246 break;
247 else
248 fcntl(arg1, F_SETFD, 0);
249 return 0;
251 break;
252 case PROC_sig_dfl:
253 if ((m->arg.handler = signal(arg1, SIG_DFL)) == SIG_DFL)
254 break;
255 m->save = (short)arg1;
256 return 0;
257 case PROC_sig_ign:
258 if ((m->arg.handler = signal(arg1, SIG_IGN)) == SIG_IGN)
259 break;
260 m->save = (short)arg1;
261 return 0;
262 case PROC_sys_pgrp:
263 proc->pgrp = arg1;
264 break;
265 case PROC_sys_umask:
266 if ((m->save = (short)umask(arg1)) == arg1)
267 break;
268 return 0;
269 default:
270 proc->mods = m->next;
271 free(m);
272 return -1;
274 proc->mods = m->next;
275 free(m);
277 #else
278 NoP(proc);
279 #endif
280 return 0;
283 #if _use_spawnveg
286 * restore modifications
289 static void
290 restore(Proc_t* proc)
292 register Modify_t* m;
293 register Modify_t* p;
294 int oerrno;
296 NoP(proc);
297 oerrno = errno;
298 m = proc->mods;
299 proc->mods = 0;
300 while (m)
302 switch (m->op)
304 case PROC_fd_dup:
305 case PROC_fd_dup|PROC_FD_PARENT:
306 case PROC_fd_dup|PROC_FD_CHILD:
307 case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
308 if (m->op & PROC_FD_PARENT)
309 close(m->arg.fd.parent.fd);
310 if (m->arg.fd.child.fd != m->arg.fd.parent.fd && m->arg.fd.child.fd != PROC_ARG_NULL)
312 if (!(m->op & PROC_FD_PARENT))
314 if (m->op & PROC_FD_CHILD)
316 close(m->arg.fd.parent.fd);
317 fcntl(m->arg.fd.child.fd, F_DUPFD, m->arg.fd.parent.fd);
319 fcntl(m->arg.fd.parent.fd, F_SETFD, m->arg.fd.parent.flag);
321 close(m->arg.fd.child.fd);
322 fcntl(m->save, F_DUPFD, m->arg.fd.child.fd);
323 close(m->save);
324 if (m->arg.fd.child.flag)
325 fcntl(m->arg.fd.child.fd, F_SETFD, FD_CLOEXEC);
327 else if ((m->op & (PROC_FD_PARENT|PROC_FD_CHILD)) == PROC_FD_CHILD)
328 fcntl(m->arg.fd.parent.fd, F_SETFD, 0);
329 break;
330 case PROC_sig_dfl:
331 case PROC_sig_ign:
332 signal(m->save, m->arg.handler);
333 break;
334 case PROC_sys_umask:
335 umask(m->save);
336 break;
338 p = m;
339 m = m->next;
340 free(p);
342 errno = oerrno;
345 #else
347 #define restore(p)
349 #endif
352 * fork and exec or spawn proc(argv) and return a Proc_t handle
354 * pipe not used when PROC_READ|PROC_WRITE omitted
355 * argv==0 duplicates current process if possible
356 * cmd==0 names the current shell
357 * cmd=="" does error cleanup
358 * envv is the child environment
359 * modv is the child modification vector of PROC_*() ops
362 Proc_t*
363 procopen(const char* cmd, char** argv, char** envv, long* modv, int flags)
365 register Proc_t* proc = 0;
366 register int procfd;
367 register char** p;
368 char** v;
369 int i;
370 int forked = 0;
371 int signalled = 0;
372 long n;
373 char path[PATH_MAX];
374 char env[PATH_MAX + 2];
375 int pio[2];
376 #if !_pipe_rw && !_lib_socketpair
377 int poi[2];
378 #endif
379 #if defined(SIGCHLD) && ( _lib_sigprocmask || _lib_sigsetmask )
380 Sig_mask_t mask;
381 #endif
382 #if _use_spawnveg
383 int newenv = 0;
384 #endif
385 #if DEBUG_PROC
386 int debug = PROC_OPT_EXEC;
387 #endif
389 #if _lib_fork
390 if (!argv && (flags & PROC_OVERLAY))
391 #else
392 if (!argv)
393 #endif
395 errno = ENOEXEC;
396 return 0;
398 pio[0] = pio[1] = -1;
399 #if !_pipe_rw && !_lib_socketpair
400 poi[0] = poi[1] = -1;
401 #endif
402 if (cmd && (!*cmd || !pathpath(path, cmd, NiL, PATH_REGULAR|PATH_EXECUTE)))
403 goto bad;
404 switch (flags & (PROC_READ|PROC_WRITE))
406 case 0:
407 procfd = -1;
408 break;
409 case PROC_READ:
410 procfd = 1;
411 break;
412 case PROC_WRITE:
413 procfd = 0;
414 break;
415 case PROC_READ|PROC_WRITE:
416 procfd = 2;
417 break;
419 if (proc_default.pid == -1)
420 proc = &proc_default;
421 else if (!(proc = newof(0, Proc_t, 1, 0)))
422 goto bad;
423 proc->pid = -1;
424 proc->pgrp = 0;
425 proc->rfd = -1;
426 proc->wfd = -1;
427 proc->flags = flags;
428 sfsync(NiL);
429 if (environ && envv != (char**)environ && (envv || (flags & PROC_PARANOID) || argv && (environ[0][0] != '_' || environ[0][1] != '=')))
431 if (!setenviron(NiL))
432 goto bad;
433 #if _use_spawnveg
434 newenv = 1;
435 #endif
437 if (procfd >= 0)
439 #if _pipe_rw
440 if (pipe(pio))
441 goto bad;
442 #else
443 if (procfd > 1)
445 #if _lib_socketpair
446 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pio))
447 goto bad;
448 #else
449 if (pipe(pio) || pipe(poi))
450 goto bad;
451 #endif
453 else if (pipe(pio))
454 goto bad;
455 #endif
457 if (flags & PROC_OVERLAY)
459 proc->pid = 0;
460 forked = 1;
462 #if _use_spawnveg
463 else if (argv)
464 proc->pid = 0;
465 #endif
466 #if _lib_fork
467 else
469 if (!(flags & PROC_FOREGROUND))
470 sigcritical(SIG_REG_EXEC|SIG_REG_PROC);
471 else
473 signalled = 1;
474 proc->sigint = signal(SIGINT, SIG_IGN);
475 proc->sigquit = signal(SIGQUIT, SIG_IGN);
476 #if defined(SIGCHLD)
477 #if _lib_sigprocmask
478 sigemptyset(&mask);
479 sigaddset(&mask, SIGCHLD);
480 sigprocmask(SIG_BLOCK, &mask, &proc->mask);
481 #else
482 #if _lib_sigsetmask
483 mask = sigmask(SIGCHLD);
484 proc->mask = sigblock(mask);
485 #else
486 proc->sigchld = signal(SIGCHLD, SIG_DFL);
487 #endif
488 #endif
489 #endif
491 proc->pid = fork();
492 if (!(flags & PROC_FOREGROUND))
493 sigcritical(0);
494 else if (!proc->pid)
496 if (proc->sigint != SIG_IGN)
498 proc->sigint = SIG_DFL;
499 signal(SIGINT, proc->sigint);
501 if (proc->sigquit != SIG_IGN)
503 proc->sigquit = SIG_DFL;
504 signal(SIGQUIT, proc->sigquit);
506 #if defined(SIGCHLD)
507 #if _lib_sigprocmask
508 sigprocmask(SIG_SETMASK, &proc->mask, NiL);
509 #else
510 #if _lib_sigsetmask
511 sigsetmask(proc->mask);
512 #else
513 if (proc->sigchld != SIG_IGN)
514 signal(SIGCHLD, SIG_DFL);
515 #endif
516 #endif
517 #endif
519 else if (proc->pid == -1)
520 goto bad;
521 forked = 1;
523 #endif
524 if (!proc->pid)
526 #if _use_spawnveg
527 char** oenviron = 0;
528 char* oenviron0 = 0;
530 v = 0;
531 #endif
532 #if DEBUG_PROC
533 stropt(getenv(PROC_ENV_OPTIONS), options, sizeof(*options), setopt, &debug);
534 #if _lib_fork
535 if (debug & PROC_OPT_TRACE)
537 if (!fork())
539 sfsprintf(path, sizeof(path), "%d", getppid());
540 execlp("trace", "trace", "-p", path, NiL);
541 _exit(EXIT_NOTFOUND);
543 sleep(2);
545 #endif
546 #endif
547 if (flags & PROC_DAEMON)
549 #ifdef SIGHUP
550 modify(proc, forked, PROC_sig_ign, SIGHUP, 0);
551 #endif
552 modify(proc, forked, PROC_sig_dfl, SIGTERM, 0);
553 #ifdef SIGTSTP
554 modify(proc, forked, PROC_sig_ign, SIGTSTP, 0);
555 #endif
556 #ifdef SIGTTIN
557 modify(proc, forked, PROC_sig_ign, SIGTTIN, 0);
558 #endif
559 #ifdef SIGTTOU
560 modify(proc, forked, PROC_sig_ign, SIGTTOU, 0);
561 #endif
563 if (flags & (PROC_BACKGROUND|PROC_DAEMON))
565 modify(proc, forked, PROC_sig_ign, SIGINT, 0);
566 #ifdef SIGQUIT
567 modify(proc, forked, PROC_sig_ign, SIGQUIT, 0);
568 #endif
570 if (flags & (PROC_DAEMON|PROC_SESSION))
571 modify(proc, forked, PROC_sys_pgrp, -1, 0);
572 if (forked || (flags & PROC_OVERLAY))
574 if ((flags & PROC_PRIVELEGED) && !geteuid())
576 setuid(geteuid());
577 setgid(getegid());
579 if (flags & (PROC_PARANOID|PROC_GID))
580 setgid(getgid());
581 if (flags & (PROC_PARANOID|PROC_UID))
582 setuid(getuid());
584 if (procfd > 1)
586 if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[0], PROC_ARG_NULL))
587 goto cleanup;
588 if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[1], 1))
589 goto cleanup;
590 #if _pipe_rw || _lib_socketpair
591 if (modify(proc, forked, PROC_fd_dup, 1, 0))
592 goto cleanup;
593 #else
594 if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[0], 0))
595 goto cleanup;
596 if (poi[1] != 0 && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[1], PROC_ARG_NULL))
597 goto cleanup;
598 #endif
600 else if (procfd >= 0)
602 if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!!procfd], !!procfd))
603 goto cleanup;
604 if (pio[!procfd] != !!procfd && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!procfd], PROC_ARG_NULL))
605 goto cleanup;
607 if (modv)
608 for (i = 0; n = modv[i]; i++)
609 switch (PROC_OP(n))
611 case PROC_fd_dup:
612 case PROC_fd_dup|PROC_FD_PARENT:
613 case PROC_fd_dup|PROC_FD_CHILD:
614 case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
615 if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), PROC_ARG(n, 2)))
616 goto cleanup;
617 break;
618 default:
619 if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), 0))
620 goto cleanup;
621 break;
623 #if _lib_fork
624 if (forked && (flags & PROC_ENVCLEAR))
625 environ = 0;
626 #if _use_spawnveg
627 else
628 #endif
629 #endif
630 #if _use_spawnveg
631 if (newenv)
633 p = environ;
634 while (*p++);
635 if (!(oenviron = (char**)memdup(environ, (p - environ) * sizeof(char*))))
636 goto cleanup;
638 #endif
639 if (argv && envv != (char**)environ)
641 #if _use_spawnveg
642 if (!newenv && environ[0][0] == '_' && environ[0][1] == '=')
643 oenviron0 = environ[0];
644 #endif
645 env[0] = '_';
646 env[1] = '=';
647 env[2] = 0;
648 if (!setenviron(env))
649 goto cleanup;
651 if ((flags & PROC_PARANOID) && setenv("PATH", astconf("PATH", NiL, NiL), 1))
652 goto cleanup;
653 if ((p = envv) && p != (char**)environ)
654 while (*p)
655 if (!setenviron(*p++))
656 goto cleanup;
657 p = argv;
658 #if _lib_fork
659 if (forked && !p)
660 return proc;
661 #endif
662 #if DEBUG_PROC
663 if (!(debug & PROC_OPT_EXEC) || (debug & PROC_OPT_VERBOSE))
665 if ((debug & PROC_OPT_ENVIRONMENT) && (p = environ))
666 while (*p)
667 sfprintf(sfstderr, "%s\n", *p++);
668 sfprintf(sfstderr, "+ %s", cmd ? path : "sh");
669 if ((p = argv) && *p)
670 while (*++p)
671 sfprintf(sfstderr, " %s", *p);
672 sfprintf(sfstderr, "\n");
673 sfsync(sfstderr);
674 if (!(debug & PROC_OPT_EXEC))
675 _exit(0);
676 p = argv;
678 #endif
679 if (cmd)
681 strcpy(env + 2, path);
682 if (forked || (flags & PROC_OVERLAY))
683 execve(path, p, environ);
684 #if _use_spawnveg
685 else if ((proc->pid = spawnveg(path, p, environ, proc->pgrp)) != -1)
686 goto cleanup;
687 #endif
688 if (errno != ENOEXEC)
689 goto cleanup;
692 * try cmd as a shell script
695 if (!(flags & PROC_ARGMOD))
697 while (*p++);
698 if (!(v = newof(0, char*, p - argv + 2, 0)))
699 goto cleanup;
700 p = v + 2;
701 if (*argv)
702 argv++;
703 while (*p++ = *argv++);
704 p = v + 1;
706 *p = path;
707 *--p = "sh";
709 strcpy(env + 2, (flags & PROC_PARANOID) ? astconf("SH", NiL, NiL) : pathshell());
710 if (forked || (flags & PROC_OVERLAY))
711 execve(env + 2, p, environ);
712 #if _use_spawnveg
713 else
714 proc->pid = spawnveg(env + 2, p, environ, proc->pgrp);
715 #endif
716 cleanup:
717 if (forked)
719 if (!(flags & PROC_OVERLAY))
720 _exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC);
721 goto bad;
723 #if _use_spawnveg
724 free(v);
725 if (p = oenviron)
727 environ = 0;
728 while (*p)
729 if (!setenviron(*p++))
730 goto bad;
731 free(oenviron);
733 else if (oenviron0)
734 environ[0] = oenviron0;
735 restore(proc);
736 if (flags & PROC_OVERLAY)
737 exit(0);
738 #endif
740 if (proc->pid != -1)
742 if (!forked)
744 if (flags & PROC_FOREGROUND)
746 signalled = 1;
747 proc->sigint = signal(SIGINT, SIG_IGN);
748 proc->sigquit = signal(SIGQUIT, SIG_IGN);
749 #if defined(SIGCHLD)
750 #if _lib_sigprocmask
751 sigemptyset(&mask);
752 sigaddset(&mask, SIGCHLD);
753 sigprocmask(SIG_BLOCK, &mask, &proc->mask);
754 #else
755 #if _lib_sigsetmask
756 mask = sigmask(SIGCHLD);
757 proc->mask = sigblock(mask);
758 #else
759 proc->sigchld = signal(SIGCHLD, SIG_DFL);
760 #endif
761 #endif
762 #endif
765 else if (modv)
766 for (i = 0; n = modv[i]; i++)
767 switch (PROC_OP(n))
769 case PROC_fd_dup|PROC_FD_PARENT:
770 case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
771 close(PROC_ARG(n, 1));
772 break;
773 case PROC_sys_pgrp:
774 if (proc->pgrp < 0)
775 proc->pgrp = proc->pid;
776 else if (proc->pgrp > 0)
778 if (proc->pgrp == 1)
779 proc->pgrp = proc->pid;
780 if (setpgid(proc->pid, proc->pgrp) < 0 && proc->pid != proc->pgrp && errno == EPERM)
781 setpgid(proc->pid, proc->pid);
783 break;
785 if (procfd >= 0)
787 #ifdef SIGPIPE
788 if ((flags & (PROC_WRITE|PROC_IGNORE)) == (PROC_WRITE|PROC_IGNORE))
790 Handler_t handler;
792 if ((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL && handler != ignoresig)
793 signal(SIGPIPE, handler);
795 #endif
796 switch (procfd)
798 case 0:
799 proc->wfd = pio[1];
800 close(pio[0]);
801 break;
802 default:
803 #if _pipe_rw || _lib_socketpair
804 proc->wfd = pio[0];
805 #else
806 proc->wfd = poi[1];
807 close(poi[0]);
808 #endif
809 /*FALLTHROUGH*/
810 case 1:
811 proc->rfd = pio[0];
812 close(pio[1]);
813 break;
815 if (proc->rfd > 2)
816 fcntl(proc->rfd, F_SETFD, FD_CLOEXEC);
817 if (proc->wfd > 2)
818 fcntl(proc->wfd, F_SETFD, FD_CLOEXEC);
820 if (!proc->pid)
821 proc->pid = getpid();
822 return proc;
824 bad:
825 if (signalled)
827 if (proc->sigint != SIG_IGN)
828 signal(SIGINT, proc->sigint);
829 if (proc->sigquit != SIG_IGN)
830 signal(SIGQUIT, proc->sigquit);
831 #if defined(SIGCHLD)
832 #if _lib_sigprocmask
833 sigprocmask(SIG_SETMASK, &proc->mask, NiL);
834 #else
835 #if _lib_sigsetmask
836 sigsetmask(proc->mask);
837 #else
838 if (proc->sigchld != SIG_DFL)
839 signal(SIGCHLD, proc->sigchld);
840 #endif
841 #endif
842 #endif
844 if ((flags & PROC_CLEANUP) && modv)
845 for (i = 0; n = modv[i]; i++)
846 switch (PROC_OP(n))
848 case PROC_fd_dup:
849 case PROC_fd_dup|PROC_FD_PARENT:
850 case PROC_fd_dup|PROC_FD_CHILD:
851 case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
852 if (PROC_ARG(n, 2) != PROC_ARG_NULL)
853 close(PROC_ARG(n, 1));
854 break;
856 if (pio[0] >= 0)
857 close(pio[0]);
858 if (pio[1] >= 0)
859 close(pio[1]);
860 #if !_pipe_rw && !_lib_socketpair
861 if (poi[0] >= 0)
862 close(poi[0]);
863 if (poi[1] >= 0)
864 close(poi[1]);
865 #endif
866 procfree(proc);
867 return 0;