<sys/ioccom.h>, <sys/ioctl.h>
[minix3.git] / commands / mt / mt.c
blobc107450fafa59afbe999d99534f97c6d76a1793b
1 /* mt 1.3 - magnetic tape control Author: Kees J. Bot
2 * 4 Apr 1993
3 */
4 #define nil NULL
5 #ifndef _POSIX_SOURCE
6 #define _POSIX_SOURCE 1
7 #endif
8 #include <sys/types.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <errno.h>
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <string.h>
15 #include <sys/ioctl.h>
16 #include <sys/mtio.h>
18 /* Device status. */
19 #define DS_OK 0
20 #define DS_ERR 1
21 #define DS_EOF 2
23 /* SCSI Sense key bits. */
24 #define SENSE_KEY 0x0F /* The key part. */
25 #define SENSE_ILI 0x20 /* Illegal block size. */
26 #define SENSE_EOM 0x40 /* End-of-media. */
27 #define SENSE_EOF 0x80 /* Filemark reached. */
29 /* Supported operations: */
31 typedef struct tape_operation {
32 int op; /* Opcode for MTIOCTOP ioctl (if any). */
33 char *cmd; /* Command name. */
34 int lim; /* Limits on count. */
35 } tape_operation_t;
37 #define SELF -1 /* Not a simple command, have to interpret. */
38 #define IGN -1 /* Ignore count field (or accept anything.) */
39 #define NNG 0 /* Nonnegative count field. */
40 #define POS 1 /* Positive count field. */
42 tape_operation_t tapeops[] = {
43 { MTWEOF, "eof", POS }, /* Write EOF mark */
44 { MTWEOF, "weof", POS }, /* Same */
45 { MTFSF, "fsf", POS }, /* Forward Space File */
46 { MTFSR, "fsr", POS }, /* Forward Space Record */
47 { MTBSF, "bsf", NNG }, /* Backward Space File */
48 { MTBSR, "bsr", POS }, /* Backward Space Record */
49 { MTEOM, "eom", IGN }, /* To End-Of-Media */
50 { MTREW, "rewind", IGN }, /* Rewind */
51 { MTOFFL, "offline", IGN }, /* Rewind and take offline */
52 { MTOFFL, "rewoffl", IGN }, /* Same */
53 { SELF, "status", IGN }, /* Tape Status */
54 { MTRETEN, "retension",IGN }, /* Retension the tape */
55 { MTERASE, "erase", IGN }, /* Erase the tape */
56 { MTSETDNSTY, "density", NNG }, /* Select density */
57 { MTSETBSIZ, "blksize", NNG }, /* Select block size */
58 { MTSETBSIZ, "blocksize",NNG }, /* Same */
61 #define arraysize(a) (sizeof(a)/sizeof((a)[0]))
62 #define arraylimit(a) ((a) + arraysize(a))
64 /* From aha_scsi.c: */
65 char *dev_state[] = {
66 "OK", "ERR", "EOF"
69 char *scsi_sense[] = {
70 "NO SENSE INFO", "RECOVERED ERROR", "NOT READY", "MEDIUM ERROR",
71 "HARDWARE ERROR", "ILLEGAL REQUEST", "UNIT ATTENTION", "DATA PROTECT",
72 "BLANK CHECK", "VENDOR UNIQUE ERROR", "COPY ABORTED", "ABORTED COMMAND",
73 "EQUAL", "VOLUME OVERFLOW", "MISCOMPARE", "SENSE RESERVED"
76 void usage(void)
78 fprintf(stderr, "Usage: mt [-f device] command [count]\n");
79 exit(1);
82 int main(int argc, char **argv)
84 char *tape;
85 char *cmd;
86 int count= 1;
87 int fd, r;
88 tape_operation_t *op, *found;
89 struct mtop mtop;
90 struct mtget mtget;
92 tape= getenv("TAPE");
94 /* -f tape? */
95 if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'f') {
96 tape= argv[1] + 2;
98 if (*tape == 0) {
99 if (--argc < 2) usage();
100 argv++;
101 tape= argv[1];
103 argc--;
104 argv++;
107 if (argc != 2 && argc != 3) usage();
109 if (argc == 3) {
110 /* Check and convert the 'count' argument. */
111 char *end;
113 errno= 0;
114 count= strtol(argv[2], &end, 0);
115 if (*end != 0) usage();
116 if (errno == ERANGE || (mtop.mt_count= count) != count) {
117 fprintf(stderr, "mt: %s: count too large, overflow\n",
118 argv[2]);
119 exit(1);
123 if (tape == nil) {
124 fprintf(stderr,
125 "mt: tape device not specified by -f or $TAPE\n");
126 exit(1);
129 cmd= argv[1];
130 if (strcmp(cmd, "rew") == 0) cmd= "rewind"; /* aha! */
131 found= nil;
133 /* Search for an operation that is unambiguously named. */
134 for (op= tapeops; op < arraylimit(tapeops); op++) {
135 if (strncmp(op->cmd, cmd, strlen(cmd)) == 0) {
136 if (found != nil) {
137 fprintf(stderr, "mt: %s: ambiguous\n", cmd);
138 exit(1);
140 found= op;
144 if ((op= found) == nil) {
145 fprintf(stderr, "mt: unknown command '%s'\n", cmd);
146 exit(1);
149 /* Check count. */
150 switch (op->lim) {
151 case NNG:
152 if (count < 0) {
153 fprintf(stderr, "mt %s: count may not be negative\n",
154 op->cmd);
155 exit(1);
157 break;
158 case POS:
159 if (count <= 0) {
160 fprintf(stderr,
161 "mt %s: count must be greater than zero\n",
162 op->cmd);
163 exit(1);
165 break;
168 if (strcmp(tape, "-") == 0) {
169 fd= 0;
170 } else
171 if ((fd= open(tape, O_RDONLY)) < 0) {
172 fprintf(stderr, "mt: %s: %s\n", tape, strerror(errno));
173 exit(1);
176 if (op->op != SELF) {
177 /* A simple tape operation. */
179 mtop.mt_op= op->op;
180 mtop.mt_count= count;
181 r= ioctl(fd, MTIOCTOP, &mtop);
182 } else
183 if (strcmp(op->cmd, "status") == 0) {
184 /* Get status information. */
186 if ((r= ioctl(fd, MTIOCGET, &mtget)) == 0) {
187 printf("\
188 SCSI tape drive %s:\n\
189 drive status = 0x%02x (%s), sense key = 0x%02x (%s%s%s%s)\n\
190 file no = %ld, block no = %ld, residual = %ld, block size = ",
191 tape, mtget.mt_dsreg,
192 mtget.mt_dsreg > 2 ? "?" :
193 dev_state[mtget.mt_dsreg],
194 mtget.mt_erreg,
195 mtget.mt_erreg & SENSE_EOF ? "EOF + " : "",
196 mtget.mt_erreg & SENSE_EOM ? "EOM + " : "",
197 mtget.mt_erreg & SENSE_ILI ? "ILI + " : "",
198 scsi_sense[mtget.mt_erreg & SENSE_KEY],
199 (long) mtget.mt_fileno,
200 (long) mtget.mt_blkno,
201 (long) mtget.mt_resid);
202 printf(mtget.mt_blksiz == 0 ? "variable\n" : "%d\n",
203 mtget.mt_blksiz);
206 if (r < 0) {
207 if (errno == ENOTTY) {
208 fprintf(stderr, "mt: %s: command '%s' not supported\n",
209 tape, op->cmd);
210 exit(2);
212 fprintf(stderr, "mt: %s: %s\n", tape, strerror(errno));
213 exit(1);
215 exit(0);