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