]> git.wh0rd.org - dump.git/blob - restore/tape.c
Version 0.4b5.
[dump.git] / restore / tape.c
1 /*
2 * Ported to Linux's Second Extended File System as part of the
3 * dump and restore backup suit
4 * Remy Card <card@Linux.EU.Org>, 1994-1997
5 * Stelian Pop <pop@cybercable.fr>, 1999
6 *
7 */
8
9 /*
10 * Copyright (c) 1983, 1993
11 * The Regents of the University of California. All rights reserved.
12 * (c) UNIX System Laboratories, Inc.
13 * All or some portions of this file are derived from material licensed
14 * to the University of California by American Telephone and Telegraph
15 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
16 * the permission of UNIX System Laboratories, Inc.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
26 * 3. All advertising materials mentioning features or use of this software
27 * must display the following acknowledgement:
28 * This product includes software developed by the University of
29 * California, Berkeley and its contributors.
30 * 4. Neither the name of the University nor the names of its contributors
31 * may be used to endorse or promote products derived from this software
32 * without specific prior written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 * SUCH DAMAGE.
45 */
46
47 #ifndef lint
48 #if 0
49 static char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 5/1/95";
50 #endif
51 static const char rcsid[] =
52 "$Id: tape.c,v 1.2 1999/10/11 12:53:24 stelian Exp $";
53 #endif /* not lint */
54
55 #include <sys/param.h>
56 #include <sys/file.h>
57 #include <sys/mtio.h>
58 #include <sys/stat.h>
59
60 #ifdef __linux__
61 #include <sys/time.h>
62 #include <linux/ext2_fs.h>
63 #include <bsdcompat.h>
64 #else /* __linux__ */
65 #include <ufs/ufs/dinode.h>
66 #endif /* __linux__ */
67 #include <protocols/dumprestore.h>
68
69 #include <errno.h>
70 #include <setjmp.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <unistd.h>
75
76 #ifdef __linux__
77 #include <ext2fs/ext2fs.h>
78 #endif
79
80 #include "restore.h"
81 #include "extern.h"
82 #include "pathnames.h"
83
84 static long fssize = MAXBSIZE;
85 static int mt = -1;
86 static int pipein = 0;
87 static char *magtape;
88 static int blkcnt;
89 static int numtrec;
90 static char *tapebuf;
91 static union u_spcl endoftapemark;
92 static long blksread; /* blocks read since last header */
93 static long tpblksread = 0; /* TP_BSIZE blocks read */
94 static long tapesread;
95 static jmp_buf restart;
96 static int gettingfile = 0; /* restart has a valid frame */
97 static char *host = NULL;
98
99 static int ofile;
100 static char *map;
101 static char lnkbuf[MAXPATHLEN + 1];
102 static int pathlen;
103
104 int oldinofmt; /* old inode format conversion required */
105 int Bcvt; /* Swap Bytes (for CCI or sun) */
106 static int Qcvt; /* Swap quads (for sun) */
107
108 #define FLUSHTAPEBUF() blkcnt = ntrec + 1
109
110 static void accthdr __P((struct s_spcl *));
111 static int checksum __P((int *));
112 static void findinode __P((struct s_spcl *));
113 static void findtapeblksize __P((void));
114 static int gethead __P((struct s_spcl *));
115 static void readtape __P((char *));
116 static void setdumpnum __P((void));
117 static u_long swabl __P((u_long));
118 static u_char *swablong __P((u_char *, int));
119 static u_char *swabshort __P((u_char *, int));
120 static void terminateinput __P((void));
121 static void xtrfile __P((char *, long));
122 static void xtrlnkfile __P((char *, long));
123 static void xtrlnkskip __P((char *, long));
124 static void xtrmap __P((char *, long));
125 static void xtrmapskip __P((char *, long));
126 static void xtrskip __P((char *, long));
127
128 static int readmapflag;
129
130 /*
131 * Set up an input source
132 */
133 void
134 setinput(source)
135 char *source;
136 {
137 FLUSHTAPEBUF();
138 if (bflag)
139 newtapebuf(ntrec);
140 else
141 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
142 terminal = stdin;
143
144 #ifdef RRESTORE
145 if (strchr(source, ':')) {
146 host = source;
147 source = strchr(host, ':');
148 *source++ = '\0';
149 if (rmthost(host) == 0)
150 done(1);
151 } else
152 #endif
153 if (strcmp(source, "-") == 0) {
154 /*
155 * Since input is coming from a pipe we must establish
156 * our own connection to the terminal.
157 */
158 terminal = fopen(_PATH_TTY, "r");
159 if (terminal == NULL) {
160 (void)fprintf(stderr, "cannot open %s: %s\n",
161 _PATH_TTY, strerror(errno));
162 terminal = fopen(_PATH_DEVNULL, "r");
163 if (terminal == NULL) {
164 (void)fprintf(stderr, "cannot open %s: %s\n",
165 _PATH_DEVNULL, strerror(errno));
166 done(1);
167 }
168 }
169 pipein++;
170 }
171 setuid(getuid()); /* no longer need or want root privileges */
172 magtape = strdup(source);
173 if (magtape == NULL) {
174 fprintf(stderr, "Cannot allocate space for magtape buffer\n");
175 done(1);
176 }
177 }
178
179 void
180 newtapebuf(size)
181 long size;
182 {
183 static tapebufsize = -1;
184
185 ntrec = size;
186 if (size <= tapebufsize)
187 return;
188 if (tapebuf != NULL)
189 free(tapebuf);
190 tapebuf = malloc(size * TP_BSIZE);
191 if (tapebuf == NULL) {
192 fprintf(stderr, "Cannot allocate space for tape buffer\n");
193 done(1);
194 }
195 tapebufsize = size;
196 }
197
198 /*
199 * Verify that the tape drive can be accessed and
200 * that it actually is a dump tape.
201 */
202 void
203 setup()
204 {
205 int i, j, *ip;
206 struct stat stbuf;
207
208 vprintf(stdout, "Verify tape and initialize maps\n");
209 #ifdef RRESTORE
210 if (host)
211 mt = rmtopen(magtape, 0);
212 else
213 #endif
214 if (pipein)
215 mt = 0;
216 else
217 mt = open(magtape, O_RDONLY, 0);
218 if (mt < 0) {
219 fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
220 done(1);
221 }
222 volno = 1;
223 setdumpnum();
224 FLUSHTAPEBUF();
225 if (!pipein && !bflag)
226 findtapeblksize();
227 if (gethead(&spcl) == FAIL) {
228 blkcnt--; /* push back this block */
229 blksread--;
230 tpblksread--;
231 cvtflag++;
232 if (gethead(&spcl) == FAIL) {
233 fprintf(stderr, "Tape is not a dump tape\n");
234 done(1);
235 }
236 fprintf(stderr, "Converting to new file system format.\n");
237 }
238 if (pipein) {
239 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
240 endoftapemark.s_spcl.c_type = TS_END;
241 ip = (int *)&endoftapemark;
242 j = sizeof(union u_spcl) / sizeof(int);
243 i = 0;
244 do
245 i += *ip++;
246 while (--j);
247 endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
248 }
249 if (vflag || command == 't' || command == 'C')
250 printdumpinfo();
251 if (filesys == NULL) {
252 filesys = spcl.c_filesys;
253 }
254 dumptime = spcl.c_ddate;
255 dumpdate = spcl.c_date;
256 if (stat(".", &stbuf) < 0) {
257 fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
258 done(1);
259 }
260 if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE )
261 fssize = TP_BSIZE;
262 if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE)
263 fssize = stbuf.st_blksize;
264 if (((fssize - 1) & fssize) != 0) {
265 fprintf(stderr, "bad block size %ld\n", fssize);
266 done(1);
267 }
268 if (spcl.c_volume != 1) {
269 fprintf(stderr, "Tape is not volume 1 of the dump\n");
270 done(1);
271 }
272 if (gethead(&spcl) == FAIL) {
273 dprintf(stdout, "header read failed at %ld blocks\n", blksread);
274 panic("no header after volume mark!\n");
275 }
276 findinode(&spcl);
277 if (spcl.c_type != TS_CLRI) {
278 fprintf(stderr, "Cannot find file removal list\n");
279 done(1);
280 }
281 maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
282 dprintf(stdout, "maxino = %ld\n", maxino);
283 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
284 if (map == NULL)
285 panic("no memory for active inode map\n");
286 usedinomap = map;
287 curfile.action = USING;
288 getfile(xtrmap, xtrmapskip);
289 if (spcl.c_type != TS_BITS) {
290 fprintf(stderr, "Cannot find file dump list\n");
291 done(1);
292 }
293 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
294 if (map == (char *)NULL)
295 panic("no memory for file dump list\n");
296 dumpmap = map;
297 curfile.action = USING;
298 getfile(xtrmap, xtrmapskip);
299 /*
300 * If there may be whiteout entries on the tape, pretend that the
301 * whiteout inode exists, so that the whiteout entries can be
302 * extracted.
303 */
304 if (oldinofmt == 0)
305 SETINO(WINO, dumpmap);
306 }
307
308 /*
309 * Prompt user to load a new dump volume.
310 * "Nextvol" is the next suggested volume to use.
311 * This suggested volume is enforced when doing full
312 * or incremental restores, but can be overridden by
313 * the user when only extracting a subset of the files.
314 */
315 void
316 getvol(nextvol)
317 long nextvol;
318 {
319 long newvol=0, savecnt=0, wantnext=0, i;
320 union u_spcl tmpspcl;
321 # define tmpbuf tmpspcl.s_spcl
322 char buf[TP_BSIZE];
323
324 if (nextvol == 1) {
325 tapesread = 0;
326 gettingfile = 0;
327 }
328 if (pipein) {
329 if (nextvol != 1)
330 panic("Changing volumes on pipe input?\n");
331 if (volno == 1)
332 return;
333 goto gethdr;
334 }
335 savecnt = blksread;
336 again:
337 if (pipein)
338 done(1); /* pipes do not get a second chance */
339 if (command == 'R' || command == 'r' || curfile.action != SKIP) {
340 newvol = nextvol;
341 wantnext = 1;
342 } else {
343 newvol = 0;
344 wantnext = 0;
345 }
346 while (newvol <= 0) {
347 if (tapesread == 0) {
348 fprintf(stderr, "%s%s%s%s%s",
349 "You have not read any tapes yet.\n",
350 "Unless you know which volume your",
351 " file(s) are on you should start\n",
352 "with the last volume and work",
353 " towards the first.\n");
354 } else {
355 fprintf(stderr, "You have read volumes");
356 strcpy(buf, ": ");
357 for (i = 1; i < 32; i++)
358 if (tapesread & (1 << i)) {
359 fprintf(stderr, "%s%ld", buf, i);
360 strcpy(buf, ", ");
361 }
362 fprintf(stderr, "\n");
363 }
364 do {
365 fprintf(stderr, "Specify next volume #: ");
366 (void) fflush(stderr);
367 (void) fgets(buf, BUFSIZ, terminal);
368 } while (!feof(terminal) && buf[0] == '\n');
369 if (feof(terminal))
370 done(1);
371 newvol = atoi(buf);
372 if (newvol <= 0) {
373 fprintf(stderr,
374 "Volume numbers are positive numerics\n");
375 }
376 }
377 if (newvol == volno) {
378 tapesread |= 1 << volno;
379 return;
380 }
381 closemt();
382 fprintf(stderr, "Mount tape volume %ld\n", newvol);
383 fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
384 fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
385 (void) fflush(stderr);
386 (void) fgets(buf, BUFSIZ, terminal);
387 if (feof(terminal))
388 done(1);
389 if (!strcmp(buf, "none\n")) {
390 terminateinput();
391 return;
392 }
393 if (buf[0] != '\n') {
394 (void) strcpy(magtape, buf);
395 magtape[strlen(magtape) - 1] = '\0';
396 }
397 #ifdef RRESTORE
398 if (host)
399 mt = rmtopen(magtape, 0);
400 else
401 #endif
402 mt = open(magtape, O_RDONLY, 0);
403
404 if (mt == -1) {
405 fprintf(stderr, "Cannot open %s\n", magtape);
406 volno = -1;
407 goto again;
408 }
409 gethdr:
410 volno = newvol;
411 setdumpnum();
412 FLUSHTAPEBUF();
413 if (gethead(&tmpbuf) == FAIL) {
414 dprintf(stdout, "header read failed at %ld blocks\n", blksread);
415 fprintf(stderr, "tape is not dump tape\n");
416 volno = 0;
417 goto again;
418 }
419 if (tmpbuf.c_volume != volno) {
420 fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
421 volno = 0;
422 goto again;
423 }
424 if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
425 #ifdef __linux__
426 fprintf(stderr, "Wrong dump date\n\tgot: %s",
427 ctime4(&tmpbuf.c_date));
428 fprintf(stderr, "\twanted: %s", ctime4(&dumpdate));
429 #else
430 fprintf(stderr, "Wrong dump date\n\tgot: %s",
431 ctime(&tmpbuf.c_date));
432 fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
433 #endif
434 volno = 0;
435 goto again;
436 }
437 tapesread |= 1 << volno;
438 blksread = savecnt;
439 /*
440 * If continuing from the previous volume, skip over any
441 * blocks read already at the end of the previous volume.
442 *
443 * If coming to this volume at random, skip to the beginning
444 * of the next record.
445 */
446 dprintf(stdout, "read %ld recs, tape starts with %d\n",
447 tpblksread, tmpbuf.c_firstrec);
448 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
449 if (!wantnext) {
450 tpblksread = tmpbuf.c_firstrec;
451 for (i = tmpbuf.c_count; i > 0; i--)
452 readtape(buf);
453 } else if (tmpbuf.c_firstrec > 0 &&
454 tmpbuf.c_firstrec < tpblksread - 1) {
455 /*
456 * -1 since we've read the volume header
457 */
458 i = tpblksread - tmpbuf.c_firstrec - 1;
459 dprintf(stderr, "Skipping %ld duplicate record%s.\n",
460 i, i > 1 ? "s" : "");
461 while (--i >= 0)
462 readtape(buf);
463 }
464 }
465 if (curfile.action == USING) {
466 if (volno == 1)
467 panic("active file into volume 1\n");
468 return;
469 }
470 /*
471 * Skip up to the beginning of the next record
472 */
473 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
474 for (i = tmpbuf.c_count; i > 0; i--)
475 readtape(buf);
476 (void) gethead(&spcl);
477 findinode(&spcl);
478 if (gettingfile) {
479 gettingfile = 0;
480 longjmp(restart, 1);
481 }
482 }
483
484 /*
485 * Handle unexpected EOF.
486 */
487 static void
488 terminateinput()
489 {
490
491 if (gettingfile && curfile.action == USING) {
492 printf("Warning: %s %s\n",
493 "End-of-input encountered while extracting", curfile.name);
494 }
495 curfile.name = "<name unknown>";
496 curfile.action = UNKNOWN;
497 curfile.dip = NULL;
498 curfile.ino = maxino;
499 if (gettingfile) {
500 gettingfile = 0;
501 longjmp(restart, 1);
502 }
503 }
504
505 /*
506 * handle multiple dumps per tape by skipping forward to the
507 * appropriate one.
508 */
509 static void
510 setdumpnum()
511 {
512 struct mtop tcom;
513
514 if (dumpnum == 1 || volno != 1)
515 return;
516 if (pipein) {
517 fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
518 done(1);
519 }
520 tcom.mt_op = MTFSF;
521 tcom.mt_count = dumpnum - 1;
522 #ifdef RRESTORE
523 if (host)
524 rmtioctl(MTFSF, dumpnum - 1);
525 else
526 #endif
527 if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
528 fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
529 }
530
531 void
532 printdumpinfo()
533 {
534 #ifdef __linux__
535 fprintf(stdout, "Dump date: %s", ctime4(&spcl.c_date));
536 fprintf(stdout, "Dumped from: %s",
537 (spcl.c_ddate == 0) ? "the epoch\n" : ctime4(&spcl.c_ddate));
538 #else
539 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date));
540 fprintf(stdout, "Dumped from: %s",
541 (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
542 #endif
543 if (spcl.c_host[0] == '\0')
544 return;
545 fprintf(stderr, "Level %d dump of %s on %s:%s\n",
546 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
547 fprintf(stderr, "Label: %s\n", spcl.c_label);
548 }
549
550 int
551 extractfile(name)
552 char *name;
553 {
554 int flags;
555 mode_t mode;
556 struct timeval timep[2];
557 struct entry *ep;
558 #ifdef __linux__
559 int err;
560 uid_t uid;
561 gid_t gid;
562 #endif
563
564 curfile.name = name;
565 curfile.action = USING;
566 #ifdef __linux__
567 timep[0].tv_sec = curfile.dip->di_atime.tv_sec;
568 timep[0].tv_usec = curfile.dip->di_atime.tv_usec;
569 timep[1].tv_sec = curfile.dip->di_mtime.tv_sec;
570 timep[1].tv_usec = curfile.dip->di_mtime.tv_usec;
571 #else /* __linux__ */
572 timep[0].tv_sec = curfile.dip->di_atime;
573 timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
574 timep[1].tv_sec = curfile.dip->di_mtime;
575 timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
576 #endif /* __linux__ */
577 mode = curfile.dip->di_mode;
578 flags = curfile.dip->di_flags;
579 switch (mode & IFMT) {
580
581 default:
582 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
583 skipfile();
584 return (FAIL);
585
586 case IFSOCK:
587 vprintf(stdout, "skipped socket %s\n", name);
588 skipfile();
589 return (GOOD);
590
591 case IFDIR:
592 if (mflag) {
593 ep = lookupname(name);
594 if (ep == NULL || ep->e_flags & EXTRACT)
595 panic("unextracted directory %s\n", name);
596 skipfile();
597 return (GOOD);
598 }
599 vprintf(stdout, "extract file %s\n", name);
600 return (genliteraldir(name, curfile.ino));
601
602 case IFLNK:
603 lnkbuf[0] = '\0';
604 pathlen = 0;
605 #ifdef __linux__
606 uid = curfile.dip->di_uid;
607 gid = curfile.dip->di_gid;
608 #endif
609 getfile(xtrlnkfile, xtrlnkskip);
610 if (pathlen == 0) {
611 vprintf(stdout,
612 "%s: zero length symbolic link (ignored)\n", name);
613 return (GOOD);
614 }
615 #ifdef __linux__
616 err = linkit(lnkbuf, name, SYMLINK);
617 if (err == GOOD)
618 (void) chown(name, uid, gid);
619 return (err);
620 #else
621 return (linkit(lnkbuf, name, SYMLINK));
622 #endif
623
624 case IFIFO:
625 vprintf(stdout, "extract fifo %s\n", name);
626 if (Nflag) {
627 skipfile();
628 return (GOOD);
629 }
630 if (uflag && !Nflag)
631 (void)unlink(name);
632 if (mkfifo(name, mode) < 0) {
633 fprintf(stderr, "%s: cannot create fifo: %s\n",
634 name, strerror(errno));
635 skipfile();
636 return (FAIL);
637 }
638 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
639 (void) chmod(name, mode);
640 #ifdef __linux__
641 (void) fsetflags(name, flags);
642 #else
643 (void) chflags(name, flags);
644 #endif
645 skipfile();
646 utimes(name, timep);
647 return (GOOD);
648
649 case IFCHR:
650 case IFBLK:
651 vprintf(stdout, "extract special file %s\n", name);
652 if (Nflag) {
653 skipfile();
654 return (GOOD);
655 }
656 if (uflag)
657 (void)unlink(name);
658 if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
659 fprintf(stderr, "%s: cannot create special file: %s\n",
660 name, strerror(errno));
661 skipfile();
662 return (FAIL);
663 }
664 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
665 (void) chmod(name, mode);
666 #ifdef __linux__
667 (void) fsetflags(name, flags);
668 #else
669 (void) chflags(name, flags);
670 #endif
671 skipfile();
672 utimes(name, timep);
673 return (GOOD);
674
675 case IFREG:
676 vprintf(stdout, "extract file %s\n", name);
677 if (Nflag) {
678 skipfile();
679 return (GOOD);
680 }
681 if (uflag)
682 (void)unlink(name);
683 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
684 0666)) < 0) {
685 fprintf(stderr, "%s: cannot create file: %s\n",
686 name, strerror(errno));
687 skipfile();
688 return (FAIL);
689 }
690 (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
691 (void) fchmod(ofile, mode);
692 #ifdef __linux__
693 (void) fsetflags(ofile, flags);
694 #else
695 (void) fchflags(ofile, flags);
696 #endif
697 getfile(xtrfile, xtrskip);
698 (void) close(ofile);
699 utimes(name, timep);
700 return (GOOD);
701 }
702 /* NOTREACHED */
703 }
704
705 /*
706 * skip over bit maps on the tape
707 */
708 void
709 skipmaps()
710 {
711
712 while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
713 skipfile();
714 }
715
716 /*
717 * skip over a file on the tape
718 */
719 void
720 skipfile()
721 {
722
723 curfile.action = SKIP;
724 getfile(xtrnull, xtrnull);
725 }
726
727 /*
728 * Extract a file from the tape.
729 * When an allocated block is found it is passed to the fill function;
730 * when an unallocated block (hole) is found, a zeroed buffer is passed
731 * to the skip function.
732 */
733 void
734 getfile(fill, skip)
735 void (*fill) __P((char *, long));
736 void (*skip) __P((char *, long));
737 {
738 register int i;
739 int curblk = 0;
740 quad_t size = spcl.c_dinode.di_size;
741 int last_write_was_hole = 0;
742 long origsize = size;
743 static char clearedbuf[MAXBSIZE];
744 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
745 char junk[TP_BSIZE];
746
747 if (spcl.c_type == TS_END)
748 panic("ran off end of tape\n");
749 if (spcl.c_magic != NFS_MAGIC)
750 panic("not at beginning of a file\n");
751 if (!gettingfile && setjmp(restart) != 0)
752 return;
753 gettingfile++;
754 loop:
755 for (i = 0; i < spcl.c_count; i++) {
756 if (readmapflag || spcl.c_addr[i]) {
757 readtape(&buf[curblk++][0]);
758 if (curblk == fssize / TP_BSIZE) {
759 (*fill)((char *)buf, (long)(size > TP_BSIZE ?
760 fssize : (curblk - 1) * TP_BSIZE + size));
761 curblk = 0;
762 last_write_was_hole = 0;
763 }
764 } else {
765 if (curblk > 0) {
766 (*fill)((char *)buf, (long)(size > TP_BSIZE ?
767 curblk * TP_BSIZE :
768 (curblk - 1) * TP_BSIZE + size));
769 curblk = 0;
770 }
771 (*skip)(clearedbuf, (long)(size > TP_BSIZE ?
772 TP_BSIZE : size));
773 last_write_was_hole = 1;
774 }
775 if ((size -= TP_BSIZE) <= 0) {
776 for (i++; i < spcl.c_count; i++)
777 if (readmapflag || spcl.c_addr[i])
778 readtape(junk);
779 break;
780 }
781 }
782 if (gethead(&spcl) == GOOD && size > 0) {
783 if (spcl.c_type == TS_ADDR)
784 goto loop;
785 dprintf(stdout,
786 "Missing address (header) block for %s at %ld blocks\n",
787 curfile.name, blksread);
788 }
789 if (curblk > 0) {
790 (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
791 last_write_was_hole = 0;
792 }
793 if (last_write_was_hole) {
794 ftruncate(ofile, origsize);
795 }
796 findinode(&spcl);
797 gettingfile = 0;
798 }
799
800 /*
801 * Write out the next block of a file.
802 */
803 static void
804 xtrfile(buf, size)
805 char *buf;
806 long size;
807 {
808
809 if (Nflag)
810 return;
811 if (write(ofile, buf, (int) size) == -1) {
812 fprintf(stderr,
813 "write error extracting inode %ld, name %s\nwrite: %s\n",
814 curfile.ino, curfile.name, strerror(errno));
815 done(1);
816 }
817 }
818
819 /*
820 * Skip over a hole in a file.
821 */
822 /* ARGSUSED */
823 static void
824 xtrskip(buf, size)
825 char *buf;
826 long size;
827 {
828
829 if (lseek(ofile, size, SEEK_CUR) == -1) {
830 fprintf(stderr,
831 "seek error extracting inode %ld, name %s\nlseek: %s\n",
832 curfile.ino, curfile.name, strerror(errno));
833 done(1);
834 }
835 }
836
837 /*
838 * Collect the next block of a symbolic link.
839 */
840 static void
841 xtrlnkfile(buf, size)
842 char *buf;
843 long size;
844 {
845
846 pathlen += size;
847 if (pathlen > MAXPATHLEN) {
848 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
849 curfile.name, lnkbuf, buf, pathlen);
850 done(1);
851 }
852 (void) strcat(lnkbuf, buf);
853 }
854
855 /*
856 * Skip over a hole in a symbolic link (should never happen).
857 */
858 /* ARGSUSED */
859 static void
860 xtrlnkskip(buf, size)
861 char *buf;
862 long size;
863 {
864
865 fprintf(stderr, "unallocated block in symbolic link %s\n",
866 curfile.name);
867 done(1);
868 }
869
870 /*
871 * Collect the next block of a bit map.
872 */
873 static void
874 xtrmap(buf, size)
875 char *buf;
876 long size;
877 {
878
879 memmove(map, buf, size);
880 map += size;
881 }
882
883 /*
884 * Skip over a hole in a bit map (should never happen).
885 */
886 /* ARGSUSED */
887 static void
888 xtrmapskip(buf, size)
889 char *buf;
890 long size;
891 {
892
893 panic("hole in map\n");
894 map += size;
895 }
896
897 /*
898 * Noop, when an extraction function is not needed.
899 */
900 /* ARGSUSED */
901 void
902 xtrnull(buf, size)
903 char *buf;
904 long size;
905 {
906
907 return;
908 }
909
910 int
911 do_cmpfiles(int fd_tape, int fd_disk, long size)
912 {
913 #ifndef BUFSIZE
914 #define BUFSIZE 1024
915 #endif
916 static char buf_tape[BUFSIZ];
917 static char buf_disk[BUFSIZ];
918 int n_tape;
919 int n_disk;
920
921 while (size > 0) {
922 if ((n_tape = read(fd_tape, buf_tape, BUFSIZE)) < 1) {
923 close(fd_tape), close(fd_disk);
924 panic("do_cmpfiles: unexpected EOF[1]");
925 }
926 if ((n_disk = read(fd_disk, buf_disk, BUFSIZE)) < 1) {
927 close(fd_tape), close(fd_disk);
928 panic("do_cmpfiles: unexpected EOF[2]");
929 }
930 if (n_tape != n_disk) {
931 close(fd_tape), close(fd_disk);
932 panic("do_cmpfiles: sizes different!");
933 }
934 if (memcmp(buf_tape, buf_disk, n_tape) != 0) return (1);
935 size -= n_tape;
936 }
937 return (0);
938 }
939
940 /* for debugging compare problems */
941 #undef COMPARE_FAIL_KEEP_FILE
942
943 #ifdef COMPARE_FAIL_KEEP_FILE
944 /* return true if tapefile should be unlinked after compare */
945 int
946 #else
947 void
948 #endif
949 cmpfiles(char *tapefile, char *diskfile, struct stat *sbuf_disk)
950 {
951 struct stat sbuf_tape;
952 int fd_tape, fd_disk;
953
954 if (stat(tapefile, &sbuf_tape) != 0) {
955 panic("Can't lstat tmp file %s: %s\n", tapefile,
956 strerror(errno));
957 }
958
959 if (sbuf_disk->st_size != sbuf_tape.st_size) {
960 fprintf(stderr,
961 "%s: size changed from %ld to %ld.\n",
962 diskfile, sbuf_tape.st_size, sbuf_disk->st_size);
963 #ifdef COMPARE_FAIL_KEEP_FILE
964 return (0);
965 #else
966 return;
967 #endif
968 }
969
970 if ((fd_tape = open(tapefile, O_RDONLY)) < 0) {
971 panic("Can't open %s: %s\n", tapefile, strerror(errno));
972 }
973 if ((fd_disk = open(diskfile, O_RDONLY)) < 0) {
974 close(fd_tape);
975 panic("Can't open %s: %s\n", diskfile, strerror(errno));
976 }
977
978 if (do_cmpfiles(fd_tape, fd_disk, sbuf_tape.st_size)) {
979 fprintf(stderr, "%s: tape and disk copies are different\n",
980 diskfile);
981 close(fd_tape);
982 close(fd_disk);
983 #ifdef COMPARE_FAIL_KEEP_FILE
984 /* rename the file to live in /tmp */
985 /* rename `tapefile' to /tmp/<basename of diskfile> */
986 {
987 char *p = strrchr(diskfile, '/');
988 char newname[MAXPATHLEN];
989 if (!p) {
990 panic("can't find / in %s\n", diskfile);
991 }
992 sprintf(newname, "%s/debug/%s", tmpdir, p + 1);
993 if (rename(tapefile, newname)) {
994 panic("rename from %s to %s failed: %s\n",
995 tapefile, newname,
996 strerror(errno));
997 } else {
998 fprintf(stderr, "*** %s saved to %s\n",
999 tapefile, newname);
1000 }
1001 }
1002
1003 /* don't unlink the file (it's not there anymore */
1004 /* anyway) */
1005 return (0);
1006 #else
1007 return;
1008 #endif
1009 }
1010 close(fd_tape);
1011 close(fd_disk);
1012 #ifdef COMPARE_FAIL_KEEP_FILE
1013 return (1);
1014 #endif
1015 }
1016
1017 static char tmpfilename[128];
1018
1019 void
1020 comparefile(name)
1021 char *name;
1022 {
1023 static char *tmpfile = NULL;
1024 int mode;
1025 struct stat sb, stemp;
1026 int r;
1027
1028 if ((r = lstat(name, &sb)) != 0) {
1029 fprintf(stderr, "%s: does not exist (%d, %d).\n", name, r, errno);
1030 skipfile();
1031 return;
1032 }
1033
1034 curfile.name = name;
1035 curfile.action = USING;
1036 mode = curfile.dip->di_mode;
1037
1038 vprintf(stdout, "comparing %s (size: %ld, mode: 0%o)\n", name,
1039 sb.st_size, mode);
1040
1041 if (sb.st_mode != mode) {
1042 fprintf(stderr, "%s: mode changed from 0%o to 0%o.\n",
1043 name, mode & 07777, sb.st_mode & 07777);
1044 }
1045 switch (mode & IFMT) {
1046 default:
1047 skipfile();
1048 return;
1049
1050 case IFSOCK:
1051 skipfile();
1052 return;
1053
1054 case IFDIR:
1055 skipfile();
1056 return;
1057
1058 case IFLNK: {
1059 char lbuf[MAXPATHLEN + 1];
1060 int lsize;
1061
1062 if (!(sb.st_mode & S_IFLNK)) {
1063 fprintf(stderr, "%s: is no longer a symbolic link\n",
1064 name);
1065 return;
1066 }
1067 lnkbuf[0] = '\0';
1068 pathlen = 0;
1069 getfile(xtrlnkfile, xtrlnkskip);
1070 if (pathlen == 0) {
1071 fprintf(stderr,
1072 "%s: zero length symbolic link (ignored)\n",
1073 name);
1074 return;
1075 }
1076 if ((lsize = readlink(name, lbuf, MAXPATHLEN)) < 0) {
1077 panic("readlink of %s failed: %s", name,
1078 strerror(errno));
1079 }
1080 lbuf[lsize] = 0;
1081 if (strcmp(lbuf, lnkbuf) != 0) {
1082 fprintf(stderr,
1083 "%s: symbolic link changed from %s to %s.\n",
1084 name, lnkbuf, lbuf);
1085 return;
1086 }
1087 return;
1088 }
1089
1090 case IFCHR:
1091 case IFBLK:
1092 if (!(sb.st_mode & (S_IFCHR|S_IFBLK))) {
1093 fprintf(stderr, "%s: no longer a special file\n",
1094 name);
1095 skipfile();
1096 return;
1097 }
1098
1099 if (sb.st_rdev != (int)curfile.dip->di_rdev) {
1100 fprintf(stderr,
1101 "%s: device changed from %d,%d to %d,%d.\n",
1102 name,
1103 ((int)curfile.dip->di_rdev >> 8) & 0xf,
1104 (int)curfile.dip->di_rdev & 0xf,
1105 ((int)sb.st_rdev >> 8) & 0xf,
1106 (int)sb.st_rdev & 0xf);
1107 }
1108 skipfile();
1109 return;
1110
1111 case IFREG:
1112 if (tmpfile == NULL) {
1113 /* argument to mktemp() must not be in RO space: */
1114 sprintf(tmpfilename, "%s/restoreCXXXXXX", tmpdir);
1115 tmpfile = mktemp(&tmpfilename[0]);
1116 }
1117 if ((stat(tmpfile, &stemp) == 0) && (unlink(tmpfile) != 0)) {
1118 panic("cannot delete tmp file %s: %s\n",
1119 tmpfile, strerror(errno));
1120 }
1121 if ((ofile = creat(tmpfile, 0600)) < 0) {
1122 panic("cannot create file temp file %s: %s\n",
1123 name, strerror(errno));
1124 }
1125 getfile(xtrfile, xtrskip);
1126 (void) close(ofile);
1127 #ifdef COMPARE_FAIL_KEEP_FILE
1128 if (cmpfiles(tmpfile, name, &sb))
1129 unlink(tmpfile);
1130 #else
1131 cmpfiles(tmpfile, name, &sb);
1132 unlink(tmpfile);
1133 #endif
1134 return;
1135 }
1136 /* NOTREACHED */
1137 }
1138
1139 /*
1140 * Read TP_BSIZE blocks from the input.
1141 * Handle read errors, and end of media.
1142 */
1143 static void
1144 readtape(buf)
1145 char *buf;
1146 {
1147 long rd, newvol, i;
1148 int cnt, seek_failed;
1149
1150 if (blkcnt < numtrec) {
1151 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
1152 blksread++;
1153 tpblksread++;
1154 return;
1155 }
1156 for (i = 0; i < ntrec; i++)
1157 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1158 if (numtrec == 0)
1159 numtrec = ntrec;
1160 cnt = ntrec * TP_BSIZE;
1161 rd = 0;
1162 getmore:
1163 #ifdef RRESTORE
1164 if (host)
1165 i = rmtread(&tapebuf[rd], cnt);
1166 else
1167 #endif
1168 i = read(mt, &tapebuf[rd], cnt);
1169 /*
1170 * Check for mid-tape short read error.
1171 * If found, skip rest of buffer and start with the next.
1172 */
1173 if (!pipein && numtrec < ntrec && i > 0) {
1174 dprintf(stdout, "mid-media short read error.\n");
1175 numtrec = ntrec;
1176 }
1177 /*
1178 * Handle partial block read.
1179 */
1180 if (pipein && i == 0 && rd > 0)
1181 i = rd;
1182 else if (i > 0 && i != ntrec * TP_BSIZE) {
1183 if (pipein) {
1184 rd += i;
1185 cnt -= i;
1186 if (cnt > 0)
1187 goto getmore;
1188 i = rd;
1189 } else {
1190 /*
1191 * Short read. Process the blocks read.
1192 */
1193 if (i % TP_BSIZE != 0)
1194 vprintf(stdout,
1195 "partial block read: %ld should be %ld\n",
1196 i, ntrec * TP_BSIZE);
1197 numtrec = i / TP_BSIZE;
1198 }
1199 }
1200 /*
1201 * Handle read error.
1202 */
1203 if (i < 0) {
1204 fprintf(stderr, "Tape read error while ");
1205 switch (curfile.action) {
1206 default:
1207 fprintf(stderr, "trying to set up tape\n");
1208 break;
1209 case UNKNOWN:
1210 fprintf(stderr, "trying to resynchronize\n");
1211 break;
1212 case USING:
1213 fprintf(stderr, "restoring %s\n", curfile.name);
1214 break;
1215 case SKIP:
1216 fprintf(stderr, "skipping over inode %ld\n",
1217 curfile.ino);
1218 break;
1219 }
1220 if (!yflag && !reply("continue"))
1221 done(1);
1222 i = ntrec * TP_BSIZE;
1223 memset(tapebuf, 0, i);
1224 #ifdef RRESTORE
1225 if (host)
1226 seek_failed = (rmtseek(i, 1) < 0);
1227 else
1228 #endif
1229 seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
1230
1231 if (seek_failed) {
1232 fprintf(stderr,
1233 "continuation failed: %s\n", strerror(errno));
1234 done(1);
1235 }
1236 }
1237 /*
1238 * Handle end of tape.
1239 */
1240 if (i == 0) {
1241 vprintf(stdout, "End-of-tape encountered\n");
1242 if (!pipein) {
1243 newvol = volno + 1;
1244 volno = 0;
1245 numtrec = 0;
1246 getvol(newvol);
1247 readtape(buf);
1248 return;
1249 }
1250 if (rd % TP_BSIZE != 0)
1251 panic("partial block read: %d should be %d\n",
1252 rd, ntrec * TP_BSIZE);
1253 terminateinput();
1254 memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
1255 }
1256 blkcnt = 0;
1257 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
1258 blksread++;
1259 tpblksread++;
1260 }
1261
1262 static void
1263 findtapeblksize()
1264 {
1265 register long i;
1266
1267 for (i = 0; i < ntrec; i++)
1268 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1269 blkcnt = 0;
1270 #ifdef RRESTORE
1271 if (host)
1272 i = rmtread(tapebuf, ntrec * TP_BSIZE);
1273 else
1274 #endif
1275 i = read(mt, tapebuf, ntrec * TP_BSIZE);
1276
1277 if (i <= 0) {
1278 fprintf(stderr, "tape read error: %s\n", strerror(errno));
1279 done(1);
1280 }
1281 if (i % TP_BSIZE != 0) {
1282 fprintf(stderr, "Tape block size (%ld) %s (%d)\n",
1283 i, "is not a multiple of dump block size", TP_BSIZE);
1284 done(1);
1285 }
1286 ntrec = i / TP_BSIZE;
1287 numtrec = ntrec;
1288 vprintf(stdout, "Tape block size is %ld\n", ntrec);
1289 }
1290
1291 void
1292 closemt()
1293 {
1294
1295 if (mt < 0)
1296 return;
1297 #ifdef RRESTORE
1298 if (host)
1299 rmtclose();
1300 else
1301 #endif
1302 (void) close(mt);
1303 }
1304
1305 /*
1306 * Read the next block from the tape.
1307 * Check to see if it is one of several vintage headers.
1308 * If it is an old style header, convert it to a new style header.
1309 * If it is not any valid header, return an error.
1310 */
1311 static int
1312 gethead(buf)
1313 struct s_spcl *buf;
1314 {
1315 long i;
1316 union {
1317 quad_t qval;
1318 int32_t val[2];
1319 } qcvt;
1320 union u_ospcl {
1321 char dummy[TP_BSIZE];
1322 struct s_ospcl {
1323 int32_t c_type;
1324 int32_t c_date;
1325 int32_t c_ddate;
1326 int32_t c_volume;
1327 int32_t c_tapea;
1328 u_short c_inumber;
1329 int32_t c_magic;
1330 int32_t c_checksum;
1331 struct odinode {
1332 unsigned short odi_mode;
1333 u_short odi_nlink;
1334 u_short odi_uid;
1335 u_short odi_gid;
1336 int32_t odi_size;
1337 int32_t odi_rdev;
1338 char odi_addr[36];
1339 int32_t odi_atime;
1340 int32_t odi_mtime;
1341 int32_t odi_ctime;
1342 } c_dinode;
1343 int32_t c_count;
1344 char c_addr[256];
1345 } s_ospcl;
1346 } u_ospcl;
1347
1348 if (!cvtflag) {
1349 readtape((char *)buf);
1350 if (buf->c_magic != NFS_MAGIC) {
1351 if (swabl(buf->c_magic) != NFS_MAGIC)
1352 return (FAIL);
1353 if (!Bcvt) {
1354 vprintf(stdout, "Note: Doing Byte swapping\n");
1355 Bcvt = 1;
1356 }
1357 }
1358 if (checksum((int *)buf) == FAIL)
1359 return (FAIL);
1360 if (Bcvt) {
1361 swabst((u_char *)"8l4s31l", (u_char *)buf);
1362 swabst((u_char *)"l",(u_char *) &buf->c_level);
1363 swabst((u_char *)"2l",(u_char *) &buf->c_flags);
1364 }
1365 goto good;
1366 }
1367 readtape((char *)(&u_ospcl.s_ospcl));
1368 memset(buf, 0, (long)TP_BSIZE);
1369 buf->c_type = u_ospcl.s_ospcl.c_type;
1370 buf->c_date = u_ospcl.s_ospcl.c_date;
1371 buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1372 buf->c_volume = u_ospcl.s_ospcl.c_volume;
1373 buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1374 buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1375 buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1376 buf->c_magic = u_ospcl.s_ospcl.c_magic;
1377 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1378 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1379 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1380 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1381 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
1382 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1383 #ifdef __linux__
1384 buf->c_dinode.di_atime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_atime;
1385 buf->c_dinode.di_mtime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1386 buf->c_dinode.di_ctime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1387 #else /* __linux__ */
1388 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
1389 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1390 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1391 #endif /* __linux__ */
1392 buf->c_count = u_ospcl.s_ospcl.c_count;
1393 memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256);
1394 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
1395 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
1396 return(FAIL);
1397 buf->c_magic = NFS_MAGIC;
1398
1399 good:
1400 if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
1401 (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
1402 qcvt.qval = buf->c_dinode.di_size;
1403 if (qcvt.val[0] || qcvt.val[1]) {
1404 printf("Note: Doing Quad swapping\n");
1405 Qcvt = 1;
1406 }
1407 }
1408 if (Qcvt) {
1409 qcvt.qval = buf->c_dinode.di_size;
1410 i = qcvt.val[1];
1411 qcvt.val[1] = qcvt.val[0];
1412 qcvt.val[0] = i;
1413 buf->c_dinode.di_size = qcvt.qval;
1414 }
1415 readmapflag = 0;
1416
1417 switch (buf->c_type) {
1418
1419 case TS_CLRI:
1420 case TS_BITS:
1421 /*
1422 * Have to patch up missing information in bit map headers
1423 */
1424 buf->c_inumber = 0;
1425 buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
1426 if (buf->c_count > TP_NINDIR)
1427 readmapflag = 1;
1428 else
1429 for (i = 0; i < buf->c_count; i++)
1430 buf->c_addr[i]++;
1431 break;
1432
1433 case TS_TAPE:
1434 if ((buf->c_flags & DR_NEWINODEFMT) == 0)
1435 oldinofmt = 1;
1436 /* fall through */
1437 case TS_END:
1438 buf->c_inumber = 0;
1439 break;
1440
1441 case TS_INODE:
1442 case TS_ADDR:
1443 break;
1444
1445 default:
1446 panic("gethead: unknown inode type %d\n", buf->c_type);
1447 break;
1448 }
1449 /*
1450 * If we are restoring a filesystem with old format inodes,
1451 * copy the uid/gid to the new location.
1452 */
1453 if (oldinofmt) {
1454 buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
1455 buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
1456 }
1457 if (dflag)
1458 accthdr(buf);
1459 return(GOOD);
1460 }
1461
1462 /*
1463 * Check that a header is where it belongs and predict the next header
1464 */
1465 static void
1466 accthdr(header)
1467 struct s_spcl *header;
1468 {
1469 static ino_t previno = 0x7fffffff;
1470 static int prevtype;
1471 static long predict;
1472 long blks, i;
1473
1474 if (header->c_type == TS_TAPE) {
1475 fprintf(stderr, "Volume header (%s inode format) ",
1476 oldinofmt ? "old" : "new");
1477 if (header->c_firstrec)
1478 fprintf(stderr, "begins with record %d",
1479 header->c_firstrec);
1480 fprintf(stderr, "\n");
1481 previno = 0x7fffffff;
1482 return;
1483 }
1484 if (previno == 0x7fffffff)
1485 goto newcalc;
1486 switch (prevtype) {
1487 case TS_BITS:
1488 fprintf(stderr, "Dumped inodes map header");
1489 break;
1490 case TS_CLRI:
1491 fprintf(stderr, "Used inodes map header");
1492 break;
1493 case TS_INODE:
1494 fprintf(stderr, "File header, ino %ld", previno);
1495 break;
1496 case TS_ADDR:
1497 fprintf(stderr, "File continuation header, ino %ld", previno);
1498 break;
1499 case TS_END:
1500 fprintf(stderr, "End of tape header");
1501 break;
1502 }
1503 if (predict != blksread - 1)
1504 fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
1505 predict, blksread - 1);
1506 fprintf(stderr, "\n");
1507 newcalc:
1508 blks = 0;
1509 if (header->c_type != TS_END)
1510 for (i = 0; i < header->c_count; i++)
1511 if (readmapflag || header->c_addr[i] != 0)
1512 blks++;
1513 predict = blks;
1514 blksread = 0;
1515 prevtype = header->c_type;
1516 previno = header->c_inumber;
1517 }
1518
1519 /*
1520 * Find an inode header.
1521 * Complain if had to skip, and complain is set.
1522 */
1523 static void
1524 findinode(header)
1525 struct s_spcl *header;
1526 {
1527 static long skipcnt = 0;
1528 long i;
1529 char buf[TP_BSIZE];
1530
1531 curfile.name = "<name unknown>";
1532 curfile.action = UNKNOWN;
1533 curfile.dip = NULL;
1534 curfile.ino = 0;
1535 do {
1536 if (header->c_magic != NFS_MAGIC) {
1537 skipcnt++;
1538 while (gethead(header) == FAIL ||
1539 header->c_date != dumpdate)
1540 skipcnt++;
1541 }
1542 switch (header->c_type) {
1543
1544 case TS_ADDR:
1545 /*
1546 * Skip up to the beginning of the next record
1547 */
1548 for (i = 0; i < header->c_count; i++)
1549 if (header->c_addr[i])
1550 readtape(buf);
1551 while (gethead(header) == FAIL ||
1552 header->c_date != dumpdate)
1553 skipcnt++;
1554 break;
1555
1556 case TS_INODE:
1557 curfile.dip = &header->c_dinode;
1558 curfile.ino = header->c_inumber;
1559 break;
1560
1561 case TS_END:
1562 curfile.ino = maxino;
1563 break;
1564
1565 case TS_CLRI:
1566 curfile.name = "<file removal list>";
1567 break;
1568
1569 case TS_BITS:
1570 curfile.name = "<file dump list>";
1571 break;
1572
1573 case TS_TAPE:
1574 panic("unexpected tape header\n");
1575 /* NOTREACHED */
1576
1577 default:
1578 panic("unknown tape header type %d\n", spcl.c_type);
1579 /* NOTREACHED */
1580
1581 }
1582 } while (header->c_type == TS_ADDR);
1583 if (skipcnt > 0)
1584 fprintf(stderr, "resync restore, skipped %ld blocks\n",
1585 skipcnt);
1586 skipcnt = 0;
1587 }
1588
1589 static int
1590 checksum(buf)
1591 register int *buf;
1592 {
1593 register int i, j;
1594
1595 j = sizeof(union u_spcl) / sizeof(int);
1596 i = 0;
1597 if(!Bcvt) {
1598 do
1599 i += *buf++;
1600 while (--j);
1601 } else {
1602 /* What happens if we want to read restore tapes
1603 for a 16bit int machine??? */
1604 do
1605 i += swabl(*buf++);
1606 while (--j);
1607 }
1608
1609 if (i != CHECKSUM) {
1610 fprintf(stderr, "Checksum error %o, inode %ld file %s\n", i,
1611 curfile.ino, curfile.name);
1612 return(FAIL);
1613 }
1614 return(GOOD);
1615 }
1616
1617 #ifdef RRESTORE
1618 #if __STDC__
1619 #include <stdarg.h>
1620 #else
1621 #include <varargs.h>
1622 #endif
1623
1624 void
1625 #if __STDC__
1626 msg(const char *fmt, ...)
1627 #else
1628 msg(fmt, va_alist)
1629 char *fmt;
1630 va_dcl
1631 #endif
1632 {
1633 va_list ap;
1634 #if __STDC__
1635 va_start(ap, fmt);
1636 #else
1637 va_start(ap);
1638 #endif
1639 (void)vfprintf(stderr, fmt, ap);
1640 va_end(ap);
1641 }
1642 #endif /* RRESTORE */
1643
1644 static u_char *
1645 swabshort(sp, n)
1646 register u_char *sp;
1647 register int n;
1648 {
1649 char c;
1650
1651 while (--n >= 0) {
1652 c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1653 sp += 2;
1654 }
1655 return (sp);
1656 }
1657
1658 static u_char *
1659 swablong(sp, n)
1660 register u_char *sp;
1661 register int n;
1662 {
1663 char c;
1664
1665 while (--n >= 0) {
1666 c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1667 c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1668 sp += 4;
1669 }
1670 return (sp);
1671 }
1672
1673 void
1674 swabst(cp, sp)
1675 register u_char *cp, *sp;
1676 {
1677 int n = 0;
1678
1679 while (*cp) {
1680 switch (*cp) {
1681 case '0': case '1': case '2': case '3': case '4':
1682 case '5': case '6': case '7': case '8': case '9':
1683 n = (n * 10) + (*cp++ - '0');
1684 continue;
1685
1686 case 's': case 'w': case 'h':
1687 if (n == 0)
1688 n = 1;
1689 sp = swabshort(sp, n);
1690 break;
1691
1692 case 'l':
1693 if (n == 0)
1694 n = 1;
1695 sp = swablong(sp, n);
1696 break;
1697
1698 default: /* Any other character, like 'b' counts as byte. */
1699 if (n == 0)
1700 n = 1;
1701 sp += n;
1702 break;
1703 }
1704 cp++;
1705 n = 0;
1706 }
1707 }
1708
1709 static u_long
1710 swabl(x)
1711 u_long x;
1712 {
1713 swabst((u_char *)"l", (u_char *)&x);
1714 return (x);
1715 }