1 /* $OpenBSD: mt.c,v 1.35 2011/05/05 19:51:48 krw Exp $ */ 2 /* $NetBSD: mt.c,v 1.14.2.1 1996/05/27 15:12:11 mrg Exp $ */ 3 4 /* 5 * Copyright (c) 1980, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * mt -- 35 * magnetic tape manipulation program 36 */ 37 #include <sys/types.h> 38 #include <sys/ioctl.h> 39 #include <sys/mtio.h> 40 #include <sys/stat.h> 41 #include <sys/disklabel.h> 42 43 #include <ctype.h> 44 #include <err.h> 45 #include <errno.h> 46 #include <fcntl.h> 47 #include <paths.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 #include <util.h> 53 54 #include "mt.h" 55 56 struct commands { 57 char *c_name; 58 int c_code; 59 int c_ronly; 60 int c_mincount; 61 } com[] = { 62 { "blocksize", MTSETBSIZ, 1, 0 }, 63 { "bsf", MTBSF, 1, 1 }, 64 { "bsr", MTBSR, 1, 1 }, 65 { "density", MTSETDNSTY, 1, 1 }, 66 { "eof", MTWEOF, 0, 1 }, 67 { "eom", MTEOM, 1, 1 }, 68 { "erase", MTERASE, 0, 1 }, 69 { "fsf", MTFSF, 1, 1 }, 70 { "fsr", MTFSR, 1, 1 }, 71 { "offline", MTOFFL, 1, 1 }, 72 #define COM_EJECT 9 /* element in the above array */ 73 { "rewind", MTREW, 1, 1 }, 74 { "rewoffl", MTOFFL, 1, 1 }, 75 { "status", MTNOP, 1, 1 }, 76 { "retension", MTRETEN, 1, 1 }, 77 #define COM_RETEN 13 /* element in the above array */ 78 { "weof", MTWEOF, 0, 1 }, 79 { NULL } 80 }; 81 82 void printreg(char *, u_int, char *); 83 void status(struct mtget *); 84 void usage(void); 85 86 char *host = NULL; /* remote host (if any) */ 87 88 int 89 _rmtopendev(char *path, int oflags, int dflags, char **realpath) 90 { 91 #ifdef RMT 92 if (host) 93 return rmtopen(path, oflags); 94 #endif 95 return opendev(path, oflags, dflags, realpath); 96 } 97 98 int 99 _rmtmtioctop(int fd, struct mtop *com) 100 { 101 #ifdef RMT 102 if (host) 103 return rmtioctl(com->mt_op, com->mt_count); 104 #endif 105 return ioctl(fd, MTIOCTOP, com); 106 } 107 108 struct mtget * 109 _rmtstatus(int fd) 110 { 111 static struct mtget mt_status; 112 113 #ifdef RMT 114 if (host) 115 return rmtstatus(); 116 #endif 117 if (ioctl(fd, MTIOCGET, &mt_status) < 0) 118 err(2, "ioctl MTIOCGET"); 119 return &mt_status; 120 } 121 122 void 123 _rmtclose(void) 124 { 125 #ifdef RMT 126 if (host) 127 rmtclose(); 128 #endif 129 } 130 131 char *progname; 132 int eject = 0; 133 134 int 135 main(int argc, char *argv[]) 136 { 137 struct commands *comp; 138 struct mtop mt_com; 139 int ch, mtfd, flags, insert = 0; 140 char *p, *tape, *realtape, *opts; 141 size_t len; 142 143 if ((progname = strrchr(argv[0], '/'))) 144 progname++; 145 else 146 progname = argv[0]; 147 148 if (strcmp(progname, "eject") == 0) { 149 opts = "t"; 150 eject = 1; 151 tape = NULL; 152 } else { 153 opts = "f:"; 154 if ((tape = getenv("TAPE")) == NULL) 155 tape = _PATH_DEFTAPE; 156 } 157 158 while ((ch = getopt(argc, argv, opts)) != -1) { 159 switch (ch) { 160 case 't': 161 insert = 1; 162 break; 163 case 'f': 164 tape = optarg; 165 break; 166 default: 167 usage(); 168 } 169 } 170 argc -= optind; 171 argv += optind; 172 173 if (eject) { 174 if (argc == 1) { 175 tape = *argv++; 176 argc--; 177 } 178 if (argc != 0) 179 usage(); 180 } else if (argc < 1 || argc > 2) 181 usage(); 182 183 if (tape == NULL) 184 usage(); 185 186 if (strchr(tape, ':')) { 187 #ifdef RMT 188 host = tape; 189 tape = strchr(host, ':'); 190 *tape++ = '\0'; 191 if (rmthost(host) == 0) 192 exit(X_ABORT); 193 #else 194 err(1, "no remote support"); 195 #endif 196 } 197 198 if (eject) { 199 if (insert) 200 comp = &com[COM_RETEN]; 201 else 202 comp = &com[COM_EJECT]; 203 } else { 204 len = strlen(p = *argv++); 205 for (comp = com;; comp++) { 206 if (comp->c_name == NULL) 207 errx(1, "%s: unknown command", p); 208 if (strncmp(p, comp->c_name, len) == 0) 209 break; 210 } 211 } 212 213 flags = comp->c_ronly ? O_RDONLY : O_WRONLY | O_CREAT; 214 /* NOTE: OPENDEV_PART required since cd(4) devices go through here. */ 215 if ((mtfd = _rmtopendev(tape, flags, OPENDEV_PART, &realtape)) < 0) { 216 if (errno != 0) 217 warn("%s", host ? tape : realtape); 218 exit(2); 219 } 220 if (comp->c_code != MTNOP) { 221 mt_com.mt_op = comp->c_code; 222 if (*argv) { 223 mt_com.mt_count = strtol(*argv, &p, 10); 224 if (mt_com.mt_count < comp->c_mincount || *p) 225 errx(2, "%s: illegal count", *argv); 226 } 227 else 228 mt_com.mt_count = 1; 229 if (_rmtmtioctop(mtfd, &mt_com) < 0) { 230 if (eject) 231 err(2, "%s", tape); 232 else 233 err(2, "%s: %s", tape, comp->c_name); 234 } 235 } else { 236 status(_rmtstatus(mtfd)); 237 } 238 239 _rmtclose(); 240 241 exit(X_FINOK); 242 /* NOTREACHED */ 243 } 244 245 struct tape_desc { 246 short t_type; /* type of magtape device */ 247 char *t_name; /* printing name */ 248 char *t_dsbits; /* "drive status" register */ 249 char *t_erbits; /* "error" register */ 250 } tapes[] = { 251 #define SCSI_DS_BITS "\20\5WriteProtect\2Mounted" 252 { 0x7, "SCSI", SCSI_DS_BITS, "76543210" }, 253 { 0 } 254 }; 255 256 /* 257 * Interpret the status buffer returned 258 */ 259 void 260 status(struct mtget *bp) 261 { 262 struct tape_desc *mt; 263 264 for (mt = tapes;; mt++) { 265 if (mt->t_type == 0) { 266 (void)printf("%d: unknown tape drive type\n", 267 bp->mt_type); 268 return; 269 } 270 if (mt->t_type == bp->mt_type) 271 break; 272 } 273 (void)printf("%s tape drive, residual=%d\n", mt->t_name, bp->mt_resid); 274 printreg("ds", bp->mt_dsreg, mt->t_dsbits); 275 printreg("\ner", bp->mt_erreg, mt->t_erbits); 276 (void)putchar('\n'); 277 (void)printf("blocksize: %d (%d)\n", bp->mt_blksiz, bp->mt_mblksiz); 278 (void)printf("density: %d (%d)\n", bp->mt_density, bp->mt_mdensity); 279 } 280 281 /* 282 * Print a register a la the %b format of the kernel's printf. 283 */ 284 void 285 printreg(char *s, u_int v, char *bits) 286 { 287 int i, any = 0; 288 char c; 289 290 if (bits && *bits == 8) 291 printf("%s=%o", s, v); 292 else 293 printf("%s=%x", s, v); 294 if (!bits) 295 return; 296 bits++; 297 if (v && *bits) { 298 putchar('<'); 299 while ((i = *bits++)) { 300 if (v & (1 << (i-1))) { 301 if (any) 302 putchar(','); 303 any = 1; 304 for (; (c = *bits) > 32; bits++) 305 putchar(c); 306 } else 307 for (; *bits > 32; bits++) 308 ; 309 } 310 putchar('>'); 311 } 312 } 313 314 void 315 usage(void) 316 { 317 if (eject) 318 (void)fprintf(stderr, "usage: %s [-t] device\n", progname); 319 else 320 (void)fprintf(stderr, 321 "usage: %s [-f device] command [count]\n", progname); 322 exit(X_USAGE); 323 } 324