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