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