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