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