mt.c revision 7913
11590Srgrimes/*
21590Srgrimes * Copyright (c) 1980, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
341590Srgrimes#ifndef lint
351590Srgrimesstatic char copyright[] =
361590Srgrimes"@(#) Copyright (c) 1980, 1993\n\
371590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381590Srgrimes#endif /* not lint */
391590Srgrimes
401590Srgrimes#ifndef lint
411590Srgrimesstatic char sccsid[] = "@(#)mt.c	8.1 (Berkeley) 6/6/93";
421590Srgrimes#endif /* not lint */
431590Srgrimes
441590Srgrimes/*
451590Srgrimes * mt --
461590Srgrimes *   magnetic tape manipulation program
471590Srgrimes */
481590Srgrimes#include <sys/types.h>
491590Srgrimes#include <sys/ioctl.h>
501590Srgrimes#include <sys/mtio.h>
511590Srgrimes#include <fcntl.h>
521590Srgrimes#include <errno.h>
531590Srgrimes#include <stdlib.h>
541590Srgrimes#include <stdio.h>
551590Srgrimes#include <ctype.h>
561590Srgrimes#include <string.h>
571590Srgrimes
587913Sjoerg/* the appropriate sections of <sys/mtio.h> are also #ifdef'd for FreeBSD */
597913Sjoerg#if defined(__FreeBSD__)
607913Sjoerg/* c_flags */
617913Sjoerg#define NEED_2ARGS	0x01
627913Sjoerg#define ZERO_ALLOWED	0X02
637913Sjoerg#endif /* defined(__FreeBSD__) */
647913Sjoerg
651590Srgrimesstruct commands {
661590Srgrimes	char *c_name;
671590Srgrimes	int c_code;
681590Srgrimes	int c_ronly;
697913Sjoerg#if defined(__FreeBSD__)
707913Sjoerg	int c_flags;
717913Sjoerg#endif /* defined(__FreeBSD__) */
721590Srgrimes} com[] = {
731590Srgrimes	{ "bsf",	MTBSF,	1 },
741590Srgrimes	{ "bsr",	MTBSR,	1 },
751590Srgrimes	{ "eof",	MTWEOF,	0 },
761590Srgrimes	{ "fsf",	MTFSF,	1 },
771590Srgrimes	{ "fsr",	MTFSR,	1 },
781590Srgrimes	{ "offline",	MTOFFL,	1 },
791590Srgrimes	{ "rewind",	MTREW,	1 },
801590Srgrimes	{ "rewoffl",	MTOFFL,	1 },
811590Srgrimes	{ "status",	MTNOP,	1 },
821590Srgrimes	{ "weof",	MTWEOF,	0 },
837913Sjoerg#if defined(__FreeBSD__)
847913Sjoerg	{ "erase",	MTERASE, 0 },
857913Sjoerg	{ "blocksize",	MTSETBSIZ, 0, NEED_2ARGS|ZERO_ALLOWED },
867913Sjoerg	{ "density",	MTSETDNSTY, 0, NEED_2ARGS|ZERO_ALLOWED },
877913Sjoerg	{ "eom",	MTEOD, 1 },
887913Sjoerg	{ "comp",	MTCOMP, 0, NEED_2ARGS|ZERO_ALLOWED },
897913Sjoerg#endif /* defined(__FreeBSD__) */
901590Srgrimes	{ NULL }
911590Srgrimes};
921590Srgrimes
931590Srgrimesvoid err __P((const char *, ...));
941590Srgrimesvoid printreg __P((char *, u_int, char *));
951590Srgrimesvoid status __P((struct mtget *));
961590Srgrimesvoid usage __P((void));
977913Sjoerg#if defined (__FreeBSD__)
987913Sjoergvoid st_status (struct mtget *);
997913Sjoerg#endif /* defined (__FreeBSD__) */
1001590Srgrimes
1011590Srgrimesint
1021590Srgrimesmain(argc, argv)
1031590Srgrimes	int argc;
1041590Srgrimes	char *argv[];
1051590Srgrimes{
1061590Srgrimes	register struct commands *comp;
1071590Srgrimes	struct mtget mt_status;
1081590Srgrimes	struct mtop mt_com;
1091590Srgrimes	int ch, len, mtfd;
1101590Srgrimes	char *p, *tape;
1111590Srgrimes
1121590Srgrimes	if ((tape = getenv("TAPE")) == NULL)
1131590Srgrimes		tape = DEFTAPE;
1141590Srgrimes
1151590Srgrimes	while ((ch = getopt(argc, argv, "f:t:")) != EOF)
1161590Srgrimes		switch(ch) {
1171590Srgrimes		case 'f':
1181590Srgrimes		case 't':
1191590Srgrimes			tape = optarg;
1201590Srgrimes			break;
1211590Srgrimes		case '?':
1221590Srgrimes		default:
1231590Srgrimes			usage();
1241590Srgrimes		}
1251590Srgrimes	argc -= optind;
1261590Srgrimes	argv += optind;
1271590Srgrimes
1281590Srgrimes	if (argc < 1 || argc > 2)
1291590Srgrimes		usage();
1301590Srgrimes
1311590Srgrimes	len = strlen(p = *argv++);
1321590Srgrimes	for (comp = com;; comp++) {
1331590Srgrimes		if (comp->c_name == NULL)
1341590Srgrimes			err("%s: unknown command", p);
1351590Srgrimes		if (strncmp(p, comp->c_name, len) == 0)
1361590Srgrimes			break;
1371590Srgrimes	}
1387913Sjoerg#if defined(__FreeBSD__)
1397913Sjoerg	if((comp->c_flags & NEED_2ARGS) && argc != 2)
1407913Sjoerg		usage();
1417913Sjoerg#endif /* defined(__FreeBSD__) */
1421590Srgrimes	if ((mtfd = open(tape, comp->c_ronly ? O_RDONLY : O_RDWR)) < 0)
1431590Srgrimes		err("%s: %s", tape, strerror(errno));
1441590Srgrimes	if (comp->c_code != MTNOP) {
1451590Srgrimes		mt_com.mt_op = comp->c_code;
1461590Srgrimes		if (*argv) {
1477913Sjoerg#if defined (__FreeBSD__)
1487913Sjoerg			/* allow for hex numbers; useful for density */
1497913Sjoerg			mt_com.mt_count = strtol(*argv, &p, 0);
1507913Sjoerg#else
1511590Srgrimes			mt_com.mt_count = strtol(*argv, &p, 10);
1527913Sjoerg#endif /* defined(__FreeBSD__) */
1537913Sjoerg			if (mt_com.mt_count <=
1547913Sjoerg#if defined (__FreeBSD__)
1557913Sjoerg			    ((comp->c_flags & ZERO_ALLOWED)? -1: 0)
1567913Sjoerg#else
1577913Sjoerg			    0
1587913Sjoerg#endif /* defined (__FreeBSD__) */
1597913Sjoerg			    || *p)
1601590Srgrimes				err("%s: illegal count", *argv);
1611590Srgrimes		}
1621590Srgrimes		else
1631590Srgrimes			mt_com.mt_count = 1;
1641590Srgrimes		if (ioctl(mtfd, MTIOCTOP, &mt_com) < 0)
1651590Srgrimes			err("%s: %s: %s", tape, comp->c_name, strerror(errno));
1661590Srgrimes	} else {
1671590Srgrimes		if (ioctl(mtfd, MTIOCGET, &mt_status) < 0)
1681590Srgrimes			err("%s", strerror(errno));
1691590Srgrimes		status(&mt_status);
1701590Srgrimes	}
1711590Srgrimes	exit (0);
1721590Srgrimes	/* NOTREACHED */
1731590Srgrimes}
1741590Srgrimes
1751590Srgrimes#ifdef vax
1761590Srgrimes#include <vax/mba/mtreg.h>
1771590Srgrimes#include <vax/mba/htreg.h>
1781590Srgrimes
1791590Srgrimes#include <vax/uba/utreg.h>
1801590Srgrimes#include <vax/uba/tmreg.h>
1811590Srgrimes#undef b_repcnt		/* argh */
1821590Srgrimes#include <vax/uba/tsreg.h>
1831590Srgrimes#endif
1841590Srgrimes
1851590Srgrimes#ifdef sun
1861590Srgrimes#include <sundev/tmreg.h>
1871590Srgrimes#include <sundev/arreg.h>
1881590Srgrimes#endif
1891590Srgrimes
1901590Srgrimes#ifdef tahoe
1911590Srgrimes#include <tahoe/vba/cyreg.h>
1921590Srgrimes#endif
1931590Srgrimes
1941590Srgrimesstruct tape_desc {
1951590Srgrimes	short	t_type;		/* type of magtape device */
1961590Srgrimes	char	*t_name;	/* printing name */
1971590Srgrimes	char	*t_dsbits;	/* "drive status" register */
1981590Srgrimes	char	*t_erbits;	/* "error" register */
1991590Srgrimes} tapes[] = {
2001590Srgrimes#ifdef vax
2011590Srgrimes	{ MT_ISTS,	"ts11",		0,		TSXS0_BITS },
2021590Srgrimes	{ MT_ISHT,	"tm03",		HTDS_BITS,	HTER_BITS },
2031590Srgrimes	{ MT_ISTM,	"tm11",		0,		TMER_BITS },
2041590Srgrimes	{ MT_ISMT,	"tu78",		MTDS_BITS,	0 },
2051590Srgrimes	{ MT_ISUT,	"tu45",		UTDS_BITS,	UTER_BITS },
2061590Srgrimes#endif
2071590Srgrimes#ifdef sun
2081590Srgrimes	{ MT_ISCPC,	"TapeMaster",	TMS_BITS,	0 },
2091590Srgrimes	{ MT_ISAR,	"Archive",	ARCH_CTRL_BITS,	ARCH_BITS },
2101590Srgrimes#endif
2111590Srgrimes#ifdef tahoe
2121590Srgrimes	{ MT_ISCY,	"cipher",	CYS_BITS,	CYCW_BITS },
2131590Srgrimes#endif
2147913Sjoerg#if defined (__FreeBSD__)
2157913Sjoerg	/*
2167913Sjoerg	 * XXX This is terrific.  The st driver reports the tape drive
2177913Sjoerg	 * as 0x7 (MT_ISAR - Sun/Archive compatible); the wt driver
2187913Sjoerg	 * either reports MT_ISVIPER1 for an Archive tape, or 0x11
2197913Sjoerg	 * (MT_ISMFOUR) for other tapes.
2207913Sjoerg	 * XXX for the wt driver, rely on it behaving like a "standard"
2217913Sjoerg	 * magtape driver.
2227913Sjoerg	 */
2237913Sjoerg	{ MT_ISAR,	"SCSI tape drive", 0,		0 },
2247913Sjoerg	{ MT_ISVIPER1,	"Archive Viper", 0,		0 },
2257913Sjoerg	{ MT_ISMFOUR,	"Wangtek",	0,		0 },
2267913Sjoerg#endif /* defined (__FreeBSD__) */
2271590Srgrimes	{ 0 }
2281590Srgrimes};
2291590Srgrimes
2301590Srgrimes/*
2311590Srgrimes * Interpret the status buffer returned
2321590Srgrimes */
2331590Srgrimesvoid
2341590Srgrimesstatus(bp)
2351590Srgrimes	register struct mtget *bp;
2361590Srgrimes{
2371590Srgrimes	register struct tape_desc *mt;
2381590Srgrimes
2391590Srgrimes	for (mt = tapes;; mt++) {
2401590Srgrimes		if (mt->t_type == 0) {
2411590Srgrimes			(void)printf("%d: unknown tape drive type\n",
2421590Srgrimes			    bp->mt_type);
2431590Srgrimes			return;
2441590Srgrimes		}
2451590Srgrimes		if (mt->t_type == bp->mt_type)
2461590Srgrimes			break;
2471590Srgrimes	}
2487913Sjoerg#if defined (__FreeBSD__)
2497913Sjoerg	if(mt->t_type == MT_ISAR)
2507913Sjoerg		st_status(bp);
2517913Sjoerg	else {
2527913Sjoerg#endif /* defined (__FreeBSD__) */
2531590Srgrimes	(void)printf("%s tape drive, residual=%d\n", mt->t_name, bp->mt_resid);
2541590Srgrimes	printreg("ds", bp->mt_dsreg, mt->t_dsbits);
2551590Srgrimes	printreg("\ner", bp->mt_erreg, mt->t_erbits);
2561590Srgrimes	(void)putchar('\n');
2577913Sjoerg#if defined (__FreeBSD__)
2587913Sjoerg	}
2597913Sjoerg#endif /* defined (__FreeBSD__) */
2601590Srgrimes}
2611590Srgrimes
2621590Srgrimes/*
2631590Srgrimes * Print a register a la the %b format of the kernel's printf.
2641590Srgrimes */
2651590Srgrimesvoid
2661590Srgrimesprintreg(s, v, bits)
2671590Srgrimes	char *s;
2681590Srgrimes	register u_int v;
2691590Srgrimes	register char *bits;
2701590Srgrimes{
2711590Srgrimes	register int i, any = 0;
2721590Srgrimes	register char c;
2731590Srgrimes
2741590Srgrimes	if (bits && *bits == 8)
2751590Srgrimes		printf("%s=%o", s, v);
2761590Srgrimes	else
2771590Srgrimes		printf("%s=%x", s, v);
2781590Srgrimes	bits++;
2791590Srgrimes	if (v && bits) {
2801590Srgrimes		putchar('<');
2811590Srgrimes		while (i = *bits++) {
2821590Srgrimes			if (v & (1 << (i-1))) {
2831590Srgrimes				if (any)
2841590Srgrimes					putchar(',');
2851590Srgrimes				any = 1;
2861590Srgrimes				for (; (c = *bits) > 32; bits++)
2871590Srgrimes					putchar(c);
2881590Srgrimes			} else
2891590Srgrimes				for (; *bits > 32; bits++)
2901590Srgrimes					;
2911590Srgrimes		}
2921590Srgrimes		putchar('>');
2931590Srgrimes	}
2941590Srgrimes}
2951590Srgrimes
2961590Srgrimesvoid
2971590Srgrimesusage()
2981590Srgrimes{
2991590Srgrimes	(void)fprintf(stderr, "usage: mt [-f device] command [ count ]\n");
3001590Srgrimes	exit(1);
3011590Srgrimes}
3021590Srgrimes
3031590Srgrimes#if __STDC__
3041590Srgrimes#include <stdarg.h>
3051590Srgrimes#else
3061590Srgrimes#include <varargs.h>
3071590Srgrimes#endif
3081590Srgrimes
3091590Srgrimesvoid
3101590Srgrimes#if __STDC__
3111590Srgrimeserr(const char *fmt, ...)
3121590Srgrimes#else
3131590Srgrimeserr(fmt, va_alist)
3141590Srgrimes	char *fmt;
3151590Srgrimes        va_dcl
3161590Srgrimes#endif
3171590Srgrimes{
3181590Srgrimes	va_list ap;
3191590Srgrimes#if __STDC__
3201590Srgrimes	va_start(ap, fmt);
3211590Srgrimes#else
3221590Srgrimes	va_start(ap);
3231590Srgrimes#endif
3241590Srgrimes	(void)fprintf(stderr, "mt: ");
3251590Srgrimes	(void)vfprintf(stderr, fmt, ap);
3261590Srgrimes	va_end(ap);
3271590Srgrimes	(void)fprintf(stderr, "\n");
3281590Srgrimes	exit(1);
3291590Srgrimes	/* NOTREACHED */
3301590Srgrimes}
3317913Sjoerg
3327913Sjoerg#if defined (__FreeBSD__)
3337913Sjoerg
3347913Sjoergstruct densities {
3357913Sjoerg	int dens;
3367913Sjoerg	const char *name;
3377913Sjoerg} dens [] = {
3387913Sjoerg	{ 0x1,  "X3.22-1983  " },
3397913Sjoerg	{ 0x2,  "X3.39-1986  " },
3407913Sjoerg	{ 0x3,  "X3.54-1986  " },
3417913Sjoerg	{ 0x5,  "X3.136-1986 " },
3427913Sjoerg	{ 0x6,  "X3.157-1987 " },
3437913Sjoerg	{ 0x7,  "X3.116-1986 " },
3447913Sjoerg	{ 0x8,  "X3.158-1986 " },
3457913Sjoerg	{ 0x9,  "X3B5/87-099 " },
3467913Sjoerg	{ 0xA,  "X3B5/86-199 " },
3477913Sjoerg	{ 0xB,  "X3.56-1986  " },
3487913Sjoerg	{ 0xC,  "HI-TC1      " },
3497913Sjoerg	{ 0xD,  "HI-TC2      " },
3507913Sjoerg	{ 0xF,  "QIC-120     " },
3517913Sjoerg	{ 0x10, "QIC-150     " },
3527913Sjoerg	{ 0x11, "QIC-320     " },
3537913Sjoerg	{ 0x12, "QIC-1350    " },
3547913Sjoerg	{ 0x13, "X3B5/88-185A" },
3557913Sjoerg	{ 0x14, "X3.202-1991 " },
3567913Sjoerg	{ 0x15, "ECMA TC17   " },
3577913Sjoerg	{ 0x16, "X3.193-1990 " },
3587913Sjoerg	{ 0x17, "X3B5/91-174 " },
3597913Sjoerg	{ 0, 0 }
3607913Sjoerg};
3617913Sjoerg
3627913Sjoergconst char *
3637913Sjoerggetdens(int d)
3647913Sjoerg{
3657913Sjoerg	static char buf[20];
3667913Sjoerg	struct densities *sd;
3677913Sjoerg
3687913Sjoerg	for (sd = dens; sd->dens; sd++)
3697913Sjoerg		if (sd->dens == d)
3707913Sjoerg			break;
3717913Sjoerg	if (sd->dens == 0) {
3727913Sjoerg		sprintf(buf, "0x%02x        ", d);
3737913Sjoerg		return buf;
3747913Sjoerg	}
3757913Sjoerg	else
3767913Sjoerg		return sd->name;
3777913Sjoerg}
3787913Sjoerg
3797913Sjoergconst char *
3807913Sjoerggetblksiz(int bs)
3817913Sjoerg{
3827913Sjoerg	static char buf[25];
3837913Sjoerg	if (bs == 0)
3847913Sjoerg		return "variable";
3857913Sjoerg	else {
3867913Sjoerg		sprintf(buf, "= %d bytes", bs);
3877913Sjoerg		return buf;
3887913Sjoerg	}
3897913Sjoerg}
3907913Sjoerg
3917913Sjoerg
3927913Sjoergvoid
3937913Sjoergst_status(struct mtget *bp)
3947913Sjoerg{
3957913Sjoerg	printf("Present Mode:   Density = %s Blocksize %s\n",
3967913Sjoerg	       getdens(bp->mt_density), getblksiz(bp->mt_blksiz));
3977913Sjoerg	printf("---------available modes---------\n");
3987913Sjoerg	printf("Mode 0:         Density = %s Blocksize %s\n",
3997913Sjoerg	       getdens(bp->mt_density0), getblksiz(bp->mt_blksiz0));
4007913Sjoerg	printf("Mode 1:         Density = %s Blocksize %s\n",
4017913Sjoerg	       getdens(bp->mt_density1), getblksiz(bp->mt_blksiz1));
4027913Sjoerg	printf("Mode 2:         Density = %s Blocksize %s\n",
4037913Sjoerg	       getdens(bp->mt_density2), getblksiz(bp->mt_blksiz2));
4047913Sjoerg	printf("Mode 3:         Density = %s Blocksize %s\n",
4057913Sjoerg	       getdens(bp->mt_density3), getblksiz(bp->mt_blksiz3));
4067913Sjoerg}
4077913Sjoerg
4087913Sjoerg#endif /* defined (__FreeBSD__) */
409