1 /* 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static char copyright[] = 36 "@(#) Copyright (c) 1980, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 static char sccsid[] = "@(#)mt.c 8.2 (Berkeley) 5/4/95"; 42 #endif /* not lint */ 43 44 /* 45 * mt -- 46 * magnetic tape manipulation program 47 */ 48 #include <sys/types.h> 49 #include <sys/ioctl.h> 50 #include <sys/mtio.h> 51 52 #include <ctype.h> 53 #include <errno.h> 54 #include <fcntl.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <unistd.h> 59 60 /* the appropriate sections of <sys/mtio.h> are also #ifdef'd for FreeBSD */ 61 #if defined(__FreeBSD__) 62 /* c_flags */ 63 #define NEED_2ARGS 0x01 64 #define ZERO_ALLOWED 0x02 65 #define IS_DENSITY 0x04 66 #define DISABLE_THIS 0x08 67 #endif /* defined(__FreeBSD__) */ 68 69 struct commands { 70 char *c_name; 71 int c_code; 72 int c_ronly; 73 #if defined(__FreeBSD__) 74 int c_flags; 75 #endif /* defined(__FreeBSD__) */ 76 } com[] = { 77 { "bsf", MTBSF, 1 }, 78 { "bsr", MTBSR, 1 }, 79 #if defined(__FreeBSD__) 80 /* XXX FreeBSD considered "eof" dangerous, since it's being 81 confused with "eom" (and is an alias for "weof" anyway) */ 82 { "eof", MTWEOF, 0, DISABLE_THIS }, 83 #else 84 { "eof", MTWEOF, 0 }, 85 #endif 86 { "fsf", MTFSF, 1 }, 87 { "fsr", MTFSR, 1 }, 88 { "offline", MTOFFL, 1 }, 89 { "rewind", MTREW, 1 }, 90 { "rewoffl", MTOFFL, 1 }, 91 { "status", MTNOP, 1 }, 92 { "weof", MTWEOF, 0 }, 93 #if defined(__FreeBSD__) 94 { "erase", MTERASE, 0 }, 95 { "blocksize", MTSETBSIZ, 0, NEED_2ARGS|ZERO_ALLOWED }, 96 { "density", MTSETDNSTY, 0, NEED_2ARGS|ZERO_ALLOWED|IS_DENSITY }, 97 { "eom", MTEOD, 1 }, 98 { "comp", MTCOMP, 0, NEED_2ARGS|ZERO_ALLOWED }, 99 { "retension", MTRETENS, 1 }, 100 #endif /* defined(__FreeBSD__) */ 101 { NULL } 102 }; 103 104 void err __P((const char *, ...)); 105 void printreg __P((char *, u_int, char *)); 106 void status __P((struct mtget *)); 107 void usage __P((void)); 108 #if defined (__FreeBSD__) 109 void st_status (struct mtget *); 110 int stringtodens (const char *s); 111 const char *denstostring (int d); 112 void warn_eof __P((void)); 113 #endif /* defined (__FreeBSD__) */ 114 115 int 116 main(argc, argv) 117 int argc; 118 char *argv[]; 119 { 120 register struct commands *comp; 121 struct mtget mt_status; 122 struct mtop mt_com; 123 int ch, len, mtfd; 124 char *p, *tape; 125 126 if ((tape = getenv("TAPE")) == NULL) 127 tape = DEFTAPE; 128 129 while ((ch = getopt(argc, argv, "f:t:")) != -1) 130 switch(ch) { 131 case 'f': 132 case 't': 133 tape = optarg; 134 break; 135 case '?': 136 default: 137 usage(); 138 } 139 argc -= optind; 140 argv += optind; 141 142 if (argc < 1 || argc > 2) 143 usage(); 144 145 len = strlen(p = *argv++); 146 for (comp = com;; comp++) { 147 if (comp->c_name == NULL) 148 err("%s: unknown command", p); 149 if (strncmp(p, comp->c_name, len) == 0) 150 break; 151 } 152 #if defined(__FreeBSD__) 153 if((comp->c_flags & NEED_2ARGS) && argc != 2) 154 usage(); 155 if(comp->c_flags & DISABLE_THIS) { 156 warn_eof(); 157 } 158 #endif /* defined(__FreeBSD__) */ 159 if ((mtfd = open(tape, comp->c_ronly ? O_RDONLY : O_RDWR)) < 0) 160 err("%s: %s", tape, strerror(errno)); 161 if (comp->c_code != MTNOP) { 162 mt_com.mt_op = comp->c_code; 163 if (*argv) { 164 #if defined (__FreeBSD__) 165 if (!isdigit(**argv) && 166 comp->c_flags & IS_DENSITY) { 167 const char *dcanon; 168 mt_com.mt_count = stringtodens(*argv); 169 if (mt_com.mt_count == 0) 170 err("%s: unknown density", *argv); 171 dcanon = denstostring(mt_com.mt_count); 172 if (strcmp(dcanon, *argv) != 0) 173 printf( 174 "Using \"%s\" as an alias for %s\n", 175 *argv, dcanon); 176 p = ""; 177 } else 178 /* allow for hex numbers; useful for density */ 179 mt_com.mt_count = strtol(*argv, &p, 0); 180 #else 181 mt_com.mt_count = strtol(*argv, &p, 10); 182 #endif /* defined(__FreeBSD__) */ 183 if (mt_com.mt_count <= 184 #if defined (__FreeBSD__) 185 ((comp->c_flags & ZERO_ALLOWED)? -1: 0) 186 #else 187 0 188 #endif /* defined (__FreeBSD__) */ 189 || *p) 190 err("%s: illegal count", *argv); 191 } 192 else 193 mt_com.mt_count = 1; 194 if (ioctl(mtfd, MTIOCTOP, &mt_com) < 0) 195 err("%s: %s: %s", tape, comp->c_name, strerror(errno)); 196 } else { 197 if (ioctl(mtfd, MTIOCGET, &mt_status) < 0) 198 err("%s", strerror(errno)); 199 status(&mt_status); 200 } 201 exit (0); 202 /* NOTREACHED */ 203 } 204 205 #ifdef vax 206 #include <vax/mba/mtreg.h> 207 #include <vax/mba/htreg.h> 208 209 #include <vax/uba/utreg.h> 210 #include <vax/uba/tmreg.h> 211 #undef b_repcnt /* argh */ 212 #include <vax/uba/tsreg.h> 213 #endif 214 215 #ifdef sun 216 #include <sundev/tmreg.h> 217 #include <sundev/arreg.h> 218 #endif 219 220 #ifdef tahoe 221 #include <tahoe/vba/cyreg.h> 222 #endif 223 224 #ifdef __FreeBSD__ 225 #include <machine/wtio.h> 226 #endif 227 228 struct tape_desc { 229 short t_type; /* type of magtape device */ 230 char *t_name; /* printing name */ 231 char *t_dsbits; /* "drive status" register */ 232 char *t_erbits; /* "error" register */ 233 } tapes[] = { 234 #ifdef vax 235 { MT_ISTS, "ts11", 0, TSXS0_BITS }, 236 { MT_ISHT, "tm03", HTDS_BITS, HTER_BITS }, 237 { MT_ISTM, "tm11", 0, TMER_BITS }, 238 { MT_ISMT, "tu78", MTDS_BITS, 0 }, 239 { MT_ISUT, "tu45", UTDS_BITS, UTER_BITS }, 240 #endif 241 #ifdef sun 242 { MT_ISCPC, "TapeMaster", TMS_BITS, 0 }, 243 { MT_ISAR, "Archive", ARCH_CTRL_BITS, ARCH_BITS }, 244 #endif 245 #ifdef tahoe 246 { MT_ISCY, "cipher", CYS_BITS, CYCW_BITS }, 247 #endif 248 #if defined (__FreeBSD__) 249 /* 250 * XXX This is weird. The st driver reports the tape drive 251 * as 0x7 (MT_ISAR - Sun/Archive compatible); the wt driver 252 * either reports MT_ISVIPER1 for an Archive tape, or 0x11 253 * (MT_ISMFOUR) for other tapes. 254 * XXX for the wt driver, rely on it behaving like a "standard" 255 * magtape driver. 256 */ 257 { MT_ISAR, "SCSI tape drive", 0, 0 }, 258 { MT_ISVIPER1, "Archive Viper", WTDS_BITS, WTER_BITS }, 259 { MT_ISMFOUR, "Wangtek", WTDS_BITS, WTER_BITS }, 260 #endif /* defined (__FreeBSD__) */ 261 { 0 } 262 }; 263 264 /* 265 * Interpret the status buffer returned 266 */ 267 void 268 status(bp) 269 register struct mtget *bp; 270 { 271 register struct tape_desc *mt; 272 273 for (mt = tapes;; mt++) { 274 if (mt->t_type == 0) { 275 (void)printf("%d: unknown tape drive type\n", 276 bp->mt_type); 277 return; 278 } 279 if (mt->t_type == bp->mt_type) 280 break; 281 } 282 #if defined (__FreeBSD__) 283 if(mt->t_type == MT_ISAR) 284 st_status(bp); 285 else { 286 #endif /* defined (__FreeBSD__) */ 287 (void)printf("%s tape drive, residual=%d\n", mt->t_name, bp->mt_resid); 288 printreg("ds", (unsigned short)bp->mt_dsreg, mt->t_dsbits); 289 printreg("\ner", (unsigned short)bp->mt_erreg, mt->t_erbits); 290 (void)putchar('\n'); 291 #if defined (__FreeBSD__) 292 } 293 #endif /* defined (__FreeBSD__) */ 294 } 295 296 /* 297 * Print a register a la the %b format of the kernel's printf. 298 */ 299 void 300 printreg(s, v, bits) 301 char *s; 302 register u_int v; 303 register char *bits; 304 { 305 register int i, any = 0; 306 register char c; 307 308 if (bits && *bits == 8) 309 printf("%s=%o", s, v); 310 else 311 printf("%s=%x", s, v); 312 if (!bits) 313 return; 314 bits++; 315 if (v && bits) { 316 putchar('<'); 317 while (i = *bits++) { 318 if (v & (1 << (i-1))) { 319 if (any) 320 putchar(','); 321 any = 1; 322 for (; (c = *bits) > 32; bits++) 323 putchar(c); 324 } else 325 for (; *bits > 32; bits++) 326 ; 327 } 328 putchar('>'); 329 } 330 } 331 332 void 333 usage() 334 { 335 (void)fprintf(stderr, "usage: mt [-f device] command [ count ]\n"); 336 exit(1); 337 } 338 339 #if __STDC__ 340 #include <stdarg.h> 341 #else 342 #include <varargs.h> 343 #endif 344 345 void 346 #if __STDC__ 347 err(const char *fmt, ...) 348 #else 349 err(fmt, va_alist) 350 char *fmt; 351 va_dcl 352 #endif 353 { 354 va_list ap; 355 #if __STDC__ 356 va_start(ap, fmt); 357 #else 358 va_start(ap); 359 #endif 360 (void)fprintf(stderr, "mt: "); 361 (void)vfprintf(stderr, fmt, ap); 362 va_end(ap); 363 (void)fprintf(stderr, "\n"); 364 exit(1); 365 /* NOTREACHED */ 366 } 367 368 #if defined (__FreeBSD__) 369 370 struct densities { 371 int dens; 372 const char *name; 373 } dens [] = { 374 { 0x1, "X3.22-1983" }, 375 { 0x2, "X3.39-1986" }, 376 { 0x3, "X3.54-1986" }, 377 { 0x5, "X3.136-1986" }, 378 { 0x6, "X3.157-1987" }, 379 { 0x7, "X3.116-1986" }, 380 { 0x8, "X3.158-1986" }, 381 { 0x9, "X3B5/87-099" }, 382 { 0xA, "X3B5/86-199" }, 383 { 0xB, "X3.56-1986" }, 384 { 0xC, "HI-TC1" }, 385 { 0xD, "HI-TC2" }, 386 { 0xF, "QIC-120" }, 387 { 0x10, "QIC-150" }, 388 { 0x11, "QIC-320" }, 389 { 0x12, "QIC-1350" }, 390 { 0x13, "X3B5/88-185A" }, 391 { 0x14, "X3.202-1991" }, 392 { 0x15, "ECMA TC17" }, 393 { 0x16, "X3.193-1990" }, 394 { 0x17, "X3B5/91-174" }, 395 { 0, 0 } 396 }; 397 398 const char * 399 denstostring(int d) 400 { 401 static char buf[20]; 402 struct densities *sd; 403 404 for (sd = dens; sd->dens; sd++) 405 if (sd->dens == d) 406 break; 407 if (sd->dens == 0) { 408 sprintf(buf, "0x%02x", d); 409 return buf; 410 } else 411 return sd->name; 412 } 413 414 int 415 stringtodens(const char *s) 416 { 417 struct densities *sd; 418 size_t l = strlen(s); 419 420 for (sd = dens; sd->dens; sd++) 421 if (strncasecmp(sd->name, s, l) == 0) 422 break; 423 return sd->dens; 424 } 425 426 427 const char * 428 getblksiz(int bs) 429 { 430 static char buf[25]; 431 if (bs == 0) 432 return "variable"; 433 else { 434 sprintf(buf, "= %d bytes", bs); 435 return buf; 436 } 437 } 438 439 440 void 441 st_status(struct mtget *bp) 442 { 443 printf("Present Mode: Density = %-12s Blocksize %s\n", 444 denstostring(bp->mt_density), getblksiz(bp->mt_blksiz)); 445 printf("---------available modes---------\n"); 446 printf("Mode 0: Density = %-12s Blocksize %s\n", 447 denstostring(bp->mt_density0), getblksiz(bp->mt_blksiz0)); 448 printf("Mode 1: Density = %-12s Blocksize %s\n", 449 denstostring(bp->mt_density1), getblksiz(bp->mt_blksiz1)); 450 printf("Mode 2: Density = %-12s Blocksize %s\n", 451 denstostring(bp->mt_density2), getblksiz(bp->mt_blksiz2)); 452 printf("Mode 3: Density = %-12s Blocksize %s\n", 453 denstostring(bp->mt_density3), getblksiz(bp->mt_blksiz3)); 454 } 455 456 void 457 warn_eof(void) 458 { 459 fprintf(stderr, 460 "The \"eof\" command has been disabled.\n" 461 "Use \"weof\" if you really want to write end-of-file marks,\n" 462 "or \"eom\" if you rather want to skip to the end of " 463 "recorded medium.\n"); 464 exit(1); 465 } 466 467 #endif /* defined (__FreeBSD__) */ 468