]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.bin/mt/mt.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.bin / mt / mt.c
1 /*
2  * Copyright (c) 1980, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #ifndef lint
31 static const char copyright[] =
32 "@(#) Copyright (c) 1980, 1993\n\
33         The Regents of the University of California.  All rights reserved.\n";
34 #endif /* not lint */
35
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)mt.c        8.2 (Berkeley) 5/4/95";
39 #endif
40 #endif /* not lint */
41
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44
45 /*
46  * mt --
47  *   magnetic tape manipulation program
48  */
49 #include <sys/types.h>
50 #include <sys/ioctl.h>
51 #include <sys/mtio.h>
52
53 #include <ctype.h>
54 #include <err.h>
55 #include <fcntl.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <unistd.h>
60
61 /* the appropriate sections of <sys/mtio.h> are also #ifdef'd for FreeBSD */
62 /* c_flags */
63 #define NEED_2ARGS      0x01
64 #define ZERO_ALLOWED    0x02
65 #define IS_DENSITY      0x04
66 #define DISABLE_THIS    0x08
67 #define IS_COMP         0x10
68
69 #ifndef TRUE
70 #define TRUE 1
71 #endif
72 #ifndef FALSE
73 #define FALSE 0
74 #endif
75
76 static const struct commands {
77         const char *c_name;
78         unsigned long c_code;
79         int c_ronly;
80         int c_flags;
81 } com[] = {
82         { "bsf",        MTBSF,  1, 0 },
83         { "bsr",        MTBSR,  1, 0 },
84         /* XXX FreeBSD considered "eof" dangerous, since it's being
85            confused with "eom" (and is an alias for "weof" anyway) */
86         { "eof",        MTWEOF, 0, DISABLE_THIS },
87         { "fsf",        MTFSF,  1, 0 },
88         { "fsr",        MTFSR,  1, 0 },
89         { "offline",    MTOFFL, 1, 0 },
90         { "rewind",     MTREW,  1, 0 },
91         { "rewoffl",    MTOFFL, 1, 0 },
92         { "status",     MTNOP,  1, 0 },
93         { "weof",       MTWEOF, 0, ZERO_ALLOWED },
94         { "erase",      MTERASE, 0, ZERO_ALLOWED},
95         { "blocksize",  MTSETBSIZ, 0, NEED_2ARGS|ZERO_ALLOWED },
96         { "density",    MTSETDNSTY, 0, NEED_2ARGS|ZERO_ALLOWED|IS_DENSITY },
97         { "eom",        MTEOD, 1, 0 },
98         { "eod",        MTEOD, 1, 0 },
99         { "smk",        MTWSS, 0, 0 },
100         { "wss",        MTWSS, 0, 0 },
101         { "fss",        MTFSS, 1, 0 },
102         { "bss",        MTBSS, 1, 0 },
103         { "comp",       MTCOMP, 0, NEED_2ARGS|ZERO_ALLOWED|IS_COMP },
104         { "retension",  MTRETENS, 1, 0 },
105         { "rdhpos",     MTIOCRDHPOS,  0, 0 },
106         { "rdspos",     MTIOCRDSPOS,  0, 0 },
107         { "sethpos",    MTIOCHLOCATE, 0, NEED_2ARGS|ZERO_ALLOWED },
108         { "setspos",    MTIOCSLOCATE, 0, NEED_2ARGS|ZERO_ALLOWED },
109         { "errstat",    MTIOCERRSTAT, 0, 0 },
110         { "setmodel",   MTIOCSETEOTMODEL, 0, NEED_2ARGS|ZERO_ALLOWED },
111         { "seteotmodel",        MTIOCSETEOTMODEL, 0, NEED_2ARGS|ZERO_ALLOWED },
112         { "getmodel",   MTIOCGETEOTMODEL, 0, 0 },
113         { "geteotmodel",        MTIOCGETEOTMODEL, 0, 0 },
114         { NULL, 0, 0, 0 }
115 };
116
117 static const char *getblksiz(int);
118 static void printreg(const char *, u_int, const char *);
119 static void status(struct mtget *);
120 static void usage(void);
121 static void st_status(struct mtget *);
122 static int stringtodens(const char *s);
123 static const char *denstostring(int d);
124 static int denstobp(int d, int bpi);
125 static u_int32_t stringtocomp(const char *s);
126 static const char *comptostring(u_int32_t comp);
127 static void warn_eof(void);
128
129 int
130 main(int argc, char *argv[])
131 {
132         const struct commands *comp;
133         struct mtget mt_status;
134         struct mtop mt_com;
135         int ch, len, mtfd;
136         const char *p, *tape;
137
138         if ((tape = getenv("TAPE")) == NULL)
139                 tape = DEFTAPE;
140
141         while ((ch = getopt(argc, argv, "f:t:")) != -1)
142                 switch(ch) {
143                 case 'f':
144                 case 't':
145                         tape = optarg;
146                         break;
147                 case '?':
148                 default:
149                         usage();
150                 }
151         argc -= optind;
152         argv += optind;
153
154         if (argc < 1 || argc > 2)
155                 usage();
156
157         len = strlen(p = *argv++);
158         for (comp = com;; comp++) {
159                 if (comp->c_name == NULL)
160                         errx(1, "%s: unknown command", p);
161                 if (strncmp(p, comp->c_name, len) == 0)
162                         break;
163         }
164         if((comp->c_flags & NEED_2ARGS) && argc != 2)
165                 usage();
166         if(comp->c_flags & DISABLE_THIS) {
167                 warn_eof();
168         }
169         if ((mtfd = open(tape, comp->c_ronly ? O_RDONLY : O_RDWR)) < 0)
170                 err(1, "%s", tape);
171         if (comp->c_code != MTNOP) {
172                 mt_com.mt_op = comp->c_code;
173                 if (*argv) {
174                         if (!isdigit(**argv) &&
175                             (comp->c_flags & IS_DENSITY)) {
176                                 const char *dcanon;
177                                 mt_com.mt_count = stringtodens(*argv);
178                                 if (mt_com.mt_count == 0)
179                                         errx(1, "%s: unknown density", *argv);
180                                 dcanon = denstostring(mt_com.mt_count);
181                                 if (strcmp(dcanon, *argv) != 0)
182                                         printf(
183                                         "Using \"%s\" as an alias for %s\n",
184                                                *argv, dcanon);
185                                 p = "";
186                         } else if (!isdigit(**argv) &&
187                                    (comp->c_flags & IS_COMP)) {
188
189                                 mt_com.mt_count = stringtocomp(*argv);
190                                 if ((u_int32_t)mt_com.mt_count == 0xf0f0f0f0)
191                                         errx(1, "%s: unknown compression",
192                                              *argv);
193                                 p = "";
194                         } else {
195                                 char *q;
196                                 /* allow for hex numbers; useful for density */
197                                 mt_com.mt_count = strtol(*argv, &q, 0);
198                                 p = q;
199                         }
200                         if ((mt_com.mt_count <=
201                             ((comp->c_flags & ZERO_ALLOWED)? -1: 0)
202                             && ((comp->c_flags & IS_COMP) == 0)
203                             ) || *p)
204                                 errx(1, "%s: illegal count", *argv);
205                 }
206                 else
207                         mt_com.mt_count = 1;
208                 switch (comp->c_code) {
209                 case MTIOCERRSTAT:
210                 {
211                         unsigned int i;
212                         union mterrstat umn;
213                         struct scsi_tape_errors *s = &umn.scsi_errstat;
214
215                         if (ioctl(mtfd, comp->c_code, (caddr_t)&umn) < 0)
216                                 err(2, "%s", tape);
217                         (void)printf("Last I/O Residual: %u\n", s->io_resid);
218                         (void)printf(" Last I/O Command:");
219                         for (i = 0; i < sizeof (s->io_cdb); i++)
220                                 (void)printf(" %02X", s->io_cdb[i]);
221                         (void)printf("\n");
222                         (void)printf("   Last I/O Sense:\n\n\t");
223                         for (i = 0; i < sizeof (s->io_sense); i++) {
224                                 (void)printf(" %02X", s->io_sense[i]);
225                                 if (((i + 1) & 0xf) == 0) {
226                                         (void)printf("\n\t");
227                                 }
228                         }
229                         (void)printf("\n");
230                         (void)printf("Last Control Residual: %u\n",
231                             s->ctl_resid);
232                         (void)printf(" Last Control Command:");
233                         for (i = 0; i < sizeof (s->ctl_cdb); i++)
234                                 (void)printf(" %02X", s->ctl_cdb[i]);
235                         (void)printf("\n");
236                         (void)printf("   Last Control Sense:\n\n\t");
237                         for (i = 0; i < sizeof (s->ctl_sense); i++) {
238                                 (void)printf(" %02X", s->ctl_sense[i]);
239                                 if (((i + 1) & 0xf) == 0) {
240                                         (void)printf("\n\t");
241                                 }
242                         }
243                         (void)printf("\n\n");
244                         exit(0);
245                         /* NOTREACHED */
246                 }
247                 case MTIOCRDHPOS:
248                 case MTIOCRDSPOS:
249                 {
250                         u_int32_t block;
251                         if (ioctl(mtfd, comp->c_code, (caddr_t)&block) < 0)
252                                 err(2, "%s", tape);
253                         (void)printf("%s: %s block location %u\n", tape,
254                             (comp->c_code == MTIOCRDHPOS)? "hardware" :
255                             "logical", block);
256                         exit(0);
257                         /* NOTREACHED */
258                 }
259                 case MTIOCSLOCATE:
260                 case MTIOCHLOCATE:
261                 {
262                         u_int32_t block = (u_int32_t)mt_com.mt_count;
263                         if (ioctl(mtfd, comp->c_code, (caddr_t)&block) < 0)
264                                 err(2, "%s", tape);
265                         exit(0);
266                         /* NOTREACHED */
267                 }
268                 case MTIOCGETEOTMODEL:
269                 {
270                         u_int32_t om;
271                         if (ioctl(mtfd, MTIOCGETEOTMODEL, (caddr_t)&om) < 0)
272                                 err(2, "%s", tape);
273                         (void)printf("%s: the model is %u filemar%s at EOT\n",
274                             tape, om, (om > 1)? "ks" : "k");
275                         exit(0);
276                         /* NOTREACHED */
277                 }
278                 case MTIOCSETEOTMODEL:
279                 {
280                         u_int32_t om, nm = (u_int32_t)mt_com.mt_count;
281                         if (ioctl(mtfd, MTIOCGETEOTMODEL, (caddr_t)&om) < 0)
282                                 err(2, "%s", tape);
283                         if (ioctl(mtfd, comp->c_code, (caddr_t)&nm) < 0)
284                                 err(2, "%s", tape);
285                         (void)printf("%s: old model was %u filemar%s at EOT\n",
286                             tape, om, (om > 1)? "ks" : "k");
287                         (void)printf("%s: new model  is %u filemar%s at EOT\n",
288                             tape, nm, (nm > 1)? "ks" : "k");
289                         exit(0);
290                         /* NOTREACHED */
291                 }
292                 default:
293                         break;
294                 }
295                 if (ioctl(mtfd, MTIOCTOP, &mt_com) < 0)
296                         err(1, "%s: %s", tape, comp->c_name);
297         } else {
298                 if (ioctl(mtfd, MTIOCGET, &mt_status) < 0)
299                         err(1, NULL);
300                 status(&mt_status);
301         }
302         exit(0);
303         /* NOTREACHED */
304 }
305
306 static const struct tape_desc {
307         short   t_type;         /* type of magtape device */
308         const char *t_name;     /* printing name */
309         const char *t_dsbits;   /* "drive status" register */
310         const char *t_erbits;   /* "error" register */
311 } tapes[] = {
312         { MT_ISAR,      "SCSI tape drive", 0,           0 },
313         { 0, NULL, 0, 0 }
314 };
315
316 /*
317  * Interpret the status buffer returned
318  */
319 static void
320 status(struct mtget *bp)
321 {
322         const struct tape_desc *mt;
323
324         for (mt = tapes;; mt++) {
325                 if (mt->t_type == 0) {
326                         (void)printf("%d: unknown tape drive type\n",
327                             bp->mt_type);
328                         return;
329                 }
330                 if (mt->t_type == bp->mt_type)
331                         break;
332         }
333         if(mt->t_type == MT_ISAR)
334                 st_status(bp);
335         else {
336                 (void)printf("%s tape drive, residual=%d\n", 
337                     mt->t_name, bp->mt_resid);
338                 printreg("ds", (unsigned short)bp->mt_dsreg, mt->t_dsbits);
339                 printreg("\ner", (unsigned short)bp->mt_erreg, mt->t_erbits);
340                 (void)putchar('\n');
341         }
342 }
343
344 /*
345  * Print a register a la the %b format of the kernel's printf.
346  */
347 static void
348 printreg(const char *s, u_int v, const char *bits)
349 {
350         int i, any = 0;
351         char c;
352
353         if (bits && *bits == 8)
354                 printf("%s=%o", s, v);
355         else
356                 printf("%s=%x", s, v);
357         if (!bits)
358                 return;
359         bits++;
360         if (v && bits) {
361                 putchar('<');
362                 while ((i = *bits++)) {
363                         if (v & (1 << (i-1))) {
364                                 if (any)
365                                         putchar(',');
366                                 any = 1;
367                                 for (; (c = *bits) > 32; bits++)
368                                         putchar(c);
369                         } else
370                                 for (; *bits > 32; bits++)
371                                         ;
372                 }
373                 putchar('>');
374         }
375 }
376
377 static void
378 usage(void)
379 {
380         (void)fprintf(stderr, "usage: mt [-f device] command [count]\n");
381         exit(1);
382 }
383
384 static const struct densities {
385         int dens;
386         int bpmm;
387         int bpi;
388         const char *name;
389 } dens[] = {
390         /*
391          * Taken from T10 Project 997D 
392          * SCSI-3 Stream Device Commands (SSC)
393          * Revision 11, 4-Nov-97
394          */
395         /*Num.  bpmm    bpi     Reference     */
396         { 0x1,  32,     800,    "X3.22-1983" },
397         { 0x2,  63,     1600,   "X3.39-1986" },
398         { 0x3,  246,    6250,   "X3.54-1986" },
399         { 0x5,  315,    8000,   "X3.136-1986" },
400         { 0x6,  126,    3200,   "X3.157-1987" },
401         { 0x7,  252,    6400,   "X3.116-1986" },
402         { 0x8,  315,    8000,   "X3.158-1987" },
403         { 0x9,  491,    37871,  "X3.180" },
404         { 0xA,  262,    6667,   "X3B5/86-199" },
405         { 0xB,  63,     1600,   "X3.56-1986" },
406         { 0xC,  500,    12690,  "HI-TC1" },
407         { 0xD,  999,    25380,  "HI-TC2" },
408         { 0xF,  394,    10000,  "QIC-120" },
409         { 0x10, 394,    10000,  "QIC-150" },
410         { 0x11, 630,    16000,  "QIC-320" },
411         { 0x12, 2034,   51667,  "QIC-1350" },
412         { 0x13, 2400,   61000,  "X3B5/88-185A" },
413         { 0x14, 1703,   43245,  "X3.202-1991" },
414         { 0x15, 1789,   45434,  "ECMA TC17" },
415         { 0x16, 394,    10000,  "X3.193-1990" },
416         { 0x17, 1673,   42500,  "X3B5/91-174" },
417         { 0x18, 1673,   42500,  "X3B5/92-50" },
418         { 0x19, 2460,   62500,  "DLTapeIII" },
419         { 0x1A, 3214,   81633,  "DLTapeIV(20GB)" },
420         { 0x1B, 3383,   85937,  "DLTapeIV(35GB)" },
421         { 0x1C, 1654,   42000,  "QIC-385M" },
422         { 0x1D, 1512,   38400,  "QIC-410M" },
423         { 0x1E, 1385,   36000,  "QIC-1000C" },
424         { 0x1F, 2666,   67733,  "QIC-2100C" },
425         { 0x20, 2666,   67733,  "QIC-6GB(M)" },
426         { 0x21, 2666,   67733,  "QIC-20GB(C)" },
427         { 0x22, 1600,   40640,  "QIC-2GB(C)" },
428         { 0x23, 2666,   67733,  "QIC-875M" },
429         { 0x24, 2400,   61000,  "DDS-2" },
430         { 0x25, 3816,   97000,  "DDS-3" },
431         { 0x26, 3816,   97000,  "DDS-4" },
432         { 0x27, 3056,   77611,  "Mammoth" },
433         { 0x28, 1491,   37871,  "X3.224" },
434         { 0x41, 3868,   98250,  "DLTapeIV(40GB)" },
435         { 0x48, 5236,   133000, "SDLTapeI(110)" },
436         { 0x49, 7598,   193000, "SDLTapeI(160)" },
437         { 0, 0, 0, NULL }
438 };
439
440 static const struct compression_types {
441         u_int32_t       comp_number;
442         const char      *name;
443 } comp_types[] = {
444         { 0x00, "none" },
445         { 0x00, "off" },
446         { 0x10, "IDRC" },
447         { 0x20, "DCLZ" },
448         { 0xffffffff, "enable" },
449         { 0xffffffff, "on" },
450         { 0xf0f0f0f0, NULL}
451 };
452
453 static const char *
454 denstostring(int d)
455 {
456         static char buf[20];
457         const struct densities *sd;
458
459         /* densities 0 and 0x7f are handled as special cases */
460         if (d == 0)
461                 return "default";
462         if (d == 0x7f)
463                 return "same";
464         for (sd = dens; sd->dens; sd++)
465                 if (sd->dens == d)
466                         break;
467         if (sd->dens == 0)
468                 sprintf(buf, "0x%02x", d);
469         else 
470                 sprintf(buf, "0x%02x:%s", d, sd->name);
471         return buf;
472 }
473
474 /*
475  * Given a specific density number, return either the bits per inch or bits
476  * per millimeter for the given density.
477  */
478 static int
479 denstobp(int d, int bpi)
480 {
481         const struct densities *sd;
482
483         for (sd = dens; sd->dens; sd++)
484                 if (sd->dens == d)
485                         break;
486         if (sd->dens == 0)
487                 return(0);
488         else {
489                 if (bpi)
490                         return(sd->bpi);
491                 else
492                         return(sd->bpmm);
493         }
494 }
495
496 static int
497 stringtodens(const char *s)
498 {
499         const struct densities *sd;
500         size_t l = strlen(s);
501
502         for (sd = dens; sd->dens; sd++)
503                 if (strncasecmp(sd->name, s, l) == 0)
504                         break;
505         return sd->dens;
506 }
507
508
509 static const char *
510 getblksiz(int bs)
511 {
512         static char buf[25];
513         if (bs == 0)
514                 return "variable";
515         else {
516                 sprintf(buf, "%d bytes", bs);
517                 return buf;
518         }
519 }
520
521 static const char *
522 comptostring(u_int32_t comp)
523 {
524         static char buf[20];
525         const struct compression_types *ct;
526
527         if (comp == MT_COMP_DISABLED)
528                 return "disabled";
529         else if (comp == MT_COMP_UNSUPP)
530                 return "unsupported";
531
532         for (ct = comp_types; ct->name; ct++)
533                 if (ct->comp_number == comp)
534                         break;
535
536         if (ct->comp_number == 0xf0f0f0f0) {
537                 sprintf(buf, "0x%x", comp);
538                 return(buf);
539         } else
540                 return(ct->name);
541 }
542
543 static u_int32_t
544 stringtocomp(const char *s)
545 {
546         const struct compression_types *ct;
547         size_t l = strlen(s);
548
549         for (ct = comp_types; ct->name; ct++)
550                 if (strncasecmp(ct->name, s, l) == 0)
551                         break;
552
553         return(ct->comp_number);
554 }
555
556 static void
557 st_status(struct mtget *bp)
558 {
559         printf("Mode      Density              Blocksize      bpi      "
560                "Compression\n"
561                "Current:  %-17s    %-12s   %-7d  %s\n"
562                "---------available modes---------\n"
563                "0:        %-17s    %-12s   %-7d  %s\n"
564                "1:        %-17s    %-12s   %-7d  %s\n"
565                "2:        %-17s    %-12s   %-7d  %s\n"
566                "3:        %-17s    %-12s   %-7d  %s\n",
567                denstostring(bp->mt_density), getblksiz(bp->mt_blksiz),
568                denstobp(bp->mt_density, TRUE), comptostring(bp->mt_comp),
569                denstostring(bp->mt_density0), getblksiz(bp->mt_blksiz0),
570                denstobp(bp->mt_density0, TRUE), comptostring(bp->mt_comp0),
571                denstostring(bp->mt_density1), getblksiz(bp->mt_blksiz1),
572                denstobp(bp->mt_density1, TRUE), comptostring(bp->mt_comp1),
573                denstostring(bp->mt_density2), getblksiz(bp->mt_blksiz2),
574                denstobp(bp->mt_density2, TRUE), comptostring(bp->mt_comp2),
575                denstostring(bp->mt_density3), getblksiz(bp->mt_blksiz3),
576                denstobp(bp->mt_density3, TRUE), comptostring(bp->mt_comp3));
577
578         if (bp->mt_dsreg != MTIO_DSREG_NIL) {
579                 auto char foo[32];
580                 const char sfmt[] = "Current Driver State: %s.\n";
581                 printf("---------------------------------\n");
582                 switch (bp->mt_dsreg) {
583                 case MTIO_DSREG_REST:
584                         printf(sfmt, "at rest");      
585                         break;
586                 case MTIO_DSREG_RBSY:    
587                         printf(sfmt, "Communicating with drive");
588                         break;
589                 case MTIO_DSREG_WR:
590                         printf(sfmt, "Writing");
591                         break;
592                 case MTIO_DSREG_FMK:
593                         printf(sfmt, "Writing Filemarks");
594                         break;
595                 case MTIO_DSREG_ZER:
596                         printf(sfmt, "Erasing");
597                         break;
598                 case MTIO_DSREG_RD:
599                         printf(sfmt, "Reading");
600                         break;
601                 case MTIO_DSREG_FWD:
602                         printf(sfmt, "Spacing Forward");
603                         break;
604                 case MTIO_DSREG_REV:     
605                         printf(sfmt, "Spacing Reverse");
606                         break;
607                 case MTIO_DSREG_POS:
608                         printf(sfmt,
609                             "Hardware Positioning (direction unknown)");
610                         break;
611                 case MTIO_DSREG_REW:
612                         printf(sfmt, "Rewinding");
613                         break;
614                 case MTIO_DSREG_TEN:
615                         printf(sfmt, "Retensioning");
616                         break;
617                 case MTIO_DSREG_UNL:
618                         printf(sfmt, "Unloading");
619                         break;
620                 case MTIO_DSREG_LD:
621                         printf(sfmt, "Loading");
622                         break;
623                 default:
624                         (void) sprintf(foo, "Unknown state 0x%x", bp->mt_dsreg);
625                         printf(sfmt, foo);
626                         break;
627                 }
628         }
629         if (bp->mt_resid == 0 && bp->mt_fileno == (daddr_t) -1 &&
630             bp->mt_blkno == (daddr_t) -1)
631                 return;
632         printf("---------------------------------\n");
633         printf("File Number: %d\tRecord Number: %d\tResidual Count %d\n",
634             bp->mt_fileno, bp->mt_blkno, bp->mt_resid);
635 }
636
637 static void
638 warn_eof(void)
639 {
640         fprintf(stderr,
641                 "The \"eof\" command has been disabled.\n"
642                 "Use \"weof\" if you really want to write end-of-file marks,\n"
643                 "or \"eom\" if you rather want to skip to the end of "
644                 "recorded medium.\n");
645         exit(1);
646 }