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