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