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