1 /* mt 1.3 - magnetic tape control Author: Kees J. Bot
6 #define _POSIX_SOURCE 1
15 #include <sys/ioctl.h>
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. */
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: */
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"
78 fprintf(stderr
, "Usage: mt [-f device] command [count]\n");
82 int main(int argc
, char **argv
)
88 tape_operation_t
*op
, *found
;
95 if (argc
> 1 && argv
[1][0] == '-' && argv
[1][1] == 'f') {
99 if (--argc
< 2) usage();
107 if (argc
!= 2 && argc
!= 3) usage();
110 /* Check and convert the 'count' argument. */
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",
125 "mt: tape device not specified by -f or $TAPE\n");
130 if (strcmp(cmd
, "rew") == 0) cmd
= "rewind"; /* aha! */
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) {
137 fprintf(stderr
, "mt: %s: ambiguous\n", cmd
);
144 if ((op
= found
) == nil
) {
145 fprintf(stderr
, "mt: unknown command '%s'\n", cmd
);
153 fprintf(stderr
, "mt %s: count may not be negative\n",
161 "mt %s: count must be greater than zero\n",
168 if (strcmp(tape
, "-") == 0) {
171 if ((fd
= open(tape
, O_RDONLY
)) < 0) {
172 fprintf(stderr
, "mt: %s: %s\n", tape
, strerror(errno
));
176 if (op
->op
!= SELF
) {
177 /* A simple tape operation. */
180 mtop
.mt_count
= count
;
181 r
= ioctl(fd
, MTIOCTOP
, &mtop
);
183 if (strcmp(op
->cmd
, "status") == 0) {
184 /* Get status information. */
186 if ((r
= ioctl(fd
, MTIOCGET
, &mtget
)) == 0) {
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
],
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 if (mtget
.mt_blksiz
== 0) printf("variable\n");
203 else printf("%d\n", mtget
.mt_blksiz
);
207 if (errno
== ENOTTY
) {
208 fprintf(stderr
, "mt: %s: command '%s' not supported\n",
212 fprintf(stderr
, "mt: %s: %s\n", tape
, strerror(errno
));