BSD Networking commands for UNIX PC STARLAN. Part 3 of 3.

Roger Florkowski roger at taliesin.UUCP
Thu Sep 20 15:12:43 AEST 1990


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 3)."
# Contents:  lib/sigport.c rcp.c rtape.c
# Wrapped by roger at taliesin on Wed Sep 19 23:37:55 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f lib/sigport.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"lib/sigport.c\"
else
echo shar: Extracting \"lib/sigport.c\" \(5911 characters\)
sed "s/^X//" >lib/sigport.c <<'END_OF_lib/sigport.c'
X/* $Id: sigport.c,v 1.1 90/09/19 23:25:01 roger C_1 $
X *
X *	sigport.c: manage signals between local and remote
X *
X *	Roger Florkowski
X *	cs.utexas.edu!taliesin!roger
X */
X
X/* 
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *	
X * Main purpose of this file is to provide a way for a local process
X * to send a signal to a remote process when the local process has
X * been interrupted.
X */
X
X/* I actually got poll() to do something. */
X#define USEPOLL
X
X#include <net/sys/tiuser.h>
X#ifdef USEPOLL
X#include <net/sys/poll.h>
X#endif
X#include <sys/utsname.h>
X#include <stdio.h>
X#include <fcntl.h>
X#include "rcmds.h"
X
Xextern errno, t_errno;
Xstatic int rgetstr();
X
X/* fire up a second communications channel for the signal monitor */
X/* this routine gets executed by the local machine, ie, remsh or rexec */
Xint
XrsignalPort(fd)
Xint fd;		/* remote fd */
X{
X    struct t_call *call;
X    char buf[BUFSIZ];
X    int signalFD, namesz;
X
X    /* first find out who we should connect to */
X    if ((namesz = rgetstr (fd, buf, sizeof (buf))) < 0) {
X	DEBUG3("rgetstr failed, ret %d, errno %d, t_errno %d\n", namesz,
X		errno, t_errno);
X	return (-1);
X    }
X    DEBUG2("rgetstr returned [%d], %s\n", namesz, buf);
X
X    /* open starlan in connection-mode (character mode) */
X    /* bind to local communications endpoint */
X    if ((signalFD = openbind(T_CCOTS, NULL)) < 0) {
X	DEBUG2("openbind failed. errno %d t_errno %d\n", errno, t_errno);
X	return (-1);
X    }
X    DEBUG1("open returned %d\n", signalFD);
X
X    /* now connect to what the remote told us */
X    if ((call = (struct t_call *)t_alloc (signalFD,T_CALL,T_ALL)) == NULL)
X	return (-1);
X    strncpy (call->addr.buf, buf, namesz);
X    call->addr.len = namesz;
X    DEBUG3("about to connect to %*.*s\n", namesz, namesz, call->addr.buf);
X    if (!lname2addr (signalFD, &(call->addr))){
X	DEBUG2("lname2addr failed. errno %d t_errno %d\n", errno, t_errno);
X	return (-1);
X    }
X    if (t_connect (signalFD, call, NULL)) {
X	DEBUG2("t_connect failed. errno %d t_errno %d\n", errno, t_errno);
X	if (t_errno == TLOOK) {
X	    int look;
X	    if (look = t_look (signalFD)) 
X		DEBUG2("t_look failed. errno %d t_errno %d\n", errno, t_errno);
X	    else
X		DEBUG1("t_look returned %d\n", look);
X	}
X	return (-1);
X    }
X    DEBUG3("connected to %*.*s\n", namesz, namesz, call->addr.buf);
X    t_free (call, T_CALL);
X
X    return (signalFD);
X}
X
Xstatic int
Xrgetstr(fd, buf, cnt)
Xint fd;
Xchar *buf;
Xint cnt;
X{
X    int rcvflags, ccnt;
X    char c, *bp;
X
X    bp = buf;
X    ccnt = 0;
X    do {
X	if (t_rcv(fd, &c, 1, &rcvflags) != 1)
X	    return (-1);
X	*buf++ = c;
X	if (cnt == ++ccnt) 
X	    return (-2);
X    } while (c != 0);
X    return (ccnt - 1);
X}
X
X
X/* fire up a second communications channel for the signal monitor */
X/* this routine gets executed by the remote machine, ie, rshd or rexecd */
Xint
XsignalPort(fd, port)
Xint fd;
Xint port;	/* port the daemon os running on */
X{
X    struct t_bind *reqbind, *retbind;
X    struct t_call *call;
X    struct utsname utsname;
X    char nodename[sizeof (utsname.nodename)+1];
X    int signalFD;
X#ifdef USEPOLL
X    int myfd, i;
X    struct pollfd *pp, fds[2];
X#endif /* USEPOLL */
X
X    DEBUG("signal port requested\n");
X
X    /* open starlan in connection-mode (character mode) */
X    if ((signalFD = openslan(NULL, O_RDWR, T_CCOTS)) < 0) {
X	DEBUG2("openslan failed. errno %d t_errno %d\n", errno, t_errno);
X	return (-1);
X    }
X    DEBUG1("open returned %d\n", signalFD);
X
X    /* bind to <hostname>.<port> for listening */
X    if (uname (&utsname) < 0) 
X	return (-1);
X    if ((reqbind = (struct t_bind *)t_alloc (signalFD,T_BIND,T_ALL)) == NULL)
X	return (-1);
X    if ((retbind = (struct t_bind *)t_alloc (signalFD,T_BIND,T_ALL)) == NULL)
X	return (-1);
X    strncpy (nodename, utsname.nodename, sizeof (utsname.nodename));
X    sprintf (reqbind->addr.buf, "%s.%d", nodename, port);
X    DEBUG1("about to bind to %s\n", reqbind->addr.buf);
X    reqbind->addr.len = strlen (reqbind->addr.buf);
X
X    reqbind->qlen = 1;				/* assign for listening */
X    if (!lname2addr (signalFD, &(reqbind->addr))) {
X	DEBUG2("lname2addr failed. errno %d t_errno %d\n", errno, t_errno);
X	return (-1);
X    }
X    if (t_bind (signalFD, reqbind, retbind)) {
X	DEBUG2("t_bind failed. errno %d t_errno %d\n", errno, t_errno);
X	return (-1);
X    }
X
X    /* tell remote what to bind to */
X    (void) t_snd(fd, retbind->addr.buf, retbind->addr.len+1, NULL);
X    DEBUG3("bound to %*.*s\n", retbind->addr.len, retbind->addr.len,
X	    retbind->addr.buf);
X    t_free (reqbind, T_BIND);
X    t_free (retbind, T_BIND);
X
X    /* now listen for incoming call from caller (will hang forever) */
X    /* TODO: poll both signalFD and fd.  Maybe we received a disconnect
X     * 		on fd? 
X     */
X    if ((call = (struct t_call *)t_alloc (signalFD,T_CALL,T_ALL)) == NULL)
X	return (-1);
X#ifdef USEPOLL
X    fds[0].fd = fd;
X    fds[1].fd = signalFD;
X    fds[0].events = fds[1].events = POLLIN;
X    DEBUG2("polling on %d and %d\n", fd, signalFD);
X    if (poll (fds, 2, -1) == -1) {
X	DEBUG("poll failed\n");
X	return (-1);
X    }
X    DEBUG("returned from poll\n");
X    for (i = 0, pp = fds, myfd = -1; i < 2; i++, pp++) {
X	if (pp->revents) {		/* got an event */
X	    if (pp->revents != POLLIN) {
X		DEBUG1("poll failed, revents = %d\n", pp->revents);
X		return (-1);
X	    }
X	    myfd = pp->fd;
X	}
X    }
X    if (myfd != signalFD) {
X	DEBUG2("expected fd %d, got fd %d\n", signalFD, myfd);
X	return (-1);
X    }
X#endif /* USEPOLL */
X    DEBUG1("listening on %d\n", signalFD);
X    if (t_listen (signalFD, call)) {
X	DEBUG2("t_listen failed. errno %d t_errno %d\n", errno, t_errno);
X	return (-1);
X    }
X
X    if (t_accept (signalFD, signalFD, call)) {
X	DEBUG2("t_accept failed. errno %d t_errno %d\n", errno, t_errno);
X	return (-1);
X    }
X    t_free (call, T_CALL);
X    return (signalFD);
X}
END_OF_lib/sigport.c
if test 5911 -ne `wc -c <lib/sigport.c`; then
    echo shar: \"lib/sigport.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f rcp.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"rcp.c\"
else
echo shar: Extracting \"rcp.c\" \(18300 characters\)
sed "s/^X//" >rcp.c <<'END_OF_rcp.c'
X/* $Id: rcp.c,v 1.1 90/09/19 23:27:22 roger C_1 $
X *
X *	This is a UnixPC STARLAN port of BSD's rcp.
X *	Roger Florkowski
X *	cs.utexas.edu!taliesin!roger
X */
X
X/*
X * Copyright (c) 1983 The Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
Xchar copyright[] =
X"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
X All rights reserved.\n";
X#endif /* not lint */
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)rcp.c	5.11 (Berkeley) 9/22/88";
X#endif /* not lint */
X
X/*
X * rcp
X */
X#include <sys/param.h>
X#include <sys/file.h>
X#include <sys/stat.h>
X#include <sys/ioctl.h>
X
X#include <fcntl.h>
X#include <stdio.h>
X#include <signal.h>
X#include <pwd.h>
X#include <ctype.h>
X#include <errno.h>
X
X#include <sys/dir.h>
X#include "rcmds.h"
X
Xint	rem;
Xchar	*colon(), *strchr(), *strrchr(), *malloc(), *strcpy();
Xint	errs;
Xint	lostconn();
Xextern	errno;
Xchar	*sys_errlist[];
Xint	iamremote, targetshouldbedirectory;
Xint	iamrecursive;
Xint	pflag;
Xstruct	passwd *pwd;
Xstruct	passwd *getpwuid();
Xint	userid;
Xint	port;
X
Xstruct buffer {
X	int	cnt;
X	char	*buf;
X} *allocbuf();
X
X/* not defined anywhere ??? (although referenced in the manual) */
Xstruct utimbuf {
X    time_t	actime;
X    time_t	modtime;
X};
X
X/*VARARGS*/
Xint	error();
X
X/* we might be writing to a pipe. t_rcv,t_snd only work directly to starlan */
X/* not needed. RF.
X#define	ga()	 (iamremote ? t_snd(rem,"",1,NULL) : write(rem,"",1))
X#define WRITE(a,b,c)	(iamremote ? t_snd(a,b,c,0) : write(a,b,c))
X#define READ(a,b,c)	(iamremote ? t_rcv(a,b,c,0) : read(a,b,c))
X*/
X
X#define	ga()	 write(rem,"",1)
X#define WRITE(a,b,c)	write(a,b,c)
X#define READ(a,b,c)	read(a,b,c)
X
XFILE	*debug;
Xint 	mypid, Verbose;
X
Xmain(argc, argv)
X	int argc;
X	char **argv;
X{
X	char *targ, *host, *src;
X	char *suser, *tuser, *thost;
X	int i;
X	char buf[BUFSIZ], cmd[16];
X	char *debugfile;
X	int do_debug = 0;
X
X	port = RSHD_PORT;
X	pwd = getpwuid(userid = getuid());
X	if (pwd == 0) {
X		fprintf(stderr, "who are you?\n");
X		exit(1);
X	}
X
X	for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
X		(*argv)++;
X		while (**argv) switch (*(*argv)++) {
X
X		    case 'r':
X			iamrecursive++;
X			break;
X
X		    case 'p':		/* preserve mtimes and atimes */
X			pflag++;
X			break;
X
X		    case 'v':
X			Verbose++;
X			break;
X
X#ifdef DO_DEBUG
X		    case 'D':
X			do_debug = 1;
X			opendebug();
X			break;
X#endif
X		    /* The rest of these are not for users. */
X		    case 'd':
X			targetshouldbedirectory = 1;
X			break;
X
X		    case 'f':		/* "from" */
X			iamremote = 1;
X			DEBUG("from flag, jumping right to source\n");
X			(void) response();
X			(void) setuid(userid);
X			source(--argc, ++argv);
X			exit(errs);
X
X		    case 't':		/* "to" */
X			iamremote = 1;
X			DEBUG("to flag, jumping right to sink\n");
X			(void) setuid(userid);
X			sink(--argc, ++argv);
X			exit(errs);
X
X		    default:
X			usage();
X		}
X	}
X	if (argc < 2)
X		usage();
X	if (argc > 2)
X		targetshouldbedirectory = 1;
X	rem = -1;
X	(void) sprintf(cmd, "rcp%s%s%s%s",
X	    do_debug ? " -D" : "",
X	    iamrecursive ? " -r" : "", pflag ? " -p" : "", 
X	    targetshouldbedirectory ? " -d" : "");
X	(void) signal(SIGPIPE, lostconn);
X	targ = colon(argv[argc - 1]);
X	if (targ) {				/* ... to remote */
X		DEBUG1("[%d] ... to remote\n", mypid);
X		*targ++ = 0;
X		if (*targ == 0)
X			targ = ".";
X		thost = strchr(argv[argc - 1], '@');
X		if (thost) {
X			*thost++ = 0;
X			tuser = argv[argc - 1];
X			if (*tuser == '\0')
X				tuser = NULL;
X			else if (!okname(tuser))
X				exit(1);
X		} else {
X			thost = argv[argc - 1];
X			tuser = NULL;
X		}
X		DEBUG3("[%d] thost=%s\ntuser=%s\n", mypid,
X			thost==NULL?"":thost,
X			tuser==NULL?"":tuser);
X		for (i = 0; i < argc - 1; i++) {
X			src = colon(argv[i]);
X			if (src) {		/* remote to remote */
X				DEBUG1("[%d] remote to remote\n", mypid);
X				*src++ = 0;
X				if (*src == 0)
X					src = ".";
X				host = strchr(argv[i], '@');
X				if (host) {
X					*host++ = 0;
X					suser = argv[i];
X					if (*suser == '\0')
X						suser = pwd->pw_name;
X					else if (!okname(suser))
X						continue;
X		(void) sprintf(buf, "remsh %s -l %s -n %s %s '%s%s%s:%s'",
X					    host, suser, cmd, src,
X					    tuser ? tuser : "",
X					    tuser ? "@" : "",
X					    thost, targ);
X				} else
X		(void) sprintf(buf, "remsh %s -n %s %s '%s%s%s:%s'",
X					    argv[i], cmd, src,
X					    tuser ? tuser : "",
X					    tuser ? "@" : "",
X					    thost, targ);
X				(void) susystem(buf);
X			} else {		/* local to remote */
X				DEBUG1("[%d] local to remote\n", mypid);
X				if (rem == -1) {
X					(void) sprintf(buf, "%s -t %s",
X					    cmd, targ);
X					host = thost;
X					rem = rcmd(host, port, pwd->pw_name,
X					    tuser ? tuser : pwd->pw_name,
X					    buf, 0);
X					if (rem < 0)
X						exit(1);
X					if (response() < 0)
X						exit(1);
X					(void) setuid(userid);
X				}
X				source(1, argv+i);
X			}
X		}
X	} else {				/* ... to local */
X		DEBUG1("[%d] ... to remote\n", mypid);
X		if (targetshouldbedirectory)
X			verifydir(argv[argc - 1]);
X		for (i = 0; i < argc - 1; i++) {
X			src = colon(argv[i]);
X			if (src == 0) {		/* local to local */
X				DEBUG1("[%d] local to local\n", mypid);
X#ifdef future
X				/* could probably use GNUcp for this */
X				(void) sprintf(buf, "/bin/cp%s%s %s %s",
X				    iamrecursive ? " -r" : "",
X				    pflag ? " -p" : "",
X				    argv[i], argv[argc - 1]);
X				(void) susystem(buf);
X#else
X				exit(0);	/* cp -r not supported */
X#endif
X			} else {		/* remote to local */
X				DEBUG1("[%d] remote to local\n", mypid);
X				*src++ = 0;
X				if (*src == 0)
X					src = ".";
X				host = strchr(argv[i], '@');
X				if (host) {
X					*host++ = 0;
X					suser = argv[i];
X					if (*suser == '\0')
X						suser = pwd->pw_name;
X					else if (!okname(suser))
X						continue;
X				} else {
X					host = argv[i];
X					suser = pwd->pw_name;
X				}
X				DEBUG3("[%d] host=%s\nsuser=%s\n", mypid,
X					host==NULL?"":host,
X					suser==NULL?"":suser);
X				(void) sprintf(buf, "%s -f %s", cmd, src);
X				rem = rcmd(host, port, pwd->pw_name, suser,
X				    buf, 0);
X				if (rem < 0)
X					continue;
X/* 				(void) setreuid(0, userid); */
X				sink(1, argv+argc-1);
X/* 				(void) setreuid(userid, 0); */
X				(void) close(rem);
X				rem = -1;
X			}
X		}
X	}
X	DEBUG2("[%d] exiting(%d)\n", mypid, errs);
X	exit(errs);
X}
X
X#ifdef DO_DEBUG
Xopendebug()
X{
X	debug = fopen("/tmp/rcp.out", "a");
X	if (debug == 0)
X	    exit(1);
X	(void) setbuf(debug, (char *)0);
X	DEBUG1("rcp [%d] started\n", mypid = getpid());
X}
X#endif
X
Xverifydir(cp)
X	char *cp;
X{
X	struct stat stb;
X
X	if (stat(cp, &stb) >= 0) {
X		if ((stb.st_mode & S_IFMT) == S_IFDIR)
X			return;
X		errno = ENOTDIR;
X	}
X	error("rcp: %s: %s.\n", cp, sys_errlist[errno]);
X	exit(1);
X}
X
Xchar *
Xcolon(cp)
X	char *cp;
X{
X
X	while (*cp) {
X		if (*cp == ':')
X			return (cp);
X		if (*cp == '/')
X			return (0);
X		cp++;
X	}
X	return (0);
X}
X
Xokname(cp0)
X	char *cp0;
X{
X	register char *cp = cp0;
X	register int c;
X
X	do {
X		c = *cp;
X		if (c & 0200)
X			goto bad;
X		if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
X			goto bad;
X		cp++;
X	} while (*cp);
X	return (1);
Xbad:
X	fprintf(stderr, "rcp: invalid user name %s\n", cp0);
X	return (0);
X}
X
Xsusystem(s)
X	char *s;
X{
X	int status, pid, w;
X	register int (*istat)(), (*qstat)();
X
X	if ((pid = fork()) == 0) {
X		(void) setuid(userid);
X		execl("/bin/sh", "sh", "-c", s, (char *)0);
X		_exit(127);
X	}
X	istat = signal(SIGINT, SIG_IGN);
X	qstat = signal(SIGQUIT, SIG_IGN);
X	while ((w = wait(&status)) != pid && w != -1)
X		;
X	if (w == -1)
X		status = -1;
X	(void) signal(SIGINT, istat);
X	(void) signal(SIGQUIT, qstat);
X	return (status);
X}
X
Xsource(argc, argv)
X	int argc;
X	char **argv;
X{
X	char *last, *name;
X	struct stat stb;
X	static struct buffer buffer;
X	struct buffer *bp;
X	int x, readerr, f, amt;
X	off_t i;
X	char buf[BUFSIZ];
X
X	DEBUG2("[%d] source: iamremote %d, ", mypid, iamremote);
X	DEBUG2("iamrecursive %d, rem %d\n", iamrecursive, rem);
X	for (x = 0; x < argc; x++) {
X		name = argv[x];
X		if (Verbose && !iamremote)
X			fprintf (stderr, "< %s\n", name);
X		DEBUG2("[%d] %s ", mypid, name);
X		if ((f = open(name, 0)) < 0) {
X			error("rcp: %s: %s\n", name, sys_errlist[errno]);
X			continue;
X		}
X		if (fstat(f, &stb) < 0)
X			goto notreg;
X		switch (stb.st_mode&S_IFMT) {
X
X		case S_IFREG:
X			DEBUG("regular file\n");
X			break;
X
X		case S_IFDIR:
X			DEBUG("directory\n");
X			if (iamrecursive) {
X				(void) close(f);
X				rsource(name, &stb);
X				continue;
X			}
X			/* fall into ... */
X		default:
Xnotreg:
X			DEBUG("not reg\n");
X			(void) close(f);
X			error("rcp: %s: not a plain file\n", name);
X			continue;
X		}
X		last = strrchr(name, '/');
X		if (last == 0)
X			last = name;
X		else
X			last++;
X		if (pflag) {
X			/*
X			 * Make it compatible with possible future
X			 * versions expecting microseconds.
X			 */
X			(void) sprintf(buf, "T%ld 0 %ld 0\n",
X			    stb.st_mtime, stb.st_atime);
X			DEBUG2("[%d] source: setimes: %s", mypid, buf);
X			(void) WRITE(rem, buf, strlen(buf));
X			if (response() < 0) {
X				(void) close(f);
X				continue;
X			}
X		}
X		(void) sprintf(buf, "C%04o %ld %s\n",
X		    stb.st_mode&07777, stb.st_size, last);
X		DEBUG2("[%d] source: %s", mypid, buf);
X		(void) WRITE(rem, buf, strlen(buf));
X		if (response() < 0) {
X			(void) close(f);
X			continue;
X		}
X		if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) {
X			(void) close(f);
X			continue;
X		}
X		readerr = 0;
X		for (i = 0; i < stb.st_size; i += bp->cnt) {
X			amt = bp->cnt;
X			if (i + amt > stb.st_size)
X				amt = stb.st_size - i;
X			if (readerr == 0 && read(f, bp->buf, amt) != amt)
X				readerr = errno;
X			(void) WRITE(rem, bp->buf, amt);
X		}
X		(void) close(f);
X		if (readerr == 0)
X			ga();
X		else
X			error("rcp: %s: %s\n", name, sys_errlist[readerr]);
X		(void) response();
X	}
X}
X
Xrsource(name, statp)
X	char *name;
X	struct stat *statp;
X{
X	FILE *d;
X	struct direct dentry;
X	register struct direct *dp = &dentry;
X	char *last;
X	char buf[BUFSIZ];
X	char *bufv[1];
X
X	errno = 0;
X	DEBUG2("[%d] rsource: \"%s\"\n", mypid, name);
X	if ((d = fopen(name,"r")) == 0) {
X		DEBUG1("[%d] rsource: opendir failed\n", mypid);
X		error("rcp: %s: %s\n", name, sys_errlist[errno]);
X		return;
X	}
X	last = strrchr(name, '/');
X	if (last == 0)
X		last = name;
X	else
X		last++;
X	if (pflag) {
X		(void) sprintf(buf, "T%ld 0 %ld 0\n",
X		    statp->st_mtime, statp->st_atime);
X		DEBUG2("[%d] rsource: setimes: %s", mypid, buf);
X		(void) WRITE(rem, buf, strlen(buf));
X		if (response() < 0) {
X			DEBUG1("[%d] rsource: bad response\n", mypid);
X			fclose(d);
X			return;
X		}
X	}
X	(void) sprintf(buf, "D%04o %d %s\n", statp->st_mode&07777, 0, last);
X	DEBUG2("[%d] rsource: %s", mypid, buf);
X	(void) WRITE(rem, buf, strlen(buf));
X	if (response() < 0) {
X		DEBUG1("[%d] rsource: bad response\n", mypid);
X		fclose(d);
X		return;
X	}
X
X	while (fread((char *)dp, sizeof(dentry), 1, d) == 1) {
X		DEBUG2("[%d] rsource: readdir: %s\n", mypid, dp->d_name);
X		if (dp->d_ino == 0)
X			continue;
X		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
X			continue;
X		if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
X			error("%s/%s: Name too long.\n", name, dp->d_name);
X			continue;
X		}
X		(void) sprintf(buf, "%s/%s", name, dp->d_name);
X		bufv[0] = buf;
X		source(1, bufv);
X	}
X	DEBUG2("[%d] rsource: dropped out of readdir loop %d\n", mypid, errno);
X	fclose(d);
X	(void) WRITE(rem, "E\n", 2);
X	(void) response();
X}
X
Xresponse()
X{
X	char resp, c, rbuf[BUFSIZ], *cp = rbuf;
X
X	if (READ(rem, &resp, 1) != 1)
X		lostconn();
X	switch (resp) {
X
X	case 0:				/* ok */
X		return (0);
X
X	default:
X		*cp++ = resp;
X		/* fall into... */
X	case 1:				/* error, followed by err msg */
X	case 2:				/* fatal error, "" */
X		do {
X			if (READ(rem, &c, 1) != 1)
X				lostconn();
X			*cp++ = c;
X		} while (cp < &rbuf[BUFSIZ] && c != '\n');
X		if (iamremote == 0)
X			(void) write(2, rbuf, cp - rbuf);
X		errs++;
X		if (resp == 1)
X			return (-1);
X		exit(1);
X	}
X	/*NOTREACHED*/
X}
X
Xlostconn()
X{
X
X	if (iamremote == 0)
X		fprintf(stderr, "rcp: lost connection\n");
X	exit(1);
X}
X
Xsink(argc, argv)
X	int argc;
X	char **argv;
X{
X	off_t i, j;
X	char *targ, *whopp, *cp;
X	int of, mode, wrerr, exists, first, count, amt, size;
X	struct buffer *bp;
X	static struct buffer buffer;
X	struct stat stb;
X	int targisdir = 0;
X	int mask = umask(0);
X	char *myargv[1];
X	char cmdbuf[BUFSIZ], nambuf[BUFSIZ];
X	int setimes = 0;
X	struct utimbuf tv;
X	int rcvflags, scratch;
X#define atime	tv.actime
X#define mtime	tv.modtime
X#define	SCREWUP(str)	{ whopp = str; goto screwup; }
X
X	DEBUG3("[%d] sink: iamremote %d, rem %d\n", mypid, iamremote, rem);
X	if (!pflag)
X		(void) umask(mask);
X	if (argc != 1) {
X		error("rcp: ambiguous target\n");
X		exit(1);
X	}
X	targ = *argv;
X	if (targetshouldbedirectory)
X		verifydir(targ);
X	ga();
X	if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
X		targisdir = 1;
X	for (first = 1; ; first = 0) {
X		cp = cmdbuf;
X		if (READ(rem, cp, 1) <= 0)
X			return;
X		if (*cp++ == '\n')
X			SCREWUP("unexpected '\\n'");
X		do {
X			if (READ(rem, cp, 1) != 1)
X				SCREWUP("lost connection");
X		} while (*cp++ != '\n');
X		*cp = 0;
X		if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') {
X			if (iamremote == 0)
X				(void) write(2, cmdbuf+1, strlen(cmdbuf+1));
X			if (cmdbuf[0] == '\02')
X				exit(1);
X			errs++;
X			continue;
X		}
X		*--cp = 0;
X		cp = cmdbuf;
X		if (*cp == 'E') {
X			ga();
X			return;
X		}
X
X#define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
X		if (*cp == 'T') {
X			setimes++;
X			cp++;
X			getnum(mtime);
X			if (*cp++ != ' ')
X				SCREWUP("mtime.sec not delimited");
X			getnum(scratch);	/* not supported */
X			if (*cp++ != ' ')
X				SCREWUP("mtime.usec not delimited");
X			getnum(atime);
X			if (*cp++ != ' ')
X				SCREWUP("atime.sec not delimited");
X			getnum(scratch);	/* not supported */
X			if (*cp++ != '\0')
X				SCREWUP("atime.usec not delimited");
X			ga();
X			continue;
X		}
X		if (*cp != 'C' && *cp != 'D') {
X			/*
X			 * Check for the case "rcp remote:foo\* local:bar".
X			 * In this case, the line "No match." can be returned
X			 * by the shell before the rcp command on the remote is
X			 * executed so the ^Aerror_message convention isn't
X			 * followed.
X			 */
X			if (first) {
X				error("%s\n", cp);
X				exit(1);
X			}
X			SCREWUP("expected control record");
X		}
X		cp++;
X		mode = 0;
X		for (; cp < cmdbuf+5; cp++) {
X			if (*cp < '0' || *cp > '7')
X				SCREWUP("bad mode");
X			mode = (mode << 3) | (*cp - '0');
X		}
X		if (*cp++ != ' ')
X			SCREWUP("mode not delimited");
X		size = 0;
X		while (isdigit(*cp))
X			size = size * 10 + (*cp++ - '0');
X		if (*cp++ != ' ')
X			SCREWUP("size not delimited");
X		if (targisdir)
X			(void) sprintf(nambuf, "%s%s%s", targ,
X			    *targ ? "/" : "", cp);
X		else
X			(void) strcpy(nambuf, targ);
X		exists = stat(nambuf, &stb) == 0;
X		if (cmdbuf[0] == 'D') {
X			if (Verbose && !iamremote) 
X				fprintf (stderr, "> %s/\n", nambuf);
X			if (exists) {
X				if ((stb.st_mode&S_IFMT) != S_IFDIR) {
X					errno = ENOTDIR;
X					goto bad;
X				}
X				if (pflag)
X					(void) chmod(nambuf, mode);
X			} else if (mkdir(nambuf, mode) < 0)
X				goto bad;
X			myargv[0] = nambuf;
X			sink(1, myargv);
X			if (setimes) {
X				DEBUG2("[%d] setimes: %s, ", mypid, nambuf);
X				DEBUG2("mtime %ld, atime %ld\n", mtime, atime);
X				setimes = 0;
X				if (utime(nambuf, &tv) < 0)
X					error("rcp: can't set times on %s: %s\n",
X					    nambuf, sys_errlist[errno]);
X			}
X			continue;
X		}
X		if (Verbose && !iamremote) 
X			fprintf (stderr, "> %s\n", nambuf);
X		if ((of = open(nambuf, O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0) {
X	bad:
X			error("rcp: %s: %s\n", nambuf, sys_errlist[errno]);
X			continue;
X		}
X/* should be set by the open?
X		if (exists && pflag)
X			(void) fchmod(of, mode);
X*/
X		ga();
X		if ((bp = allocbuf(&buffer, of, BUFSIZ)) == 0) {
X			(void) close(of);
X			continue;
X		}
X		cp = bp->buf;
X		count = 0;
X		wrerr = 0;
X		for (i = 0; i < size; i += BUFSIZ) {
X			amt = BUFSIZ;
X			if (i + amt > size)
X				amt = size - i;
X			count += amt;
X			do {
X				j = READ(rem, cp, amt);
X				if (j <= 0) {
X					if (j == 0)
X					    error("rcp: dropped connection");
X					else
X					    error("rcp: %s\n",
X						sys_errlist[errno]);
X					exit(1);
X				}
X				amt -= j;
X				cp += j;
X			} while (amt > 0);
X			if (count == bp->cnt) {
X				if (wrerr == 0 &&
X				    write(of, bp->buf, count) != count)
X					wrerr++;
X				count = 0;
X				cp = bp->buf;
X			}
X		}
X		if (count != 0 && wrerr == 0 &&
X		    write(of, bp->buf, count) != count)
X			wrerr++;
X/* sysV doesn't have this
X		if (ftruncate(of, size))
X			error("rcp: can't truncate %s: %s\n",
X			    nambuf, sys_errlist[errno]);
X*/
X		(void) close(of);
X		(void) response();
X		if (setimes) {
X			DEBUG2("[%d] setimes: %s, ", mypid, nambuf);
X			DEBUG2("mtime %ld, atime %ld\n", mtime, atime);
X			setimes = 0;
X			if (utime(nambuf, &tv) < 0)
X				error("rcp: can't set times on %s: %s\n",
X				    nambuf, sys_errlist[errno]);
X		}				   
X		if (wrerr)
X			error("rcp: %s: %s\n", nambuf, sys_errlist[errno]);
X		else
X			ga();
X	}
Xscrewup:
X	error("rcp: protocol screwup: %s\n", whopp);
X	exit(1);
X}
X
Xstruct buffer *
Xallocbuf(bp, fd, size)
X	struct buffer *bp;
X	int fd, size;
X{
X	if (bp->cnt < size) {
X		if (bp->buf != 0)
X			free(bp->buf);
X		bp->buf = (char *)malloc((unsigned) size);
X		if (bp->buf == 0) {
X			error("rcp: malloc: out of memory\n");
X			return ((struct buffer *)0);
X		}
X	}
X	bp->cnt = size;
X	return (bp);
X}
X
X/*VARARGS1*/
Xerror(fmt, a1, a2, a3, a4, a5)
X	char *fmt;
X	int a1, a2, a3, a4, a5;
X{
X	char buf[BUFSIZ], *cp = buf;
X
X	errs++;
X	*cp++ = 1;
X	(void) sprintf(cp, fmt, a1, a2, a3, a4, a5);
X	(void) WRITE(rem, buf, strlen(buf));
X	if (iamremote == 0)
X		(void) write(2, buf+1, strlen(buf+1));
X}
X
Xusage()
X{
X	fputs("usage: rcp [-pv] f1 f2; or: rcp [-rpv] f1 ... fn d2\n", stderr);
X	exit(1);
X}
X
Xmkdir(path, mode)
Xchar *path;
Xint mode;
X{
X    char buf[BUFSIZ];
X
X    sprintf (buf, "mkdir %s", path);
X    if (susystem (buf))
X	return (-1);
X    if (chmod (path, mode))
X	return (-1);
X    return (0);
X}
END_OF_rcp.c
if test 18300 -ne `wc -c <rcp.c`; then
    echo shar: \"rcp.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f rtape.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"rtape.c\"
else
echo shar: Extracting \"rtape.c\" \(13552 characters\)
sed "s/^X//" >rtape.c <<'END_OF_rtape.c'
X/* $Id: rtape.c,v 1.1 90/09/19 23:27:28 roger C_1 $
X *
X *	This is a UnixPC STARLAN program to interface with BSD's rmtd
X *	Roger Florkowski
X *	cs.utexas.edu!taliesin!roger
X */
X
X/* rtape -- remote tape driver.
X * 
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *	
X *	This program reads from stdin, and writes to a remote
X *	tape device (outputmode),  or reads from a remote
X *	tape device, and writes to stdout (inputmode).
X *	It was written to work with the UnixPC starlan port of
X *	bsd rmt.c
X *
X *	rtape will prompt you to change the media when it detects
X *	that it has reached the end.
X *
X *	Typical usage:
X *
X *	output (to remote tape):
X *	cpio -ocT124 | rtape -oT124 -d/dev/rft3 <remote host>
X *
X *	input (from remote tape):
X *	rtape -iT124 -d/dev/rft3 <remote host> | cpio -icT124
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include <errno.h>
X#include <sys/types.h>
X#include <fcntl.h>
X#include <net/sys/tiuser.h>
X#include <pwd.h>
X#include <setjmp.h>
X#include <ctype.h>
X#include "rcmds.h"
X
X#define RMT	"/usr/net/servers/rmtd"	/* location of rmt */
X#define TTY	"/dev/tty"		/* for changeTape() */
X#define BUFSIZE		512		/* default buffer size */
X#define NOTOK		-1
X#define OK		0
X#define CONTROL		1
X#define DATA		0
X#define SEEK_SET	0		/* bytes from beginning */
X#define SEEK_CUR	1		/* bytes from current position */
X#define SEEK_END	2		/* bytes from end */
X#define OUTPUT		0
X#define INPUT		1
X
Xextern char *getenv();
X
Xextern char *optarg;
Xextern int optind;
Xextern int t_errno;
Xint MediaNum;
X
Xextern	void	disconnect();
Xvoid	inputmode (),
X	outputmode (),
X	send_cntl_msg ();
Xint	sendsig(), alarmtr();
Xjmp_buf jumpbuf;
X
Xint	netd;				/* network descriptor	*/
Xint	rmterrno;			/* errno received from remote */
Xchar	*progname;			/* program name		*/
Xchar	*host;				/* remote host name	*/
XFILE	*debug;
X
Xmain(argc, argv)
Xint	argc;
Xchar	*argv[];
X{
X    int i, sz, mode, bufsize, seekto, input;
X    char *device, msg[BUFSIZE];
X    char *buf, *remoteDebug, *user;
X    struct passwd *pwd;
X
X    progname = argv[0];
X    MediaNum = 1;
X
X    mode = NOTOK;
X    bufsize = BUFSIZE;
X    seekto = 0;
X    user = remoteDebug = host = device = NULL;
X    while ((i = getopt(argc, argv, "BT:C:iod:O:l:F:f:")) != EOF) {
X
X	switch (i) {
X	    case 'B':			/* cpio compatible bufsize */
X		if (bufsize != BUFSIZE) {
X		    fprintf (stderr, "only one of B or T or C\n");
X		    Usage ();
X		}
X		bufsize = 5120;
X		break;
X	    case 'T':			/* buf size */
X		if (bufsize != BUFSIZE) {
X		    fprintf (stderr, "only one of B or T or C\n");
X		    Usage ();
X		}
X		sz = atoi (optarg);
X		if (sz > 0) 
X		    bufsize = sz * 1024;
X		else {
X		    fprintf (stderr, "Illegal argument to -%c, '%s'\n",
X			    i, optarg);
X		    Usage ();
X		}
X		break;
X	    case 'C':			/* choose your bufsize */
X		if (bufsize != BUFSIZE) {
X		    fprintf (stderr, "only one of B or T or C\n");
X		    Usage ();
X		}
X		bufsize = atoi (optarg);
X		if (bufsize <= 0) {
X		    fprintf (stderr, "Illegal argument to -%c, '%s'\n",
X			    i, optarg);
X		    Usage ();
X		}
X		break;
X	    case 'O':			/* offset */
X		sz = atoi (optarg);
X		if (sz > 0)
X		    seekto = sz * 512;
X		break;
X	    case 'i':			/* input */
X	    case 'o':			/* output */
X		if (mode != NOTOK)
X		    Usage();
X		mode = i == 'i' ? O_RDONLY : O_WRONLY;
X		input = i == 'i' ? INPUT : OUTPUT;
X		break;
X	    case 'd':			/* remote device */
X		device = optarg;
X		break;
X	    case 'l':			/* remote user */
X		user = optarg;
X		break;
X#if defined(DO_DEBUG) || defined(RMT_DEBUG)
X	    case 'F':			/* save debug info */
X		debug = fopen(optarg, "a");
X		if (debug == 0)
X		    exit(1);
X		(void) setbuf(debug, (char *)0);
X		break;
X	    case 'f':			/* save remote debug info */
X		remoteDebug = optarg;
X		break;
X#endif
X	    case '?':	Usage();
X	}
X    }
X
X    /* check out options */
X    if (mode == NOTOK || device == NULL)
X	Usage();
X    if (argc - optind != 1)
X	Usage();
X    host = argv[optind];
X
X    if ((buf = (char *)malloc (bufsize)) == NULL) {
X	fprintf (stderr, "%s: can't malloc space: not enough memory for buffer size\n", progname);
X	exit (1);
X    }
X
X    DEBUG3("%s [%d] started, bufsize %d\n", progname, getpid(), bufsize);
X
X    /* start-up remote process */
X    pwd = (struct passwd *)getpwuid(getuid());
X    if (pwd == 0) {
X	    fprintf(stderr, "who are you?\n");
X	    exit(1);
X    }
X    sprintf (msg, "%s %s", RMT, remoteDebug == NULL ? "" : remoteDebug);
X    netd = rcmd(host, RSHD_PORT, pwd->pw_name,
X	user ? user : pwd->pw_name, msg, 0);
X    if (netd < 0)
X	    exit(1);
X
X    (void) setuid(getuid());
X    signal(SIGINT, sendsig);
X    signal(SIGQUIT, sendsig);
X    signal(SIGTERM, sendsig);
X    signal(SIGPIPE, sendsig);
X
X    /* begin protocol */
X
X    /* open device */
X    sprintf (msg, "O%s\n%d\n", device, mode);
X    (void) send_recv_cntl (msg, 0);
X
X    /* seek on device */
X    if (seekto) {
X	sprintf (msg, "L%d\n%d\n", seekto, SEEK_SET);
X	(void) send_recv_cntl (msg, 0);
X    }
X
X    /* enter data read <-> write loop */
X    if (input)
X	inputmode (msg, buf, bufsize, device, mode);
X    else
X	outputmode (msg, buf, bufsize, device, mode);
X
X    /* close device */
X    sprintf (msg, "C\n");
X    (void) send_recv_cntl (msg, 0);
X
X    /* close up communications */
X    safe ();
X    end (0);
X}
X
XinProgress(input)
Xint input;
X{
X    fprintf (stderr, "%s in progress.  Do not remove the media on %s.\n",
X	    input == INPUT ? "Restore" : "Back-up", host);
X    fflush (stderr);
X}
X
Xsafe()
X{
X    fprintf (stderr, "It is safe to remove the media on %s.\n", host);
X    fflush (stderr);
X}
X
X/* read from remote device */
Xvoid
Xinputmode(msg, buf, bufsize, device, mode)
Xchar *msg, *buf, *device;
Xint bufsize, mode;
X{
X    int nrecv, nsent;
X
X    /* data read (from remote) <-> write (to local) loop */
X    inProgress (INPUT);
X    for (;;) {
X	int remote_read;
X
X	rmterrno = 0;
X	sprintf (msg, "R%d\n", bufsize);
X	if ((nrecv = send_recv_cntl (msg, 1)) == OK) {
X	    if (remote_read = atoi (msg))
X		nrecv = recv (buf, bufsize);
X	}
X	if (nrecv != bufsize){	/* short read? */
X	    if (nrecv < 0 && rmterrno != ENXIO) {
X		fprintf (stderr, "%s: Remote can't read device; aborting\n",
X			progname);
X		break;
X	    }
X	    if (changeTape (msg, device, mode))
X		return;
X	    inProgress (INPUT);
X	    continue;		/* re-read full block as cpio would */
X	}
X
X	/* make sure we read the same number of bytes (from the stream)
X	 * that the remote read (from device).
X	 */
X	if (nrecv != remote_read) {
X	    DEBUG2 ("communication error.  Remote read %d, we read %d\n",
X		    remote_read, nrecv);
X	    fprintf (stderr,"communication error. Remote read %d, we read %d\n",
X		    remote_read, nrecv);
X	    break;		/* drop out of loop */
X	}
X	if ((nsent = write (1, buf, nrecv)) < 0) {
X	    fprintf (stderr, "%s: can't write output; aborting\n", progname);
X	    break;
X	}
X    }
X}
X
X/* write to remote device */
Xvoid
Xoutputmode(msg, buf, bufsize, device, mode)
Xchar *msg, *buf, *device;
Xint bufsize, mode;
X{
X    register int cc, nrecv, nsent;
X
X    /* data read (from local) <-> write (to remote) loop */
X    inProgress (OUTPUT);
X    for (;;) {
X	int remote_wrote;
X
X	rmterrno = 0;
X
X	/* read async chunks from stdin
X	 * On big buf reads, we may hang in read trying to fill up our buf.  
X	 */
X	for (nrecv = 0; nrecv < bufsize; nrecv += cc) {
X	    cc = read (0, &buf[nrecv], bufsize - nrecv);
X	    if (cc == 0)
X		break;		/* pipe ended */
X	    if (cc < 0) {
X		fprintf (stderr, "%s: can't read input;  aborting.\n",progname);
X		return;		/* break out of loop */
X	    }
X	}
X
X	/* normal termination from stdin */
X	if (nrecv == 0)
X	    break;
X
XoutputWrite:
X	/* send out the amount we read. */
X	sprintf (msg, "W%d\n", nrecv);
X	send_cntl_msg (msg);
X	nsent = send (buf, nrecv, DATA);
X	remote_wrote = (recv_cntl_msg (msg, 1) == OK) ? atoi (msg) : NOTOK;
X
X	if (nsent != remote_wrote) {
X	    if (remote_wrote < 0 && rmterrno != ENXIO) {
X		fprintf (stderr, "%s: remote can't write to device; aborting\n",
X			progname);
X		break;
X	    }
X	    if (changeTape (msg, device, mode))
X		return;
X	    inProgress (OUTPUT);
X	    goto outputWrite;	/* re-write output, as cpio would */
X	}
X	if (nsent != nrecv) {
X	    DEBUG2 ("communication error.  We read %d, we wrote %d\n",
X		    nrecv, nsent);
X	    fprintf (stderr,"communication error. We read %d, we wrote %d\n",
X		    nrecv, nsent);
X	    break;		/* drop out of loop */
X	}
X    }
X}
X
XUsage()
X{
X    fprintf (stderr, "Usage: %s -i|-o [-B | -T 1k bufs | -C raw bufsize] [-O offset] [-l user] -d <device> <host>\n", progname);
X    exit (1);
X}
X
Xend (ret)
Xint ret;
X{
X    (void)disconnect (netd);
X    if (debug)
X	close (debug);
X    exit (ret);
X}
X
Xint
Xsend_recv_cntl (msg, go_on)
Xchar *msg;
Xint go_on;
X{
X    send_cntl_msg (msg);
X    return (recv_cntl_msg (msg, go_on));
X}
X
X/* send a control msg to remote */
Xvoid
Xsend_cntl_msg (msg)
Xchar *msg;
X{
X    DEBUG1 ("sending control message\n%s", msg);
X    if (send (msg, strlen (msg), CONTROL) == NOTOK) {
X	fprintf (stderr, "send error. errno %d, t_errno %d\n", errno, t_errno);
X	end (1);
X    }
X}
X
X/* receive a control msg from remote */
Xint
Xrecv_cntl_msg (msg, go_on)
Xchar *msg;
Xint go_on;	/* in read-write faze, don't stop on error */
X{
X    int nrcvd, rcvflags;
X
X    t_errno = 0;
X    if ( t_getstate(netd) != T_DATAXFER) {
X	DEBUG ("t_snd: unexpected state\n");
X	goto iobad;
X    }
X    t_errno = 0;
X    if ((nrcvd = t_rcv (netd, msg, 1, &rcvflags)) <= 0) {
X	DEBUG ("t_rcv: error on read\n");
X	goto iobad;
X    }
X    switch (*msg) {
X
X	/* acknowledgement */
X	case 'A':
X	    getstring (msg);	/* read in ack data */
X	    DEBUG1( "recv_cntl: A %d\n", atoi (msg));
X	    return(OK);
X
X	/* error on remote */
X	case 'E':
X	    getstring (msg);	/* read in rmterrno */
X	    rmterrno = atoi (msg);
X	    getstring (msg);	/* read in sys_errlist */
X	    DEBUG2 ("recv_cntl: E %d\n%s\n", rmterrno, msg);
X	    if (rmterrno != ENXIO)
X		fprintf (stderr, "remote error %d\n%s\n", rmterrno, msg);
X	    if (go_on)
X		return (NOTOK);
X	default:
X	    DEBUG1 ("recv_cntl: unknown control %c\n", *msg);
X    }
X
X    end (1);
Xiobad:
X    fprintf (stderr, "recv_cntl error.  errno %d, t_errno %d\n", errno,
X	    t_errno);
X    end (1);
X}
X
X/* send a msg (or data) to remote */
Xint
Xsend (msg, nbytes, control)
Xchar *msg;
Xint nbytes;
Xint control;
X{
X    int nsent;
X
X    t_errno = 0;
X    if ( t_getstate(netd) != T_DATAXFER) {
X	DEBUG ("t_snd: unexpected state\n");
X	return (NOTOK);
X    }
X    t_errno = 0;
X    DEBUG1 ("t_snd: sending %d bytes\n", nbytes);
X    if ( (nsent = t_snd (netd, msg, nbytes, NULL)) < 0) {
X	DEBUG ("t_snd: error on write\n");
X	return (NOTOK);
X    }
X
X    if (control && nsent != nbytes) {
X	DEBUG1 ("t_snd: short write.  Wrote %d\n", nsent);
X	return (NOTOK);
X    }
X    return (nsent);
X}
X
X/* receive data from remote */
Xint
Xrecv (msg, nbytes)
Xchar *msg;
Xint nbytes;
X{
X    register int cc, nrcvd; 
X    int rcvflags;
X
X    t_errno = 0;
X    if ( t_getstate(netd) != T_DATAXFER) {
X	DEBUG ("t_snd: unexpected state\n");
X	return (NOTOK);
X    }
X    t_errno = 0;
X    DEBUG1 ("t_rcv: requesting %d bytes...", nbytes);
X    DFLUSH ();
X
X    /* on big buf reads, we may hang in t_rcv trying to fill
X     * up our buf.  Allow 5 seconds to fill our buf, else
X     * return the number of bytes read so far.
X     */
X    if (setjmp (jumpbuf)) {
X	DEBUG1("ALARM! received %d bytes\n", nrcvd);
X	return (nrcvd);
X    }
X    signal (SIGALRM, alarmtr);
X    alarm (5);
X
X    /* read async chunks from stream */
X    for (nrcvd = 0; nrcvd < nbytes; nrcvd += cc) {
X	cc = t_rcv (netd, &msg[nrcvd], nbytes - nrcvd, &rcvflags);
X	if (cc <= 0) {
X	    DEBUG ("t_rcv: error on read\n");
X	    return (NOTOK);
X	}
X    }
X    alarm (0);
X    DEBUG1("received %d bytes\n", nrcvd);
X
X    return (nrcvd);
X}
X
X/*
X * -) send close msg to remote
X * -) open /dev/tty 
X * -) ask them to change tape
X * -) send open msg to remote (watch for retension!)
X */
Xint
XchangeTape(msg, device, mode)
Xchar *msg, *device;
Xint mode;	/* input or output? */
X{
X    int tty, l, done;
X    char c;
X
X    DEBUG("in changeTape\n");
X    /* must read from /dev/tty, since stdin is unavailable */
X    if ((tty = open_tty()) < 0)
X	return (NOTOK);
X
X    /* close device */
X    sprintf (msg, "C\n");
X    send_recv_cntl (msg, 0);
X
X    safe ();
X    fprintf(stderr, "\nTo EXIT -- press <E> followed by <RETURN>.\n");
X    fprintf(stderr,"To continue - insert media #%d in %s on %s and press <RETURN>\n", 
X	    ++MediaNum, device, host);
X    done = 0;
X    while ((l = read (tty, &c, 1)) == 1){
X	if (c == '\n' || c == '\r'){	/* must have <CR> to exit from loop */
X	    if (done)
X		end (0);	/* we've already close, so end is safe */
X	    break;
X	}
X	if (toupper(c) == 'E'){	/* 'E' must be followed by <CR> to exit */
X	    done = 1;
X	    continue;
X	}
X	done = 0;		/* must be garbage */
X    }
X    if (l <= 0)			/* 0 == EOF, else error.  Stop in either case */
X	end (0);		/* we've already close, so end is safe */
X
X    /* re-open device */
X    sprintf (msg, "O%s\n%d\n", device, mode);
X    send_recv_cntl (msg, 0);
X}
X
Xint 
Xopen_tty ()
X{
X    int fd;
X
X    if ((fd = open(TTY, O_RDWR)) < 0)
X	return (-1);
X    if (isatty (fd))
X	return (fd);
X    close (fd);
X    return (-1);
X}
X
X/* following routine taken from bsd rmtd.c */
Xgetstring(bp)
X	char *bp;
X{
X	int i, rcvflags;
X	char *cp = bp;
X
X	for (i = 0; i < BUFSIZE; i++) {
X		if (t_rcv (netd, cp+i, 1, &rcvflags) != 1) {
X		    DEBUG ("getstring: t_rcv: error on read\n");
X		    break;
X		}
X		if (cp[i] == '\n')
X			break;
X	}
X	cp[i] = '\0';
X}
X
Xsendsig(signo)
X	char signo;
X{
X
X/*     fprintf (stderr, "caught sig %d\n", signo); */
X    safe ();
X    end (-signo);
X}
X
Xalarmtr()
X{
X    longjmp (jumpbuf, 1);
X}
END_OF_rtape.c
if test 13552 -ne `wc -c <rtape.c`; then
    echo shar: \"rtape.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 3 \(of 3\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

-- 
Roger Florkowski                                 ~!cs.utexas.edu!taliesin!roger



More information about the Comp.sys.att mailing list