/************************************************************************
 * This program is Copyright (C) 1986 by Jonathan Payne.  JOVE is       *
 * provided to you without charge, and with no warranty.  You may give  *
 * away copies of JOVE, including sources, provided that this notice is *
 * included in all the files.                                           *
 ************************************************************************/

/* This is a server for JOVE interactive subprocesses.  It runs the command
   and wraps the command's output in packets so that JOVE can identify its
   source.  By the time we get here, our standard output goes to JOVE's
   process input. */

#define NOT_JOVE

#include "tune.h"

#ifdef PIPEPROCS

RCS("$Id: portsrv.c,v 14.31 1993/02/15 02:01:49 tom Exp tom $")

#include "jove.h"
#include "io.h"
#include "process.h"

struct {
	struct header header;
	char buf[BLKSIZ];
} packet;

#ifdef PORTSRV_SHOULD_BUFFER
int	proc_read __(( int _(fd), char *_(buf), size_t _(size) ));
int
proc_read(fd, buf, size)
register char	*buf;
size_t	size;
{
	register int	n = size,
			nread = 0;

	/* line-buffer unbuffered output. */
	while ((n = read(fd, buf, n)) == 1 && *buf++ != '\n' && --size > 0)
		nread += n;
	if (n >= 0)
		n += nread;
	return n;
}
#else
#   define proc_read read
#endif

void	proc_write __(( int _(nbytes) ));
void
proc_write(nbytes)
{
	write(1, &packet, sizeof packet.header + nbytes);
}

void	serv_error __(( char *_(msg) ));
void
serv_error(msg)
register char	*msg;
{
	register char	*d = packet.buf;
	int		status = -errno;

	while (*d++ = *msg++) ;
	--d;
	proc_write(packet.header.nbytes = d - packet.buf);
	packet.header.nbytes = EOF;
	*(int *) packet.buf = status << 8;
	proc_write(sizeof(WAIT_T));		/* cheat... */
	_exit(status);
}

#endif /* PIPEPROCS */

/* ARGSUSED */
void
main(argc, argv)
char	*argv[];
{
#ifdef PIPEPROCS
	int		p[2];
	register int	pid, wpid;

	packet.header.pid = getpid();

	if (pipe(p) < 0)
		serv_error("[portsrv: Pipe failed.]\n");

	if ((pid = fork()) < 0)
		serv_error("[portsrv: Fork failed.]\n");

	if (pid == 0) {
		/* We'll intercept childs output in pipe p */
		dup2(p[WRITE], 1);
		dup2(p[WRITE], 2);
		close(p[READ]);
		close(p[WRITE]);
		setpgrp(getpid(), getpid());
		execv(argv[1], &argv[2]);
		_exit(-ENOEXEC);
	}

	signal(SIGINT, SIG_IGN);
	signal(SIGQUIT, SIG_IGN);

	close(0);		/* Don't want this guy to read anything
				   jove sends to our soon to be created
				   child */
	close(p[WRITE]);

	/* Tell jove the pid of the real child as opposed to us. */
	packet.header.nbytes = 0;	/* special marker. */
	*(int *) packet.buf = pid;
	proc_write(sizeof pid);

	/* Read proc's output and send it to jove */
	while ((packet.header.nbytes =
			proc_read(p[READ], packet.buf, sizeof packet.buf)) > 0)
		proc_write(packet.header.nbytes);

	close(p[READ]);

	/* Tell jove we are finished; send exit code of child in EOF packet. */
	packet.header.nbytes = EOF;
	while ((wpid = wait((int *) packet.buf)) != pid) {
		if (wpid < 0)
			break;
	}
	proc_write(sizeof(WAIT_T));
#endif /* PIPEPROCS */

	_exit(EXIT_SUCCESS);
}

/*======================================================================
 * $Log: portsrv.c,v $
 * Revision 14.31  1993/02/15  02:01:49  tom
 * remove (void) casts.
 *
 * Revision 14.30  1993/01/26  18:43:17  tom
 * cleanup whitespace.
 *
 * Revision 14.26  1992/08/26  23:57:05  tom
 * add RCS directives.
 *
 */
