(no message)
[unix-history] / usr / src / sbin / restore / tape.c
CommitLineData
f78e116c
KM
1/* Copyright (c) 1983 Regents of the University of California */
2
3#ifndef lint
6a8e228c 4static char sccsid[] = "@(#)tape.c 3.13 (Berkeley) 83/05/03";
f78e116c
KM
5#endif
6
7#include "restore.h"
8#include <dumprestor.h>
9#include <sys/ioctl.h>
10#include <sys/mtio.h>
2cb5dabb 11#include <sys/file.h>
f78e116c
KM
12#include <setjmp.h>
13#include <stat.h>
2cb5dabb
KM
14
15static long fssize;
16static int mt = -1;
17static int pipein = 0;
18static char *magtape;
2cb5dabb
KM
19static int bct = NTREC+1;
20static char tbf[NTREC*TP_BSIZE];
21static union u_spcl endoftapemark;
22static long blksread;
23static jmp_buf restart;
24static int gettingfile = 0; /* restart has a valid frame */
25
26static int ofile;
27static char *map;
28static char lnkbuf[MAXPATHLEN + 1];
29static int pathlen;
f78e116c
KM
30
31/*
32 * Set up an input source
33 */
34setinput(source)
35 char *source;
36{
37#ifdef RRESTOR
38 char *host;
39 char *index();
40
41 host = source;
42 magtape = index(host, ':');
43 if (magtape == 0) {
44nohost:
5c5f44c7 45 msg("need keyletter ``f'' and device ``host:tape''\n");
f78e116c
KM
46 done(1);
47 }
48 *magtape++ = '\0';
49 if (rmthost(host) == 0)
50 done(1);
51 setuid(getuid()); /* no longer need or want root privileges */
52#else
b677c5d7
KM
53 if (strcmp(source, "-") != 0) {
54 terminal = stdin;
55 } else {
56 /*
57 * Since input is coming from a pipe we must establish
58 * our own connection to the terminal.
59 */
60 terminal = fopen("/dev/tty", "r");
61 if (terminal == NULL) {
62 perror("open(\"/dev/tty\")");
63 done(1);
64 }
2cb5dabb 65 pipein++;
2cb5dabb 66 }
f78e116c
KM
67 magtape = source;
68#endif RRESTOR
69}
70
71/*
72 * Verify that the tape drive can be accessed and
73 * that it actually is a dump tape.
74 */
75setup()
76{
2cb5dabb 77 int i, j, *ip;
f78e116c
KM
78 struct stat stbuf;
79 extern char *ctime();
80 extern int xtrmap(), xtrmapskip();
81
82 vprintf(stdout, "Verify tape and initialize maps\n");
f78e116c
KM
83#ifdef RRESTOR
84 if ((mt = rmtopen(magtape, 0)) < 0)
85#else
2cb5dabb
KM
86 if (pipein)
87 mt = 0;
88 else if ((mt = open(magtape, 0)) < 0)
f78e116c
KM
89#endif
90 {
91 fprintf(stderr, "%s: cannot open tape\n", magtape);
92 done(1);
93 }
768eb687
KM
94 volno = 1;
95 setdumpnum();
f78e116c 96 flsht();
5c5f44c7 97 if (gethead(&spcl) == FAIL) {
f78e116c
KM
98 bct--; /* push back this block */
99 cvtflag++;
5c5f44c7 100 if (gethead(&spcl) == FAIL) {
f78e116c
KM
101 fprintf(stderr, "Tape is not a dump tape\n");
102 done(1);
103 }
104 fprintf(stderr, "Converting to new file system format.\n");
105 }
2cb5dabb
KM
106 if (pipein) {
107 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
108 endoftapemark.s_spcl.c_type = TS_END;
109 ip = (int *)&endoftapemark;
110 j = sizeof(union u_spcl) / sizeof(int);
111 i = 0;
112 do
113 i += *ip++;
114 while (--j);
115 endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
116 }
6a8e228c
KM
117 if (vflag || command == 't') {
118 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date));
119 fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
120 }
f78e116c 121 dumptime = spcl.c_ddate;
2cb5dabb 122 dumpdate = spcl.c_date;
f78e116c
KM
123 if (stat(".", &stbuf) < 0) {
124 fprintf(stderr, "cannot stat .\n");
125 done(1);
126 }
127 fssize = stbuf.st_blksize;
128 if (fssize <= 0 || ((fssize - 1) & fssize) != 0) {
129 fprintf(stderr, "bad block size %d\n", fssize);
130 done(1);
131 }
2cb5dabb 132 if (checkvol(&spcl, (long)1) == FAIL) {
f78e116c
KM
133 fprintf(stderr, "Tape is not volume 1 of the dump\n");
134 done(1);
135 }
2cb5dabb
KM
136 if (readhdr(&spcl) == FAIL)
137 panic("no header after volume mark!\n");
138 findinode(&spcl, 1);
139 if (checktype(&spcl, TS_CLRI) == FAIL) {
f78e116c
KM
140 fprintf(stderr, "Cannot find file removal list\n");
141 done(1);
142 }
2cb5dabb 143 maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
768eb687 144 dprintf(stdout, "maxino = %d\n", maxino);
7851e15d 145 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
f78e116c
KM
146 if (map == (char *)NIL)
147 panic("no memory for file removal list\n");
cf6db0ab 148 clrimap = map;
f78e116c
KM
149 curfile.action = USING;
150 getfile(xtrmap, xtrmapskip);
2cb5dabb 151 if (checktype(&spcl, TS_BITS) == FAIL) {
f78e116c
KM
152 fprintf(stderr, "Cannot find file dump list\n");
153 done(1);
154 }
7851e15d 155 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
f78e116c
KM
156 if (map == (char *)NULL)
157 panic("no memory for file dump list\n");
cf6db0ab 158 dumpmap = map;
f78e116c
KM
159 curfile.action = USING;
160 getfile(xtrmap, xtrmapskip);
f78e116c
KM
161}
162
163getvol(nextvol)
164 long nextvol;
165{
166 long newvol;
2cb5dabb 167 long savecnt;
f78e116c
KM
168 union u_spcl tmpspcl;
169# define tmpbuf tmpspcl.s_spcl
170
2cb5dabb 171 if (pipein) {
e108d3a2 172 if (nextvol != 1)
2cb5dabb 173 panic("Changing volumes on pipe input?\n");
e108d3a2
KM
174 if (volno == 1)
175 return;
176 goto gethdr;
2cb5dabb
KM
177 }
178 savecnt = blksread;
f78e116c 179again:
e108d3a2
KM
180 if (pipein)
181 done(1); /* pipes do not get a second chance */
f78e116c
KM
182 if (command == 'R' || command == 'r' || curfile.action != SKIP)
183 newvol = nextvol;
184 else
185 newvol = 0;
186 while (newvol <= 0) {
538cb7bb 187 do {
b677c5d7
KM
188 fprintf(stderr, "Specify next volume #: ");
189 (void) fflush(stderr);
190 (void) fgets(tbf, BUFSIZ, terminal);
191 } while (!feof(terminal) && tbf[0] == '\n');
192 if (feof(terminal))
538cb7bb 193 done(1);
f78e116c
KM
194 newvol = atoi(tbf);
195 if (newvol <= 0) {
196 fprintf(stderr,
197 "Volume numbers are positive numerics\n");
198 }
199 }
200 if (newvol == volno)
201 return;
202 closemt();
5c5f44c7 203 fprintf(stderr, "Mount tape volume %d then type return ", newvol);
b677c5d7
KM
204 (void) fflush(stderr);
205 while (getc(terminal) != '\n')
f78e116c
KM
206 ;
207#ifdef RRESTOR
208 if ((mt = rmtopen(magtape, 0)) == -1)
209#else
210 if ((mt = open(magtape, 0)) == -1)
211#endif
212 {
213 fprintf(stderr, "Cannot open tape!\n");
214 goto again;
215 }
e108d3a2 216gethdr:
f78e116c 217 volno = newvol;
768eb687 218 setdumpnum();
f78e116c 219 flsht();
2cb5dabb 220 if (readhdr(&tmpbuf) == FAIL) {
f78e116c
KM
221 fprintf(stderr, "tape is not dump tape\n");
222 volno = 0;
223 goto again;
224 }
2cb5dabb 225 if (checkvol(&tmpbuf, volno) == FAIL) {
f78e116c
KM
226 fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
227 volno = 0;
228 goto again;
229 }
2cb5dabb 230 if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
6a8e228c
KM
231 fprintf(stderr, "Wrong dump date got: %swanted %s",
232 ctime(&tmpbuf.c_date), ctime(dumpdate));
2cb5dabb
KM
233 volno = 0;
234 goto again;
235 }
5c5f44c7 236 blksread = savecnt;
f78e116c
KM
237 if (curfile.action == USING) {
238 if (volno == 1)
239 panic("active file into volume 1\n");
240 return;
241 }
5c5f44c7 242 (void) gethead(&spcl);
f78e116c
KM
243 findinode(&spcl, curfile.action == UNKNOWN ? 1 : 0);
244 if (gettingfile) {
245 gettingfile = 0;
246 longjmp(restart, 1);
247 }
248}
249
768eb687
KM
250/*
251 * handle multiple dumps per tape by skipping forward to the
252 * appropriate one.
253 */
254setdumpnum()
255{
256 struct mtop tcom;
257
258 if (dumpnum == 1 || volno != 1)
259 return;
260 if (pipein) {
261 fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
262 done(1);
263 }
264 tcom.mt_op = MTFSF;
265 tcom.mt_count = dumpnum - 1;
266#ifdef RRESTOR
267 rmtioctl(MTFSF, dumpnum - 1);
268#else
538cb7bb 269 if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
768eb687
KM
270 perror("ioctl MTFSF");
271#endif
272}
273
f78e116c
KM
274extractfile(name)
275 char *name;
276{
277 int mode;
278 time_t timep[2];
279 struct entry *ep;
280 extern int xtrlnkfile(), xtrlnkskip();
281 extern int xtrfile(), xtrskip();
282
283 curfile.name = name;
284 curfile.action = USING;
285 timep[0] = curfile.dip->di_atime;
286 timep[1] = curfile.dip->di_mtime;
287 mode = curfile.dip->di_mode;
288 switch (mode & IFMT) {
289
290 default:
291 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
292 skipfile();
293 return (FAIL);
294
295 case IFDIR:
296 if (mflag) {
297 ep = lookupname(name);
298 if (ep == NIL || ep->e_flags & EXTRACT)
299 panic("unextracted directory %s\n", name);
300 skipfile();
301 return (GOOD);
302 }
303 vprintf(stdout, "extract file %s\n", name);
304 return (genliteraldir(name, curfile.ino));
305
306 case IFLNK:
307 lnkbuf[0] = '\0';
308 pathlen = 0;
309 getfile(xtrlnkfile, xtrlnkskip);
310 if (pathlen == 0) {
311 vprintf(stdout,
312 "%s: zero length symbolic link (ignored)\n", name);
313 } else if (symlink(lnkbuf, name) < 0) {
314 fprintf(stderr, "%s: cannot create symbolic link\n",
315 name);
316 return (FAIL);
317 } else
318 vprintf(stdout, "extract symbolic link %s\n", name);
319 return (GOOD);
320
321 case IFCHR:
322 case IFBLK:
323 vprintf(stdout, "extract special file %s\n", name);
324 if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
325 fprintf(stderr, "%s: cannot create special file\n",
326 name);
327 skipfile();
328 return (FAIL);
329 }
768eb687
KM
330 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
331 (void) chmod(name, mode);
f78e116c
KM
332 skipfile();
333 utime(name, timep);
334 return (GOOD);
335
336 case IFREG:
337 vprintf(stdout, "extract file %s\n", name);
338 if ((ofile = open(name, FWRONLY|FCREATE, 0666)) < 0) {
339 fprintf(stderr, "%s: cannot create file\n", name);
340 skipfile();
341 return (FAIL);
342 }
768eb687
KM
343 (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
344 (void) fchmod(ofile, mode);
f78e116c 345 getfile(xtrfile, xtrskip);
768eb687 346 (void) close(ofile);
f78e116c
KM
347 utime(name, timep);
348 return (GOOD);
349 }
350 /* NOTREACHED */
351}
352
e108d3a2
KM
353/*
354 * skip over bit maps on the tape
355 */
356skipmaps()
357{
358
359 while (checktype(&spcl, TS_CLRI) == GOOD ||
360 checktype(&spcl, TS_BITS) == GOOD)
361 skipfile();
362}
363
364/*
365 * skip over a file on the tape
366 */
f78e116c
KM
367skipfile()
368{
369 extern int null();
370
371 curfile.action = SKIP;
372 getfile(null, null);
373}
374
375/*
376 * Do the file extraction, calling the supplied functions
377 * with the blocks
378 */
379getfile(f1, f2)
380 int (*f2)(), (*f1)();
381{
382 register int i;
383 int curblk = 0;
384 off_t size = spcl.c_dinode.di_size;
385 static char clearedbuf[MAXBSIZE];
386 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
387
2cb5dabb 388 if (checktype(&spcl, TS_END) == GOOD)
f78e116c 389 panic("ran off end of tape\n");
e108d3a2 390 if (ishead(&spcl) == FAIL)
f78e116c 391 panic("not at beginning of a file\n");
e108d3a2 392 if (!gettingfile && setjmp(restart) != 0)
f78e116c
KM
393 return;
394 gettingfile++;
395loop:
396 for (i = 0; i < spcl.c_count; i++) {
397 if (spcl.c_addr[i]) {
398 readtape(&buf[curblk++][0]);
399 if (curblk == fssize / TP_BSIZE) {
400 (*f1)(buf, size > TP_BSIZE ?
401 (long) (fssize) :
402 (curblk - 1) * TP_BSIZE + size);
403 curblk = 0;
404 }
405 } else {
406 if (curblk > 0) {
407 (*f1)(buf, size > TP_BSIZE ?
408 (long) (curblk * TP_BSIZE) :
409 (curblk - 1) * TP_BSIZE + size);
410 curblk = 0;
411 }
412 (*f2)(clearedbuf, size > TP_BSIZE ?
413 (long) TP_BSIZE : size);
414 }
9f13f26d
KM
415 if ((size -= TP_BSIZE) <= 0)
416 break;
f78e116c 417 }
5c5f44c7 418 if (readhdr(&spcl) == GOOD && size > 0) {
9f13f26d
KM
419 if (checktype(&spcl, TS_ADDR) == GOOD)
420 goto loop;
768eb687 421 dprintf(stdout, "Missing address (header) block for %s\n",
f78e116c 422 curfile.name);
f78e116c 423 }
9f13f26d 424 if (curblk > 0)
f78e116c 425 (*f1)(buf, (curblk * TP_BSIZE) + size);
f78e116c
KM
426 findinode(&spcl, 1);
427 gettingfile = 0;
428}
429
430/*
431 * The next routines are called during file extraction to
432 * put the data into the right form and place.
433 */
434xtrfile(buf, size)
435 char *buf;
436 long size;
437{
438
439 if (write(ofile, buf, (int) size) == -1) {
440 fprintf(stderr, "write error extracting inode %d, name %s\n",
441 curfile.ino, curfile.name);
442 perror("write");
443 done(1);
444 }
445}
446
447xtrskip(buf, size)
448 char *buf;
449 long size;
450{
451
452#ifdef lint
453 buf = buf;
454#endif
455 if (lseek(ofile, size, 1) == (long)-1) {
456 fprintf(stderr, "seek error extracting inode %d, name %s\n",
457 curfile.ino, curfile.name);
458 perror("lseek");
459 done(1);
460 }
461}
462
463xtrlnkfile(buf, size)
464 char *buf;
465 long size;
466{
467
468 pathlen += size;
469 if (pathlen > MAXPATHLEN) {
470 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
471 curfile.name, lnkbuf, buf, pathlen);
472 done(1);
473 }
538cb7bb 474 (void) strcat(lnkbuf, buf);
f78e116c
KM
475}
476
477xtrlnkskip(buf, size)
478 char *buf;
479 long size;
480{
481
482#ifdef lint
483 buf = buf, size = size;
484#endif
485 fprintf(stderr, "unallocated block in symbolic link %s\n",
486 curfile.name);
487 done(1);
488}
489
490xtrmap(buf, size)
491 char *buf;
492 long size;
493{
494
495 bcopy(buf, map, size);
cf6db0ab 496 map += size;
f78e116c
KM
497}
498
499xtrmapskip(buf, size)
500 char *buf;
501 long size;
502{
503
504#ifdef lint
505 buf = buf;
f78e116c
KM
506#endif
507 panic("hole in map\n");
cf6db0ab 508 map += size;
f78e116c
KM
509}
510
511null() {;}
512
513/*
514 * Do the tape i/o, dealing with volume changes
515 * etc..
516 */
517readtape(b)
518 char *b;
519{
520 register long i;
7851e15d
KM
521 long rd, newvol;
522 int cnt;
f78e116c
KM
523
524 if (bct >= NTREC) {
525 for (i = 0; i < NTREC; i++)
526 ((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
527 bct = 0;
74025ab9
KM
528 cnt = NTREC*TP_BSIZE;
529 rd = 0;
530 getmore:
f78e116c 531#ifdef RRESTOR
74025ab9 532 i = rmtread(&tbf[rd], cnt);
f78e116c 533#else
74025ab9 534 i = read(mt, &tbf[rd], cnt);
f78e116c 535#endif
74025ab9
KM
536 if (i > 0 && i != NTREC*TP_BSIZE) {
537 if (!pipein)
538 panic("partial block read: %d should be %d\n",
539 i, NTREC*TP_BSIZE);
540 rd += i;
541 cnt -= i;
542 if (cnt > 0)
543 goto getmore;
544 i = rd;
545 }
546 if (i < 0) {
f78e116c
KM
547 fprintf(stderr, "Tape read error while ");
548 switch (curfile.action) {
74025ab9
KM
549 default:
550 fprintf(stderr, "trying to set up tape\n");
551 break;
f78e116c
KM
552 case UNKNOWN:
553 fprintf(stderr, "trying to resyncronize\n");
554 break;
555 case USING:
556 fprintf(stderr, "restoring %s\n", curfile.name);
557 break;
558 case SKIP:
559 fprintf(stderr, "skipping over inode %d\n",
560 curfile.ino);
561 break;
562 }
563 if (!yflag && !reply("continue"))
564 done(1);
565 i = NTREC*TP_BSIZE;
566 bzero(tbf, i);
567#ifdef RRESTOR
568 if (rmtseek(i, 1) < 0)
569#else
570 if (lseek(mt, i, 1) == (long)-1)
571#endif
572 {
573 fprintf(stderr, "continuation failed\n");
574 done(1);
575 }
576 }
577 if (i == 0) {
2cb5dabb
KM
578 if (pipein) {
579 bcopy((char *)&endoftapemark, b,
580 (long)TP_BSIZE);
581 flsht();
582 return;
583 }
f78e116c
KM
584 newvol = volno + 1;
585 volno = 0;
586 getvol(newvol);
587 readtape(b);
588 return;
589 }
590 }
591 bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
2cb5dabb 592 blksread++;
f78e116c
KM
593}
594
595flsht()
596{
597
598 bct = NTREC+1;
599}
600
f78e116c
KM
601closemt()
602{
603 if (mt < 0)
604 return;
605#ifdef RRESTOR
606 rmtclose();
607#else
768eb687 608 (void) close(mt);
f78e116c
KM
609#endif
610}
611
612checkvol(b, t)
613 struct s_spcl *b;
614 long t;
615{
616
2cb5dabb
KM
617 if (b->c_volume != t)
618 return(FAIL);
619 return(GOOD);
f78e116c
KM
620}
621
622readhdr(b)
623 struct s_spcl *b;
624{
625
5c5f44c7 626 if (gethead(b) == FAIL) {
768eb687 627 dprintf(stdout, "readhdr fails at %d blocks\n", blksread);
2cb5dabb 628 return(FAIL);
5c5f44c7 629 }
2cb5dabb 630 return(GOOD);
f78e116c
KM
631}
632
633/*
634 * read the tape into buf, then return whether or
635 * or not it is a header block.
636 */
637gethead(buf)
638 struct s_spcl *buf;
639{
5c5f44c7 640 long i;
f78e116c
KM
641 union u_ospcl {
642 char dummy[TP_BSIZE];
643 struct s_ospcl {
2cb5dabb
KM
644 long c_type;
645 long c_date;
646 long c_ddate;
647 long c_volume;
648 long c_tapea;
cf6db0ab 649 u_short c_inumber;
2cb5dabb
KM
650 long c_magic;
651 long c_checksum;
f78e116c
KM
652 struct odinode {
653 unsigned short odi_mode;
cf6db0ab
KM
654 u_short odi_nlink;
655 u_short odi_uid;
656 u_short odi_gid;
2cb5dabb
KM
657 long odi_size;
658 long odi_rdev;
f78e116c 659 char odi_addr[36];
2cb5dabb
KM
660 long odi_atime;
661 long odi_mtime;
662 long odi_ctime;
f78e116c 663 } c_dinode;
2cb5dabb
KM
664 long c_count;
665 char c_addr[256];
f78e116c
KM
666 } s_ospcl;
667 } u_ospcl;
668
669 if (!cvtflag) {
670 readtape((char *)buf);
5c5f44c7 671 if (buf->c_magic != NFS_MAGIC || checksum((int *)buf) == FAIL)
2cb5dabb 672 return(FAIL);
5c5f44c7 673 goto good;
f78e116c
KM
674 }
675 readtape((char *)(&u_ospcl.s_ospcl));
676 bzero((char *)buf, (long)TP_BSIZE);
677 buf->c_type = u_ospcl.s_ospcl.c_type;
678 buf->c_date = u_ospcl.s_ospcl.c_date;
679 buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
680 buf->c_volume = u_ospcl.s_ospcl.c_volume;
681 buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
682 buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
683 buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
684 buf->c_magic = u_ospcl.s_ospcl.c_magic;
685 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
686 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
687 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
688 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
689 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
690 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
691 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
692 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
693 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
694 buf->c_count = u_ospcl.s_ospcl.c_count;
2cb5dabb 695 bcopy(u_ospcl.s_ospcl.c_addr, buf->c_addr, (long)256);
f78e116c 696 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
5c5f44c7 697 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
2cb5dabb 698 return(FAIL);
f78e116c 699 buf->c_magic = NFS_MAGIC;
5c5f44c7
KM
700
701good:
702 switch (buf->c_type) {
703
704 case TS_CLRI:
705 case TS_BITS:
706 /*
707 * Have to patch up missing information in bit map headers
708 */
709 buf->c_inumber = 0;
710 buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
711 for (i = 0; i < buf->c_count; i++)
712 buf->c_addr[i]++;
713 break;
714
715 case TS_TAPE:
716 case TS_END:
717 buf->c_inumber = 0;
718 break;
719
720 case TS_INODE:
721 case TS_ADDR:
722 break;
723
724 default:
725 panic("gethead: unknown inode type %d\n", buf->c_type);
726 break;
727 }
2cb5dabb
KM
728 if (dflag)
729 accthdr(buf);
730 return(GOOD);
731}
732
733/*
734 * Check that a header is where it belongs and predict the next header
735 */
736accthdr(header)
737 struct s_spcl *header;
738{
7851e15d 739 static ino_t previno = 0x7fffffff;
2cb5dabb
KM
740 static int prevtype;
741 static long predict;
742 long blks, i;
743
5c5f44c7
KM
744 if (header->c_type == TS_TAPE) {
745 fprintf(stderr, "Volume header\n");
746 return;
747 }
7851e15d 748 if (previno == 0x7fffffff)
2cb5dabb
KM
749 goto newcalc;
750 switch (prevtype) {
2cb5dabb 751 case TS_BITS:
5c5f44c7 752 fprintf(stderr, "Dump mask header");
2cb5dabb
KM
753 break;
754 case TS_CLRI:
5c5f44c7 755 fprintf(stderr, "Remove mask header");
2cb5dabb
KM
756 break;
757 case TS_INODE:
5c5f44c7 758 fprintf(stderr, "File header, ino %d", previno);
2cb5dabb
KM
759 break;
760 case TS_ADDR:
5c5f44c7 761 fprintf(stderr, "File continuation header, ino %d", previno);
2cb5dabb
KM
762 break;
763 case TS_END:
5c5f44c7 764 fprintf(stderr, "End of tape header");
2cb5dabb
KM
765 break;
766 }
2cb5dabb
KM
767 if (predict != blksread - 1)
768 fprintf(stderr, "; predicted %d blocks, got %d blocks",
769 predict, blksread - 1);
770 fprintf(stderr, "\n");
771newcalc:
772 blks = 0;
5c5f44c7 773 if (header->c_type != TS_END)
2cb5dabb
KM
774 for (i = 0; i < header->c_count; i++)
775 if (header->c_addr[i] != 0)
776 blks++;
777 predict = blks;
778 blksread = 0;
779 prevtype = header->c_type;
780 previno = header->c_inumber;
f78e116c
KM
781}
782
783/*
784 * Find an inode header.
785 * Complain if had to skip, and complain is set.
786 */
787findinode(header, complain)
788 struct s_spcl *header;
789 int complain;
790{
2cb5dabb 791 static long skipcnt = 0;
f78e116c
KM
792
793 curfile.name = "<name unknown>";
794 curfile.action = UNKNOWN;
795 curfile.dip = (struct dinode *)NIL;
796 curfile.ino = 0;
2cb5dabb
KM
797 if (ishead(header) == FAIL) {
798 skipcnt++;
799 while (gethead(header) == FAIL)
f78e116c 800 skipcnt++;
2cb5dabb 801 }
f78e116c 802 for (;;) {
2cb5dabb 803 if (checktype(header, TS_INODE) == GOOD) {
f78e116c
KM
804 curfile.dip = &header->c_dinode;
805 curfile.ino = header->c_inumber;
806 break;
807 }
2cb5dabb 808 if (checktype(header, TS_END) == GOOD) {
f78e116c
KM
809 curfile.ino = maxino;
810 break;
811 }
2cb5dabb 812 if (checktype(header, TS_CLRI) == GOOD) {
f78e116c 813 curfile.name = "<file removal list>";
e108d3a2 814 break;
f78e116c 815 }
2cb5dabb 816 if (checktype(header, TS_BITS) == GOOD) {
f78e116c 817 curfile.name = "<file dump list>";
e108d3a2 818 break;
f78e116c 819 }
2cb5dabb 820 while (gethead(header) == FAIL)
f78e116c
KM
821 skipcnt++;
822 }
823 if (skipcnt > 0 && complain)
824 fprintf(stderr, "resync restor, skipped %d blocks\n", skipcnt);
825 skipcnt = 0;
826}
827
828/*
829 * return whether or not the buffer contains a header block
830 */
831ishead(buf)
832 struct s_spcl *buf;
833{
834
835 if (buf->c_magic != NFS_MAGIC)
2cb5dabb
KM
836 return(FAIL);
837 return(GOOD);
f78e116c
KM
838}
839
840checktype(b, t)
841 struct s_spcl *b;
842 int t;
843{
844
2cb5dabb
KM
845 if (b->c_type != t)
846 return(FAIL);
847 return(GOOD);
f78e116c
KM
848}
849
850checksum(b)
851 register int *b;
852{
853 register int i, j;
854
855 j = sizeof(union u_spcl) / sizeof(int);
856 i = 0;
857 do
858 i += *b++;
859 while (--j);
860 if (i != CHECKSUM) {
861 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
862 curfile.ino, curfile.name);
2cb5dabb 863 return(FAIL);
f78e116c 864 }
2cb5dabb 865 return(GOOD);
f78e116c
KM
866}
867
868#ifdef RRESTOR
74025ab9 869/* VARARGS1 */
f78e116c
KM
870msg(cp, a1, a2, a3)
871 char *cp;
872{
873
874 fprintf(stderr, cp, a1, a2, a3);
875}
876#endif RRESTOR