16426961fSdist /*
25f8b5756Sbostic * Copyright (c) 1983, 1993
35f8b5756Sbostic * The Regents of the University of California. All rights reserved.
42d438a85Sbostic * (c) UNIX System Laboratories, Inc.
52d438a85Sbostic * All or some portions of this file are derived from material licensed
62d438a85Sbostic * to the University of California by American Telephone and Telegraph
72d438a85Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with
82d438a85Sbostic * the permission of UNIX System Laboratories, Inc.
9179758f1Sbostic *
10fb448fe7Sbostic * %sccs.include.redist.c%
116426961fSdist */
12711b0b98Smckusick
136426961fSdist #ifndef lint
14*7123cb22Smckusick static char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 05/01/95";
15179758f1Sbostic #endif /* not lint */
16150f930bSsam
17e786d8ceSbostic #include <sys/param.h>
18e786d8ceSbostic #include <sys/file.h>
19711b0b98Smckusick #include <sys/ioctl.h>
20711b0b98Smckusick #include <sys/mtio.h>
218eb28771Ssam #include <sys/stat.h>
22e786d8ceSbostic
23e786d8ceSbostic #include <ufs/ufs/dinode.h>
24e786d8ceSbostic #include <protocols/dumprestore.h>
25e786d8ceSbostic
26e786d8ceSbostic #include <errno.h>
27e786d8ceSbostic #include <setjmp.h>
28e786d8ceSbostic #include <stdio.h>
29e786d8ceSbostic #include <stdlib.h>
30e786d8ceSbostic #include <string.h>
31e786d8ceSbostic #include <unistd.h>
32e786d8ceSbostic
33e786d8ceSbostic #include "restore.h"
34e786d8ceSbostic #include "extern.h"
3503b38d59Sbostic #include "pathnames.h"
36711b0b98Smckusick
37167a9d62Smckusick static long fssize = MAXBSIZE;
383c0c659fSmckusick static int mt = -1;
393c0c659fSmckusick static int pipein = 0;
4091b7679cSmckusick static char magtape[BUFSIZ];
4144d805ceSmckusick static int blkcnt;
423c778ad6Smckusick static int numtrec;
4344d805ceSmckusick static char *tapebuf;
443c0c659fSmckusick static union u_spcl endoftapemark;
45aad233d8Smckusick static long blksread; /* blocks read since last header */
4652a32e52Smckusick static long tpblksread = 0; /* TP_BSIZE blocks read */
47f0f93cf0Smckusick static long tapesread;
483c0c659fSmckusick static jmp_buf restart;
493c0c659fSmckusick static int gettingfile = 0; /* restart has a valid frame */
50aad233d8Smckusick static char *host = NULL;
51711b0b98Smckusick
523c0c659fSmckusick static int ofile;
533c0c659fSmckusick static char *map;
543c0c659fSmckusick static char lnkbuf[MAXPATHLEN + 1];
553c0c659fSmckusick static int pathlen;
56711b0b98Smckusick
5724259a59Smckusick int oldinofmt; /* old inode format conversion required */
58f7e6f5f8Ssklower int Bcvt; /* Swap Bytes (for CCI or sun) */
59f7e6f5f8Ssklower static int Qcvt; /* Swap quads (for sun) */
60aad233d8Smckusick
6144d805ceSmckusick #define FLUSHTAPEBUF() blkcnt = ntrec + 1
6244d805ceSmckusick
63e786d8ceSbostic static void accthdr __P((struct s_spcl *));
64e786d8ceSbostic static int checksum __P((int *));
65e786d8ceSbostic static void findinode __P((struct s_spcl *));
66e786d8ceSbostic static void findtapeblksize __P((void));
67e786d8ceSbostic static int gethead __P((struct s_spcl *));
68e786d8ceSbostic static void readtape __P((char *));
69e786d8ceSbostic static void setdumpnum __P((void));
70e786d8ceSbostic static u_long swabl __P((u_long));
71e786d8ceSbostic static u_char *swablong __P((u_char *, int));
72e786d8ceSbostic static u_char *swabshort __P((u_char *, int));
73e786d8ceSbostic static void terminateinput __P((void));
74e786d8ceSbostic static void xtrfile __P((char *, long));
75e786d8ceSbostic static void xtrlnkfile __P((char *, long));
76e786d8ceSbostic static void xtrlnkskip __P((char *, long));
77e786d8ceSbostic static void xtrmap __P((char *, long));
78e786d8ceSbostic static void xtrmapskip __P((char *, long));
79e786d8ceSbostic static void xtrskip __P((char *, long));
80e786d8ceSbostic
81711b0b98Smckusick /*
82711b0b98Smckusick * Set up an input source
83711b0b98Smckusick */
84e786d8ceSbostic void
setinput(source)85711b0b98Smckusick setinput(source)
86711b0b98Smckusick char *source;
87711b0b98Smckusick {
8844d805ceSmckusick FLUSHTAPEBUF();
8964b996e7Smckusick if (bflag)
9064b996e7Smckusick newtapebuf(ntrec);
9164b996e7Smckusick else
9264b996e7Smckusick newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
93213e2460Smckusick terminal = stdin;
94aad233d8Smckusick
952e472962Smckusick #ifdef RRESTORE
96608bde00Sbostic if (strchr(source, ':')) {
97711b0b98Smckusick host = source;
98608bde00Sbostic source = strchr(host, ':');
99aad233d8Smckusick *source++ = '\0';
100711b0b98Smckusick if (rmthost(host) == 0)
101711b0b98Smckusick done(1);
102aad233d8Smckusick } else
103aad233d8Smckusick #endif
104213e2460Smckusick if (strcmp(source, "-") == 0) {
105103ba4deSmckusick /*
106103ba4deSmckusick * Since input is coming from a pipe we must establish
107103ba4deSmckusick * our own connection to the terminal.
108103ba4deSmckusick */
10903b38d59Sbostic terminal = fopen(_PATH_TTY, "r");
110103ba4deSmckusick if (terminal == NULL) {
111e786d8ceSbostic (void)fprintf(stderr, "cannot open %s: %s\n",
11203b38d59Sbostic _PATH_TTY, strerror(errno));
11303b38d59Sbostic terminal = fopen(_PATH_DEVNULL, "r");
114e40fb7ddSmckusick if (terminal == NULL) {
115e786d8ceSbostic (void)fprintf(stderr, "cannot open %s: %s\n",
11603b38d59Sbostic _PATH_DEVNULL, strerror(errno));
117103ba4deSmckusick done(1);
118103ba4deSmckusick }
119e40fb7ddSmckusick }
1203c0c659fSmckusick pipein++;
1213c0c659fSmckusick }
122aad233d8Smckusick setuid(getuid()); /* no longer need or want root privileges */
12391b7679cSmckusick (void) strcpy(magtape, source);
124711b0b98Smckusick }
125711b0b98Smckusick
126e786d8ceSbostic void
newtapebuf(size)12764b996e7Smckusick newtapebuf(size)
12864b996e7Smckusick long size;
12964b996e7Smckusick {
13044d805ceSmckusick static tapebufsize = -1;
13164b996e7Smckusick
13264b996e7Smckusick ntrec = size;
13344d805ceSmckusick if (size <= tapebufsize)
13464b996e7Smckusick return;
13544d805ceSmckusick if (tapebuf != NULL)
13644d805ceSmckusick free(tapebuf);
137e786d8ceSbostic tapebuf = malloc(size * TP_BSIZE);
13844d805ceSmckusick if (tapebuf == NULL) {
13964b996e7Smckusick fprintf(stderr, "Cannot allocate space for tape buffer\n");
14064b996e7Smckusick done(1);
14164b996e7Smckusick }
14244d805ceSmckusick tapebufsize = size;
14364b996e7Smckusick }
14464b996e7Smckusick
145711b0b98Smckusick /*
146711b0b98Smckusick * Verify that the tape drive can be accessed and
147711b0b98Smckusick * that it actually is a dump tape.
148711b0b98Smckusick */
149e786d8ceSbostic void
setup()150711b0b98Smckusick setup()
151711b0b98Smckusick {
1523c0c659fSmckusick int i, j, *ip;
153711b0b98Smckusick struct stat stbuf;
154711b0b98Smckusick
155711b0b98Smckusick vprintf(stdout, "Verify tape and initialize maps\n");
1562e472962Smckusick #ifdef RRESTORE
157aad233d8Smckusick if (host)
158086b8d64Sbostic mt = rmtopen(magtape, 0);
159aad233d8Smckusick else
160aad233d8Smckusick #endif
1613c0c659fSmckusick if (pipein)
1623c0c659fSmckusick mt = 0;
163aad233d8Smckusick else
164e786d8ceSbostic mt = open(magtape, O_RDONLY, 0);
165aad233d8Smckusick if (mt < 0) {
166e786d8ceSbostic fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
167711b0b98Smckusick done(1);
168711b0b98Smckusick }
1692c6546ceSmckusick volno = 1;
1702c6546ceSmckusick setdumpnum();
17144d805ceSmckusick FLUSHTAPEBUF();
17264b996e7Smckusick if (!pipein && !bflag)
17364b996e7Smckusick findtapeblksize();
174e6690a1dSmckusick if (gethead(&spcl) == FAIL) {
17544d805ceSmckusick blkcnt--; /* push back this block */
176aad233d8Smckusick blksread--;
17752a32e52Smckusick tpblksread--;
178711b0b98Smckusick cvtflag++;
179e6690a1dSmckusick if (gethead(&spcl) == FAIL) {
180711b0b98Smckusick fprintf(stderr, "Tape is not a dump tape\n");
181711b0b98Smckusick done(1);
182711b0b98Smckusick }
183711b0b98Smckusick fprintf(stderr, "Converting to new file system format.\n");
184711b0b98Smckusick }
1853c0c659fSmckusick if (pipein) {
1863c0c659fSmckusick endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
1873c0c659fSmckusick endoftapemark.s_spcl.c_type = TS_END;
1883c0c659fSmckusick ip = (int *)&endoftapemark;
1893c0c659fSmckusick j = sizeof(union u_spcl) / sizeof(int);
1903c0c659fSmckusick i = 0;
1913c0c659fSmckusick do
1923c0c659fSmckusick i += *ip++;
1933c0c659fSmckusick while (--j);
1943c0c659fSmckusick endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
1953c0c659fSmckusick }
1966591ccf8Smckusick if (vflag || command == 't')
1976591ccf8Smckusick printdumpinfo();
198711b0b98Smckusick dumptime = spcl.c_ddate;
1993c0c659fSmckusick dumpdate = spcl.c_date;
200711b0b98Smckusick if (stat(".", &stbuf) < 0) {
201e786d8ceSbostic fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
202711b0b98Smckusick done(1);
203711b0b98Smckusick }
204167a9d62Smckusick if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
205711b0b98Smckusick fssize = stbuf.st_blksize;
206167a9d62Smckusick if (((fssize - 1) & fssize) != 0) {
207711b0b98Smckusick fprintf(stderr, "bad block size %d\n", fssize);
208711b0b98Smckusick done(1);
209711b0b98Smckusick }
21044d805ceSmckusick if (spcl.c_volume != 1) {
211711b0b98Smckusick fprintf(stderr, "Tape is not volume 1 of the dump\n");
212711b0b98Smckusick done(1);
213711b0b98Smckusick }
21444d805ceSmckusick if (gethead(&spcl) == FAIL) {
21544d805ceSmckusick dprintf(stdout, "header read failed at %d blocks\n", blksread);
2163c0c659fSmckusick panic("no header after volume mark!\n");
21744d805ceSmckusick }
2186591ccf8Smckusick findinode(&spcl);
21944d805ceSmckusick if (spcl.c_type != TS_CLRI) {
220711b0b98Smckusick fprintf(stderr, "Cannot find file removal list\n");
221711b0b98Smckusick done(1);
222711b0b98Smckusick }
2233c0c659fSmckusick maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
2242c6546ceSmckusick dprintf(stdout, "maxino = %d\n", maxino);
22566947ca7Smckusick map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
226e786d8ceSbostic if (map == NULL)
2273b2bb250Smckusick panic("no memory for active inode map\n");
2283b2bb250Smckusick usedinomap = map;
229711b0b98Smckusick curfile.action = USING;
230711b0b98Smckusick getfile(xtrmap, xtrmapskip);
23144d805ceSmckusick if (spcl.c_type != TS_BITS) {
232711b0b98Smckusick fprintf(stderr, "Cannot find file dump list\n");
233711b0b98Smckusick done(1);
234711b0b98Smckusick }
23566947ca7Smckusick map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
236711b0b98Smckusick if (map == (char *)NULL)
237711b0b98Smckusick panic("no memory for file dump list\n");
238877a77f3Smckusick dumpmap = map;
239711b0b98Smckusick curfile.action = USING;
240711b0b98Smckusick getfile(xtrmap, xtrmapskip);
24119b02dc7Smckusick /*
24219b02dc7Smckusick * If there may be whiteout entries on the tape, pretend that the
24319b02dc7Smckusick * whiteout inode exists, so that the whiteout entries can be
24419b02dc7Smckusick * extracted.
24519b02dc7Smckusick */
24619b02dc7Smckusick if (oldinofmt == 0)
24719b02dc7Smckusick SETINO(WINO, dumpmap);
248711b0b98Smckusick }
249711b0b98Smckusick
250f0f93cf0Smckusick /*
251f0f93cf0Smckusick * Prompt user to load a new dump volume.
252f0f93cf0Smckusick * "Nextvol" is the next suggested volume to use.
253f0f93cf0Smckusick * This suggested volume is enforced when doing full
254f0f93cf0Smckusick * or incremental restores, but can be overrridden by
255f0f93cf0Smckusick * the user when only extracting a subset of the files.
256f0f93cf0Smckusick */
257e786d8ceSbostic void
getvol(nextvol)258711b0b98Smckusick getvol(nextvol)
259711b0b98Smckusick long nextvol;
260711b0b98Smckusick {
26152a32e52Smckusick long newvol, savecnt, wantnext, i;
262711b0b98Smckusick union u_spcl tmpspcl;
263711b0b98Smckusick # define tmpbuf tmpspcl.s_spcl
2646591ccf8Smckusick char buf[TP_BSIZE];
265711b0b98Smckusick
266dbf6ba0aSmckusick if (nextvol == 1) {
267f0f93cf0Smckusick tapesread = 0;
268dbf6ba0aSmckusick gettingfile = 0;
269dbf6ba0aSmckusick }
2703c0c659fSmckusick if (pipein) {
2716370a777Smckusick if (nextvol != 1)
2723c0c659fSmckusick panic("Changing volumes on pipe input?\n");
2736370a777Smckusick if (volno == 1)
2743c0c659fSmckusick return;
2756370a777Smckusick goto gethdr;
2763c0c659fSmckusick }
2773c0c659fSmckusick savecnt = blksread;
278711b0b98Smckusick again:
2796370a777Smckusick if (pipein)
2806370a777Smckusick done(1); /* pipes do not get a second chance */
28152a32e52Smckusick if (command == 'R' || command == 'r' || curfile.action != SKIP) {
282711b0b98Smckusick newvol = nextvol;
28352a32e52Smckusick wantnext = 1;
28452a32e52Smckusick } else {
285711b0b98Smckusick newvol = 0;
28652a32e52Smckusick wantnext = 0;
28752a32e52Smckusick }
288711b0b98Smckusick while (newvol <= 0) {
289f0f93cf0Smckusick if (tapesread == 0) {
290f0f93cf0Smckusick fprintf(stderr, "%s%s%s%s%s",
291f0f93cf0Smckusick "You have not read any tapes yet.\n",
292f0f93cf0Smckusick "Unless you know which volume your",
293f0f93cf0Smckusick " file(s) are on you should start\n",
294f0f93cf0Smckusick "with the last volume and work",
295f7e6f5f8Ssklower " towards towards the first.\n");
296f0f93cf0Smckusick } else {
297f0f93cf0Smckusick fprintf(stderr, "You have read volumes");
29844d805ceSmckusick strcpy(buf, ": ");
299f0f93cf0Smckusick for (i = 1; i < 32; i++)
300f0f93cf0Smckusick if (tapesread & (1 << i)) {
30144d805ceSmckusick fprintf(stderr, "%s%d", buf, i);
30244d805ceSmckusick strcpy(buf, ", ");
303f0f93cf0Smckusick }
304f0f93cf0Smckusick fprintf(stderr, "\n");
305f0f93cf0Smckusick }
306f73bbb4eSmckusick do {
307103ba4deSmckusick fprintf(stderr, "Specify next volume #: ");
308103ba4deSmckusick (void) fflush(stderr);
30944d805ceSmckusick (void) fgets(buf, BUFSIZ, terminal);
31044d805ceSmckusick } while (!feof(terminal) && buf[0] == '\n');
311103ba4deSmckusick if (feof(terminal))
312f73bbb4eSmckusick done(1);
31344d805ceSmckusick newvol = atoi(buf);
314711b0b98Smckusick if (newvol <= 0) {
315711b0b98Smckusick fprintf(stderr,
316711b0b98Smckusick "Volume numbers are positive numerics\n");
317711b0b98Smckusick }
318711b0b98Smckusick }
319f0f93cf0Smckusick if (newvol == volno) {
320f0f93cf0Smckusick tapesread |= 1 << volno;
321711b0b98Smckusick return;
322f0f93cf0Smckusick }
323711b0b98Smckusick closemt();
32491b7679cSmckusick fprintf(stderr, "Mount tape volume %d\n", newvol);
325135f3f2dSmckusick fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
326135f3f2dSmckusick fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
327103ba4deSmckusick (void) fflush(stderr);
32844d805ceSmckusick (void) fgets(buf, BUFSIZ, terminal);
329e40fb7ddSmckusick if (feof(terminal))
330e40fb7ddSmckusick done(1);
33144d805ceSmckusick if (!strcmp(buf, "none\n")) {
332fcea58adSmckusick terminateinput();
333fcea58adSmckusick return;
334135f3f2dSmckusick }
33544d805ceSmckusick if (buf[0] != '\n') {
33644d805ceSmckusick (void) strcpy(magtape, buf);
33791b7679cSmckusick magtape[strlen(magtape) - 1] = '\0';
33891b7679cSmckusick }
3392e472962Smckusick #ifdef RRESTORE
340aad233d8Smckusick if (host)
341aad233d8Smckusick mt = rmtopen(magtape, 0);
342aad233d8Smckusick else
343711b0b98Smckusick #endif
344e786d8ceSbostic mt = open(magtape, O_RDONLY, 0);
345aad233d8Smckusick
346aad233d8Smckusick if (mt == -1) {
34791b7679cSmckusick fprintf(stderr, "Cannot open %s\n", magtape);
34891b7679cSmckusick volno = -1;
349711b0b98Smckusick goto again;
350711b0b98Smckusick }
3516370a777Smckusick gethdr:
352711b0b98Smckusick volno = newvol;
3532c6546ceSmckusick setdumpnum();
35444d805ceSmckusick FLUSHTAPEBUF();
35544d805ceSmckusick if (gethead(&tmpbuf) == FAIL) {
35644d805ceSmckusick dprintf(stdout, "header read failed at %d blocks\n", blksread);
357711b0b98Smckusick fprintf(stderr, "tape is not dump tape\n");
358711b0b98Smckusick volno = 0;
359711b0b98Smckusick goto again;
360711b0b98Smckusick }
361ad52e9c7Smckusick if (tmpbuf.c_volume != volno) {
362711b0b98Smckusick fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
363711b0b98Smckusick volno = 0;
364711b0b98Smckusick goto again;
365711b0b98Smckusick }
3663c0c659fSmckusick if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
36711931016Smckusick fprintf(stderr, "Wrong dump date\n\tgot: %s",
36811931016Smckusick ctime(&tmpbuf.c_date));
36911931016Smckusick fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
3703c0c659fSmckusick volno = 0;
3713c0c659fSmckusick goto again;
3723c0c659fSmckusick }
373f0f93cf0Smckusick tapesread |= 1 << volno;
374e6690a1dSmckusick blksread = savecnt;
37552a32e52Smckusick /*
37652a32e52Smckusick * If continuing from the previous volume, skip over any
37752a32e52Smckusick * blocks read already at the end of the previous volume.
37852a32e52Smckusick *
37952a32e52Smckusick * If coming to this volume at random, skip to the beginning
38052a32e52Smckusick * of the next record.
38152a32e52Smckusick */
38252a32e52Smckusick dprintf(stdout, "read %ld recs, tape starts with %ld\n",
38352a32e52Smckusick tpblksread, tmpbuf.c_firstrec);
38452a32e52Smckusick if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
38552a32e52Smckusick if (!wantnext) {
38652a32e52Smckusick tpblksread = tmpbuf.c_firstrec;
38752a32e52Smckusick for (i = tmpbuf.c_count; i > 0; i--)
38852a32e52Smckusick readtape(buf);
38952a32e52Smckusick } else if (tmpbuf.c_firstrec > 0 &&
39052a32e52Smckusick tmpbuf.c_firstrec < tpblksread - 1) {
39152a32e52Smckusick /*
39252a32e52Smckusick * -1 since we've read the volume header
39352a32e52Smckusick */
39452a32e52Smckusick i = tpblksread - tmpbuf.c_firstrec - 1;
39552a32e52Smckusick dprintf(stderr, "Skipping %d duplicate record%s.\n",
39652a32e52Smckusick i, i > 1 ? "s" : "");
39752a32e52Smckusick while (--i >= 0)
39852a32e52Smckusick readtape(buf);
39952a32e52Smckusick }
40052a32e52Smckusick }
401711b0b98Smckusick if (curfile.action == USING) {
402711b0b98Smckusick if (volno == 1)
403711b0b98Smckusick panic("active file into volume 1\n");
404711b0b98Smckusick return;
405711b0b98Smckusick }
4066591ccf8Smckusick /*
4076591ccf8Smckusick * Skip up to the beginning of the next record
4086591ccf8Smckusick */
4090b0d351eSmckusick if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
4106591ccf8Smckusick for (i = tmpbuf.c_count; i > 0; i--)
4116591ccf8Smckusick readtape(buf);
412e6690a1dSmckusick (void) gethead(&spcl);
4136591ccf8Smckusick findinode(&spcl);
414711b0b98Smckusick if (gettingfile) {
415711b0b98Smckusick gettingfile = 0;
416711b0b98Smckusick longjmp(restart, 1);
417711b0b98Smckusick }
418711b0b98Smckusick }
419711b0b98Smckusick
4202c6546ceSmckusick /*
421fcea58adSmckusick * Handle unexpected EOF.
422fcea58adSmckusick */
423e786d8ceSbostic static void
terminateinput()424fcea58adSmckusick terminateinput()
425fcea58adSmckusick {
426fcea58adSmckusick
427fcea58adSmckusick if (gettingfile && curfile.action == USING) {
428fcea58adSmckusick printf("Warning: %s %s\n",
429fcea58adSmckusick "End-of-input encountered while extracting", curfile.name);
430fcea58adSmckusick }
431fcea58adSmckusick curfile.name = "<name unknown>";
432fcea58adSmckusick curfile.action = UNKNOWN;
433e786d8ceSbostic curfile.dip = NULL;
434fcea58adSmckusick curfile.ino = maxino;
435fcea58adSmckusick if (gettingfile) {
436fcea58adSmckusick gettingfile = 0;
437fcea58adSmckusick longjmp(restart, 1);
438fcea58adSmckusick }
439fcea58adSmckusick }
440fcea58adSmckusick
441fcea58adSmckusick /*
4422c6546ceSmckusick * handle multiple dumps per tape by skipping forward to the
4432c6546ceSmckusick * appropriate one.
4442c6546ceSmckusick */
445e786d8ceSbostic static void
setdumpnum()4462c6546ceSmckusick setdumpnum()
4472c6546ceSmckusick {
4482c6546ceSmckusick struct mtop tcom;
4492c6546ceSmckusick
4502c6546ceSmckusick if (dumpnum == 1 || volno != 1)
4512c6546ceSmckusick return;
4522c6546ceSmckusick if (pipein) {
4532c6546ceSmckusick fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
4542c6546ceSmckusick done(1);
4552c6546ceSmckusick }
4562c6546ceSmckusick tcom.mt_op = MTFSF;
4572c6546ceSmckusick tcom.mt_count = dumpnum - 1;
4582e472962Smckusick #ifdef RRESTORE
459aad233d8Smckusick if (host)
4602c6546ceSmckusick rmtioctl(MTFSF, dumpnum - 1);
461aad233d8Smckusick else
462aad233d8Smckusick #endif
463f73bbb4eSmckusick if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
464e786d8ceSbostic fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
4652c6546ceSmckusick }
4662c6546ceSmckusick
467e786d8ceSbostic void
printdumpinfo()4686591ccf8Smckusick printdumpinfo()
4696591ccf8Smckusick {
4706591ccf8Smckusick fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date));
471655e2ee3Smckusick fprintf(stdout, "Dumped from: %s",
472655e2ee3Smckusick (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
4736591ccf8Smckusick if (spcl.c_host[0] == '\0')
4746591ccf8Smckusick return;
4756591ccf8Smckusick fprintf(stderr, "Level %d dump of %s on %s:%s\n",
4766591ccf8Smckusick spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
4776591ccf8Smckusick fprintf(stderr, "Label: %s\n", spcl.c_label);
4786591ccf8Smckusick }
4796591ccf8Smckusick
480e786d8ceSbostic int
extractfile(name)481711b0b98Smckusick extractfile(name)
482711b0b98Smckusick char *name;
483711b0b98Smckusick {
484af59b353Smckusick int flags;
485af59b353Smckusick mode_t mode;
48663cb96feSmckusick struct timeval timep[2];
487711b0b98Smckusick struct entry *ep;
488711b0b98Smckusick
489711b0b98Smckusick curfile.name = name;
490711b0b98Smckusick curfile.action = USING;
491*7123cb22Smckusick timep[0].tv_sec = curfile.dip->di_atime;
492*7123cb22Smckusick timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
493*7123cb22Smckusick timep[1].tv_sec = curfile.dip->di_mtime;
494*7123cb22Smckusick timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
495711b0b98Smckusick mode = curfile.dip->di_mode;
496af59b353Smckusick flags = curfile.dip->di_flags;
497711b0b98Smckusick switch (mode & IFMT) {
498711b0b98Smckusick
499711b0b98Smckusick default:
500711b0b98Smckusick fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
501711b0b98Smckusick skipfile();
502711b0b98Smckusick return (FAIL);
503711b0b98Smckusick
504670a5108Smckusick case IFSOCK:
505670a5108Smckusick vprintf(stdout, "skipped socket %s\n", name);
506670a5108Smckusick skipfile();
507670a5108Smckusick return (GOOD);
508670a5108Smckusick
509711b0b98Smckusick case IFDIR:
510711b0b98Smckusick if (mflag) {
511711b0b98Smckusick ep = lookupname(name);
512e786d8ceSbostic if (ep == NULL || ep->e_flags & EXTRACT)
513711b0b98Smckusick panic("unextracted directory %s\n", name);
514711b0b98Smckusick skipfile();
515711b0b98Smckusick return (GOOD);
516711b0b98Smckusick }
517711b0b98Smckusick vprintf(stdout, "extract file %s\n", name);
518711b0b98Smckusick return (genliteraldir(name, curfile.ino));
519711b0b98Smckusick
520711b0b98Smckusick case IFLNK:
521711b0b98Smckusick lnkbuf[0] = '\0';
522711b0b98Smckusick pathlen = 0;
523711b0b98Smckusick getfile(xtrlnkfile, xtrlnkskip);
524711b0b98Smckusick if (pathlen == 0) {
525711b0b98Smckusick vprintf(stdout,
526711b0b98Smckusick "%s: zero length symbolic link (ignored)\n", name);
527711b0b98Smckusick return (GOOD);
528167a9d62Smckusick }
529167a9d62Smckusick return (linkit(lnkbuf, name, SYMLINK));
530711b0b98Smckusick
531711b0b98Smckusick case IFCHR:
532711b0b98Smckusick case IFBLK:
533711b0b98Smckusick vprintf(stdout, "extract special file %s\n", name);
534677df798Smckusick if (Nflag) {
535677df798Smckusick skipfile();
536677df798Smckusick return (GOOD);
537677df798Smckusick }
538711b0b98Smckusick if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
539e786d8ceSbostic fprintf(stderr, "%s: cannot create special file: %s\n",
540e786d8ceSbostic name, strerror(errno));
541711b0b98Smckusick skipfile();
542711b0b98Smckusick return (FAIL);
543711b0b98Smckusick }
5442c6546ceSmckusick (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
5452c6546ceSmckusick (void) chmod(name, mode);
546af59b353Smckusick (void) chflags(name, flags);
547af59b353Smckusick skipfile();
548af59b353Smckusick utimes(name, timep);
549af59b353Smckusick return (GOOD);
550af59b353Smckusick
551af59b353Smckusick case IFIFO:
552af59b353Smckusick vprintf(stdout, "extract fifo %s\n", name);
553af59b353Smckusick if (Nflag) {
554af59b353Smckusick skipfile();
555af59b353Smckusick return (GOOD);
556af59b353Smckusick }
557af59b353Smckusick if (mkfifo(name, mode) < 0) {
558af59b353Smckusick fprintf(stderr, "%s: cannot create fifo: %s\n",
559af59b353Smckusick name, strerror(errno));
560af59b353Smckusick skipfile();
561af59b353Smckusick return (FAIL);
562af59b353Smckusick }
563af59b353Smckusick (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
564af59b353Smckusick (void) chmod(name, mode);
565af59b353Smckusick (void) chflags(name, flags);
566711b0b98Smckusick skipfile();
56763cb96feSmckusick utimes(name, timep);
568711b0b98Smckusick return (GOOD);
569711b0b98Smckusick
570711b0b98Smckusick case IFREG:
571711b0b98Smckusick vprintf(stdout, "extract file %s\n", name);
572677df798Smckusick if (Nflag) {
573677df798Smckusick skipfile();
574677df798Smckusick return (GOOD);
575677df798Smckusick }
576608bde00Sbostic if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
577608bde00Sbostic 0666)) < 0) {
578e786d8ceSbostic fprintf(stderr, "%s: cannot create file: %s\n",
579e786d8ceSbostic name, strerror(errno));
580711b0b98Smckusick skipfile();
581711b0b98Smckusick return (FAIL);
582711b0b98Smckusick }
5832c6546ceSmckusick (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
5842c6546ceSmckusick (void) fchmod(ofile, mode);
585af59b353Smckusick (void) fchflags(ofile, flags);
586711b0b98Smckusick getfile(xtrfile, xtrskip);
5872c6546ceSmckusick (void) close(ofile);
58863cb96feSmckusick utimes(name, timep);
589711b0b98Smckusick return (GOOD);
590711b0b98Smckusick }
591711b0b98Smckusick /* NOTREACHED */
592711b0b98Smckusick }
593711b0b98Smckusick
5946370a777Smckusick /*
5956370a777Smckusick * skip over bit maps on the tape
5966370a777Smckusick */
597e786d8ceSbostic void
skipmaps()5986370a777Smckusick skipmaps()
5996370a777Smckusick {
6006370a777Smckusick
60144d805ceSmckusick while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
6026370a777Smckusick skipfile();
6036370a777Smckusick }
6046370a777Smckusick
6056370a777Smckusick /*
6066370a777Smckusick * skip over a file on the tape
6076370a777Smckusick */
608e786d8ceSbostic void
skipfile()609711b0b98Smckusick skipfile()
610711b0b98Smckusick {
611711b0b98Smckusick
612711b0b98Smckusick curfile.action = SKIP;
61344d805ceSmckusick getfile(xtrnull, xtrnull);
614711b0b98Smckusick }
615711b0b98Smckusick
616711b0b98Smckusick /*
61744d805ceSmckusick * Extract a file from the tape.
61844d805ceSmckusick * When an allocated block is found it is passed to the fill function;
61944d805ceSmckusick * when an unallocated block (hole) is found, a zeroed buffer is passed
62044d805ceSmckusick * to the skip function.
621711b0b98Smckusick */
622e786d8ceSbostic void
62344d805ceSmckusick getfile(fill, skip)
624e786d8ceSbostic void (*fill) __P((char *, long));
625e786d8ceSbostic void (*skip) __P((char *, long));
626711b0b98Smckusick {
627711b0b98Smckusick register int i;
628711b0b98Smckusick int curblk = 0;
6290f2a59f8Smckusick quad_t size = spcl.c_dinode.di_size;
630711b0b98Smckusick static char clearedbuf[MAXBSIZE];
631711b0b98Smckusick char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
63280f15c7fSmckusick char junk[TP_BSIZE];
633711b0b98Smckusick
63444d805ceSmckusick if (spcl.c_type == TS_END)
635711b0b98Smckusick panic("ran off end of tape\n");
63644d805ceSmckusick if (spcl.c_magic != NFS_MAGIC)
637711b0b98Smckusick panic("not at beginning of a file\n");
6386370a777Smckusick if (!gettingfile && setjmp(restart) != 0)
639711b0b98Smckusick return;
640711b0b98Smckusick gettingfile++;
641711b0b98Smckusick loop:
642711b0b98Smckusick for (i = 0; i < spcl.c_count; i++) {
643711b0b98Smckusick if (spcl.c_addr[i]) {
644711b0b98Smckusick readtape(&buf[curblk++][0]);
645711b0b98Smckusick if (curblk == fssize / TP_BSIZE) {
6460f2a59f8Smckusick (*fill)((char *)buf, (long)(size > TP_BSIZE ?
6470f2a59f8Smckusick fssize : (curblk - 1) * TP_BSIZE + size));
648711b0b98Smckusick curblk = 0;
649711b0b98Smckusick }
650711b0b98Smckusick } else {
651711b0b98Smckusick if (curblk > 0) {
6520f2a59f8Smckusick (*fill)((char *)buf, (long)(size > TP_BSIZE ?
6530f2a59f8Smckusick curblk * TP_BSIZE :
6540f2a59f8Smckusick (curblk - 1) * TP_BSIZE + size));
655711b0b98Smckusick curblk = 0;
656711b0b98Smckusick }
6570f2a59f8Smckusick (*skip)(clearedbuf, (long)(size > TP_BSIZE ?
6580f2a59f8Smckusick TP_BSIZE : size));
659711b0b98Smckusick }
66080f15c7fSmckusick if ((size -= TP_BSIZE) <= 0) {
66180f15c7fSmckusick for (i++; i < spcl.c_count; i++)
66280f15c7fSmckusick if (spcl.c_addr[i])
66380f15c7fSmckusick readtape(junk);
66461d42042Smckusick break;
665711b0b98Smckusick }
66680f15c7fSmckusick }
66744d805ceSmckusick if (gethead(&spcl) == GOOD && size > 0) {
66844d805ceSmckusick if (spcl.c_type == TS_ADDR)
66961d42042Smckusick goto loop;
67044d805ceSmckusick dprintf(stdout,
67144d805ceSmckusick "Missing address (header) block for %s at %d blocks\n",
67244d805ceSmckusick curfile.name, blksread);
673711b0b98Smckusick }
67461d42042Smckusick if (curblk > 0)
6750f2a59f8Smckusick (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
6766591ccf8Smckusick findinode(&spcl);
677711b0b98Smckusick gettingfile = 0;
678711b0b98Smckusick }
679711b0b98Smckusick
680711b0b98Smckusick /*
68144d805ceSmckusick * Write out the next block of a file.
682711b0b98Smckusick */
683e786d8ceSbostic static void
xtrfile(buf,size)684711b0b98Smckusick xtrfile(buf, size)
685711b0b98Smckusick char *buf;
686711b0b98Smckusick long size;
687711b0b98Smckusick {
688711b0b98Smckusick
689677df798Smckusick if (Nflag)
690677df798Smckusick return;
691711b0b98Smckusick if (write(ofile, buf, (int) size) == -1) {
692e786d8ceSbostic fprintf(stderr,
693e786d8ceSbostic "write error extracting inode %d, name %s\nwrite: %s\n",
694e786d8ceSbostic curfile.ino, curfile.name, strerror(errno));
695711b0b98Smckusick done(1);
696711b0b98Smckusick }
697711b0b98Smckusick }
698711b0b98Smckusick
69944d805ceSmckusick /*
70044d805ceSmckusick * Skip over a hole in a file.
70144d805ceSmckusick */
70244d805ceSmckusick /* ARGSUSED */
703e786d8ceSbostic static void
xtrskip(buf,size)704711b0b98Smckusick xtrskip(buf, size)
705711b0b98Smckusick char *buf;
706711b0b98Smckusick long size;
707711b0b98Smckusick {
708711b0b98Smckusick
7098b833fe8Sbostic if (lseek(ofile, size, SEEK_CUR) == -1) {
710e786d8ceSbostic fprintf(stderr,
711e786d8ceSbostic "seek error extracting inode %d, name %s\nlseek: %s\n",
712e786d8ceSbostic curfile.ino, curfile.name, strerror(errno));
713711b0b98Smckusick done(1);
714711b0b98Smckusick }
715711b0b98Smckusick }
716711b0b98Smckusick
71744d805ceSmckusick /*
71844d805ceSmckusick * Collect the next block of a symbolic link.
71944d805ceSmckusick */
720e786d8ceSbostic static void
xtrlnkfile(buf,size)721711b0b98Smckusick xtrlnkfile(buf, size)
722711b0b98Smckusick char *buf;
723711b0b98Smckusick long size;
724711b0b98Smckusick {
725711b0b98Smckusick
726711b0b98Smckusick pathlen += size;
727711b0b98Smckusick if (pathlen > MAXPATHLEN) {
728711b0b98Smckusick fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
729711b0b98Smckusick curfile.name, lnkbuf, buf, pathlen);
730711b0b98Smckusick done(1);
731711b0b98Smckusick }
732f73bbb4eSmckusick (void) strcat(lnkbuf, buf);
733711b0b98Smckusick }
734711b0b98Smckusick
73544d805ceSmckusick /*
73644d805ceSmckusick * Skip over a hole in a symbolic link (should never happen).
73744d805ceSmckusick */
73844d805ceSmckusick /* ARGSUSED */
739e786d8ceSbostic static void
xtrlnkskip(buf,size)740711b0b98Smckusick xtrlnkskip(buf, size)
741711b0b98Smckusick char *buf;
742711b0b98Smckusick long size;
743711b0b98Smckusick {
744711b0b98Smckusick
745711b0b98Smckusick fprintf(stderr, "unallocated block in symbolic link %s\n",
746711b0b98Smckusick curfile.name);
747711b0b98Smckusick done(1);
748711b0b98Smckusick }
749711b0b98Smckusick
75044d805ceSmckusick /*
75144d805ceSmckusick * Collect the next block of a bit map.
75244d805ceSmckusick */
753e786d8ceSbostic static void
xtrmap(buf,size)754711b0b98Smckusick xtrmap(buf, size)
755711b0b98Smckusick char *buf;
756711b0b98Smckusick long size;
757711b0b98Smckusick {
758711b0b98Smckusick
759608bde00Sbostic memmove(map, buf, size);
760877a77f3Smckusick map += size;
761711b0b98Smckusick }
762711b0b98Smckusick
76344d805ceSmckusick /*
76444d805ceSmckusick * Skip over a hole in a bit map (should never happen).
76544d805ceSmckusick */
76644d805ceSmckusick /* ARGSUSED */
767e786d8ceSbostic static void
xtrmapskip(buf,size)768711b0b98Smckusick xtrmapskip(buf, size)
769711b0b98Smckusick char *buf;
770711b0b98Smckusick long size;
771711b0b98Smckusick {
772711b0b98Smckusick
773711b0b98Smckusick panic("hole in map\n");
774877a77f3Smckusick map += size;
775711b0b98Smckusick }
776711b0b98Smckusick
77744d805ceSmckusick /*
77844d805ceSmckusick * Noop, when an extraction function is not needed.
77944d805ceSmckusick */
78044d805ceSmckusick /* ARGSUSED */
781e786d8ceSbostic void
xtrnull(buf,size)78244d805ceSmckusick xtrnull(buf, size)
78344d805ceSmckusick char *buf;
78444d805ceSmckusick long size;
78544d805ceSmckusick {
78644d805ceSmckusick
78744d805ceSmckusick return;
78844d805ceSmckusick }
789711b0b98Smckusick
790711b0b98Smckusick /*
79144d805ceSmckusick * Read TP_BSIZE blocks from the input.
79244d805ceSmckusick * Handle read errors, and end of media.
793711b0b98Smckusick */
794e786d8ceSbostic static void
readtape(buf)79544d805ceSmckusick readtape(buf)
79644d805ceSmckusick char *buf;
797711b0b98Smckusick {
79844d805ceSmckusick long rd, newvol, i;
79944d805ceSmckusick int cnt, seek_failed;
800711b0b98Smckusick
80144d805ceSmckusick if (blkcnt < numtrec) {
802608bde00Sbostic memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
80364b996e7Smckusick blksread++;
80452a32e52Smckusick tpblksread++;
80564b996e7Smckusick return;
80664b996e7Smckusick }
807181ffc32Smckusick for (i = 0; i < ntrec; i++)
80844d805ceSmckusick ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
8093c778ad6Smckusick if (numtrec == 0)
8103c778ad6Smckusick numtrec = ntrec;
811181ffc32Smckusick cnt = ntrec * TP_BSIZE;
8120b027efeSmckusick rd = 0;
8130b027efeSmckusick getmore:
8142e472962Smckusick #ifdef RRESTORE
815aad233d8Smckusick if (host)
81644d805ceSmckusick i = rmtread(&tapebuf[rd], cnt);
817aad233d8Smckusick else
818711b0b98Smckusick #endif
81944d805ceSmckusick i = read(mt, &tapebuf[rd], cnt);
8203c778ad6Smckusick /*
8213c778ad6Smckusick * Check for mid-tape short read error.
822aad233d8Smckusick * If found, skip rest of buffer and start with the next.
8233c778ad6Smckusick */
824aad233d8Smckusick if (!pipein && numtrec < ntrec && i > 0) {
825aad233d8Smckusick dprintf(stdout, "mid-media short read error.\n");
8263c778ad6Smckusick numtrec = ntrec;
8273c778ad6Smckusick }
8283c778ad6Smckusick /*
8293c778ad6Smckusick * Handle partial block read.
8303c778ad6Smckusick */
8319f0d31b3Smckusick if (pipein && i == 0 && rd > 0)
8329f0d31b3Smckusick i = rd;
8339f0d31b3Smckusick else if (i > 0 && i != ntrec * TP_BSIZE) {
83464b996e7Smckusick if (pipein) {
8350b027efeSmckusick rd += i;
8360b027efeSmckusick cnt -= i;
8370b027efeSmckusick if (cnt > 0)
8380b027efeSmckusick goto getmore;
8390b027efeSmckusick i = rd;
84064b996e7Smckusick } else {
841aad233d8Smckusick /*
842aad233d8Smckusick * Short read. Process the blocks read.
843aad233d8Smckusick */
84464b996e7Smckusick if (i % TP_BSIZE != 0)
845aad233d8Smckusick vprintf(stdout,
846aad233d8Smckusick "partial block read: %d should be %d\n",
84764b996e7Smckusick i, ntrec * TP_BSIZE);
8483c778ad6Smckusick numtrec = i / TP_BSIZE;
84964b996e7Smckusick }
8500b027efeSmckusick }
8513c778ad6Smckusick /*
8523c778ad6Smckusick * Handle read error.
8533c778ad6Smckusick */
8540b027efeSmckusick if (i < 0) {
855711b0b98Smckusick fprintf(stderr, "Tape read error while ");
856711b0b98Smckusick switch (curfile.action) {
8570b027efeSmckusick default:
8580b027efeSmckusick fprintf(stderr, "trying to set up tape\n");
8590b027efeSmckusick break;
860711b0b98Smckusick case UNKNOWN:
861295dbe20Smckusick fprintf(stderr, "trying to resynchronize\n");
862711b0b98Smckusick break;
863711b0b98Smckusick case USING:
864711b0b98Smckusick fprintf(stderr, "restoring %s\n", curfile.name);
865711b0b98Smckusick break;
866711b0b98Smckusick case SKIP:
867711b0b98Smckusick fprintf(stderr, "skipping over inode %d\n",
868711b0b98Smckusick curfile.ino);
869711b0b98Smckusick break;
870711b0b98Smckusick }
871711b0b98Smckusick if (!yflag && !reply("continue"))
872711b0b98Smckusick done(1);
873181ffc32Smckusick i = ntrec * TP_BSIZE;
874608bde00Sbostic memset(tapebuf, 0, i);
8752e472962Smckusick #ifdef RRESTORE
876aad233d8Smckusick if (host)
877aad233d8Smckusick seek_failed = (rmtseek(i, 1) < 0);
878aad233d8Smckusick else
879711b0b98Smckusick #endif
880e786d8ceSbostic seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
881aad233d8Smckusick
882aad233d8Smckusick if (seek_failed) {
883e786d8ceSbostic fprintf(stderr,
884e786d8ceSbostic "continuation failed: %s\n", strerror(errno));
885711b0b98Smckusick done(1);
886711b0b98Smckusick }
887711b0b98Smckusick }
8883c778ad6Smckusick /*
8893c778ad6Smckusick * Handle end of tape.
8903c778ad6Smckusick */
891711b0b98Smckusick if (i == 0) {
892aad233d8Smckusick vprintf(stdout, "End-of-tape encountered\n");
89331fed6adSmckusick if (!pipein) {
894711b0b98Smckusick newvol = volno + 1;
895711b0b98Smckusick volno = 0;
8963c778ad6Smckusick numtrec = 0;
897711b0b98Smckusick getvol(newvol);
89844d805ceSmckusick readtape(buf);
899711b0b98Smckusick return;
900711b0b98Smckusick }
90131fed6adSmckusick if (rd % TP_BSIZE != 0)
90231fed6adSmckusick panic("partial block read: %d should be %d\n",
90331fed6adSmckusick rd, ntrec * TP_BSIZE);
904fcea58adSmckusick terminateinput();
905608bde00Sbostic memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
90631fed6adSmckusick }
90744d805ceSmckusick blkcnt = 0;
908608bde00Sbostic memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
9093c0c659fSmckusick blksread++;
91052a32e52Smckusick tpblksread++;
911711b0b98Smckusick }
912711b0b98Smckusick
913e786d8ceSbostic static void
findtapeblksize()91464b996e7Smckusick findtapeblksize()
91564b996e7Smckusick {
91664b996e7Smckusick register long i;
91764b996e7Smckusick
91864b996e7Smckusick for (i = 0; i < ntrec; i++)
91944d805ceSmckusick ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
92044d805ceSmckusick blkcnt = 0;
92164b996e7Smckusick #ifdef RRESTORE
922aad233d8Smckusick if (host)
92344d805ceSmckusick i = rmtread(tapebuf, ntrec * TP_BSIZE);
924aad233d8Smckusick else
92564b996e7Smckusick #endif
92644d805ceSmckusick i = read(mt, tapebuf, ntrec * TP_BSIZE);
927aad233d8Smckusick
92864b996e7Smckusick if (i <= 0) {
929e786d8ceSbostic fprintf(stderr, "tape read error: %s\n", strerror(errno));
93064b996e7Smckusick done(1);
93164b996e7Smckusick }
93264b996e7Smckusick if (i % TP_BSIZE != 0) {
93364b996e7Smckusick fprintf(stderr, "Tape block size (%d) %s (%d)\n",
93464b996e7Smckusick i, "is not a multiple of dump block size", TP_BSIZE);
93564b996e7Smckusick done(1);
93664b996e7Smckusick }
93764b996e7Smckusick ntrec = i / TP_BSIZE;
9383c778ad6Smckusick numtrec = ntrec;
93964b996e7Smckusick vprintf(stdout, "Tape block size is %d\n", ntrec);
94064b996e7Smckusick }
94164b996e7Smckusick
942e786d8ceSbostic void
closemt()943711b0b98Smckusick closemt()
944711b0b98Smckusick {
94544d805ceSmckusick
946711b0b98Smckusick if (mt < 0)
947711b0b98Smckusick return;
9482e472962Smckusick #ifdef RRESTORE
949aad233d8Smckusick if (host)
950711b0b98Smckusick rmtclose();
951aad233d8Smckusick else
952711b0b98Smckusick #endif
953aad233d8Smckusick (void) close(mt);
954711b0b98Smckusick }
955711b0b98Smckusick
956711b0b98Smckusick /*
95744d805ceSmckusick * Read the next block from the tape.
95844d805ceSmckusick * Check to see if it is one of several vintage headers.
95944d805ceSmckusick * If it is an old style header, convert it to a new style header.
96044d805ceSmckusick * If it is not any valid header, return an error.
961711b0b98Smckusick */
962e786d8ceSbostic static int
gethead(buf)963711b0b98Smckusick gethead(buf)
964711b0b98Smckusick struct s_spcl *buf;
965711b0b98Smckusick {
966135f3f2dSmckusick long i;
96704c26334Smckusick union {
96804c26334Smckusick quad_t qval;
96904c26334Smckusick long val[2];
97004c26334Smckusick } qcvt;
971711b0b98Smckusick union u_ospcl {
972711b0b98Smckusick char dummy[TP_BSIZE];
973711b0b98Smckusick struct s_ospcl {
9743c0c659fSmckusick long c_type;
9753c0c659fSmckusick long c_date;
9763c0c659fSmckusick long c_ddate;
9773c0c659fSmckusick long c_volume;
9783c0c659fSmckusick long c_tapea;
979877a77f3Smckusick u_short c_inumber;
9803c0c659fSmckusick long c_magic;
9813c0c659fSmckusick long c_checksum;
982711b0b98Smckusick struct odinode {
983711b0b98Smckusick unsigned short odi_mode;
984877a77f3Smckusick u_short odi_nlink;
985877a77f3Smckusick u_short odi_uid;
986877a77f3Smckusick u_short odi_gid;
9873c0c659fSmckusick long odi_size;
9883c0c659fSmckusick long odi_rdev;
989711b0b98Smckusick char odi_addr[36];
9903c0c659fSmckusick long odi_atime;
9913c0c659fSmckusick long odi_mtime;
9923c0c659fSmckusick long odi_ctime;
993711b0b98Smckusick } c_dinode;
9943c0c659fSmckusick long c_count;
9953c0c659fSmckusick char c_addr[256];
996711b0b98Smckusick } s_ospcl;
997711b0b98Smckusick } u_ospcl;
998711b0b98Smckusick
999711b0b98Smckusick if (!cvtflag) {
1000711b0b98Smckusick readtape((char *)buf);
1001f7e6f5f8Ssklower if (buf->c_magic != NFS_MAGIC) {
1002f7e6f5f8Ssklower if (swabl(buf->c_magic) != NFS_MAGIC)
10033c0c659fSmckusick return (FAIL);
1004f7e6f5f8Ssklower if (!Bcvt) {
1005f7e6f5f8Ssklower vprintf(stdout, "Note: Doing Byte swapping\n");
1006f7e6f5f8Ssklower Bcvt = 1;
1007f7e6f5f8Ssklower }
1008f7e6f5f8Ssklower }
1009f7e6f5f8Ssklower if (checksum((int *)buf) == FAIL)
1010f7e6f5f8Ssklower return (FAIL);
1011f7e6f5f8Ssklower if (Bcvt)
1012e786d8ceSbostic swabst((u_char *)"8l4s31l", (u_char *)buf);
1013e6690a1dSmckusick goto good;
1014711b0b98Smckusick }
1015711b0b98Smckusick readtape((char *)(&u_ospcl.s_ospcl));
1016608bde00Sbostic memset(buf, 0, (long)TP_BSIZE);
1017711b0b98Smckusick buf->c_type = u_ospcl.s_ospcl.c_type;
1018711b0b98Smckusick buf->c_date = u_ospcl.s_ospcl.c_date;
1019711b0b98Smckusick buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1020711b0b98Smckusick buf->c_volume = u_ospcl.s_ospcl.c_volume;
1021711b0b98Smckusick buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1022711b0b98Smckusick buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1023711b0b98Smckusick buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1024711b0b98Smckusick buf->c_magic = u_ospcl.s_ospcl.c_magic;
1025711b0b98Smckusick buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1026711b0b98Smckusick buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1027711b0b98Smckusick buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1028711b0b98Smckusick buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1029711b0b98Smckusick buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
1030711b0b98Smckusick buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1031*7123cb22Smckusick buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
1032*7123cb22Smckusick buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1033*7123cb22Smckusick buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1034711b0b98Smckusick buf->c_count = u_ospcl.s_ospcl.c_count;
1035608bde00Sbostic memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256);
1036711b0b98Smckusick if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
1037e6690a1dSmckusick checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
10383c0c659fSmckusick return(FAIL);
1039711b0b98Smckusick buf->c_magic = NFS_MAGIC;
1040e6690a1dSmckusick
1041e6690a1dSmckusick good:
10420b80bffbSmckusick if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
1043f7e6f5f8Ssklower (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
104404c26334Smckusick qcvt.qval = buf->c_dinode.di_size;
104504c26334Smckusick if (qcvt.val[0] || qcvt.val[1]) {
1046f7e6f5f8Ssklower printf("Note: Doing Quad swapping\n");
1047f7e6f5f8Ssklower Qcvt = 1;
1048f7e6f5f8Ssklower }
1049f7e6f5f8Ssklower }
1050f7e6f5f8Ssklower if (Qcvt) {
105104c26334Smckusick qcvt.qval = buf->c_dinode.di_size;
105204c26334Smckusick i = qcvt.val[1];
105304c26334Smckusick qcvt.val[1] = qcvt.val[0];
105404c26334Smckusick qcvt.val[0] = i;
1055a7a62901Smckusick buf->c_dinode.di_size = qcvt.qval;
1056f7e6f5f8Ssklower }
1057aad233d8Smckusick
1058e6690a1dSmckusick switch (buf->c_type) {
1059e6690a1dSmckusick
1060e6690a1dSmckusick case TS_CLRI:
1061e6690a1dSmckusick case TS_BITS:
1062e6690a1dSmckusick /*
1063e6690a1dSmckusick * Have to patch up missing information in bit map headers
1064e6690a1dSmckusick */
1065e6690a1dSmckusick buf->c_inumber = 0;
1066e6690a1dSmckusick buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
1067e6690a1dSmckusick for (i = 0; i < buf->c_count; i++)
1068e6690a1dSmckusick buf->c_addr[i]++;
1069e6690a1dSmckusick break;
1070e6690a1dSmckusick
1071e6690a1dSmckusick case TS_TAPE:
107224259a59Smckusick if ((buf->c_flags & DR_NEWINODEFMT) == 0)
107324259a59Smckusick oldinofmt = 1;
107424259a59Smckusick /* fall through */
1075e6690a1dSmckusick case TS_END:
1076e6690a1dSmckusick buf->c_inumber = 0;
1077e6690a1dSmckusick break;
1078e6690a1dSmckusick
1079e6690a1dSmckusick case TS_INODE:
1080e6690a1dSmckusick case TS_ADDR:
1081e6690a1dSmckusick break;
1082e6690a1dSmckusick
1083e6690a1dSmckusick default:
1084e6690a1dSmckusick panic("gethead: unknown inode type %d\n", buf->c_type);
1085e6690a1dSmckusick break;
1086e6690a1dSmckusick }
108724259a59Smckusick /*
108824259a59Smckusick * If we are restoring a filesystem with old format inodes,
108924259a59Smckusick * copy the uid/gid to the new location.
109024259a59Smckusick */
109124259a59Smckusick if (oldinofmt) {
109224259a59Smckusick buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
109324259a59Smckusick buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
109424259a59Smckusick }
10953c0c659fSmckusick if (dflag)
10963c0c659fSmckusick accthdr(buf);
10973c0c659fSmckusick return(GOOD);
10983c0c659fSmckusick }
10993c0c659fSmckusick
11003c0c659fSmckusick /*
11013c0c659fSmckusick * Check that a header is where it belongs and predict the next header
11023c0c659fSmckusick */
1103e786d8ceSbostic static void
accthdr(header)11043c0c659fSmckusick accthdr(header)
11053c0c659fSmckusick struct s_spcl *header;
11063c0c659fSmckusick {
110766947ca7Smckusick static ino_t previno = 0x7fffffff;
11083c0c659fSmckusick static int prevtype;
11093c0c659fSmckusick static long predict;
11103c0c659fSmckusick long blks, i;
11113c0c659fSmckusick
11120b0d351eSmckusick if (header->c_type == TS_TAPE) {
11134ad48669Smckusick fprintf(stderr, "Volume header (%s inode format) ",
11144ad48669Smckusick oldinofmt ? "old" : "new");
111552a32e52Smckusick if (header->c_firstrec)
111652a32e52Smckusick fprintf(stderr, "begins with record %d",
111752a32e52Smckusick header->c_firstrec);
111852a32e52Smckusick fprintf(stderr, "\n");
1119ad8f41e5Smckusick previno = 0x7fffffff;
1120e6690a1dSmckusick return;
1121e6690a1dSmckusick }
112266947ca7Smckusick if (previno == 0x7fffffff)
11233c0c659fSmckusick goto newcalc;
11243c0c659fSmckusick switch (prevtype) {
11253c0c659fSmckusick case TS_BITS:
11263b2bb250Smckusick fprintf(stderr, "Dumped inodes map header");
11273c0c659fSmckusick break;
11283c0c659fSmckusick case TS_CLRI:
11293b2bb250Smckusick fprintf(stderr, "Used inodes map header");
11303c0c659fSmckusick break;
11313c0c659fSmckusick case TS_INODE:
1132e6690a1dSmckusick fprintf(stderr, "File header, ino %d", previno);
11333c0c659fSmckusick break;
11343c0c659fSmckusick case TS_ADDR:
1135e6690a1dSmckusick fprintf(stderr, "File continuation header, ino %d", previno);
11363c0c659fSmckusick break;
11373c0c659fSmckusick case TS_END:
1138e6690a1dSmckusick fprintf(stderr, "End of tape header");
11393c0c659fSmckusick break;
11403c0c659fSmckusick }
11413c0c659fSmckusick if (predict != blksread - 1)
11423c0c659fSmckusick fprintf(stderr, "; predicted %d blocks, got %d blocks",
11433c0c659fSmckusick predict, blksread - 1);
11443c0c659fSmckusick fprintf(stderr, "\n");
11453c0c659fSmckusick newcalc:
11463c0c659fSmckusick blks = 0;
1147e6690a1dSmckusick if (header->c_type != TS_END)
11483c0c659fSmckusick for (i = 0; i < header->c_count; i++)
11493c0c659fSmckusick if (header->c_addr[i] != 0)
11503c0c659fSmckusick blks++;
11513c0c659fSmckusick predict = blks;
11523c0c659fSmckusick blksread = 0;
11533c0c659fSmckusick prevtype = header->c_type;
11543c0c659fSmckusick previno = header->c_inumber;
1155711b0b98Smckusick }
1156711b0b98Smckusick
1157711b0b98Smckusick /*
1158711b0b98Smckusick * Find an inode header.
1159711b0b98Smckusick * Complain if had to skip, and complain is set.
1160711b0b98Smckusick */
1161e786d8ceSbostic static void
findinode(header)11626591ccf8Smckusick findinode(header)
1163711b0b98Smckusick struct s_spcl *header;
1164711b0b98Smckusick {
11653c0c659fSmckusick static long skipcnt = 0;
1166ad8f41e5Smckusick long i;
1167ad8f41e5Smckusick char buf[TP_BSIZE];
1168711b0b98Smckusick
1169711b0b98Smckusick curfile.name = "<name unknown>";
1170711b0b98Smckusick curfile.action = UNKNOWN;
1171e786d8ceSbostic curfile.dip = NULL;
1172711b0b98Smckusick curfile.ino = 0;
117344d805ceSmckusick do {
117444d805ceSmckusick if (header->c_magic != NFS_MAGIC) {
1175711b0b98Smckusick skipcnt++;
117644d805ceSmckusick while (gethead(header) == FAIL ||
117744d805ceSmckusick header->c_date != dumpdate)
11783c0c659fSmckusick skipcnt++;
11793c0c659fSmckusick }
118044d805ceSmckusick switch (header->c_type) {
118144d805ceSmckusick
118244d805ceSmckusick case TS_ADDR:
1183ad8f41e5Smckusick /*
1184ad8f41e5Smckusick * Skip up to the beginning of the next record
1185ad8f41e5Smckusick */
1186ad8f41e5Smckusick for (i = 0; i < header->c_count; i++)
1187ad8f41e5Smckusick if (header->c_addr[i])
1188ad8f41e5Smckusick readtape(buf);
118944d805ceSmckusick while (gethead(header) == FAIL ||
119044d805ceSmckusick header->c_date != dumpdate)
119144d805ceSmckusick skipcnt++;
119244d805ceSmckusick break;
119344d805ceSmckusick
119444d805ceSmckusick case TS_INODE:
1195711b0b98Smckusick curfile.dip = &header->c_dinode;
1196711b0b98Smckusick curfile.ino = header->c_inumber;
1197711b0b98Smckusick break;
119844d805ceSmckusick
119944d805ceSmckusick case TS_END:
1200711b0b98Smckusick curfile.ino = maxino;
1201711b0b98Smckusick break;
120244d805ceSmckusick
120344d805ceSmckusick case TS_CLRI:
1204711b0b98Smckusick curfile.name = "<file removal list>";
1205711b0b98Smckusick break;
120644d805ceSmckusick
120744d805ceSmckusick case TS_BITS:
1208711b0b98Smckusick curfile.name = "<file dump list>";
1209711b0b98Smckusick break;
121044d805ceSmckusick
121144d805ceSmckusick case TS_TAPE:
121244d805ceSmckusick panic("unexpected tape header\n");
121344d805ceSmckusick /* NOTREACHED */
121444d805ceSmckusick
121544d805ceSmckusick default:
121644d805ceSmckusick panic("unknown tape header type %d\n", spcl.c_type);
121744d805ceSmckusick /* NOTREACHED */
121844d805ceSmckusick
1219711b0b98Smckusick }
122044d805ceSmckusick } while (header->c_type == TS_ADDR);
12216591ccf8Smckusick if (skipcnt > 0)
1222fc5757e5Smckusick fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
1223711b0b98Smckusick skipcnt = 0;
1224711b0b98Smckusick }
1225711b0b98Smckusick
1226e786d8ceSbostic static int
checksum(buf)122744d805ceSmckusick checksum(buf)
122844d805ceSmckusick register int *buf;
1229711b0b98Smckusick {
1230711b0b98Smckusick register int i, j;
1231711b0b98Smckusick
1232711b0b98Smckusick j = sizeof(union u_spcl) / sizeof(int);
1233711b0b98Smckusick i = 0;
1234f7e6f5f8Ssklower if(!Bcvt) {
1235711b0b98Smckusick do
123644d805ceSmckusick i += *buf++;
1237711b0b98Smckusick while (--j);
1238f7e6f5f8Ssklower } else {
1239f7e6f5f8Ssklower /* What happens if we want to read restore tapes
1240f7e6f5f8Ssklower for a 16bit int machine??? */
1241f7e6f5f8Ssklower do
124244d805ceSmckusick i += swabl(*buf++);
1243f7e6f5f8Ssklower while (--j);
1244f7e6f5f8Ssklower }
1245f7e6f5f8Ssklower
1246711b0b98Smckusick if (i != CHECKSUM) {
1247711b0b98Smckusick fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1248711b0b98Smckusick curfile.ino, curfile.name);
12493c0c659fSmckusick return(FAIL);
1250711b0b98Smckusick }
12513c0c659fSmckusick return(GOOD);
1252711b0b98Smckusick }
1253711b0b98Smckusick
12542e472962Smckusick #ifdef RRESTORE
1255e786d8ceSbostic #if __STDC__
1256e786d8ceSbostic #include <stdarg.h>
1257e786d8ceSbostic #else
1258e786d8ceSbostic #include <varargs.h>
1259e786d8ceSbostic #endif
1260711b0b98Smckusick
1261e786d8ceSbostic void
1262e786d8ceSbostic #if __STDC__
msg(const char * fmt,...)1263e786d8ceSbostic msg(const char *fmt, ...)
1264e786d8ceSbostic #else
1265e786d8ceSbostic msg(fmt, va_alist)
1266e786d8ceSbostic char *fmt;
1267e786d8ceSbostic va_dcl
1268e786d8ceSbostic #endif
1269e786d8ceSbostic {
1270e786d8ceSbostic va_list ap;
1271e786d8ceSbostic #if __STDC__
1272e786d8ceSbostic va_start(ap, fmt);
1273e786d8ceSbostic #else
1274e786d8ceSbostic va_start(ap);
1275e786d8ceSbostic #endif
1276e786d8ceSbostic (void)vfprintf(stderr, fmt, ap);
1277e786d8ceSbostic va_end(ap);
1278711b0b98Smckusick }
1279aad233d8Smckusick #endif /* RRESTORE */
1280f7e6f5f8Ssklower
1281e786d8ceSbostic static u_char *
swabshort(sp,n)12820062352bSmckusick swabshort(sp, n)
12830062352bSmckusick register u_char *sp;
12840062352bSmckusick register int n;
12850062352bSmckusick {
12860062352bSmckusick char c;
12870062352bSmckusick
12880062352bSmckusick while (--n >= 0) {
12890062352bSmckusick c = sp[0]; sp[0] = sp[1]; sp[1] = c;
12900062352bSmckusick sp += 2;
12910062352bSmckusick }
12920062352bSmckusick return (sp);
12930062352bSmckusick }
12940062352bSmckusick
1295e786d8ceSbostic static u_char *
swablong(sp,n)12960062352bSmckusick swablong(sp, n)
12970062352bSmckusick register u_char *sp;
12980062352bSmckusick register int n;
12990062352bSmckusick {
13000062352bSmckusick char c;
13010062352bSmckusick
13020062352bSmckusick while (--n >= 0) {
13030062352bSmckusick c = sp[0]; sp[0] = sp[3]; sp[3] = c;
13040062352bSmckusick c = sp[2]; sp[2] = sp[1]; sp[1] = c;
13050062352bSmckusick sp += 4;
13060062352bSmckusick }
13070062352bSmckusick return (sp);
13080062352bSmckusick }
13090062352bSmckusick
1310e786d8ceSbostic void
swabst(cp,sp)1311f7e6f5f8Ssklower swabst(cp, sp)
13120062352bSmckusick register u_char *cp, *sp;
1313f7e6f5f8Ssklower {
1314f7e6f5f8Ssklower int n = 0;
13150062352bSmckusick
1316f7e6f5f8Ssklower while (*cp) {
1317f7e6f5f8Ssklower switch (*cp) {
1318f7e6f5f8Ssklower case '0': case '1': case '2': case '3': case '4':
1319f7e6f5f8Ssklower case '5': case '6': case '7': case '8': case '9':
1320f7e6f5f8Ssklower n = (n * 10) + (*cp++ - '0');
1321f7e6f5f8Ssklower continue;
1322f7e6f5f8Ssklower
1323f7e6f5f8Ssklower case 's': case 'w': case 'h':
13240062352bSmckusick if (n == 0)
13250062352bSmckusick n = 1;
13260062352bSmckusick sp = swabshort(sp, n);
1327f7e6f5f8Ssklower break;
1328f7e6f5f8Ssklower
1329f7e6f5f8Ssklower case 'l':
13300062352bSmckusick if (n == 0)
13310062352bSmckusick n = 1;
13320062352bSmckusick sp = swablong(sp, n);
13330062352bSmckusick break;
13340062352bSmckusick
13350062352bSmckusick default: /* Any other character, like 'b' counts as byte. */
13360062352bSmckusick if (n == 0)
13370062352bSmckusick n = 1;
13380062352bSmckusick sp += n;
13390062352bSmckusick break;
1340f7e6f5f8Ssklower }
13410062352bSmckusick cp++;
13420062352bSmckusick n = 0;
1343f7e6f5f8Ssklower }
1344f7e6f5f8Ssklower }
13450062352bSmckusick
1346e786d8ceSbostic static u_long
swabl(x)13470062352bSmckusick swabl(x)
13480062352bSmckusick u_long x;
13490062352bSmckusick {
1350e786d8ceSbostic swabst((u_char *)"l", (u_char *)&x);
13510062352bSmckusick return (x);
13520062352bSmckusick }
1353