summaryrefslogtreecommitdiff
path: root/minix/commands/mt/mt.c
blob: bf96d1581e5d8782c334ff07c5ae6c7a9b97bdd9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/*	mt 1.3 - magnetic tape control			Author: Kees J. Bot
 *								4 Apr 1993
 */
#define nil	NULL
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE	1
#endif
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mtio.h>

/* Device status. */
#define DS_OK		0
#define DS_ERR		1
#define DS_EOF		2

/* SCSI Sense key bits. */
#define SENSE_KEY	0x0F	/* The key part. */
#define SENSE_ILI	0x20	/* Illegal block size. */
#define SENSE_EOM	0x40	/* End-of-media. */
#define SENSE_EOF	0x80	/* Filemark reached. */

/* Supported operations: */

typedef struct tape_operation {
	int	op;		/* Opcode for MTIOCTOP ioctl (if any). */
	char	*cmd;		/* Command name. */
	int	lim;		/* Limits on count. */
} tape_operation_t;

#define SELF	-1	/* Not a simple command, have to interpret. */
#define IGN	-1	/* Ignore count field (or accept anything.) */
#define NNG	 0	/* Nonnegative count field. */
#define POS	 1	/* Positive count field. */

tape_operation_t tapeops[] = {
	{ MTWEOF,  "eof",      POS },	/* Write EOF mark */
	{ MTWEOF,  "weof",     POS },	/* Same */
	{ MTFSF,   "fsf",      POS },	/* Forward Space File */
	{ MTFSR,   "fsr",      POS },	/* Forward Space Record */
	{ MTBSF,   "bsf",      NNG },	/* Backward Space File */
	{ MTBSR,   "bsr",      POS },	/* Backward Space Record */
	{ MTEOM,   "eom",      IGN },	/* To End-Of-Media */
	{ MTREW,   "rewind",   IGN },	/* Rewind */
	{ MTOFFL,  "offline",  IGN },	/* Rewind and take offline */
	{ MTOFFL,  "rewoffl",  IGN },	/* Same */
	{ SELF,	   "status",   IGN },	/* Tape Status */
	{ MTRETEN, "retension",IGN },	/* Retension the tape */
	{ MTERASE, "erase",    IGN },	/* Erase the tape */
	{ MTSETDNSTY,  "density",  NNG },	/* Select density */
	{ MTSETBSIZ,  "blksize",  NNG },	/* Select block size */
	{ MTSETBSIZ,  "blocksize",NNG },	/* Same */
};

#define arraysize(a)	(sizeof(a)/sizeof((a)[0]))
#define arraylimit(a)	((a) + arraysize(a))

/* From aha_scsi.c: */
char *dev_state[] = {
	"OK", "ERR", "EOF"
};

char *scsi_sense[] = {
	"NO SENSE INFO", "RECOVERED ERROR", "NOT READY", "MEDIUM ERROR",
	"HARDWARE ERROR", "ILLEGAL REQUEST", "UNIT ATTENTION", "DATA PROTECT",
	"BLANK CHECK", "VENDOR UNIQUE ERROR", "COPY ABORTED", "ABORTED COMMAND",
	"EQUAL", "VOLUME OVERFLOW", "MISCOMPARE", "SENSE RESERVED"
};

void usage(void)
{
	fprintf(stderr, "Usage: mt [-f device] command [count]\n");
	exit(1);
}

int main(int argc, char **argv)
{
	char *tape;
	char *cmd;
	int count= 1;
	int fd, r;
	tape_operation_t *op, *found;
	struct mtop mtop;
	struct mtget mtget;

	tape= getenv("TAPE");

	/* -f tape? */
	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'f') {
		tape= argv[1] + 2;

		if (*tape == 0) {
			if (--argc < 2) usage();
			argv++;
			tape= argv[1];
		}
		argc--;
		argv++;
	}

	if (argc != 2 && argc != 3) usage();

	if (argc == 3) {
		/* Check and convert the 'count' argument. */
		char *end;

		errno= 0;
		count= strtol(argv[2], &end, 0);
		if (*end != 0) usage();
		if (errno == ERANGE || (mtop.mt_count= count) != count) {
			fprintf(stderr, "mt: %s: count too large, overflow\n",
				argv[2]);
			exit(1);
		}
	}

	if (tape == nil) {
		fprintf(stderr,
			"mt: tape device not specified by -f or $TAPE\n");
		exit(1);
	}

	cmd= argv[1];
	if (strcmp(cmd, "rew") == 0) cmd= "rewind";	/* aha! */
	found= nil;

	/* Search for an operation that is unambiguously named. */
	for (op= tapeops; op < arraylimit(tapeops); op++) {
		if (strncmp(op->cmd, cmd, strlen(cmd)) == 0) {
			if (found != nil) {
				fprintf(stderr, "mt: %s: ambiguous\n", cmd);
				exit(1);
			}
			found= op;
		}
	}

	if ((op= found) == nil) {
		fprintf(stderr, "mt: unknown command '%s'\n", cmd);
		exit(1);
	}

	/* Check count. */
	switch (op->lim) {
	case NNG:
		if (count < 0) {
			fprintf(stderr, "mt %s: count may not be negative\n",
				op->cmd);
			exit(1);
		}
		break;
	case POS:
		if (count <= 0) {
			fprintf(stderr,
				"mt %s: count must be greater than zero\n",
				op->cmd);
			exit(1);
		}
		break;
	}

	if (strcmp(tape, "-") == 0) {
		fd= 0;
	} else
	if ((fd= open(tape, O_RDONLY)) < 0) {
		fprintf(stderr, "mt: %s: %s\n", tape, strerror(errno));
		exit(1);
	}

	if (op->op != SELF) {
		/* A simple tape operation. */

		mtop.mt_op= op->op;
		mtop.mt_count= count;
		r= ioctl(fd, MTIOCTOP, &mtop);
	} else
	if (strcmp(op->cmd, "status") == 0) {
		/* Get status information. */

		if ((r= ioctl(fd, MTIOCGET, &mtget)) == 0) {
			printf("\
SCSI tape drive %s:\n\
   drive status = 0x%02x (%s), sense key = 0x%02x (%s%s%s%s)\n\
   file no = %ld, block no = %ld, residual = %ld, block size = ",
   				tape, mtget.mt_dsreg,
   				mtget.mt_dsreg > 2 ? "?" :
   						dev_state[mtget.mt_dsreg],
				mtget.mt_erreg,
				mtget.mt_erreg & SENSE_EOF ? "EOF + " : "",
				mtget.mt_erreg & SENSE_EOM ? "EOM + " : "",
				mtget.mt_erreg & SENSE_ILI ? "ILI + " : "",
				scsi_sense[mtget.mt_erreg & SENSE_KEY],
				(long) mtget.mt_fileno,
				(long) mtget.mt_blkno,
				(long) mtget.mt_resid);
			if (mtget.mt_blksiz == 0) printf("variable\n");
			else printf("%d\n", mtget.mt_blksiz);
		}
	}
	if (r < 0) {
		if (errno == ENOTTY) {
			fprintf(stderr, "mt: %s: command '%s' not supported\n",
				tape, op->cmd);
			exit(2);
		}
		fprintf(stderr, "mt: %s: %s\n", tape, strerror(errno));
		exit(1);
	}
	exit(0);
}