xref: /openbsd/bin/mt/mt.c (revision 3aaa63eb)
1*3aaa63ebSderaadt /*	$OpenBSD: mt.c,v 1.41 2019/06/28 13:34:59 deraadt Exp $	*/
25832cf07Sderaadt /*	$NetBSD: mt.c,v 1.14.2.1 1996/05/27 15:12:11 mrg Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*
5df930be7Sderaadt  * Copyright (c) 1980, 1993
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
9df930be7Sderaadt  * modification, are permitted provided that the following conditions
10df930be7Sderaadt  * are met:
11df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
12df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
13df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
14df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
15df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
1629295d1cSmillert  * 3. Neither the name of the University nor the names of its contributors
17df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
18df930be7Sderaadt  *    without specific prior written permission.
19df930be7Sderaadt  *
20df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30df930be7Sderaadt  * SUCH DAMAGE.
31df930be7Sderaadt  */
32df930be7Sderaadt 
33df930be7Sderaadt /*
34df930be7Sderaadt  * mt --
35df930be7Sderaadt  *   magnetic tape manipulation program
36df930be7Sderaadt  */
37df930be7Sderaadt #include <sys/types.h>
38df930be7Sderaadt #include <sys/ioctl.h>
39df930be7Sderaadt #include <sys/mtio.h>
40d9f8509cSdm #include <sys/stat.h>
41dbb6d566Sdownsj #include <sys/disklabel.h>
42d9f8509cSdm 
43df930be7Sderaadt #include <ctype.h>
44d9f8509cSdm #include <err.h>
45dbb6d566Sdownsj #include <errno.h>
46d9f8509cSdm #include <fcntl.h>
47dbb6d566Sdownsj #include <paths.h>
48d9f8509cSdm #include <stdio.h>
49d9f8509cSdm #include <stdlib.h>
50df930be7Sderaadt #include <string.h>
5193e5a945Sniklas #include <unistd.h>
523e34b74fSdownsj #include <util.h>
537cb582b5Sderaadt #include <limits.h>
5493e5a945Sniklas 
5593e5a945Sniklas #include "mt.h"
56df930be7Sderaadt 
57df930be7Sderaadt struct commands {
58df930be7Sderaadt 	char *c_name;
59df930be7Sderaadt 	int c_code;
60df930be7Sderaadt 	int c_ronly;
615be1c94aStholo 	int c_mincount;
62df930be7Sderaadt } com[] = {
635be1c94aStholo 	{ "blocksize",	MTSETBSIZ,  1, 0 },
645be1c94aStholo 	{ "bsf",	MTBSF,      1, 1 },
655be1c94aStholo 	{ "bsr",	MTBSR,      1, 1 },
665be1c94aStholo 	{ "density",	MTSETDNSTY, 1, 1 },
675be1c94aStholo 	{ "eof",	MTWEOF,     0, 1 },
685be1c94aStholo 	{ "eom",	MTEOM,      1, 1 },
695be1c94aStholo 	{ "erase",	MTERASE,    0, 1 },
705be1c94aStholo 	{ "fsf",	MTFSF,      1, 1 },
715be1c94aStholo 	{ "fsr",	MTFSR,      1, 1 },
725be1c94aStholo 	{ "offline",	MTOFFL,     1, 1 },
7331b724bbSderaadt #define COM_EJECT	9	/* element in the above array */
745be1c94aStholo 	{ "rewind",	MTREW,      1, 1 },
755be1c94aStholo 	{ "rewoffl",	MTOFFL,     1, 1 },
765be1c94aStholo 	{ "status",	MTNOP,      1, 1 },
775be1c94aStholo 	{ "retension",	MTRETEN,    1, 1 },
7831b724bbSderaadt #define COM_RETEN	13	/* element in the above array */
795be1c94aStholo 	{ "weof",	MTWEOF,     0, 1 },
80df930be7Sderaadt 	{ NULL }
81df930be7Sderaadt };
82df930be7Sderaadt 
83c72b5b24Smillert void printreg(char *, u_int, char *);
84c72b5b24Smillert void status(struct mtget *);
85c72b5b24Smillert void usage(void);
86df930be7Sderaadt 
87e60bfc87Stedu int		_rmtopendev(char *path, int oflags, int dflags, char **realp);
88e60bfc87Stedu int		_rmtmtioctop(int fd, struct mtop *cmd);
89a3427febSderaadt struct mtget	*_rmtstatus(int fd);
90a3427febSderaadt void		_rmtclose(void);
91a3427febSderaadt 
92dab586c4Stobias extern char	*__progname;
93dab586c4Stobias 
9493e5a945Sniklas char	*host = NULL;	/* remote host (if any) */
9593e5a945Sniklas 
968a86195dSderaadt int
_rmtopendev(char * path,int oflags,int dflags,char ** realp)97e60bfc87Stedu _rmtopendev(char *path, int oflags, int dflags, char **realp)
988a86195dSderaadt {
998a86195dSderaadt #ifdef RMT
1008a86195dSderaadt 	if (host)
1018a86195dSderaadt 		return rmtopen(path, oflags);
1028a86195dSderaadt #endif
103e60bfc87Stedu 	return opendev(path, oflags, dflags, realp);
1048a86195dSderaadt }
1058a86195dSderaadt 
1068a86195dSderaadt int
_rmtmtioctop(int fd,struct mtop * cmd)107e60bfc87Stedu _rmtmtioctop(int fd, struct mtop *cmd)
1088a86195dSderaadt {
1098a86195dSderaadt #ifdef RMT
1108a86195dSderaadt 	if (host)
111e60bfc87Stedu 		return rmtioctl(cmd->mt_op, cmd->mt_count);
1128a86195dSderaadt #endif
113e60bfc87Stedu 	return ioctl(fd, MTIOCTOP, cmd);
1148a86195dSderaadt }
1158a86195dSderaadt 
1168a86195dSderaadt struct mtget *
_rmtstatus(int fd)1178a86195dSderaadt _rmtstatus(int fd)
1188a86195dSderaadt {
1198a86195dSderaadt 	static struct mtget mt_status;
1208a86195dSderaadt 
1218a86195dSderaadt #ifdef RMT
1228a86195dSderaadt 	if (host)
1238a86195dSderaadt 		return rmtstatus();
1248a86195dSderaadt #endif
125*3aaa63ebSderaadt 	if (ioctl(fd, MTIOCGET, &mt_status) == -1)
1268a86195dSderaadt 		err(2, "ioctl MTIOCGET");
1278a86195dSderaadt 	return &mt_status;
1288a86195dSderaadt }
1298a86195dSderaadt 
1308a86195dSderaadt void
_rmtclose(void)1318a86195dSderaadt _rmtclose(void)
1328a86195dSderaadt {
1338a86195dSderaadt #ifdef RMT
1348a86195dSderaadt 	if (host)
1358a86195dSderaadt 		rmtclose();
1368a86195dSderaadt #endif
1378a86195dSderaadt }
1388a86195dSderaadt 
139dbb6d566Sdownsj int	eject = 0;
140dbb6d566Sdownsj 
141df930be7Sderaadt int
main(int argc,char * argv[])142ab83b6d6Sderaadt main(int argc, char *argv[])
143df930be7Sderaadt {
144f516ca97Smpech 	struct commands *comp;
145df930be7Sderaadt 	struct mtop mt_com;
1463cf25153Sderaadt 	int ch, mtfd, flags, insert = 0;
14731b724bbSderaadt 	char *p, *tape, *realtape, *opts;
1483cf25153Sderaadt 	size_t len;
149df930be7Sderaadt 
150dab586c4Stobias 	if (strcmp(__progname, "eject") == 0) {
15131b724bbSderaadt 		opts = "t";
152dbb6d566Sdownsj 		eject = 1;
153f89198a3Sdownsj 		tape = NULL;
154f89198a3Sdownsj 	} else {
15531b724bbSderaadt 		opts = "f:";
156df930be7Sderaadt 		if ((tape = getenv("TAPE")) == NULL)
1571e2ae582Smillert 			tape = _PATH_DEFTAPE;
158f89198a3Sdownsj 	}
159df930be7Sderaadt 
16031b724bbSderaadt 	while ((ch = getopt(argc, argv, opts)) != -1) {
161df930be7Sderaadt 		switch (ch) {
16231b724bbSderaadt 		case 't':
16331b724bbSderaadt 			insert = 1;
16431b724bbSderaadt 			break;
165df930be7Sderaadt 		case 'f':
166df930be7Sderaadt 			tape = optarg;
167df930be7Sderaadt 			break;
168df930be7Sderaadt 		default:
169df930be7Sderaadt 			usage();
170df930be7Sderaadt 		}
171dbb6d566Sdownsj 	}
172df930be7Sderaadt 	argc -= optind;
173df930be7Sderaadt 	argv += optind;
174df930be7Sderaadt 
175dbb6d566Sdownsj 	if (eject) {
176dbb6d566Sdownsj 		if (argc == 1) {
177dbb6d566Sdownsj 			tape = *argv++;
178dbb6d566Sdownsj 			argc--;
179dbb6d566Sdownsj 		}
180dbb6d566Sdownsj 		if (argc != 0)
181dbb6d566Sdownsj 			usage();
182dbb6d566Sdownsj 	} else if (argc < 1 || argc > 2)
183df930be7Sderaadt 		usage();
184df930be7Sderaadt 
185f89198a3Sdownsj 	if (tape == NULL)
186f89198a3Sdownsj 		usage();
187f89198a3Sdownsj 
18893e5a945Sniklas 	if (strchr(tape, ':')) {
1898a86195dSderaadt #ifdef RMT
19093e5a945Sniklas 		host = tape;
19193e5a945Sniklas 		tape = strchr(host, ':');
19293e5a945Sniklas 		*tape++ = '\0';
19393e5a945Sniklas 		if (rmthost(host) == 0)
19493e5a945Sniklas 			exit(X_ABORT);
1958a86195dSderaadt #else
1968a86195dSderaadt 		err(1, "no remote support");
1978a86195dSderaadt #endif
19893e5a945Sniklas 	}
19993e5a945Sniklas 
2007cb582b5Sderaadt 	if (strlen(tape) >= PATH_MAX)
2017cb582b5Sderaadt 		err(1, "tape name too long for protocol");
2027cb582b5Sderaadt 
20331b724bbSderaadt 	if (eject) {
20431b724bbSderaadt 		if (insert)
20531b724bbSderaadt 			comp = &com[COM_RETEN];
20631b724bbSderaadt 		else
207dbb6d566Sdownsj 			comp = &com[COM_EJECT];
20831b724bbSderaadt 	} else {
209df930be7Sderaadt 		len = strlen(p = *argv++);
210df930be7Sderaadt 		for (comp = com;; comp++) {
211df930be7Sderaadt 			if (comp->c_name == NULL)
212df930be7Sderaadt 				errx(1, "%s: unknown command", p);
213df930be7Sderaadt 			if (strncmp(p, comp->c_name, len) == 0)
214df930be7Sderaadt 				break;
215df930be7Sderaadt 		}
216dbb6d566Sdownsj 	}
217d9f8509cSdm 
218d9f8509cSdm 	flags = comp->c_ronly ? O_RDONLY : O_WRONLY | O_CREAT;
219eb27cc7bSkrw 	/* NOTE: OPENDEV_PART required since cd(4) devices go through here. */
220*3aaa63ebSderaadt 	if ((mtfd = _rmtopendev(tape, flags, OPENDEV_PART, &realtape)) == -1) {
221b9f7d163Smillert 		if (errno != 0)
222b9f7d163Smillert 			warn("%s", host ? tape : realtape);
223b9f7d163Smillert 		exit(2);
224b9f7d163Smillert 	}
225df930be7Sderaadt 	if (comp->c_code != MTNOP) {
226df930be7Sderaadt 		mt_com.mt_op = comp->c_code;
227df930be7Sderaadt 		if (*argv) {
228df930be7Sderaadt 			mt_com.mt_count = strtol(*argv, &p, 10);
2295be1c94aStholo 			if (mt_com.mt_count < comp->c_mincount || *p)
230df930be7Sderaadt 				errx(2, "%s: illegal count", *argv);
231df930be7Sderaadt 		}
232df930be7Sderaadt 		else
233df930be7Sderaadt 			mt_com.mt_count = 1;
234*3aaa63ebSderaadt 		if (_rmtmtioctop(mtfd, &mt_com) == -1) {
2358aaf01bbSderaadt 			if (eject)
2368aaf01bbSderaadt 				err(2, "%s", tape);
2378aaf01bbSderaadt 			else
238df930be7Sderaadt 				err(2, "%s: %s", tape, comp->c_name);
2398aaf01bbSderaadt 		}
240df930be7Sderaadt 	} else {
2418a86195dSderaadt 		status(_rmtstatus(mtfd));
24293e5a945Sniklas 	}
24393e5a945Sniklas 
2448a86195dSderaadt 	_rmtclose();
24593e5a945Sniklas 
24693e5a945Sniklas 	exit(X_FINOK);
247df930be7Sderaadt 	/* NOTREACHED */
248df930be7Sderaadt }
249df930be7Sderaadt 
250df930be7Sderaadt struct tape_desc {
251df930be7Sderaadt 	short	t_type;		/* type of magtape device */
252df930be7Sderaadt 	char	*t_name;	/* printing name */
253df930be7Sderaadt 	char	*t_dsbits;	/* "drive status" register */
254df930be7Sderaadt 	char	*t_erbits;	/* "error" register */
255df930be7Sderaadt } tapes[] = {
25663088399Sderaadt #define SCSI_DS_BITS	"\20\5WriteProtect\2Mounted"
25763088399Sderaadt 	{ 0x7,		"SCSI",		SCSI_DS_BITS,	"76543210" },
258df930be7Sderaadt 	{ 0 }
259df930be7Sderaadt };
260df930be7Sderaadt 
261df930be7Sderaadt /*
262df930be7Sderaadt  * Interpret the status buffer returned
263df930be7Sderaadt  */
264df930be7Sderaadt void
status(struct mtget * bp)265ab83b6d6Sderaadt status(struct mtget *bp)
266df930be7Sderaadt {
267f516ca97Smpech 	struct tape_desc *mt;
268df930be7Sderaadt 
269df930be7Sderaadt 	for (mt = tapes;; mt++) {
270df930be7Sderaadt 		if (mt->t_type == 0) {
271df930be7Sderaadt 			(void)printf("%d: unknown tape drive type\n",
272df930be7Sderaadt 			    bp->mt_type);
273df930be7Sderaadt 			return;
274df930be7Sderaadt 		}
275df930be7Sderaadt 		if (mt->t_type == bp->mt_type)
276df930be7Sderaadt 			break;
277df930be7Sderaadt 	}
278df930be7Sderaadt 	(void)printf("%s tape drive, residual=%d\n", mt->t_name, bp->mt_resid);
279df930be7Sderaadt 	printreg("ds", bp->mt_dsreg, mt->t_dsbits);
280df930be7Sderaadt 	printreg("\ner", bp->mt_erreg, mt->t_erbits);
281df930be7Sderaadt 	(void)putchar('\n');
282628571dcSkrw 	(void)printf("blocksize: %d (%d)\n", bp->mt_blksiz, bp->mt_mblksiz);
283628571dcSkrw 	(void)printf("density: %d (%d)\n", bp->mt_density, bp->mt_mdensity);
284d00e20d1Skrw 	(void)printf("current file number: %d\n", bp->mt_fileno);
285d00e20d1Skrw 	(void)printf("current block number: %d\n", bp->mt_blkno);
286df930be7Sderaadt }
287df930be7Sderaadt 
288df930be7Sderaadt /*
289df930be7Sderaadt  * Print a register a la the %b format of the kernel's printf.
290df930be7Sderaadt  */
291df930be7Sderaadt void
printreg(char * s,u_int v,char * bits)292ab83b6d6Sderaadt printreg(char *s, u_int v, char *bits)
293df930be7Sderaadt {
294f516ca97Smpech 	int i, any = 0;
295f516ca97Smpech 	char c;
296df930be7Sderaadt 
297df930be7Sderaadt 	if (bits && *bits == 8)
298df930be7Sderaadt 		printf("%s=%o", s, v);
299df930be7Sderaadt 	else
300df930be7Sderaadt 		printf("%s=%x", s, v);
301cd408bcaSderaadt 	if (!bits)
302cd408bcaSderaadt 		return;
303df930be7Sderaadt 	bits++;
30463088399Sderaadt 	if (v && *bits) {
305df930be7Sderaadt 		putchar('<');
30693e5a945Sniklas 		while ((i = *bits++)) {
307df930be7Sderaadt 			if (v & (1 << (i-1))) {
308df930be7Sderaadt 				if (any)
309df930be7Sderaadt 					putchar(',');
310df930be7Sderaadt 				any = 1;
311df930be7Sderaadt 				for (; (c = *bits) > 32; bits++)
312df930be7Sderaadt 					putchar(c);
313df930be7Sderaadt 			} else
314df930be7Sderaadt 				for (; *bits > 32; bits++)
315df930be7Sderaadt 					;
316df930be7Sderaadt 		}
317df930be7Sderaadt 		putchar('>');
318df930be7Sderaadt 	}
319df930be7Sderaadt }
320df930be7Sderaadt 
321df930be7Sderaadt void
usage(void)322ab83b6d6Sderaadt usage(void)
323df930be7Sderaadt {
324dbb6d566Sdownsj 	if (eject)
325dab586c4Stobias 		(void)fprintf(stderr, "usage: %s [-t] device\n", __progname);
326dbb6d566Sdownsj 	else
327dbb6d566Sdownsj 		(void)fprintf(stderr,
328dab586c4Stobias 		    "usage: %s [-f device] command [count]\n", __progname);
32993e5a945Sniklas 	exit(X_USAGE);
330df930be7Sderaadt }
331