[alt.sources] Util to control ctg tapes using the 386.ix Wangtek driver

pat@rwing.UUCP (Pat Myrto) (08/16/90)

This thing is for those users of ISC 386/ix that are using the Wangtek
tape driver.  Since the tapecntl or ctape commands don't work with this
driver, one is left with no means to retension or erase the tape.
Wt.c provides a means to accomplish this, plus providing a rewind
and fsf (fwd skip over file) function accomplished by faking it using
the proper combination of open() and close() on the tape device (the
no-rewind device in the case of fsf, the rewind device for the rewind
function).  These opens are done O_RDONLY so as to not mark the tape or
affect data.  It works for me, your mileage may vary.  It compiles OK
on ISC 386/ix, I don't know about other flavors.  No makefile, just
either say 'make wt' or 'cc -O wt.c -o wt'.

The posting was inspired by Most Frequently Asked Question #5 in
the comp.unix.386ix newsgroup.  Its posted here, because comp.unix.386/ix
isn't a sources newsgroup.

#! /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:  README wt.c
# Wrapped by pat@rwing on Wed Aug 15 19:15:29 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(2668 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X				wt.c
X				====
X
This is a util that I made because ISC 2.0.2 didn't provide a
means to retension, or erase cartridge tapes that used the Wangtek
driver provided as part of the ISC package.  Once that worked, I added
in a piecemeal fashion the functions that accomplished a rewind (by
opening and closing the device), and a means to skip over data on an
partially filled cartridge, so one could put another archive on it.
The fwd skip function also works for positioning to read the second
archive.
X
Since the driver only provides 2 ioctl() operations (retension and
erase), the rewind and fsf functions are cobbled together by use of
open(), close() and read() operations - in other words, faked.
The fsf (forward skip file) takes an optional count, but because
of the limitations of the driver, it doesn't handle a count greater
than the number of files to skip gracefully, and ends up positioning
the tape in a useless position.  A rewind is needed to get things
squared away again.  Still, its handy if one doesn't tell it to
go past the last record.
X
The util defaults to use the devices that are normally created when
the Wangtek driver is configured, with provision to try the several
alternate names in case one or more is removed, etc.  One can also
specify the device to access using the one and only option, -f.
X
This thing is anything but elegant, but it is one approach to the
question of how does one do these operations on a cartridge tape under
ISC version 2.0.2.  More info as to how its used is in the source.
No makefile is needed - with wt.c in the current working directory
simply type ``make wt'', or if you prefer, use this command:
X``cc -O -s wt.c -o wt -lc_s''.  This will make a smaller executable
because it uses the shared library.
X
DISCLAIMER:  No guarantees are made regarding suitability or
correctness of wt.c, especially when used to position the tape to put
more than one archive on a tape.  If one doesn't know what they are
doing, using the fsf option could set you up to lose data - as in the
case where a second archive is present, and one replaces the first one
on the tape.  Second files or archives on a tape are not a great idea
unless one KNOWS that they will not be altering the preceeding
archive.  If one has to change the preceeding archives, read ALL the
data off the cartridge, or put the changed archive on another
cartridge, and then, if necessary, copy the following archives off the
previous ctg and add them to the new one.  One cannot change the size
of archives on a tape without clobbering following archives as one can
do on a floppy disk.  Use common sense here.
X
XEnjoy, but at your own risk.				pat@rwing
X
END_OF_FILE
if test 2668 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'wt.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'wt.c'\"
else
echo shar: Extracting \"'wt.c'\" \(5600 characters\)
sed "s/^X//" >'wt.c' <<'END_OF_FILE'
X/*	@(#) wt.c - a Wangtek command utility.
X *	A utility to issue the ioctl(2) commands to retension
X *	and/or erase cartridge tapes using the Wangtek (wt) driver.
X *	There was no way to accomplish this provided with the system,
X *	and while trivial, one needs to be able to retension new tapes
X *	and sometimes erase cartridges, to remove records that confuse
X *	the less-than-great Wangtek driver provided by ISC.  Some other
X *	basic ops added as time passed that, while possible by proper
X *	command line operations using various commands, these were awkward
X *	and error prone.  This kludge helps a little bit.
X *	Of course, the REAL answer is a decent driver, and proper support
X *	utilities.
X *
X *	This thing will try /dev/rmt0, if that fails, it will look at
X *	/dev/tape, then /dev/rSA/rmt0.  If given a name via -f option it
X *	will try only that name.
X *
X *	Tossed together (literally) by pat@rwing Fri Aug 10 22:54:44 PDT 1990
X *
X *	Placed in the Public Domain by pat@rwing.
X */
X
X#include <sys/wtioctl.h>
X#include <stdio.h>
X#include <errno.h>
X#include <fcntl.h>
X
X#define	NOENTS 4
X
X/* HUNK
X * size of read() requests when scanning over data - I heard that ctg
X * tapes block at 63k, performance trials tend to bear this out.
X */
X#define HUNK 64512
X
void	exit();		/* to keep lint(1) smiling */
void	usage();
X
X/* usual default names for the normal rewind-on-close device */
char *tape[NOENTS] = {
X	"/dev/rmt0",
X	"/dev/tape",
X	"/dev/rSA/tape",
X	(char *)NULL
X};
X
X/* usual default names for the NO rewind-on-close device */
char *ntape[NOENTS] = {
X	"/dev/rnmt0",
X	"/dev/ntape",
X	"/dev/rSA/ntape",
X	(char *)NULL
X};
X
X/* foundation of a couple of commonly used error messages */
char msgfmt[] = "Unable to open tape for %s\n";
char errnofmt[] = "Return from errno = %d\n";
extern int errno;
X
main(argc, argv)
int argc;
char **argv;
X{
X    int fd, i, j, count, result;
X    char scratch[HUNK];	/* buffer for reads to scan over data */
X    char *cname=argv[0];
X
X    /* see if user specifies a device, and if so, get its name */
X    if (*argv[1] == '-') {
X	if (argv[1][1] == 'f') {
X	    if (argv[1][2] != '\0') {
X		ntape[0] = tape[0] = &argv[1][2];
X		argv += 1; argc -= 1;
X	    } else {
X		ntape[0] = tape[0] = argv[2];
X		argv += 2; argc -= 2;
X	    }
X	    ntape[1] = tape[1] = (char *)NULL; /* lock out default names */
X	} else {
X	    (void) fprintf(stderr,
X			  "\n%s: %2.2s -- invalid option\n\n", cname, argv[1]);
X	    usage(cname);
X	    exit(1);
X	}
X    }
X
X    /* erase tape */
X    if (!strncmp(argv[1], "erase", 3)){
X	/* search for a working device */
X	for (i = 0; tape[i] != NULL && (fd = open(tape[i], O_WRONLY)) < 0; i++)
X			;
X	if (fd < 0) {		/* open failed, complain and exit */
X	    (void) fprintf(stderr, msgfmt, "writing");
X	    (void) perror("");
X	    exit(errno);	/* in case a script can use it */
X	}
X	if (ioctl(fd, WTQICMD, ERASE) <0)
X		perror("erase ioctl failed");
X
X	(void) close(fd);    /* if close fails, nothing we can do about it */
X    } /* end erase */
X
X    else if (!strncmp(argv[1], "retens", 3)) {	/* retension tape */
X	for (i = 0; tape[i] != NULL && (fd = open(tape[i], O_RDONLY)) < 0; i++)
X			;
X	if (fd < 0) {
X	    (void) fprintf(stderr, msgfmt, "reading");
X	    (void) perror("");
X	    exit(errno);
X	}
X	if (ioctl(fd, WTQICMD, RETENS) < 0)
X		perror("retension ioctl failed");
X
X	(void) close(fd);
X    } /* end retension */
X
X    else if (!strncmp(argv[1], "rewind", 3)) {	/* rewind */
X	for (i = 0; tape[i] != NULL && (fd = open(tape[i], O_RDONLY)) < 0; i++)
X			;
X	if (fd < 0) {
X	    (void) fprintf(stderr, msgfmt, "reading");
X	    (void) perror("");
X	    exit(errno);
X	}
X	(void) close(fd); /* no rewind ioctl(), so fake it with open/close */
X    } /* end rewind */
X
X    /* This operation is faked, so it does not handle requests
X     * to skip over more files (archives) than exist on the tape.
X     * Still, its useful to position the tape if one knows the number
X     * of recordings are on the ctg.
X     */
X
X    else if (!strncmp(argv[1], "fsf", 3)) {	/* forward skip over archive */
X	count = atoi(argv[2]);
X	count = (count == 0 ? 1 : count);
X	for (j = 0; j < count; j++) {
X	    for (i = 0; ntape[i] != NULL	/* split to keep on screen */
X		&& (fd = open(ntape[i], O_RDONLY)) < 0; i++)
X			    ;
X	    if (fd < 0) {
X		(void) fprintf(stderr, msgfmt, "reading");
X		(void) perror("");
X		exit(errno);
X	    }
X
X	    while((result = read(fd, scratch, HUNK)) > 0)
X			    ;
X
X	    if (result < 0) {
X		perror("past EOD - rewind tape to use");
X		exit(1);
X	    }
X	    (void) close(fd); /* closing tape opened as ntape holds position */
X	}
X    } /* end fwd skip file */
X
X    else {  /* unrecognized cmd */
X	usage(cname);	/* tell user how to use this thing */
X	exit(1);	/* give a failed exit */
X    }
X    exit(0);
X    /*NOTREACHED*/
X}
X
void usage(cname)
char *cname;
X{
X    
X    /* void casts are to make lint shut up */
X    (void) fprintf(stderr, "Command utility for Wangtek ctg drives.\n");
X    (void) fprintf(stderr, "Usage: %s [-f device] command \n", cname);
X    (void) fprintf(stderr, "command is one of:\n");
X    (void) fprintf(stderr, "    erase - erase tape\n");
X    (void) fprintf(stderr, "    retens - retension tape \n");
X    (void) fprintf(stderr, "    rewind - rewind a tape left unwound\n");
X    (void) fprintf(stderr, "    fsf [n] - skip over file or archive on tape\n");
X    (void) fprintf(stderr, "if an open fails, wt tries other names for ");
X    (void) fprintf(stderr, "the tape device,\nin case a node wasn't");
X    (void) fprintf(stderr, "created, or was removed.  If a name is given by\n");
X    (void) fprintf(stderr, "the -f option, only that name will be tried.\n");
X}
END_OF_FILE
if test 5600 -ne `wc -c <'wt.c'`; then
    echo shar: \"'wt.c'\" unpacked with wrong size!
fi
# end of 'wt.c'
fi
echo shar: End of shell archive.
exit 0
-- 
pat@rwing                                       (Pat Myrto),  Seattle, WA
                            ...!uunet!pilchuck!rwing!pat
      ...!uw-beaver!uw-entropy!dataio!/
WISDOM:    "Travelling unarmed is like boating without a life jacket"