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