v21i102: Table of Contents for Exebyte 8mm tapes
Rich Salz
rsalz at bbn.com
Thu Apr 12 05:37:42 AEST 1990
Submitted-by: Matt Landau <mlandau at diamond.bbn.com>
Posting-number: Volume 21, Issue 102
Archive-name: exebyte_toc
Exetoc is a program that allows you to write a table of contents file onto
the front of a 2GB helical scan tape, read it back later, and update it
without disturbing the other contents of the tape.
It does this by reserving a fixed amount of space at the start of the tape
(about 10 megabytes in the current implementation) that can be used to
store information about the contents of the tape. About 2 megabytes of
this space is available for keeping the table of contents. The rest acts
as a buffer space between the end of the table of contents and the first
data file on the tape.
#! /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 shell archive."
# Contents: Makefile exetoc.c smtops.c exitcodes.h smtio.h smtops.h
# exetoc.man
# Wrapped by mlandau at dilithium on Wed Apr 11 14:41:09 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f Makefile -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(765 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
XSRCS = exetoc.c smtops.c
XOBJS = exetoc.o smtops.o
XHDRS = exitcodes.h smtio.h smtops.h
XDOCS = exetoc.man
X
X# Uncomment this if you have librmt.a installed someplace
XRMT = -DREMOTE=1 -I/usr/local/include
XLIBS = /usr/local/lib/librmt.a
X
X# Uncomment this if you DON'T have librmt.a installed someplace
X#RMT =
X#LIBS =
X
XCFLAGS = $(RMT) -O
X
XBINDIR = /usr/local/bin
XMANDIR = /usr/local/man/man1
XMANEXT = 1
X
Xexetoc: $(OBJS)
X cc $(CFLAGS) -o exetoc $(OBJS) $(LIBS)
X
Xinstall: exetoc
X install -s exetoc $(BINDIR)
X cp exetoc.man $(MANDIR)/exetoc.$(MANEXT)
X
Xclean:
X /bin/rm -f exetoc a.out $(OBJS) core *.BAK *.CKP
X
Xshar:
X shar Makefile $(SRCS) $(HDRS) $(DOCS) >exetoc.shar
X
Xsaber:
X # load $(SRCS)
X
X
Xexetoc.o: exitcodes.h smtio.h smtops.h
Xsmtops.o: exitcodes.h smtio.h smtops.h
END_OF_Makefile
if test 765 -ne `wc -c <Makefile`; then
echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f exetoc.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"exetoc.c\"
else
echo shar: Extracting \"exetoc.c\" \(8029 characters\)
sed "s/^X//" >exetoc.c <<'END_OF_exetoc.c'
X/*
X * exetoc.c -- A program to read, write, and rewrite tables of contents
X * on tapes in an exebyte tape drive.
X *
X * USAGE: exetoc [-t|f tape] [-g file] [-p file] [-i] [-v] [-q]
X *
X * -t specifies the tape drive, default is /dev/rsmt0
X * -f is a synonym for -t, a la mt.
X * -g gets the table of contents from the tape and
X * sticks it into "file", which may be "-"
X * for standard output.
X * -p puts the table of contents contained in "file"
X * onto the front of the tape. You can use
X * "-" to take the table of contents from
X * standard input.
X * -i initializes the tape by creating a blank table
X * of contents.
X * -v verifies that this tape has been initialized.
X * -q causes the program to work quietly.
X *
X * You MUST provide exactly one of the -i, -g, -p, or -v flags.
X */
X
X#if !lint && !SABER
Xstatic char RcsId[] = "$Header: exetoc.c,v 1.3 89/10/27 16:14:34 mlandau Exp $";
X#endif
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#include "exitcodes.h"
X#include "smtops.h"
X
X#define FORWARD /* nothing */
X
X#define KBytes(n) (n * 1024)
X#define MBytes(n) (1024 * KBytes(n))
X#define MIN(a, b) ((a) < (b) ? (a) : (b))
X#define streq(s1, s2) (!strcmp(s1, s2))
X
X#define IOBUF_SIZE KBytes(62) /* Exebyte likes 62KB chunks */
X#define TOC_SIZE MBytes(10) /* TOC occupied 10 MB on the tape */
X#define TOC_USEABLE MBytes(2) /* About 2 MB of it can be used */
X
X#define TOC_MARKER "[ExeTOC Table of Contents]"
X
X#define OP_NONE 0
X#define OP_VERIFY 1
X#define OP_INIT 2
X#define OP_FETCH 3
X#define OP_STORE 4
X
X/* Getopt stuff */
Xextern char *optarg;
Xextern int optind;
Xextern int opterr;
X
X/* Linked in later */
Xextern char *getenv();
Xextern char *rindex();
X
X/* Shut Saber up */
XFORWARD void usage();
XFORWARD void set_operation();
XFORWARD void mark_tape();
XFORWARD void initialize_tape();
XFORWARD int check_tape();
XFORWARD void toc_to_file();
XFORWARD void toc_from_file();
XFORWARD void rewind_named_device();
X
X
X/* Only need one big buffer to hold the table of contents */
Xstatic char Buffer[IOBUF_SIZE];
Xstatic int Quiet = 0;
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X int option;
X int operation = OP_NONE;
X char *tapename = "/dev/rsmt0";
X int hastoc;
X int tapefd;
X int tocfd;
X
X opterr = 0;
X if ((tapename = getenv("EXEBYTE")) == NULL)
X tapename = "/dev/rsmt0";
X while ((option = getopt(argc, argv, "t:f:g:p:ivq")) != EOF)
X {
X switch (option)
X {
X case 't':
X case 'f':
X tapename = optarg;
X break;
X
X case 'g':
X set_operation(&operation, OP_FETCH);
X if (streq(optarg, "-"))
X tocfd = fileno(stdout);
X else
X tocfd = check_open(optarg, O_WRONLY|O_CREAT|O_TRUNC, 0666);
X break;
X
X case 'p':
X set_operation(&operation, OP_STORE);
X if (streq(optarg, "-"))
X tocfd = fileno(stdin);
X else
X tocfd = check_open(optarg, O_RDONLY, 0666);
X break;
X
X case 'i':
X set_operation(&operation, OP_INIT);
X break;
X
X case 'v':
X set_operation(&operation, OP_VERIFY);
X break;
X
X case 'q':
X Quiet = 1;
X break;
X
X default:
X usage(argv[0]);
X exit(EXIT_USAGE);
X /* NOTREACHED */
X break;
X }
X }
X
X switch (operation)
X {
X case OP_NONE:
X fputs("You must specify one of -g, -p, -i, or -v\n", stderr);
X exit(EXIT_USAGE);
X
X case OP_INIT:
X tapefd = smt_open(tapename, O_WRONLY);
X initialize_tape(tapefd);
X smt_close(tapefd);
X rewind_named_device(tapename);
X exit(EXIT_OK);
X
X case OP_VERIFY:
X tapefd = smt_open(tapename, O_RDONLY);
X hastoc = check_tape(tapefd);
X smt_close(tapefd);
X rewind_named_device(tapename);
X if (!Quiet)
X printf("Tape in %s %s a labeled ExeTOC tape.\n",
X tapename, hastoc ? "is" : "is not");
X exit(hastoc ? EXIT_OK : EXIT_NOTOC);
X
X case OP_FETCH:
X tapefd = smt_open(tapename, O_RDWR);
X if (!check_tape(tapefd))
X {
X fprintf(stderr, "Tape in %s is not a labeled ExeTOC tape.\n",
X tapename);
X exit(EXIT_NOTOC);
X }
X toc_to_file(tapefd, tocfd);
X smt_close(tapefd);
X rewind_named_device(tapename);
X if (tocfd != fileno(stdout))
X close(tocfd);
X exit(EXIT_OK);
X
X case OP_STORE:
X tapefd = smt_open(tapename, O_RDWR);
X if (!check_tape(tapefd))
X {
X fprintf(stderr, "Tape in %s is not a labeled ExeTOC tape.\n",
X tapename);
X exit(EXIT_NOTOC);
X }
X mark_tape(tapefd);
X toc_from_file(tapefd, tocfd);
X smt_close_without_eof(tapefd);
X rewind_named_device(tapename);
X if (tocfd != fileno(stdin))
X close(tocfd);
X exit(EXIT_OK);
X
X default:
X fprintf(stderr, "Unknown tape operation code (%d)\n", operation);
X exit(EXIT_USAGE);
X }
X}
X
Xvoid usage(progname)
Xchar *progname;
X{
X static char *summary =
X "usage: %s [-t tape] [-g file] [-p file] [-i] [-v] [-q]\n";
X static char *syntax[] = {
X "",
X "\t-t specifies the tape device. Default is $EXEBYTE, or /dev/rsmt0.",
X "\t-g gets the table of contents from the tape into the named file.",
X "\t-p puts the table of contants in the named file onto the tape.",
X "\t-i initializes a new tape so it can include a table of contents.",
X "\t-v verifies that a tape has previously been initialized.",
X "\t-q causes the program to work more quietly than usual.",
X "",
X "(Note: the tape is always rewound after any of these operations.)",
X NULL
X };
X char *p;
X register int i;
X
X if ((p = rindex(progname, '/')) != NULL)
X progname = p+1;
X
X fprintf(stderr, summary, progname);
X for (i = 0; syntax[i] != NULL; ++i)
X fprintf(stderr, "%s\n", syntax[i]);
X}
X
X
X
Xvoid rewind_named_device(name)
Xchar *name;
X{
X int tapefd = smt_open(name, O_RDONLY);
X
X smt_rewind(tapefd);
X smt_close(tapefd);
X}
X
X
Xvoid set_operation(op, opcode)
Xint *op;
Xint opcode;
X{
X if (*op != OP_NONE)
X {
X fputs("Only one of -g, -p, -i, and -q may be supplied.\n", stderr);
X exit(EXIT_USAGE);
X }
X *op = opcode;
X}
X
X
Xint check_open(name, mode, perm)
Xchar *name;
Xint mode;
Xint perm;
X{
X int fd;
X
X if ((fd = open(name, mode, perm)) < 0)
X {
X perror(name);
X exit(EXIT_IO);
X }
X return (fd);
X}
X
X
Xvoid mark_tape(tapefd)
Xint tapefd;
X{
X bzero(Buffer, sizeof(Buffer));
X strcpy(Buffer, TOC_MARKER);
X smt_rewind(tapefd);
X if (smt_write(tapefd, Buffer, sizeof(Buffer)) < sizeof(Buffer))
X {
X perror("tape label");
X exit(EXIT_IO);
X }
X}
X
X
Xvoid initialize_tape(tapefd)
Xint tapefd;
X{
X int nbufs = (TOC_SIZE / IOBUF_SIZE);
X
X mark_tape(tapefd);
X bzero(Buffer, sizeof(Buffer));
X while (--nbufs > 0)
X smt_write(tapefd, Buffer, sizeof(Buffer));
X}
X
X
Xint check_tape(tapefd)
Xint tapefd;
X{
X smt_rewind(tapefd);
X return (smt_read(tapefd, Buffer, sizeof(Buffer)) == sizeof(Buffer)
X &&
X streq(Buffer, TOC_MARKER));
X}
X
X
Xvoid toc_to_file(tapefd, tocfd)
Xint tapefd;
Xint tocfd;
X{
X int n;
X register int i;
X register char *bp;
X
X bzero(Buffer, sizeof(Buffer));
X while ((n = smt_read(tapefd, Buffer, sizeof(Buffer))) > 0)
X {
X if (n < sizeof(Buffer))
X {
X perror("tape read");
X exit(EXIT_IO);
X }
X for (bp = Buffer, i = 0; i < sizeof(Buffer) && *bp != 0; bp++, i++)
X continue;
X if (write(tocfd, Buffer, i) != i)
X {
X perror("file write");
X exit(EXIT_IO);
X }
X if (i < sizeof(Buffer))
X break;
X }
X}
X
X
Xvoid toc_from_file(tapefd, tocfd)
Xint tapefd;
Xint tocfd;
X{
X struct stat s;
X int n;
X
X if (tocfd != fileno(stdin))
X {
X if (fstat(tocfd, &s) < 0)
X {
X perror("fstat");
X exit(EXIT_IO);
X }
X if (s.st_size > TOC_USEABLE)
X {
X fputs("Table of Contents file is too large.\n", stderr);
X exit(EXIT_TOOBIG);
X }
X }
X
X bzero(Buffer, sizeof(Buffer));
X while ((n = read(tocfd, Buffer, sizeof(Buffer))) > 0)
X {
X if (n < sizeof(Buffer))
X bzero(Buffer + n, sizeof(Buffer) - n);
X if (smt_write(tapefd, Buffer, sizeof(Buffer)) < sizeof(Buffer))
X {
X perror("tape write");
X exit(EXIT_IO);
X }
X }
X if (n < 0)
X {
X perror("file read");
X exit(EXIT_IO);
X }
X}
END_OF_exetoc.c
if test 8029 -ne `wc -c <exetoc.c`; then
echo shar: \"exetoc.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f smtops.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"smtops.c\"
else
echo shar: Extracting \"smtops.c\" \(3587 characters\)
sed "s/^X//" >smtops.c <<'END_OF_smtops.c'
X#if !lint && !SABER
Xstatic char RcsId[] = "$Header: smtops.c,v 1.2 89/10/27 16:14:58 mlandau Exp $";
X#endif
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/types.h>
X#include <sys/ioctl.h>
X#include <sys/mtio.h>
X
X#if REMOTE
X#include <rmt.h>
X#endif
X
X#include "exitcodes.h"
X#include "smtops.h"
X
X
X/****************************************************************************
X * BASIC MAGTAPE OPERATIONS FOR EXEBYTE DRIVES
X ***************************************************************************/
X
X
X/*
X * smt_open(): Open a tape device.
X *
X * Actually, it's just a wrapper around open, but data abstraction is
X * good, right?
X */
X
X
Xint smt_open(device, mode)
Xchar *device;
Xint mode;
X{
X int fd;
X
X if ((fd = open(device, mode)) < 0)
X {
X perror(device);
X exit(EXIT_IO);
X }
X return (fd);
X}
X
X
X/*
X * smt_close(): Close a tape device -- this is just a wrapper around close.
X */
X
Xvoid smt_close(tapefd)
Xint tapefd;
X{
X if (close(tapefd) < 0)
X {
X perror("tape close");
X exit(EXIT_IO);
X }
X}
X
X
X/*
X * smt_close_without_eof(): Rewind and close a tape device.
X *
X * This routine provides a rewind-and-close operation, which is
X * necessary to prevent the tape device driver from adding an EOF
X * mark to the tape if the last operation before closing the device
X * was a write. Since we are continutally rewriting the same file,
X * we need to inform the driver that we don't want a new EOF mark
X * every time we do so.
X */
X
Xvoid smt_close_without_eof(tapefd)
Xint tapefd;
X{
X smt_rewind(tapefd);
X smt_close(tapefd);
X}
X
X
X/*
X * smt_read(): Read from the tape drive
X * smt_write(): Write to the tape drive
X *
X *
X * This are wrappers around read and write. They're mostly here
X * so that we can use the rmt library if we want to.
X */
X
Xint smt_read(tapefd, buffer, count)
Xint tapefd;
Xchar *buffer;
Xint count;
X{
X return (read(tapefd, buffer, count));
X}
X
X
Xint smt_write(tapefd, buffer, count)
Xint tapefd;
Xchar *buffer;
Xint count;
X{
X return (write(tapefd, buffer, count));
X}
X
X
X/*
X * smt_status(): Return the status of the tape drive.
X *
X * This code is cribbed from the mts command. The smt_stat structure
X * looks like this:
X *
X * struct smt_stat
X * {
X * char smt_type[8]; -- cartridge type
X * u_long smt_remain; -- KBytes left on tape
X * u_long smt_size; -- Total size of tape (KBytes)
X * u_long smt_ecc; -- ECC numbers
X * long smt_wp:1; -- write protected?
X * long smt_bot:1; -- at beginning of tape?
X * }
X */
X
Xstruct smt_stat *smt_status(tapefd)
Xint tapefd;
X{
X static struct smt_stat status;
X
X if (ioctl(tapefd, SMTIOGETSTAT, &status) < 0)
X {
X perror("tape status");
X exit(EXIT_IO);
X }
X return (&status);
X}
X
X
X
X/*
X * smt_rewind(): Rewind a tape and verify that it worked.
X */
X
Xvoid smt_rewind(tapefd)
Xint tapefd;
X{
X static struct mtop rewind_op = { MTREW, 1 };
X
X if (ioctl(tapefd, MTIOCTOP, &rewind_op) < 0)
X {
X perror("tape rewind");
X exit(EXIT_IO);
X }
X#if !REMOTE
X /* rmtlib.a does not like the custom ioctls used in the smt_status
X routine, so don't use it internally */
X if (!smt_status(tapefd)->smt_bot)
X {
X fputs("Could not rewind tape for some unknown reason.");
X exit(EXIT_IO);
X }
X#endif
X}
X
X
X/*
X * smt_eof(): Write an EOF mark on the tape.
X *
X * We will probably never need this, but it doesn't hurt to include it.
X */
X
Xvoid smt_eof(tapefd)
Xint tapefd;
X{
X static struct mtop eof_op = { MTWEOF, 1 };
X
X if (ioctl(tapefd, MTIOCTOP, &eof_op) < 0)
X {
X perror("write eof");
X exit(EXIT_IO);
X }
X}
X
X
END_OF_smtops.c
if test 3587 -ne `wc -c <smtops.c`; then
echo shar: \"smtops.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f exitcodes.h -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"exitcodes.h\"
else
echo shar: Extracting \"exitcodes.h\" \(153 characters\)
sed "s/^X//" >exitcodes.h <<'END_OF_exitcodes.h'
X#ifndef EXITCODES_H
X#define EXITCODES_H 1
X
X#define EXIT_OK 0
X#define EXIT_USAGE 1
X#define EXIT_IO 2
X#define EXIT_NOTOC 3
X#define EXIT_TOOBIG 4
X
X#endif
END_OF_exitcodes.h
if test 153 -ne `wc -c <exitcodes.h`; then
echo shar: \"exitcodes.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f smtio.h -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"smtio.h\"
else
echo shar: Extracting \"smtio.h\" \(445 characters\)
sed "s/^X//" >smtio.h <<'END_OF_smtio.h'
X#include <sys/ioctl.h>
X
X/* structures and defines for ioctls */
Xstruct smt_stat {
X char smt_type[8]; /* Cartridge type */
X unsigned long smt_remain; /* # of kilobytes remaining on tape */
X unsigned long smt_size; /* size (in kb) of tape */
X unsigned long smt_ecc; /* ECC count */
X long smt_wp:1; /* Write protected */
X long smt_bot:1; /* At beginning of tape */
X};
X
X#define SMTIOGETSTAT _IOR(m,0,struct smt_stat) /* get the drive status */
END_OF_smtio.h
if test 445 -ne `wc -c <smtio.h`; then
echo shar: \"smtio.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f smtops.h -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"smtops.h\"
else
echo shar: Extracting \"smtops.h\" \(308 characters\)
sed "s/^X//" >smtops.h <<'END_OF_smtops.h'
X#ifndef SMTOPS_H
X#define SMTOPS_H 1
X
X#include "smtio.h"
Xextern struct smt_stat *smt_status();
X
Xextern int smt_open();
Xextern void smt_close();
Xextern void smt_close_without_eof();
Xextern void smt_rewind();
Xextern void smt_eof();
Xextern int smt_read();
Xextern int smt_write();
X
X#endif
END_OF_smtops.h
if test 308 -ne `wc -c <smtops.h`; then
echo shar: \"smtops.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f exetoc.man -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"exetoc.man\"
else
echo shar: Extracting \"exetoc.man\" \(3224 characters\)
sed "s/^X//" >exetoc.man <<'END_OF_exetoc.man'
X.TH EXETOC 1L "27 Oct 1989"
X.SH NAME
Xexetoc \- Manage a table of contents on an Exebyte 2GB tape cartridge.
X.SH SYNOPSIS
X.B exetoc
X.BI [-t tape ]
X.BI [-g file ]
X.BI [-p file ]
X.B [-i]
X.B [-v]
X.B [-q]
X.SH DESCRIPTION
X.B Exetoc is a program that allows you to write a table of contents
Xfile onto the front of a 2GB helical scan tape, read it back later,
Xand update it without disturbing the other contents of the tape.
X.PP
XIt does this by reserving a fixed amount of space at the start of
Xthe tape (about 10 megabytes in the current implementation) that can be
Xused to store information about the contents of the tape. About 2
Xmegabytes of this space is available for keeping the table of
Xcontents. The rest acts as a buffer space between the end of the table
Xof contents and the first data file on the tape.
X.SH OPTIONS
X.B Exetoc understands the following options:
X.TP
X.BI -t tapedrive
XSets the tape drive name to something other than the default, which
Xis derived by looking for the environment variable EXETOC, or using
X"/dev/rsmt0" if the environment variable is not set. Exetoc is normally
Xlinked with the remote tape library, allowing you to use
Xnames of the form \fIhost:device\fP for direct access to remote tape
Xdrives.
X.TP
X.BI -g file
XGets the table of contents from the tape and places a copy of
Xit into the named file. If \fIfile\fP is given as -, the table of
Xcontents is copied to standard output.
X.TP
X.BI -p file
XPuts a table of contents onto the tape. The contents of the table
Xare taken from the named file, or from standard input if \fIfile\fP
Xis given as -. This flag may be used to create and rewrite tables
Xof contents.
X.TP
X.B -i
XInitializes a tape by creating a blank table of contents at the
Xfront of the tape. You must initialize a tape with the -i flag before
Xyou can write a table of contents onto it for the first time.
X.TP
X.B -v
XVerifies that the tape in the tape drive has previously been initialized
Xwith exetoc -i.
X.TP
X.B -q
XCauses the program to work more quietly than it otherwise would.
X.LP
XAny other option causes exetoc to deliver a lengthy message explaining
Xthe legal flags.
X.SH "ENVIRIONMENT VARIABLES"
X.TP
XEXEBYTE
XSpecifies the default tape drive to use. Exetoc is normally linked
Xwith the remote tape library, allowing you to use names of the form
X\fIhost:device\fP for direct access to remote tape drives.
X.SH "EXIT STATUS"
XExetoc exits with one of the following well-defined status codes:
X.TP
X0
Xindicates successful completion of an operation.
X.TP
X1
Xindicates an error in usage (illegal command line flag, for instance).
X.TP
X2
Xindicates an I/O error of some kind. A diagnostic message is printed
Xon standard error in this case, explaining what the error was.
X.TP
X3
Xindicates that a read, write, or verify operation was attempted with a
Xtape that has never been initialized to hold a table of contents.
X.TP
X4
Xindicates that the table of contents file you are trying to write onto
Xthe tape is too large to fit.
X.SH BUGS
XThe tape is rewound after \fIany\fP exetoc operation, even if the no-rewind
Xdevice was specified on the command line.
X.SH "SEE ALSO"
X.nf
Xdd(1), bdd(1), mt(1)
X.SH AUTHOR
X.nf
XMatt Landau, BBN Systems and Technologies Corp. (mlandau at bbn.com)
END_OF_exetoc.man
if test 3224 -ne `wc -c <exetoc.man`; then
echo shar: \"exetoc.man\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0
exit 0 # Just in case...
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.
More information about the Comp.sources.unix
mailing list