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