386BSD 0.0 development
[unix-history] / usr / src / sbin / restore / tape.c
CommitLineData
6beb798a
WJ
1/*
2 * Copyright (c) 1983 The Regents of the University of California.
3 * 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 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char sccsid[] = "@(#)tape.c 5.21 (Berkeley) 2/22/91";
36#endif /* not lint */
37
38#include "restore.h"
39#include <protocols/dumprestore.h>
40#include <sys/ioctl.h>
41#include <sys/mtio.h>
42#include <sys/file.h>
43#include <setjmp.h>
44#include <sys/stat.h>
45#include "pathnames.h"
46
47static long fssize = MAXBSIZE;
48static int mt = -1;
49static int pipein = 0;
50static char magtape[BUFSIZ];
51static int bct;
52static int numtrec;
53static char *tbf;
54static union u_spcl endoftapemark;
55static long blksread;
56static long tapesread;
57static jmp_buf restart;
58static int gettingfile = 0; /* restart has a valid frame */
59
60static int ofile;
61static char *map;
62static char lnkbuf[MAXPATHLEN + 1];
63static int pathlen;
64
65int Bcvt; /* Swap Bytes (for CCI or sun) */
66static int Qcvt; /* Swap quads (for sun) */
67u_long swabl();
68/*
69 * Set up an input source
70 */
71setinput(source)
72 char *source;
73{
74 extern int errno;
75#ifdef RRESTORE
76 char *host, *tape;
77#endif RRESTORE
78 char *strerror();
79
80 flsht();
81 if (bflag)
82 newtapebuf(ntrec);
83 else
84 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
85 terminal = stdin;
86#ifdef RRESTORE
87 host = source;
88 tape = index(host, ':');
89 if (tape == 0) {
90nohost:
91 msg("need keyletter ``f'' and device ``host:tape''\n");
92 done(1);
93 }
94 *tape++ = '\0';
95 (void) strcpy(magtape, tape);
96 if (rmthost(host) == 0)
97 done(1);
98 setuid(getuid()); /* no longer need or want root privileges */
99#else
100 if (strcmp(source, "-") == 0) {
101 /*
102 * Since input is coming from a pipe we must establish
103 * our own connection to the terminal.
104 */
105 terminal = fopen(_PATH_TTY, "r");
106 if (terminal == NULL) {
107 (void)fprintf(stderr, "Cannot open %s: %s\n",
108 _PATH_TTY, strerror(errno));
109 terminal = fopen(_PATH_DEVNULL, "r");
110 if (terminal == NULL) {
111 (void)fprintf(stderr, "Cannot open %s: %s\n",
112 _PATH_DEVNULL, strerror(errno));
113 done(1);
114 }
115 }
116 pipein++;
117 }
118 (void) strcpy(magtape, source);
119#endif RRESTORE
120}
121
122newtapebuf(size)
123 long size;
124{
125 static tbfsize = -1;
126
127 ntrec = size;
128 if (size <= tbfsize)
129 return;
130 if (tbf != NULL)
131 free(tbf);
132 tbf = (char *)malloc(size * TP_BSIZE);
133 if (tbf == NULL) {
134 fprintf(stderr, "Cannot allocate space for tape buffer\n");
135 done(1);
136 }
137 tbfsize = size;
138}
139
140/*
141 * Verify that the tape drive can be accessed and
142 * that it actually is a dump tape.
143 */
144setup()
145{
146 int i, j, *ip;
147 struct stat stbuf;
148 extern int xtrmap(), xtrmapskip();
149
150 vprintf(stdout, "Verify tape and initialize maps\n");
151#ifdef RRESTORE
152 if ((mt = rmtopen(magtape, 0)) < 0)
153#else
154 if (pipein)
155 mt = 0;
156 else if ((mt = open(magtape, 0)) < 0)
157#endif
158 {
159 perror(magtape);
160 done(1);
161 }
162 volno = 1;
163 setdumpnum();
164 flsht();
165 if (!pipein && !bflag)
166 findtapeblksize();
167 if (gethead(&spcl) == FAIL) {
168 bct--; /* push back this block */
169 cvtflag++;
170 if (gethead(&spcl) == FAIL) {
171 fprintf(stderr, "Tape is not a dump tape\n");
172 done(1);
173 }
174 fprintf(stderr, "Converting to new file system format.\n");
175 }
176 if (pipein) {
177 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
178 endoftapemark.s_spcl.c_type = TS_END;
179 ip = (int *)&endoftapemark;
180 j = sizeof(union u_spcl) / sizeof(int);
181 i = 0;
182 do
183 i += *ip++;
184 while (--j);
185 endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
186 }
187 if (vflag || command == 't')
188 printdumpinfo();
189 dumptime = spcl.c_ddate;
190 dumpdate = spcl.c_date;
191 if (stat(".", &stbuf) < 0) {
192 perror("cannot stat .");
193 done(1);
194 }
195 if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
196 fssize = stbuf.st_blksize;
197 if (((fssize - 1) & fssize) != 0) {
198 fprintf(stderr, "bad block size %d\n", fssize);
199 done(1);
200 }
201 if (checkvol(&spcl, (long)1) == FAIL) {
202 fprintf(stderr, "Tape is not volume 1 of the dump\n");
203 done(1);
204 }
205 if (readhdr(&spcl) == FAIL)
206 panic("no header after volume mark!\n");
207 findinode(&spcl);
208 if (checktype(&spcl, TS_CLRI) == FAIL) {
209 fprintf(stderr, "Cannot find file removal list\n");
210 done(1);
211 }
212 maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
213 dprintf(stdout, "maxino = %d\n", maxino);
214 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
215 if (map == (char *)NIL)
216 panic("no memory for file removal list\n");
217 clrimap = map;
218 curfile.action = USING;
219 getfile(xtrmap, xtrmapskip);
220 if (checktype(&spcl, TS_BITS) == FAIL) {
221 fprintf(stderr, "Cannot find file dump list\n");
222 done(1);
223 }
224 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
225 if (map == (char *)NULL)
226 panic("no memory for file dump list\n");
227 dumpmap = map;
228 curfile.action = USING;
229 getfile(xtrmap, xtrmapskip);
230}
231
232/*
233 * Prompt user to load a new dump volume.
234 * "Nextvol" is the next suggested volume to use.
235 * This suggested volume is enforced when doing full
236 * or incremental restores, but can be overrridden by
237 * the user when only extracting a subset of the files.
238 */
239getvol(nextvol)
240 long nextvol;
241{
242 long newvol;
243 long savecnt, i;
244 union u_spcl tmpspcl;
245# define tmpbuf tmpspcl.s_spcl
246 char buf[TP_BSIZE];
247 extern char *ctime();
248
249 if (nextvol == 1) {
250 tapesread = 0;
251 gettingfile = 0;
252 }
253 if (pipein) {
254 if (nextvol != 1)
255 panic("Changing volumes on pipe input?\n");
256 if (volno == 1)
257 return;
258 goto gethdr;
259 }
260 savecnt = blksread;
261again:
262 if (pipein)
263 done(1); /* pipes do not get a second chance */
264 if (command == 'R' || command == 'r' || curfile.action != SKIP)
265 newvol = nextvol;
266 else
267 newvol = 0;
268 while (newvol <= 0) {
269 if (tapesread == 0) {
270 fprintf(stderr, "%s%s%s%s%s",
271 "You have not read any tapes yet.\n",
272 "Unless you know which volume your",
273 " file(s) are on you should start\n",
274 "with the last volume and work",
275 " towards towards the first.\n");
276 } else {
277 fprintf(stderr, "You have read volumes");
278 strcpy(tbf, ": ");
279 for (i = 1; i < 32; i++)
280 if (tapesread & (1 << i)) {
281 fprintf(stderr, "%s%d", tbf, i);
282 strcpy(tbf, ", ");
283 }
284 fprintf(stderr, "\n");
285 }
286 do {
287 fprintf(stderr, "Specify next volume #: ");
288 (void) fflush(stderr);
289 (void) fgets(tbf, BUFSIZ, terminal);
290 } while (!feof(terminal) && tbf[0] == '\n');
291 if (feof(terminal))
292 done(1);
293 newvol = atoi(tbf);
294 if (newvol <= 0) {
295 fprintf(stderr,
296 "Volume numbers are positive numerics\n");
297 }
298 }
299 if (newvol == volno) {
300 tapesread |= 1 << volno;
301 return;
302 }
303 closemt();
304 fprintf(stderr, "Mount tape volume %d\n", newvol);
305 fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
306 fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
307 (void) fflush(stderr);
308 (void) fgets(tbf, BUFSIZ, terminal);
309 if (feof(terminal))
310 done(1);
311 if (!strcmp(tbf, "none\n")) {
312 curfile.name = "<name unknown>";
313 curfile.action = UNKNOWN;
314 curfile.dip = (struct dinode *)NIL;
315 curfile.ino = maxino;
316 if (gettingfile) {
317 gettingfile = 0;
318 longjmp(restart, 1);
319 }
320 }
321 if (tbf[0] != '\n') {
322 (void) strcpy(magtape, tbf);
323 magtape[strlen(magtape) - 1] = '\0';
324 }
325#ifdef RRESTORE
326 if ((mt = rmtopen(magtape, 0)) == -1)
327#else
328 if ((mt = open(magtape, 0)) == -1)
329#endif
330 {
331 fprintf(stderr, "Cannot open %s\n", magtape);
332 volno = -1;
333 goto again;
334 }
335gethdr:
336 volno = newvol;
337 setdumpnum();
338 flsht();
339 if (readhdr(&tmpbuf) == FAIL) {
340 fprintf(stderr, "tape is not dump tape\n");
341 volno = 0;
342 goto again;
343 }
344 if (checkvol(&tmpbuf, volno) == FAIL) {
345 fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
346 volno = 0;
347 goto again;
348 }
349 if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
350 fprintf(stderr, "Wrong dump date\n\tgot: %s",
351 ctime(&tmpbuf.c_date));
352 fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
353 volno = 0;
354 goto again;
355 }
356 tapesread |= 1 << volno;
357 blksread = savecnt;
358 if (curfile.action == USING) {
359 if (volno == 1)
360 panic("active file into volume 1\n");
361 return;
362 }
363 /*
364 * Skip up to the beginning of the next record
365 */
366 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
367 for (i = tmpbuf.c_count; i > 0; i--)
368 readtape(buf);
369 (void) gethead(&spcl);
370 findinode(&spcl);
371 if (gettingfile) {
372 gettingfile = 0;
373 longjmp(restart, 1);
374 }
375}
376
377/*
378 * handle multiple dumps per tape by skipping forward to the
379 * appropriate one.
380 */
381setdumpnum()
382{
383 struct mtop tcom;
384
385 if (dumpnum == 1 || volno != 1)
386 return;
387 if (pipein) {
388 fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
389 done(1);
390 }
391 tcom.mt_op = MTFSF;
392 tcom.mt_count = dumpnum - 1;
393#ifdef RRESTORE
394 rmtioctl(MTFSF, dumpnum - 1);
395#else
396 if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
397 perror("ioctl MTFSF");
398#endif
399}
400
401printdumpinfo()
402{
403 extern char *ctime();
404
405 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date));
406 fprintf(stdout, "Dumped from: %s",
407 (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
408 if (spcl.c_host[0] == '\0')
409 return;
410 fprintf(stderr, "Level %d dump of %s on %s:%s\n",
411 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
412 fprintf(stderr, "Label: %s\n", spcl.c_label);
413}
414
415extractfile(name)
416 char *name;
417{
418 int mode;
419 struct timeval timep[2];
420 struct entry *ep;
421 extern int xtrlnkfile(), xtrlnkskip();
422 extern int xtrfile(), xtrskip();
423
424 curfile.name = name;
425 curfile.action = USING;
426 timep[0].tv_sec = curfile.dip->di_atime;
427 timep[0].tv_usec = 0;
428 timep[1].tv_sec = curfile.dip->di_mtime;
429 timep[1].tv_usec = 0;
430 mode = curfile.dip->di_mode;
431 switch (mode & IFMT) {
432
433 default:
434 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
435 skipfile();
436 return (FAIL);
437
438 case IFSOCK:
439 vprintf(stdout, "skipped socket %s\n", name);
440 skipfile();
441 return (GOOD);
442
443 case IFDIR:
444 if (mflag) {
445 ep = lookupname(name);
446 if (ep == NIL || ep->e_flags & EXTRACT)
447 panic("unextracted directory %s\n", name);
448 skipfile();
449 return (GOOD);
450 }
451 vprintf(stdout, "extract file %s\n", name);
452 return (genliteraldir(name, curfile.ino));
453
454 case IFLNK:
455 lnkbuf[0] = '\0';
456 pathlen = 0;
457 getfile(xtrlnkfile, xtrlnkskip);
458 if (pathlen == 0) {
459 vprintf(stdout,
460 "%s: zero length symbolic link (ignored)\n", name);
461 return (GOOD);
462 }
463 return (linkit(lnkbuf, name, SYMLINK));
464
465 case IFCHR:
466 case IFBLK:
467 vprintf(stdout, "extract special file %s\n", name);
468 if (Nflag) {
469 skipfile();
470 return (GOOD);
471 }
472 if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
473 fprintf(stderr, "%s: ", name);
474 (void) fflush(stderr);
475 perror("cannot create special file");
476 skipfile();
477 return (FAIL);
478 }
479 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
480 (void) chmod(name, mode);
481 skipfile();
482 utimes(name, timep);
483 return (GOOD);
484
485 case IFREG:
486 vprintf(stdout, "extract file %s\n", name);
487 if (Nflag) {
488 skipfile();
489 return (GOOD);
490 }
491 if ((ofile = creat(name, 0666)) < 0) {
492 fprintf(stderr, "%s: ", name);
493 (void) fflush(stderr);
494 perror("cannot create file");
495 skipfile();
496 return (FAIL);
497 }
498 (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
499 (void) fchmod(ofile, mode);
500 getfile(xtrfile, xtrskip);
501 (void) close(ofile);
502 utimes(name, timep);
503 return (GOOD);
504 }
505 /* NOTREACHED */
506}
507
508/*
509 * skip over bit maps on the tape
510 */
511skipmaps()
512{
513
514 while (checktype(&spcl, TS_CLRI) == GOOD ||
515 checktype(&spcl, TS_BITS) == GOOD)
516 skipfile();
517}
518
519/*
520 * skip over a file on the tape
521 */
522skipfile()
523{
524 extern int null();
525
526 curfile.action = SKIP;
527 getfile(null, null);
528}
529
530/*
531 * Do the file extraction, calling the supplied functions
532 * with the blocks
533 */
534getfile(f1, f2)
535 int (*f2)(), (*f1)();
536{
537 register int i;
538 int curblk = 0;
539 off_t size = spcl.c_dinode.di_size;
540 static char clearedbuf[MAXBSIZE];
541 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
542 char junk[TP_BSIZE];
543
544 if (checktype(&spcl, TS_END) == GOOD)
545 panic("ran off end of tape\n");
546 if (ishead(&spcl) == FAIL)
547 panic("not at beginning of a file\n");
548 if (!gettingfile && setjmp(restart) != 0)
549 return;
550 gettingfile++;
551loop:
552 for (i = 0; i < spcl.c_count; i++) {
553 if (spcl.c_addr[i]) {
554 readtape(&buf[curblk++][0]);
555 if (curblk == fssize / TP_BSIZE) {
556 (*f1)(buf, size > TP_BSIZE ?
557 (long) (fssize) :
558 (curblk - 1) * TP_BSIZE + size);
559 curblk = 0;
560 }
561 } else {
562 if (curblk > 0) {
563 (*f1)(buf, size > TP_BSIZE ?
564 (long) (curblk * TP_BSIZE) :
565 (curblk - 1) * TP_BSIZE + size);
566 curblk = 0;
567 }
568 (*f2)(clearedbuf, size > TP_BSIZE ?
569 (long) TP_BSIZE : size);
570 }
571 if ((size -= TP_BSIZE) <= 0) {
572 for (i++; i < spcl.c_count; i++)
573 if (spcl.c_addr[i])
574 readtape(junk);
575 break;
576 }
577 }
578 if (readhdr(&spcl) == GOOD && size > 0) {
579 if (checktype(&spcl, TS_ADDR) == GOOD)
580 goto loop;
581 dprintf(stdout, "Missing address (header) block for %s\n",
582 curfile.name);
583 }
584 if (curblk > 0)
585 (*f1)(buf, (curblk * TP_BSIZE) + size);
586 findinode(&spcl);
587 gettingfile = 0;
588}
589
590/*
591 * The next routines are called during file extraction to
592 * put the data into the right form and place.
593 */
594xtrfile(buf, size)
595 char *buf;
596 long size;
597{
598
599 if (Nflag)
600 return;
601 if (write(ofile, buf, (int) size) == -1) {
602 fprintf(stderr, "write error extracting inode %d, name %s\n",
603 curfile.ino, curfile.name);
604 perror("write");
605 done(1);
606 }
607}
608
609xtrskip(buf, size)
610 char *buf;
611 long size;
612{
613
614#ifdef lint
615 buf = buf;
616#endif
617 if (lseek(ofile, size, 1) == (long)-1) {
618 fprintf(stderr, "seek error extracting inode %d, name %s\n",
619 curfile.ino, curfile.name);
620 perror("lseek");
621 done(1);
622 }
623}
624
625xtrlnkfile(buf, size)
626 char *buf;
627 long size;
628{
629
630 pathlen += size;
631 if (pathlen > MAXPATHLEN) {
632 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
633 curfile.name, lnkbuf, buf, pathlen);
634 done(1);
635 }
636 (void) strcat(lnkbuf, buf);
637}
638
639xtrlnkskip(buf, size)
640 char *buf;
641 long size;
642{
643
644#ifdef lint
645 buf = buf, size = size;
646#endif
647 fprintf(stderr, "unallocated block in symbolic link %s\n",
648 curfile.name);
649 done(1);
650}
651
652xtrmap(buf, size)
653 char *buf;
654 long size;
655{
656
657 bcopy(buf, map, size);
658 map += size;
659}
660
661xtrmapskip(buf, size)
662 char *buf;
663 long size;
664{
665
666#ifdef lint
667 buf = buf;
668#endif
669 panic("hole in map\n");
670 map += size;
671}
672
673null() {;}
674
675/*
676 * Do the tape i/o, dealing with volume changes
677 * etc..
678 */
679readtape(b)
680 char *b;
681{
682 register long i;
683 long rd, newvol;
684 int cnt;
685
686top:
687 if (bct < numtrec) {
688 bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
689 blksread++;
690 return;
691 }
692 for (i = 0; i < ntrec; i++)
693 ((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
694 if (numtrec == 0)
695 numtrec = ntrec;
696 cnt = ntrec*TP_BSIZE;
697 rd = 0;
698getmore:
699#ifdef RRESTORE
700 i = rmtread(&tbf[rd], cnt);
701#else
702 i = read(mt, &tbf[rd], cnt);
703#endif
704 /*
705 * Check for mid-tape short read error.
706 * If found, return rest of buffer.
707 */
708 if (numtrec < ntrec && i != 0) {
709 numtrec = ntrec;
710 goto top;
711 }
712 /*
713 * Handle partial block read.
714 */
715 if (i > 0 && i != ntrec*TP_BSIZE) {
716 if (pipein) {
717 rd += i;
718 cnt -= i;
719 if (cnt > 0)
720 goto getmore;
721 i = rd;
722 } else {
723 if (i % TP_BSIZE != 0)
724 panic("partial block read: %d should be %d\n",
725 i, ntrec * TP_BSIZE);
726 numtrec = i / TP_BSIZE;
727 }
728 }
729 /*
730 * Handle read error.
731 */
732 if (i < 0) {
733 fprintf(stderr, "Tape read error while ");
734 switch (curfile.action) {
735 default:
736 fprintf(stderr, "trying to set up tape\n");
737 break;
738 case UNKNOWN:
739 fprintf(stderr, "trying to resynchronize\n");
740 break;
741 case USING:
742 fprintf(stderr, "restoring %s\n", curfile.name);
743 break;
744 case SKIP:
745 fprintf(stderr, "skipping over inode %d\n",
746 curfile.ino);
747 break;
748 }
749 if (!yflag && !reply("continue"))
750 done(1);
751 i = ntrec*TP_BSIZE;
752 bzero(tbf, i);
753#ifdef RRESTORE
754 if (rmtseek(i, 1) < 0)
755#else
756 if (lseek(mt, i, 1) == (long)-1)
757#endif
758 {
759 perror("continuation failed");
760 done(1);
761 }
762 }
763 /*
764 * Handle end of tape.
765 */
766 if (i == 0) {
767 if (!pipein) {
768 newvol = volno + 1;
769 volno = 0;
770 numtrec = 0;
771 getvol(newvol);
772 readtape(b);
773 return;
774 }
775 if (rd % TP_BSIZE != 0)
776 panic("partial block read: %d should be %d\n",
777 rd, ntrec * TP_BSIZE);
778 bcopy((char *)&endoftapemark, &tbf[rd], (long)TP_BSIZE);
779 }
780 bct = 0;
781 bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
782 blksread++;
783}
784
785findtapeblksize()
786{
787 register long i;
788
789 for (i = 0; i < ntrec; i++)
790 ((struct s_spcl *)&tbf[i * TP_BSIZE])->c_magic = 0;
791 bct = 0;
792#ifdef RRESTORE
793 i = rmtread(tbf, ntrec * TP_BSIZE);
794#else
795 i = read(mt, tbf, ntrec * TP_BSIZE);
796#endif
797 if (i <= 0) {
798 perror("Tape read error");
799 done(1);
800 }
801 if (i % TP_BSIZE != 0) {
802 fprintf(stderr, "Tape block size (%d) %s (%d)\n",
803 i, "is not a multiple of dump block size", TP_BSIZE);
804 done(1);
805 }
806 ntrec = i / TP_BSIZE;
807 numtrec = ntrec;
808 vprintf(stdout, "Tape block size is %d\n", ntrec);
809}
810
811flsht()
812{
813
814 bct = ntrec+1;
815}
816
817closemt()
818{
819 if (mt < 0)
820 return;
821#ifdef RRESTORE
822 rmtclose();
823#else
824 (void) close(mt);
825#endif
826}
827
828checkvol(b, t)
829 struct s_spcl *b;
830 long t;
831{
832
833 if (b->c_volume != t)
834 return(FAIL);
835 return(GOOD);
836}
837
838readhdr(b)
839 struct s_spcl *b;
840{
841
842 if (gethead(b) == FAIL) {
843 dprintf(stdout, "readhdr fails at %d blocks\n", blksread);
844 return(FAIL);
845 }
846 return(GOOD);
847}
848
849/*
850 * read the tape into buf, then return whether or
851 * or not it is a header block.
852 */
853gethead(buf)
854 struct s_spcl *buf;
855{
856 long i;
857 union u_ospcl {
858 char dummy[TP_BSIZE];
859 struct s_ospcl {
860 long c_type;
861 long c_date;
862 long c_ddate;
863 long c_volume;
864 long c_tapea;
865 u_short c_inumber;
866 long c_magic;
867 long c_checksum;
868 struct odinode {
869 unsigned short odi_mode;
870 u_short odi_nlink;
871 u_short odi_uid;
872 u_short odi_gid;
873 long odi_size;
874 long odi_rdev;
875 char odi_addr[36];
876 long odi_atime;
877 long odi_mtime;
878 long odi_ctime;
879 } c_dinode;
880 long c_count;
881 char c_addr[256];
882 } s_ospcl;
883 } u_ospcl;
884
885 if (!cvtflag) {
886 readtape((char *)buf);
887 if (buf->c_magic != NFS_MAGIC) {
888 if (swabl(buf->c_magic) != NFS_MAGIC)
889 return (FAIL);
890 if (!Bcvt) {
891 vprintf(stdout, "Note: Doing Byte swapping\n");
892 Bcvt = 1;
893 }
894 }
895 if (checksum((int *)buf) == FAIL)
896 return (FAIL);
897 if (Bcvt)
898 swabst("8l4s31l", (char *)buf);
899 goto good;
900 }
901 readtape((char *)(&u_ospcl.s_ospcl));
902 bzero((char *)buf, (long)TP_BSIZE);
903 buf->c_type = u_ospcl.s_ospcl.c_type;
904 buf->c_date = u_ospcl.s_ospcl.c_date;
905 buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
906 buf->c_volume = u_ospcl.s_ospcl.c_volume;
907 buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
908 buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
909 buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
910 buf->c_magic = u_ospcl.s_ospcl.c_magic;
911 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
912 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
913 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
914 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
915 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
916 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
917 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
918 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
919 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
920 buf->c_count = u_ospcl.s_ospcl.c_count;
921 bcopy(u_ospcl.s_ospcl.c_addr, buf->c_addr, (long)256);
922 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
923 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
924 return(FAIL);
925 buf->c_magic = NFS_MAGIC;
926
927good:
928 if (buf->c_dinode.di_size == 0 &&
929 (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
930 if (buf->c_dinode.di_qsize.val[0] ||
931 buf->c_dinode.di_qsize.val[1]) {
932 printf("Note: Doing Quad swapping\n");
933 Qcvt = 1;
934 }
935 }
936 if (Qcvt) {
937 i = buf->c_dinode.di_qsize.val[1];
938 buf->c_dinode.di_qsize.val[1] = buf->c_dinode.di_qsize.val[0];
939 buf->c_dinode.di_qsize.val[0] = i;
940 }
941 switch (buf->c_type) {
942
943 case TS_CLRI:
944 case TS_BITS:
945 /*
946 * Have to patch up missing information in bit map headers
947 */
948 buf->c_inumber = 0;
949 buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
950 for (i = 0; i < buf->c_count; i++)
951 buf->c_addr[i]++;
952 break;
953
954 case TS_TAPE:
955 case TS_END:
956 buf->c_inumber = 0;
957 break;
958
959 case TS_INODE:
960 case TS_ADDR:
961 break;
962
963 default:
964 panic("gethead: unknown inode type %d\n", buf->c_type);
965 break;
966 }
967 if (dflag)
968 accthdr(buf);
969 return(GOOD);
970}
971
972/*
973 * Check that a header is where it belongs and predict the next header
974 */
975accthdr(header)
976 struct s_spcl *header;
977{
978 static ino_t previno = 0x7fffffff;
979 static int prevtype;
980 static long predict;
981 long blks, i;
982
983 if (header->c_type == TS_TAPE) {
984 fprintf(stderr, "Volume header\n");
985 previno = 0x7fffffff;
986 return;
987 }
988 if (previno == 0x7fffffff)
989 goto newcalc;
990 switch (prevtype) {
991 case TS_BITS:
992 fprintf(stderr, "Dump mask header");
993 break;
994 case TS_CLRI:
995 fprintf(stderr, "Remove mask header");
996 break;
997 case TS_INODE:
998 fprintf(stderr, "File header, ino %d", previno);
999 break;
1000 case TS_ADDR:
1001 fprintf(stderr, "File continuation header, ino %d", previno);
1002 break;
1003 case TS_END:
1004 fprintf(stderr, "End of tape header");
1005 break;
1006 }
1007 if (predict != blksread - 1)
1008 fprintf(stderr, "; predicted %d blocks, got %d blocks",
1009 predict, blksread - 1);
1010 fprintf(stderr, "\n");
1011newcalc:
1012 blks = 0;
1013 if (header->c_type != TS_END)
1014 for (i = 0; i < header->c_count; i++)
1015 if (header->c_addr[i] != 0)
1016 blks++;
1017 predict = blks;
1018 blksread = 0;
1019 prevtype = header->c_type;
1020 previno = header->c_inumber;
1021}
1022
1023/*
1024 * Find an inode header.
1025 * Complain if had to skip, and complain is set.
1026 */
1027findinode(header)
1028 struct s_spcl *header;
1029{
1030 static long skipcnt = 0;
1031 long i;
1032 char buf[TP_BSIZE];
1033
1034 curfile.name = "<name unknown>";
1035 curfile.action = UNKNOWN;
1036 curfile.dip = (struct dinode *)NIL;
1037 curfile.ino = 0;
1038 if (ishead(header) == FAIL) {
1039 skipcnt++;
1040 while (gethead(header) == FAIL || header->c_date != dumpdate)
1041 skipcnt++;
1042 }
1043 for (;;) {
1044 if (checktype(header, TS_ADDR) == GOOD) {
1045 /*
1046 * Skip up to the beginning of the next record
1047 */
1048 for (i = 0; i < header->c_count; i++)
1049 if (header->c_addr[i])
1050 readtape(buf);
1051 (void) gethead(header);
1052 continue;
1053 }
1054 if (checktype(header, TS_INODE) == GOOD) {
1055 curfile.dip = &header->c_dinode;
1056 curfile.ino = header->c_inumber;
1057 break;
1058 }
1059 if (checktype(header, TS_END) == GOOD) {
1060 curfile.ino = maxino;
1061 break;
1062 }
1063 if (checktype(header, TS_CLRI) == GOOD) {
1064 curfile.name = "<file removal list>";
1065 break;
1066 }
1067 if (checktype(header, TS_BITS) == GOOD) {
1068 curfile.name = "<file dump list>";
1069 break;
1070 }
1071 while (gethead(header) == FAIL)
1072 skipcnt++;
1073 }
1074 if (skipcnt > 0)
1075 fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
1076 skipcnt = 0;
1077}
1078
1079/*
1080 * return whether or not the buffer contains a header block
1081 */
1082ishead(buf)
1083 struct s_spcl *buf;
1084{
1085
1086 if (buf->c_magic != NFS_MAGIC)
1087 return(FAIL);
1088 return(GOOD);
1089}
1090
1091checktype(b, t)
1092 struct s_spcl *b;
1093 int t;
1094{
1095
1096 if (b->c_type != t)
1097 return(FAIL);
1098 return(GOOD);
1099}
1100
1101checksum(b)
1102 register int *b;
1103{
1104 register int i, j;
1105
1106 j = sizeof(union u_spcl) / sizeof(int);
1107 i = 0;
1108 if(!Bcvt) {
1109 do
1110 i += *b++;
1111 while (--j);
1112 } else {
1113 /* What happens if we want to read restore tapes
1114 for a 16bit int machine??? */
1115 do
1116 i += swabl(*b++);
1117 while (--j);
1118 }
1119
1120 if (i != CHECKSUM) {
1121 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1122 curfile.ino, curfile.name);
1123 return(FAIL);
1124 }
1125 return(GOOD);
1126}
1127
1128#ifdef RRESTORE
1129/* VARARGS1 */
1130msg(cp, a1, a2, a3)
1131 char *cp;
1132{
1133
1134 fprintf(stderr, cp, a1, a2, a3);
1135}
1136#endif RRESTORE
1137
1138u_char *
1139swabshort(sp, n)
1140 register u_char *sp;
1141 register int n;
1142{
1143 char c;
1144
1145 while (--n >= 0) {
1146 c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1147 sp += 2;
1148 }
1149 return (sp);
1150}
1151
1152u_char *
1153swablong(sp, n)
1154 register u_char *sp;
1155 register int n;
1156{
1157 char c;
1158
1159 while (--n >= 0) {
1160 c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1161 c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1162 sp += 4;
1163 }
1164 return (sp);
1165}
1166
1167swabst(cp, sp)
1168 register u_char *cp, *sp;
1169{
1170 int n = 0;
1171 u_char c;
1172
1173 while (*cp) {
1174 switch (*cp) {
1175 case '0': case '1': case '2': case '3': case '4':
1176 case '5': case '6': case '7': case '8': case '9':
1177 n = (n * 10) + (*cp++ - '0');
1178 continue;
1179
1180 case 's': case 'w': case 'h':
1181 if (n == 0)
1182 n = 1;
1183 sp = swabshort(sp, n);
1184 break;
1185
1186 case 'l':
1187 if (n == 0)
1188 n = 1;
1189 sp = swablong(sp, n);
1190 break;
1191
1192 default: /* Any other character, like 'b' counts as byte. */
1193 if (n == 0)
1194 n = 1;
1195 sp += n;
1196 break;
1197 }
1198 cp++;
1199 n = 0;
1200 }
1201}
1202
1203u_long
1204swabl(x)
1205 u_long x;
1206{
1207 swabst("l", (char *)&x);
1208 return (x);
1209}