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