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