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