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