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