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 66Proc_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 79static 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 93static int 94setopt(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 111typedef struct Fd_s 112{ 113 short fd; 114 short flag; 115} Fd_t; 116 117typedef 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 147static void 148ignoresig(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 159static int 160modify(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 326static void 327restore(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 399Proc_t* 400procopen(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"); 735sfsync(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