ast@cs.vu.nl (Andy Tanenbaum) (06/06/88)
Since I still haven't got a PD tar that actually works on MINIX, I decided to fix up Michiel Huisjes tar. In particular, what I wanted was a way to handle tar files larger than 1 diskette. I accomplished this by writing a program vol, which accepts an input stream from stdin and writes it on diskette, pausing when the diskette is full to prompt for a new diskette. To write the current directory and its subdirectories on a seequence of diskettes, type: tar c - . | vol 360 /dev/fd0 To restore the file system later, type: vol -u 360 /dev/fd0 | tar x - To make this work, I had to modify tar slightly. The diff listing (relative to V1.3 tar) is enclosed below. Comments, improvements etc. should be posted to this group. Andy Tanenbaum (ast@cs.vu.nl) : This is a shar archive. Extract with sh, not csh. : This archive ends with exit, so do not worry about trailing junk. : --------------------------- cut here -------------------------- PATH=/bin:/usr/bin echo Extracting \v\o\l\.\c sed 's/^X//' > \v\o\l\.\c << '+ END-OF-FILE '\v\o\l\.\c X/* vol - break stdin into volumes Author: Andy Tanenbaum */ X X/* This program reads standard input and writes it onto diskettes, pausing X * at the start of each one. It's main use is for saving files that are X * larger than a single diskette. Vol just writes its standard input onto X * a diskette, and prompts for a new one when it is full. This mechanism X * is transparent to the process producing vol's standard input. For example, X * tar c - . | vol 360 /dev/fd0 X * puts the tar output as as many diskettes as needed. To read them back in, X * use X * vol -u 360 /dev/fd0 | tar x - X * X */ X X#include <sys/stat.h> X#include <minix/blocksize.h> X#include <signal.h> X Xextern int errno; Xextern char *itoa(); X Xchar buffer[BLOCK_SIZE]; X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X int volume = 1, size, reading, fd, tty; X char *p, *name; X struct stat stb; X X signal(SIGPIPE, SIG_IGN); X X /* Fetch and verify the arguments. */ X if (argc != 3 && argc != 4) X message("Usage: vol [-u] size block-special\n", ""); X p = argv[1]; X reading = (*p == '-' && *(p+1) == 'u' ? 1 : 0); X size = atoi(argv[reading + 1]); X name = argv[reading + 2]; X tty = open("/dev/tty", 0); X X if (size <= 0) X message("vol: bad volume size\n", argv[reading+1]); X if (stat(name, &stb) < 0) X message("vol: cannot stat %s\n", name); X if ( (stb.st_mode & S_IFMT) != S_IFBLK) X message("vol: %s is not a block special file\n", name); X if (tty < 0) X message("vol: cannot open /dev/tty\n", ""); X X while (1) { X /* Open the special file. */ X fd = open(name, 1 - reading); X if (fd < 0) X message("vol: cannot open %s\n", name); X X std_err("Please insert volume "); X num(volume); X std_err(" and hit return\n"); X read(tty, buffer, BLOCK_SIZE); X volume++; X X /* Read or write the requisite number of blocks. */ X if (reading) X diskio(size, fd, 1, name, "stdout"); /* vol -u | tar xf -*/ X else X diskio(size, 0, fd, "stdin", name); /* tar cf - | vol */ X X close(fd); X } X} X Xdiskio(size, fd1, fd2, errstr1, errstr2) Xint size, fd1, fd2; Xchar *errstr1, *errstr2; X{ X/* Read 'size' blocks from 'fd1' and write them on 'fd2'. Watch out for X * the fact that reads on pipes can return less than the desired data. X */ X X int n, m, count; X long needed; X X needed = (long) BLOCK_SIZE * (long) size; /* # bytes to read */ X while (needed > 0L) { X count = (needed > (long) BLOCK_SIZE ? BLOCK_SIZE : (int) needed); X n = read(fd1, buffer, count); X if (n == 0) exit(0); X if (n < 0) message("Error encountered while reading %s\n", errstr1); X m = write(fd2, buffer, n); X if (m < 0 && errno == SIGPIPE) exit(0); X if (m > 0 && m != n) message("Output error on %s\n", errstr2); X if (m < 0) message("Error encountered while writing %s\n", errstr2); X needed -= n; X } X} X X X Xmessage(s1, s2) Xchar *s1, *s2; X{ X printf(s1, s2); X exit(1); X} X Xnum(n) Xint n; X{ X char out[3]; X X out[0] = ' '; X out[1] = '0'; X out[2] = 0; X if (n < 10) { X out[1] += n; X } else { X out[1] += (n%10); X out[2] = '0' + (n/10); X } X std_err(out); X} + END-OF-FILE vol.c chmod 'u=rw,g=r,o=r' \v\o\l\.\c set `sum \v\o\l\.\c` sum=$1 case $sum in 56099) :;; *) echo 'Bad sum in '\v\o\l\.\c >&2 esac echo Extracting \t\a\r\.\d\i\f\f sed 's/^X//' > \t\a\r\.\d\i\f\f << '+ END-OF-FILE '\t\a\r\.\d\i\f\f X3c3 X< /* Usage: tar [cxt][v] tapefile [files] X--- X> /* Usage: tar [cxt] tapefile [files] X59a60 X> extern printf(); X104c105,109 X< tar_fd = creat_fl ? creat(argv[2], 0644) : open(argv[2], 0); X--- X> if (strcmp(argv[2], "-") != 0) { X> tar_fd = creat_fl ? creat(argv[2], 0644) : open(argv[2], 0); X> } else { X> tar_fd = (creat_fl ? 1 : 0); X> } X427c432 X< write(1, output, index); X--- X> write(2, output, index); X435c440 X< write(1, output, BLOCK_SIZE); X--- X> write(2, output, BLOCK_SIZE); + END-OF-FILE tar.diff chmod 'u=rw,g=r,o=r' \t\a\r\.\d\i\f\f set `sum \t\a\r\.\d\i\f\f` sum=$1 case $sum in 59831) :;; *) echo 'Bad sum in '\t\a\r\.\d\i\f\f >&2 esac exit 0