
/*
 *         PVM version 3.3:  Parallel Virtual Machine System
 *               University of Tennessee, Knoxville TN.
 *           Oak Ridge National Laboratory, Oak Ridge TN.
 *                   Emory University, Atlanta GA.
 *      Authors:  A. L. Beguelin, J. J. Dongarra, G. A. Geist,
 *    W. C. Jiang, R. J. Manchek, B. K. Moore, and V. S. Sunderam
 *                   (C) 1992 All Rights Reserved
 *
 *                              NOTICE
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby granted
 * provided that the above copyright notice appear in all copies and
 * that both the copyright notice and this permission notice appear in
 * supporting documentation.
 *
 * Neither the Institutions (Emory University, Oak Ridge National
 * Laboratory, and University of Tennessee) nor the Authors make any
 * representations about the suitability of this software for any
 * purpose.  This software is provided ``as is'' without express or
 * implied warranty.
 *
 * PVM version 3 was funded in part by the U.S. Department of Energy,
 * the National Science Foundation and the State of Tennessee.
 */

/*
 *	cons.c
 *
 *	PVM-console task.  Gives the user a shell to manage the virtual
 *	machine and other tasks.
 *
$Log: cons.c,v $
 * Revision 1.6  1995/05/30  16:51:30  manchek
 * added SP2MPI architecture
 *
 * Revision 1.5  1995/05/17  15:28:06  manchek
 * added FDSETISINT switch.
 * allow pvm_getfds() to fail silently (e.g. for shared memory)
 *
 * Revision 1.4  1994/10/15  18:40:09  manchek
 * don't compare add-host notify source to 0x80000000
 *
 * Revision 1.3  1994/06/03  20:01:52  manchek
 * version 3.3.0
 *
 * Revision 1.2  1993/09/16  21:33:40  manchek
 * moved notify(HostAdd) to before we read script file.
 * added include for linux/time.h
 *
 * Revision 1.1  1993/08/30  23:30:32  manchek
 * Initial revision
 *
 */

#include <stdio.h>
#include <sys/types.h>
#ifdef IMA_LINUX
#include <linux/time.h>
#endif
#if defined(IMA_RS6K) || defined(IMA_POWER4) || defined(IMA_SP2MPI)
#include <sys/select.h>
#endif
#ifdef	IMA_I860
#include <sys/socket.h>
#endif
#include <ctype.h>
#include <signal.h>
#include <pvm3.h>
#include "cmd.h"
#include "myalloc.h"
#include "../src/listmac.h"
#include "../src/bfunc.h"
#include "job.h"

#define	PVMERRMSG(n)	((n) <= 0 && (n) > -pvm_nerr \
						? pvm_errlist[-(n)] : "Unknown Error")

char *getenv();

extern char *pvm_errlist[];
extern int pvm_nerr;

int mytid = -1;
int nhosts = 0;
int narchs = 0;
struct pvmhostinfo *hostlist = 0;
struct alias *aliases = 0;

static char rcsid[] = "$Id: cons.c,v 1.6 1995/05/30 16:51:30 manchek Exp $";


main(argc, argv)
	int argc;
	char **argv;
{
	char *prompt = "pvm> ";
	char cmd[1024];
	int cc;
	int i;
	int src, cod, len;
	char *p;
	FILE *ff;
	fd_set rfds, fds;
	int nfds;
	int n;
	int *np = 0;

	pvm_setopt(PvmResvTids, 1);

	aliases = TALLOC(1, struct alias, "alias");
	BZERO((char*)aliases, sizeof(struct alias));
	aliases->a_link = aliases->a_rlink = aliases;

	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'd')
		pvm_setopt(PvmDebugMask, xtoi(argv[1] + 2));

	pvm_setopt(PvmRoute, PvmDontRoute);

	i = pvm_setopt(PvmAutoErr, 0);
	cc = pvm_start_pvmd(argc - 1, argv + 1, 1);
	if (cc < 0) {
		if (cc != PvmDupHost) {
			pvm_perror("Console");
			exit(1);
		}
		printf("pvmd already running.\n");
	}
	pvm_setopt(PvmAutoErr, i);
	if ((mytid = pvm_mytid()) < 0)
		exit(1);

	(void)signal(SIGINT, SIG_IGN);
	(void)signal(SIGTERM, SIG_IGN);

	job_init();

/*
	ttpcb_dumpall();
*/
	pvm_notify(PvmHostAdd, 0, -1, (int*)0);

	if (!(p = getenv("HOME")))
		p = ".";
	sprintf(cmd, "%s/.pvmrc", p);
	if (ff = fopen(cmd, "r")) {
		while (fgets(cmd, sizeof(cmd)-1, ff))
			docmd(cmd);
		(void)fclose(ff);
	}

	FD_ZERO(&rfds);
	FD_SET(0, &rfds);
	nfds = 1;
	i = pvm_setopt(PvmAutoErr, 0);
	if (pvm_getfds(&np) > 0) {
		FD_SET(np[0], &rfds);
		nfds = np[0] + 1;
	}
	pvm_setopt(PvmAutoErr, i);

	printf(prompt);
	fflush(stdout);
	while (1) {

	/*
	* flush task stdout
	*/

		if (mytid > 0) {
			checkmsgs();
		}

	/*
	* wait for command or more output
	*/
		fds = rfds;
		if ((n = select(nfds,
#ifdef	FDSETISINT
				(int *)&fds, (int *)0, (int *)0,
#else
				&fds, (fd_set *)0, (fd_set *)0,
#endif
				(struct timeval*)0))
		== -1) {
			perror("select");
			continue;
		}
		if (n > 0 && FD_ISSET(0, &fds)) {

			if ((n = read(0, cmd, sizeof(cmd)-1)) < 1) {
				printf("quit");
				quit_cmd();
			}
			cmd[n] = 0;
			docmd(cmd);
			printf(prompt);
			fflush(stdout);
		}
	}
}


/*	acav()
*
*	Parse a string into words separated by whitespace.
*	Max number of words is original value of *acp.
*
*	Trashes out the original string.
*	Returns 0 with av[0]..av[*acp - 1] pointing to the words.
*	Returns 1 if too many words.
*	Returns -1 if unbalanced quote.
*/

int
acav(s, acp, av)
	char *s;			/* the string to parse */
	int *acp;			/* max num words in, num words found out */
	char **av;			/* pointers to words */
{
	int ac = 0;			/* number of words found */
	char *p = s;		/* input scanner */
	char *q;			/* output */
	int n = *acp;		/* max number of words allowed */
	int mode = 0;		/* quote mode */

	while (*p) {
		while (isspace(*p)) p++;
		if (*p) {
			if (*p == '#')
				break;
			if (ac >= n) {
				*acp = ac;
				return 1;
			}
			q = p;
			av[ac++] = p;
			while (*p) {
				if (mode) {
					if (mode == '\\') {
						*q++ = *p;
						mode = 0;

					} else if (mode == *p) {
						mode = 0;

					} else
						*q++ = *p;

				} else {
					if (isspace(*p))
						break;

					switch (*p) {

					case '"':
					case '\'':
					case '\\':
						mode = *p;
						break;

					default:
						*q++ = *p;
						break;
					}
				}
				p++;
			}
			if (*p)
				p++;
			if (*q)
				*q = 0;
			if (mode) {
				printf("unmatched %c\n", (char)mode);
				return -1;
			}
		}
	}
	*acp = ac;
	return 0;
}


/*	xtoi()
*
*	Yet another version of ascii hex to integer
*/

xtoi(p)
	char *p;
{
	int i = 0;
	char c;

	while (isxdigit(c = *p++)) {
		i = (i << 4) + c - (isdigit(c) ? '0' : (isupper(c) ? 'A' : 'a') - 10);
	}
	return i;
}


/*	axtoi()
*
*	ascii hex or decimal to integer.
*/

axtoi(p)
	char *p;
{
	if (p[0] == '0' && p[1] == 'x')
		return xtoi(p + 2);
	else
		return atoi(p);
}


int
tidtoi(p)
	char *p;
{
	if (*p == 't')
		p++;
	return xtoi(p);
}


checkmsgs()
{
	int cc;
	int len, cod, src;
	int n;
	struct job *jp;
	int *dtids;
	int i, j;

	while ((cc = pvm_nrecv(-1, -1)) > 0) {
		pvm_bufinfo(cc, &len, &cod, &src);

		if (cod == 0) {
			pvm_upkint(&n, 1, 1);
			dtids = TALLOC(n, int, "");
			pvm_upkint(dtids, n, 1);
			printf("\nConsole: %d new host%s added\n", n, (n == 1 ? "" : "s"));
			pvm_freebuf(cc);
			if (!pvm_config(&nhosts, &narchs, &hostlist)) {
				fputs("                    HOST     DTID     ARCH   SPEED\n",
						stdout);
				for (j = n; j-- > 0; )
					for (i = nhosts; i-- > 0; ) {
						if (dtids[j] == hostlist[i].hi_tid) {
							printf("%24s %8x %8s%8d\n",
									hostlist[i].hi_name,
									hostlist[i].hi_tid,
									hostlist[i].hi_arch,
									hostlist[i].hi_speed);
							break;
						}
					}
			}
			MY_FREE(dtids);
			continue;
		}

		if (cod > 0 && (jp = job_find(cod))) {
			checkoutput(jp, cc, len, cod, src);
			continue;
		}

		fprintf(stderr, "Console: msg from t%x code %d length %d ?\n",
				src, cod, len);
		pvm_freebuf(cc);
	}
	if (cc < 0)
		exit(1);
	return 0;
}


