1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 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 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 38 /* 39 * not quite ready for _use_spawnveg 40 */ 41 42 #if _use_spawnveg && _lib_fork 43 #undef _use_spawnveg 44 #endif 45 46 #ifndef DEBUG_PROC 47 #define DEBUG_PROC 1 48 #endif 49 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 58 59 Proc_t proc_default = { -1 }; 60 61 #if DEBUG_PROC 62 63 #include <namval.h> 64 65 #define PROC_ENV_OPTIONS "PROC_OPTIONS" 66 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) 71 72 static const Namval_t options[] = 73 { 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 80 }; 81 82 /* 83 * called by stropt() to set options 84 */ 85 86 static int 87 setopt(register void* a, register const void* p, register int n, const char* v) 88 { 89 NoP(v); 90 if (p) 91 { 92 if (n) 93 *((int*)a) |= ((Namval_t*)p)->value; 94 else 95 *((int*)a) &= ~((Namval_t*)p)->value; 96 } 97 return 0; 98 } 99 100 #endif 101 102 #if _use_spawnveg 103 104 typedef struct Fd_s 105 { 106 short fd; 107 short flag; 108 } Fd_t; 109 110 typedef struct Mod_s 111 { 112 struct Mod_s* next; 113 short op; 114 short save; 115 116 union 117 { 118 119 struct 120 { 121 Fd_t parent; 122 Fd_t child; 123 } fd; 124 125 Handler_t handler; 126 127 } arg; 128 129 } Modify_t; 130 131 #endif 132 133 #ifdef SIGPIPE 134 135 /* 136 * catch but ignore sig 137 * avoids SIG_IGN being passed to children 138 */ 139 140 static void 141 ignoresig(int sig) 142 { 143 signal(sig, ignoresig); 144 } 145 146 #endif 147 148 /* 149 * do modification op and save previous state for restore() 150 */ 151 152 static int 153 modify(Proc_t* proc, int forked, int op, long arg1, long arg2) 154 { 155 #if _lib_fork 156 if (forked) 157 { 158 switch (op) 159 { 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) 165 { 166 if (arg2 != PROC_ARG_NULL) 167 { 168 close(arg2); 169 if (fcntl(arg1, F_DUPFD, arg2) != arg2) 170 return -1; 171 } 172 if (op & PROC_FD_CHILD) 173 close(arg1); 174 } 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) 186 { 187 if (arg1 == 1) 188 arg1 = 0; 189 if (setpgid(0, arg1) < 0 && arg1 && errno == EPERM) 190 setpgid(0, 0); 191 } 192 break; 193 case PROC_sys_umask: 194 umask(arg1); 195 break; 196 default: 197 return -1; 198 } 199 } 200 #if _use_spawnveg 201 else 202 #endif 203 #else 204 NoP(forked); 205 #endif 206 #if _use_spawnveg 207 { 208 register Modify_t* m; 209 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) 215 { 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) 223 { 224 if (arg2 != PROC_ARG_NULL) 225 { 226 m->arg.fd.child.flag = fcntl(arg2, F_GETFD, 0); 227 if ((m->save = fcntl(arg2, F_DUPFD, 3)) < 0) 228 { 229 m->op = 0; 230 return -1; 231 } 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); 238 } 239 else if (op & PROC_FD_CHILD) 240 { 241 if (m->arg.fd.parent.flag) 242 break; 243 fcntl(arg1, F_SETFD, FD_CLOEXEC); 244 } 245 else if (!m->arg.fd.parent.flag) 246 break; 247 else 248 fcntl(arg1, F_SETFD, 0); 249 return 0; 250 } 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; 273 } 274 proc->mods = m->next; 275 free(m); 276 } 277 #else 278 NoP(proc); 279 #endif 280 return 0; 281 } 282 283 #if _use_spawnveg 284 285 /* 286 * restore modifications 287 */ 288 289 static void 290 restore(Proc_t* proc) 291 { 292 register Modify_t* m; 293 register Modify_t* p; 294 int oerrno; 295 296 NoP(proc); 297 oerrno = errno; 298 m = proc->mods; 299 proc->mods = 0; 300 while (m) 301 { 302 switch (m->op) 303 { 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) 311 { 312 if (!(m->op & PROC_FD_PARENT)) 313 { 314 if (m->op & PROC_FD_CHILD) 315 { 316 close(m->arg.fd.parent.fd); 317 fcntl(m->arg.fd.child.fd, F_DUPFD, m->arg.fd.parent.fd); 318 } 319 fcntl(m->arg.fd.parent.fd, F_SETFD, m->arg.fd.parent.flag); 320 } 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); 326 } 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; 337 } 338 p = m; 339 m = m->next; 340 free(p); 341 } 342 errno = oerrno; 343 } 344 345 #else 346 347 #define restore(p) 348 349 #endif 350 351 /* 352 * fork and exec or spawn proc(argv) and return a Proc_t handle 353 * 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 360 */ 361 362 Proc_t* 363 procopen(const char* cmd, char** argv, char** envv, long* modv, long flags) 364 { 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 long n; 372 char path[PATH_MAX]; 373 char env[PATH_MAX + 2]; 374 int pio[2]; 375 #if !_pipe_rw && !_lib_socketpair 376 int poi[2]; 377 #endif 378 #if defined(SIGCHLD) && ( _lib_sigprocmask || _lib_sigsetmask ) 379 Sig_mask_t mask; 380 #endif 381 #if _use_spawnveg 382 int newenv = 0; 383 #endif 384 #if DEBUG_PROC 385 int debug = PROC_OPT_EXEC; 386 #endif 387 388 #if _lib_fork 389 if (!argv && (flags & PROC_OVERLAY)) 390 #else 391 if (!argv) 392 #endif 393 { 394 errno = ENOEXEC; 395 return 0; 396 } 397 pio[0] = pio[1] = -1; 398 #if !_pipe_rw && !_lib_socketpair 399 poi[0] = poi[1] = -1; 400 #endif 401 if (cmd && (!*cmd || !pathpath(path, cmd, NiL, PATH_REGULAR|PATH_EXECUTE))) 402 goto bad; 403 switch (flags & (PROC_READ|PROC_WRITE)) 404 { 405 case 0: 406 procfd = -1; 407 break; 408 case PROC_READ: 409 procfd = 1; 410 break; 411 case PROC_WRITE: 412 procfd = 0; 413 break; 414 case PROC_READ|PROC_WRITE: 415 procfd = 2; 416 break; 417 } 418 if (proc_default.pid == -1) 419 proc = &proc_default; 420 else if (!(proc = newof(0, Proc_t, 1, 0))) 421 goto bad; 422 proc->pid = -1; 423 proc->pgrp = 0; 424 proc->rfd = -1; 425 proc->wfd = -1; 426 proc->flags = flags; 427 sfsync(NiL); 428 if (environ && envv != (char**)environ && (envv || (flags & PROC_PARANOID) || argv && (environ[0][0] != '_' || environ[0][1] != '='))) 429 { 430 if (!setenviron(NiL)) 431 goto bad; 432 #if _use_spawnveg 433 newenv = 1; 434 #endif 435 } 436 if (procfd >= 0) 437 { 438 #if _pipe_rw 439 if (pipe(pio)) 440 goto bad; 441 #else 442 if (procfd > 1) 443 { 444 #if _lib_socketpair 445 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pio)) 446 goto bad; 447 #else 448 if (pipe(pio) || pipe(poi)) 449 goto bad; 450 #endif 451 } 452 else if (pipe(pio)) 453 goto bad; 454 #endif 455 } 456 if (flags & PROC_OVERLAY) 457 { 458 proc->pid = 0; 459 forked = 1; 460 } 461 #if _use_spawnveg 462 else if (argv) 463 proc->pid = 0; 464 #endif 465 #if _lib_fork 466 else 467 { 468 if (!(flags & PROC_FOREGROUND)) 469 sigcritical(SIG_REG_EXEC|SIG_REG_PROC); 470 else 471 { 472 proc->sigint = signal(SIGINT, SIG_IGN); 473 proc->sigquit = signal(SIGQUIT, SIG_IGN); 474 #if defined(SIGCHLD) 475 proc->sigchld = signal(SIGCHLD, SIG_DFL); 476 #if _lib_sigprocmask 477 sigemptyset(&mask); 478 sigaddset(&mask, SIGCHLD); 479 sigprocmask(SIG_BLOCK, &mask, &proc->mask); 480 #else 481 #if _lib_sigsetmask 482 mask = sigmask(SIGCHLD); 483 proc->mask = sigblock(mask); 484 #endif 485 #endif 486 #endif 487 } 488 proc->pid = fork(); 489 if (!(flags & PROC_FOREGROUND)) 490 sigcritical(0); 491 else if (!proc->pid) 492 { 493 if (proc->sigint != SIG_IGN) 494 proc->sigint = SIG_DFL; 495 signal(SIGINT, proc->sigint); 496 if (proc->sigquit != SIG_IGN) 497 proc->sigquit = SIG_DFL; 498 signal(SIGQUIT, proc->sigquit); 499 #if defined(SIGCHLD) 500 if (proc->sigchld != SIG_IGN) 501 proc->sigchld = SIG_DFL; 502 signal(SIGCHLD, proc->sigchld); 503 #endif 504 } 505 if (proc->pid == -1) 506 goto bad; 507 forked = 1; 508 } 509 #endif 510 if (!proc->pid) 511 { 512 char* s; 513 #if _use_spawnveg 514 char** oenviron = 0; 515 char* oenviron0 = 0; 516 517 v = 0; 518 #endif 519 #if DEBUG_PROC 520 stropt(getenv(PROC_ENV_OPTIONS), options, sizeof(*options), setopt, &debug); 521 #if _lib_fork 522 if (debug & PROC_OPT_TRACE) 523 { 524 if (!fork()) 525 { 526 sfsprintf(path, sizeof(path), "%d", getppid()); 527 execlp("trace", "trace", "-p", path, NiL); 528 _exit(EXIT_NOTFOUND); 529 } 530 sleep(2); 531 } 532 #endif 533 #endif 534 if (flags & PROC_DAEMON) 535 { 536 #ifdef SIGHUP 537 modify(proc, forked, PROC_sig_ign, SIGHUP, 0); 538 #endif 539 modify(proc, forked, PROC_sig_dfl, SIGTERM, 0); 540 #ifdef SIGTSTP 541 modify(proc, forked, PROC_sig_ign, SIGTSTP, 0); 542 #endif 543 #ifdef SIGTTIN 544 modify(proc, forked, PROC_sig_ign, SIGTTIN, 0); 545 #endif 546 #ifdef SIGTTOU 547 modify(proc, forked, PROC_sig_ign, SIGTTOU, 0); 548 #endif 549 } 550 if (flags & (PROC_BACKGROUND|PROC_DAEMON)) 551 { 552 modify(proc, forked, PROC_sig_ign, SIGINT, 0); 553 #ifdef SIGQUIT 554 modify(proc, forked, PROC_sig_ign, SIGQUIT, 0); 555 #endif 556 } 557 if (flags & (PROC_DAEMON|PROC_SESSION)) 558 modify(proc, forked, PROC_sys_pgrp, -1, 0); 559 if (forked || (flags & PROC_OVERLAY)) 560 { 561 if ((flags & PROC_PRIVELEGED) && !geteuid()) 562 { 563 setuid(geteuid()); 564 setgid(getegid()); 565 } 566 if (flags & (PROC_PARANOID|PROC_GID)) 567 setgid(getgid()); 568 if (flags & (PROC_PARANOID|PROC_UID)) 569 setuid(getuid()); 570 } 571 if (procfd > 1) 572 { 573 if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[0], PROC_ARG_NULL)) 574 goto cleanup; 575 if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[1], 1)) 576 goto cleanup; 577 #if _pipe_rw || _lib_socketpair 578 if (modify(proc, forked, PROC_fd_dup, 1, 0)) 579 goto cleanup; 580 #else 581 if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[0], 0)) 582 goto cleanup; 583 if (poi[1] != 0 && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[1], PROC_ARG_NULL)) 584 goto cleanup; 585 #endif 586 } 587 else if (procfd >= 0) 588 { 589 if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!!procfd], !!procfd)) 590 goto cleanup; 591 if (pio[!procfd] != !!procfd && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!procfd], PROC_ARG_NULL)) 592 goto cleanup; 593 } 594 if (modv) 595 for (i = 0; n = modv[i]; i++) 596 switch (PROC_OP(n)) 597 { 598 case PROC_fd_dup: 599 case PROC_fd_dup|PROC_FD_PARENT: 600 case PROC_fd_dup|PROC_FD_CHILD: 601 case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD: 602 if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), PROC_ARG(n, 2))) 603 goto cleanup; 604 break; 605 default: 606 if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), 0)) 607 goto cleanup; 608 break; 609 } 610 #if _lib_fork 611 if (forked && (flags & PROC_ENVCLEAR)) 612 environ = 0; 613 #if _use_spawnveg 614 else 615 #endif 616 #endif 617 #if _use_spawnveg 618 if (newenv) 619 { 620 p = environ; 621 while (*p++); 622 if (!(oenviron = (char**)memdup(environ, (p - environ) * sizeof(char*)))) 623 goto cleanup; 624 } 625 #endif 626 if (argv && envv != (char**)environ) 627 { 628 #if _use_spawnveg 629 if (!newenv && environ[0][0] == '_' && environ[0][1] == '=') 630 oenviron0 = environ[0]; 631 #endif 632 env[0] = '_'; 633 env[1] = '='; 634 env[2] = 0; 635 if (!setenviron(env)) 636 goto cleanup; 637 } 638 if ((flags & PROC_PARANOID) && setenv("PATH", astconf("PATH", NiL, NiL), 1)) 639 goto cleanup; 640 if ((p = envv) && p != (char**)environ) 641 while (*p) 642 if (!setenviron(*p++)) 643 goto cleanup; 644 p = argv; 645 #if _lib_fork 646 if (forked && !p) 647 return proc; 648 #endif 649 #if DEBUG_PROC 650 if (!(debug & PROC_OPT_EXEC) || (debug & PROC_OPT_VERBOSE)) 651 { 652 if ((debug & PROC_OPT_ENVIRONMENT) && (p = environ)) 653 while (*p) 654 sfprintf(sfstderr, "%s\n", *p++); 655 sfprintf(sfstderr, "+ %s", cmd ? path : "sh"); 656 if ((p = argv) && *p) 657 while (*++p) 658 sfprintf(sfstderr, " %s", *p); 659 sfprintf(sfstderr, "\n"); 660 sfsync(sfstderr); 661 if (!(debug & PROC_OPT_EXEC)) 662 _exit(0); 663 p = argv; 664 } 665 #endif 666 if (cmd) 667 { 668 strcpy(env + 2, path); 669 if (forked || (flags & PROC_OVERLAY)) 670 execve(path, p, environ); 671 #if _use_spawnveg 672 else if ((proc->pid = spawnveg(path, p, environ, proc->pgrp)) != -1) 673 goto cleanup; 674 #endif 675 if (errno != ENOEXEC) 676 goto cleanup; 677 678 /* 679 * try cmd as a shell script 680 */ 681 682 if (!(flags & PROC_ARGMOD)) 683 { 684 while (*p++); 685 if (!(v = newof(0, char*, p - argv + 2, 0))) 686 goto cleanup; 687 p = v + 2; 688 if (*argv) 689 argv++; 690 while (*p++ = *argv++); 691 p = v + 1; 692 } 693 *p = path; 694 *--p = "sh"; 695 } 696 strcpy(env + 2, (flags & PROC_PARANOID) ? astconf("SH", NiL, NiL) : pathshell()); 697 if (forked || (flags & PROC_OVERLAY)) 698 execve(env + 2, p, environ); 699 #if _use_spawnveg 700 else 701 proc->pid = spawnveg(env + 2, p, environ, proc->pgrp); 702 #endif 703 cleanup: 704 if (forked) 705 { 706 if (!(flags & PROC_OVERLAY)) 707 _exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC); 708 goto bad; 709 } 710 #if _use_spawnveg 711 if (v) 712 free(v); 713 if (p = oenviron) 714 { 715 environ = 0; 716 while (*p) 717 if (!setenviron(*p++)) 718 goto bad; 719 free(oenviron); 720 } 721 else if (oenviron0) 722 environ[0] = oenviron0; 723 restore(proc); 724 if (flags & PROC_OVERLAY) 725 exit(0); 726 #endif 727 } 728 if (proc->pid != -1) 729 { 730 if (!forked) 731 { 732 if (flags & PROC_FOREGROUND) 733 { 734 proc->sigint = signal(SIGINT, SIG_IGN); 735 proc->sigquit = signal(SIGQUIT, SIG_IGN); 736 #if defined(SIGCHLD) 737 proc->sigchld = signal(SIGCHLD, SIG_DFL); 738 #endif 739 } 740 } 741 else if (modv) 742 for (i = 0; n = modv[i]; i++) 743 switch (PROC_OP(n)) 744 { 745 case PROC_fd_dup|PROC_FD_PARENT: 746 case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD: 747 close(PROC_ARG(n, 1)); 748 break; 749 case PROC_sys_pgrp: 750 if (proc->pgrp < 0) 751 proc->pgrp = proc->pid; 752 else if (proc->pgrp > 0) 753 { 754 if (proc->pgrp == 1) 755 proc->pgrp = proc->pid; 756 if (setpgid(proc->pid, proc->pgrp) < 0 && proc->pid != proc->pgrp && errno == EPERM) 757 setpgid(proc->pid, proc->pid); 758 } 759 break; 760 } 761 if (procfd >= 0) 762 { 763 #ifdef SIGPIPE 764 if ((flags & (PROC_WRITE|PROC_IGNORE)) == (PROC_WRITE|PROC_IGNORE)) 765 { 766 Handler_t handler; 767 768 if ((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL && handler != ignoresig) 769 signal(SIGPIPE, handler); 770 } 771 #endif 772 switch (procfd) 773 { 774 case 0: 775 proc->wfd = pio[1]; 776 close(pio[0]); 777 break; 778 default: 779 #if _pipe_rw || _lib_socketpair 780 proc->wfd = pio[0]; 781 #else 782 proc->wfd = poi[1]; 783 close(poi[0]); 784 #endif 785 /*FALLTHROUGH*/ 786 case 1: 787 proc->rfd = pio[0]; 788 close(pio[1]); 789 break; 790 } 791 if (proc->rfd > 2) 792 fcntl(proc->rfd, F_SETFD, FD_CLOEXEC); 793 if (proc->wfd > 2) 794 fcntl(proc->wfd, F_SETFD, FD_CLOEXEC); 795 } 796 if (!proc->pid) 797 proc->pid = getpid(); 798 return proc; 799 } 800 bad: 801 if ((flags & PROC_CLEANUP) && modv) 802 for (i = 0; n = modv[i]; i++) 803 switch (PROC_OP(n)) 804 { 805 case PROC_fd_dup: 806 case PROC_fd_dup|PROC_FD_PARENT: 807 case PROC_fd_dup|PROC_FD_CHILD: 808 case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD: 809 if (PROC_ARG(n, 2) != PROC_ARG_NULL) 810 close(PROC_ARG(n, 1)); 811 break; 812 } 813 if (pio[0] >= 0) 814 close(pio[0]); 815 if (pio[1] >= 0) 816 close(pio[1]); 817 #if !_pipe_rw && !_lib_socketpair 818 if (poi[0] >= 0) 819 close(poi[0]); 820 if (poi[1] >= 0) 821 close(poi[1]); 822 #endif 823 procfree(proc); 824 return 0; 825 } 826