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