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