home *** CD-ROM | disk | FTP | other *** search
- From: Arnold Robbins <linus!gatech!arnold>
- Subject: Diffs to tar to use a remote system's tape drive
- Newsgroups: mod.sources
- Approved: john@genrad.UUCP
-
- Mod.sources: Volume 2, Issue 5
- Submitted by: Arnold Robbins <linus!gatech!arnold>
-
-
- * WARNING: The man page rmt(8) for /etc/rmt documents the remote mag
- * tape protocol which rdump and rrestore use. Unfortunately, the man
- * page is *WRONG*. The author of the routines I'm including originally
- * wrote his code just based on the man page, and it didn't work, so he
- * went to the rdump source to figure out why. The only thing he had to
- * change was to check for the 'F' return code in addition to the 'E',
- * and to separate the various arguments with \n instead of a space. I
- * personally don't think that this is much of a problem, but I wanted to
- * point it out.
- *
- * Arnold Robbins
-
-
- The following context diffs to the 4.2 BSD tar.c and man page allow tar
- to read and write tapes on a remote system's tape drive. The routines
- at the end that deal with /etc/rmt across a pipe are general purpose and
- in the public domain.
-
- It is interesting to note that what rmt(8) says about its protocol, and what
- you actually have to do to get it to work are quite different.
-
- The command line syntax has not changed. Instead, the file name for the -f
- option looks sorta like what rcp takes, e.g.
-
- $ tar -cvf gatech:/dev/rmt8 /usr/src
-
- In particular, if "/dev/" does not follow the colon, tar decides it is using
- a regular, local file.
-
- The diffs are for the tar that comes with BRL Unix. Your line numbers
- may vary.
-
- Arnold Robbins (rmt stuff courtesy of Jeff Lee, gatech!jeff)
- arnold@gatech.{CSNET, UUCP}
- --------------------- cut here ----------------------------
- *** /usr/src/bin/tar.c Wed Nov 14 00:09:23 1984
- --- tar.c Mon Jul 1 14:25:40 1985
- ***************
- *** 115,120
- char *getcwd();
- char *getwd();
-
- main(argc, argv)
- int argc;
- char *argv[];
-
- --- 115,141 -----
- char *getcwd();
- char *getwd();
-
- + int open();
- + int read();
- + int write();
- + int close();
- + int ioctl();
- + long lseek();
- +
- + int rmtopen();
- + int rmtread();
- + int rmtwrite();
- + int rmtclose();
- + int rmtioctl();
- + long rmtlseek();
- +
- + int (*t_open)();
- + int (*t_read)();
- + int (*t_write)();
- + int (*t_close)();
- + int (*t_ioctl)();
- + long (*t_lseek)();
- +
- main(argc, argv)
- int argc;
- char *argv[];
- ***************
- *** 264,269
- nblock);
- done(1);
- }
- if (rflag) {
- if (cflag && tfile != NULL)
- usage();
-
- --- 285,293 -----
- nblock);
- done(1);
- }
- +
- + fix_remote();
- +
- if (rflag) {
- if (cflag && tfile != NULL)
- usage();
- ***************
- *** 285,291
- }
- mt = dup(1);
- nblock = 1;
- ! } else if ((mt = open(usefile, 2)) < 0) {
- if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) {
- fprintf(stderr,
- "tar: cannot open %s\n", usefile);
-
- --- 309,315 -----
- }
- mt = dup(1);
- nblock = 1;
- ! } else if ((mt = (*t_open)(usefile, 2)) < 0) {
- if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) {
- fprintf(stderr,
- "tar: cannot open %s\n", usefile);
- ***************
- *** 298,304
- if (strcmp(usefile, "-") == 0) {
- mt = dup(0);
- nblock = 1;
- ! } else if ((mt = open(usefile, 0)) < 0) {
- fprintf(stderr, "tar: cannot open %s\n", usefile);
- done(1);
- }
-
- --- 322,328 -----
- if (strcmp(usefile, "-") == 0) {
- mt = dup(0);
- nblock = 1;
- ! } else if ((mt = (*t_open)(usefile, 0)) < 0) {
- fprintf(stderr, "tar: cannot open %s\n", usefile);
- done(1);
- }
- ***************
- *** 306,311
- doxtract(argv);
- else
- dotable();
- done(0);
- }
-
-
- --- 330,336 -----
- doxtract(argv);
- else
- dotable();
- + (*t_close) (mt);
- done(0);
- }
-
- ***************
- *** 1195,1201
- {
- first = 1;
- if (recno >= nblock) {
- ! if (write(mt, tbuf, TBLOCK*nblock) < 0) {
- fprintf(stderr, "tar: tape write error\n");
- done(2);
- }
-
- --- 1220,1226 -----
- {
- first = 1;
- if (recno >= nblock) {
- ! if ((*t_write)(mt, tbuf, TBLOCK*nblock) < 0) {
- fprintf(stderr, "tar: tape write error\n");
- done(2);
- }
- ***************
- *** 1209,1215
- * residual to the tape buffer.
- */
- while (recno == 0 && n >= nblock) {
- ! if (write(mt, buffer, TBLOCK*nblock) < 0) {
- fprintf(stderr, "tar: tape write error\n");
- done(2);
- }
-
- --- 1234,1240 -----
- * residual to the tape buffer.
- */
- while (recno == 0 && n >= nblock) {
- ! if ((*t_write)(mt, buffer, TBLOCK*nblock) < 0) {
- fprintf(stderr, "tar: tape write error\n");
- done(2);
- }
- ***************
- *** 1221,1227
- bcopy(buffer, (char *)&tbuf[recno++], TBLOCK);
- buffer += TBLOCK;
- if (recno >= nblock) {
- ! if (write(mt, tbuf, TBLOCK*nblock) < 0) {
- fprintf(stderr, "tar: tape write error\n");
- done(2);
- }
-
- --- 1246,1252 -----
- bcopy(buffer, (char *)&tbuf[recno++], TBLOCK);
- buffer += TBLOCK;
- if (recno >= nblock) {
- ! if ((*t_write)(mt, tbuf, TBLOCK*nblock) < 0) {
- fprintf(stderr, "tar: tape write error\n");
- done(2);
- }
- ***************
- *** 1240,1246
- struct mtget mtget;
-
- if (mtdev == 1)
- ! mtdev = ioctl(mt, MTIOCGET, &mtget);
- if (mtdev == 0) {
- if (ioctl(mt, MTIOCTOP, &mtop) < 0) {
- fprintf(stderr, "tar: tape backspace error\n");
-
- --- 1265,1271 -----
- struct mtget mtget;
-
- if (mtdev == 1)
- ! mtdev = (*t_ioctl)(mt, MTIOCGET, &mtget);
- if (mtdev == 0) {
- if ((*t_ioctl)(mt, MTIOCTOP, &mtop) < 0) {
- fprintf(stderr, "tar: tape backspace error\n");
- ***************
- *** 1242,1248
- if (mtdev == 1)
- mtdev = ioctl(mt, MTIOCGET, &mtget);
- if (mtdev == 0) {
- ! if (ioctl(mt, MTIOCTOP, &mtop) < 0) {
- fprintf(stderr, "tar: tape backspace error\n");
- done(4);
- }
-
- --- 1267,1273 -----
- if (mtdev == 1)
- mtdev = (*t_ioctl)(mt, MTIOCGET, &mtget);
- if (mtdev == 0) {
- ! if ((*t_ioctl)(mt, MTIOCTOP, &mtop) < 0) {
- fprintf(stderr, "tar: tape backspace error\n");
- done(4);
- }
- ***************
- *** 1247,1253
- done(4);
- }
- } else
- ! lseek(mt, (long) -TBLOCK*nblock, 1);
- recno--;
- }
-
-
- --- 1272,1278 -----
- done(4);
- }
- } else
- ! (*t_lseek)(mt, (long) -TBLOCK*nblock, 1);
- recno--;
- }
-
- ***************
- *** 1253,1259
-
- flushtape()
- {
- ! write(mt, tbuf, TBLOCK*nblock);
- }
-
- bread(fd, buf, size)
-
- --- 1278,1284 -----
-
- flushtape()
- {
- ! (*t_write)(mt, tbuf, TBLOCK*nblock);
- }
-
- bread(fd, buf, size)
- ***************
- *** 1265,1271
- static int lastread = 0;
-
- if (!Bflag)
- ! return (read(fd, buf, size));
- for (count = 0; count < size; count += lastread) {
- if (lastread < 0) {
- if (count > 0)
-
- --- 1290,1296 -----
- static int lastread = 0;
-
- if (!Bflag)
- ! return ((*t_read)(fd, buf, size));
- for (count = 0; count < size; count += lastread) {
- if (lastread < 0) {
- if (count > 0)
- ***************
- *** 1272,1278
- return (count);
- return (lastread);
- }
- ! lastread = read(fd, buf, size - count);
- buf += lastread;
- }
- return (count);
-
- --- 1297,1303 -----
- return (count);
- return (lastread);
- }
- ! lastread = (*t_read)(fd, buf, size - count);
- buf += lastread;
- }
- return (count);
- ***************
- *** 1288,1291
- exit(1);
- }
- return (buf);
- }
-
- --- 1313,1758 -----
- exit(1);
- }
- return (buf);
- + }
- +
- + fix_remote ()
- + {
- + char *cp, *index ();
- +
- + if ((cp = index (usefile, ':')) == NULL ||
- + strncmp (cp + 1, "/dev/", 5) != 0)
- + {
- + t_open = open;
- + t_read = read;
- + t_write = write;
- + t_close = close;
- + t_ioctl = ioctl;
- + t_lseek = lseek;
- + }
- + else
- + {
- + t_open = rmtopen;
- + t_read = rmtread;
- + t_write = rmtwrite;
- + t_close = rmtclose;
- + t_ioctl = rmtioctl;
- + t_lseek = rmtlseek;
- + }
- + }
- +
- + /*
- + * rmt --- remote tape emulator subroutines
- + *
- + * Originally written by Jeff Lee, modified some by Arnold Robbins
- + */
- +
- + /* these are included above, except setjmp.h */
- + /*
- + #include <stdio.h>
- + #include <errno.h>
- + #include <setjmp.h>
- + #include <signal.h>
- +
- + #include <sys/types.h>
- + #include <sys/ioctl.h>
- + #include <sys/mtio.h>
- + */
- +
- + #include <setjmp.h>
- +
- + /*
- + * MAXUNIT --- Maximum number of remote tape file units
- + *
- + * READ --- Return the number of the read side file descriptor
- + * WRITE --- Return the number of the write side file descriptor
- + */
- +
- + #define MAXUNIT 4
- +
- + #define READ(fd) (Ctp[fd][0])
- + #define WRITE(fd) (Ptc[fd][1])
- +
- + static int Ctp[MAXUNIT][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
- + static int Ptc[MAXUNIT][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
- +
- + jmp_buf Jmpbuf;
- + extern int errno;
- +
- +
- +
- + /*
- + * abort --- close off a remote tape connection
- + */
- +
- + static abort(tfd)
- + int tfd;
- + {
- + close(READ(tfd));
- + close(WRITE(tfd));
- + READ(tfd) = -1;
- + WRITE(tfd) = -1;
- + }
- +
- +
- +
- + /*
- + * command --- attempt to perform a remote tape command
- + */
- +
- + static command(tfd, buf)
- + char *buf;
- + int tfd;
- + {
- + int blen;
- + int (*pstat)();
- +
- + /*
- + * save current pipe status and try to make the request
- + */
- +
- + blen = strlen(buf);
- + pstat = signal(SIGPIPE, SIG_IGN);
- + if (write(WRITE(tfd), buf, blen) == blen)
- + {
- + signal(SIGPIPE, pstat);
- + return(0);
- + }
- +
- + /*
- + * something went wrong. close down and go home
- + */
- +
- + signal(SIGPIPE, pstat);
- + abort(tfd);
- +
- + errno = EIO;
- + return(-1);
- + }
- +
- +
- +
- + /*
- + * status --- retrieve the status from the pipe
- + */
- +
- + static status(tfd)
- + int tfd;
- + {
- + int i;
- + char c, *cp;
- + char buf[64];
- +
- + /*
- + * read the reply command line
- + */
- +
- + for (i = 0, cp = buf; i < 64; i++, cp++)
- + {
- + if (read(READ(tfd), cp, 1) != 1)
- + {
- + abort(tfd);
- + errno = EIO;
- + return(-1);
- + }
- + if (*cp == '\n')
- + {
- + *cp = 0;
- + break;
- + }
- + }
- +
- + if (i == 64)
- + {
- + abort(tfd);
- + errno = EIO;
- + return(-1);
- + }
- +
- + /*
- + * check the return status
- + */
- +
- + for (cp = buf; *cp; cp++)
- + if (*cp != ' ')
- + break;
- +
- + if (*cp == 'E' || *cp == 'F')
- + {
- + errno = atoi(cp + 1);
- + while (read(READ(tfd), &c, 1) == 1)
- + if (c == '\n')
- + break;
- +
- + if (*cp == 'F')
- + abort(tfd);
- +
- + return(-1);
- + }
- +
- + /*
- + * check for mis-synced pipes
- + */
- +
- + if (*cp != 'A')
- + {
- + abort(tfd);
- + errno = EIO;
- + return(-1);
- + }
- +
- + return(atoi(cp + 1));
- + }
- +
- +
- +
- + /*
- + * rmtopen --- open a magtape device on system specified
- + */
- +
- + rmtopen(dev, mode)
- + char *dev;
- + int mode;
- + {
- + int i, rc;
- + char buf[64];
- + char *sys;
- +
- + /*
- + * first, find an open pair of file descriptors
- + */
- +
- + for (i = 0; i < MAXUNIT; i++)
- + if (READ(i) == -1 && WRITE(i) == -1)
- + break;
- +
- + if (i == MAXUNIT)
- + {
- + errno = EMFILE;
- + return(-1);
- + }
- +
- + /*
- + * pull apart system and device
- + */
- + for (sys = dev; *dev != ':'; dev++)
- + ;
- + *dev++ = '\0';
- +
- + /*
- + * setup the pipes for the 'rsh' command and fork
- + */
- +
- + if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1)
- + return(-1);
- +
- + if ((rc = fork()) == -1)
- + return(-1);
- +
- + if (rc == 0)
- + {
- + close(0);
- + dup(Ptc[i][0]);
- + close(Ptc[i][0]); close(Ptc[i][1]);
- + close(1);
- + dup(Ctp[i][1]);
- + close(Ctp[i][0]); close(Ctp[i][1]);
- +
- + execl("/usr/ucb/rsh", "rsh", sys, "/etc/rmt", (char *) 0);
- +
- + /*
- + * bad problems if we get here
- + */
- +
- + perror("exec");
- + exit(1);
- + }
- +
- + close(Ptc[i][0]); close(Ctp[i][1]);
- +
- + /*
- + * now attempt to open the tape device
- + */
- +
- + sprintf(buf, "O%s\n%d\n", dev, mode);
- + if (command(i, buf) == -1 || status(i) == -1)
- + return(-1);
- +
- + return(i);
- + }
- +
- +
- +
- + /*
- + * rmtclose --- close a remote magtape unit and shut down
- + */
- +
- + rmtclose(tfd)
- + int tfd;
- + {
- + int rc;
- +
- + if (command(tfd, "C\n") != -1)
- + {
- + rc = status(tfd);
- +
- + abort(tfd);
- + return(rc);
- + }
- +
- + return(-1);
- + }
- +
- +
- +
- + /*
- + * rmtread --- read a buffer from a remote tape
- + */
- +
- + rmtread(tfd, data, cnt)
- + int tfd, cnt;
- + char *data;
- + {
- + int rc, i;
- + char buf[64];
- +
- + sprintf(buf, "R%d\n", cnt);
- + if (command(tfd, buf) == -1 || (rc = status(tfd)) == -1)
- + return(-1);
- +
- + for (i = 0; i < rc; i += cnt, data += cnt)
- + {
- + cnt = read(READ(tfd), data, rc);
- + if (cnt <= 0)
- + {
- + abort(tfd);
- + errno = EIO;
- + return(-1);
- + }
- + }
- +
- + return(rc);
- + }
- +
- +
- +
- + /*
- + * rmtwrite --- write a buffer to the remote tape
- + */
- +
- + rmtwrite(tfd, data, cnt)
- + int tfd, cnt;
- + char *data;
- + {
- + int rc;
- + char buf[64];
- + int (*pstat)();
- +
- + sprintf(buf, "W%d\n", cnt);
- + if (command(tfd, buf) == -1)
- + return(-1);
- +
- + pstat = signal(SIGPIPE, SIG_IGN);
- + if (write(WRITE(tfd), data, cnt) == cnt)
- + return(status(tfd));
- +
- + abort(tfd);
- + errno = EIO;
- + return(-1);
- + }
- +
- +
- +
- + /*
- + * rmtlseek --- perform an imitation lseek operation remotely
- + */
- +
- + rmtlseek(tfd, wh, off)
- + int tfd, wh, off;
- + {
- + char buf[64];
- +
- + sprintf(buf, "L%d\n%d\n", wh, off);
- + if (command(tfd, buf) == -1)
- + return(-1);
- +
- + return(status(tfd));
- + }
- +
- +
- +
- + /*
- + * rmtioctl --- perform raw tape operations remotely
- + */
- +
- + rmtioctl(tfd, op, arg)
- + int tfd, op;
- + char *arg;
- + {
- + char c;
- + int rc, cnt;
- + char buf[64];
- +
- + /*
- + * MTIOCOP is the easy one. nothing is transfered in binary
- + */
- +
- + if (op == MTIOCTOP)
- + {
- + sprintf(buf, "I%d\n%d\n", ((struct mtop *) arg)->mt_op,
- + ((struct mtop *) arg)->mt_count);
- + if (command(tfd, buf) == -1)
- + return(-1);
- + return(status(tfd));
- + }
- +
- + /*
- + * we can only handle 2 ops, if not the other one, punt
- + */
- +
- + if (op != MTIOCGET)
- + {
- + errno = EINVAL;
- + return(-1);
- + }
- +
- + /*
- + * grab the status and read it directly into the structure
- + * this assumes that the status buffer is (hopefully) not
- + * padded and that 2 shorts fit in a long without any word
- + * alignment problems, ie - the whole struct is contiguous
- + * NOTE - this is probably NOT a good assumption.
- + */
- +
- + if (command(tfd, "S\n") == -1 || (rc = status(tfd)) == -1)
- + return(-1);
- +
- + for (; rc > 0; rc -= cnt, arg += cnt)
- + {
- + cnt = read(READ(tfd), arg, rc);
- + if (cnt <= 0)
- + {
- + abort(tfd);
- + errno = EIO;
- + return(-1);
- + }
- + }
- +
- + /*
- + * now we check for byte position. mt_type is a small integer field
- + * (normally) so we will check its magnitude. if it is larger than
- + * 256, we will assume that the bytes are swapped and go through
- + * and reverse all the bytes
- + */
- +
- + if (((struct mtget *) arg)->mt_type < 256)
- + return(0);
- +
- + for (cnt = 0; cnt < rc; cnt += 2)
- + {
- + c = arg[cnt];
- + arg[cnt] = arg[cnt+1];
- + arg[cnt+1] = c;
- + }
- +
- + return(0);
- }
- *** /usr/man/man1/tar.1 Mon Jun 27 00:35:14 1983
- --- tar.1 Mon Jul 1 13:51:09 1985
- ***************
- *** 95,101
- .B f
- .I Tar
- uses the next argument as the name of the archive instead of
- ! /dev/rmt?. If the name of the file is `\-', tar writes to standard output or
- reads from standard input, whichever is appropriate. Thus,
- .I tar
- can be used as the head or tail of a filter chain.
-
- --- 95,113 -----
- .B f
- .I Tar
- uses the next argument as the name of the archive instead of
- ! /dev/rmt?.
- ! .sp
- ! If the file name has the form
- ! .IR system :/dev/???,
- ! .I tar
- ! will use the tape drive /dev/??? on the remote system
- ! .IR system ,
- ! via
- ! .IR rsh (1),
- ! and
- ! .IR rmt (8).
- ! .sp
- ! If the name of the file is `\-', tar writes to standard output or
- reads from standard input, whichever is appropriate. Thus,
- .I tar
- can be used as the head or tail of a filter chain.
- ***************
- *** 179,181
- The current limit on file name length is 100 characters.
- .br
- There is no way to selectively follow symbolic links.
-
- --- 191,195 -----
- The current limit on file name length is 100 characters.
- .br
- There is no way to selectively follow symbolic links.
- + .br
- + Using a remote system's tape drive can be slow.
-
-