1 /* $OpenBSD: mt.c,v 1.41 2019/06/28 13:34:59 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 #include <limits.h> 54 55 #include "mt.h" 56 57 struct commands { 58 char *c_name; 59 int c_code; 60 int c_ronly; 61 int c_mincount; 62 } com[] = { 63 { "blocksize", MTSETBSIZ, 1, 0 }, 64 { "bsf", MTBSF, 1, 1 }, 65 { "bsr", MTBSR, 1, 1 }, 66 { "density", MTSETDNSTY, 1, 1 }, 67 { "eof", MTWEOF, 0, 1 }, 68 { "eom", MTEOM, 1, 1 }, 69 { "erase", MTERASE, 0, 1 }, 70 { "fsf", MTFSF, 1, 1 }, 71 { "fsr", MTFSR, 1, 1 }, 72 { "offline", MTOFFL, 1, 1 }, 73 #define COM_EJECT 9 /* element in the above array */ 74 { "rewind", MTREW, 1, 1 }, 75 { "rewoffl", MTOFFL, 1, 1 }, 76 { "status", MTNOP, 1, 1 }, 77 { "retension", MTRETEN, 1, 1 }, 78 #define COM_RETEN 13 /* element in the above array */ 79 { "weof", MTWEOF, 0, 1 }, 80 { NULL } 81 }; 82 83 void printreg(char *, u_int, char *); 84 void status(struct mtget *); 85 void usage(void); 86 87 int _rmtopendev(char *path, int oflags, int dflags, char **realp); 88 int _rmtmtioctop(int fd, struct mtop *cmd); 89 struct mtget *_rmtstatus(int fd); 90 void _rmtclose(void); 91 92 extern char *__progname; 93 94 char *host = NULL; /* remote host (if any) */ 95 96 int 97 _rmtopendev(char *path, int oflags, int dflags, char **realp) 98 { 99 #ifdef RMT 100 if (host) 101 return rmtopen(path, oflags); 102 #endif 103 return opendev(path, oflags, dflags, realp); 104 } 105 106 int 107 _rmtmtioctop(int fd, struct mtop *cmd) 108 { 109 #ifdef RMT 110 if (host) 111 return rmtioctl(cmd->mt_op, cmd->mt_count); 112 #endif 113 return ioctl(fd, MTIOCTOP, cmd); 114 } 115 116 struct mtget * 117 _rmtstatus(int fd) 118 { 119 static struct mtget mt_status; 120 121 #ifdef RMT 122 if (host) 123 return rmtstatus(); 124 #endif 125 if (ioctl(fd, MTIOCGET, &mt_status) == -1) 126 err(2, "ioctl MTIOCGET"); 127 return &mt_status; 128 } 129 130 void 131 _rmtclose(void) 132 { 133 #ifdef RMT 134 if (host) 135 rmtclose(); 136 #endif 137 } 138 139 int eject = 0; 140 141 int 142 main(int argc, char *argv[]) 143 { 144 struct commands *comp; 145 struct mtop mt_com; 146 int ch, mtfd, flags, insert = 0; 147 char *p, *tape, *realtape, *opts; 148 size_t len; 149 150 if (strcmp(__progname, "eject") == 0) { 151 opts = "t"; 152 eject = 1; 153 tape = NULL; 154 } else { 155 opts = "f:"; 156 if ((tape = getenv("TAPE")) == NULL) 157 tape = _PATH_DEFTAPE; 158 } 159 160 while ((ch = getopt(argc, argv, opts)) != -1) { 161 switch (ch) { 162 case 't': 163 insert = 1; 164 break; 165 case 'f': 166 tape = optarg; 167 break; 168 default: 169 usage(); 170 } 171 } 172 argc -= optind; 173 argv += optind; 174 175 if (eject) { 176 if (argc == 1) { 177 tape = *argv++; 178 argc--; 179 } 180 if (argc != 0) 181 usage(); 182 } else if (argc < 1 || argc > 2) 183 usage(); 184 185 if (tape == NULL) 186 usage(); 187 188 if (strchr(tape, ':')) { 189 #ifdef RMT 190 host = tape; 191 tape = strchr(host, ':'); 192 *tape++ = '\0'; 193 if (rmthost(host) == 0) 194 exit(X_ABORT); 195 #else 196 err(1, "no remote support"); 197 #endif 198 } 199 200 if (strlen(tape) >= PATH_MAX) 201 err(1, "tape name too long for protocol"); 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)) == -1) { 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) == -1) { 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 (void)printf("current file number: %d\n", bp->mt_fileno); 285 (void)printf("current block number: %d\n", bp->mt_blkno); 286 } 287 288 /* 289 * Print a register a la the %b format of the kernel's printf. 290 */ 291 void 292 printreg(char *s, u_int v, char *bits) 293 { 294 int i, any = 0; 295 char c; 296 297 if (bits && *bits == 8) 298 printf("%s=%o", s, v); 299 else 300 printf("%s=%x", s, v); 301 if (!bits) 302 return; 303 bits++; 304 if (v && *bits) { 305 putchar('<'); 306 while ((i = *bits++)) { 307 if (v & (1 << (i-1))) { 308 if (any) 309 putchar(','); 310 any = 1; 311 for (; (c = *bits) > 32; bits++) 312 putchar(c); 313 } else 314 for (; *bits > 32; bits++) 315 ; 316 } 317 putchar('>'); 318 } 319 } 320 321 void 322 usage(void) 323 { 324 if (eject) 325 (void)fprintf(stderr, "usage: %s [-t] device\n", __progname); 326 else 327 (void)fprintf(stderr, 328 "usage: %s [-f device] command [count]\n", __progname); 329 exit(X_USAGE); 330 } 331