1 1.49 andvar /* $NetBSD: mt.c,v 1.49 2022/01/24 09:14:36 andvar Exp $ */ 2 1.5 cgd 3 1.1 cgd /* 4 1.5 cgd * Copyright (c) 1980, 1993 5 1.5 cgd * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.37 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.21 christos #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.46 lukem __COPYRIGHT("@(#) Copyright (c) 1980, 1993\ 35 1.46 lukem The Regents of the University of California. All rights reserved."); 36 1.1 cgd #endif /* not lint */ 37 1.1 cgd 38 1.1 cgd #ifndef lint 39 1.5 cgd #if 0 40 1.8 tls static char sccsid[] = "@(#)mt.c 8.2 (Berkeley) 6/6/93"; 41 1.5 cgd #else 42 1.49 andvar __RCSID("$NetBSD: mt.c,v 1.49 2022/01/24 09:14:36 andvar Exp $"); 43 1.5 cgd #endif 44 1.1 cgd #endif /* not lint */ 45 1.1 cgd 46 1.1 cgd /* 47 1.1 cgd * mt -- 48 1.1 cgd * magnetic tape manipulation program 49 1.1 cgd */ 50 1.1 cgd #include <sys/types.h> 51 1.39 christos #include <sys/param.h> 52 1.1 cgd #include <sys/ioctl.h> 53 1.1 cgd #include <sys/mtio.h> 54 1.12 scottr #include <sys/stat.h> 55 1.12 scottr 56 1.12 scottr #include <ctype.h> 57 1.12 scottr #include <err.h> 58 1.1 cgd #include <fcntl.h> 59 1.19 lukem #include <paths.h> 60 1.36 wiz #include <rmt.h> 61 1.12 scottr #include <stdio.h> 62 1.5 cgd #include <stdlib.h> 63 1.3 jtc #include <string.h> 64 1.11 scottr #include <unistd.h> 65 1.25 thorpej 66 1.16 jtc /* pseudo ioctl constants */ 67 1.16 jtc #define MTASF 100 68 1.16 jtc 69 1.1 cgd struct commands { 70 1.20 hannken const char *c_name; /* command */ 71 1.38 christos size_t c_namelen; /* command len */ 72 1.44 gmcgarry u_long c_spcl; /* ioctl request */ 73 1.23 hannken int c_code; /* ioctl code for MTIOCTOP command */ 74 1.20 hannken int c_ronly; /* open tape read-only */ 75 1.20 hannken int c_mincount; /* min allowed count value */ 76 1.16 jtc }; 77 1.16 jtc 78 1.38 christos #define CMD(a) a, sizeof(a) - 1 79 1.47 joerg static const struct commands com[] = { 80 1.38 christos { CMD("asf"), MTIOCTOP, MTASF, 1, 0 }, 81 1.38 christos { CMD("blocksize"), MTIOCTOP, MTSETBSIZ, 1, 0 }, 82 1.38 christos { CMD("bsf"), MTIOCTOP, MTBSF, 1, 1 }, 83 1.38 christos { CMD("bsr"), MTIOCTOP, MTBSR, 1, 1 }, 84 1.38 christos { CMD("compress"), MTIOCTOP, MTCMPRESS, 1, 0 }, 85 1.38 christos { CMD("density"), MTIOCTOP, MTSETDNSTY, 1, 0 }, 86 1.38 christos { CMD("eof"), MTIOCTOP, MTWEOF, 0, 1 }, 87 1.38 christos { CMD("eom"), MTIOCTOP, MTEOM, 1, 0 }, 88 1.38 christos { CMD("erase"), MTIOCTOP, MTERASE, 0, 0 }, 89 1.38 christos { CMD("fsf"), MTIOCTOP, MTFSF, 1, 1 }, 90 1.38 christos { CMD("fsr"), MTIOCTOP, MTFSR, 1, 1 }, 91 1.38 christos { CMD("offline"), MTIOCTOP, MTOFFL, 1, 0 }, 92 1.38 christos { CMD("rdhpos"), MTIOCRDHPOS, 0, 1, 0 }, 93 1.38 christos { CMD("rdspos"), MTIOCRDSPOS, 0, 1, 0 }, 94 1.38 christos { CMD("retension"), MTIOCTOP, MTRETEN, 1, 0 }, 95 1.38 christos { CMD("rewind"), MTIOCTOP, MTREW, 1, 0 }, 96 1.38 christos { CMD("rewoffl"), MTIOCTOP, MTOFFL, 1, 0 }, 97 1.38 christos { CMD("setblk"), MTIOCTOP, MTSETBSIZ, 1, 0 }, 98 1.38 christos { CMD("setdensity"), MTIOCTOP, MTSETDNSTY, 1, 0 }, 99 1.38 christos { CMD("sethpos"), MTIOCHLOCATE, 0, 1, 0 }, 100 1.38 christos { CMD("setspos"), MTIOCSLOCATE, 0, 1, 0 }, 101 1.38 christos { CMD("status"), MTIOCGET, MTNOP, 1, 0 }, 102 1.38 christos { CMD("weof"), MTIOCTOP, MTWEOF, 0, 1 }, 103 1.38 christos { CMD("eew"), MTIOCTOP, MTEWARN, 1, 0 }, 104 1.48 mlelstv { CMD("cache"), MTIOCTOP, MTCACHE, 1, 0 }, 105 1.48 mlelstv { CMD("nocache"), MTIOCTOP, MTNOCACHE, 1, 0 }, 106 1.43 christos { .c_name = NULL } 107 1.1 cgd }; 108 1.1 cgd 109 1.47 joerg static void printreg(const char *, u_int, const char *); 110 1.47 joerg static void status(struct mtget *); 111 1.47 joerg __dead static void usage(void); 112 1.1 cgd 113 1.3 jtc int 114 1.36 wiz main(int argc, char *argv[]) 115 1.1 cgd { 116 1.39 christos const struct commands *cp, *comp; 117 1.5 cgd struct mtget mt_status; 118 1.5 cgd struct mtop mt_com; 119 1.38 christos int ch, mtfd, flags; 120 1.27 mycroft char *p; 121 1.27 mycroft const char *tape; 122 1.24 veego int count; 123 1.39 christos size_t len; 124 1.1 cgd 125 1.36 wiz setprogname(argv[0]); 126 1.5 cgd if ((tape = getenv("TAPE")) == NULL) 127 1.19 lukem tape = _PATH_DEFTAPE; 128 1.5 cgd 129 1.5 cgd while ((ch = getopt(argc, argv, "f:t:")) != -1) 130 1.5 cgd switch (ch) { 131 1.3 jtc case 'f': 132 1.3 jtc case 't': 133 1.3 jtc tape = optarg; 134 1.3 jtc break; 135 1.5 cgd case '?': 136 1.3 jtc default: 137 1.3 jtc usage(); 138 1.3 jtc } 139 1.3 jtc argc -= optind; 140 1.3 jtc argv += optind; 141 1.3 jtc 142 1.5 cgd if (argc < 1 || argc > 2) 143 1.3 jtc usage(); 144 1.3 jtc 145 1.39 christos len = strlen(p = *argv++); 146 1.39 christos for (comp = NULL, cp = com; cp->c_name != NULL; cp++) { 147 1.39 christos size_t clen = MIN(len, cp->c_namelen); 148 1.39 christos if (strncmp(p, cp->c_name, clen) == 0) { 149 1.39 christos if (comp != NULL) 150 1.39 christos errx(1, "%s: Ambiguous command `%s' or `%s'?", 151 1.39 christos p, cp->c_name, comp->c_name); 152 1.39 christos else 153 1.39 christos comp = cp; 154 1.39 christos } 155 1.23 hannken } 156 1.39 christos if (comp == NULL) 157 1.39 christos errx(1, "%s: unknown command", p); 158 1.22 mjacob 159 1.23 hannken if (*argv) { 160 1.23 hannken count = strtol(*argv, &p, 10); 161 1.23 hannken if (count < comp->c_mincount || *p) 162 1.23 hannken errx(2, "%s: illegal count", *argv); 163 1.23 hannken } else 164 1.23 hannken count = 1; 165 1.12 scottr 166 1.23 hannken flags = comp->c_ronly ? O_RDONLY : O_WRONLY; 167 1.20 hannken 168 1.17 jtc if ((mtfd = open(tape, flags)) < 0) 169 1.7 pk err(2, "%s", tape); 170 1.16 jtc 171 1.23 hannken switch (comp->c_spcl) { 172 1.23 hannken case MTIOCTOP: 173 1.23 hannken if (comp->c_code == MTASF) { 174 1.35 mason 175 1.23 hannken /* If mtget.mt_fileno was implemented, We could 176 1.23 hannken compute the minimal seek needed to position 177 1.23 hannken the tape. Until then, rewind and seek from 178 1.49 andvar beginning-of-tape */ 179 1.23 hannken 180 1.23 hannken mt_com.mt_op = MTREW; 181 1.23 hannken mt_com.mt_count = 1; 182 1.23 hannken if (ioctl(mtfd, MTIOCTOP, &mt_com) < 0) 183 1.23 hannken err(2, "%s", tape); 184 1.23 hannken 185 1.33 christos if (count > 0) { 186 1.33 christos mt_com.mt_op = MTFSF; 187 1.33 christos mt_com.mt_count = count; 188 1.33 christos if (ioctl(mtfd, MTIOCTOP, &mt_com) < 0) 189 1.33 christos err(2, "%s", tape); 190 1.33 christos } 191 1.34 mason 192 1.22 mjacob } else { 193 1.23 hannken mt_com.mt_op = comp->c_code; 194 1.23 hannken mt_com.mt_count = count; 195 1.16 jtc 196 1.23 hannken if (ioctl(mtfd, MTIOCTOP, &mt_com) < 0) 197 1.23 hannken err(2, "%s: %s", tape, comp->c_name); 198 1.16 jtc 199 1.23 hannken } 200 1.23 hannken break; 201 1.16 jtc 202 1.23 hannken case MTIOCGET: 203 1.17 jtc if (ioctl(mtfd, MTIOCGET, &mt_status) < 0) 204 1.17 jtc err(2, "%s: %s", tape, comp->c_name); 205 1.17 jtc status(&mt_status); 206 1.23 hannken break; 207 1.23 hannken 208 1.23 hannken case MTIOCRDSPOS: 209 1.23 hannken case MTIOCRDHPOS: 210 1.23 hannken if (ioctl(mtfd, comp->c_spcl, (caddr_t) &count) < 0) 211 1.23 hannken err(2, "%s", tape); 212 1.23 hannken printf("%s: block location %u\n", tape, (unsigned int) count); 213 1.23 hannken break; 214 1.23 hannken 215 1.23 hannken case MTIOCSLOCATE: 216 1.23 hannken case MTIOCHLOCATE: 217 1.23 hannken if (ioctl(mtfd, comp->c_spcl, (caddr_t) &count) < 0) 218 1.23 hannken err(2, "%s", tape); 219 1.23 hannken break; 220 1.23 hannken 221 1.23 hannken default: 222 1.45 dogcow errx(1, "internal error: unknown request %ld", comp->c_spcl); 223 1.1 cgd } 224 1.9 scottr 225 1.17 jtc exit(0); 226 1.5 cgd /* NOTREACHED */ 227 1.1 cgd } 228 1.1 cgd 229 1.30 christos #if defined(sun) && !defined(__SVR4) 230 1.1 cgd #include <sundev/tmreg.h> 231 1.1 cgd #include <sundev/arreg.h> 232 1.1 cgd #endif 233 1.1 cgd 234 1.1 cgd #ifdef tahoe 235 1.1 cgd #include <tahoe/vba/cyreg.h> 236 1.1 cgd #endif 237 1.1 cgd 238 1.47 joerg static const struct tape_desc { 239 1.1 cgd short t_type; /* type of magtape device */ 240 1.27 mycroft const char *t_name; /* printing name */ 241 1.27 mycroft const char *t_dsbits; /* "drive status" register */ 242 1.27 mycroft const char *t_erbits; /* "error" register */ 243 1.1 cgd } tapes[] = { 244 1.30 christos #if defined(sun) && !defined(__SVR4) 245 1.1 cgd { MT_ISCPC, "TapeMaster", TMS_BITS, 0 }, 246 1.1 cgd { MT_ISAR, "Archive", ARCH_CTRL_BITS, ARCH_BITS }, 247 1.1 cgd #endif 248 1.1 cgd #ifdef tahoe 249 1.1 cgd { MT_ISCY, "cipher", CYS_BITS, CYCW_BITS }, 250 1.1 cgd #endif 251 1.26 mjacob #define SCSI_DS_BITS "\20\5WriteProtect\2Mounted" 252 1.26 mjacob { 0x7, "SCSI", SCSI_DS_BITS, "76543210" }, 253 1.43 christos { .t_type = 0 } 254 1.1 cgd }; 255 1.1 cgd 256 1.26 mjacob 257 1.1 cgd /* 258 1.1 cgd * Interpret the status buffer returned 259 1.1 cgd */ 260 1.47 joerg static void 261 1.36 wiz status(struct mtget *bp) 262 1.1 cgd { 263 1.27 mycroft const struct tape_desc *mt; 264 1.1 cgd 265 1.5 cgd for (mt = tapes;; mt++) { 266 1.5 cgd if (mt->t_type == 0) { 267 1.5 cgd (void)printf("%d: unknown tape drive type\n", 268 1.5 cgd bp->mt_type); 269 1.5 cgd return; 270 1.5 cgd } 271 1.1 cgd if (mt->t_type == bp->mt_type) 272 1.1 cgd break; 273 1.1 cgd } 274 1.5 cgd (void)printf("%s tape drive, residual=%d\n", mt->t_name, bp->mt_resid); 275 1.1 cgd printreg("ds", bp->mt_dsreg, mt->t_dsbits); 276 1.1 cgd printreg("\ner", bp->mt_erreg, mt->t_erbits); 277 1.5 cgd (void)putchar('\n'); 278 1.21 christos (void)printf("blocksize: %d (%d, %d, %d, %d)\n", 279 1.14 mrg bp->mt_blksiz, bp->mt_mblksiz[0], bp->mt_mblksiz[1], 280 1.14 mrg bp->mt_mblksiz[2], bp->mt_mblksiz[3]); 281 1.21 christos (void)printf("density: %d (%d, %d, %d, %d)\n", 282 1.14 mrg bp->mt_density, bp->mt_mdensity[0], bp->mt_mdensity[1], 283 1.14 mrg bp->mt_mdensity[2], bp->mt_mdensity[3]); 284 1.32 simonb (void)printf("current file number: %d\n", bp->mt_fileno); 285 1.32 simonb (void)printf("current block number: %d\n", bp->mt_blkno); 286 1.1 cgd } 287 1.1 cgd 288 1.1 cgd /* 289 1.5 cgd * Print a register a la the %b format of the kernel's printf. 290 1.1 cgd */ 291 1.47 joerg static void 292 1.36 wiz printreg(const char *s, u_int v, const char *bits) 293 1.1 cgd { 294 1.36 wiz int any, i; 295 1.18 tls char c; 296 1.1 cgd 297 1.36 wiz any = 0; 298 1.1 cgd if (bits && *bits == 8) 299 1.1 cgd printf("%s=%o", s, v); 300 1.1 cgd else 301 1.1 cgd printf("%s=%x", s, v); 302 1.42 christos if (v && bits && *++bits) { 303 1.1 cgd putchar('<'); 304 1.11 scottr while ((i = *bits++)) { 305 1.1 cgd if (v & (1 << (i-1))) { 306 1.1 cgd if (any) 307 1.1 cgd putchar(','); 308 1.1 cgd any = 1; 309 1.1 cgd for (; (c = *bits) > 32; bits++) 310 1.1 cgd putchar(c); 311 1.1 cgd } else 312 1.1 cgd for (; *bits > 32; bits++) 313 1.1 cgd ; 314 1.1 cgd } 315 1.1 cgd putchar('>'); 316 1.1 cgd } 317 1.3 jtc } 318 1.3 jtc 319 1.47 joerg static void 320 1.36 wiz usage(void) 321 1.3 jtc { 322 1.40 hira (void)fprintf(stderr, "usage: %s [-f device] command [count]\n", 323 1.40 hira getprogname()); 324 1.17 jtc exit(1); 325 1.28 mycroft /* NOTREACHED */ 326 1.1 cgd } 327