/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1985-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* 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>
#include <ast_tty.h>
/*
* not quite ready for _use_spawnveg
*/
#if _use_spawnveg
#if _lib_fork
#else
#if _WINIX
#endif
#endif
#endif
#ifndef DEBUG_PROC
#endif
#if _lib_socketpair
#if _sys_socket
#else
#endif
#endif
#if DEBUG_PROC
#include <namval.h>
{
"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)
else
}
return 0;
}
#endif
#if _use_spawnveg
typedef struct Fd_s
{
short fd;
short flag;
} Fd_t;
typedef struct Mod_s
{
short op;
short save;
union
{
struct
{
} fd;
} arg;
} Modify_t;
#endif
#ifdef SIGPIPE
/*
* catch but ignore sig
* avoids SIG_IGN being passed to children
*/
static void
{
}
#endif
/*
* do modification op and save previous state for restore()
*/
static int
{
#if _lib_fork
if (forked)
{
int i;
#ifndef TIOCSCTTY
char* s;
#endif
switch (op)
{
case PROC_fd_dup:
case PROC_fd_dup|PROC_FD_PARENT:
case PROC_fd_dup|PROC_FD_CHILD:
{
if (arg2 != PROC_ARG_NULL)
{
return -1;
}
if (op & PROC_FD_CHILD)
}
break;
case PROC_fd_ctty:
setsid();
for (i = 0; i <= 2; i++)
if (arg1 != i)
close(i);
arg2 = -1;
#ifdef TIOCSCTTY
return -1;
#else
return -1;
return -1;
#endif
for (i = 0; i <= 2; i++)
return -1;
if (arg1 > 2)
if (arg2 > 2)
break;
case PROC_sig_dfl:
break;
case PROC_sig_ign:
break;
case PROC_sys_pgrp:
if (arg1 < 0)
setsid();
else if (arg1 > 0)
{
if (arg1 == 1)
arg1 = 0;
setpgid(0, 0);
}
break;
case PROC_sys_umask:
break;
default:
return -1;
}
}
#if _use_spawnveg
else
#endif
#else
#endif
#if _use_spawnveg
{
register Modify_t* m;
return -1;
{
case PROC_fd_dup:
case PROC_fd_dup|PROC_FD_PARENT:
case PROC_fd_dup|PROC_FD_CHILD:
{
if (arg2 != PROC_ARG_NULL)
{
{
m->op = 0;
return -1;
}
#if F_dupfd_cloexec == F_DUPFD
#endif
return -1;
if (op & PROC_FD_CHILD)
}
else if (op & PROC_FD_CHILD)
{
break;
}
break;
else
return 0;
}
break;
case PROC_sig_dfl:
break;
return 0;
case PROC_sig_ign:
break;
return 0;
case PROC_sys_pgrp:
break;
case PROC_sys_umask:
break;
return 0;
default:
free(m);
return -1;
}
free(m);
}
#else
#endif
return 0;
}
#if _use_spawnveg
/*
* restore modifications
*/
static void
{
register Modify_t* m;
register Modify_t* p;
int oerrno;
while (m)
{
switch (m->op)
{
case PROC_fd_dup:
case PROC_fd_dup|PROC_FD_PARENT:
case PROC_fd_dup|PROC_FD_CHILD:
if (m->op & PROC_FD_PARENT)
{
if (!(m->op & PROC_FD_PARENT))
{
if (m->op & PROC_FD_CHILD)
{
}
}
}
break;
case PROC_sig_dfl:
case PROC_sig_ign:
break;
case PROC_sys_umask:
break;
}
p = m;
m = m->next;
free(p);
}
}
#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
*/
{
register int procfd;
register char** p;
char** v;
int i;
int forked = 0;
int signalled = 0;
long n;
#if _lib_fork
#endif
#if !_pipe_rw && !_lib_socketpair
#endif
#endif
#if _use_spawnveg
int newenv = 0;
#endif
#if DEBUG_PROC
#endif
#if _lib_fork
#else
#endif
{
return 0;
}
#if _lib_fork
#endif
#if !_pipe_rw && !_lib_socketpair
#endif
goto bad;
{
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;
}
proc = &proc_default;
goto bad;
if (environ && envv != (char**)environ && (envv || (flags & PROC_PARANOID) || argv && (environ[0][0] != '_' || environ[0][1] != '=')))
{
if (!setenviron(NiL))
goto bad;
#if _use_spawnveg
if (!(flags & PROC_ORPHAN))
newenv = 1;
#endif
}
if (procfd >= 0)
{
#if _pipe_rw
goto bad;
#else
if (procfd > 1)
{
#if _lib_socketpair
goto bad;
#else
goto bad;
#endif
}
goto bad;
#endif
}
if (flags & PROC_OVERLAY)
{
forked = 1;
}
#if _use_spawnveg
#endif
#if _lib_fork
else
{
if (!(flags & PROC_FOREGROUND))
else
{
signalled = 1;
#if defined(SIGCHLD)
#if _lib_sigprocmask
sigemptyset(&mask);
#else
#if _lib_sigsetmask
#else
#endif
#endif
#endif
}
goto bad;
if (!(flags & PROC_FOREGROUND))
sigcritical(0);
{
{
}
{
}
#if defined(SIGCHLD)
#if _lib_sigprocmask
#else
#if _lib_sigsetmask
#else
#endif
#endif
#endif
}
goto bad;
forked = 1;
}
#endif
{
#if _use_spawnveg
char** oenviron = 0;
char* oenviron0 = 0;
v = 0;
#endif
#if _lib_fork
if (flags & PROC_ORPHAN)
{
{
}
else
{
}
}
#endif
#if DEBUG_PROC
#if _lib_fork
if (debug & PROC_OPT_TRACE)
{
if (!fork())
{
}
sleep(2);
}
#endif
#endif
if (flags & PROC_DAEMON)
{
#ifdef SIGHUP
#endif
#ifdef SIGTSTP
#endif
#ifdef SIGTTIN
#endif
#ifdef SIGTTOU
#endif
}
{
#ifdef SIGQUIT
#endif
}
{
{
}
}
if (procfd > 1)
{
goto cleanup;
goto cleanup;
#if _pipe_rw || _lib_socketpair
goto cleanup;
#else
goto cleanup;
goto cleanup;
#endif
}
else if (procfd >= 0)
{
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:
goto cleanup;
break;
default:
goto cleanup;
break;
}
#if _lib_fork
environ = 0;
#if _use_spawnveg
else
#endif
#endif
#if _use_spawnveg
if (newenv)
{
p = environ;
while (*p++);
goto cleanup;
}
#endif
{
#if _use_spawnveg
#endif
env[0] = '_';
env[2] = 0;
if (!setenviron(env))
goto cleanup;
}
goto cleanup;
while (*p)
if (!setenviron(*p++))
goto cleanup;
p = argv;
#if _lib_fork
if (forked && !p)
return proc;
#endif
#if DEBUG_PROC
{
while (*p)
if ((p = argv) && *p)
while (*++p)
if (!(debug & PROC_OPT_EXEC))
_exit(0);
p = argv;
}
#endif
if (cmd)
{
#if _use_spawnveg
goto cleanup;
#endif
goto cleanup;
/*
* try cmd as a shell script
*/
if (!(flags & PROC_ARGMOD))
{
while (*p++);
goto cleanup;
p = v + 2;
if (*argv)
argv++;
while (*p++ = *argv++);
p = v + 1;
}
*p = path;
*--p = "sh";
}
#if _use_spawnveg
else
#endif
if (forked)
{
if (!(flags & PROC_OVERLAY))
goto bad;
}
#if _use_spawnveg
if (v)
free(v);
if (p = oenviron)
{
environ = 0;
while (*p)
if (!setenviron(*p++))
goto bad;
}
else if (oenviron0)
if (flags & PROC_OVERLAY)
exit(0);
#endif
}
{
if (!forked)
{
if (flags & PROC_FOREGROUND)
{
signalled = 1;
#if defined(SIGCHLD)
#if _lib_sigprocmask
sigemptyset(&mask);
#else
#if _lib_sigsetmask
#else
#endif
#endif
#endif
}
}
else if (modv)
for (i = 0; n = modv[i]; i++)
switch (PROC_OP(n))
{
case PROC_fd_dup|PROC_FD_PARENT:
break;
case PROC_sys_pgrp:
{
}
break;
}
if (procfd >= 0)
{
#ifdef SIGPIPE
{
}
#endif
switch (procfd)
{
case 0:
break;
default:
#if _pipe_rw || _lib_socketpair
#else
#endif
/*FALLTHROUGH*/
case 1:
break;
}
}
else if (flags & PROC_ORPHAN)
{
goto bad;
}
return proc;
}
bad:
if (signalled)
{
#if defined(SIGCHLD)
#if _lib_sigprocmask
#else
#if _lib_sigsetmask
#else
#endif
#endif
#endif
}
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:
break;
}
if (pio[0] >= 0)
if (pio[1] >= 0)
if (pop[0] >= 0)
if (pop[1] >= 0)
#if !_pipe_rw && !_lib_socketpair
if (poi[0] >= 0)
if (poi[1] >= 0)
#endif
return 0;
}