14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1985-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.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
setopt(register void * a,register const void * p,register int n,const char * v)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
ignoresig(int sig)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
modify(Proc_t * proc,int forked,int op,long arg1,long arg2)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
restore(Proc_t * proc)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*
procopen(const char * cmd,char ** argv,char ** envv,long * modv,int flags)3638462SApril.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;
3718462SApril.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 {
4738462SApril.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);
4858462SApril.Chin@Sun.COM #else
4868462SApril.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)
4978462SApril.Chin@Sun.COM {
4984887Schin proc->sigint = SIG_DFL;
4998462SApril.Chin@Sun.COM signal(SIGINT, proc->sigint);
5008462SApril.Chin@Sun.COM }
5014887Schin if (proc->sigquit != SIG_IGN)
5028462SApril.Chin@Sun.COM {
5034887Schin proc->sigquit = SIG_DFL;
5048462SApril.Chin@Sun.COM signal(SIGQUIT, proc->sigquit);
5058462SApril.Chin@Sun.COM }
5064887Schin #if defined(SIGCHLD)
5078462SApril.Chin@Sun.COM #if _lib_sigprocmask
5088462SApril.Chin@Sun.COM sigprocmask(SIG_SETMASK, &proc->mask, NiL);
5098462SApril.Chin@Sun.COM #else
5108462SApril.Chin@Sun.COM #if _lib_sigsetmask
5118462SApril.Chin@Sun.COM sigsetmask(proc->mask);
5128462SApril.Chin@Sun.COM #else
5134887Schin if (proc->sigchld != SIG_IGN)
5148462SApril.Chin@Sun.COM signal(SIGCHLD, SIG_DFL);
5158462SApril.Chin@Sun.COM #endif
5168462SApril.Chin@Sun.COM #endif
5174887Schin #endif
5184887Schin }
5198462SApril.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 {
7478462SApril.Chin@Sun.COM signalled = 1;
7484887Schin proc->sigint = signal(SIGINT, SIG_IGN);
7494887Schin proc->sigquit = signal(SIGQUIT, SIG_IGN);
7504887Schin #if defined(SIGCHLD)
7518462SApril.Chin@Sun.COM #if _lib_sigprocmask
7528462SApril.Chin@Sun.COM sigemptyset(&mask);
7538462SApril.Chin@Sun.COM sigaddset(&mask, SIGCHLD);
7548462SApril.Chin@Sun.COM sigprocmask(SIG_BLOCK, &mask, &proc->mask);
7558462SApril.Chin@Sun.COM #else
7568462SApril.Chin@Sun.COM #if _lib_sigsetmask
7578462SApril.Chin@Sun.COM mask = sigmask(SIGCHLD);
7588462SApril.Chin@Sun.COM proc->mask = sigblock(mask);
7598462SApril.Chin@Sun.COM #else
7604887Schin proc->sigchld = signal(SIGCHLD, SIG_DFL);
7614887Schin #endif
7628462SApril.Chin@Sun.COM #endif
7638462SApril.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:
8268462SApril.Chin@Sun.COM if (signalled)
8278462SApril.Chin@Sun.COM {
8288462SApril.Chin@Sun.COM if (proc->sigint != SIG_IGN)
8298462SApril.Chin@Sun.COM signal(SIGINT, proc->sigint);
8308462SApril.Chin@Sun.COM if (proc->sigquit != SIG_IGN)
8318462SApril.Chin@Sun.COM signal(SIGQUIT, proc->sigquit);
8328462SApril.Chin@Sun.COM #if defined(SIGCHLD)
8338462SApril.Chin@Sun.COM #if _lib_sigprocmask
8348462SApril.Chin@Sun.COM sigprocmask(SIG_SETMASK, &proc->mask, NiL);
8358462SApril.Chin@Sun.COM #else
8368462SApril.Chin@Sun.COM #if _lib_sigsetmask
8378462SApril.Chin@Sun.COM sigsetmask(proc->mask);
8388462SApril.Chin@Sun.COM #else
8398462SApril.Chin@Sun.COM if (proc->sigchld != SIG_DFL)
8408462SApril.Chin@Sun.COM signal(SIGCHLD, proc->sigchld);
8418462SApril.Chin@Sun.COM #endif
8428462SApril.Chin@Sun.COM #endif
8438462SApril.Chin@Sun.COM #endif
8448462SApril.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