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