/*
 *
 * Copyright 1998-1999, University of Notre Dame.
 * Authors: Jeffrey M. Squyres, Kinis L. Meyer with M. D. McNally 
 *          and Andrew Lumsdaine
 *
 * This file is part of the Notre Dame LAM implementation of MPI.
 *
 * You should have received a copy of the License Agreement for the
 * Notre Dame LAM implementation of MPI along with the software; see
 * the file LICENSE.  If not, contact Office of Research, University
 * of Notre Dame, Notre Dame, IN 46556.
 *
 * Permission to modify the code and to distribute modified code is
 * granted, provided the text of this NOTICE is retained, a notice that
 * the code was modified is included with the above COPYRIGHT NOTICE and
 * with the COPYRIGHT NOTICE in the LICENSE file, and that the LICENSE
 * file is distributed with the modified code.
 *
 * LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
 * By way of example, but not limitation, Licensor MAKES NO
 * REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
 * PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE COMPONENTS
 * OR DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS
 * OR OTHER RIGHTS.  
 *
 * Additional copyrights may follow.
 *
 *	Ohio Trollius
 *	Copyright 1997 The Ohio State University
 *	GDB/NJN
 *
 *	$Id: kcreate.c,v 6.8 1999/07/29 12:41:09 lamteam 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"

/*
 * 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 **);


int
kcreate(const char *pathname, char **argv)
{
    int			pid;

    if ((pid = fork()) < 0)
	return(LAMERROR);
    else if (pid == 0) {
	_cipc_cleanup();
	execvp(pathname, argv);
	exit(errno);
    }

    return(pid);
}

int
kcreatev(const char *pathname, char **argv, char **envv, char *wrkdir, int *fds)
{
    struct sigaction	act;
    sigset_t		sigs;
    int			pid;
    int			rtf;
    char		*p;

    if ((pid = fork()) < 0)
	return(LAMERROR);
    else if (pid == 0) {
/*
 * Unblock all signals.
 */
	sigprocmask(0, 0, &sigs);
	sigprocmask(SIG_UNBLOCK, &sigs, 0);
/*
 * Reset SIGCHLD and SIGPIPE handlers.
 */
	act.sa_handler = SIG_DFL;
	act.sa_flags = 0;
	sigemptyset(&act.sa_mask);
	sigaction(SIGCHLD, &act, 0);
	sigaction(SIGPIPE, &act, 0);

	(void) setsid();
	_cipc_cleanup();

	rtf = (p = getenv("TROLLIUSRTF")) ? stoi((unsigned char *) p) : 0;

	if (redirect_stdio(rtf, fds))
	    exit(errno);

	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);
    }

    return(pid);
}

/*
 *	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.
 */
	    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);
	    }
	}
    }

    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);
}
