summaryrefslogtreecommitdiff
path: root/usr/src/lib/libast/common/misc/procopen.c
diff options
context:
space:
mode:
authorchin <none@none>2007-08-17 12:01:52 -0700
committerchin <none@none>2007-08-17 12:01:52 -0700
commitda2e3ebdc1edfbc5028edf1354e7dd2fa69a7968 (patch)
tree5280d3b78e289fe9551371ab6e7f15ef9944ea14 /usr/src/lib/libast/common/misc/procopen.c
parent073dbf9103ef2a2b05d8a16e2d26db04e0374b0e (diff)
downloadillumos-gate-da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968.tar.gz
6437624 RFE: Add ksh93 (as /usr/bin/ksh93) and libshell.so to OS/Net
6505835 AST tools and library (libpp) required for creating l10n messages for ksh93 PSARC/2006/550 Korn Shell 93 Integration PSARC/2006/587 /etc/ksh.kshrc for ksh93 PSARC/2007/035 ksh93 Amendments Contributed by Roland Mainz <roland.mainz@nrubsig.org> --HG-- rename : usr/src/lib/libcmd/common/mapfile-vers => deleted_files/usr/src/lib/libcmd/common/mapfile-vers rename : usr/src/lib/libcmd/common/placeholder.c => deleted_files/usr/src/lib/libcmd/common/placeholder.c
Diffstat (limited to 'usr/src/lib/libast/common/misc/procopen.c')
-rw-r--r--usr/src/lib/libast/common/misc/procopen.c825
1 files changed, 825 insertions, 0 deletions
diff --git a/usr/src/lib/libast/common/misc/procopen.c b/usr/src/lib/libast/common/misc/procopen.c
new file mode 100644
index 0000000000..bdb845a671
--- /dev/null
+++ b/usr/src/lib/libast/common/misc/procopen.c
@@ -0,0 +1,825 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2007 AT&T Knowledge Ventures *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Knowledge Ventures *
+* *
+* A copy of the License is available at *
+* http://www.opensource.org/licenses/cpl1.0.txt *
+* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* David Korn <dgk@research.att.com> *
+* Phong Vo <kpv@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * common process execution support with
+ * proper sfio, signal and wait() syncronization
+ *
+ * _ contains the process path name and is
+ * placed at the top of the environment
+ */
+
+#include "proclib.h"
+
+#include <ls.h>
+
+/*
+ * not quite ready for _use_spawnveg
+ */
+
+#if _use_spawnveg && _lib_fork
+#undef _use_spawnveg
+#endif
+
+#ifndef DEBUG_PROC
+#define DEBUG_PROC 1
+#endif
+
+#if _lib_socketpair
+#if _sys_socket
+#include <sys/types.h>
+#include <sys/socket.h>
+#else
+#undef _lib_socketpair
+#endif
+#endif
+
+Proc_t proc_default = { -1 };
+
+#if DEBUG_PROC
+
+#include <namval.h>
+
+#define PROC_ENV_OPTIONS "PROC_OPTIONS"
+
+#define PROC_OPT_ENVIRONMENT (1<<0)
+#define PROC_OPT_EXEC (1<<1)
+#define PROC_OPT_TRACE (1<<2)
+#define PROC_OPT_VERBOSE (1<<3)
+
+static const Namval_t options[] =
+{
+ "debug", PROC_OPT_VERBOSE,
+ "environment", PROC_OPT_ENVIRONMENT,
+ "exec", PROC_OPT_EXEC,
+ "trace", PROC_OPT_TRACE,
+ "verbose", PROC_OPT_VERBOSE,
+ 0, 0
+};
+
+/*
+ * called by stropt() to set options
+ */
+
+static int
+setopt(register void* a, register const void* p, register int n, const char* v)
+{
+ NoP(v);
+ if (p)
+ {
+ if (n)
+ *((int*)a) |= ((Namval_t*)p)->value;
+ else
+ *((int*)a) &= ~((Namval_t*)p)->value;
+ }
+ return 0;
+}
+
+#endif
+
+#if _use_spawnveg
+
+typedef struct Fd_s
+{
+ short fd;
+ short flag;
+} Fd_t;
+
+typedef struct Mod_s
+{
+ struct Mod_s* next;
+ short op;
+ short save;
+
+ union
+ {
+
+ struct
+ {
+ Fd_t parent;
+ Fd_t child;
+ } fd;
+
+ Handler_t handler;
+
+ } arg;
+
+} Modify_t;
+
+#endif
+
+#ifdef SIGPIPE
+
+/*
+ * catch but ignore sig
+ * avoids SIG_IGN being passed to children
+ */
+
+static void
+ignoresig(int sig)
+{
+ signal(sig, ignoresig);
+}
+
+#endif
+
+/*
+ * do modification op and save previous state for restore()
+ */
+
+static int
+modify(Proc_t* proc, int forked, int op, long arg1, long arg2)
+{
+#if _lib_fork
+ if (forked)
+ {
+ switch (op)
+ {
+ case PROC_fd_dup:
+ case PROC_fd_dup|PROC_FD_PARENT:
+ case PROC_fd_dup|PROC_FD_CHILD:
+ case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
+ if (arg1 != arg2)
+ {
+ if (arg2 != PROC_ARG_NULL)
+ {
+ close(arg2);
+ if (fcntl(arg1, F_DUPFD, arg2) != arg2)
+ return -1;
+ }
+ if (op & PROC_FD_CHILD)
+ close(arg1);
+ }
+ break;
+ case PROC_sig_dfl:
+ signal(arg1, SIG_DFL);
+ break;
+ case PROC_sig_ign:
+ signal(arg1, SIG_IGN);
+ break;
+ case PROC_sys_pgrp:
+ if (arg1 < 0)
+ setsid();
+ else if (arg1 > 0)
+ {
+ if (arg1 == 1)
+ arg1 = 0;
+ if (setpgid(0, arg1) < 0 && arg1 && errno == EPERM)
+ setpgid(0, 0);
+ }
+ break;
+ case PROC_sys_umask:
+ umask(arg1);
+ break;
+ default:
+ return -1;
+ }
+ }
+#if _use_spawnveg
+ else
+#endif
+#else
+ NoP(forked);
+#endif
+#if _use_spawnveg
+ {
+ register Modify_t* m;
+
+ if (!(m = newof(NiL, Modify_t, 1, 0)))
+ return -1;
+ m->next = proc->mods;
+ proc->mods = m;
+ switch (m->op = op)
+ {
+ case PROC_fd_dup:
+ case PROC_fd_dup|PROC_FD_PARENT:
+ case PROC_fd_dup|PROC_FD_CHILD:
+ case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
+ m->arg.fd.parent.fd = (short)arg1;
+ m->arg.fd.parent.flag = fcntl(arg1, F_GETFD, 0);
+ if ((m->arg.fd.child.fd = (short)arg2) != arg1)
+ {
+ if (arg2 != PROC_ARG_NULL)
+ {
+ m->arg.fd.child.flag = fcntl(arg2, F_GETFD, 0);
+ if ((m->save = fcntl(arg2, F_DUPFD, 3)) < 0)
+ {
+ m->op = 0;
+ return -1;
+ }
+ fcntl(m->save, F_SETFD, FD_CLOEXEC);
+ close(arg2);
+ if (fcntl(arg1, F_DUPFD, arg2) != arg2)
+ return -1;
+ if (op & PROC_FD_CHILD)
+ close(arg1);
+ }
+ else if (op & PROC_FD_CHILD)
+ {
+ if (m->arg.fd.parent.flag)
+ break;
+ fcntl(arg1, F_SETFD, FD_CLOEXEC);
+ }
+ else if (!m->arg.fd.parent.flag)
+ break;
+ else
+ fcntl(arg1, F_SETFD, 0);
+ return 0;
+ }
+ break;
+ case PROC_sig_dfl:
+ if ((m->arg.handler = signal(arg1, SIG_DFL)) == SIG_DFL)
+ break;
+ m->save = (short)arg1;
+ return 0;
+ case PROC_sig_ign:
+ if ((m->arg.handler = signal(arg1, SIG_IGN)) == SIG_IGN)
+ break;
+ m->save = (short)arg1;
+ return 0;
+ case PROC_sys_pgrp:
+ proc->pgrp = arg1;
+ break;
+ case PROC_sys_umask:
+ if ((m->save = (short)umask(arg1)) == arg1)
+ break;
+ return 0;
+ default:
+ proc->mods = m->next;
+ free(m);
+ return -1;
+ }
+ proc->mods = m->next;
+ free(m);
+ }
+#else
+ NoP(proc);
+#endif
+ return 0;
+}
+
+#if _use_spawnveg
+
+/*
+ * restore modifications
+ */
+
+static void
+restore(Proc_t* proc)
+{
+ register Modify_t* m;
+ register Modify_t* p;
+ int oerrno;
+
+ NoP(proc);
+ oerrno = errno;
+ m = proc->mods;
+ proc->mods = 0;
+ while (m)
+ {
+ switch (m->op)
+ {
+ case PROC_fd_dup:
+ case PROC_fd_dup|PROC_FD_PARENT:
+ case PROC_fd_dup|PROC_FD_CHILD:
+ case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
+ if (m->op & PROC_FD_PARENT)
+ close(m->arg.fd.parent.fd);
+ if (m->arg.fd.child.fd != m->arg.fd.parent.fd && m->arg.fd.child.fd != PROC_ARG_NULL)
+ {
+ if (!(m->op & PROC_FD_PARENT))
+ {
+ if (m->op & PROC_FD_CHILD)
+ {
+ close(m->arg.fd.parent.fd);
+ fcntl(m->arg.fd.child.fd, F_DUPFD, m->arg.fd.parent.fd);
+ }
+ fcntl(m->arg.fd.parent.fd, F_SETFD, m->arg.fd.parent.flag);
+ }
+ close(m->arg.fd.child.fd);
+ fcntl(m->save, F_DUPFD, m->arg.fd.child.fd);
+ close(m->save);
+ if (m->arg.fd.child.flag)
+ fcntl(m->arg.fd.child.fd, F_SETFD, FD_CLOEXEC);
+ }
+ else if ((m->op & (PROC_FD_PARENT|PROC_FD_CHILD)) == PROC_FD_CHILD)
+ fcntl(m->arg.fd.parent.fd, F_SETFD, 0);
+ break;
+ case PROC_sig_dfl:
+ case PROC_sig_ign:
+ signal(m->save, m->arg.handler);
+ break;
+ case PROC_sys_umask:
+ umask(m->save);
+ break;
+ }
+ p = m;
+ m = m->next;
+ free(p);
+ }
+ errno = oerrno;
+}
+
+#else
+
+#define restore(p)
+
+#endif
+
+/*
+ * fork and exec or spawn proc(argv) and return a Proc_t handle
+ *
+ * pipe not used when PROC_READ|PROC_WRITE omitted
+ * argv==0 duplicates current process if possible
+ * cmd==0 names the current shell
+ * cmd=="" does error cleanup
+ * envv is the child environment
+ * modv is the child modification vector of PROC_*() ops
+ */
+
+Proc_t*
+procopen(const char* cmd, char** argv, char** envv, long* modv, long flags)
+{
+ register Proc_t* proc = 0;
+ register int procfd;
+ register char** p;
+ char** v;
+ int i;
+ int forked = 0;
+ long n;
+ char path[PATH_MAX];
+ char env[PATH_MAX + 2];
+ int pio[2];
+#if !_pipe_rw && !_lib_socketpair
+ int poi[2];
+#endif
+#if defined(SIGCHLD) && ( _lib_sigprocmask || _lib_sigsetmask )
+ Sig_mask_t mask;
+#endif
+#if _use_spawnveg
+ int newenv = 0;
+#endif
+#if DEBUG_PROC
+ int debug = PROC_OPT_EXEC;
+#endif
+
+#if _lib_fork
+ if (!argv && (flags & PROC_OVERLAY))
+#else
+ if (!argv)
+#endif
+ {
+ errno = ENOEXEC;
+ return 0;
+ }
+ pio[0] = pio[1] = -1;
+#if !_pipe_rw && !_lib_socketpair
+ poi[0] = poi[1] = -1;
+#endif
+ if (cmd && (!*cmd || !pathpath(path, cmd, NiL, PATH_REGULAR|PATH_EXECUTE)))
+ goto bad;
+ switch (flags & (PROC_READ|PROC_WRITE))
+ {
+ case 0:
+ procfd = -1;
+ break;
+ case PROC_READ:
+ procfd = 1;
+ break;
+ case PROC_WRITE:
+ procfd = 0;
+ break;
+ case PROC_READ|PROC_WRITE:
+ procfd = 2;
+ break;
+ }
+ if (proc_default.pid == -1)
+ proc = &proc_default;
+ else if (!(proc = newof(0, Proc_t, 1, 0)))
+ goto bad;
+ proc->pid = -1;
+ proc->pgrp = 0;
+ proc->rfd = -1;
+ proc->wfd = -1;
+ proc->flags = flags;
+ sfsync(NiL);
+ if (environ && envv != (char**)environ && (envv || (flags & PROC_PARANOID) || argv && (environ[0][0] != '_' || environ[0][1] != '=')))
+ {
+ if (!setenviron(NiL))
+ goto bad;
+#if _use_spawnveg
+ newenv = 1;
+#endif
+ }
+ if (procfd >= 0)
+ {
+#if _pipe_rw
+ if (pipe(pio))
+ goto bad;
+#else
+ if (procfd > 1)
+ {
+#if _lib_socketpair
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, pio))
+ goto bad;
+#else
+ if (pipe(pio) || pipe(poi))
+ goto bad;
+#endif
+ }
+ else if (pipe(pio))
+ goto bad;
+#endif
+ }
+ if (flags & PROC_OVERLAY)
+ {
+ proc->pid = 0;
+ forked = 1;
+ }
+#if _use_spawnveg
+ else if (argv)
+ proc->pid = 0;
+#endif
+#if _lib_fork
+ else
+ {
+ if (!(flags & PROC_FOREGROUND))
+ sigcritical(SIG_REG_EXEC|SIG_REG_PROC);
+ else
+ {
+ proc->sigint = signal(SIGINT, SIG_IGN);
+ proc->sigquit = signal(SIGQUIT, SIG_IGN);
+#if defined(SIGCHLD)
+ proc->sigchld = signal(SIGCHLD, SIG_DFL);
+#if _lib_sigprocmask
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &mask, &proc->mask);
+#else
+#if _lib_sigsetmask
+ mask = sigmask(SIGCHLD);
+ proc->mask = sigblock(mask);
+#endif
+#endif
+#endif
+ }
+ proc->pid = fork();
+ if (!(flags & PROC_FOREGROUND))
+ sigcritical(0);
+ else if (!proc->pid)
+ {
+ if (proc->sigint != SIG_IGN)
+ proc->sigint = SIG_DFL;
+ signal(SIGINT, proc->sigint);
+ if (proc->sigquit != SIG_IGN)
+ proc->sigquit = SIG_DFL;
+ signal(SIGQUIT, proc->sigquit);
+#if defined(SIGCHLD)
+ if (proc->sigchld != SIG_IGN)
+ proc->sigchld = SIG_DFL;
+ signal(SIGCHLD, proc->sigchld);
+#endif
+ }
+ if (proc->pid == -1)
+ goto bad;
+ forked = 1;
+ }
+#endif
+ if (!proc->pid)
+ {
+ char* s;
+#if _use_spawnveg
+ char** oenviron = 0;
+ char* oenviron0 = 0;
+
+ v = 0;
+#endif
+#if DEBUG_PROC
+ stropt(getenv(PROC_ENV_OPTIONS), options, sizeof(*options), setopt, &debug);
+#if _lib_fork
+ if (debug & PROC_OPT_TRACE)
+ {
+ if (!fork())
+ {
+ sfsprintf(path, sizeof(path), "%d", getppid());
+ execlp("trace", "trace", "-p", path, NiL);
+ _exit(EXIT_NOTFOUND);
+ }
+ sleep(2);
+ }
+#endif
+#endif
+ if (flags & PROC_DAEMON)
+ {
+#ifdef SIGHUP
+ modify(proc, forked, PROC_sig_ign, SIGHUP, 0);
+#endif
+ modify(proc, forked, PROC_sig_dfl, SIGTERM, 0);
+#ifdef SIGTSTP
+ modify(proc, forked, PROC_sig_ign, SIGTSTP, 0);
+#endif
+#ifdef SIGTTIN
+ modify(proc, forked, PROC_sig_ign, SIGTTIN, 0);
+#endif
+#ifdef SIGTTOU
+ modify(proc, forked, PROC_sig_ign, SIGTTOU, 0);
+#endif
+ }
+ if (flags & (PROC_BACKGROUND|PROC_DAEMON))
+ {
+ modify(proc, forked, PROC_sig_ign, SIGINT, 0);
+#ifdef SIGQUIT
+ modify(proc, forked, PROC_sig_ign, SIGQUIT, 0);
+#endif
+ }
+ if (flags & (PROC_DAEMON|PROC_SESSION))
+ modify(proc, forked, PROC_sys_pgrp, -1, 0);
+ if (forked || (flags & PROC_OVERLAY))
+ {
+ if ((flags & PROC_PRIVELEGED) && !geteuid())
+ {
+ setuid(geteuid());
+ setgid(getegid());
+ }
+ if (flags & (PROC_PARANOID|PROC_GID))
+ setgid(getgid());
+ if (flags & (PROC_PARANOID|PROC_UID))
+ setuid(getuid());
+ }
+ if (procfd > 1)
+ {
+ if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[0], PROC_ARG_NULL))
+ goto cleanup;
+ if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[1], 1))
+ goto cleanup;
+#if _pipe_rw || _lib_socketpair
+ if (modify(proc, forked, PROC_fd_dup, 1, 0))
+ goto cleanup;
+#else
+ if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[0], 0))
+ goto cleanup;
+ if (poi[1] != 0 && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, poi[1], PROC_ARG_NULL))
+ goto cleanup;
+#endif
+ }
+ else if (procfd >= 0)
+ {
+ if (modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!!procfd], !!procfd))
+ goto cleanup;
+ if (pio[!procfd] != !!procfd && modify(proc, forked, PROC_fd_dup|PROC_FD_CHILD, pio[!procfd], PROC_ARG_NULL))
+ goto cleanup;
+ }
+ if (modv)
+ for (i = 0; n = modv[i]; i++)
+ switch (PROC_OP(n))
+ {
+ case PROC_fd_dup:
+ case PROC_fd_dup|PROC_FD_PARENT:
+ case PROC_fd_dup|PROC_FD_CHILD:
+ case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
+ if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), PROC_ARG(n, 2)))
+ goto cleanup;
+ break;
+ default:
+ if (modify(proc, forked, PROC_OP(n), PROC_ARG(n, 1), 0))
+ goto cleanup;
+ break;
+ }
+#if _lib_fork
+ if (forked && (flags & PROC_ENVCLEAR))
+ environ = 0;
+#if _use_spawnveg
+ else
+#endif
+#endif
+#if _use_spawnveg
+ if (newenv)
+ {
+ p = environ;
+ while (*p++);
+ if (!(oenviron = (char**)memdup(environ, (p - environ) * sizeof(char*))))
+ goto cleanup;
+ }
+#endif
+ if (argv && envv != (char**)environ)
+ {
+#if _use_spawnveg
+ if (!newenv && environ[0][0] == '_' && environ[0][1] == '=')
+ oenviron0 = environ[0];
+#endif
+ env[0] = '_';
+ env[1] = '=';
+ env[2] = 0;
+ if (!setenviron(env))
+ goto cleanup;
+ }
+ if ((flags & PROC_PARANOID) && setenv("PATH", astconf("PATH", NiL, NiL), 1))
+ goto cleanup;
+ if ((p = envv) && p != (char**)environ)
+ while (*p)
+ if (!setenviron(*p++))
+ goto cleanup;
+ p = argv;
+#if _lib_fork
+ if (forked && !p)
+ return proc;
+#endif
+#if DEBUG_PROC
+ if (!(debug & PROC_OPT_EXEC) || (debug & PROC_OPT_VERBOSE))
+ {
+ if ((debug & PROC_OPT_ENVIRONMENT) && (p = environ))
+ while (*p)
+ sfprintf(sfstderr, "%s\n", *p++);
+ sfprintf(sfstderr, "+ %s", cmd ? path : "sh");
+ if ((p = argv) && *p)
+ while (*++p)
+ sfprintf(sfstderr, " %s", *p);
+ sfprintf(sfstderr, "\n");
+sfsync(sfstderr);
+ if (!(debug & PROC_OPT_EXEC))
+ _exit(0);
+ p = argv;
+ }
+#endif
+ if (cmd)
+ {
+ strcpy(env + 2, path);
+ if (forked || (flags & PROC_OVERLAY))
+ execve(path, p, environ);
+#if _use_spawnveg
+ else if ((proc->pid = spawnveg(path, p, environ, proc->pgrp)) != -1)
+ goto cleanup;
+#endif
+ if (errno != ENOEXEC)
+ goto cleanup;
+
+ /*
+ * try cmd as a shell script
+ */
+
+ if (!(flags & PROC_ARGMOD))
+ {
+ while (*p++);
+ if (!(v = newof(0, char*, p - argv + 2, 0)))
+ goto cleanup;
+ p = v + 2;
+ if (*argv)
+ argv++;
+ while (*p++ = *argv++);
+ p = v + 1;
+ }
+ *p = path;
+ *--p = "sh";
+ }
+ strcpy(env + 2, (flags & PROC_PARANOID) ? astconf("SH", NiL, NiL) : pathshell());
+ if (forked || (flags & PROC_OVERLAY))
+ execve(env + 2, p, environ);
+#if _use_spawnveg
+ else
+ proc->pid = spawnveg(env + 2, p, environ, proc->pgrp);
+#endif
+ cleanup:
+ if (forked)
+ {
+ if (!(flags & PROC_OVERLAY))
+ _exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC);
+ goto bad;
+ }
+#if _use_spawnveg
+ if (v)
+ free(v);
+ if (p = oenviron)
+ {
+ environ = 0;
+ while (*p)
+ if (!setenviron(*p++))
+ goto bad;
+ free(oenviron);
+ }
+ else if (oenviron0)
+ environ[0] = oenviron0;
+ restore(proc);
+ if (flags & PROC_OVERLAY)
+ exit(0);
+#endif
+ }
+ if (proc->pid != -1)
+ {
+ if (!forked)
+ {
+ if (flags & PROC_FOREGROUND)
+ {
+ proc->sigint = signal(SIGINT, SIG_IGN);
+ proc->sigquit = signal(SIGQUIT, SIG_IGN);
+#if defined(SIGCHLD)
+ proc->sigchld = signal(SIGCHLD, SIG_DFL);
+#endif
+ }
+ }
+ else if (modv)
+ for (i = 0; n = modv[i]; i++)
+ switch (PROC_OP(n))
+ {
+ case PROC_fd_dup|PROC_FD_PARENT:
+ case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
+ close(PROC_ARG(n, 1));
+ break;
+ case PROC_sys_pgrp:
+ if (proc->pgrp < 0)
+ proc->pgrp = proc->pid;
+ else if (proc->pgrp > 0)
+ {
+ if (proc->pgrp == 1)
+ proc->pgrp = proc->pid;
+ if (setpgid(proc->pid, proc->pgrp) < 0 && proc->pid != proc->pgrp && errno == EPERM)
+ setpgid(proc->pid, proc->pid);
+ }
+ break;
+ }
+ if (procfd >= 0)
+ {
+#ifdef SIGPIPE
+ if ((flags & (PROC_WRITE|PROC_IGNORE)) == (PROC_WRITE|PROC_IGNORE))
+ {
+ Handler_t handler;
+
+ if ((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL && handler != ignoresig)
+ signal(SIGPIPE, handler);
+ }
+#endif
+ switch (procfd)
+ {
+ case 0:
+ proc->wfd = pio[1];
+ close(pio[0]);
+ break;
+ default:
+#if _pipe_rw || _lib_socketpair
+ proc->wfd = pio[0];
+#else
+ proc->wfd = poi[1];
+ close(poi[0]);
+#endif
+ /*FALLTHROUGH*/
+ case 1:
+ proc->rfd = pio[0];
+ close(pio[1]);
+ break;
+ }
+ if (proc->rfd > 2)
+ fcntl(proc->rfd, F_SETFD, FD_CLOEXEC);
+ if (proc->wfd > 2)
+ fcntl(proc->wfd, F_SETFD, FD_CLOEXEC);
+ }
+ if (!proc->pid)
+ proc->pid = getpid();
+ return proc;
+ }
+ bad:
+ if ((flags & PROC_CLEANUP) && modv)
+ for (i = 0; n = modv[i]; i++)
+ switch (PROC_OP(n))
+ {
+ case PROC_fd_dup:
+ case PROC_fd_dup|PROC_FD_PARENT:
+ case PROC_fd_dup|PROC_FD_CHILD:
+ case PROC_fd_dup|PROC_FD_PARENT|PROC_FD_CHILD:
+ if (PROC_ARG(n, 2) != PROC_ARG_NULL)
+ close(PROC_ARG(n, 1));
+ break;
+ }
+ if (pio[0] >= 0)
+ close(pio[0]);
+ if (pio[1] >= 0)
+ close(pio[1]);
+#if !_pipe_rw && !_lib_socketpair
+ if (poi[0] >= 0)
+ close(poi[0]);
+ if (poi[1] >= 0)
+ close(poi[1]);
+#endif
+ procfree(proc);
+ return 0;
+}