/*
* Copyright (c) 2001-2003 The Trustees of Indiana University.
* All rights reserved.
* Copyright (c) 1998-2001 University of Notre Dame.
* All rights reserved.
* Copyright (c) 1994-1998 The Ohio State University.
* All rights reserved.
*
* This file is part of the LAM/MPI software package. For license
* information, see the LICENSE file in the top level directory of the
* LAM/MPI source distribution.
*
* $HEADER$
*
* $Id: kcreate.c,v 1.15 2003/11/04 02:40:26 jsquyres Exp $
*
* Function: - creates an OTB process
* - does not make a Trollius kernel request
* - essentially a packaged fork and exec
* - redirects created process's stdio
* Accepts: - child program name
* - argument vector
* - environment vector
* - stdio file descriptors (0 if no redirection)
* Returns: - (to parent) child pid or ERROR
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "kio.h"
#include "preq.h"
#include "terror.h"
#include "typical.h"
#include "lamdebug.h"
/*
* external functions
*/
extern void _cipc_cleanup();
extern int lam_pty_open();
extern int liosattach();
extern int liofdattach();
extern int4 stoi();
/*
* private functions
*/
static int redirect_stdio(int, int *);
static int set_environment(char **);
static void set_handler_default(int);
int
kcreate(const char *pathname, char **argv)
{
return kcreatev(pathname, argv, NULL, NULL, NULL, 0);
}
int
kcreatev(const char *pathname, char **argv, char **envv, char *wrkdir,
int *fds, int umask_mode)
{
sigset_t sigs;
sigset_t newset;
sigset_t oldset;
int pid;
int rtf;
int errno_save;
char *p;
sigemptyset(&newset);
sigaddset(&newset, SIGTERM);
sigaddset(&newset, SIGINT);
sigaddset(&newset, SIGHUP);
sigprocmask(SIG_BLOCK, &newset, &oldset);
pid = fork();
if (pid != 0) {
errno_save = errno;
sigprocmask(SIG_SETMASK, &oldset, (sigset_t *)0);
if (pid < 0) {
errno = errno_save;
return LAMERROR;
}
else {
return pid;
}
}
if (pid == 0) {
/*
* Set signal handlers back to the default. This must be done before unblocking
* the signals to avoid a race where a signal delivered to the child can lead
* to the execution of the kenyad signal handlers and accidental killing
* of kenyad.
*/
set_handler_default(SIGTERM);
set_handler_default(SIGINT);
set_handler_default(SIGHUP);
set_handler_default(SIGCHLD);
set_handler_default(SIGPIPE);
/*
* Unblock all signals.
*/
sigprocmask(0, 0, &sigs);
sigprocmask(SIG_UNBLOCK, &sigs, 0);
/*
* set umask if desired
*/
if (umask_mode > 0)
umask(umask_mode);
/*
* Redirect the stdio fd's
*/
rtf = (p = getenv("TROLLIUSRTF")) ? stoi((unsigned char *) p) : 0;
if (redirect_stdio(rtf, fds))
exit(errno);
/*
* Close all the rest of the file descriptors.
*/
_cipc_cleanup();
lamcloselog();
if (set_environment(envv))
exit(errno);
if (wrkdir) {
if (chdir(wrkdir) && !(rtf & RTF_TRYCWD)) {
fprintf(stderr, "kcreatev: chdir(%s): ", wrkdir);
terror("");
exit(errno);
}
}
execvp(pathname, argv);
exit(errno);
}
/* This is never reached, but we put it here because some compilers
can't see logic like if (x) { ...; return; } else { ...; exit(); }
and complain because there's no return statement. [sigh]. */
return LAMERROR;
}
/*
* redirect_stdio
*
* Function: - redirect process stdio
* Accepts: - runtime flags
* - passed file descriptors or NULL
*/
static int
redirect_stdio(int rtf, int *fds)
{
int ionode;
int stdout_fd;
int stderr_fd;
int master;
int slave;
char *p;
if (fds) {
/*
* Redirect stdio to the passed fds.
*/
dup2(fds[0], fileno(stdin));
dup2(fds[1], fileno(stdout));
dup2(fds[2], fileno(stderr));
} else {
if ((rtf&RTF_IO) && !(rtf&RTF_PFDIO) && (p = getenv("TROLLIUSFD"))) {
/*
* Connect UNIX stderr and stdout to IO daemon.
*/
ionode = stoi((unsigned char *) p);
p = strchr(p, ':') + 1;
p = strchr(p, ':') + 1; /* skip stdin */
stdout_fd = stoi((unsigned char *) p);
p = strchr(p, ':') + 1;
stderr_fd = stoi((unsigned char *) p);
/*
* Attach stderr stream to iod nobuffered.
*/
if (liosattach(stderr, ionode, stderr_fd, _IONBF))
return(LAMERROR);
/*
* Try to use a pty for stdout if asked for and if stdout is a tty.
* pty support is enabled ONLY IF FD passing is supported */
#if LAM_HAVE_FD_PASSING
if ((rtf & RTF_PTYS) && (rtf & RTF_TTYOUT)) {
if (lam_pty_open(&master, &slave)) {
if (errno == ENOPTYSUPPORT) {
/*
* No pty support on this node so fall back to no pty IO.
*/
if (liosattach(stdout, ionode, stdout_fd, _IONBF))
return(LAMERROR);
}
} else {
if (dup2(slave, fileno(stdout)) != fileno(stdout))
return(LAMERROR);
if (liofdattach(master, ionode, stdout_fd))
return(LAMERROR);
}
} else {
if (liosattach(stdout, ionode, stdout_fd, _IONBF))
return(LAMERROR);
}
#else
/* we dont have FD passing so just connect to the IO stream */
if (liosattach(stdout, ionode, stdout_fd, _IONBF)){
return (LAMERROR);
}
#endif
}
}
return(0);
}
/*
* set_environment
*
* Function: - set process environment
* Accepts: - environment vector
*/
static int
set_environment(char **env)
{
int i;
if (env) {
for (i = 0; env[i]; i++) {
if (putenv(env[i]))
return(LAMERROR);
}
}
return(0);
}
static void
set_handler_default(int sig)
{
struct sigaction act;
act.sa_handler = SIG_DFL;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(sig, &act, (struct sigaction *)0);
}
syntax highlighted by Code2HTML, v. 0.9.1