"Fossies" - the Fresh Open Source Software Archive 
Member "schily-2021-09-18/mt/mt.c" (20 Aug 2021, 15409 Bytes) of package /linux/privat/schily-2021-09-18.tar.bz2:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /* @(#)mt.c 1.32 21/08/20 Copyright 2000-2021 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)mt.c 1.32 21/08/20 Copyright 2000-2021 J. Schilling";
6 #endif
7 /*
8 * Magnetic tape manipulation program
9 *
10 * Copyright (c) 2000-2021 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 #include <schily/mconfig.h>
27
28 /*
29 * XXX Until we find a better way, the next definitions must be in sync
30 * XXX with the definitions in librmt/remote.c
31 */
32 #if !defined(HAVE_FORK) || !defined(HAVE_SOCKETPAIR) || !defined(HAVE_DUP2)
33 #undef USE_RCMD_RSH
34 #endif
35 #if !defined(HAVE_GETSERVBYNAME)
36 #undef USE_REMOTE /* Cannot get rcmd() port # */
37 #endif
38 #if (!defined(HAVE_NETDB_H) || !defined(HAVE_RCMD)) && !defined(USE_RCMD_RSH)
39 #undef USE_REMOTE /* There is no rcmd() */
40 #endif
41
42 #include <schily/stdio.h>
43 #include <schily/stdlib.h>
44 #include <schily/unistd.h>
45 #include <schily/string.h>
46 #include <schily/utypes.h>
47 #include <schily/fcntl.h>
48 #include <schily/ioctl.h>
49 #include <schily/errno.h>
50
51 #define GT_COMERR /* #define comerr gtcomerr */
52 #define GT_ERROR /* #define error gterror */
53 #include <schily/schily.h>
54 #include <schily/standard.h>
55 /*#undef HAVE_SYS_MTIO_H*/
56 #include <schily/mtio.h>
57 #include <schily/librmt.h>
58 #include <schily/nlsdefs.h>
59
60 LOCAL BOOL help;
61 LOCAL BOOL prvers;
62 LOCAL BOOL wready;
63 LOCAL int debug;
64
65 LOCAL struct mtop mt_op;
66 LOCAL struct rmtget mt_status;
67
68 #ifndef HAVE_MTGET_TYPE
69 #ifdef HAVE_MTGET_MODEL
70 #define HAVE_MTGET_TYPE
71 #define mt_type mt_model
72 #endif
73 #endif
74
75 #define NO_ASF 1000
76 #define NO_NBSF 1001
77 #ifndef MTASF
78 # define MTASF NO_ASF
79 #endif
80 #ifndef MTNBSF
81 # define MTNBSF NO_NBSF
82 #endif
83
84 #define MTC_NONE 0 /* No flags defined */
85 #define MTC_RW 0 /* This command writes to the tape */
86 #define MTC_RDO 1 /* This command does not write */
87 #define MTC_CNT 2 /* This command uses the count arg */
88 #define MTC_NDEL 4 /* Open the tape drive with O_NDELAY */
89
90
91 LOCAL struct mt_cmds {
92 char *mtc_name; /* The name of the command */
93 char *mtc_text; /* Description of the command */
94 int mtc_opcode; /* The opcode for mtio */
95 int mtc_flags; /* Flags for this command */
96 } cmds[] = {
97 #ifdef MTWEOF
98 { "weof", "write EOF mark", MTWEOF, MTC_RW|MTC_CNT },
99 { "eof", "write EOF mark", MTWEOF, MTC_RW|MTC_CNT },
100 #endif
101 #ifdef MTFSF
102 { "fsf", "forward skip FILE mark", MTFSF, MTC_RDO|MTC_CNT },
103 #endif
104 #ifdef MTBSF
105 { "bsf", "backward skip FILE mark", MTBSF, MTC_RDO|MTC_CNT },
106 #endif
107 { "asf", "absolute FILE mark pos", MTASF, MTC_RDO|MTC_CNT },
108 #ifdef MTFSR
109 { "fsr", "forward skip record", MTFSR, MTC_RDO|MTC_CNT },
110 #endif
111 #ifdef MTBSR
112 { "bsr", "backward skip record", MTBSR, MTC_RDO|MTC_CNT },
113 #endif
114 #ifdef MTREW
115 { "rewind", "rewind tape", MTREW, MTC_RDO },
116 #endif
117 #ifdef MTOFFL
118 { "offline", "rewind and unload", MTOFFL, MTC_RDO },
119 { "rewoffl", "rewind and unload", MTOFFL, MTC_RDO },
120 #endif
121 #ifdef MTNOP
122 { "status", "get tape status", MTNOP, MTC_RDO },
123 #endif
124 { "nop", "no operation", MTNOP, MTC_RDO },
125 #ifdef MTRETEN
126 { "retension", "retension tape cartridge", MTRETEN, MTC_RDO },
127 #endif
128 #ifdef MTERASE
129 { "erase", "erase tape", MTERASE, MTC_RW },
130 #endif
131 #ifdef MTEOM
132 { "eom", "position to EOM", MTEOM, MTC_RDO },
133 #endif
134
135 #if MTNBSF != NO_NBSF
136 { "nbsf", "backward skip FILE mark", MTNBSF, MTC_RDO|MTC_CNT },
137 #endif
138
139 #ifdef MTLOAD
140 { "load", "load tape", MTLOAD, MTC_RDO|MTC_NDEL },
141 #endif
142
143 { NULL, NULL, 0, MTC_NONE }
144 };
145
146 LOCAL void usage __PR((int ex));
147 EXPORT int main __PR((int ac, char *av[]));
148 LOCAL void mtstatus __PR((struct rmtget *sp));
149 LOCAL char *print_key __PR((Llong key));
150 LOCAL int openremote __PR((char *tape));
151 LOCAL int opentape __PR((char *tape, struct mt_cmds *cp));
152 LOCAL int mtioctl __PR((int cmd, caddr_t arg));
153
154 LOCAL void
155 usage(ex)
156 int ex;
157 {
158 struct mt_cmds *cp;
159 int i;
160
161 error("Usage: mt [ -f device ] [options] command [ count ]\n");
162 error("Options:\n");
163 error("\t-help\t\tprint this online help\n");
164 error("\t-version\tprint version number\n");
165 error("\t-wready\t\twait for the tape to become ready before doing command\n");
166 error("\n");
167 error("Commands are:\n");
168 for (cp = cmds; cp->mtc_name != NULL; cp++) {
169 error("%s%n", cp->mtc_name, &i);
170 error("%*s%s\n", 14-i, "", cp->mtc_text);
171 }
172 exit(ex);
173 }
174
175 LOCAL char opts[] = "f*,t*,version,help,h,debug,wready";
176
177 int
178 main(ac, av)
179 int ac;
180 char *av[];
181 {
182 int cac;
183 char * const *cav;
184 char *tape = NULL;
185 char *cmd = "BADCMD";
186 int count = 1;
187 struct mt_cmds *cp;
188
189 save_args(ac, av);
190
191 (void) setlocale(LC_ALL, "");
192
193 #ifdef USE_NLS
194 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
195 #define TEXT_DOMAIN "mt" /* Use this only if it weren't */
196 #endif
197 { char *dir;
198 dir = searchfileinpath("share/locale", F_OK,
199 SIP_ANY_FILE|SIP_NO_PATH, NULL);
200 if (dir)
201 (void) bindtextdomain(TEXT_DOMAIN, dir);
202 else
203 #if defined(PROTOTYPES) && defined(INS_BASE)
204 (void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
205 #else
206 (void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
207 #endif
208 (void) textdomain(TEXT_DOMAIN);
209 }
210 #endif /* USE_NLS */
211
212 cac = --ac;
213 cav = ++av;
214
215 if (getallargs(&cac, &cav, opts,
216 &tape, &tape,
217 &prvers,
218 &help, &help,
219 &debug,
220 &wready) < 0) {
221 errmsgno(EX_BAD, "Bad Option: '%s'.\n", cav[0]);
222 usage(EX_BAD);
223 }
224 if (help) usage(0);
225 if (prvers) {
226 gtprintf("mt %s %s (%s-%s-%s)\n\n", "1.32", "2021/08/20", HOST_CPU, HOST_VENDOR, HOST_OS);
227 gtprintf("Copyright (C) 2000-2021 %s\n", _("Jörg Schilling"));
228 gtprintf("This is free software; see the source for copying conditions. There is NO\n");
229 gtprintf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
230 exit(0);
231 }
232
233 if (tape == NULL && (tape = getenv("TAPE")) == NULL) {
234 #ifdef DEFTAPE
235 tape = DEFTAPE;
236 #else
237 errmsgno(EX_BAD, "No default tape defined.\n");
238 usage(EX_BAD);
239 /* NOTREACHED */
240 #endif
241 }
242
243 cac = ac;
244 cav = av;
245 if (getfiles(&cac, &cav, opts) == 0) {
246 errmsgno(EX_BAD, "Missing args.\n");
247 usage(EX_BAD);
248 } else {
249 cmd = cav[0];
250 cav++;
251 cac--;
252 }
253 if (getfiles(&cac, &cav, opts) > 0) {
254 if (*astoi(cav[0], &count) != '\0') {
255 errmsgno(EX_BAD, "Not a number: '%s'.\n", cav[0]);
256 usage(EX_BAD);
257 }
258 if (count < 0) {
259 comerrno(EX_BAD, "negative file number or repeat count\n");
260 /* NOTREACHED */
261 }
262 cav++;
263 cac--;
264 }
265 if (getfiles(&cac, &cav, opts) > 0) {
266 errmsgno(EX_BAD, "Too many args.\n");
267 usage(EX_BAD);
268 }
269
270 for (cp = cmds; cp->mtc_name != NULL; cp++) {
271 if (strncmp(cmd, cp->mtc_name, strlen(cmd)) == 0)
272 break;
273 }
274 if (cp->mtc_name == NULL) {
275 comerrno(EX_BAD, "Unknown command: %s\n", cmd);
276 /* NOTREACHED */
277 }
278 #ifdef DEBUG
279 error("cmd: %s opcode: %d %s %s\n",
280 cp->mtc_name, cp->mtc_opcode,
281 (cp->mtc_flags & MTC_RDO) != 0 ? "RO":"RW",
282 (cp->mtc_flags & MTC_CNT) != 0 ? "usecount":"");
283 #endif
284
285 if ((cp->mtc_flags & MTC_CNT) == 0)
286 count = 1;
287
288 #ifdef USE_REMOTE
289 rmtdebug(debug);
290 (void)openremote(tape); /* This needs super user privilleges */
291 #endif
292 #ifdef HAVE_SETREUID
293 if (setreuid(-1, getuid()) < 0)
294 #else
295 #ifdef HAVE_SETEUID
296 if (seteuid(getuid()) < 0)
297 #else
298 if (setuid(getuid()) < 0)
299 #endif
300 #endif
301 comerr("Panic cannot set back effective uid.\n");
302
303 if (opentape(tape, cp) < 0) {
304 if (geterrno() == EIO) {
305 comerrno(EX_BAD, "'%s': no tape loaded or drive offline.\n",
306 tape);
307 } else if ((cp->mtc_flags & MTC_RDO) == 0 &&
308 geterrno() == EACCES) {
309 comerr("Cannot open '%s': tape may be write protected.\n", tape);
310 } else {
311 comerr("Cannot open '%s'.\n", tape);
312 }
313 /* NOTREACHED */
314 }
315
316 #ifdef DEBUG
317 error("Tape: %s cmd : %s (%s) count: %d\n", tape, cmd, cp->mtc_name, count);
318 #endif
319
320 if (cp->mtc_opcode == MTNOP) {
321 if (strcmp(cp->mtc_name, "nop")) {
322 /*
323 * Status ioctl
324 */
325 if (mtioctl(MTIOCGET, (caddr_t)&mt_status) < 0) {
326 comerr("Cannot get mt status from '%s'.\n", tape);
327 /* NOTREACHED */
328 }
329 mtstatus(&mt_status);
330 }
331 #if MTASF == NO_ASF
332 } else if (cp->mtc_opcode == MTASF) {
333 (void)mtioctl(MTIOCGET, (caddr_t)&mt_status);
334 if (mtioctl(MTIOCGET, (caddr_t)&mt_status) < 0) {
335 comerr("Cannot get mt status from '%s'.\n", tape);
336 /* NOTREACHED */
337 }
338 /*
339 * If the device does not support to report the current file
340 * tape file position - rewind the tape, and space forward.
341 */
342 #ifndef MTF_ASF
343 if (1) {
344 #else
345 if (!(mt_status.mt_flags & MTF_ASF) || MTNBSF == NO_NBSF) {
346 #endif
347 mt_status.mt_fileno = 0;
348 mt_op.mt_count = 1;
349 mt_op.mt_op = MTREW;
350 if (mtioctl(MTIOCTOP, (caddr_t)&mt_op) < 0) {
351 comerr("%s %s %d failed\n", tape, cp->mtc_name,
352 count);
353 /* NOTREACHED */
354 }
355 }
356 if (count < mt_status.mt_fileno) {
357 mt_op.mt_op = MTNBSF;
358 mt_op.mt_count = mt_status.mt_fileno - count;
359 /*printf("mt: bsf= %lld\n", (Llong)mt_op.mt_count);*/
360 } else {
361 mt_op.mt_op = MTFSF;
362 mt_op.mt_count = count - mt_status.mt_fileno;
363 /*printf("mt: fsf= %lld\n", (Llong)mt_op.mt_count);*/
364 }
365 if (mtioctl(MTIOCTOP, (caddr_t)&mt_op) < 0) {
366 if (mtioctl(MTIOCTOP, (caddr_t)&mt_op) < 0) {
367 comerr("%s %s %d failed\n", tape, cp->mtc_name,
368 count);
369 /* NOTREACHED */
370 }
371 }
372 #endif
373 } else {
374 /*
375 * Regular magnetic tape ioctl
376 */
377 mt_op.mt_op = cp->mtc_opcode;
378 mt_op.mt_count = count;
379 if (mtioctl(MTIOCTOP, (caddr_t)&mt_op) < 0) {
380 comerr("%s %s %lld failed\n", tape, cp->mtc_name,
381 (Llong)mt_op.mt_count);
382 /* NOTREACHED */
383 }
384 }
385 return (0);
386 }
387
388 /*
389 * If we try to make this portable, we need a way to initialize it
390 * in an OS independant way.
391 * Don't use it for now.
392 */
393 /*LOCAL */
394 struct tape_info {
395 short t_type; /* type of magnetic tape device */
396 char *t_name; /* name for prining */
397 char *t_dsbits; /* "drive status" register */
398 char *t_erbits; /* "error" register */
399 };
400 #ifdef XXX
401 tapes[] = {
402 { MT_ISTS, "ts11", 0, TSXS0_BITS },
403 { 0 }
404 };
405 #endif
406
407 /*
408 * Interpret the status buffer returned
409 */
410 LOCAL void
411 mtstatus(sp)
412 register struct rmtget *sp;
413 {
414 register struct tape_info *mt = NULL;
415
416 #ifdef XXX
417 #ifdef HAVE_MTGET_TYPE
418 for (mt = tapes; mt->t_type; mt++)
419 if (mt->t_type == sp->mt_type)
420 break;
421 #endif
422 #endif
423
424 #if defined(MTF_SCSI)
425
426 if ((sp->mt_xflags & RMT_FLAGS) && (sp->mt_flags & MTF_SCSI)) {
427 /*
428 * Handle SCSI tape drives specially.
429 */
430 if (sp->mt_xflags & RMT_TYPE) {
431 if (mt != NULL && mt->t_type == sp->mt_type)
432 gtprintf("%s tape drive:\n", mt->t_name);
433 else
434 gtprintf("%s tape drive:\n", "SCSI");
435 } else {
436 gtprintf("Unknown SCSI tape drive:\n");
437 }
438 printf(" sense key(0x%llx)= %s residual= %lld ",
439 sp->mt_erreg, print_key(sp->mt_erreg), sp->mt_resid);
440 gtprintf("retries= %lld\n", sp->mt_dsreg);
441 } else
442 #endif /* MTF_SCSI */
443 {
444 /*
445 * Handle other drives below.
446 */
447 if (sp->mt_xflags & RMT_TYPE) {
448 if (mt == NULL || mt->t_type == 0) {
449 gtprintf("Unknown tape drive type (0x%llX):\n", (Ullong)sp->mt_type);
450 } else {
451 gtprintf("%s tape drive:\n", mt->t_name);
452 }
453 } else {
454 gtprintf("Unknown tape drive:\n");
455 }
456 if (sp->mt_xflags & RMT_RESID)
457 gtprintf(" residual= %lld", sp->mt_resid);
458 /*
459 * If we implement better support for specific OS,
460 * then we may want to implement something like the
461 * *BSD kernel %b printf format (e.g. printreg).
462 */
463 if (sp->mt_xflags & RMT_DSREG)
464 printf (" ds = %llX", (Ullong)sp->mt_dsreg);
465
466 if (sp->mt_xflags & RMT_ERREG)
467 printf (" er = %llX", sp->mt_erreg);
468 putchar('\n');
469 }
470 gtprintf(" file no= %lld block no= %lld\n",
471 (sp->mt_xflags & RMT_FILENO)?
472 sp->mt_fileno:
473 (Llong)-1,
474 (sp->mt_xflags & RMT_BLKNO)?
475 sp->mt_blkno:
476 (Llong)-1);
477
478 if (sp->mt_xflags & RMT_BF)
479 gtprintf(" optimum blocking factor= %ld\n", sp->mt_bf);
480
481 if (sp->mt_xflags & RMT_FLAGS)
482 gtprintf(" flags= 0x%llX\n", sp->mt_flags);
483 }
484
485 static char *sense_keys[] = {
486 "No Additional Sense", /* 0x00 */
487 "Recovered Error", /* 0x01 */
488 "Not Ready", /* 0x02 */
489 "Medium Error", /* 0x03 */
490 "Hardware Error", /* 0x04 */
491 "Illegal Request", /* 0x05 */
492 "Unit Attention", /* 0x06 */
493 "Data Protect", /* 0x07 */
494 "Blank Check", /* 0x08 */
495 "Vendor Unique", /* 0x09 */
496 "Copy Aborted", /* 0x0a */
497 "Aborted Command", /* 0x0b */
498 "Equal", /* 0x0c */
499 "Volume Overflow", /* 0x0d */
500 "Miscompare", /* 0x0e */
501 "Reserved" /* 0x0f */
502 };
503
504 LOCAL char *
505 print_key(key)
506 Llong key;
507 {
508 static char keys[32];
509
510 if (key >= 0 && key < (sizeof(sense_keys)/sizeof(sense_keys[0])))
511 return (sense_keys[key]);
512 js_snprintf(keys, sizeof(keys), "Unknown Key: %lld", key);
513 return (keys);
514 }
515
516 /*--------------------------------------------------------------------------*/
517 LOCAL int isremote;
518 LOCAL int remfd = -1;
519 LOCAL int mtfd;
520 LOCAL char *remfn;
521
522 #ifdef USE_REMOTE
523 LOCAL int
524 openremote(tape)
525 char *tape;
526 {
527 char host[128];
528
529 if ((remfn = rmtfilename(tape)) != NULL) {
530 rmthostname(host, sizeof(host), tape);
531 isremote++;
532
533 if (debug)
534 errmsgno(EX_BAD, "Remote: %s Host: %s file: %s\n",
535 tape, host, remfn);
536
537 if ((remfd = rmtgetconn(host, 4096, 0)) < 0)
538 comerrno(EX_BAD, "Cannot get connection to '%s'.\n",
539 /* errno not valid !! */ host);
540 }
541 return (isremote);
542 }
543 #endif
544
545 LOCAL int
546 opentape(tape, cp)
547 char *tape;
548 register struct mt_cmds *cp;
549 {
550 int ret;
551 int n = 0;
552 int oflag;
553
554 oflag = (cp->mtc_flags & MTC_RDO) ? O_RDONLY : O_RDWR;
555 #ifdef O_NDELAY
556 if (cp->mtc_flags & MTC_NDEL)
557 oflag |= O_NDELAY;
558 #endif
559
560 retry:
561 ret = 0;
562 if (isremote) {
563 #ifdef USE_REMOTE
564 if (rmtopen(remfd, remfn, oflag) < 0)
565 ret = -1;
566 #else
567 comerrno(EX_BAD, "Remote tape support not present.\n");
568 #endif
569 } else if ((mtfd = open(tape, oflag)) < 0) {
570 ret = -1;
571 }
572 if (wready && n++ < 120 && ret < 0 &&
573 (geterrno() == EIO || geterrno() == EBUSY)) {
574 sleep(1);
575 goto retry;
576 }
577 return (ret);
578 }
579
580 LOCAL int
581 mtioctl(cmd, arg)
582 int cmd;
583 caddr_t arg;
584 {
585 int ret = -1;
586 struct rmtget *mtp;
587 struct mtop *mop;
588
589 if (isremote) {
590 #ifdef USE_REMOTE
591 switch (cmd) {
592
593 case MTIOCGET:
594 ret = rmtxstatus(remfd, (struct rmtget *)arg);
595 if (ret < 0)
596 return (ret);
597
598 mtp = (struct rmtget *)arg;
599 /*#define DEBUG*/
600 #ifdef DEBUG
601 error("type: %llX ds: %llX er: %llX resid: %lld fileno: %lld blkno: %lld flags: %llX bf: %ld\n",
602 mtp->mt_type, mtp->mt_dsreg, mtp->mt_erreg, mtp->mt_resid, mtp->mt_fileno,
603 mtp->mt_blkno, mtp->mt_flags, mtp->mt_bf);
604 #endif
605 break;
606 case MTIOCTOP:
607 mop = (struct mtop *)arg;
608 ret = rmtioctl(remfd, mop->mt_op, mop->mt_count);
609 break;
610 default:
611 comerrno(ENOTTY, "Invalid mtioctl.\n");
612 /* NOTREACHED */
613 }
614 #else
615 comerrno(EX_BAD, "Remote tape support not present.\n");
616 #endif
617 } else {
618 #ifdef HAVE_IOCTL
619 if (cmd == MTIOCGET) {
620 struct mtget mtget;
621
622 ret = ioctl(mtfd, cmd, &mtget);
623 if (ret >= 0) {
624 if (_mtg2rmtg((struct rmtget *)arg, &mtget) < 0)
625 ret = -1;
626 }
627 } else
628 ret = ioctl(mtfd, cmd, arg);
629 #else
630 ret = -1;
631 #ifdef ENOSYS
632 seterrno(ENOSYS);
633 #else
634 seterrno(EINVAL);
635 #endif
636 #endif
637 }
638 return (ret);
639 }