[comp.os.minix] V1.3 posting #42 - amoeba/util/*

ast@cs.vu.nl (Andy Tanenbaum) (07/18/88)

: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'READ_ME'
sed 's/^X//' > 'READ_ME' << '+ END-OF-FILE ''READ_ME'
XThis directory contains the sources for amoeba based utilities.  These are
Xmainly of interest if you have an ethernet connection.  Master and sherver
Xshould not be installed if you do not have an ethernet connection since they
Xwill take up precious memory.
X
X
XInstallation:
X
X1. Type make
X
X2. Copy files as follows:
X
X	cp rsh  /usr/bin
X	cp rcp  /usr/bin
X	cp to   /usr/bin
X	cp from /usr/bin
X
X3. Edit /etc/rc and add the lines:
X
X	echo "Starting sherver(s)"
X	/usr/bin/master 1 <uid> <gid> /etc/sherver port
X
X   where port is the name that your node is to be known by.  It should not be
X   more than 6 characters long.  It can be made up of any characters you like.
X   Note that the flags <uid> and <gid> are the uid and group id that the 
X   sherver will run under. 
X
X   
X
+ END-OF-FILE READ_ME
chmod 'u=rw,g=r,o=r' 'READ_ME'
set `wc -c 'READ_ME'`
count=$1
case $count in
767)	:;;
*)	echo 'Bad character count in ''READ_ME' >&2
		echo 'Count should be 767' >&2
esac
echo Extracting 'from.c'
sed 's/^X//' > 'from.c' << '+ END-OF-FILE ''from.c'
X#include <stdio.h>
X#include <signal.h>
X#include "amoeba.h"
X
X#define BUFSIZE		20480
X
Xchar *	cmd;
X
X
Xcatchalarm()
X{
X	fprintf(stderr, "%s: timeout\n", cmd);
X	exit(1);
X}
X
X
Xmain(argc, argv)
Xint	argc;
Xchar **	argv;
X{
X	unshort		getreq();
X	unshort		putrep();
X	char *		malloc();
X	int		catchalarm();
X
X	char *		buf;
X	header		hdr;
X	unshort		cnt;
X	unshort		bufsize = BUFSIZE;
X	unsigned	tim = 15 * 60;		/* #secs before timeout */
X
X	cmd = *argv;
X	if (argc > 1 && strncmp(argv[1], "-t", 2) == 0)
X	{
X		tim = atoi(&argv[1][2]);
X		argc--;
X		argv++;
X	}
X	if (tim)
X		signal(SIGALRM, catchalarm);
X	if (argc != 2 && argc != 3)	/* if (!(argc & 2))?? */
X	{
X		fprintf(stderr, "Usage: %s [-ttime] [bufsize] port\n", cmd);
X		exit(-1);
X	}
X	if (argc == 3)
X		bufsize = atoi(argv[2]);
X	if ((buf = malloc(bufsize * sizeof (char))) == NULL)
X	{
X		fprintf(stderr, "%s: out of memory\n", cmd);
X		exit(-1);
X	}
X	strncpy(&hdr.h_port, argv[1], PORTSIZE);
X	for (;;)
X	{
X		if (tim)
X			alarm(tim);
X		cnt = getreq(&hdr, buf, bufsize);
X		if (tim)
X			alarm(0);
X		if ((short)cnt < 0)
X		{
X			fprintf(stderr, "%s: getreq failed\n", cmd);
X			exit(-3);
X		}
X		hdr.h_status = 0;
X		if (cnt != 0)
X			if (write(1, buf, cnt) < 0)
X			{
X				perror(cmd);
X				hdr.h_status = -1;
X			}
X		putrep(&hdr, NILBUF, 0);
X		if (hdr.h_status)
X			exit(-4);
X		if (cnt == 0)
X			exit(0);
X	}
X}
+ END-OF-FILE from.c
chmod 'u=rw,g=r,o=r' 'from.c'
set `wc -c 'from.c'`
count=$1
case $count in
1312)	:;;
*)	echo 'Bad character count in ''from.c' >&2
		echo 'Count should be 1312' >&2
esac
echo Extracting 'makefile'
sed 's/^X//' > 'makefile' << '+ END-OF-FILE ''makefile'
XSHELL	= /bin/sh
XCFLAGS	=
XCC = cc -F
X
Xall: from to rsh sherver master
X	
Xfrom: from.s
X	$(CC) -o $@ from.s
X
Xto: to.s
X	$(CC) -o $@ to.s
X
Xrsh: rsh.s prot.s
X	$(CC) -o $@ rsh.s prot.s
X	chmem =500 $@
X
Xsherver: sherver.s prot.s
X	$(CC) -o $@ sherver.s prot.s
X	chmem =500 $@
X
Xmaster: master.s
X	$(CC) -o $@ master.s
X	chmem =500 $@
X
Xsherver.s: sherver.h
Xrsh.s: sherver.h
+ END-OF-FILE makefile
chmod 'u=rw,g=r,o=r' 'makefile'
set `wc -c 'makefile'`
count=$1
case $count in
358)	:;;
*)	echo 'Bad character count in ''makefile' >&2
		echo 'Count should be 358' >&2
esac
echo Extracting 'master.c'
sed 's/^X//' > 'master.c' << '+ END-OF-FILE ''master.c'
X#include <signal.h>
X
Xchar console[] = "/dev/console";
X
Xrun(uid, gid, argv)
Xchar **argv;
X{
X
X	for (;;)
X		switch (fork()) {
X		default:
X			return;
X		case 0:
X			setgid(gid);
X			setuid(uid);
X/*
X			execvp(*argv, argv);
X*/
X			execv(*argv, argv);
X			prints("can't execute %s\n", *argv);
X/*
X			kill(getppid(), SIGTERM);
X*/
X			_exit(1);
X		case -1:
X			sleep(10);
X		}
X}
X
Xmain(argc, argv)
Xchar **argv;
X{
X  register n, uid, gid;
X
X  /* Minix can't do this
X	setpgrp(getpid(), getpid());
X  */
X	if (argc < 4) {
X		prints("Usage: master # uid gid command args ...\n");
X		return(1);
X	}
X	n = atoi(argv[1]);
X	if (n < 1 || n > 20) {
X		prints("Bad count.\n");
X		return(1);
X	}
X	signal(SIGHUP, SIG_IGN);
X	signal(SIGINT, SIG_IGN);
X	signal(SIGQUIT, SIG_IGN);
X
X/* Put the program into the background. */
X	switch (fork()) {
X	case 0:
X		break;
X	case -1:
X		perror(argv[0]);
X		return 1;
X	default:
X		return 0;
X	}
X	uid = atoi(argv[2]);
X	gid = atoi(argv[3]);
X
X/* Start n copies of the program. */
X	do
X		run(uid, gid, &argv[4]);
X	while (--n);
X
X/* Replace each one that dies. */
X	while (wait((int *) 0) > 0)
X		run(uid, gid, &argv[4]);
X	return(0);
X}
+ END-OF-FILE master.c
chmod 'u=rw,g=r,o=r' 'master.c'
set `wc -c 'master.c'`
count=$1
case $count in
1108)	:;;
*)	echo 'Bad character count in ''master.c' >&2
		echo 'Count should be 1108' >&2
esac
echo Extracting 'prot.c'
sed 's/^X//' > 'prot.c' << '+ END-OF-FILE ''prot.c'
X#include <stdio.h>
X#include <pwd.h>
X#include <grp.h>
X
X#define isblank(c)	((c) == ' ' || (c) == '\t' || (c) == '\n')
X
X#define MAXTOKEN	16
X
Xstatic char *gettok(fp)
XFILE *fp;
X{
X	static char buf[MAXTOKEN + 1];
X	register char c, *p = buf;
X
X	do		/* skip blanks */
X		if ((c = getc(fp)) == EOF)
X			return(0);
X	while (isblank(c));
X	do {
X		if (c == '#') {		/* skip comment */
X			while ((c = getc(fp)) != EOF)
X				if (c == '\n') break;
X			break;
X		}
X		*p++ = c;
X	} while (c != ':' && (c = getc(fp)) != EOF && !isblank(c));
X	*p++ = 0;
X	return(buf);
X}
X
Xstatic number(p)
Xchar *p;
X{
X	int n;
X
X	return sscanf(p, "%d", &n) == 1 ? n : -1;
X}
X
Xchkprot(chkfil, chkdefault, uid, gid)
Xchar *chkfil;
Xchar *chkdefault;
X{
X	register userchk = 0, n;
X	register FILE *fp;
X	register char *p;
X	register struct passwd *pw;
X	register struct group *gr;
X	extern FILE *fopen();
X	extern struct passwd *getpwuid();
X	extern struct group *getgrgid();
X
X	pw = getpwuid(uid);
X	endpwent();
X	gr = getgrgid(gid);
X	endgrent();
X	if ((fp = fopen(chkfil, "r")) == NULL && (fp = fopen(chkdefault, "r")) == NULL)
X		return(-1);
X	while ((p = gettok(fp)) != 0)
X		if (strcmp(p, "group:") == 0)
X			userchk = 0;
X		else if (strcmp(p, "user:") == 0)
X			userchk = 1;
X		else if (userchk) {
X			if (pw && strcmp(p, pw->pw_name) == 0 ||
X							uid == number(p)) {
X				fclose(fp);
X				return(1);
X			}
X		}
X		else
X			if (gr && strcmp(p, gr->gr_name) == 0 ||
X							gid == number(p)) {
X				fclose(fp);
X				return(1);
X			}
X	return(0);
X}
+ END-OF-FILE prot.c
chmod 'u=rw,g=r,o=r' 'prot.c'
set `wc -c 'prot.c'`
count=$1
case $count in
1465)	:;;
*)	echo 'Bad character count in ''prot.c' >&2
		echo 'Count should be 1465' >&2
esac
echo Extracting 'rcp'
sed 's/^X//' > 'rcp' << '+ END-OF-FILE ''rcp'
X: Copy a file from any machine to any other machine.
Xusage="Usage: $0 [machine!]from-file [machine!]to-file"
XPATH=/usr/local:/bin:/usr/bin
XCDPATH=
Xcase $# in
X2)	:
X	;;
X*)	echo "$usage" 1>&2
X	exit 1
Xesac
Xfrom=$1 to=$2
Xcase $from in
X*!*)	IFS="!"
X	set $from
X	case $# in
X	2)	from_mach=$1 from_file=$2 IFS=" "
X		;;
X	*)	echo "$usage" 1>&2
X		exit 1
X	esac
X	;;
X*)	from_file=$from
Xesac
Xcase "$from_file" in
X"")	echo "$usage" 1>&2
X	exit 1
Xesac
Xcase $to in
X*!*)	IFS="!"
X	set $to
X	case $# in
X	2)	to_mach=$1 to_file=$2 IFS=" "
X		;;
X	*)	echo "$usage" 1>&2
X		exit 1
X	esac
X	;;
X*)	to_file=$to
Xesac
Xcase "$to_file" in
X"")	echo "$usage" 1>&2
X	exit 1
Xesac
Xcase "$from_mach" in
X"$to_mach")
X	: machines equal
X	case "$to_mach" in
X	"")	: local
X		cp "$from_file" "$to_file"
X		;;
X	*)	: remote
X		rsh "$to_mach" "cp $from_file $to_file"
X		;;
X	esac
X	;;
X*)	: machines not equal
X	case "$to_mach" in
X	"")	: to local
X		if test -d "$to_file"
X		then	rsh -e "$from_mach" "cat $from_file" >"$to_file/`basename $from_file`"
X		else	rsh -e "$from_mach" "cat $from_file" >"$to_file"
X		fi
X		;;
X	*)	: to remote
X		case "$from_mach" in
X		"")	: from local
X			rsh -i "$to_mach" "if test -d $to_file; then cat >$to_file/`basename $from_file`; else cat >$to_file; fi" <"$from_file"
X			;;
X		*)	: from remote
X			rsh -e "$from_mach" "cat $from_file" | rsh -i "$to_mach" "if test -d $to_file; then cat >$to_file/`basename $from_file`; else cat >$to_file; fi"
X			;;
X		esac
X		;;
X	esac
X	;;
Xesac
+ END-OF-FILE rcp
chmod 'u=rwx,g=rx,o=rx' 'rcp'
set `wc -c 'rcp'`
count=$1
case $count in
1437)	:;;
*)	echo 'Bad character count in ''rcp' >&2
		echo 'Count should be 1437' >&2
esac
echo Extracting 'rsh.c'
sed 's/^X//' > 'rsh.c' << '+ END-OF-FILE ''rsh.c'
X/*	rsh [-ei] machine command
X *
X *	-b:	run remote process in background
X *	-e:	separate error output
X *	-i:	send input
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include "amoeba.h"
X#include "sherver.h"
X
Xchar *prog, *mach, buf[BUFFERSIZE];
X
Xusage(){
X	fprintf(stderr, "Usage: %s [-bei] machine command ...\n", prog);
X	exit(1);
X}
X
Xpanic(s)
Xchar *s;
X{
X	fprintf(stderr, "%s: %s\n", prog, s);
X	exit(1);
X}
X
Xchar *collect(buf, vec, sep)
Xchar *buf, **vec, sep;
X{
X	register char *p;
X
X	while ((p = *vec++) != 0) {
X		while (*p != 0) {
X			*buf++ = *p++;
X			if (buf == &buf[BUFFERSIZE])
X				panic("environment too large\n");
X		}
X		*buf++ = *vec == 0 ? 0 : sep;
X	}
X	return(buf);
X}
X
Xchar *setupbuf(argv, flags)
Xchar **argv;
Xint *flags;
X{
X	register char *p;
X	extern char **environ, *getenv();
X
X	if (*argv == 0) {
X		if ((p = getenv("SHELL")) == 0)
X			p = "/bin/sh";
X		if (strlen(p) > BUFFERSIZE - 10) /* 10 > strlen("exec  -i") */
X			panic("pathname of shell too large");
X		sprintf(buf, "exec %s -i", p);
X		p = &buf[strlen(buf) + 1];
X		*flags |= IFLG;
X	}
X	else
X		p = collect(buf, argv, ' ');
X	return collect(p, environ, 0);
X}
X
Xexecute(hdr, p, flags)
Xheader *hdr;
Xchar *p;
X{
X	register unshort cnt;
X
X	timeout(50);
X	strncpy(&hdr->h_port, mach, PORTSIZE);
X	hdr->h_command = EXEC_COMMAND;
X	hdr->h_size = p - buf;
X	hdr->h_extra = flags;
X	cnt = trans(hdr, buf, p - buf, hdr, buf, BUFFERSIZE);
X	if ((short) cnt < 0) {
X		fprintf(stderr, "%s: %s not available\n", prog, mach);
X		return(0);
X	}
X	if (hdr->h_status != COMM_DONE) {
X		if (cnt == 0)
X			fprintf(stderr, "can't execute command\n");
X		else
X			fprintf(stderr, "%.*s\n", cnt, buf);
X		return(0);
X	}
X	return(1);
X}
X
Xalrm(){
X	fprintf(stderr, "rsh: getreq timed out\n");
X	exit(1);
X}
X
Xcommandloop(hdr)
Xheader *hdr;
X{
X	register unshort cnt;
X
X	for (;;) {
X		alarm(12*60*60);
X		cnt = getreq(hdr, buf, BUFFERSIZE);
X		alarm(0);
X		if ((short) cnt < 0) {
X			fprintf(stderr, "getreq failed\n");
X			return(-1);
X		}
X		switch (hdr->h_command) {
X		case READ_FD:
X			if (hdr->h_extra < NFD)
X				cnt = read(hdr->h_extra, buf, hdr->h_size);
X			else
X				fprintf(stderr, "read: bad fd\n");
X			hdr->h_size = (unshort) cnt;
X			putrep(hdr, buf, cnt < 0 ? 0 : cnt);
X			if (cnt == 0)
X				return(0);
X			break;
X		case WRITE_FD:
X			if (hdr->h_extra < NFD)
X				if (cnt == 0)
X					close(hdr->h_extra);
X				else
X					write(hdr->h_extra, buf, cnt);
X			else
X				fprintf(stderr, "write: bad fd\n");
X			putrep(hdr, NILBUF, 0);
X			break;
X		case EXIT_STATUS:
X			if (cnt != 0) {
X				write(2, "Remote message: ", 16);
X				write(2, buf, cnt);
X				write(2, "\n", 1);
X			}
X			putrep(hdr, NILBUF, 0);
X			return(hdr->h_extra >> 8);
X			break;
X		default:
X			fprintf(stderr, "unknown command\n");
X			putrep(hdr, NILBUF, 0);
X		}
X	}
X}
X
Xsetupin(hdr)
Xheader *hdr;
X{
X	register pid;
X
X	uniqport(&hdr->h_priv.prv_random);
X	if ((pid = fork()) < 0) {
X		perror(prog);
X		exit(-1);
X	}
X	if (pid == 0) {
X		hdr->h_port = hdr->h_priv.prv_random;
X		_exit(commandloop(hdr));   /* get read commands from sherver */
X	}
X	return(pid);
X}
X
Xmain(argc, argv)
Xchar **argv;
X{
X	char *p;
X	header hdr;
X	register pid, status;
X	int flags;
X
X#ifdef sun
X	put_user_name_in_env();
X#endif
X	prog = *argv++;
X	if (argc == 1)
X		usage();
X	signal(SIGALRM, alrm);
X	while (*argv != 0 && **argv == '-') {
X		while (*++*argv)
X			switch (**argv) {
X			case 'b':	flags |= BFLG;		break;
X			case 'e':	flags |= EFLG;		break;
X			case 'i':	flags |= IFLG;		break;
X			default:	usage();
X			}
X		argv++;
X	}
X	if ((mach = *argv++) == 0)
X		usage();
X	chkperm(mach);
X	p = setupbuf(argv, &flags);	/* get command and environment */
X	if (flags & IFLG)		/* set up input process */
X		pid = setupin(&hdr);
X	if (!execute(&hdr, p, flags)) {	/* send command to sherver */
X		if (flags & IFLG)
X			kill(pid, SIGKILL);
X		exit(1);
X	}
X	if (!(flags & BFLG))		/* get commands from sherver */
X		status = commandloop(&hdr);
X	if (flags & IFLG) {		/* wait for input process */
X		close(0); close(1); close(2);
X		while (wait((int *) 0) != pid)
X			;
X	}
X	exit(status);
X}
X
Xchkperm(svport)
Xchar *svport;
X{
X	static char chkfil[] = "/etc/XXXXXXXXXXXXXX";
X	extern char *strchr();
X
X	sprintf(strchr(chkfil, 'X'), "rsh:%.14s", svport);
X	if (chkprot(chkfil, "/etc/rsh:default", geteuid(), getegid()) == 0)
X		panic("permission denied");
X}
X
Xchar *strchr(s, c)
Xregister char *s;
X{
X	while (*s) {
X		if (*s == c)
X			return s;
X		s++;
X	}
X	return 0;
X}
X
X#ifdef sun
X#include <pwd.h>
X
Xput_user_name_in_env()
X{
X	extern struct passwd *getpwuid();
X	register struct passwd *pw;
X	static char buf[512];
X	char host[10];
X
X	gethostname(host, sizeof host);
X	pw = getpwuid(getuid());
X	sprintf(buf, "UserName=%s@%s", pw ? pw->pw_name : "???", host);
X	putenv(buf);
X}
X#endif sun
+ END-OF-FILE rsh.c
chmod 'u=rw,g=r,o=r' 'rsh.c'
set `wc -c 'rsh.c'`
count=$1
case $count in
4628)	:;;
*)	echo 'Bad character count in ''rsh.c' >&2
		echo 'Count should be 4628' >&2
esac
echo Extracting 'sherver.c'
sed 's/^X//' > 'sherver.c' << '+ END-OF-FILE ''sherver.c'
X#include <stdio.h>
X#include <errno.h>
X#include <signal.h>
X#include "amoeba.h"
X#include "sherver.h"
X
X/* isn't minix wonderful */
X#undef	BUFFERSIZE
X#define	BUFFERSIZE	8192
X
X#define COMPATIBLE			/* with the new rsh */
X
X#define MAXWAIT	(4*60*60)		/* maximum waiting time in seconds */
X#define Secs *10
X#define LOCATETIMER	30 Secs
X
X#ifdef DEBUG
Xchar *
Xportstr(p) port *p; {
X	static char strbuf[80];
X
X	sprintf(strbuf,"%x:%x:%x:%x:%x:%x",
X		p->_portbytes[0]&0xFF,
X		p->_portbytes[1]&0xFF,
X		p->_portbytes[2]&0xFF,
X		p->_portbytes[3]&0xFF,
X		p->_portbytes[4]&0xFF,
X		p->_portbytes[5]&0xFF);
X	return strbuf;
X}
X#endif
X
Xheader hdr;
Xchar *prog, buf[BUFFERSIZE], *envvec[MAXENV], *errstr;
Xint pidlist[NFD];
Xextern errno;
Xstatic char *sig[] = {
X	"signal 0",
X	"hangup",
X	"interrupt",
X	"quit",
X	"illegal instruction",
X	"trace/BPT trap",
X	"IOT trap",
X	"EMT trap",
X	"floating exception",
X	"kill",
X	"bus error",
X	"memory fault",
X	"bad system call",
X	"broken pipe",
X	"alarm call",
X	"terminate",
X	"urgent socket",
X	"stop (signal)",
X	"stop",
X	"continue",
X	"child exited",
X	"stop (tty input)",
X	"stop (tty output)",
X	"tty input interrupt",
X	"cputime limit exceeded",
X	"filesize limit exceeded",
X	"virtual time alarm",
X	"profiling timer alarm",
X};
X
Xpanic(s, arg)
Xchar *s;
X{
X	register FILE *f;
X	FILE *	fopen();
X
X#ifdef DEBUG
X#define f stderr
X#else
X	if (f = fopen("/dev/tty0", "w")) {
X#endif DEBUG
X		fprintf(f, "%s: ", prog);
X		fprintf(f, s, arg);
X		fprintf(f, "\n");
X#ifdef DEBUG
X#undef f
X#else
X		fclose(f);
X	}
X#endif DEBUG
X	_exit(1);
X}
X
Xalrm(){		/* set alarm again to avoid races */
X	signal(SIGALRM, alrm);
X	alarm(MAXWAIT);
X}
X
Xkillall(){	/* kill all the created processes */
X	register n;
X
X	for (n = 0; n < NFD; n++)
X		if (pidlist[n] != 0)
X			kill(pidlist[n], SIGKILL);
X}
X
Xtrap(){		/* got SIGAMOEBA */
X	killall();
X	_exit(0);
X}
X
Xcopyloop(pp, rfd, wfd)
Xport *pp;
X{
X	register unshort cnt;
X	register n;
X
X	do {
X		alarm(MAXWAIT);
X		n = read(rfd, buf, BUFFERSIZE);
X		alarm(0); alarm(0);
X		if (n < 0) {
X			strcpy(buf, errno==EINTR ? "waited too long for input"
X						 : "read error");
X			killall();
X			return(1);
X		}
X		hdr.h_port = *pp;
X		hdr.h_command = WRITE_FD;
X		hdr.h_size = n;
X		hdr.h_extra = wfd;
X		cnt = trans(&hdr, buf, (unshort) n, &hdr, NILBUF, 0);
X		if (cnt != 0)
X			panic("trans failed (%d iso 0)", (short) cnt);
X	} while (n != 0);
X	return(0);
X}
X
Xsetupin(hdr)
Xheader *hdr;
X{
X	int fd, p[2];
X	register unshort cnt;
X	port svport;
X
X	if (pipe(p) < 0)
X		errstr = "can't pipe";
X	else if (p[0] != 0)
X		errstr = "pipe returned wrong fd";
X	else if ((pidlist[0] = fork()) < 0)
X		errstr = "can't fork";
X	else if (pidlist[0] == 0) {
X		close(p[0]);
X		signal(SIGPIPE, SIG_IGN);
X#ifdef COMPATIBLE
X		if (!NullPort(&hdr->h_signature))
X			svport = hdr->h_signature;
X		else
X#endif
X		svport = hdr->h_priv.prv_random;
X		for (;;) {
X			hdr->h_port = svport;
X			hdr->h_command = READ_FD;
X			hdr->h_size = BUFFERSIZE;
X			hdr->h_extra = 0;
X#ifdef DEBUG
X			fprintf(stderr,"Using read port %s\n",portstr(&hdr->h_port));
X#endif
X			cnt = trans(hdr, NILBUF, 0, hdr, buf, BUFFERSIZE);
X			if ((short) cnt < 0)
X				panic("read trans failed (%d)", (short) cnt);
X			if (cnt == 0)
X				_exit(0);
X			if (write(p[1], buf, cnt) != cnt) {
X				timeout(300);
X				hdr->h_port = svport;
X				hdr->h_command = EXIT_STATUS;
X				hdr->h_extra = 0x100;
X				if ((cnt = trans(hdr, NILBUF, 0, hdr, NILBUF, 0)) != 0)
X					panic("trans failed (%d iso 0)", (short) cnt);
X				_exit(1);
X			}
X		}
X	}
X	else
X		close(p[1]);
X}
X
Xsetuperr(){
X	int errpipe[2];
X
X	if (pipe(errpipe) < 0) {
X		errstr = "can't pipe";
X		return(-1);
X	}
X	if ((pidlist[2] = fork()) < 0) {
X		close(errpipe[0]);
X		close(errpipe[1]);
X		errstr = "can't fork";
X		return(-1);
X	}
X	if (pidlist[2] == 0) {
X		close(errpipe[1]);
X		timeout(LOCATETIMER);
X		_exit(copyloop(&hdr.h_port, errpipe[0], 2));
X	}
X	close(errpipe[0]);
X	return(errpipe[1]);
X}
X
Xsplitup(size){
X	register char *p = buf, *top = &buf[size], **vec = envvec;
X
X	while (p != top) {
X		if (vec == &envvec[MAXENV]) {
X			errstr = "too much environment";
X			return(0);
X		}
X		*vec++ = p;
X		while (*p++ != 0)
X			if (p == top) {
X				errstr = "bad format";
X				return(0);
X			}
X	}
X	*vec = 0;
X	return(1);
X}
X
Xrunit(outpipe, errout)
Xint outpipe[2];
X{
X	register fd;
X	register char *homedir;
X	extern char **environ, *getenv();
X
X	close(1); close(2);
X	if (hdr.h_extra & BFLG) {
X		if ((fd = open("/dev/null", 1)) != 1)
X			panic("open returned wrong fd (%d iso 1)", fd);
X		else if ((fd = dup(1)) != 2)
X			panic("dup returned wrong fd (%d iso 2)", fd);
X	}
X	else {
X		close(outpipe[0]);	/* outpipe[0] >= 1 */
X		if ((fd = dup(outpipe[1])) != 1)
X			panic("dup returned wrong fd (%d iso 1)", fd);
X		if (hdr.h_extra & EFLG) {
X			if ((fd = dup(errout)) != 2)
X				panic("dup returned wrong fd (%d iso 2)", fd);
X			else
X				close(errout);
X		}
X		else if ((fd = dup(1)) != 2)
X			panic("dup returned wrong fd (%d iso 2)", fd);
X	}
X	for (fd = 3; fd < 20; fd++)
X		close(fd);
X#ifdef LOG
X	{
X#include <fcntl.h>
X		register int logfd;
X		
X		logfd = open("/usr/tmp/rsh.log", O_WRONLY|O_APPEND|O_CREAT, 0244);
X		if (logfd >= 0) {
X#include <time.h>
X			register char *s;
X			register struct tm *tm;
X			long t;
X			char buf[1024];		/* had better be large enough */
X			static char *months[] = {
X				"Jan", "Feb", "Mar", "Apr", "May", "Jun",
X				"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
X			};
X
X			time(&t);
X			tm = localtime(&t);
X			environ = &envvec[1];
X			s = getenv("UserName");
X			if (s == 0)
X				s = getenv("HOME");
X			if (s == 0)
X				s = getenv("LOGNAME");
X			if (s == 0)
X				s = getenv("USER");
X			sprintf(buf, "%02d-%s-%02d %02d:%02d:%02d %s\t%s%s\n",
X				tm->tm_mday, months[tm->tm_mon], tm->tm_year,
X				tm->tm_hour, tm->tm_min, tm->tm_sec,
X				s?s:"???", envvec[0],
X				hdr.h_extra & IFLG ? " (interactive)" : "");
X			lseek(logfd, 0L, 2);
X			write(logfd, buf, strlen(buf));
X			close(logfd);
X		}
X	}
X#endif
X	environ = &envvec[1];
X	if ((homedir = getenv("HOME")) == 0 || chdir(homedir) < 0)
X		chdir("/");
X	execl("/bin/sh", "sh", "-c", envvec[0], (char *) 0);
X	panic("can't execute shell", 0);
X}
X
Xexecomm(size){
X	int outpipe[2], errout;
X
X	if (!splitup(size))
X		return(-1);
X	if (!(hdr.h_extra & BFLG)) {
X		if ((hdr.h_extra & EFLG) && (errout = setuperr()) < 0)
X			return(-1);
X		if (pipe(outpipe) < 0) {
X			if (hdr.h_extra & EFLG)
X				close(errout);
X			errstr = "can't pipe";
X			return(-1);
X		}
X	}
X	if ((pidlist[1] = fork()) < 0) {
X		if (!(hdr.h_extra & BFLG)) {
X			if (hdr.h_extra & EFLG)
X				close(errout);
X			close(outpipe[0]);
X			close(outpipe[1]);
X		}
X		errstr = "can't fork";
X		return(-1);
X	}
X	if (pidlist[1] == 0) 
X		runit(outpipe, errout);
X	if (hdr.h_extra & BFLG)
X		return(0);
X	if (hdr.h_extra & EFLG)
X		close(errout);
X	close(outpipe[1]);
X	return(outpipe[0]);
X}
X
Xawaitchild(hdr, status)
Xheader *hdr;
X{
X	register pid, n;
X	int wstat;
X
X	if (status == 0) {
X		alarm(MAXWAIT);
X		while ((pid = wait(&wstat)) > 0) {
X			if (pid == pidlist[1]) {
X				pidlist[1] = 0;
X				hdr->h_extra = status;
X			}
X			status = wstat;
X		}
X		alarm(0); alarm(0);
X		if (pidlist[1] != 0) {
X			strcpy(buf, errno == EINTR ? "waited too long"
X						   : "wait error");
X			killall();
X			hdr->h_extra = 0x100;
X		}
X		else if (status & 0xFF)
X			if ((status & 0x7F) < sizeof(sig) / sizeof(sig[0]))
X				strcpy(buf, sig[status & 0x7F]);
X			else
X				sprintf(buf, "signal %d", status & 0x7F);
X		else
X			buf[0] = 0;
X		if (status & 0x80)
X			strcat(buf, " - core dumped");
X	}
X	else
X		hdr->h_extra = status << 8;
X	timeout(300);
X	hdr->h_command = EXIT_STATUS;
X	if ((n = trans(hdr, buf, strlen(buf), hdr, NILBUF, 0)) != 0)
X		panic("trans failed (%d iso 0)", (short) n);
X}
X
Xmain(argc, argv)
Xchar **argv;
X{
X	register unshort cnt;
X	register fd;
X	unshort getreq(), putrep();
X
X	prog = argv[0];
X	if (argc != 2)
X		panic("usage: sherver machine", 0);
X	signal(SIGALRM, alrm);
X	signal(SIGAMOEBA, trap);
X	strncpy(&hdr.h_port, argv[1], PORTSIZE);
X	cnt = getreq(&hdr, buf, BUFFERSIZE);
X	if ((short) cnt < 0)
X		panic("getreq failed (%d)", (short) cnt);
X	if (hdr.h_size == cnt) {
X		close(0);
X		if (hdr.h_extra & IFLG)
X			setupin(&hdr);
X		else if (open("/dev/null", 0) != 0)
X			errstr = "can't open /dev/null";
X		if (errstr == 0) {
X			uniqport(&hdr.h_port);
X			fd = execomm(cnt);
X		}
X	}
X	else
X		errstr = hdr.h_size > BUFFERSIZE ? "request too large" :
X								"bad format";
X	if (errstr == 0) {
X		hdr.h_status = COMM_DONE;
X		putrep(&hdr, NILBUF, 0);
X		if (!(hdr.h_extra & BFLG)) {
X			timeout(LOCATETIMER);
X			awaitchild(&hdr, copyloop(&hdr.h_port, fd, 1));
X		}
X	}
X	else {
X		hdr.h_status = COMM_ERROR;
X		putrep(&hdr, errstr, strlen(errstr));
X	}
X}
+ END-OF-FILE sherver.c
chmod 'u=rw,g=r,o=r' 'sherver.c'
set `wc -c 'sherver.c'`
count=$1
case $count in
8478)	:;;
*)	echo 'Bad character count in ''sherver.c' >&2
		echo 'Count should be 8478' >&2
esac
echo Extracting 'sherver.h'
sed 's/^X//' > 'sherver.h' << '+ END-OF-FILE ''sherver.h'
X#define BUFFERSIZE	20480
X#define MAXENV		  100
X#define NFD		    3
X
X/* initial command from rsh to sherver */
X#define EXEC_COMMAND	1
X
X/* flags in h_extra for EXEC_COMMAND */
X#define BFLG		0x01
X#define EFLG		0x02
X#define IFLG		0x04
X
X/* commands from sherver to rsh (parameter (fd or status) in h_extra) */
X#define READ_FD		1
X#define WRITE_FD	2
X#define EXIT_STATUS	4
X
X/* replies */
X#define COMM_DONE	0
X#define COMM_ERROR	-1
+ END-OF-FILE sherver.h
chmod 'u=rw,g=r,o=r' 'sherver.h'
set `wc -c 'sherver.h'`
count=$1
case $count in
421)	:;;
*)	echo 'Bad character count in ''sherver.h' >&2
		echo 'Count should be 421' >&2
esac
echo Extracting 'to.c'
sed 's/^X//' > 'to.c' << '+ END-OF-FILE ''to.c'
X#include <stdio.h>
X#include "amoeba.h"
X
X#define BUFSIZE		20480
X
Xmain(argc, argv)
Xchar **argv;
X{
X	header hdr;
X	char *buf, *malloc();
X	char *cmd = argv[0];
X	unshort cnt, bufsize = BUFSIZE;
X	unshort trans();
X
X	if (argc > 1 && strncmp(argv[1], "-t", 2) == 0) {
X		timeout(atoi(&argv[1][2]), 0);
X		argc--;
X		argv++;
X	}
X	if (argc != 2 && argc != 3) {
X		fprintf(stderr, "Usage: %s port\n", cmd);
X		exit(-1);
X	}
X	if (argc == 3)
X		bufsize = atoi(argv[2]);
X	if ((buf = malloc(bufsize)) == NULL) {
X		fprintf(stderr, "%s: out of memory\n", cmd);
X		exit(-1);
X	}
X	strncpy(&hdr.h_port, argv[1], PORTSIZE);
X	for (;;) {
X		cnt = read(0, buf, bufsize);
X		if ((short) cnt < 0) {
X			perror("read");
X			exit(-3);
X		}
X		if (trans(&hdr, buf, cnt, &hdr, NILBUF, 0) != 0) {
X			fprintf(stderr, "%s: trans failed\n", cmd);
X			exit(-4);
X		}
X		if (hdr.h_status) {
X			fprintf(stderr, "%s: write failed in from\n", cmd);
X			exit(-5);
X		}
X		if (cnt == 0)
X			exit(0);
X	}
X}
+ END-OF-FILE to.c
chmod 'u=rw,g=r,o=r' 'to.c'
set `wc -c 'to.c'`
count=$1
case $count in
938)	:;;
*)	echo 'Bad character count in ''to.c' >&2
		echo 'Count should be 938' >&2
esac
exit 0