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