1 /* $OpenBSD: mt.c,v 1.36 2013/11/12 04:36:02 deraadt 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 int _rmtopendev(char *path, int oflags, int dflags, char **realpath); 87 int _rmtmtioctop(int fd, struct mtop *com); 88 struct mtget *_rmtstatus(int fd); 89 void _rmtclose(void); 90 91 char *host = NULL; /* remote host (if any) */ 92 93 int 94 _rmtopendev(char *path, int oflags, int dflags, char **realpath) 95 { 96 #ifdef RMT 97 if (host) 98 return rmtopen(path, oflags); 99 #endif 100 return opendev(path, oflags, dflags, realpath); 101 } 102 103 int 104 _rmtmtioctop(int fd, struct mtop *com) 105 { 106 #ifdef RMT 107 if (host) 108 return rmtioctl(com->mt_op, com->mt_count); 109 #endif 110 return ioctl(fd, MTIOCTOP, com); 111 } 112 113 struct mtget * 114 _rmtstatus(int fd) 115 { 116 static struct mtget mt_status; 117 118 #ifdef RMT 119 if (host) 120 return rmtstatus(); 121 #endif 122 if (ioctl(fd, MTIOCGET, &mt_status) < 0) 123 err(2, "ioctl MTIOCGET"); 124 return &mt_status; 125 } 126 127 void 128 _rmtclose(void) 129 { 130 #ifdef RMT 131 if (host) 132 rmtclose(); 133 #endif 134 } 135 136 char *progname; 137 int eject = 0; 138 139 int 140 main(int argc, char *argv[]) 141 { 142 struct commands *comp; 143 struct mtop mt_com; 144 int ch, mtfd, flags, insert = 0; 145 char *p, *tape, *realtape, *opts; 146 size_t len; 147 148 if ((progname = strrchr(argv[0], '/'))) 149 progname++; 150 else 151 progname = argv[0]; 152 153 if (strcmp(progname, "eject") == 0) { 154 opts = "t"; 155 eject = 1; 156 tape = NULL; 157 } else { 158 opts = "f:"; 159 if ((tape = getenv("TAPE")) == NULL) 160 tape = _PATH_DEFTAPE; 161 } 162 163 while ((ch = getopt(argc, argv, opts)) != -1) { 164 switch (ch) { 165 case 't': 166 insert = 1; 167 break; 168 case 'f': 169 tape = optarg; 170 break; 171 default: 172 usage(); 173 } 174 } 175 argc -= optind; 176 argv += optind; 177 178 if (eject) { 179 if (argc == 1) { 180 tape = *argv++; 181 argc--; 182 } 183 if (argc != 0) 184 usage(); 185 } else if (argc < 1 || argc > 2) 186 usage(); 187 188 if (tape == NULL) 189 usage(); 190 191 if (strchr(tape, ':')) { 192 #ifdef RMT 193 host = tape; 194 tape = strchr(host, ':'); 195 *tape++ = '\0'; 196 if (rmthost(host) == 0) 197 exit(X_ABORT); 198 #else 199 err(1, "no remote support"); 200 #endif 201 } 202 203 if (eject) { 204 if (insert) 205 comp = &com[COM_RETEN]; 206 else 207 comp = &com[COM_EJECT]; 208 } else { 209 len = strlen(p = *argv++); 210 for (comp = com;; comp++) { 211 if (comp->c_name == NULL) 212 errx(1, "%s: unknown command", p); 213 if (strncmp(p, comp->c_name, len) == 0) 214 break; 215 } 216 } 217 218 flags = comp->c_ronly ? O_RDONLY : O_WRONLY | O_CREAT; 219 /* NOTE: OPENDEV_PART required since cd(4) devices go through here. */ 220 if ((mtfd = _rmtopendev(tape, flags, OPENDEV_PART, &realtape)) < 0) { 221 if (errno != 0) 222 warn("%s", host ? tape : realtape); 223 exit(2); 224 } 225 if (comp->c_code != MTNOP) { 226 mt_com.mt_op = comp->c_code; 227 if (*argv) { 228 mt_com.mt_count = strtol(*argv, &p, 10); 229 if (mt_com.mt_count < comp->c_mincount || *p) 230 errx(2, "%s: illegal count", *argv); 231 } 232 else 233 mt_com.mt_count = 1; 234 if (_rmtmtioctop(mtfd, &mt_com) < 0) { 235 if (eject) 236 err(2, "%s", tape); 237 else 238 err(2, "%s: %s", tape, comp->c_name); 239 } 240 } else { 241 status(_rmtstatus(mtfd)); 242 } 243 244 _rmtclose(); 245 246 exit(X_FINOK); 247 /* NOTREACHED */ 248 } 249 250 struct tape_desc { 251 short t_type; /* type of magtape device */ 252 char *t_name; /* printing name */ 253 char *t_dsbits; /* "drive status" register */ 254 char *t_erbits; /* "error" register */ 255 } tapes[] = { 256 #define SCSI_DS_BITS "\20\5WriteProtect\2Mounted" 257 { 0x7, "SCSI", SCSI_DS_BITS, "76543210" }, 258 { 0 } 259 }; 260 261 /* 262 * Interpret the status buffer returned 263 */ 264 void 265 status(struct mtget *bp) 266 { 267 struct tape_desc *mt; 268 269 for (mt = tapes;; mt++) { 270 if (mt->t_type == 0) { 271 (void)printf("%d: unknown tape drive type\n", 272 bp->mt_type); 273 return; 274 } 275 if (mt->t_type == bp->mt_type) 276 break; 277 } 278 (void)printf("%s tape drive, residual=%d\n", mt->t_name, bp->mt_resid); 279 printreg("ds", bp->mt_dsreg, mt->t_dsbits); 280 printreg("\ner", bp->mt_erreg, mt->t_erbits); 281 (void)putchar('\n'); 282 (void)printf("blocksize: %d (%d)\n", bp->mt_blksiz, bp->mt_mblksiz); 283 (void)printf("density: %d (%d)\n", bp->mt_density, bp->mt_mdensity); 284 } 285 286 /* 287 * Print a register a la the %b format of the kernel's printf. 288 */ 289 void 290 printreg(char *s, u_int v, char *bits) 291 { 292 int i, any = 0; 293 char c; 294 295 if (bits && *bits == 8) 296 printf("%s=%o", s, v); 297 else 298 printf("%s=%x", s, v); 299 if (!bits) 300 return; 301 bits++; 302 if (v && *bits) { 303 putchar('<'); 304 while ((i = *bits++)) { 305 if (v & (1 << (i-1))) { 306 if (any) 307 putchar(','); 308 any = 1; 309 for (; (c = *bits) > 32; bits++) 310 putchar(c); 311 } else 312 for (; *bits > 32; bits++) 313 ; 314 } 315 putchar('>'); 316 } 317 } 318 319 void 320 usage(void) 321 { 322 if (eject) 323 (void)fprintf(stderr, "usage: %s [-t] device\n", progname); 324 else 325 (void)fprintf(stderr, 326 "usage: %s [-f device] command [count]\n", progname); 327 exit(X_USAGE); 328 } 329