roger@taliesin.UUCP (Roger Florkowski) (09/20/90)
#! /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@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