1 /* $OpenBSD: mt.c,v 1.29 2006/06/14 02:14:25 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 #ifndef lint 34 static char copyright[] = 35 "@(#) Copyright (c) 1980, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37 #endif /* not lint */ 38 39 #ifndef lint 40 #if 0 41 static char sccsid[] = "@(#)mt.c 8.2 (Berkeley) 6/6/93"; 42 #else 43 static char rcsid[] = "$OpenBSD: mt.c,v 1.29 2006/06/14 02:14:25 krw Exp $"; 44 #endif 45 #endif /* not lint */ 46 47 /* 48 * mt -- 49 * magnetic tape manipulation program 50 */ 51 #include <sys/types.h> 52 #include <sys/ioctl.h> 53 #include <sys/mtio.h> 54 #include <sys/stat.h> 55 #include <sys/disklabel.h> 56 57 #include <ctype.h> 58 #include <err.h> 59 #include <errno.h> 60 #include <fcntl.h> 61 #include <paths.h> 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <unistd.h> 66 #include <util.h> 67 68 #include "mt.h" 69 70 struct commands { 71 char *c_name; 72 int c_code; 73 int c_ronly; 74 int c_mincount; 75 } com[] = { 76 { "blocksize", MTSETBSIZ, 1, 0 }, 77 { "bsf", MTBSF, 1, 1 }, 78 { "bsr", MTBSR, 1, 1 }, 79 { "density", MTSETDNSTY, 1, 1 }, 80 { "eof", MTWEOF, 0, 1 }, 81 { "eom", MTEOM, 1, 1 }, 82 { "erase", MTERASE, 0, 1 }, 83 { "fsf", MTFSF, 1, 1 }, 84 { "fsr", MTFSR, 1, 1 }, 85 { "offline", MTOFFL, 1, 1 }, 86 #define COM_EJECT 9 /* element in the above array */ 87 { "rewind", MTREW, 1, 1 }, 88 { "rewoffl", MTOFFL, 1, 1 }, 89 { "status", MTNOP, 1, 1 }, 90 { "retension", MTRETEN, 1, 1 }, 91 #define COM_RETEN 13 /* element in the above array */ 92 { "weof", MTWEOF, 0, 1 }, 93 { NULL } 94 }; 95 96 void printreg(char *, u_int, char *); 97 void status(struct mtget *); 98 void usage(void); 99 100 char *host = NULL; /* remote host (if any) */ 101 102 char *progname; 103 int eject = 0; 104 105 int 106 main(int argc, char *argv[]) 107 { 108 struct commands *comp; 109 struct mtget mt_status; 110 struct mtop mt_com; 111 int ch, len, mtfd, flags, insert = 0; 112 char *p, *tape, *realtape, *opts; 113 114 if ((progname = strrchr(argv[0], '/'))) 115 progname++; 116 else 117 progname = argv[0]; 118 119 if (strcmp(progname, "eject") == 0) { 120 opts = "t"; 121 eject = 1; 122 tape = NULL; 123 } else { 124 opts = "f:"; 125 if ((tape = getenv("TAPE")) == NULL) 126 tape = _PATH_DEFTAPE; 127 } 128 129 while ((ch = getopt(argc, argv, opts)) != -1) { 130 switch (ch) { 131 case 't': 132 insert = 1; 133 break; 134 case 'f': 135 tape = optarg; 136 break; 137 default: 138 usage(); 139 } 140 } 141 argc -= optind; 142 argv += optind; 143 144 if (eject) { 145 if (argc == 1) { 146 tape = *argv++; 147 argc--; 148 } 149 if (argc != 0) 150 usage(); 151 } else if (argc < 1 || argc > 2) 152 usage(); 153 154 if (tape == NULL) 155 usage(); 156 157 if (strchr(tape, ':')) { 158 host = tape; 159 tape = strchr(host, ':'); 160 *tape++ = '\0'; 161 if (rmthost(host) == 0) 162 exit(X_ABORT); 163 } 164 165 if (eject) { 166 if (insert) 167 comp = &com[COM_RETEN]; 168 else 169 comp = &com[COM_EJECT]; 170 } else { 171 len = strlen(p = *argv++); 172 for (comp = com;; comp++) { 173 if (comp->c_name == NULL) 174 errx(1, "%s: unknown command", p); 175 if (strncmp(p, comp->c_name, len) == 0) 176 break; 177 } 178 } 179 180 flags = comp->c_ronly ? O_RDONLY : O_WRONLY | O_CREAT; 181 if ((mtfd = host ? rmtopen(tape, flags) : opendev(tape, flags, 182 OPENDEV_PART, &realtape)) < 0) { 183 if (errno != 0) 184 warn("%s", host ? tape : realtape); 185 exit(2); 186 } 187 if (comp->c_code != MTNOP) { 188 mt_com.mt_op = comp->c_code; 189 if (*argv) { 190 mt_com.mt_count = strtol(*argv, &p, 10); 191 if (mt_com.mt_count < comp->c_mincount || *p) 192 errx(2, "%s: illegal count", *argv); 193 } 194 else 195 mt_com.mt_count = 1; 196 if ((host ? rmtioctl(mt_com.mt_op, mt_com.mt_count) : 197 ioctl(mtfd, MTIOCTOP, &mt_com)) < 0) { 198 if (eject) 199 err(2, "%s", tape); 200 else 201 err(2, "%s: %s", tape, comp->c_name); 202 } 203 } else { 204 if (host) 205 status(rmtstatus()); 206 else { 207 if (ioctl(mtfd, MTIOCGET, &mt_status) < 0) 208 err(2, "ioctl MTIOCGET"); 209 status(&mt_status); 210 } 211 } 212 213 if (host) 214 rmtclose(); 215 216 exit(X_FINOK); 217 /* NOTREACHED */ 218 } 219 220 struct tape_desc { 221 short t_type; /* type of magtape device */ 222 char *t_name; /* printing name */ 223 char *t_dsbits; /* "drive status" register */ 224 char *t_erbits; /* "error" register */ 225 } tapes[] = { 226 #define SCSI_DS_BITS "\20\5WriteProtect\2Mounted" 227 { 0x7, "SCSI", SCSI_DS_BITS, "76543210" }, 228 { 0 } 229 }; 230 231 /* 232 * Interpret the status buffer returned 233 */ 234 void 235 status(struct mtget *bp) 236 { 237 struct tape_desc *mt; 238 239 for (mt = tapes;; mt++) { 240 if (mt->t_type == 0) { 241 (void)printf("%d: unknown tape drive type\n", 242 bp->mt_type); 243 return; 244 } 245 if (mt->t_type == bp->mt_type) 246 break; 247 } 248 (void)printf("%s tape drive, residual=%d\n", mt->t_name, bp->mt_resid); 249 printreg("ds", bp->mt_dsreg, mt->t_dsbits); 250 printreg("\ner", bp->mt_erreg, mt->t_erbits); 251 (void)putchar('\n'); 252 (void)printf("blocksize: %d (%d)\n", bp->mt_blksiz, bp->mt_mblksiz); 253 (void)printf("density: %d (%d)\n", bp->mt_density, bp->mt_mdensity); 254 } 255 256 /* 257 * Print a register a la the %b format of the kernel's printf. 258 */ 259 void 260 printreg(char *s, u_int v, char *bits) 261 { 262 int i, any = 0; 263 char c; 264 265 if (bits && *bits == 8) 266 printf("%s=%o", s, v); 267 else 268 printf("%s=%x", s, v); 269 if (!bits) 270 return; 271 bits++; 272 if (v && *bits) { 273 putchar('<'); 274 while ((i = *bits++)) { 275 if (v & (1 << (i-1))) { 276 if (any) 277 putchar(','); 278 any = 1; 279 for (; (c = *bits) > 32; bits++) 280 putchar(c); 281 } else 282 for (; *bits > 32; bits++) 283 ; 284 } 285 putchar('>'); 286 } 287 } 288 289 void 290 usage(void) 291 { 292 if (eject) 293 (void)fprintf(stderr, "usage: %s [-t] device\n", progname); 294 else 295 (void)fprintf(stderr, 296 "usage: %s [-f device] command [count]\n", progname); 297 exit(X_USAGE); 298 } 299