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