1 /*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
8 /* All Rights Reserved */
9
10 /*
11 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
12 * Use is subject to license terms.
13 */
14
15 #include <setjmp.h>
16 #include "restore.h"
17 #include <byteorder.h>
18 #include <rmt.h>
19 #include <sys/mtio.h>
20 #include <utime.h>
21 #include <sys/errno.h>
22 #include <sys/fdio.h>
23 #include <sys/sysmacros.h> /* for expdev */
24 #include <assert.h>
25 #include <limits.h>
26 #include <priv_utils.h>
27 #include <aclutils.h>
28
29 #define MAXINO 65535 /* KLUDGE */
30
31 #define MAXTAPES 128
32
33 static size_t fssize = MAXBSIZE; /* preferred size of writes to filesystem */
34 int mt = -1;
35 static int continuemap = 0;
36 char magtape[BUFSIZ];
37 int pipein = 0;
38 char *host; /* used in dumprmt.c */
39 daddr32_t rec_position;
40 static char *archivefile; /* used in metamucil.c */
41 static int bct; /* block # index into tape record buffer */
42 static int numtrec; /* # of logical blocks in current tape record */
43 static char *tbf = NULL;
44 static size_t tbfsize = 0;
45 static int recsread;
46 union u_spcl u_spcl;
47 static union u_spcl endoftapemark;
48 static struct s_spcl dumpinfo;
49 static long blksread; /* # of logical blocks actually read/touched */
50 static long tapea; /* current logical block # on tape */
51 static uchar_t tapesread[MAXTAPES];
52 static jmp_buf restart;
53 static int gettingfile = 0; /* restart has a valid frame */
54 static int ofile;
55 static char *map, *beginmap;
56 static char *endmap;
57 static char lnkbuf[MAXPATHLEN + 2];
58 static int pathlen;
59 static int inodeinfo; /* Have starting volume information */
60 static int hostinfo; /* Have dump host information */
61
62 static int autoload_tape(void);
63 static void setdumpnum(void);
64 static void metacheck(struct s_spcl *);
65 static void xtrmeta(char *, size_t);
66 static void metaskip(char *, size_t);
67 static void xtrfile(char *, size_t);
68 static void xtrskip(char *, size_t);
69 static void xtrlnkfile(char *, size_t);
70 static void xtrlnkskip(char *, size_t);
71 static void xtrmap(char *, size_t);
72 static void xtrmapskip(char *, size_t);
73 static void readtape(char *);
74 static int checkvol(struct s_spcl *, int);
75 static void accthdr(struct s_spcl *);
76 static int ishead(struct s_spcl *);
77 static int checktype(struct s_spcl *, int);
78 static void metaset(char *name);
79
80 /*
81 * Set up an input source
82 */
83 void
setinput(char * source,char * archive)84 setinput(char *source, char *archive)
85 {
86
87 flsht();
88 archivefile = archive;
89 if (bflag == 0) {
90 ntrec = ((CARTRIDGETREC > HIGHDENSITYTREC) ?
91 (NTREC > CARTRIDGETREC ? NTREC : CARTRIDGETREC) :
92 (NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC));
93 saved_ntrec = (ntrec * (tp_bsize/DEV_BSIZE));
94 }
95 newtapebuf(ntrec);
96 terminal = stdin;
97
98 if (source == NULL) {
99 /* A can't-happen */
100 (void) fprintf(stderr,
101 gettext("Internal consistency check failed.\n"));
102 done(1);
103 }
104
105 if (strchr(source, ':')) {
106 char *tape;
107
108 host = source;
109 tape = strchr(host, ':');
110 *tape++ = '\0';
111 if (strlen(tape) > (sizeof (magtape) - 1)) {
112 (void) fprintf(stderr, gettext("Tape name too long\n"));
113 done(1);
114 }
115 (void) strcpy(magtape, tape);
116 if (rmthost(host, ntrec) == 0)
117 done(1);
118 } else {
119 if (strlen(source) > (sizeof (magtape) - 1)) {
120 (void) fprintf(stderr, gettext("Tape name too long\n"));
121 done(1);
122 }
123 /* Not remote, no need for privileges */
124 __priv_relinquish();
125 host = NULL;
126 if (strcmp(source, "-") == 0) {
127 /*
128 * Since input is coming from a pipe we must establish
129 * our own connection to the terminal.
130 */
131 terminal = fopen("/dev/tty", "r");
132 if (terminal == NULL) {
133 int saverr = errno;
134 char *msg =
135 gettext("Cannot open(\"/dev/tty\")");
136 errno = saverr;
137 perror(msg);
138 terminal = fopen("/dev/null", "r");
139 if (terminal == NULL) {
140 saverr = errno;
141 msg = gettext(
142 "Cannot open(\"/dev/null\")");
143 errno = saverr;
144 perror(msg);
145 done(1);
146 }
147 }
148 pipein++;
149 if (archive) {
150 (void) fprintf(stderr, gettext(
151 "Cannot specify an archive file when reading from a pipe\n"));
152 done(1);
153 }
154 }
155 (void) strcpy(magtape, source);
156 }
157 }
158
159 void
newtapebuf(size_t size)160 newtapebuf(size_t size)
161 {
162 size_t nsize;
163
164 nsize = size * tp_bsize;
165 ntrec = size;
166 if (nsize <= tbfsize)
167 return;
168 if (tbf != NULL)
169 free(tbf);
170 tbf = (char *)malloc(nsize);
171 if (tbf == NULL) {
172 (void) fprintf(stderr,
173 gettext("Cannot allocate space for buffer\n"));
174 done(1);
175 }
176 tbfsize = nsize;
177 }
178
179 /*
180 * Verify that the tape drive can be accessed and
181 * that it actually is a dump tape.
182 */
183 void
setup(void)184 setup(void)
185 {
186 int i, j;
187 int32_t *ip;
188 struct stat stbuf;
189 size_t mapsize;
190 char *syment = RESTORESYMTABLE;
191
192 vprintf(stdout, gettext("Verify volume and initialize maps\n"));
193 if (archivefile) {
194 mt = open(archivefile, O_RDONLY|O_LARGEFILE);
195 if (mt < 0) {
196 perror(archivefile);
197 done(1);
198 }
199 volno = 0;
200 } else if (host) {
201 if ((mt = rmtopen(magtape, O_RDONLY)) < 0) {
202 perror(magtape);
203 done(1);
204 }
205 volno = 1;
206 } else {
207 if (pipein)
208 mt = 0;
209 else if ((mt = open(magtape, O_RDONLY|O_LARGEFILE)) < 0) {
210 perror(magtape);
211 done(1);
212 }
213 volno = 1;
214 }
215 setdumpnum();
216 flsht();
217 if (!pipein && !bflag)
218 if (archivefile)
219 findtapeblksize(ARCHIVE_FILE);
220 else
221 findtapeblksize(TAPE_FILE);
222 if (bflag == 1) {
223 tape_rec_size = saved_ntrec * DEV_BSIZE;
224 }
225
226 /*
227 * Get the first header. If c_magic is NOT NFS_MAGIC or if
228 * the checksum is in error, it will fail. The magic could then
229 * be either OFS_MAGIC or MTB_MAGIC. If OFS_MAGIC, assume we
230 * have an old dump, and try to convert it. If it is MTB_MAGIC, we
231 * procees this after.
232 */
233 if ((gethead(&spcl) == FAIL) && (spcl.c_magic != MTB_MAGIC)) {
234 bct--; /* push back this block */
235 blksread--;
236 tapea--;
237 cvtflag++;
238 if (gethead(&spcl) == FAIL) {
239 (void) fprintf(stderr,
240 gettext("Volume is not in dump format\n"));
241 done(1);
242 }
243 (void) fprintf(stderr,
244 gettext("Converting to new file system format.\n"));
245 }
246 /*
247 * The above gethead will have failed if the magic is
248 * MTB_MAGIC. If that is true, we need to adjust tp_bsize.
249 * We have assumed to this time that tp_bsize was 1024, if
250 * this is a newer dump, get the real tp_bsize from the header,
251 * and recalculate ntrec, numtrec.
252 */
253 if (spcl.c_magic == MTB_MAGIC) {
254 tp_bsize = spcl.c_tpbsize;
255 if ((tp_bsize % TP_BSIZE_MIN != 0) ||
256 (tp_bsize > TP_BSIZE_MAX)) {
257 (void) fprintf(stderr,
258 gettext("Volume is not in dump format\n"));
259 done(1);
260 }
261 ntrec = (tape_rec_size/tp_bsize);
262 numtrec = ntrec;
263 newtapebuf(ntrec);
264 bct--; /* push back this block */
265 blksread--;
266 tapea--;
267 /* we have to re-do this in case checksum is wrong */
268 if (gethead(&spcl) == FAIL) {
269 (void) fprintf(stderr,
270 gettext("Volume is not in dump format\n"));
271 done(1);
272 }
273 }
274 if (vflag)
275 byteorder_banner(byteorder, stdout);
276 if (pipein) {
277 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC :
278 ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC);
279 endoftapemark.s_spcl.c_type = TS_END;
280
281 /*
282 * include this since the `resync' loop in findinode
283 * expects to find a header with the c_date field
284 * filled in.
285 */
286 endoftapemark.s_spcl.c_date = spcl.c_date;
287
288 ip = (int32_t *)&endoftapemark;
289 /*LINTED [assertion always true]*/
290 assert((sizeof (endoftapemark) % sizeof (int32_t)) == 0);
291 j = sizeof (endoftapemark) / sizeof (int32_t);
292 i = 0;
293 do
294 i += *ip++;
295 while (--j)
296 ;
297 endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
298 }
299 if (vflag && command != 't')
300 printdumpinfo();
301 dumptime = spcl.c_ddate;
302 dumpdate = spcl.c_date;
303 if (stat(".", &stbuf) < 0) {
304 perror(gettext("cannot stat ."));
305 done(1);
306 }
307 if (stbuf.st_blksize >= tp_bsize && stbuf.st_blksize <= MAXBSIZE) {
308 /* LINTED: value fits in a size_t */
309 fssize = stbuf.st_blksize;
310 } else {
311 fssize = MAXBSIZE;
312 }
313
314 if (checkvol(&spcl, 1) == FAIL) {
315 (void) fprintf(stderr,
316 gettext("This is not volume 1 of the dump\n"));
317 done(1);
318 }
319 if (readhdr(&spcl) == FAIL)
320 panic(gettext("no header after volume mark!\n"));
321
322 findinode(&spcl); /* sets curfile, resyncs the tape if need be */
323 if (checktype(&spcl, TS_CLRI) == FAIL) {
324 (void) fprintf(stderr,
325 gettext("Cannot find file removal list\n"));
326 done(1);
327 }
328 maxino = (unsigned)((spcl.c_count * tp_bsize * NBBY) + 1);
329 dprintf(stdout, "maxino = %lu\n", maxino);
330 /*
331 * Allocate space for at least MAXINO inodes to allow us
332 * to restore partial dump tapes written before dump was
333 * fixed to write out the entire inode map.
334 */
335 if (maxino > ULONG_MAX) {
336 (void) fprintf(stderr,
337 gettext("file system too large\n"));
338 done(1);
339 }
340 /* LINTED maxino size-checked above */
341 mapsize = (size_t)d_howmany(maxino > MAXINO ? maxino : MAXINO, NBBY);
342 beginmap = map = calloc((size_t)1, mapsize);
343 if (map == (char *)NIL) {
344 (void) fprintf(stderr,
345 gettext("no memory for file removal list\n"));
346 done(1);
347 }
348 endmap = map + mapsize;
349 clrimap = map;
350 curfile.action = USING;
351 continuemap = 1;
352 getfile(xtrmap, xtrmapskip);
353 if (MAXINO > maxino)
354 maxino = MAXINO;
355 if (checktype(&spcl, TS_BITS) == FAIL) {
356 /* if we have TS_CLRI then no TS_BITS then a TS_END */
357 /* then we have an empty dump file */
358 if (gethead(&spcl) == GOOD &&
359 checktype(&spcl, TS_END) == GOOD) {
360 if ((command == 'r') || (command == 'R')) {
361 initsymtable(syment);
362 dumpsymtable(syment, volno);
363 }
364 done(0);
365 }
366 /* otherwise we have an error */
367 (void) fprintf(stderr, gettext("Cannot find file dump list\n"));
368 done(1);
369 }
370 /* LINTED maxino size-checked above */
371 mapsize = (size_t)d_howmany(maxino, NBBY);
372 beginmap = map = calloc((size_t)1, mapsize);
373 if (map == (char *)NULL) {
374 (void) fprintf(stderr,
375 gettext("no memory for file dump list\n"));
376 done(1);
377 }
378 endmap = map + mapsize;
379 dumpmap = map;
380 curfile.action = USING;
381 continuemap = 1;
382 getfile(xtrmap, xtrmapskip);
383 continuemap = 0;
384 }
385
386 /*
387 * Initialize fssize variable for 'R' command to work.
388 */
389 void
setupR(void)390 setupR(void)
391 {
392 struct stat stbuf;
393
394 if (stat(".", &stbuf) < 0) {
395 perror(gettext("cannot stat ."));
396 done(1);
397 }
398 if (stbuf.st_blksize >= tp_bsize && stbuf.st_blksize <= MAXBSIZE) {
399 /* LINTED: value fits in a size_t */
400 fssize = stbuf.st_blksize;
401 } else {
402 fssize = MAXBSIZE;
403 }
404 }
405
406 /*
407 * Prompt user to load a new dump volume.
408 * "Nextvol" is the next suggested volume to use.
409 * This suggested volume is enforced when doing full
410 * or incremental restores, but can be overrridden by
411 * the user when only extracting a subset of the files.
412 *
413 * first_time is used with archive files and can have 1 of 3 states:
414 * FT_STATE_1 Tape has not been read yet
415 * FT_STATE_2 Tape has been read but not positioned past directory
416 * information
417 * FT_STATE_3 Tape has been read and is reading file information
418 */
419 #define FT_STATE_1 1
420 #define FT_STATE_2 2
421 #define FT_STATE_3 3
422
423 void
getvol(int nextvol)424 getvol(int nextvol)
425 {
426 int newvol;
427 long savecnt, savetapea, wantnext;
428 long i;
429 union u_spcl tmpspcl;
430 #define tmpbuf tmpspcl.s_spcl
431 char buf[TP_BSIZE_MAX];
432 static int first_time = FT_STATE_1;
433
434 if (tbf == NULL) {
435 (void) fprintf(stderr, gettext(
436 "Internal consistency failure in getvol: tbf is NULL\n"));
437 done(1);
438 }
439
440 if (nextvol == 1) {
441 for (i = 0; i < MAXTAPES; i++)
442 tapesread[i] = 0;
443 gettingfile = 0;
444 }
445 if (pipein) {
446 if (nextvol != 1)
447 panic(gettext("changing volumes on pipe input\n"));
448 if (volno == 1)
449 return;
450 goto gethdr;
451 }
452 savecnt = blksread; /* ignore volume verification tape i/o */
453 savetapea = tapea;
454 again:
455 if (pipein)
456 done(1); /* pipes do not get a second chance */
457 if (command == 'R' || command == 'r' || curfile.action != SKIP) {
458 wantnext = 1;
459 newvol = nextvol;
460 } else {
461 wantnext = 0;
462 newvol = 0;
463 }
464
465 if (autoload) {
466 if ((volno == 1) && (nextvol == 1)) {
467 tapesread[volno-1]++;
468 return;
469 }
470 if (autoload_tape()) {
471 wantnext = 1;
472 newvol = nextvol;
473 goto gethdr;
474 }
475 }
476
477 while (newvol <= 0) {
478 int n = 0;
479
480 for (i = 0; i < MAXTAPES; i++)
481 if (tapesread[i])
482 n++;
483 if (n == 0) {
484 (void) fprintf(stderr, "%s", gettext(
485 "You have not read any volumes yet.\n\
486 Unless you know which volume your file(s) are on you should start\n\
487 with the last volume and work towards the first.\n"));
488 } else {
489 (void) fprintf(stderr,
490 gettext("You have read volumes"));
491 (void) strcpy(tbf, ": ");
492 for (i = 0; i < MAXTAPES; i++)
493 if (tapesread[i]) {
494 (void) fprintf(stderr, "%s%ld",
495 tbf, i+1);
496 (void) strcpy(tbf, ", ");
497 }
498 (void) fprintf(stderr, "\n");
499 }
500 do {
501 (void) fprintf(stderr,
502 gettext("Specify next volume #: "));
503 (void) fflush(stderr);
504 /* LINTED tbfsize is limited to a few MB */
505 (void) fgets(tbf, (int)tbfsize, terminal);
506 } while (!feof(terminal) && tbf[0] == '\n');
507 if (feof(terminal))
508 done(1);
509 newvol = atoi(tbf);
510 if (newvol <= 0) {
511 (void) fprintf(stderr, gettext(
512 "Volume numbers are positive numerics\n"));
513 }
514 if (newvol > MAXTAPES) {
515 (void) fprintf(stderr, gettext(
516 "This program can only deal with %d volumes\n"),
517 MAXTAPES);
518 newvol = 0;
519 }
520 }
521 if (newvol == volno) {
522 tapesread[volno-1]++;
523 return;
524 }
525 closemt(ALLOW_OFFLINE);
526 /*
527 * XXX: if we are switching devices, we should probably try
528 * the device once without prompting to enable unattended
529 * operation.
530 */
531 if (host)
532 (void) fprintf(stderr, gettext(
533 "Mount volume %d\nthen enter volume name on host %s (default: %s) "),
534 newvol, host, magtape);
535 else
536 (void) fprintf(stderr, gettext(
537 "Mount volume %d\nthen enter volume name (default: %s) "),
538 newvol, magtape);
539 (void) fflush(stderr);
540 /* LINTED tbfsize is limited to a few MB */
541 (void) fgets(tbf, (int)tbfsize, terminal);
542 if (feof(terminal))
543 done(1);
544 /*
545 * XXX We don't allow rotating among tape hosts, just drives.
546 */
547 if (tbf[0] != '\n') {
548 (void) strncpy(magtape, tbf, sizeof (magtape));
549 magtape[sizeof (magtape) - 1] = '\0';
550 /* LINTED unsigned -> signed conversion ok */
551 i = (int)strlen(magtape);
552 if (magtape[i - 1] == '\n')
553 magtape[i - 1] = '\0';
554 }
555 if ((host != NULL && (mt = rmtopen(magtape, O_RDONLY)) == -1) ||
556 (host == NULL &&
557 (mt = open(magtape, O_RDONLY|O_LARGEFILE)) == -1)) {
558 int error = errno;
559 (void) fprintf(stderr, gettext("Cannot open %s: %s\n"),
560 magtape, strerror(error));
561 volno = -1;
562 goto again;
563 }
564 gethdr:
565 volno = newvol;
566 setdumpnum();
567 flsht();
568 if (!pipein && !bflag && archivefile && (first_time == FT_STATE_1)) {
569 first_time = FT_STATE_2;
570 findtapeblksize(TAPE_FILE);
571 }
572 if (readhdr(&tmpbuf) == FAIL) {
573 (void) fprintf(stderr,
574 gettext("volume is not in dump format\n"));
575 volno = 0;
576 goto again;
577 }
578 if (checkvol(&tmpbuf, volno) == FAIL) {
579 (void) fprintf(stderr, gettext("Wrong volume (%d)\n"),
580 tmpbuf.c_volume);
581 volno = 0;
582 goto again;
583 }
584
585 if (((time_t)(tmpbuf.c_date) != dumpdate) ||
586 ((time_t)(tmpbuf.c_ddate) != dumptime)) {
587 char *tmp_ct;
588 time_t lc_date = (time_t)tmpbuf.c_date;
589
590 /*
591 * This is used to save the return value from lctime(),
592 * since that's volatile across lctime() invocations.
593 */
594 tmp_ct = strdup(lctime(&lc_date));
595 if (tmp_ct == (char *)0) {
596 (void) fprintf(stderr, gettext(
597 "Cannot allocate space for time string\n"));
598 done(1);
599 }
600
601 (void) fprintf(stderr,
602 gettext("Wrong dump date\n\tgot: %s\twanted: %s"),
603 tmp_ct, lctime(&dumpdate));
604 volno = 0;
605 free(tmp_ct);
606 goto again;
607 }
608 tapesread[volno-1]++;
609 blksread = savecnt;
610 tapea = savetapea;
611 /*
612 * If continuing from the previous volume, skip over any
613 * blocks read already at the end of the previous volume.
614 *
615 * If coming to this volume at random, skip to the beginning
616 * of the next record.
617 */
618 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
619 if (!wantnext) {
620 if (archivefile && first_time == FT_STATE_2) {
621 first_time = FT_STATE_3;
622 }
623 recsread = tmpbuf.c_firstrec;
624 tapea = tmpbuf.c_tapea;
625 dprintf(stdout,
626 "restore skipping %d records\n",
627 tmpbuf.c_count);
628 for (i = tmpbuf.c_count; i > 0; i--)
629 readtape(buf);
630 } else if (tmpbuf.c_firstrec != 0) {
631 savecnt = blksread;
632 savetapea = tapea;
633
634 if (archivefile && first_time == FT_STATE_2) {
635 /*
636 * subtract 2, 1 for archive file's TS_END
637 * and 1 for tape's TS_TAPE
638 */
639 first_time = FT_STATE_3;
640 i = tapea - tmpbuf.c_tapea - 2;
641 } else {
642 i = tapea - tmpbuf.c_tapea;
643 }
644 if (i > 0)
645 dprintf(stdout, gettext(
646 "restore skipping %d duplicate records\n"),
647 i);
648 else if (i < 0)
649 dprintf(stdout, gettext(
650 "restore duplicate record botch (%d)\n"),
651 i);
652 while (--i >= 0)
653 readtape(buf);
654 blksread = savecnt;
655 tapea = savetapea + 1; /* <= (void) gethead() below */
656 }
657 }
658 if (curfile.action == USING) {
659 if (volno == 1)
660 panic(gettext("active file into volume 1\n"));
661 return;
662 }
663 (void) gethead(&spcl);
664 findinode(&spcl); /* do we always restart files in full? */
665 if (gettingfile) { /* i.e. will we lose metadata? */
666 gettingfile = 0;
667 longjmp(restart, 1); /* will this set f1 & f2? */
668 }
669 }
670
671 /*
672 * handle multiple dumps per tape by skipping forward to the
673 * appropriate one. Note we don't use absolute positioning,
674 * as that may take a very long time.
675 */
676 static void
setdumpnum(void)677 setdumpnum(void)
678 {
679 struct mtop tcom;
680 int retval;
681
682 if (dumpnum == 1 || volno != 1)
683 return;
684 if (pipein) {
685 (void) fprintf(stderr,
686 gettext("Cannot have multiple dumps on pipe input\n"));
687 done(1);
688 }
689 tcom.mt_op = MTFSF;
690 tcom.mt_count = dumpnum - 1;
691 if (host)
692 retval = rmtioctl(MTFSF, dumpnum - 1);
693 else
694 retval = ioctl(mt, (int)MTIOCTOP, (char *)&tcom);
695 if (retval < 0)
696 perror("ioctl MTFSF");
697 }
698
699 void
printdumpinfo(void)700 printdumpinfo(void)
701 {
702 int i;
703 time_t date;
704 static char *epoch = NULL;
705
706 if (epoch == NULL) {
707 epoch = strdup(gettext("the epoch\n"));
708 if (epoch == NULL) {
709 (void) fprintf(stderr, gettext("Out of memory\n"));
710 return;
711 }
712 }
713
714 date = (time_t)dumpinfo.c_date;
715 (void) fprintf(stdout,
716 gettext("Dump date: %s"), lctime(&date));
717
718 date = (time_t)dumpinfo.c_ddate;
719 (void) fprintf(stdout, gettext("Dumped from: %s"),
720 (dumpinfo.c_ddate == 0) ? epoch : lctime(&date));
721 if (hostinfo) {
722 (void) fprintf(stdout,
723 gettext("Level %d dump of %s on %.*s:%s\n"),
724 dumpinfo.c_level, dumpinfo.c_filesys,
725 sizeof (dumpinfo.c_host), dumpinfo.c_host, dumpinfo.c_dev);
726 (void) fprintf(stdout,
727 gettext("Label: %.*s\n"),
728 sizeof (dumpinfo.c_label), dumpinfo.c_label);
729 }
730 if (inodeinfo) {
731 (void) fprintf(stdout,
732 gettext("Starting inode numbers by volume:\n"));
733 for (i = 1; i <= dumpinfo.c_volume; i++)
734 (void) fprintf(stdout, gettext("\tVolume %d: %6d\n"),
735 i, dumpinfo.c_inos[i]);
736 }
737 }
738
739 int
extractfile(char * name)740 extractfile(char *name)
741 {
742 static int complained_chown = 0;
743 static int complained_lchown = 0;
744 static int complained_chmod = 0;
745 static int complained_utime = 0;
746 static int complained_mknod = 0;
747 mode_t mode;
748 time_t timep[2];
749 struct entry *ep;
750 uid_t uid;
751 gid_t gid;
752 char *errmsg;
753 int result, saverr;
754 dev_t full_dev;
755 int dfd;
756 char *rname;
757
758 curfile.name = name;
759 curfile.action = USING;
760 timep[0] = (time_t)curfile.dip->di_atime;
761 timep[1] = (time_t)curfile.dip->di_mtime;
762 mode = curfile.dip->di_mode;
763
764 uid = curfile.dip->di_suid == UID_LONG ?
765 curfile.dip->di_uid : (uid_t)curfile.dip->di_suid;
766 gid = curfile.dip->di_sgid == GID_LONG ?
767 curfile.dip->di_gid : (gid_t)curfile.dip->di_sgid;
768
769 resolve(name, &dfd, &rname);
770 if (dfd != AT_FDCWD) {
771 if (fchdir(dfd) < 0) {
772 saverr = errno;
773 (void) fprintf(stderr, gettext(
774 "%s: unable to set attribute context: %s\n"),
775 rname, strerror(saverr));
776 skipfile();
777 (void) close(dfd);
778 return (FAIL);
779 }
780 }
781
782 switch (mode & IFMT) {
783
784 default:
785 (void) fprintf(stderr, gettext("%s: unknown file mode 0%lo\n"),
786 rname, (ulong_t)(mode&IFMT));
787 skipfile();
788 result = FAIL;
789 break;
790
791 case IFSOCK:
792 vprintf(stdout, gettext("skipped socket %s\n"), rname);
793 skipfile();
794 result = GOOD;
795 break;
796
797 case IFDIR:
798 if (mflag) {
799 ep = lookupname(name);
800 if (ep == NIL || ep->e_flags & EXTRACT) {
801 panic(gettext(
802 "directory %s was not restored\n"),
803 rname);
804 skipfile();
805 result = FAIL;
806 break;
807 }
808 skipfile();
809 result = GOOD;
810 break;
811 }
812 vprintf(stdout, gettext("extract file %s\n"), rname);
813 result = genliteraldir(rname, curfile.ino);
814 break;
815
816 case IFLNK:
817 lnkbuf[0] = '\0';
818 pathlen = 0;
819 getfile(xtrlnkfile, xtrlnkskip);
820 if (pathlen == 0) {
821 vprintf(stdout, gettext(
822 "%s: zero length symbolic link (ignored)\n"),
823 rname);
824 result = GOOD;
825 break;
826 }
827 if ((result = lf_linkit(lnkbuf, rname, SYMLINK)) != GOOD)
828 break;
829
830 /* 1254700: set uid/gid (previously missing) */
831 if (lchown(rname, uid, gid) < 0 && !complained_lchown) {
832 /* Just a warning */
833 saverr = errno;
834 errmsg = gettext(
835 "Unable to restore ownership of symlink %s: %s\n");
836 (void) fprintf(stderr, errmsg,
837 rname, strerror(saverr));
838 (void) fprintf(stderr, gettext(
839 "Additional such failures will be ignored.\n"));
840 complained_lchown = 1;
841 }
842 metaset(rname);
843 result = GOOD;
844 break;
845
846 case IFCHR:
847 case IFBLK:
848 case IFIFO:
849 vprintf(stdout, gettext("extract special file %s\n"), rname);
850 /* put device rdev into dev_t expanded format */
851 /* XXX does this always do the right thing? */
852 /* XXX does dump do the right thing? */
853 if (((curfile.dip->di_ordev & 0xFFFF0000) == 0) ||
854 ((curfile.dip->di_ordev & 0xFFFF0000) == 0xFFFF0000)) {
855 full_dev = expdev((unsigned)(curfile.dip->di_ordev));
856 } else {
857 /* LINTED sign extension ok */
858 full_dev = (unsigned)(curfile.dip->di_ordev);
859 }
860
861 if (mknod(rname, mode, full_dev) < 0) {
862 struct stat64 s[1];
863
864 saverr = errno;
865 if ((stat64(rname, s)) ||
866 ((s->st_mode & S_IFMT) != (mode & S_IFMT)) ||
867 (s->st_rdev != full_dev)) {
868 if (saverr != EPERM || !complained_mknod) {
869 (void) fprintf(stderr, "%s: ", rname);
870 (void) fflush(stderr);
871 errno = saverr;
872 perror(gettext(
873 "cannot create special file"));
874 if (saverr == EPERM) {
875 (void) fprintf(stderr, gettext(
876 "Additional such failures will be ignored.\n"));
877 complained_mknod = 1;
878 }
879 }
880 skipfile();
881 result = FAIL;
882 break;
883 }
884 }
885 if (chown(rname, uid, gid) < 0 && !complained_chown) {
886 /* Just a warning */
887 saverr = errno;
888 errmsg = gettext(
889 "Unable to restore ownership of %s: %s\n");
890 (void) fprintf(stderr, errmsg,
891 rname, strerror(saverr));
892 (void) fprintf(stderr, gettext(
893 "Additional such failures will be ignored.\n"));
894 complained_chown = 1;
895 }
896 if (chmod(rname, mode) < 0 && !complained_chmod) {
897 saverr = errno;
898 errmsg = gettext(
899 "Unable to restore permissions on %s: %s\n");
900 (void) fprintf(stderr, errmsg,
901 rname, strerror(saverr));
902 (void) fprintf(stderr, gettext(
903 "Additional such failures will be ignored.\n"));
904 complained_chmod = 1;
905 }
906 skipfile();
907 metaset(rname); /* skipfile() got the metadata, if any */
908 if (utime(rname, (struct utimbuf *)timep) < 0 &&
909 !complained_utime) {
910 saverr = errno;
911 errmsg = gettext(
912 "Unable to restore times on %s: %s\n");
913 (void) fprintf(stderr, errmsg,
914 rname, strerror(saverr));
915 (void) fprintf(stderr, gettext(
916 "Additional such failures will be ignored.\n"));
917 complained_utime = 1;
918 }
919 result = GOOD;
920 break;
921
922 case IFREG:
923 vprintf(stdout, gettext("extract file %s\n"), rname);
924
925 /*
926 * perform a restrictive creat(2) initally, we'll
927 * fchmod(2) according to the archive later after
928 * we've written the blocks.
929 */
930 ofile = creat64(rname, 0600);
931
932 if (ofile < 0) {
933 saverr = errno;
934 errmsg = gettext("cannot create file");
935 (void) fprintf(stderr, "%s: ", rname);
936 (void) fflush(stderr);
937 errno = saverr;
938 perror(errmsg);
939 skipfile();
940 result = FAIL;
941 break;
942 }
943 if (fchown(ofile, uid, gid) < 0 && !complained_chown) {
944 /* Just a warning */
945 saverr = errno;
946 errmsg = gettext(
947 "Unable to restore ownership of %s: %s\n");
948 (void) fprintf(stderr, errmsg,
949 rname, strerror(saverr));
950 (void) fprintf(stderr, gettext(
951 "Additional such failures will be ignored.\n"));
952 complained_chown = 1;
953 }
954
955 getfile(xtrfile, xtrskip);
956 metaset(rname);
957
958 /*
959 * the fchmod(2) has to come after getfile() as some POSIX
960 * implementations clear the S_ISUID and S_ISGID bits of the
961 * file after every write(2).
962 */
963 if (fchmod(ofile, mode) < 0 && !complained_chmod) {
964 saverr = errno;
965 errmsg = gettext(
966 "Unable to restore permissions on %s: %s\n");
967 (void) fprintf(stderr, errmsg,
968 rname, strerror(saverr));
969 (void) fprintf(stderr, gettext(
970 "Additional such failures will be ignored.\n"));
971 complained_chmod = 1;
972 }
973
974 /*
975 * Some errors don't get reported until we close(2), so
976 * check for them.
977 * XXX unlink the file if an error is reported?
978 */
979 if (close(ofile) < 0) {
980 saverr = errno;
981 errmsg = gettext("error closing file");
982 (void) fprintf(stderr, "%s: ", rname);
983 (void) fflush(stderr);
984 errno = saverr;
985 perror(errmsg);
986 result = FAIL;
987 break;
988 }
989 if (utime(rname, (struct utimbuf *)timep) < 0 &&
990 !complained_utime) {
991 saverr = errno;
992 errmsg = gettext(
993 "Unable to restore times on %s: %s\n");
994 (void) fprintf(stderr, errmsg,
995 rname, strerror(saverr));
996 (void) fprintf(stderr, gettext(
997 "Additional such failures will be ignored.\n"));
998 complained_utime = 1;
999 }
1000
1001 result = GOOD;
1002 break;
1003 }
1004 if (dfd != AT_FDCWD) {
1005 fchdir(savepwd);
1006 (void) close(dfd);
1007 }
1008 return (result);
1009 }
1010
1011 /*
1012 * skip over bit maps on the tape
1013 */
1014 void
skipmaps(void)1015 skipmaps(void)
1016 {
1017 continuemap = 1;
1018 while (checktype(&spcl, TS_CLRI) == GOOD ||
1019 checktype(&spcl, TS_BITS) == GOOD)
1020 skipfile();
1021 continuemap = 0;
1022 }
1023
1024 /*
1025 * skip over a file on the tape
1026 */
1027 void
skipfile(void)1028 skipfile(void)
1029 {
1030 curfile.action = SKIP;
1031 getfile(null, null);
1032 }
1033 /*
1034 * Do the file extraction, calling the supplied functions
1035 * with the blocks
1036 */
1037 void
getfile(void (* f1)(),void (* f2)())1038 getfile(void (*f1)(), void (*f2)())
1039 {
1040 int i;
1041 size_t curblk = 0;
1042 offset_t size = (offset_t)spcl.c_dinode.di_size;
1043 static char clearedbuf[MAXBSIZE];
1044 char buf[TP_BSIZE_MAX];
1045 char *bufptr;
1046 char junk[TP_BSIZE_MAX];
1047
1048 assert(MAXBSIZE >= tp_bsize);
1049
1050 metaset(NULL); /* flush old metadata */
1051 if (checktype(&spcl, TS_END) == GOOD) {
1052 panic(gettext("ran off end of volume\n"));
1053 return;
1054 }
1055 if (ishead(&spcl) == FAIL) {
1056 panic(gettext("not at beginning of a file\n"));
1057 return;
1058 }
1059 metacheck(&spcl); /* check for metadata in header */
1060 if (!gettingfile && setjmp(restart) != 0) {
1061 gettingfile = 0; /* paranoia; longjmp'er should do */
1062 return;
1063 }
1064 gettingfile++;
1065 loop:
1066 if ((spcl.c_dinode.di_mode & IFMT) == IFSHAD) {
1067 f1 = xtrmeta;
1068 f2 = metaskip;
1069 }
1070 for (i = 0, bufptr = buf; i < spcl.c_count; i++) {
1071 if ((i >= TP_NINDIR) || (spcl.c_addr[i])) {
1072 readtape(bufptr);
1073 bufptr += tp_bsize;
1074 curblk++;
1075 if (curblk == (fssize / tp_bsize)) {
1076 (*f1)(buf, size > tp_bsize ?
1077 (size_t)(fssize) :
1078 /* LINTED size <= tp_bsize */
1079 (curblk - 1) * tp_bsize + (size_t)size);
1080 curblk = 0;
1081 bufptr = buf;
1082 }
1083 } else {
1084 if (curblk > 0) {
1085 (*f1)(buf, size > tp_bsize ?
1086 (size_t)(curblk * tp_bsize) :
1087 /* LINTED size <= tp_bsize */
1088 (curblk - 1) * tp_bsize + (size_t)size);
1089 curblk = 0;
1090 bufptr = buf;
1091 }
1092 (*f2)(clearedbuf, size > tp_bsize ?
1093 /* LINTED size <= tp_bsize */
1094 (long)tp_bsize : (size_t)size);
1095 }
1096 if ((size -= tp_bsize) <= 0) {
1097 for (i++; i < spcl.c_count; i++)
1098 if ((i >= TP_NINDIR) || (spcl.c_addr[i]))
1099 readtape(junk);
1100 break;
1101 }
1102 }
1103 if (curblk > 0) {
1104 /*
1105 * Ok to cast size to size_t here. The above for loop reads
1106 * data into the buffer then writes it to the output file. The
1107 * call to f1 here is to write out the data that's in the
1108 * buffer that has not yet been written to the file.
1109 * This will be less than N-KB of data, since the
1110 * above loop writes to the file in filesystem-
1111 * blocksize chunks.
1112 */
1113 /* LINTED: size fits into a size_t at this point */
1114 (*f1)(buf, (curblk * tp_bsize) + (size_t)size);
1115
1116 curblk = 0;
1117 bufptr = buf;
1118 }
1119 if ((readhdr(&spcl) == GOOD) && (checktype(&spcl, TS_ADDR) == GOOD)) {
1120 if (continuemap)
1121 size = (offset_t)spcl.c_count * tp_bsize;
1122 /* big bitmap */
1123 else if ((size <= 0) &&
1124 ((spcl.c_dinode.di_mode & IFMT) == IFSHAD)) {
1125 /* LINTED unsigned to signed conversion ok */
1126 size = spcl.c_dinode.di_size;
1127 }
1128 if (size > 0)
1129 goto loop;
1130 }
1131 if (size > 0)
1132 dprintf(stdout,
1133 gettext("Missing address (header) block for %s\n"),
1134 curfile.name);
1135 findinode(&spcl);
1136 gettingfile = 0;
1137 }
1138
1139 /*
1140 * The next routines are called during file extraction to
1141 * put the data into the right form and place.
1142 */
1143 static void
xtrfile(char * buf,size_t size)1144 xtrfile(char *buf, size_t size)
1145 {
1146 if (write(ofile, buf, (size_t)size) == -1) {
1147 int saverr = errno;
1148 (void) fprintf(stderr,
1149 gettext("write error extracting inode %d, name %s\n"),
1150 curfile.ino, curfile.name);
1151 errno = saverr;
1152 perror("write");
1153 done(1);
1154 }
1155 }
1156
1157 /*
1158 * Even though size is a size_t, it's seeking to a relative
1159 * offset. Thus, the seek could go beyond 2 GB, so lseek64 is needed.
1160 */
1161
1162 /*ARGSUSED*/
1163 static void
xtrskip(char * buf,size_t size)1164 xtrskip(char *buf, size_t size)
1165 {
1166 if (lseek64(ofile, (offset_t)size, 1) == -1) {
1167 int saverr = errno;
1168 (void) fprintf(stderr,
1169 gettext("seek error extracting inode %d, name %s\n"),
1170 curfile.ino, curfile.name);
1171 errno = saverr;
1172 perror("lseek64");
1173 done(1);
1174 }
1175 }
1176
1177 /* these are local to the next five functions */
1178 static char *metadata = NULL;
1179 static size_t metasize = 0;
1180
1181 static void
metacheck(struct s_spcl * head)1182 metacheck(struct s_spcl *head)
1183 {
1184 if (! (head->c_flags & DR_HASMETA))
1185 return;
1186 if ((metadata = malloc(metasize = (size_t)sizeof (head->c_shadow)))
1187 == NULL) {
1188 (void) fprintf(stderr,
1189 gettext("Cannot malloc for metadata\n"));
1190 done(1);
1191 }
1192 bcopy(&(head->c_shadow), metadata, metasize);
1193 }
1194
1195 static void
xtrmeta(char * buf,size_t size)1196 xtrmeta(char *buf, size_t size)
1197 {
1198 if ((metadata == NULL) && ((spcl.c_dinode.di_mode & IFMT) != IFSHAD))
1199 return;
1200 if ((metadata = realloc(metadata, metasize + size)) == NULL) {
1201 (void) fprintf(stderr,
1202 gettext("Cannot malloc for metadata\n"));
1203 done(1);
1204 }
1205 bcopy(buf, metadata + metasize, size);
1206 metasize += size;
1207 }
1208
1209 /* ARGSUSED */
1210 static void
metaskip(char * buf,size_t size)1211 metaskip(char *buf, size_t size)
1212 {
1213 if (metadata == NULL)
1214 return;
1215 if ((metadata = realloc(metadata, metasize + size)) == NULL) {
1216 (void) fprintf(stderr,
1217 gettext("Cannot malloc for metadata\n"));
1218 done(1);
1219 }
1220 bzero(metadata + metasize, size);
1221 metasize += size;
1222 }
1223
1224 static void
metaset(char * name)1225 metaset(char *name)
1226 {
1227 if (metadata == NULL)
1228 return;
1229 if (name != NULL)
1230 metaproc(name, metadata, metasize);
1231 (void) free(metadata);
1232 metadata = NULL;
1233 metasize = 0;
1234 }
1235
1236 void
metaget(char ** data,size_t * size)1237 metaget(char **data, size_t *size)
1238 {
1239 *data = metadata;
1240 *size = metasize;
1241 }
1242
1243 static void
fsd_acl(char * name,char * aclp,unsigned size)1244 fsd_acl(char *name, char *aclp, unsigned size)
1245 {
1246 static aclent_t *aclent = NULL;
1247 ufs_acl_t *diskacl;
1248 static int n = 0;
1249 acl_t *set_aclp;
1250 uint_t i;
1251 int saverr, j;
1252
1253 if (aclp == NULL) {
1254 if (aclent != NULL)
1255 free(aclent);
1256 aclent = NULL;
1257 n = 0;
1258 return;
1259 }
1260
1261 /*LINTED [aclp is malloc'd]*/
1262 diskacl = (ufs_acl_t *)aclp;
1263 /* LINTED: result fits in an int */
1264 j = size / sizeof (*diskacl);
1265 normacls(byteorder, diskacl, j);
1266
1267 i = n;
1268 n += j;
1269 aclent = realloc(aclent, n * (size_t)sizeof (*aclent));
1270 if (aclent == NULL) {
1271 (void) fprintf(stderr, gettext("Cannot malloc acl list\n"));
1272 done(1);
1273 }
1274
1275 j = 0;
1276 while (i < n) {
1277 aclent[i].a_type = diskacl[j].acl_tag;
1278 aclent[i].a_id = diskacl[j].acl_who;
1279 aclent[i].a_perm = diskacl[j].acl_perm;
1280 ++i;
1281 ++j;
1282 }
1283
1284 set_aclp = acl_to_aclp(ACLENT_T, aclent, n);
1285 if (set_aclp == NULL) {
1286 (void) fprintf(stderr, gettext("Cannot build acl_t\n"));
1287 done(1);
1288 }
1289
1290 if (acl_set(name, set_aclp) == -1) {
1291 static int once = 0;
1292
1293 /*
1294 * Treat some errors from the acl subsystem specially to
1295 * avoid being too noisy:
1296 *
1297 * ENOSYS - ACLs not supported on this file system
1298 * EPERM - not the owner or not privileged
1299 *
1300 * The following is also supported for backwards compat.
1301 * since acl(2) used to return the wrong errno:
1302 *
1303 * EINVAL - not the owner of the object
1304 */
1305 if (errno == ENOSYS || errno == EPERM || errno == EINVAL) {
1306 if (once == 0) {
1307 saverr = errno;
1308 ++once;
1309 fprintf(stderr,
1310 gettext("setacl failed: %s\n"),
1311 strerror(saverr));
1312 }
1313 } else {
1314 saverr = errno;
1315 fprintf(stderr, gettext("setacl on %s failed: %s\n"),
1316 name, strerror(saverr));
1317 }
1318 }
1319 acl_free(set_aclp);
1320 }
1321
1322 static struct fsdtypes {
1323 int type;
1324 void (*function)();
1325 } fsdtypes[] = {
1326 {FSD_ACL, fsd_acl},
1327 {FSD_DFACL, fsd_acl},
1328 {0, NULL}
1329 };
1330
1331 void
metaproc(char * name,char * mdata,size_t msize)1332 metaproc(char *name, char *mdata, size_t msize)
1333 {
1334 struct fsdtypes *fsdtype;
1335 ufs_fsd_t *fsd;
1336 char *c;
1337
1338 /*
1339 * for the whole shadow inode, dispatch each piece
1340 * to the appropriate function.
1341 */
1342 c = mdata;
1343 /* LINTED (c - mdata) fits into a size_t */
1344 while ((size_t)(c - mdata) < msize) {
1345 /*LINTED [mdata is malloc'd]*/
1346 fsd = (ufs_fsd_t *)c;
1347 assert((fsd->fsd_size % 4) == 0);
1348 /* LINTED: lint thinks pointers are signed */
1349 c += FSD_RECSZ(fsd, fsd->fsd_size);
1350 if ((fsd->fsd_type == FSD_FREE) ||
1351 ((unsigned)(fsd->fsd_size) <= sizeof (ufs_fsd_t)) ||
1352 (c > (mdata + msize)))
1353 break;
1354 for (fsdtype = fsdtypes; fsdtype->type; fsdtype++)
1355 if (fsdtype->type == fsd->fsd_type)
1356 (*fsdtype->function)(name, fsd->fsd_data,
1357 (unsigned)(fsd->fsd_size) -
1358 sizeof (fsd->fsd_type) -
1359 sizeof (fsd->fsd_size));
1360 /* ^^^ be sure to change if fsd ever changes ^^^ */
1361 }
1362
1363 /* reset the state of all the functions */
1364 for (fsdtype = fsdtypes; fsdtype->type; fsdtype++)
1365 (*fsdtype->function)(NULL, NULL, 0);
1366 }
1367
1368 static void
xtrlnkfile(char * buf,size_t size)1369 xtrlnkfile(char *buf, size_t size)
1370 {
1371 /* LINTED: signed/unsigned mix ok */
1372 pathlen += size;
1373 if (pathlen > MAXPATHLEN) {
1374 (void) fprintf(stderr,
1375 gettext("symbolic link name: %s->%s%s; too long %d\n"),
1376 curfile.name, lnkbuf, buf, pathlen);
1377 done(1);
1378 }
1379 buf[size] = '\0';
1380 (void) strcat(lnkbuf, buf);
1381 /* add an extra NULL to make this a legal complex string */
1382 lnkbuf[pathlen+1] = '\0';
1383 }
1384
1385 /*ARGSUSED*/
1386 static void
xtrlnkskip(char * buf,size_t size)1387 xtrlnkskip(char *buf, size_t size)
1388 {
1389 (void) fprintf(stderr,
1390 gettext("unallocated block in symbolic link %s\n"),
1391 curfile.name);
1392 done(1);
1393 }
1394
1395 static void
xtrmap(char * buf,size_t size)1396 xtrmap(char *buf, size_t size)
1397 {
1398 if ((map+size) > endmap) {
1399 int64_t mapsize, increment;
1400 int64_t diff;
1401
1402 if (spcl.c_type != TS_ADDR) {
1403 (void) fprintf(stderr,
1404 gettext("xtrmap: current record not TS_ADDR\n"));
1405 done(1);
1406 }
1407 if ((spcl.c_count < 0) || (spcl.c_count > TP_NINDIR)) {
1408 (void) fprintf(stderr,
1409 gettext("xtrmap: illegal c_count field (%d)\n"),
1410 spcl.c_count);
1411 done(1);
1412 }
1413
1414 increment = d_howmany(
1415 ((spcl.c_count * tp_bsize * NBBY) + 1), NBBY);
1416 mapsize = endmap - beginmap + increment;
1417 if (mapsize > UINT_MAX) {
1418 (void) fprintf(stderr,
1419 gettext("xtrmap: maximum bitmap size exceeded"));
1420 done(1);
1421 }
1422
1423 diff = map - beginmap;
1424 /* LINTED mapsize checked above */
1425 beginmap = realloc(beginmap, (size_t)mapsize);
1426 if (beginmap == NULL) {
1427 (void) fprintf(stderr,
1428 gettext("xtrmap: realloc failed\n"));
1429 done(1);
1430 }
1431 map = beginmap + diff;
1432 endmap = beginmap + mapsize;
1433 /* LINTED endmap - map cannot exceed 32 bits */
1434 bzero(map, (size_t)(endmap - map));
1435 maxino = NBBY * mapsize + 1;
1436 }
1437
1438 bcopy(buf, map, size);
1439 /* LINTED character pointers aren't signed */
1440 map += size;
1441 }
1442
1443 /*ARGSUSED*/
1444 static void
xtrmapskip(char * buf,size_t size)1445 xtrmapskip(char *buf, size_t size)
1446 {
1447 (void) fprintf(stderr, gettext("hole in map\n"));
1448 done(1);
1449 }
1450
1451 /*ARGSUSED*/
1452 void
null(char * buf,size_t size)1453 null(char *buf, size_t size)
1454 {
1455 }
1456
1457 /*
1458 * Do the tape i/o, dealing with volume changes
1459 * etc..
1460 */
1461 static void
readtape(char * b)1462 readtape(char *b)
1463 {
1464 int i;
1465 int rd, newvol;
1466 int cnt;
1467 struct s_spcl *sp;
1468 int32_t expected_magic;
1469
1470 if (tbf == NULL) {
1471 (void) fprintf(stderr, gettext(
1472 "Internal consistency failure in readtape: tbf is NULL\n"));
1473 done(1);
1474 }
1475 expected_magic = ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC);
1476
1477 top:
1478 if (bct < numtrec) {
1479 /*
1480 * check for old-dump floppy EOM -- it may appear in
1481 * the middle of a buffer. The Dflag used to be used for
1482 * this, but since it doesn't hurt to always do this we
1483 * got rid of the Dflag.
1484 */
1485 /*LINTED [tbf = malloc()]*/
1486 sp = &((union u_spcl *)&tbf[bct*tp_bsize])->s_spcl;
1487 if (sp->c_magic == expected_magic && sp->c_type == TS_EOM &&
1488 (time_t)(sp->c_date) == dumpdate &&
1489 (time_t)(sp->c_ddate) == dumptime) {
1490 for (i = 0; i < ntrec; i++)
1491 /*LINTED [tbf = malloc()]*/
1492 ((struct s_spcl *)
1493 &tbf[i*tp_bsize])->c_magic = 0;
1494 bct = 0;
1495 rd = 0;
1496 i = 0;
1497 goto nextvol;
1498 }
1499 bcopy(&tbf[(bct++*tp_bsize)], b, (size_t)tp_bsize);
1500 blksread++;
1501 tapea++;
1502 return;
1503 }
1504 /*LINTED [assertion always true]*/
1505 assert(sizeof (union u_spcl) == TP_BSIZE_MAX);
1506 for (i = 0; i < ntrec; i++)
1507 /*LINTED [tbf = malloc()]*/
1508 ((struct s_spcl *)&tbf[i*sizeof (struct s_spcl)])->c_magic = 0;
1509 if (numtrec == 0) {
1510 /* LINTED unsigned/signed assignment ok */
1511 numtrec = ntrec;
1512 }
1513 /* LINTED unsigned/signed assignment ok */
1514 cnt = ntrec*tp_bsize;
1515 rd = 0;
1516 getmore:
1517 if (host)
1518 i = rmtread(&tbf[rd], cnt);
1519 else
1520 i = read(mt, &tbf[rd], cnt);
1521 /*
1522 * Check for mid-tape short read error.
1523 * If found, return rest of buffer.
1524 */
1525 if (numtrec < ntrec && i != 0) {
1526 /* LINTED unsigned/signed assignment ok */
1527 numtrec = ntrec;
1528 goto top;
1529 }
1530 /*
1531 * Handle partial block read.
1532 */
1533 if (i > 0 && i != ntrec*tp_bsize) {
1534 if (pipein) {
1535 rd += i;
1536 cnt -= i;
1537 if (cnt > 0)
1538 goto getmore;
1539 i = rd;
1540 } else {
1541 if (i % tp_bsize != 0)
1542 panic(gettext(
1543 "partial block read: %d should be %d\n"),
1544 i, ntrec * tp_bsize);
1545 numtrec = i / tp_bsize;
1546 if (numtrec == 0)
1547 /*
1548 * it's possible to read only 512 bytes
1549 * from a QIC device...
1550 */
1551 i = 0;
1552 }
1553 }
1554 /*
1555 * Handle read error.
1556 */
1557 if (i < 0) {
1558 switch (curfile.action) {
1559 default:
1560 (void) fprintf(stderr, gettext(
1561 "Read error while trying to set up volume\n"));
1562 break;
1563 case UNKNOWN:
1564 (void) fprintf(stderr, gettext(
1565 "Read error while trying to resynchronize\n"));
1566 break;
1567 case USING:
1568 (void) fprintf(stderr, gettext(
1569 "Read error while restoring %s\n"),
1570 curfile.name);
1571 break;
1572 case SKIP:
1573 (void) fprintf(stderr, gettext(
1574 "Read error while skipping over inode %d\n"),
1575 curfile.ino);
1576 break;
1577 }
1578 if (!yflag && !reply(gettext("continue")))
1579 done(1);
1580 /* LINTED: unsigned->signed conversion ok */
1581 i = (int)(ntrec*tp_bsize);
1582 bzero(tbf, (size_t)i);
1583 if ((host != 0 && rmtseek(i, 1) < 0) ||
1584 (host == 0 && (lseek64(mt, (offset_t)i, 1) ==
1585 (off64_t)-1))) {
1586 perror(gettext("continuation failed"));
1587 done(1);
1588 }
1589 }
1590 /*
1591 * Handle end of tape. The Dflag used to be used, but since it doesn't
1592 * hurt to always check we got rid if it.
1593 */
1594
1595 /*
1596 * if the first record in the buffer just read is EOM,
1597 * change volumes.
1598 */
1599 /*LINTED [tbf = malloc()]*/
1600 sp = &((union u_spcl *)tbf)->s_spcl;
1601 if (i != 0 && sp->c_magic == expected_magic && sp->c_type == TS_EOM &&
1602 (time_t)(sp->c_date) == dumpdate &&
1603 (time_t)(sp->c_ddate) == dumptime) {
1604 i = 0;
1605 }
1606 nextvol:
1607 if (i == 0) {
1608 if (!pipein) {
1609 newvol = volno + 1;
1610 volno = 0;
1611 numtrec = 0;
1612 getvol(newvol);
1613 readtape(b); /* XXX tail recursion, not goto top? */
1614 return;
1615 }
1616 /* XXX if panic returns, should we round rd up? */
1617 /* XXX if we do, then we should zero the intervening space */
1618 if (rd % tp_bsize != 0)
1619 panic(gettext("partial block read: %d should be %d\n"),
1620 rd, ntrec * tp_bsize);
1621 bcopy((char *)&endoftapemark, &tbf[rd], (size_t)tp_bsize);
1622 }
1623 bct = 0;
1624 bcopy(&tbf[(bct++*tp_bsize)], b, (size_t)tp_bsize);
1625 blksread++;
1626 recsread++;
1627 tapea++;
1628 rec_position++;
1629 }
1630
1631 void
findtapeblksize(int arfile)1632 findtapeblksize(int arfile)
1633 {
1634 int i;
1635
1636 if (tbf == NULL) {
1637 (void) fprintf(stderr, gettext(
1638 "Internal consistency failure in findtapeblksize: "
1639 "tbf is NULL\n"));
1640 assert(tbf != NULL);
1641 done(1);
1642 }
1643
1644 for (i = 0; i < ntrec; i++)
1645 /*LINTED [tbf = malloc()]*/
1646 ((struct s_spcl *)&tbf[i * tp_bsize])->c_magic = 0;
1647 bct = 0;
1648 if (host && arfile == TAPE_FILE)
1649 tape_rec_size = rmtread(tbf, ntrec * tp_bsize);
1650 else
1651 tape_rec_size = read(mt, tbf, ntrec * tp_bsize);
1652 recsread++;
1653 rec_position++;
1654 if (tape_rec_size == (ssize_t)-1) {
1655 int saverr = errno;
1656 char *errmsg = gettext("Media read error");
1657 errno = saverr;
1658 perror(errmsg);
1659 done(1);
1660 }
1661 if (tape_rec_size % tp_bsize != 0) {
1662 (void) fprintf(stderr, gettext(
1663 "Record size (%d) is not a multiple of dump block size (%d)\n"),
1664 tape_rec_size, tp_bsize);
1665 done(1);
1666 }
1667 ntrec = (int)tape_rec_size / tp_bsize;
1668 /* LINTED unsigned/signed assignment ok */
1669 numtrec = ntrec;
1670 vprintf(stdout, gettext("Media block size is %d\n"), ntrec*2);
1671 }
1672
1673 void
flsht(void)1674 flsht(void)
1675 {
1676 /* LINTED unsigned/signed assignment ok */
1677 bct = ntrec+1;
1678 }
1679
1680 void
closemt(int mode)1681 closemt(int mode)
1682 {
1683 /*
1684 * If mode == FORCE_OFFLINE then we're not done but
1685 * we need to change tape. So, rewind and unload current
1686 * tape before loading the new one.
1687 */
1688
1689 static struct mtop mtop = { MTOFFL, 0 };
1690
1691 if (mt < 0)
1692 return;
1693 if (offline || mode == FORCE_OFFLINE)
1694 (void) fprintf(stderr, gettext("Rewinding tape\n"));
1695 if (host) {
1696 if (offline || mode == FORCE_OFFLINE)
1697 (void) rmtioctl(MTOFFL, 1);
1698 rmtclose();
1699 } else if (pipein) {
1700 char buffy[MAXBSIZE];
1701
1702 while (read(mt, buffy, sizeof (buffy)) > 0) {
1703 continue;
1704 /*LINTED [assertion always true]*/
1705 }
1706 (void) close(mt);
1707 } else {
1708 /*
1709 * Only way to tell if this is a floppy is to issue an ioctl
1710 * but why waste one - if the eject fails, tough!
1711 */
1712 if (offline || mode == FORCE_OFFLINE)
1713 (void) ioctl(mt, MTIOCTOP, &mtop);
1714 (void) ioctl(mt, FDEJECT, 0);
1715 (void) close(mt);
1716 }
1717 mt = -1;
1718 }
1719
1720 static int
checkvol(struct s_spcl * b,int t)1721 checkvol(struct s_spcl *b, int t)
1722 {
1723
1724 if (b->c_volume != t)
1725 return (FAIL);
1726 return (GOOD);
1727 }
1728
1729 int
readhdr(struct s_spcl * b)1730 readhdr(struct s_spcl *b)
1731 {
1732
1733 if (gethead(b) == FAIL) {
1734 dprintf(stdout, gettext("readhdr fails at %ld blocks\n"),
1735 blksread);
1736 return (FAIL);
1737 }
1738 return (GOOD);
1739 }
1740
1741 /*
1742 * read the tape into buf, then return whether or
1743 * or not it is a header block.
1744 */
1745 int
gethead(struct s_spcl * buf)1746 gethead(struct s_spcl *buf)
1747 {
1748 int i;
1749 union u_ospcl {
1750 char dummy[TP_BSIZE_MIN];
1751 struct s_ospcl {
1752 int32_t c_type;
1753 int32_t c_date;
1754 int32_t c_ddate;
1755 int32_t c_volume;
1756 int32_t c_tapea;
1757 ushort_t c_inumber;
1758 int32_t c_magic;
1759 int32_t c_checksum;
1760 struct odinode {
1761 unsigned short odi_mode;
1762 ushort_t odi_nlink;
1763 ushort_t odi_uid;
1764 ushort_t odi_gid;
1765 int32_t odi_size;
1766 int32_t odi_rdev;
1767 char odi_addr[36];
1768 int32_t odi_atime;
1769 int32_t odi_mtime;
1770 int32_t odi_ctime;
1771 } c_dinode;
1772 int32_t c_count;
1773 char c_baddr[256];
1774 } s_ospcl;
1775 } u_ospcl;
1776
1777 if (cvtflag) {
1778 readtape((char *)(&u_ospcl.s_ospcl));
1779 bzero((char *)buf, (size_t)TP_BSIZE_MIN);
1780 buf->c_type = u_ospcl.s_ospcl.c_type;
1781 buf->c_date = u_ospcl.s_ospcl.c_date;
1782 buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1783 buf->c_volume = u_ospcl.s_ospcl.c_volume;
1784 buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1785 buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1786 buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1787 buf->c_magic = u_ospcl.s_ospcl.c_magic;
1788 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1789 /* LINTED: unsigned/signed combination ok */
1790 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1791 buf->c_dinode.di_size =
1792 (unsigned)(u_ospcl.s_ospcl.c_dinode.odi_size);
1793 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1794 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1795 buf->c_dinode.di_suid = UID_LONG;
1796 buf->c_dinode.di_sgid = GID_LONG;
1797 buf->c_dinode.di_ordev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1798 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
1799 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1800 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1801 buf->c_count = u_ospcl.s_ospcl.c_count;
1802 bcopy(u_ospcl.s_ospcl.c_baddr, buf->c_addr,
1803 sizeof (u_ospcl.s_ospcl.c_baddr));
1804
1805 /*CONSTANTCONDITION*/
1806 assert(sizeof (u_ospcl.s_ospcl) < sizeof (union u_spcl));
1807
1808 /* we byte-swap the new spclrec, but checksum the old */
1809 /* (see comments in normspcl()) */
1810 if (normspcl(byteorder, buf,
1811 (int *)(&u_ospcl.s_ospcl), sizeof (u_ospcl.s_ospcl),
1812 OFS_MAGIC))
1813 return (FAIL);
1814 buf->c_magic =
1815 ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC);
1816 } else {
1817 readtape((char *)buf);
1818 if (normspcl(byteorder, buf, (int *)buf, tp_bsize,
1819 ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC)))
1820 return (FAIL);
1821 }
1822
1823 switch (buf->c_type) {
1824
1825 case TS_CLRI:
1826 case TS_BITS:
1827 /*
1828 * Have to patch up missing information in bit map headers
1829 */
1830 buf->c_inumber = 0;
1831 buf->c_dinode.di_size = (offset_t)buf->c_count * tp_bsize;
1832 for (i = 0; i < buf->c_count && i < TP_NINDIR; i++)
1833 buf->c_addr[i] = 1;
1834 break;
1835
1836 case TS_TAPE:
1837 case TS_END:
1838 if (dumpinfo.c_date == 0) {
1839 dumpinfo.c_date = spcl.c_date;
1840 dumpinfo.c_ddate = spcl.c_ddate;
1841 }
1842 if (!hostinfo && spcl.c_host[0] != '\0') {
1843 bcopy(spcl.c_label, dumpinfo.c_label,
1844 sizeof (spcl.c_label));
1845 bcopy(spcl.c_filesys, dumpinfo.c_filesys,
1846 sizeof (spcl.c_filesys));
1847 bcopy(spcl.c_dev, dumpinfo.c_dev,
1848 sizeof (spcl.c_dev));
1849 bcopy(spcl.c_host, dumpinfo.c_host,
1850 sizeof (spcl.c_host));
1851 dumpinfo.c_level = spcl.c_level;
1852 hostinfo++;
1853 if (c_label != NULL &&
1854 strncmp(c_label, spcl.c_label,
1855 sizeof (spcl.c_label))
1856 != 0) {
1857 (void) fprintf(stderr, gettext(
1858 "Incorrect tape label. Expected `%s', got `%.*s'\n"),
1859 c_label,
1860 sizeof (spcl.c_label), spcl.c_label);
1861 done(1);
1862 }
1863 }
1864 if (!inodeinfo && (spcl.c_flags & DR_INODEINFO)) {
1865 dumpinfo.c_volume = spcl.c_volume;
1866 bcopy(spcl.c_inos, dumpinfo.c_inos,
1867 sizeof (spcl.c_inos));
1868 inodeinfo++;
1869 }
1870 buf->c_inumber = 0;
1871 break;
1872
1873 case TS_INODE:
1874 case TS_ADDR:
1875 break;
1876
1877 default:
1878 panic(gettext("%s: unknown inode type %d\n"),
1879 "gethead", buf->c_type);
1880 return (FAIL);
1881 }
1882 if (dflag)
1883 accthdr(buf);
1884 return (GOOD);
1885 }
1886
1887 /*
1888 * Check that a header is where it belongs and predict the next header
1889 */
1890 static void
accthdr(struct s_spcl * header)1891 accthdr(struct s_spcl *header)
1892 {
1893 static ino_t previno = (ino_t)(unsigned)-1;
1894 static int prevtype;
1895 static long predict;
1896 int blks, i;
1897
1898 if (header->c_type == TS_TAPE) {
1899 if (header->c_firstrec)
1900 (void) fprintf(stderr,
1901 gettext("Volume header begins with record %d"),
1902 header->c_firstrec);
1903 else
1904 (void) fprintf(stderr, gettext("Volume header"));
1905 (void) fprintf(stderr, "\n");
1906 previno = (ino_t)(unsigned)-1;
1907 return;
1908 }
1909 if (previno == (ino_t)(unsigned)-1)
1910 goto newcalc;
1911 switch (prevtype) {
1912 case TS_BITS:
1913 (void) fprintf(stderr, gettext("Dump mask header"));
1914 break;
1915 case TS_CLRI:
1916 (void) fprintf(stderr, gettext("Remove mask header"));
1917 break;
1918 case TS_INODE:
1919 (void) fprintf(stderr,
1920 gettext("File header, ino %d at record %d"),
1921 previno, rec_position);
1922 break;
1923 case TS_ADDR:
1924 (void) fprintf(stderr,
1925 gettext("File continuation header, ino %d"),
1926 previno);
1927 break;
1928 case TS_END:
1929 (void) fprintf(stderr, gettext("End of media header"));
1930 break;
1931 }
1932 if (predict != blksread - 1)
1933 (void) fprintf(stderr,
1934 gettext("; predicted %ld blocks, got %ld blocks"),
1935 predict, blksread - 1);
1936 (void) fprintf(stderr, "\n");
1937 newcalc:
1938 blks = 0;
1939 if (header->c_type != TS_END)
1940 for (i = 0; i < header->c_count; i++)
1941 if ((i >= TP_NINDIR) || (header->c_addr[i] != 0))
1942 blks++;
1943 predict = blks;
1944 blksread = 0;
1945 prevtype = header->c_type;
1946 previno = header->c_inumber;
1947 }
1948
1949 /*
1950 * Try to determine which volume a file resides on.
1951 */
1952 int
volnumber(ino_t inum)1953 volnumber(ino_t inum)
1954 {
1955 int i;
1956
1957 if (inodeinfo == 0)
1958 return (0);
1959 for (i = 1; i <= dumpinfo.c_volume; i++)
1960 if (inum < (ino_t)(unsigned)(dumpinfo.c_inos[i]))
1961 break;
1962 return (i - 1);
1963 }
1964
1965 /*
1966 * Find an inode header.
1967 * Note that *header must be stable storage, as curfile will end up with
1968 * pointers into it.
1969 */
1970 void
findinode(struct s_spcl * header)1971 findinode(struct s_spcl *header)
1972 {
1973 long skipcnt = 0;
1974 int i;
1975 char buf[TP_BSIZE_MAX];
1976
1977 curfile.name = gettext("<name unknown>");
1978 curfile.action = UNKNOWN;
1979 curfile.dip = (struct dinode *)NULL;
1980 curfile.ino = 0;
1981 curfile.ts = 0;
1982 if (ishead(header) == FAIL) {
1983 skipcnt++;
1984 while (gethead(header) == FAIL ||
1985 (time_t)(header->c_date) != dumpdate)
1986 skipcnt++;
1987 }
1988 for (;;) {
1989 if (checktype(header, TS_ADDR) == GOOD) {
1990 /*
1991 * Skip up to the beginning of the next record
1992 */
1993 for (i = 0; i < header->c_count; i++)
1994 if ((i >= TP_NINDIR) || (header->c_addr[i]))
1995 readtape(buf);
1996 (void) gethead(header);
1997 continue;
1998 }
1999 if (checktype(header, TS_INODE) == GOOD) {
2000 curfile.dip = &header->c_dinode;
2001 if (curfile.dip->di_suid != UID_LONG)
2002 curfile.dip->di_uid = curfile.dip->di_suid;
2003 if (curfile.dip->di_sgid != GID_LONG)
2004 curfile.dip->di_gid = curfile.dip->di_sgid;
2005 curfile.ino = header->c_inumber;
2006 curfile.ts = TS_INODE;
2007 break;
2008 }
2009 if (checktype(header, TS_END) == GOOD) {
2010 curfile.ino = maxino;
2011 curfile.ts = TS_END;
2012 break;
2013 }
2014 if (checktype(header, TS_CLRI) == GOOD) {
2015 curfile.name = gettext("<file removal list>");
2016 curfile.ts = TS_CLRI;
2017 break;
2018 }
2019 if (checktype(header, TS_BITS) == GOOD) {
2020 curfile.name = gettext("<file dump list>");
2021 curfile.ts = TS_BITS;
2022 break;
2023 }
2024 while (gethead(header) == FAIL)
2025 skipcnt++;
2026 }
2027 if (skipcnt > 0)
2028 (void) fprintf(stderr,
2029 gettext("resync restore, skipped %d blocks\n"),
2030 skipcnt);
2031 }
2032
2033 /*
2034 * return whether or not the buffer contains a header block
2035 */
2036 static int
ishead(struct s_spcl * buf)2037 ishead(struct s_spcl *buf)
2038 {
2039 if (buf->c_magic !=
2040 ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC))
2041 return (FAIL);
2042 return (GOOD);
2043 }
2044
2045 static int
checktype(struct s_spcl * b,int t)2046 checktype(struct s_spcl *b, int t)
2047 {
2048 if (b->c_type != t)
2049 return (FAIL);
2050 return (GOOD);
2051 }
2052
2053 /*
2054 * If autoloading is enabled, attempt to do it. If we succeed,
2055 * return non-zero.
2056 */
2057 static int
autoload_tape(void)2058 autoload_tape(void)
2059 {
2060 int result = 0; /* assume failure */
2061 int tries;
2062 int fd;
2063
2064 if (autoload) {
2065 /*
2066 * Wait for the tape to autoload. Note that the delay
2067 * period doesn't take into account however long it takes
2068 * for the open to fail (measured at 21 seconds for an
2069 * Exabyte 8200 under 2.7 on an Ultra 2).
2070 */
2071
2072 /* rewind tape and offline drive before loading new tape */
2073 closemt(FORCE_OFFLINE);
2074 (void) fprintf(stderr,
2075 gettext("Attempting to autoload next volume\n"));
2076 for (tries = 0; tries < autoload_tries; tries++) {
2077 if (host) {
2078 if (rmtopen(magtape, O_RDONLY) >= 0) {
2079 rmtclose();
2080 result = 1;
2081 break;
2082 }
2083 } else {
2084 if ((fd = open(magtape, O_RDONLY|O_LARGEFILE,
2085 0600)) >= 0) {
2086 (void) close(fd);
2087 result = 1;
2088 break;
2089 }
2090 }
2091 (void) sleep(autoload_period);
2092 }
2093 if (result == 0) {
2094 /* Assume caller will deal with manual change-over */
2095 (void) fprintf(stderr,
2096 gettext("Autoload timed out\n"));
2097 } else {
2098 if ((host != NULL &&
2099 (mt = rmtopen(magtape, O_RDONLY)) == -1) ||
2100 (host == NULL &&
2101 (mt = open(magtape, O_RDONLY|O_LARGEFILE)) == -1)) {
2102 (void) fprintf(stderr, gettext(
2103 "Autoload could not re-open tape\n"));
2104 result = 0;
2105 } else {
2106 (void) fprintf(stderr, gettext(
2107 "Tape loaded\n"));
2108 }
2109 }
2110 }
2111
2112 return (result);
2113 }
2114