1/*********************************************************************** 2* * 3* This software is part of the ast package * 4* Copyright (c) 1985-2011 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 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 int k; 167#ifndef TIOCSCTTY 168 char* s; 169#endif 170 171 switch (op) 172 { 173 case PROC_fd_dup: 174 case PROC_fd_dup|PROC_FD_PARENT: 175 case PROC_fd_dup|PROC_FD_CHILD: 176 case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD: 177 if (arg1 != arg2) 178 { 179 if (arg2 != PROC_ARG_NULL) 180 { 181 close(arg2); 182 if (fcntl(arg1, F_DUPFD, arg2) != arg2) 183 return -1; 184 } 185 if (op & PROC_FD_CHILD) 186 close(arg1); 187 } 188 break; 189 case PROC_fd_ctty: 190 setsid(); 191 for (i = 0; i <= 2; i++) 192 if (arg1 != i) 193 close(i); 194 arg2 = -1; 195#ifdef TIOCSCTTY 196 if (ioctl(arg1, TIOCSCTTY, NiL) < 0) 197 return -1; 198#else 199 if (!(s = ttyname(arg1))) 200 return -1; 201 if ((arg2 = open(s, O_RDWR)) < 0) 202 return -1; 203#endif 204 for (i = 0; i <= 2; i++) 205 if (arg1 != i && arg2 != i && (k = fcntl(arg1, F_DUPFD, i)) != i) 206 return -1; 207 if (arg1 > 2) 208 close(arg1); 209 if (arg2 > 2) 210 close(arg2); 211 break; 212 case PROC_sig_dfl: 213 signal(arg1, SIG_DFL); 214 break; 215 case PROC_sig_ign: 216 signal(arg1, SIG_IGN); 217 break; 218 case PROC_sys_pgrp: 219 if (arg1 < 0) 220 setsid(); 221 else if (arg1 > 0) 222 { 223 if (arg1 == 1) 224 arg1 = 0; 225 if (setpgid(0, arg1) < 0 && arg1 && errno == EPERM) 226 setpgid(0, 0); 227 } 228 break; 229 case PROC_sys_umask: 230 umask(arg1); 231 break; 232 default: 233 return -1; 234 } 235 } 236#if _use_spawnveg 237 else 238#endif 239#else 240 NoP(forked); 241#endif 242#if _use_spawnveg 243 { 244 register Modify_t* m; 245 246 if (!(m = newof(NiL, Modify_t, 1, 0))) 247 return -1; 248 m->next = proc->mods; 249 proc->mods = m; 250 switch (m->op = op) 251 { 252 case PROC_fd_dup: 253 case PROC_fd_dup|PROC_FD_PARENT: 254 case PROC_fd_dup|PROC_FD_CHILD: 255 case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD: 256 m->arg.fd.parent.fd = (short)arg1; 257 m->arg.fd.parent.flag = fcntl(arg1, F_GETFD, 0); 258 if ((m->arg.fd.child.fd = (short)arg2) != arg1) 259 { 260 if (arg2 != PROC_ARG_NULL) 261 { 262 m->arg.fd.child.flag = fcntl(arg2, F_GETFD, 0); 263 if ((m->save = fcntl(arg2, F_DUPFD, 3)) < 0) 264 { 265 m->op = 0; 266 return -1; 267 } 268 fcntl(m->save, F_SETFD, FD_CLOEXEC); 269 close(arg2); 270 if (fcntl(arg1, F_DUPFD, arg2) != arg2) 271 return -1; 272 if (op & PROC_FD_CHILD) 273 close(arg1); 274 } 275 else if (op & PROC_FD_CHILD) 276 { 277 if (m->arg.fd.parent.flag) 278 break; 279 fcntl(arg1, F_SETFD, FD_CLOEXEC); 280 } 281 else if (!m->arg.fd.parent.flag) 282 break; 283 else 284 fcntl(arg1, F_SETFD, 0); 285 return 0; 286 } 287 break; 288 case PROC_sig_dfl: 289 if ((m->arg.handler = signal(arg1, SIG_DFL)) == SIG_DFL) 290 break; 291 m->save = (short)arg1; 292 return 0; 293 case PROC_sig_ign: 294 if ((m->arg.handler = signal(arg1, SIG_IGN)) == SIG_IGN) 295 break; 296 m->save = (short)arg1; 297 return 0; 298 case PROC_sys_pgrp: 299 proc->pgrp = arg1; 300 break; 301 case PROC_sys_umask: 302 if ((m->save = (short)umask(arg1)) == arg1) 303 break; 304 return 0; 305 default: 306 proc->mods = m->next; 307 free(m); 308 return -1; 309 } 310 proc->mods = m->next; 311 free(m); 312 } 313#else 314 NoP(proc); 315#endif 316 return 0; 317} 318 319#if _use_spawnveg 320 321/* 322 * restore modifications 323 */ 324 325static void 326restore(Proc_t* proc) 327{ 328 register Modify_t* m; 329 register Modify_t* p; 330 int oerrno; 331 332 NoP(proc); 333 oerrno = errno; 334 m = proc->mods; 335 proc->mods = 0; 336 while (m) 337 { 338 switch (m->op) 339 { 340 case PROC_fd_dup: 341 case PROC_fd_dup|PROC_FD_PARENT: 342 case PROC_fd_dup|PROC_FD_CHILD: 343 case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD: 344 if (m->op & PROC_FD_PARENT) 345 close(m->arg.fd.parent.fd); 346 if (m->arg.fd.child.fd != m->arg.fd.parent.fd && m->arg.fd.child.fd != PROC_ARG_NULL) 347 { 348 if (!(m->op & PROC_FD_PARENT)) 349 { 350 if (m->op & PROC_FD_CHILD) 351 { 352 close(m->arg.fd.parent.fd); 353 fcntl(m->arg.fd.child.fd, F_DUPFD, m->arg.fd.parent.fd); 354 } 355 fcntl(m->arg.fd.parent.fd, F_SETFD, m->arg.fd.parent.flag); 356 } 357 close(m->arg.fd.child.fd); 358 fcntl(m->save, F_DUPFD, m->arg.fd.child.fd); 359 close(m->save); 360 if (m->arg.fd.child.flag) 361 fcntl(m->arg.fd.child.fd, F_SETFD, FD_CLOEXEC); 362 } 363 else if ((m->op & (PROC_FD_PARENT|PROC_FD_CHILD)) == PROC_FD_CHILD) 364 fcntl(m->arg.fd.parent.fd, F_SETFD, 0); 365 break; 366 case PROC_sig_dfl: 367 case PROC_sig_ign: 368 signal(m->save, m->arg.handler); 369 break; 370 case PROC_sys_umask: 371 umask(m->save); 372 break; 373 } 374 p = m; 375 m = m->next; 376 free(p); 377 } 378 errno = oerrno; 379} 380 381#else 382 383#define restore(p) 384 385#endif 386 387/* 388 * fork and exec or spawn proc(argv) and return a Proc_t handle 389 * 390 * pipe not used when PROC_READ|PROC_WRITE omitted 391 * argv==0 duplicates current process if possible 392 * cmd==0 names the current shell 393 * cmd=="" does error cleanup 394 * envv is the child environment 395 * modv is the child modification vector of PROC_*() ops 396 */ 397 398Proc_t* 399procopen(const char* cmd, char** argv, char** envv, long* modv, int flags) 400{ 401 register Proc_t* proc = 0; 402 register int procfd; 403 register char** p; 404 char** v; 405 int i; 406 int forked = 0; 407 int signalled = 0; 408 long n; 409 char path[PATH_MAX]; 410 char env[PATH_MAX + 2]; 411 int pio[2]; 412#if _lib_fork 413 int pop[2]; 414#endif 415#if !_pipe_rw && !_lib_socketpair 416 int poi[2]; 417#endif 418#if defined(SIGCHLD) && ( _lib_sigprocmask || _lib_sigsetmask ) 419 Sig_mask_t mask; 420#endif 421#if _use_spawnveg 422 int newenv = 0; 423#endif 424#if DEBUG_PROC 425 int debug = PROC_OPT_EXEC; 426#endif 427 428#if _lib_fork 429 if (!argv && (flags & (PROC_ORPHAN|PROC_OVERLAY))) 430#else 431 if (!argv || (flags & PROC_ORPHAN)) 432#endif 433 { 434 errno = ENOEXEC; 435 return 0; 436 } 437 pio[0] = pio[1] = -1; 438#if _lib_fork 439 pop[0] = pop[1] = -1; 440#endif 441#if !_pipe_rw && !_lib_socketpair 442 poi[0] = poi[1] = -1; 443#endif 444 if (cmd && (!*cmd || !pathpath(cmd, NiL, PATH_REGULAR|PATH_EXECUTE, path, sizeof(path)))) 445 goto bad; 446 switch (flags & (PROC_READ|PROC_WRITE)) 447 { 448 case 0: 449 procfd = -1; 450 break; 451 case PROC_READ: 452 procfd = 1; 453 break; 454 case PROC_WRITE: 455 procfd = 0; 456 break; 457 case PROC_READ|PROC_WRITE: 458 procfd = 2; 459 break; 460 } 461 if (proc_default.pid == -1) 462 proc = &proc_default; 463 else if (!(proc = newof(0, Proc_t, 1, 0))) 464 goto bad; 465 proc->pid = -1; 466 proc->pgrp = 0; 467 proc->rfd = -1; 468 proc->wfd = -1; 469 proc->flags = flags; 470 sfsync(NiL); 471 if (environ && envv != (char**)environ && (envv || (flags & PROC_PARANOID) || argv && (environ[0][0] != '_' || environ[0][1] != '='))) 472 { 473 if (!setenviron(NiL)) 474 goto bad; 475#if _use_spawnveg 476 if (!(flags & PROC_ORPHAN)) 477 newenv = 1; 478#endif 479 } 480 if (procfd >= 0) 481 { 482#if _pipe_rw 483 if (pipe(pio)) 484 goto bad; 485#else 486 if (procfd > 1) 487 { 488#if _lib_socketpair 489 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pio)) 490 goto bad; 491#else 492 if (pipe(pio) || pipe(poi)) 493 goto bad; 494#endif 495 } 496 else if (pipe(pio)) 497 goto bad; 498#endif 499 } 500 if (flags & PROC_OVERLAY) 501 { 502 proc->pid = 0; 503 forked = 1; 504 } 505#if _use_spawnveg 506 else if (argv && !(flags & PROC_ORPHAN)) 507 proc->pid = 0; 508#endif 509#if _lib_fork 510 else 511 { 512 if (!(flags & PROC_FOREGROUND)) 513 sigcritical(SIG_REG_EXEC|SIG_REG_PROC); 514 else 515 { 516 signalled = 1; 517 proc->sigint = signal(SIGINT, SIG_IGN); 518 proc->sigquit = signal(SIGQUIT, SIG_IGN); 519#if defined(SIGCHLD) 520#if _lib_sigprocmask 521 sigemptyset(&mask); 522 sigaddset(&mask, SIGCHLD); 523 sigprocmask(SIG_BLOCK, &mask, &proc->mask); 524#else 525#if _lib_sigsetmask 526 mask = sigmask(SIGCHLD); 527 proc->mask = sigblock(mask); 528#else 529 proc->sigchld = signal(SIGCHLD, SIG_DFL); 530#endif 531#endif 532#endif 533 } 534 if ((flags & PROC_ORPHAN) && pipe(pop)) 535 goto bad; 536 proc->pid = fork(); 537 if (!(flags & PROC_FOREGROUND)) 538 sigcritical(0); 539 else if (!proc->pid) 540 { 541 if (proc->sigint != SIG_IGN) 542 { 543 proc->sigint = SIG_DFL; 544 signal(SIGINT, proc->sigint); 545 } 546 if (proc->sigquit != SIG_IGN) 547 { 548 proc->sigquit = SIG_DFL; 549 signal(SIGQUIT, proc->sigquit); 550 } 551#if defined(SIGCHLD) 552#if _lib_sigprocmask 553 sigprocmask(SIG_SETMASK, &proc->mask, NiL); 554#else 555#if _lib_sigsetmask 556 sigsetmask(proc->mask); 557#else 558 if (proc->sigchld != SIG_IGN) 559 signal(SIGCHLD, SIG_DFL); 560#endif 561#endif 562#endif 563 } 564 else if (proc->pid == -1) 565 goto bad; 566 forked = 1; 567 } 568#endif 569 if (!proc->pid) 570 { 571#if _use_spawnveg 572 char** oenviron = 0; 573 char* oenviron0 = 0; 574 575 v = 0; 576#endif 577#if _lib_fork 578 if (flags & PROC_ORPHAN) 579 { 580 if (!(proc->pid = fork())) 581 { 582 close(pop[0]); 583 close(pop[1]); 584 } 585 else 586 { 587 if (proc->pid > 0) 588 write(pop[1], &proc->pid, sizeof(proc->pid)); 589 _exit(EXIT_NOEXEC); 590 } 591 } 592#endif 593#if DEBUG_PROC 594 stropt(getenv(PROC_ENV_OPTIONS), options, sizeof(*options), setopt, &debug); 595#if _lib_fork 596 if (debug & PROC_OPT_TRACE) 597 { 598 if (!fork()) 599 { 600 sfsprintf(path, sizeof(path), "%d", getppid()); 601 execlp("trace", "trace", "-p", path, NiL); 602 _exit(EXIT_NOTFOUND); 603 } 604 sleep(2); 605 } 606#endif 607#endif 608 if (flags & PROC_DAEMON) 609 { 610#ifdef SIGHUP 611 modify(proc, forked, PROC_sig_ign, SIGHUP, 0); 612#endif 613 modify(proc, forked, PROC_sig_dfl, SIGTERM, 0); 614#ifdef SIGTSTP 615 modify(proc, forked, PROC_sig_ign, SIGTSTP, 0); 616#endif 617#ifdef SIGTTIN 618 modify(proc, forked, PROC_sig_ign, SIGTTIN, 0); 619#endif 620#ifdef SIGTTOU 621 modify(proc, forked, PROC_sig_ign, SIGTTOU, 0); 622#endif 623 } 624 if (flags & (PROC_BACKGROUND|PROC_DAEMON)) 625 { 626 modify(proc, forked, PROC_sig_ign, SIGINT, 0); 627#ifdef SIGQUIT 628 modify(proc, forked, PROC_sig_ign, SIGQUIT, 0); 629#endif 630 } 631 if (flags & (PROC_DAEMON|PROC_SESSION)) 632 modify(proc, forked, PROC_sys_pgrp, -1, 0); 633 if (forked || (flags & PROC_OVERLAY)) 634 { 635 if ((flags & PROC_PRIVELEGED) && !geteuid()) 636 { 637 setuid(geteuid()); 638 setgid(getegid()); 639 } 640 if (flags & (PROC_PARANOID|PROC_GID)) 641 setgid(getgid()); 642 if (flags & (PROC_PARANOID|PROC_UID)) 643 setuid(getuid()); 644 } 645 if (procfd > 1) 646 { 647 if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[0], PROC_ARG_NULL)) 648 goto cleanup; 649 if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[1], 1)) 650 goto cleanup; 651#if _pipe_rw || _lib_socketpair 652 if (modify(proc, forked, PROC_fd_dup, 1, 0)) 653 goto cleanup; 654#else 655 if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[0], 0)) 656 goto cleanup; 657 if (poi[1] != 0 && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[1], PROC_ARG_NULL)) 658 goto cleanup; 659#endif 660 } 661 else if (procfd >= 0) 662 { 663 if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!!procfd], !!procfd)) 664 goto cleanup; 665 if (pio[!procfd] != !!procfd && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!procfd], PROC_ARG_NULL)) 666 goto cleanup; 667 } 668 if (modv) 669 for (i = 0; n = modv[i]; i++) 670 switch (PROC_OP(n)) 671 { 672 case PROC_fd_dup: 673 case PROC_fd_dup|PROC_FD_PARENT: 674 case PROC_fd_dup|PROC_FD_CHILD: 675 case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD: 676 if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), PROC_ARG(n, 2))) 677 goto cleanup; 678 break; 679 default: 680 if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), 0)) 681 goto cleanup; 682 break; 683 } 684#if _lib_fork 685 if (forked && (flags & PROC_ENVCLEAR)) 686 environ = 0; 687#if _use_spawnveg 688 else 689#endif 690#endif 691#if _use_spawnveg 692 if (newenv) 693 { 694 p = environ; 695 while (*p++); 696 if (!(oenviron = (char**)memdup(environ, (p - environ) * sizeof(char*)))) 697 goto cleanup; 698 } 699#endif 700 if (argv && envv != (char**)environ) 701 { 702#if _use_spawnveg 703 if (!newenv && environ[0][0] == '_' && environ[0][1] == '=') 704 oenviron0 = environ[0]; 705#endif 706 env[0] = '_'; 707 env[1] = '='; 708 env[2] = 0; 709 if (!setenviron(env)) 710 goto cleanup; 711 } 712 if ((flags & PROC_PARANOID) && setenv("PATH", astconf("PATH", NiL, NiL), 1)) 713 goto cleanup; 714 if ((p = envv) && p != (char**)environ) 715 while (*p) 716 if (!setenviron(*p++)) 717 goto cleanup; 718 p = argv; 719#if _lib_fork 720 if (forked && !p) 721 return proc; 722#endif 723#if DEBUG_PROC 724 if (!(debug & PROC_OPT_EXEC) || (debug & PROC_OPT_VERBOSE)) 725 { 726 if ((debug & PROC_OPT_ENVIRONMENT) && (p = environ)) 727 while (*p) 728 sfprintf(sfstderr, "%s\n", *p++); 729 sfprintf(sfstderr, "+ %s", cmd ? path : "sh"); 730 if ((p = argv) && *p) 731 while (*++p) 732 sfprintf(sfstderr, " %s", *p); 733 sfprintf(sfstderr, "\n"); 734sfsync(sfstderr); 735 if (!(debug & PROC_OPT_EXEC)) 736 _exit(0); 737 p = argv; 738 } 739#endif 740 if (cmd) 741 { 742 strcpy(env + 2, path); 743 if (forked || (flags & PROC_OVERLAY)) 744 execve(path, p, environ); 745#if _use_spawnveg 746 else if ((proc->pid = spawnveg(path, p, environ, proc->pgrp)) != -1) 747 goto cleanup; 748#endif 749 if (errno != ENOEXEC) 750 goto cleanup; 751 752 /* 753 * try cmd as a shell script 754 */ 755 756 if (!(flags & PROC_ARGMOD)) 757 { 758 while (*p++); 759 if (!(v = newof(0, char*, p - argv + 2, 0))) 760 goto cleanup; 761 p = v + 2; 762 if (*argv) 763 argv++; 764 while (*p++ = *argv++); 765 p = v + 1; 766 } 767 *p = path; 768 *--p = "sh"; 769 } 770 strcpy(env + 2, (flags & PROC_PARANOID) ? astconf("SH", NiL, NiL) : pathshell()); 771 if (forked || (flags & PROC_OVERLAY)) 772 execve(env + 2, p, environ); 773#if _use_spawnveg 774 else 775 proc->pid = spawnveg(env + 2, p, environ, proc->pgrp); 776#endif 777 cleanup: 778 if (forked) 779 { 780 if (!(flags & PROC_OVERLAY)) 781 _exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC); 782 goto bad; 783 } 784#if _use_spawnveg 785 if (v) 786 free(v); 787 if (p = oenviron) 788 { 789 environ = 0; 790 while (*p) 791 if (!setenviron(*p++)) 792 goto bad; 793 free(oenviron); 794 } 795 else if (oenviron0) 796 environ[0] = oenviron0; 797 restore(proc); 798 if (flags & PROC_OVERLAY) 799 exit(0); 800#endif 801 } 802 if (proc->pid != -1) 803 { 804 if (!forked) 805 { 806 if (flags & PROC_FOREGROUND) 807 { 808 signalled = 1; 809 proc->sigint = signal(SIGINT, SIG_IGN); 810 proc->sigquit = signal(SIGQUIT, SIG_IGN); 811#if defined(SIGCHLD) 812#if _lib_sigprocmask 813 sigemptyset(&mask); 814 sigaddset(&mask, SIGCHLD); 815 sigprocmask(SIG_BLOCK, &mask, &proc->mask); 816#else 817#if _lib_sigsetmask 818 mask = sigmask(SIGCHLD); 819 proc->mask = sigblock(mask); 820#else 821 proc->sigchld = signal(SIGCHLD, SIG_DFL); 822#endif 823#endif 824#endif 825 } 826 } 827 else if (modv) 828 for (i = 0; n = modv[i]; i++) 829 switch (PROC_OP(n)) 830 { 831 case PROC_fd_dup|PROC_FD_PARENT: 832 case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD: 833 close(PROC_ARG(n, 1)); 834 break; 835 case PROC_sys_pgrp: 836 if (proc->pgrp < 0) 837 proc->pgrp = proc->pid; 838 else if (proc->pgrp > 0) 839 { 840 if (proc->pgrp == 1) 841 proc->pgrp = proc->pid; 842 if (setpgid(proc->pid, proc->pgrp) < 0 && proc->pid != proc->pgrp && errno == EPERM) 843 setpgid(proc->pid, proc->pid); 844 } 845 break; 846 } 847 if (procfd >= 0) 848 { 849#ifdef SIGPIPE 850 if ((flags & (PROC_WRITE|PROC_IGNORE)) == (PROC_WRITE|PROC_IGNORE)) 851 { 852 Handler_t handler; 853 854 if ((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL && handler != ignoresig) 855 signal(SIGPIPE, handler); 856 } 857#endif 858 switch (procfd) 859 { 860 case 0: 861 proc->wfd = pio[1]; 862 close(pio[0]); 863 break; 864 default: 865#if _pipe_rw || _lib_socketpair 866 proc->wfd = pio[0]; 867#else 868 proc->wfd = poi[1]; 869 close(poi[0]); 870#endif 871 /*FALLTHROUGH*/ 872 case 1: 873 proc->rfd = pio[0]; 874 close(pio[1]); 875 break; 876 } 877 if (proc->rfd > 2) 878 fcntl(proc->rfd, F_SETFD, FD_CLOEXEC); 879 if (proc->wfd > 2) 880 fcntl(proc->wfd, F_SETFD, FD_CLOEXEC); 881 } 882 if (!proc->pid) 883 proc->pid = getpid(); 884 else if (flags & PROC_ORPHAN) 885 { 886 while (waitpid(proc->pid, &i, 0) == -1 && errno == EINTR); 887 if (read(pop[0], &proc->pid, sizeof(proc->pid)) != sizeof(proc->pid)) 888 goto bad; 889 close(pop[0]); 890 } 891 return proc; 892 } 893 bad: 894 if (signalled) 895 { 896 if (proc->sigint != SIG_IGN) 897 signal(SIGINT, proc->sigint); 898 if (proc->sigquit != SIG_IGN) 899 signal(SIGQUIT, proc->sigquit); 900#if defined(SIGCHLD) 901#if _lib_sigprocmask 902 sigprocmask(SIG_SETMASK, &proc->mask, NiL); 903#else 904#if _lib_sigsetmask 905 sigsetmask(proc->mask); 906#else 907 if (proc->sigchld != SIG_DFL) 908 signal(SIGCHLD, proc->sigchld); 909#endif 910#endif 911#endif 912 } 913 if ((flags & PROC_CLEANUP) && modv) 914 for (i = 0; n = modv[i]; i++) 915 switch (PROC_OP(n)) 916 { 917 case PROC_fd_dup: 918 case PROC_fd_dup|PROC_FD_PARENT: 919 case PROC_fd_dup|PROC_FD_CHILD: 920 case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD: 921 if (PROC_ARG(n, 2) != PROC_ARG_NULL) 922 close(PROC_ARG(n, 1)); 923 break; 924 } 925 if (pio[0] >= 0) 926 close(pio[0]); 927 if (pio[1] >= 0) 928 close(pio[1]); 929 if (pop[0] >= 0) 930 close(pop[0]); 931 if (pop[1] >= 0) 932 close(pop[1]); 933#if !_pipe_rw && !_lib_socketpair 934 if (poi[0] >= 0) 935 close(poi[0]); 936 if (poi[1] >= 0) 937 close(poi[1]); 938#endif 939 procfree(proc); 940 return 0; 941} 942