14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1985-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * Glenn Fowler <gsf@research.att.com> * 184887Schin * David Korn <dgk@research.att.com> * 194887Schin * Phong Vo <kpv@research.att.com> * 204887Schin * * 214887Schin ***********************************************************************/ 224887Schin #pragma prototyped 234887Schin /* 244887Schin * Glenn Fowler 254887Schin * AT&T Research 264887Schin * 274887Schin * common process execution support with 284887Schin * proper sfio, signal and wait() syncronization 294887Schin * 304887Schin * _ contains the process path name and is 314887Schin * placed at the top of the environment 324887Schin */ 334887Schin 344887Schin #include "proclib.h" 354887Schin 364887Schin #include <ls.h> 374887Schin 384887Schin /* 394887Schin * not quite ready for _use_spawnveg 404887Schin */ 414887Schin 424887Schin #if _use_spawnveg && _lib_fork 434887Schin #undef _use_spawnveg 444887Schin #endif 454887Schin 464887Schin #ifndef DEBUG_PROC 474887Schin #define DEBUG_PROC 1 484887Schin #endif 494887Schin 504887Schin #if _lib_socketpair 514887Schin #if _sys_socket 524887Schin #include <sys/types.h> 534887Schin #include <sys/socket.h> 544887Schin #else 554887Schin #undef _lib_socketpair 564887Schin #endif 574887Schin #endif 584887Schin 594887Schin Proc_t proc_default = { -1 }; 604887Schin 614887Schin #if DEBUG_PROC 624887Schin 634887Schin #include <namval.h> 644887Schin 654887Schin #define PROC_ENV_OPTIONS "PROC_OPTIONS" 664887Schin 674887Schin #define PROC_OPT_ENVIRONMENT (1<<0) 684887Schin #define PROC_OPT_EXEC (1<<1) 694887Schin #define PROC_OPT_TRACE (1<<2) 704887Schin #define PROC_OPT_VERBOSE (1<<3) 714887Schin 724887Schin static const Namval_t options[] = 734887Schin { 744887Schin "debug", PROC_OPT_VERBOSE, 754887Schin "environment", PROC_OPT_ENVIRONMENT, 764887Schin "exec", PROC_OPT_EXEC, 774887Schin "trace", PROC_OPT_TRACE, 784887Schin "verbose", PROC_OPT_VERBOSE, 794887Schin 0, 0 804887Schin }; 814887Schin 824887Schin /* 834887Schin * called by stropt() to set options 844887Schin */ 854887Schin 864887Schin static int 874887Schin setopt(register void* a, register const void* p, register int n, const char* v) 884887Schin { 894887Schin NoP(v); 904887Schin if (p) 914887Schin { 924887Schin if (n) 934887Schin *((int*)a) |= ((Namval_t*)p)->value; 944887Schin else 954887Schin *((int*)a) &= ~((Namval_t*)p)->value; 964887Schin } 974887Schin return 0; 984887Schin } 994887Schin 1004887Schin #endif 1014887Schin 1024887Schin #if _use_spawnveg 1034887Schin 1044887Schin typedef struct Fd_s 1054887Schin { 1064887Schin short fd; 1074887Schin short flag; 1084887Schin } Fd_t; 1094887Schin 1104887Schin typedef struct Mod_s 1114887Schin { 1124887Schin struct Mod_s* next; 1134887Schin short op; 1144887Schin short save; 1154887Schin 1164887Schin union 1174887Schin { 1184887Schin 1194887Schin struct 1204887Schin { 1214887Schin Fd_t parent; 1224887Schin Fd_t child; 1234887Schin } fd; 1244887Schin 1254887Schin Handler_t handler; 1264887Schin 1274887Schin } arg; 1284887Schin 1294887Schin } Modify_t; 1304887Schin 1314887Schin #endif 1324887Schin 1334887Schin #ifdef SIGPIPE 1344887Schin 1354887Schin /* 1364887Schin * catch but ignore sig 1374887Schin * avoids SIG_IGN being passed to children 1384887Schin */ 1394887Schin 1404887Schin static void 1414887Schin ignoresig(int sig) 1424887Schin { 1434887Schin signal(sig, ignoresig); 1444887Schin } 1454887Schin 1464887Schin #endif 1474887Schin 1484887Schin /* 1494887Schin * do modification op and save previous state for restore() 1504887Schin */ 1514887Schin 1524887Schin static int 1534887Schin modify(Proc_t* proc, int forked, int op, long arg1, long arg2) 1544887Schin { 1554887Schin #if _lib_fork 1564887Schin if (forked) 1574887Schin { 1584887Schin switch (op) 1594887Schin { 1604887Schin case PROC_fd_dup: 1614887Schin case PROC_fd_dup|PROC_FD_PARENT: 1624887Schin case PROC_fd_dup|PROC_FD_CHILD: 1634887Schin case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD: 1644887Schin if (arg1 != arg2) 1654887Schin { 1664887Schin if (arg2 != PROC_ARG_NULL) 1674887Schin { 1684887Schin close(arg2); 1694887Schin if (fcntl(arg1, F_DUPFD, arg2) != arg2) 1704887Schin return -1; 1714887Schin } 1724887Schin if (op & PROC_FD_CHILD) 1734887Schin close(arg1); 1744887Schin } 1754887Schin break; 1764887Schin case PROC_sig_dfl: 1774887Schin signal(arg1, SIG_DFL); 1784887Schin break; 1794887Schin case PROC_sig_ign: 1804887Schin signal(arg1, SIG_IGN); 1814887Schin break; 1824887Schin case PROC_sys_pgrp: 1834887Schin if (arg1 < 0) 1844887Schin setsid(); 1854887Schin else if (arg1 > 0) 1864887Schin { 1874887Schin if (arg1 == 1) 1884887Schin arg1 = 0; 1894887Schin if (setpgid(0, arg1) < 0 && arg1 && errno == EPERM) 1904887Schin setpgid(0, 0); 1914887Schin } 1924887Schin break; 1934887Schin case PROC_sys_umask: 1944887Schin umask(arg1); 1954887Schin break; 1964887Schin default: 1974887Schin return -1; 1984887Schin } 1994887Schin } 2004887Schin #if _use_spawnveg 2014887Schin else 2024887Schin #endif 2034887Schin #else 2044887Schin NoP(forked); 2054887Schin #endif 2064887Schin #if _use_spawnveg 2074887Schin { 2084887Schin register Modify_t* m; 2094887Schin 2104887Schin if (!(m = newof(NiL, Modify_t, 1, 0))) 2114887Schin return -1; 2124887Schin m->next = proc->mods; 2134887Schin proc->mods = m; 2144887Schin switch (m->op = op) 2154887Schin { 2164887Schin case PROC_fd_dup: 2174887Schin case PROC_fd_dup|PROC_FD_PARENT: 2184887Schin case PROC_fd_dup|PROC_FD_CHILD: 2194887Schin case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD: 2204887Schin m->arg.fd.parent.fd = (short)arg1; 2214887Schin m->arg.fd.parent.flag = fcntl(arg1, F_GETFD, 0); 2224887Schin if ((m->arg.fd.child.fd = (short)arg2) != arg1) 2234887Schin { 2244887Schin if (arg2 != PROC_ARG_NULL) 2254887Schin { 2264887Schin m->arg.fd.child.flag = fcntl(arg2, F_GETFD, 0); 2274887Schin if ((m->save = fcntl(arg2, F_DUPFD, 3)) < 0) 2284887Schin { 2294887Schin m->op = 0; 2304887Schin return -1; 2314887Schin } 2324887Schin fcntl(m->save, F_SETFD, FD_CLOEXEC); 2334887Schin close(arg2); 2344887Schin if (fcntl(arg1, F_DUPFD, arg2) != arg2) 2354887Schin return -1; 2364887Schin if (op & PROC_FD_CHILD) 2374887Schin close(arg1); 2384887Schin } 2394887Schin else if (op & PROC_FD_CHILD) 2404887Schin { 2414887Schin if (m->arg.fd.parent.flag) 2424887Schin break; 2434887Schin fcntl(arg1, F_SETFD, FD_CLOEXEC); 2444887Schin } 2454887Schin else if (!m->arg.fd.parent.flag) 2464887Schin break; 2474887Schin else 2484887Schin fcntl(arg1, F_SETFD, 0); 2494887Schin return 0; 2504887Schin } 2514887Schin break; 2524887Schin case PROC_sig_dfl: 2534887Schin if ((m->arg.handler = signal(arg1, SIG_DFL)) == SIG_DFL) 2544887Schin break; 2554887Schin m->save = (short)arg1; 2564887Schin return 0; 2574887Schin case PROC_sig_ign: 2584887Schin if ((m->arg.handler = signal(arg1, SIG_IGN)) == SIG_IGN) 2594887Schin break; 2604887Schin m->save = (short)arg1; 2614887Schin return 0; 2624887Schin case PROC_sys_pgrp: 2634887Schin proc->pgrp = arg1; 2644887Schin break; 2654887Schin case PROC_sys_umask: 2664887Schin if ((m->save = (short)umask(arg1)) == arg1) 2674887Schin break; 2684887Schin return 0; 2694887Schin default: 2704887Schin proc->mods = m->next; 2714887Schin free(m); 2724887Schin return -1; 2734887Schin } 2744887Schin proc->mods = m->next; 2754887Schin free(m); 2764887Schin } 2774887Schin #else 2784887Schin NoP(proc); 2794887Schin #endif 2804887Schin return 0; 2814887Schin } 2824887Schin 2834887Schin #if _use_spawnveg 2844887Schin 2854887Schin /* 2864887Schin * restore modifications 2874887Schin */ 2884887Schin 2894887Schin static void 2904887Schin restore(Proc_t* proc) 2914887Schin { 2924887Schin register Modify_t* m; 2934887Schin register Modify_t* p; 2944887Schin int oerrno; 2954887Schin 2964887Schin NoP(proc); 2974887Schin oerrno = errno; 2984887Schin m = proc->mods; 2994887Schin proc->mods = 0; 3004887Schin while (m) 3014887Schin { 3024887Schin switch (m->op) 3034887Schin { 3044887Schin case PROC_fd_dup: 3054887Schin case PROC_fd_dup|PROC_FD_PARENT: 3064887Schin case PROC_fd_dup|PROC_FD_CHILD: 3074887Schin case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD: 3084887Schin if (m->op & PROC_FD_PARENT) 3094887Schin close(m->arg.fd.parent.fd); 3104887Schin if (m->arg.fd.child.fd != m->arg.fd.parent.fd && m->arg.fd.child.fd != PROC_ARG_NULL) 3114887Schin { 3124887Schin if (!(m->op & PROC_FD_PARENT)) 3134887Schin { 3144887Schin if (m->op & PROC_FD_CHILD) 3154887Schin { 3164887Schin close(m->arg.fd.parent.fd); 3174887Schin fcntl(m->arg.fd.child.fd, F_DUPFD, m->arg.fd.parent.fd); 3184887Schin } 3194887Schin fcntl(m->arg.fd.parent.fd, F_SETFD, m->arg.fd.parent.flag); 3204887Schin } 3214887Schin close(m->arg.fd.child.fd); 3224887Schin fcntl(m->save, F_DUPFD, m->arg.fd.child.fd); 3234887Schin close(m->save); 3244887Schin if (m->arg.fd.child.flag) 3254887Schin fcntl(m->arg.fd.child.fd, F_SETFD, FD_CLOEXEC); 3264887Schin } 3274887Schin else if ((m->op & (PROC_FD_PARENT|PROC_FD_CHILD)) == PROC_FD_CHILD) 3284887Schin fcntl(m->arg.fd.parent.fd, F_SETFD, 0); 3294887Schin break; 3304887Schin case PROC_sig_dfl: 3314887Schin case PROC_sig_ign: 3324887Schin signal(m->save, m->arg.handler); 3334887Schin break; 3344887Schin case PROC_sys_umask: 3354887Schin umask(m->save); 3364887Schin break; 3374887Schin } 3384887Schin p = m; 3394887Schin m = m->next; 3404887Schin free(p); 3414887Schin } 3424887Schin errno = oerrno; 3434887Schin } 3444887Schin 3454887Schin #else 3464887Schin 3474887Schin #define restore(p) 3484887Schin 3494887Schin #endif 3504887Schin 3514887Schin /* 3524887Schin * fork and exec or spawn proc(argv) and return a Proc_t handle 3534887Schin * 3544887Schin * pipe not used when PROC_READ|PROC_WRITE omitted 3554887Schin * argv==0 duplicates current process if possible 3564887Schin * cmd==0 names the current shell 3574887Schin * cmd=="" does error cleanup 3584887Schin * envv is the child environment 3594887Schin * modv is the child modification vector of PROC_*() ops 3604887Schin */ 3614887Schin 3624887Schin Proc_t* 363*8462SApril.Chin@Sun.COM procopen(const char* cmd, char** argv, char** envv, long* modv, int flags) 3644887Schin { 3654887Schin register Proc_t* proc = 0; 3664887Schin register int procfd; 3674887Schin register char** p; 3684887Schin char** v; 3694887Schin int i; 3704887Schin int forked = 0; 371*8462SApril.Chin@Sun.COM int signalled = 0; 3724887Schin long n; 3734887Schin char path[PATH_MAX]; 3744887Schin char env[PATH_MAX + 2]; 3754887Schin int pio[2]; 3764887Schin #if !_pipe_rw && !_lib_socketpair 3774887Schin int poi[2]; 3784887Schin #endif 3794887Schin #if defined(SIGCHLD) && ( _lib_sigprocmask || _lib_sigsetmask ) 3804887Schin Sig_mask_t mask; 3814887Schin #endif 3824887Schin #if _use_spawnveg 3834887Schin int newenv = 0; 3844887Schin #endif 3854887Schin #if DEBUG_PROC 3864887Schin int debug = PROC_OPT_EXEC; 3874887Schin #endif 3884887Schin 3894887Schin #if _lib_fork 3904887Schin if (!argv && (flags & PROC_OVERLAY)) 3914887Schin #else 3924887Schin if (!argv) 3934887Schin #endif 3944887Schin { 3954887Schin errno = ENOEXEC; 3964887Schin return 0; 3974887Schin } 3984887Schin pio[0] = pio[1] = -1; 3994887Schin #if !_pipe_rw && !_lib_socketpair 4004887Schin poi[0] = poi[1] = -1; 4014887Schin #endif 4024887Schin if (cmd && (!*cmd || !pathpath(path, cmd, NiL, PATH_REGULAR|PATH_EXECUTE))) 4034887Schin goto bad; 4044887Schin switch (flags & (PROC_READ|PROC_WRITE)) 4054887Schin { 4064887Schin case 0: 4074887Schin procfd = -1; 4084887Schin break; 4094887Schin case PROC_READ: 4104887Schin procfd = 1; 4114887Schin break; 4124887Schin case PROC_WRITE: 4134887Schin procfd = 0; 4144887Schin break; 4154887Schin case PROC_READ|PROC_WRITE: 4164887Schin procfd = 2; 4174887Schin break; 4184887Schin } 4194887Schin if (proc_default.pid == -1) 4204887Schin proc = &proc_default; 4214887Schin else if (!(proc = newof(0, Proc_t, 1, 0))) 4224887Schin goto bad; 4234887Schin proc->pid = -1; 4244887Schin proc->pgrp = 0; 4254887Schin proc->rfd = -1; 4264887Schin proc->wfd = -1; 4274887Schin proc->flags = flags; 4284887Schin sfsync(NiL); 4294887Schin if (environ && envv != (char**)environ && (envv || (flags & PROC_PARANOID) || argv && (environ[0][0] != '_' || environ[0][1] != '='))) 4304887Schin { 4314887Schin if (!setenviron(NiL)) 4324887Schin goto bad; 4334887Schin #if _use_spawnveg 4344887Schin newenv = 1; 4354887Schin #endif 4364887Schin } 4374887Schin if (procfd >= 0) 4384887Schin { 4394887Schin #if _pipe_rw 4404887Schin if (pipe(pio)) 4414887Schin goto bad; 4424887Schin #else 4434887Schin if (procfd > 1) 4444887Schin { 4454887Schin #if _lib_socketpair 4464887Schin if (socketpair(AF_UNIX, SOCK_STREAM, 0, pio)) 4474887Schin goto bad; 4484887Schin #else 4494887Schin if (pipe(pio) || pipe(poi)) 4504887Schin goto bad; 4514887Schin #endif 4524887Schin } 4534887Schin else if (pipe(pio)) 4544887Schin goto bad; 4554887Schin #endif 4564887Schin } 4574887Schin if (flags & PROC_OVERLAY) 4584887Schin { 4594887Schin proc->pid = 0; 4604887Schin forked = 1; 4614887Schin } 4624887Schin #if _use_spawnveg 4634887Schin else if (argv) 4644887Schin proc->pid = 0; 4654887Schin #endif 4664887Schin #if _lib_fork 4674887Schin else 4684887Schin { 4694887Schin if (!(flags & PROC_FOREGROUND)) 4704887Schin sigcritical(SIG_REG_EXEC|SIG_REG_PROC); 4714887Schin else 4724887Schin { 473*8462SApril.Chin@Sun.COM signalled = 1; 4744887Schin proc->sigint = signal(SIGINT, SIG_IGN); 4754887Schin proc->sigquit = signal(SIGQUIT, SIG_IGN); 4764887Schin #if defined(SIGCHLD) 4774887Schin #if _lib_sigprocmask 4784887Schin sigemptyset(&mask); 4794887Schin sigaddset(&mask, SIGCHLD); 4804887Schin sigprocmask(SIG_BLOCK, &mask, &proc->mask); 4814887Schin #else 4824887Schin #if _lib_sigsetmask 4834887Schin mask = sigmask(SIGCHLD); 4844887Schin proc->mask = sigblock(mask); 485*8462SApril.Chin@Sun.COM #else 486*8462SApril.Chin@Sun.COM proc->sigchld = signal(SIGCHLD, SIG_DFL); 4874887Schin #endif 4884887Schin #endif 4894887Schin #endif 4904887Schin } 4914887Schin proc->pid = fork(); 4924887Schin if (!(flags & PROC_FOREGROUND)) 4934887Schin sigcritical(0); 4944887Schin else if (!proc->pid) 4954887Schin { 4964887Schin if (proc->sigint != SIG_IGN) 497*8462SApril.Chin@Sun.COM { 4984887Schin proc->sigint = SIG_DFL; 499*8462SApril.Chin@Sun.COM signal(SIGINT, proc->sigint); 500*8462SApril.Chin@Sun.COM } 5014887Schin if (proc->sigquit != SIG_IGN) 502*8462SApril.Chin@Sun.COM { 5034887Schin proc->sigquit = SIG_DFL; 504*8462SApril.Chin@Sun.COM signal(SIGQUIT, proc->sigquit); 505*8462SApril.Chin@Sun.COM } 5064887Schin #if defined(SIGCHLD) 507*8462SApril.Chin@Sun.COM #if _lib_sigprocmask 508*8462SApril.Chin@Sun.COM sigprocmask(SIG_SETMASK, &proc->mask, NiL); 509*8462SApril.Chin@Sun.COM #else 510*8462SApril.Chin@Sun.COM #if _lib_sigsetmask 511*8462SApril.Chin@Sun.COM sigsetmask(proc->mask); 512*8462SApril.Chin@Sun.COM #else 5134887Schin if (proc->sigchld != SIG_IGN) 514*8462SApril.Chin@Sun.COM signal(SIGCHLD, SIG_DFL); 515*8462SApril.Chin@Sun.COM #endif 516*8462SApril.Chin@Sun.COM #endif 5174887Schin #endif 5184887Schin } 519*8462SApril.Chin@Sun.COM else if (proc->pid == -1) 5204887Schin goto bad; 5214887Schin forked = 1; 5224887Schin } 5234887Schin #endif 5244887Schin if (!proc->pid) 5254887Schin { 5264887Schin #if _use_spawnveg 5274887Schin char** oenviron = 0; 5284887Schin char* oenviron0 = 0; 5294887Schin 5304887Schin v = 0; 5314887Schin #endif 5324887Schin #if DEBUG_PROC 5334887Schin stropt(getenv(PROC_ENV_OPTIONS), options, sizeof(*options), setopt, &debug); 5344887Schin #if _lib_fork 5354887Schin if (debug & PROC_OPT_TRACE) 5364887Schin { 5374887Schin if (!fork()) 5384887Schin { 5394887Schin sfsprintf(path, sizeof(path), "%d", getppid()); 5404887Schin execlp("trace", "trace", "-p", path, NiL); 5414887Schin _exit(EXIT_NOTFOUND); 5424887Schin } 5434887Schin sleep(2); 5444887Schin } 5454887Schin #endif 5464887Schin #endif 5474887Schin if (flags & PROC_DAEMON) 5484887Schin { 5494887Schin #ifdef SIGHUP 5504887Schin modify(proc, forked, PROC_sig_ign, SIGHUP, 0); 5514887Schin #endif 5524887Schin modify(proc, forked, PROC_sig_dfl, SIGTERM, 0); 5534887Schin #ifdef SIGTSTP 5544887Schin modify(proc, forked, PROC_sig_ign, SIGTSTP, 0); 5554887Schin #endif 5564887Schin #ifdef SIGTTIN 5574887Schin modify(proc, forked, PROC_sig_ign, SIGTTIN, 0); 5584887Schin #endif 5594887Schin #ifdef SIGTTOU 5604887Schin modify(proc, forked, PROC_sig_ign, SIGTTOU, 0); 5614887Schin #endif 5624887Schin } 5634887Schin if (flags & (PROC_BACKGROUND|PROC_DAEMON)) 5644887Schin { 5654887Schin modify(proc, forked, PROC_sig_ign, SIGINT, 0); 5664887Schin #ifdef SIGQUIT 5674887Schin modify(proc, forked, PROC_sig_ign, SIGQUIT, 0); 5684887Schin #endif 5694887Schin } 5704887Schin if (flags & (PROC_DAEMON|PROC_SESSION)) 5714887Schin modify(proc, forked, PROC_sys_pgrp, -1, 0); 5724887Schin if (forked || (flags & PROC_OVERLAY)) 5734887Schin { 5744887Schin if ((flags & PROC_PRIVELEGED) && !geteuid()) 5754887Schin { 5764887Schin setuid(geteuid()); 5774887Schin setgid(getegid()); 5784887Schin } 5794887Schin if (flags & (PROC_PARANOID|PROC_GID)) 5804887Schin setgid(getgid()); 5814887Schin if (flags & (PROC_PARANOID|PROC_UID)) 5824887Schin setuid(getuid()); 5834887Schin } 5844887Schin if (procfd > 1) 5854887Schin { 5864887Schin if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[0], PROC_ARG_NULL)) 5874887Schin goto cleanup; 5884887Schin if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[1], 1)) 5894887Schin goto cleanup; 5904887Schin #if _pipe_rw || _lib_socketpair 5914887Schin if (modify(proc, forked, PROC_fd_dup, 1, 0)) 5924887Schin goto cleanup; 5934887Schin #else 5944887Schin if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[0], 0)) 5954887Schin goto cleanup; 5964887Schin if (poi[1] != 0 && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[1], PROC_ARG_NULL)) 5974887Schin goto cleanup; 5984887Schin #endif 5994887Schin } 6004887Schin else if (procfd >= 0) 6014887Schin { 6024887Schin if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!!procfd], !!procfd)) 6034887Schin goto cleanup; 6044887Schin if (pio[!procfd] != !!procfd && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!procfd], PROC_ARG_NULL)) 6054887Schin goto cleanup; 6064887Schin } 6074887Schin if (modv) 6084887Schin for (i = 0; n = modv[i]; i++) 6094887Schin switch (PROC_OP(n)) 6104887Schin { 6114887Schin case PROC_fd_dup: 6124887Schin case PROC_fd_dup|PROC_FD_PARENT: 6134887Schin case PROC_fd_dup|PROC_FD_CHILD: 6144887Schin case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD: 6154887Schin if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), PROC_ARG(n, 2))) 6164887Schin goto cleanup; 6174887Schin break; 6184887Schin default: 6194887Schin if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), 0)) 6204887Schin goto cleanup; 6214887Schin break; 6224887Schin } 6234887Schin #if _lib_fork 6244887Schin if (forked && (flags & PROC_ENVCLEAR)) 6254887Schin environ = 0; 6264887Schin #if _use_spawnveg 6274887Schin else 6284887Schin #endif 6294887Schin #endif 6304887Schin #if _use_spawnveg 6314887Schin if (newenv) 6324887Schin { 6334887Schin p = environ; 6344887Schin while (*p++); 6354887Schin if (!(oenviron = (char**)memdup(environ, (p - environ) * sizeof(char*)))) 6364887Schin goto cleanup; 6374887Schin } 6384887Schin #endif 6394887Schin if (argv && envv != (char**)environ) 6404887Schin { 6414887Schin #if _use_spawnveg 6424887Schin if (!newenv && environ[0][0] == '_' && environ[0][1] == '=') 6434887Schin oenviron0 = environ[0]; 6444887Schin #endif 6454887Schin env[0] = '_'; 6464887Schin env[1] = '='; 6474887Schin env[2] = 0; 6484887Schin if (!setenviron(env)) 6494887Schin goto cleanup; 6504887Schin } 6514887Schin if ((flags & PROC_PARANOID) && setenv("PATH", astconf("PATH", NiL, NiL), 1)) 6524887Schin goto cleanup; 6534887Schin if ((p = envv) && p != (char**)environ) 6544887Schin while (*p) 6554887Schin if (!setenviron(*p++)) 6564887Schin goto cleanup; 6574887Schin p = argv; 6584887Schin #if _lib_fork 6594887Schin if (forked && !p) 6604887Schin return proc; 6614887Schin #endif 6624887Schin #if DEBUG_PROC 6634887Schin if (!(debug & PROC_OPT_EXEC) || (debug & PROC_OPT_VERBOSE)) 6644887Schin { 6654887Schin if ((debug & PROC_OPT_ENVIRONMENT) && (p = environ)) 6664887Schin while (*p) 6674887Schin sfprintf(sfstderr, "%s\n", *p++); 6684887Schin sfprintf(sfstderr, "+ %s", cmd ? path : "sh"); 6694887Schin if ((p = argv) && *p) 6704887Schin while (*++p) 6714887Schin sfprintf(sfstderr, " %s", *p); 6724887Schin sfprintf(sfstderr, "\n"); 6734887Schin sfsync(sfstderr); 6744887Schin if (!(debug & PROC_OPT_EXEC)) 6754887Schin _exit(0); 6764887Schin p = argv; 6774887Schin } 6784887Schin #endif 6794887Schin if (cmd) 6804887Schin { 6814887Schin strcpy(env + 2, path); 6824887Schin if (forked || (flags & PROC_OVERLAY)) 6834887Schin execve(path, p, environ); 6844887Schin #if _use_spawnveg 6854887Schin else if ((proc->pid = spawnveg(path, p, environ, proc->pgrp)) != -1) 6864887Schin goto cleanup; 6874887Schin #endif 6884887Schin if (errno != ENOEXEC) 6894887Schin goto cleanup; 6904887Schin 6914887Schin /* 6924887Schin * try cmd as a shell script 6934887Schin */ 6944887Schin 6954887Schin if (!(flags & PROC_ARGMOD)) 6964887Schin { 6974887Schin while (*p++); 6984887Schin if (!(v = newof(0, char*, p - argv + 2, 0))) 6994887Schin goto cleanup; 7004887Schin p = v + 2; 7014887Schin if (*argv) 7024887Schin argv++; 7034887Schin while (*p++ = *argv++); 7044887Schin p = v + 1; 7054887Schin } 7064887Schin *p = path; 7074887Schin *--p = "sh"; 7084887Schin } 7094887Schin strcpy(env + 2, (flags & PROC_PARANOID) ? astconf("SH", NiL, NiL) : pathshell()); 7104887Schin if (forked || (flags & PROC_OVERLAY)) 7114887Schin execve(env + 2, p, environ); 7124887Schin #if _use_spawnveg 7134887Schin else 7144887Schin proc->pid = spawnveg(env + 2, p, environ, proc->pgrp); 7154887Schin #endif 7164887Schin cleanup: 7174887Schin if (forked) 7184887Schin { 7194887Schin if (!(flags & PROC_OVERLAY)) 7204887Schin _exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC); 7214887Schin goto bad; 7224887Schin } 7234887Schin #if _use_spawnveg 7244887Schin if (v) 7254887Schin free(v); 7264887Schin if (p = oenviron) 7274887Schin { 7284887Schin environ = 0; 7294887Schin while (*p) 7304887Schin if (!setenviron(*p++)) 7314887Schin goto bad; 7324887Schin free(oenviron); 7334887Schin } 7344887Schin else if (oenviron0) 7354887Schin environ[0] = oenviron0; 7364887Schin restore(proc); 7374887Schin if (flags & PROC_OVERLAY) 7384887Schin exit(0); 7394887Schin #endif 7404887Schin } 7414887Schin if (proc->pid != -1) 7424887Schin { 7434887Schin if (!forked) 7444887Schin { 7454887Schin if (flags & PROC_FOREGROUND) 7464887Schin { 747*8462SApril.Chin@Sun.COM signalled = 1; 7484887Schin proc->sigint = signal(SIGINT, SIG_IGN); 7494887Schin proc->sigquit = signal(SIGQUIT, SIG_IGN); 7504887Schin #if defined(SIGCHLD) 751*8462SApril.Chin@Sun.COM #if _lib_sigprocmask 752*8462SApril.Chin@Sun.COM sigemptyset(&mask); 753*8462SApril.Chin@Sun.COM sigaddset(&mask, SIGCHLD); 754*8462SApril.Chin@Sun.COM sigprocmask(SIG_BLOCK, &mask, &proc->mask); 755*8462SApril.Chin@Sun.COM #else 756*8462SApril.Chin@Sun.COM #if _lib_sigsetmask 757*8462SApril.Chin@Sun.COM mask = sigmask(SIGCHLD); 758*8462SApril.Chin@Sun.COM proc->mask = sigblock(mask); 759*8462SApril.Chin@Sun.COM #else 7604887Schin proc->sigchld = signal(SIGCHLD, SIG_DFL); 7614887Schin #endif 762*8462SApril.Chin@Sun.COM #endif 763*8462SApril.Chin@Sun.COM #endif 7644887Schin } 7654887Schin } 7664887Schin else if (modv) 7674887Schin for (i = 0; n = modv[i]; i++) 7684887Schin switch (PROC_OP(n)) 7694887Schin { 7704887Schin case PROC_fd_dup|PROC_FD_PARENT: 7714887Schin case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD: 7724887Schin close(PROC_ARG(n, 1)); 7734887Schin break; 7744887Schin case PROC_sys_pgrp: 7754887Schin if (proc->pgrp < 0) 7764887Schin proc->pgrp = proc->pid; 7774887Schin else if (proc->pgrp > 0) 7784887Schin { 7794887Schin if (proc->pgrp == 1) 7804887Schin proc->pgrp = proc->pid; 7814887Schin if (setpgid(proc->pid, proc->pgrp) < 0 && proc->pid != proc->pgrp && errno == EPERM) 7824887Schin setpgid(proc->pid, proc->pid); 7834887Schin } 7844887Schin break; 7854887Schin } 7864887Schin if (procfd >= 0) 7874887Schin { 7884887Schin #ifdef SIGPIPE 7894887Schin if ((flags & (PROC_WRITE|PROC_IGNORE)) == (PROC_WRITE|PROC_IGNORE)) 7904887Schin { 7914887Schin Handler_t handler; 7924887Schin 7934887Schin if ((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL && handler != ignoresig) 7944887Schin signal(SIGPIPE, handler); 7954887Schin } 7964887Schin #endif 7974887Schin switch (procfd) 7984887Schin { 7994887Schin case 0: 8004887Schin proc->wfd = pio[1]; 8014887Schin close(pio[0]); 8024887Schin break; 8034887Schin default: 8044887Schin #if _pipe_rw || _lib_socketpair 8054887Schin proc->wfd = pio[0]; 8064887Schin #else 8074887Schin proc->wfd = poi[1]; 8084887Schin close(poi[0]); 8094887Schin #endif 8104887Schin /*FALLTHROUGH*/ 8114887Schin case 1: 8124887Schin proc->rfd = pio[0]; 8134887Schin close(pio[1]); 8144887Schin break; 8154887Schin } 8164887Schin if (proc->rfd > 2) 8174887Schin fcntl(proc->rfd, F_SETFD, FD_CLOEXEC); 8184887Schin if (proc->wfd > 2) 8194887Schin fcntl(proc->wfd, F_SETFD, FD_CLOEXEC); 8204887Schin } 8214887Schin if (!proc->pid) 8224887Schin proc->pid = getpid(); 8234887Schin return proc; 8244887Schin } 8254887Schin bad: 826*8462SApril.Chin@Sun.COM if (signalled) 827*8462SApril.Chin@Sun.COM { 828*8462SApril.Chin@Sun.COM if (proc->sigint != SIG_IGN) 829*8462SApril.Chin@Sun.COM signal(SIGINT, proc->sigint); 830*8462SApril.Chin@Sun.COM if (proc->sigquit != SIG_IGN) 831*8462SApril.Chin@Sun.COM signal(SIGQUIT, proc->sigquit); 832*8462SApril.Chin@Sun.COM #if defined(SIGCHLD) 833*8462SApril.Chin@Sun.COM #if _lib_sigprocmask 834*8462SApril.Chin@Sun.COM sigprocmask(SIG_SETMASK, &proc->mask, NiL); 835*8462SApril.Chin@Sun.COM #else 836*8462SApril.Chin@Sun.COM #if _lib_sigsetmask 837*8462SApril.Chin@Sun.COM sigsetmask(proc->mask); 838*8462SApril.Chin@Sun.COM #else 839*8462SApril.Chin@Sun.COM if (proc->sigchld != SIG_DFL) 840*8462SApril.Chin@Sun.COM signal(SIGCHLD, proc->sigchld); 841*8462SApril.Chin@Sun.COM #endif 842*8462SApril.Chin@Sun.COM #endif 843*8462SApril.Chin@Sun.COM #endif 844*8462SApril.Chin@Sun.COM } 8454887Schin if ((flags & PROC_CLEANUP) && modv) 8464887Schin for (i = 0; n = modv[i]; i++) 8474887Schin switch (PROC_OP(n)) 8484887Schin { 8494887Schin case PROC_fd_dup: 8504887Schin case PROC_fd_dup|PROC_FD_PARENT: 8514887Schin case PROC_fd_dup|PROC_FD_CHILD: 8524887Schin case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD: 8534887Schin if (PROC_ARG(n, 2) != PROC_ARG_NULL) 8544887Schin close(PROC_ARG(n, 1)); 8554887Schin break; 8564887Schin } 8574887Schin if (pio[0] >= 0) 8584887Schin close(pio[0]); 8594887Schin if (pio[1] >= 0) 8604887Schin close(pio[1]); 8614887Schin #if !_pipe_rw && !_lib_socketpair 8624887Schin if (poi[0] >= 0) 8634887Schin close(poi[0]); 8644887Schin if (poi[1] >= 0) 8654887Schin close(poi[1]); 8664887Schin #endif 8674887Schin procfree(proc); 8684887Schin return 0; 8694887Schin } 870