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