755 lines
17 KiB
C
755 lines
17 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* $XConsortium: procopen.c /main/3 1995/11/01 18:02:12 rswiston $ */
|
|
/***************************************************************
|
|
* *
|
|
* AT&T - PROPRIETARY *
|
|
* *
|
|
* THIS IS PROPRIETARY SOURCE CODE LICENSED BY *
|
|
* AT&T CORP. *
|
|
* *
|
|
* Copyright (c) 1995 AT&T Corp. *
|
|
* All Rights Reserved *
|
|
* *
|
|
* This software is licensed by AT&T Corp. *
|
|
* under the terms and conditions of the license in *
|
|
* http://www.research.att.com/orgs/ssr/book/reuse *
|
|
* *
|
|
* This software was created by the *
|
|
* Software Engineering Research Department *
|
|
* AT&T Bell Laboratories *
|
|
* *
|
|
* For further information contact *
|
|
* gsf@research.att.com *
|
|
* *
|
|
***************************************************************/
|
|
|
|
/* : : generated by proto : : */
|
|
|
|
#if !defined(__PROTO__)
|
|
#if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
|
|
#if defined(__cplusplus)
|
|
#define __MANGLE__ "C"
|
|
#else
|
|
#define __MANGLE__
|
|
#endif
|
|
#define __STDARG__
|
|
#define __PROTO__(x) x
|
|
#define __OTORP__(x)
|
|
#define __PARAM__(n,o) n
|
|
#if !defined(__STDC__) && !defined(__cplusplus)
|
|
#if !defined(c_plusplus)
|
|
#define const
|
|
#endif
|
|
#define signed
|
|
#define void int
|
|
#define volatile
|
|
#define __V_ char
|
|
#else
|
|
#define __V_ void
|
|
#endif
|
|
#else
|
|
#define __PROTO__(x) ()
|
|
#define __OTORP__(x) x
|
|
#define __PARAM__(n,o) o
|
|
#define __MANGLE__
|
|
#define __V_ char
|
|
#define const
|
|
#define signed
|
|
#define void int
|
|
#define volatile
|
|
#endif
|
|
#if defined(__cplusplus) || defined(c_plusplus)
|
|
#define __VARARG__ ...
|
|
#else
|
|
#define __VARARG__
|
|
#endif
|
|
#if defined(__STDARG__)
|
|
#define __VA_START__(p,a) va_start(p,a)
|
|
#else
|
|
#define __VA_START__(p,a) va_start(p)
|
|
#endif
|
|
#endif
|
|
#include "proclib.h"
|
|
|
|
#include <ls.h>
|
|
|
|
#ifndef DEBUG_PROC
|
|
#define DEBUG_PROC 1
|
|
#endif
|
|
|
|
#if USE_SPAWN > 1
|
|
#undef _lib_fork
|
|
#else
|
|
#if !_lib_fork
|
|
#undef USE_SPAWN
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef USE_SPAWN
|
|
#if !_lib_fork || _map_spawnve
|
|
#define USE_SPAWN 1
|
|
#else
|
|
#define USE_SPAWN 0
|
|
#endif
|
|
#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 __PARAM__((__V_* a, const __V_* p, int n, const char* v), (a, p, n, v)) __OTORP__(__V_* a; const __V_* p; 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_SPAWN
|
|
|
|
typedef struct
|
|
{
|
|
short fd;
|
|
short flag;
|
|
} Fd_t;
|
|
|
|
typedef struct Mod
|
|
{
|
|
struct Mod* next;
|
|
short op;
|
|
short save;
|
|
|
|
union
|
|
{
|
|
|
|
struct
|
|
{
|
|
Fd_t parent;
|
|
Fd_t child;
|
|
} fd;
|
|
|
|
Handler_t handler;
|
|
|
|
} arg;
|
|
|
|
} Modify_t;
|
|
|
|
static Modify_t* mods;
|
|
|
|
#endif
|
|
|
|
/*
|
|
* do modification op and save previous state for restore()
|
|
*/
|
|
|
|
static int
|
|
modify __PARAM__((Proc_t* proc, int forked, int op, long arg1, long arg2), (proc, forked, op, arg1, arg2)) __OTORP__(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_SPAWN
|
|
else
|
|
#endif
|
|
#else
|
|
NoP(forked);
|
|
#endif
|
|
#if USE_SPAWN
|
|
{
|
|
Modify_t* m;
|
|
|
|
if (!(m = newof(NiL, Modify_t, 1, 0))) return(-1);
|
|
m->next = mods;
|
|
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 = arg1;
|
|
m->arg.fd.parent.flag = fcntl(arg1, F_GETFD, 0);
|
|
if ((m->arg.fd.child.fd = 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 = arg1;
|
|
return(0);
|
|
case PROC_sig_ign:
|
|
if ((m->arg.handler = signal(arg1, SIG_IGN)) == SIG_IGN) break;
|
|
m->save = arg1;
|
|
return(0);
|
|
case PROC_sys_pgrp:
|
|
proc->pgrp = arg1;
|
|
break;
|
|
case PROC_sys_umask:
|
|
if ((m->save = umask(arg1)) == arg1) break;
|
|
return(0);
|
|
default:
|
|
mods = m->next;
|
|
free(m);
|
|
return(-1);
|
|
}
|
|
mods = m->next;
|
|
free(m);
|
|
}
|
|
#else
|
|
NoP(proc);
|
|
#endif
|
|
return(0);
|
|
}
|
|
|
|
#if USE_SPAWN
|
|
|
|
/*
|
|
* restore modifications
|
|
*/
|
|
|
|
static void
|
|
restore __PARAM__((Proc_t* proc), (proc)) __OTORP__(Proc_t* proc;){
|
|
Modify_t* m;
|
|
Modify_t* p;
|
|
int oerrno;
|
|
|
|
NoP(proc);
|
|
oerrno = errno;
|
|
m = mods;
|
|
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 __PARAM__((const char* cmd, char** argv, char** envv, long* modv, long flags), (cmd, argv, envv, modv, flags)) __OTORP__(const char* cmd; char** argv; char** envv; long* modv; long flags;){
|
|
Proc_t* proc = 0;
|
|
int procfd;
|
|
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 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;
|
|
sfsync(NiL);
|
|
if (!setenviron(NiL)) goto bad;
|
|
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_SPAWN
|
|
else if (argv) proc->pid = 0;
|
|
#endif
|
|
#if _lib_fork
|
|
else
|
|
{
|
|
sigcritical(1);
|
|
proc->pid = fork();
|
|
sigcritical(0);
|
|
if (proc->pid == -1) goto bad;
|
|
forked = 1;
|
|
}
|
|
#endif
|
|
if (!proc->pid)
|
|
{
|
|
#if USE_SPAWN
|
|
char** oenviron;
|
|
|
|
v = 0;
|
|
oenviron = 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, NULL);
|
|
_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 (forked || (flags & PROC_OVERLAY))
|
|
{
|
|
if (flags & (PROC_DAEMON|PROC_SESSION)) setsid();
|
|
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 (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 (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_SPAWN
|
|
else
|
|
#endif
|
|
#endif
|
|
#if USE_SPAWN
|
|
{
|
|
oenviron = environ;
|
|
environ = 0;
|
|
if (!(flags & PROC_ENVCLEAR) && (p = oenviron))
|
|
while (*p)
|
|
if (!setenviron(*p++)) goto cleanup;
|
|
}
|
|
#endif
|
|
if (argv)
|
|
{
|
|
env[0] = '_';
|
|
env[1] = '=';
|
|
if (!setenviron(env)) goto cleanup;
|
|
}
|
|
if ((flags & PROC_PARANOID) && !setenviron("PATH=:/bin:/usr/bin")) goto cleanup;
|
|
if (p = envv)
|
|
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_SPAWN
|
|
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";
|
|
}
|
|
if (!(flags & PROC_PARANOID))
|
|
{
|
|
strcpy(env + 2, pathshell());
|
|
if (forked || (flags & PROC_OVERLAY)) execve(env + 2, p, environ);
|
|
#if USE_SPAWN
|
|
else if ((proc->pid = spawnveg(env + 2, p, environ, proc->pgrp)) != -1) goto cleanup;
|
|
#endif
|
|
}
|
|
strcpy(env + 2, "/bin/sh");
|
|
if (forked || (flags & PROC_OVERLAY)) execve(env + 2, p, environ);
|
|
#if USE_SPAWN
|
|
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_SPAWN
|
|
if (v) free(v);
|
|
if (oenviron)
|
|
{
|
|
if (environ) free(environ);
|
|
environ = oenviron;
|
|
}
|
|
restore(proc);
|
|
if (flags & PROC_OVERLAY) exit(0);
|
|
#endif
|
|
}
|
|
if (proc->pid != -1)
|
|
{
|
|
if (forked && 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_IGNORE)
|
|
{
|
|
Handler_t handler;
|
|
|
|
if ((handler = signal(SIGPIPE, SIG_IGN)) != SIG_DFL && handler != SIG_IGN)
|
|
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->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);
|
|
}
|