xref: /minix3/minix/commands/mt/mt.c (revision d0055759dd8892194db7fce6acc5085d5c9aeaee)
1433d6423SLionel Sambuc /*	mt 1.3 - magnetic tape control			Author: Kees J. Bot
2433d6423SLionel Sambuc  *								4 Apr 1993
3433d6423SLionel Sambuc  */
4433d6423SLionel Sambuc #define nil	NULL
5433d6423SLionel Sambuc #ifndef _POSIX_SOURCE
6433d6423SLionel Sambuc #define _POSIX_SOURCE	1
7433d6423SLionel Sambuc #endif
8433d6423SLionel Sambuc #include <sys/types.h>
9433d6423SLionel Sambuc #include <stdio.h>
10433d6423SLionel Sambuc #include <stdlib.h>
11433d6423SLionel Sambuc #include <errno.h>
12433d6423SLionel Sambuc #include <unistd.h>
13433d6423SLionel Sambuc #include <fcntl.h>
14433d6423SLionel Sambuc #include <string.h>
15433d6423SLionel Sambuc #include <sys/ioctl.h>
16433d6423SLionel Sambuc #include <sys/mtio.h>
17433d6423SLionel Sambuc 
18433d6423SLionel Sambuc /* Device status. */
19433d6423SLionel Sambuc #define DS_OK		0
20433d6423SLionel Sambuc #define DS_ERR		1
21433d6423SLionel Sambuc #define DS_EOF		2
22433d6423SLionel Sambuc 
23433d6423SLionel Sambuc /* SCSI Sense key bits. */
24433d6423SLionel Sambuc #define SENSE_KEY	0x0F	/* The key part. */
25433d6423SLionel Sambuc #define SENSE_ILI	0x20	/* Illegal block size. */
26433d6423SLionel Sambuc #define SENSE_EOM	0x40	/* End-of-media. */
27433d6423SLionel Sambuc #define SENSE_EOF	0x80	/* Filemark reached. */
28433d6423SLionel Sambuc 
29433d6423SLionel Sambuc /* Supported operations: */
30433d6423SLionel Sambuc 
31433d6423SLionel Sambuc typedef struct tape_operation {
32433d6423SLionel Sambuc 	int	op;		/* Opcode for MTIOCTOP ioctl (if any). */
33433d6423SLionel Sambuc 	char	*cmd;		/* Command name. */
34433d6423SLionel Sambuc 	int	lim;		/* Limits on count. */
35433d6423SLionel Sambuc } tape_operation_t;
36433d6423SLionel Sambuc 
37433d6423SLionel Sambuc #define SELF	-1	/* Not a simple command, have to interpret. */
38433d6423SLionel Sambuc #define IGN	-1	/* Ignore count field (or accept anything.) */
39433d6423SLionel Sambuc #define NNG	 0	/* Nonnegative count field. */
40433d6423SLionel Sambuc #define POS	 1	/* Positive count field. */
41433d6423SLionel Sambuc 
42433d6423SLionel Sambuc tape_operation_t tapeops[] = {
43433d6423SLionel Sambuc 	{ MTWEOF,  "eof",      POS },	/* Write EOF mark */
44433d6423SLionel Sambuc 	{ MTWEOF,  "weof",     POS },	/* Same */
45433d6423SLionel Sambuc 	{ MTFSF,   "fsf",      POS },	/* Forward Space File */
46433d6423SLionel Sambuc 	{ MTFSR,   "fsr",      POS },	/* Forward Space Record */
47433d6423SLionel Sambuc 	{ MTBSF,   "bsf",      NNG },	/* Backward Space File */
48433d6423SLionel Sambuc 	{ MTBSR,   "bsr",      POS },	/* Backward Space Record */
49433d6423SLionel Sambuc 	{ MTEOM,   "eom",      IGN },	/* To End-Of-Media */
50433d6423SLionel Sambuc 	{ MTREW,   "rewind",   IGN },	/* Rewind */
51433d6423SLionel Sambuc 	{ MTOFFL,  "offline",  IGN },	/* Rewind and take offline */
52433d6423SLionel Sambuc 	{ MTOFFL,  "rewoffl",  IGN },	/* Same */
53433d6423SLionel Sambuc 	{ SELF,	   "status",   IGN },	/* Tape Status */
54433d6423SLionel Sambuc 	{ MTRETEN, "retension",IGN },	/* Retension the tape */
55433d6423SLionel Sambuc 	{ MTERASE, "erase",    IGN },	/* Erase the tape */
56433d6423SLionel Sambuc 	{ MTSETDNSTY,  "density",  NNG },	/* Select density */
57433d6423SLionel Sambuc 	{ MTSETBSIZ,  "blksize",  NNG },	/* Select block size */
58433d6423SLionel Sambuc 	{ MTSETBSIZ,  "blocksize",NNG },	/* Same */
59433d6423SLionel Sambuc };
60433d6423SLionel Sambuc 
61433d6423SLionel Sambuc #define arraysize(a)	(sizeof(a)/sizeof((a)[0]))
62433d6423SLionel Sambuc #define arraylimit(a)	((a) + arraysize(a))
63433d6423SLionel Sambuc 
64433d6423SLionel Sambuc /* From aha_scsi.c: */
65433d6423SLionel Sambuc char *dev_state[] = {
66433d6423SLionel Sambuc 	"OK", "ERR", "EOF"
67433d6423SLionel Sambuc };
68433d6423SLionel Sambuc 
69433d6423SLionel Sambuc char *scsi_sense[] = {
70433d6423SLionel Sambuc 	"NO SENSE INFO", "RECOVERED ERROR", "NOT READY", "MEDIUM ERROR",
71433d6423SLionel Sambuc 	"HARDWARE ERROR", "ILLEGAL REQUEST", "UNIT ATTENTION", "DATA PROTECT",
72433d6423SLionel Sambuc 	"BLANK CHECK", "VENDOR UNIQUE ERROR", "COPY ABORTED", "ABORTED COMMAND",
73433d6423SLionel Sambuc 	"EQUAL", "VOLUME OVERFLOW", "MISCOMPARE", "SENSE RESERVED"
74433d6423SLionel Sambuc };
75433d6423SLionel Sambuc 
usage(void)76433d6423SLionel Sambuc void usage(void)
77433d6423SLionel Sambuc {
78433d6423SLionel Sambuc 	fprintf(stderr, "Usage: mt [-f device] command [count]\n");
79433d6423SLionel Sambuc 	exit(1);
80433d6423SLionel Sambuc }
81433d6423SLionel Sambuc 
main(int argc,char ** argv)82433d6423SLionel Sambuc int main(int argc, char **argv)
83433d6423SLionel Sambuc {
84433d6423SLionel Sambuc 	char *tape;
85433d6423SLionel Sambuc 	char *cmd;
86433d6423SLionel Sambuc 	int count= 1;
87433d6423SLionel Sambuc 	int fd, r;
88433d6423SLionel Sambuc 	tape_operation_t *op, *found;
89433d6423SLionel Sambuc 	struct mtop mtop;
90433d6423SLionel Sambuc 	struct mtget mtget;
91433d6423SLionel Sambuc 
92433d6423SLionel Sambuc 	tape= getenv("TAPE");
93433d6423SLionel Sambuc 
94433d6423SLionel Sambuc 	/* -f tape? */
95433d6423SLionel Sambuc 	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'f') {
96433d6423SLionel Sambuc 		tape= argv[1] + 2;
97433d6423SLionel Sambuc 
98433d6423SLionel Sambuc 		if (*tape == 0) {
99433d6423SLionel Sambuc 			if (--argc < 2) usage();
100433d6423SLionel Sambuc 			argv++;
101433d6423SLionel Sambuc 			tape= argv[1];
102433d6423SLionel Sambuc 		}
103433d6423SLionel Sambuc 		argc--;
104433d6423SLionel Sambuc 		argv++;
105433d6423SLionel Sambuc 	}
106433d6423SLionel Sambuc 
107433d6423SLionel Sambuc 	if (argc != 2 && argc != 3) usage();
108433d6423SLionel Sambuc 
109433d6423SLionel Sambuc 	if (argc == 3) {
110433d6423SLionel Sambuc 		/* Check and convert the 'count' argument. */
111433d6423SLionel Sambuc 		char *end;
112433d6423SLionel Sambuc 
113433d6423SLionel Sambuc 		errno= 0;
114433d6423SLionel Sambuc 		count= strtol(argv[2], &end, 0);
115433d6423SLionel Sambuc 		if (*end != 0) usage();
116433d6423SLionel Sambuc 		if (errno == ERANGE || (mtop.mt_count= count) != count) {
117433d6423SLionel Sambuc 			fprintf(stderr, "mt: %s: count too large, overflow\n",
118433d6423SLionel Sambuc 				argv[2]);
119433d6423SLionel Sambuc 			exit(1);
120433d6423SLionel Sambuc 		}
121433d6423SLionel Sambuc 	}
122433d6423SLionel Sambuc 
123433d6423SLionel Sambuc 	if (tape == nil) {
124433d6423SLionel Sambuc 		fprintf(stderr,
125433d6423SLionel Sambuc 			"mt: tape device not specified by -f or $TAPE\n");
126433d6423SLionel Sambuc 		exit(1);
127433d6423SLionel Sambuc 	}
128433d6423SLionel Sambuc 
129433d6423SLionel Sambuc 	cmd= argv[1];
130433d6423SLionel Sambuc 	if (strcmp(cmd, "rew") == 0) cmd= "rewind";	/* aha! */
131433d6423SLionel Sambuc 	found= nil;
132433d6423SLionel Sambuc 
133433d6423SLionel Sambuc 	/* Search for an operation that is unambiguously named. */
134433d6423SLionel Sambuc 	for (op= tapeops; op < arraylimit(tapeops); op++) {
135433d6423SLionel Sambuc 		if (strncmp(op->cmd, cmd, strlen(cmd)) == 0) {
136433d6423SLionel Sambuc 			if (found != nil) {
137433d6423SLionel Sambuc 				fprintf(stderr, "mt: %s: ambiguous\n", cmd);
138433d6423SLionel Sambuc 				exit(1);
139433d6423SLionel Sambuc 			}
140433d6423SLionel Sambuc 			found= op;
141433d6423SLionel Sambuc 		}
142433d6423SLionel Sambuc 	}
143433d6423SLionel Sambuc 
144433d6423SLionel Sambuc 	if ((op= found) == nil) {
145433d6423SLionel Sambuc 		fprintf(stderr, "mt: unknown command '%s'\n", cmd);
146433d6423SLionel Sambuc 		exit(1);
147433d6423SLionel Sambuc 	}
148433d6423SLionel Sambuc 
149433d6423SLionel Sambuc 	/* Check count. */
150433d6423SLionel Sambuc 	switch (op->lim) {
151433d6423SLionel Sambuc 	case NNG:
152433d6423SLionel Sambuc 		if (count < 0) {
153433d6423SLionel Sambuc 			fprintf(stderr, "mt %s: count may not be negative\n",
154433d6423SLionel Sambuc 				op->cmd);
155433d6423SLionel Sambuc 			exit(1);
156433d6423SLionel Sambuc 		}
157433d6423SLionel Sambuc 		break;
158433d6423SLionel Sambuc 	case POS:
159433d6423SLionel Sambuc 		if (count <= 0) {
160433d6423SLionel Sambuc 			fprintf(stderr,
161433d6423SLionel Sambuc 				"mt %s: count must be greater than zero\n",
162433d6423SLionel Sambuc 				op->cmd);
163433d6423SLionel Sambuc 			exit(1);
164433d6423SLionel Sambuc 		}
165433d6423SLionel Sambuc 		break;
166433d6423SLionel Sambuc 	}
167433d6423SLionel Sambuc 
168433d6423SLionel Sambuc 	if (strcmp(tape, "-") == 0) {
169433d6423SLionel Sambuc 		fd= 0;
170433d6423SLionel Sambuc 	} else
171433d6423SLionel Sambuc 	if ((fd= open(tape, O_RDONLY)) < 0) {
172433d6423SLionel Sambuc 		fprintf(stderr, "mt: %s: %s\n", tape, strerror(errno));
173433d6423SLionel Sambuc 		exit(1);
174433d6423SLionel Sambuc 	}
175433d6423SLionel Sambuc 
176433d6423SLionel Sambuc 	if (op->op != SELF) {
177433d6423SLionel Sambuc 		/* A simple tape operation. */
178433d6423SLionel Sambuc 
179433d6423SLionel Sambuc 		mtop.mt_op= op->op;
180433d6423SLionel Sambuc 		mtop.mt_count= count;
181433d6423SLionel Sambuc 		r= ioctl(fd, MTIOCTOP, &mtop);
182433d6423SLionel Sambuc 	} else
183433d6423SLionel Sambuc 	if (strcmp(op->cmd, "status") == 0) {
184433d6423SLionel Sambuc 		/* Get status information. */
185433d6423SLionel Sambuc 
186433d6423SLionel Sambuc 		if ((r= ioctl(fd, MTIOCGET, &mtget)) == 0) {
187433d6423SLionel Sambuc 			printf("\
188433d6423SLionel Sambuc SCSI tape drive %s:\n\
189433d6423SLionel Sambuc    drive status = 0x%02x (%s), sense key = 0x%02x (%s%s%s%s)\n\
190433d6423SLionel Sambuc    file no = %ld, block no = %ld, residual = %ld, block size = ",
191433d6423SLionel Sambuc    				tape, mtget.mt_dsreg,
192433d6423SLionel Sambuc    				mtget.mt_dsreg > 2 ? "?" :
193433d6423SLionel Sambuc    						dev_state[mtget.mt_dsreg],
194433d6423SLionel Sambuc 				mtget.mt_erreg,
195433d6423SLionel Sambuc 				mtget.mt_erreg & SENSE_EOF ? "EOF + " : "",
196433d6423SLionel Sambuc 				mtget.mt_erreg & SENSE_EOM ? "EOM + " : "",
197433d6423SLionel Sambuc 				mtget.mt_erreg & SENSE_ILI ? "ILI + " : "",
198433d6423SLionel Sambuc 				scsi_sense[mtget.mt_erreg & SENSE_KEY],
199433d6423SLionel Sambuc 				(long) mtget.mt_fileno,
200433d6423SLionel Sambuc 				(long) mtget.mt_blkno,
201433d6423SLionel Sambuc 				(long) mtget.mt_resid);
202*d0055759SDavid van Moolenbroek 			if (mtget.mt_blksiz == 0) printf("variable\n");
203*d0055759SDavid van Moolenbroek 			else printf("%d\n", mtget.mt_blksiz);
204433d6423SLionel Sambuc 		}
205433d6423SLionel Sambuc 	}
206433d6423SLionel Sambuc 	if (r < 0) {
207433d6423SLionel Sambuc 		if (errno == ENOTTY) {
208433d6423SLionel Sambuc 			fprintf(stderr, "mt: %s: command '%s' not supported\n",
209433d6423SLionel Sambuc 				tape, op->cmd);
210433d6423SLionel Sambuc 			exit(2);
211433d6423SLionel Sambuc 		}
212433d6423SLionel Sambuc 		fprintf(stderr, "mt: %s: %s\n", tape, strerror(errno));
213433d6423SLionel Sambuc 		exit(1);
214433d6423SLionel Sambuc 	}
215433d6423SLionel Sambuc 	exit(0);
216433d6423SLionel Sambuc }
217