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