provide correct exit values
[unix-history] / usr / src / sbin / restore / tape.c
CommitLineData
8c5eec2f
DF
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 */
f78e116c 6
8c5eec2f 7#ifndef lint
414c4f09 8static char sccsid[] = "@(#)tape.c 5.14 (Berkeley) %G%";
8c5eec2f 9#endif not lint
ebd1f727 10
f78e116c 11#include "restore.h"
d9127117 12#include <protocols/dumprestore.h>
f78e116c
KM
13#include <sys/ioctl.h>
14#include <sys/mtio.h>
2cb5dabb 15#include <sys/file.h>
f78e116c 16#include <setjmp.h>
a7b24fe9 17#include <sys/stat.h>
2cb5dabb 18
bdeceadb 19static long fssize = MAXBSIZE;
2cb5dabb
KM
20static int mt = -1;
21static int pipein = 0;
7eb08dfe 22static char magtape[BUFSIZ];
19230a53
KM
23static int bct;
24static char *tbf;
2cb5dabb
KM
25static union u_spcl endoftapemark;
26static long blksread;
170639fd 27static long tapesread;
2cb5dabb
KM
28static jmp_buf restart;
29static int gettingfile = 0; /* restart has a valid frame */
30
31static int ofile;
32static char *map;
33static char lnkbuf[MAXPATHLEN + 1];
34static int pathlen;
f78e116c 35
b4c41341
KS
36int Bcvt; /* Swap Bytes (for CCI or sun) */
37static int Qcvt; /* Swap quads (for sun) */
f78e116c
KM
38/*
39 * Set up an input source
40 */
41setinput(source)
42 char *source;
43{
e9e7ecc4 44#ifdef RRESTORE
7eb08dfe 45 char *host, *tape;
e9e7ecc4 46#endif RRESTORE
f78e116c 47
19230a53 48 flsht();
b97e998a
KM
49 if (bflag)
50 newtapebuf(ntrec);
51 else
52 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
9c695c61 53 terminal = stdin;
e9e7ecc4 54#ifdef RRESTORE
f78e116c 55 host = source;
7eb08dfe
KM
56 tape = index(host, ':');
57 if (tape == 0) {
f78e116c 58nohost:
5c5f44c7 59 msg("need keyletter ``f'' and device ``host:tape''\n");
f78e116c
KM
60 done(1);
61 }
7eb08dfe
KM
62 *tape++ = '\0';
63 (void) strcpy(magtape, tape);
f78e116c
KM
64 if (rmthost(host) == 0)
65 done(1);
66 setuid(getuid()); /* no longer need or want root privileges */
67#else
9c695c61 68 if (strcmp(source, "-") == 0) {
b677c5d7
KM
69 /*
70 * Since input is coming from a pipe we must establish
71 * our own connection to the terminal.
72 */
73 terminal = fopen("/dev/tty", "r");
74 if (terminal == NULL) {
b8eb5f1f
KM
75 perror("Cannot open(\"/dev/tty\")");
76 terminal = fopen("/dev/null", "r");
77 if (terminal == NULL) {
78 perror("Cannot open(\"/dev/null\")");
79 done(1);
80 }
b677c5d7 81 }
2cb5dabb 82 pipein++;
2cb5dabb 83 }
7eb08dfe 84 (void) strcpy(magtape, source);
e9e7ecc4 85#endif RRESTORE
f78e116c
KM
86}
87
b97e998a
KM
88newtapebuf(size)
89 long size;
90{
91 static tbfsize = -1;
92
93 ntrec = size;
94 if (size <= tbfsize)
95 return;
96 if (tbf != NULL)
97 free(tbf);
98 tbf = (char *)malloc(size * TP_BSIZE);
99 if (tbf == NULL) {
100 fprintf(stderr, "Cannot allocate space for tape buffer\n");
101 done(1);
102 }
103 tbfsize = size;
104}
105
f78e116c
KM
106/*
107 * Verify that the tape drive can be accessed and
108 * that it actually is a dump tape.
109 */
110setup()
111{
2cb5dabb 112 int i, j, *ip;
f78e116c 113 struct stat stbuf;
f78e116c
KM
114 extern int xtrmap(), xtrmapskip();
115
116 vprintf(stdout, "Verify tape and initialize maps\n");
e9e7ecc4 117#ifdef RRESTORE
f78e116c
KM
118 if ((mt = rmtopen(magtape, 0)) < 0)
119#else
2cb5dabb
KM
120 if (pipein)
121 mt = 0;
122 else if ((mt = open(magtape, 0)) < 0)
f78e116c
KM
123#endif
124 {
e9e7ecc4 125 perror(magtape);
f78e116c
KM
126 done(1);
127 }
768eb687
KM
128 volno = 1;
129 setdumpnum();
f78e116c 130 flsht();
b97e998a
KM
131 if (!pipein && !bflag)
132 findtapeblksize();
5c5f44c7 133 if (gethead(&spcl) == FAIL) {
f78e116c
KM
134 bct--; /* push back this block */
135 cvtflag++;
5c5f44c7 136 if (gethead(&spcl) == FAIL) {
f78e116c
KM
137 fprintf(stderr, "Tape is not a dump tape\n");
138 done(1);
139 }
140 fprintf(stderr, "Converting to new file system format.\n");
141 }
2cb5dabb
KM
142 if (pipein) {
143 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
144 endoftapemark.s_spcl.c_type = TS_END;
145 ip = (int *)&endoftapemark;
146 j = sizeof(union u_spcl) / sizeof(int);
147 i = 0;
148 do
149 i += *ip++;
150 while (--j);
151 endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
152 }
b32320ae
KM
153 if (vflag || command == 't')
154 printdumpinfo();
f78e116c 155 dumptime = spcl.c_ddate;
2cb5dabb 156 dumpdate = spcl.c_date;
f78e116c 157 if (stat(".", &stbuf) < 0) {
e9e7ecc4 158 perror("cannot stat .");
f78e116c
KM
159 done(1);
160 }
bdeceadb
KM
161 if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
162 fssize = stbuf.st_blksize;
163 if (((fssize - 1) & fssize) != 0) {
f78e116c
KM
164 fprintf(stderr, "bad block size %d\n", fssize);
165 done(1);
166 }
2cb5dabb 167 if (checkvol(&spcl, (long)1) == FAIL) {
f78e116c
KM
168 fprintf(stderr, "Tape is not volume 1 of the dump\n");
169 done(1);
170 }
2cb5dabb
KM
171 if (readhdr(&spcl) == FAIL)
172 panic("no header after volume mark!\n");
b32320ae 173 findinode(&spcl);
2cb5dabb 174 if (checktype(&spcl, TS_CLRI) == FAIL) {
f78e116c
KM
175 fprintf(stderr, "Cannot find file removal list\n");
176 done(1);
177 }
2cb5dabb 178 maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
768eb687 179 dprintf(stdout, "maxino = %d\n", maxino);
7851e15d 180 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
f78e116c
KM
181 if (map == (char *)NIL)
182 panic("no memory for file removal list\n");
cf6db0ab 183 clrimap = map;
f78e116c
KM
184 curfile.action = USING;
185 getfile(xtrmap, xtrmapskip);
2cb5dabb 186 if (checktype(&spcl, TS_BITS) == FAIL) {
f78e116c
KM
187 fprintf(stderr, "Cannot find file dump list\n");
188 done(1);
189 }
7851e15d 190 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
f78e116c
KM
191 if (map == (char *)NULL)
192 panic("no memory for file dump list\n");
cf6db0ab 193 dumpmap = map;
f78e116c
KM
194 curfile.action = USING;
195 getfile(xtrmap, xtrmapskip);
f78e116c
KM
196}
197
170639fd
KM
198/*
199 * Prompt user to load a new dump volume.
200 * "Nextvol" is the next suggested volume to use.
201 * This suggested volume is enforced when doing full
202 * or incremental restores, but can be overrridden by
203 * the user when only extracting a subset of the files.
204 */
f78e116c
KM
205getvol(nextvol)
206 long nextvol;
207{
208 long newvol;
170639fd 209 long savecnt, i;
f78e116c
KM
210 union u_spcl tmpspcl;
211# define tmpbuf tmpspcl.s_spcl
b32320ae 212 char buf[TP_BSIZE];
cb2a63da 213 extern char *ctime();
f78e116c 214
a162cc0b 215 if (nextvol == 1) {
170639fd 216 tapesread = 0;
a162cc0b
KM
217 gettingfile = 0;
218 }
2cb5dabb 219 if (pipein) {
e108d3a2 220 if (nextvol != 1)
2cb5dabb 221 panic("Changing volumes on pipe input?\n");
e108d3a2
KM
222 if (volno == 1)
223 return;
224 goto gethdr;
2cb5dabb
KM
225 }
226 savecnt = blksread;
f78e116c 227again:
e108d3a2
KM
228 if (pipein)
229 done(1); /* pipes do not get a second chance */
f78e116c
KM
230 if (command == 'R' || command == 'r' || curfile.action != SKIP)
231 newvol = nextvol;
232 else
233 newvol = 0;
234 while (newvol <= 0) {
170639fd
KM
235 if (tapesread == 0) {
236 fprintf(stderr, "%s%s%s%s%s",
237 "You have not read any tapes yet.\n",
238 "Unless you know which volume your",
239 " file(s) are on you should start\n",
240 "with the last volume and work",
b4c41341 241 " towards towards the first.\n");
170639fd
KM
242 } else {
243 fprintf(stderr, "You have read volumes");
244 strcpy(tbf, ": ");
245 for (i = 1; i < 32; i++)
246 if (tapesread & (1 << i)) {
247 fprintf(stderr, "%s%d", tbf, i);
248 strcpy(tbf, ", ");
249 }
250 fprintf(stderr, "\n");
251 }
538cb7bb 252 do {
b677c5d7
KM
253 fprintf(stderr, "Specify next volume #: ");
254 (void) fflush(stderr);
255 (void) fgets(tbf, BUFSIZ, terminal);
256 } while (!feof(terminal) && tbf[0] == '\n');
257 if (feof(terminal))
538cb7bb 258 done(1);
f78e116c
KM
259 newvol = atoi(tbf);
260 if (newvol <= 0) {
261 fprintf(stderr,
262 "Volume numbers are positive numerics\n");
263 }
264 }
170639fd
KM
265 if (newvol == volno) {
266 tapesread |= 1 << volno;
f78e116c 267 return;
170639fd 268 }
f78e116c 269 closemt();
7eb08dfe
KM
270 fprintf(stderr, "Mount tape volume %d\n", newvol);
271 fprintf(stderr, "then enter tape name (default: %s) ", magtape);
b677c5d7 272 (void) fflush(stderr);
7eb08dfe
KM
273 (void) fgets(tbf, BUFSIZ, terminal);
274 if (feof(terminal))
275 done(1);
276 if (tbf[0] != '\n') {
277 (void) strcpy(magtape, tbf);
278 magtape[strlen(magtape) - 1] = '\0';
279 }
e9e7ecc4 280#ifdef RRESTORE
f78e116c
KM
281 if ((mt = rmtopen(magtape, 0)) == -1)
282#else
283 if ((mt = open(magtape, 0)) == -1)
284#endif
285 {
7eb08dfe
KM
286 fprintf(stderr, "Cannot open %s\n", magtape);
287 volno = -1;
f78e116c
KM
288 goto again;
289 }
e108d3a2 290gethdr:
f78e116c 291 volno = newvol;
768eb687 292 setdumpnum();
f78e116c 293 flsht();
2cb5dabb 294 if (readhdr(&tmpbuf) == FAIL) {
f78e116c
KM
295 fprintf(stderr, "tape is not dump tape\n");
296 volno = 0;
297 goto again;
298 }
2cb5dabb 299 if (checkvol(&tmpbuf, volno) == FAIL) {
f78e116c
KM
300 fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
301 volno = 0;
302 goto again;
303 }
2cb5dabb 304 if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
3dbddecd
KM
305 fprintf(stderr, "Wrong dump date\n\tgot: %s",
306 ctime(&tmpbuf.c_date));
307 fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
2cb5dabb
KM
308 volno = 0;
309 goto again;
310 }
170639fd 311 tapesread |= 1 << volno;
5c5f44c7 312 blksread = savecnt;
f78e116c
KM
313 if (curfile.action == USING) {
314 if (volno == 1)
315 panic("active file into volume 1\n");
316 return;
317 }
b32320ae
KM
318 /*
319 * Skip up to the beginning of the next record
320 */
8d412b7c 321 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
b32320ae
KM
322 for (i = tmpbuf.c_count; i > 0; i--)
323 readtape(buf);
5c5f44c7 324 (void) gethead(&spcl);
b32320ae 325 findinode(&spcl);
f78e116c
KM
326 if (gettingfile) {
327 gettingfile = 0;
328 longjmp(restart, 1);
329 }
330}
331
768eb687
KM
332/*
333 * handle multiple dumps per tape by skipping forward to the
334 * appropriate one.
335 */
336setdumpnum()
337{
338 struct mtop tcom;
339
340 if (dumpnum == 1 || volno != 1)
341 return;
342 if (pipein) {
343 fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
344 done(1);
345 }
346 tcom.mt_op = MTFSF;
347 tcom.mt_count = dumpnum - 1;
e9e7ecc4 348#ifdef RRESTORE
768eb687
KM
349 rmtioctl(MTFSF, dumpnum - 1);
350#else
538cb7bb 351 if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
768eb687
KM
352 perror("ioctl MTFSF");
353#endif
354}
355
b32320ae
KM
356printdumpinfo()
357{
cb2a63da 358 extern char *ctime();
b32320ae
KM
359
360 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date));
f441de4a
KM
361 fprintf(stdout, "Dumped from: %s",
362 (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
b32320ae
KM
363 if (spcl.c_host[0] == '\0')
364 return;
365 fprintf(stderr, "Level %d dump of %s on %s:%s\n",
366 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
367 fprintf(stderr, "Label: %s\n", spcl.c_label);
368}
369
f78e116c
KM
370extractfile(name)
371 char *name;
372{
373 int mode;
374 time_t timep[2];
375 struct entry *ep;
376 extern int xtrlnkfile(), xtrlnkskip();
377 extern int xtrfile(), xtrskip();
378
379 curfile.name = name;
380 curfile.action = USING;
381 timep[0] = curfile.dip->di_atime;
382 timep[1] = curfile.dip->di_mtime;
383 mode = curfile.dip->di_mode;
384 switch (mode & IFMT) {
385
386 default:
387 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
388 skipfile();
389 return (FAIL);
390
74e940f5
KM
391 case IFSOCK:
392 vprintf(stdout, "skipped socket %s\n", name);
393 skipfile();
394 return (GOOD);
395
f78e116c
KM
396 case IFDIR:
397 if (mflag) {
398 ep = lookupname(name);
399 if (ep == NIL || ep->e_flags & EXTRACT)
400 panic("unextracted directory %s\n", name);
401 skipfile();
402 return (GOOD);
403 }
404 vprintf(stdout, "extract file %s\n", name);
405 return (genliteraldir(name, curfile.ino));
406
407 case IFLNK:
408 lnkbuf[0] = '\0';
409 pathlen = 0;
410 getfile(xtrlnkfile, xtrlnkskip);
411 if (pathlen == 0) {
412 vprintf(stdout,
413 "%s: zero length symbolic link (ignored)\n", name);
bdeceadb
KM
414 return (GOOD);
415 }
416 return (linkit(lnkbuf, name, SYMLINK));
f78e116c
KM
417
418 case IFCHR:
419 case IFBLK:
420 vprintf(stdout, "extract special file %s\n", name);
414c4f09
KM
421 if (Nflag) {
422 skipfile();
423 return (GOOD);
424 }
f78e116c 425 if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
e9e7ecc4
KM
426 fprintf(stderr, "%s: ", name);
427 (void) fflush(stderr);
428 perror("cannot create special file");
f78e116c
KM
429 skipfile();
430 return (FAIL);
431 }
768eb687
KM
432 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
433 (void) chmod(name, mode);
f78e116c
KM
434 skipfile();
435 utime(name, timep);
436 return (GOOD);
437
438 case IFREG:
439 vprintf(stdout, "extract file %s\n", name);
414c4f09
KM
440 if (Nflag) {
441 skipfile();
442 return (GOOD);
443 }
15aeb519 444 if ((ofile = creat(name, 0666)) < 0) {
e9e7ecc4
KM
445 fprintf(stderr, "%s: ", name);
446 (void) fflush(stderr);
447 perror("cannot create file");
f78e116c
KM
448 skipfile();
449 return (FAIL);
450 }
768eb687
KM
451 (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
452 (void) fchmod(ofile, mode);
f78e116c 453 getfile(xtrfile, xtrskip);
768eb687 454 (void) close(ofile);
f78e116c
KM
455 utime(name, timep);
456 return (GOOD);
457 }
458 /* NOTREACHED */
459}
460
e108d3a2
KM
461/*
462 * skip over bit maps on the tape
463 */
464skipmaps()
465{
466
467 while (checktype(&spcl, TS_CLRI) == GOOD ||
468 checktype(&spcl, TS_BITS) == GOOD)
469 skipfile();
470}
471
472/*
473 * skip over a file on the tape
474 */
f78e116c
KM
475skipfile()
476{
477 extern int null();
478
479 curfile.action = SKIP;
480 getfile(null, null);
481}
482
483/*
484 * Do the file extraction, calling the supplied functions
485 * with the blocks
486 */
487getfile(f1, f2)
488 int (*f2)(), (*f1)();
489{
490 register int i;
491 int curblk = 0;
492 off_t size = spcl.c_dinode.di_size;
493 static char clearedbuf[MAXBSIZE];
494 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
4f8ea093 495 char junk[TP_BSIZE];
f78e116c 496
2cb5dabb 497 if (checktype(&spcl, TS_END) == GOOD)
f78e116c 498 panic("ran off end of tape\n");
e108d3a2 499 if (ishead(&spcl) == FAIL)
f78e116c 500 panic("not at beginning of a file\n");
e108d3a2 501 if (!gettingfile && setjmp(restart) != 0)
f78e116c
KM
502 return;
503 gettingfile++;
504loop:
505 for (i = 0; i < spcl.c_count; i++) {
506 if (spcl.c_addr[i]) {
507 readtape(&buf[curblk++][0]);
508 if (curblk == fssize / TP_BSIZE) {
509 (*f1)(buf, size > TP_BSIZE ?
510 (long) (fssize) :
511 (curblk - 1) * TP_BSIZE + size);
512 curblk = 0;
513 }
514 } else {
515 if (curblk > 0) {
516 (*f1)(buf, size > TP_BSIZE ?
517 (long) (curblk * TP_BSIZE) :
518 (curblk - 1) * TP_BSIZE + size);
519 curblk = 0;
520 }
521 (*f2)(clearedbuf, size > TP_BSIZE ?
522 (long) TP_BSIZE : size);
523 }
4f8ea093
KM
524 if ((size -= TP_BSIZE) <= 0) {
525 for (i++; i < spcl.c_count; i++)
526 if (spcl.c_addr[i])
527 readtape(junk);
9f13f26d 528 break;
4f8ea093 529 }
f78e116c 530 }
5c5f44c7 531 if (readhdr(&spcl) == GOOD && size > 0) {
9f13f26d
KM
532 if (checktype(&spcl, TS_ADDR) == GOOD)
533 goto loop;
768eb687 534 dprintf(stdout, "Missing address (header) block for %s\n",
f78e116c 535 curfile.name);
f78e116c 536 }
9f13f26d 537 if (curblk > 0)
f78e116c 538 (*f1)(buf, (curblk * TP_BSIZE) + size);
b32320ae 539 findinode(&spcl);
f78e116c
KM
540 gettingfile = 0;
541}
542
543/*
544 * The next routines are called during file extraction to
545 * put the data into the right form and place.
546 */
547xtrfile(buf, size)
548 char *buf;
549 long size;
550{
551
414c4f09
KM
552 if (Nflag)
553 return;
f78e116c
KM
554 if (write(ofile, buf, (int) size) == -1) {
555 fprintf(stderr, "write error extracting inode %d, name %s\n",
556 curfile.ino, curfile.name);
557 perror("write");
558 done(1);
559 }
560}
561
562xtrskip(buf, size)
563 char *buf;
564 long size;
565{
566
567#ifdef lint
568 buf = buf;
569#endif
570 if (lseek(ofile, size, 1) == (long)-1) {
571 fprintf(stderr, "seek error extracting inode %d, name %s\n",
572 curfile.ino, curfile.name);
573 perror("lseek");
574 done(1);
575 }
576}
577
578xtrlnkfile(buf, size)
579 char *buf;
580 long size;
581{
582
583 pathlen += size;
584 if (pathlen > MAXPATHLEN) {
585 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
586 curfile.name, lnkbuf, buf, pathlen);
587 done(1);
588 }
538cb7bb 589 (void) strcat(lnkbuf, buf);
f78e116c
KM
590}
591
592xtrlnkskip(buf, size)
593 char *buf;
594 long size;
595{
596
597#ifdef lint
598 buf = buf, size = size;
599#endif
600 fprintf(stderr, "unallocated block in symbolic link %s\n",
601 curfile.name);
602 done(1);
603}
604
605xtrmap(buf, size)
606 char *buf;
607 long size;
608{
609
610 bcopy(buf, map, size);
cf6db0ab 611 map += size;
f78e116c
KM
612}
613
614xtrmapskip(buf, size)
615 char *buf;
616 long size;
617{
618
619#ifdef lint
620 buf = buf;
f78e116c
KM
621#endif
622 panic("hole in map\n");
cf6db0ab 623 map += size;
f78e116c
KM
624}
625
626null() {;}
627
628/*
629 * Do the tape i/o, dealing with volume changes
630 * etc..
631 */
632readtape(b)
633 char *b;
634{
635 register long i;
7851e15d
KM
636 long rd, newvol;
637 int cnt;
f78e116c 638
b97e998a
KM
639 if (bct < ntrec) {
640 bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
641 blksread++;
642 return;
643 }
644 for (i = 0; i < ntrec; i++)
645 ((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
646 bct = 0;
647 cnt = ntrec*TP_BSIZE;
648 rd = 0;
649getmore:
e9e7ecc4 650#ifdef RRESTORE
b97e998a 651 i = rmtread(&tbf[rd], cnt);
f78e116c 652#else
b97e998a 653 i = read(mt, &tbf[rd], cnt);
f78e116c 654#endif
b97e998a
KM
655 if (i > 0 && i != ntrec*TP_BSIZE) {
656 if (pipein) {
74025ab9
KM
657 rd += i;
658 cnt -= i;
659 if (cnt > 0)
660 goto getmore;
661 i = rd;
b97e998a
KM
662 } else {
663 if (i % TP_BSIZE != 0)
664 panic("partial block read: %d should be %d\n",
665 i, ntrec * TP_BSIZE);
666 bcopy((char *)&endoftapemark, &tbf[i],
667 (long)TP_BSIZE);
74025ab9 668 }
b97e998a
KM
669 }
670 if (i < 0) {
671 fprintf(stderr, "Tape read error while ");
672 switch (curfile.action) {
673 default:
674 fprintf(stderr, "trying to set up tape\n");
675 break;
676 case UNKNOWN:
bf7abb47 677 fprintf(stderr, "trying to resynchronize\n");
b97e998a
KM
678 break;
679 case USING:
680 fprintf(stderr, "restoring %s\n", curfile.name);
681 break;
682 case SKIP:
683 fprintf(stderr, "skipping over inode %d\n",
684 curfile.ino);
685 break;
686 }
687 if (!yflag && !reply("continue"))
688 done(1);
689 i = ntrec*TP_BSIZE;
690 bzero(tbf, i);
e9e7ecc4 691#ifdef RRESTORE
b97e998a 692 if (rmtseek(i, 1) < 0)
f78e116c 693#else
b97e998a 694 if (lseek(mt, i, 1) == (long)-1)
f78e116c 695#endif
b97e998a
KM
696 {
697 perror("continuation failed");
698 done(1);
f78e116c 699 }
b97e998a
KM
700 }
701 if (i == 0) {
ad073f89
KM
702 if (!pipein) {
703 newvol = volno + 1;
704 volno = 0;
705 getvol(newvol);
706 readtape(b);
f78e116c
KM
707 return;
708 }
ad073f89
KM
709 if (rd % TP_BSIZE != 0)
710 panic("partial block read: %d should be %d\n",
711 rd, ntrec * TP_BSIZE);
712 bcopy((char *)&endoftapemark, &tbf[rd], (long)TP_BSIZE);
f78e116c
KM
713 }
714 bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
2cb5dabb 715 blksread++;
f78e116c
KM
716}
717
b97e998a
KM
718findtapeblksize()
719{
720 register long i;
721
722 for (i = 0; i < ntrec; i++)
723 ((struct s_spcl *)&tbf[i * TP_BSIZE])->c_magic = 0;
724 bct = 0;
725#ifdef RRESTORE
726 i = rmtread(tbf, ntrec * TP_BSIZE);
727#else
728 i = read(mt, tbf, ntrec * TP_BSIZE);
729#endif
730 if (i <= 0) {
731 perror("Tape read error");
732 done(1);
733 }
734 if (i % TP_BSIZE != 0) {
735 fprintf(stderr, "Tape block size (%d) %s (%d)\n",
736 i, "is not a multiple of dump block size", TP_BSIZE);
737 done(1);
738 }
739 ntrec = i / TP_BSIZE;
740 vprintf(stdout, "Tape block size is %d\n", ntrec);
741}
742
f78e116c
KM
743flsht()
744{
745
19230a53 746 bct = ntrec+1;
f78e116c
KM
747}
748
f78e116c
KM
749closemt()
750{
751 if (mt < 0)
752 return;
e9e7ecc4 753#ifdef RRESTORE
f78e116c
KM
754 rmtclose();
755#else
768eb687 756 (void) close(mt);
f78e116c
KM
757#endif
758}
759
760checkvol(b, t)
761 struct s_spcl *b;
762 long t;
763{
764
2cb5dabb
KM
765 if (b->c_volume != t)
766 return(FAIL);
767 return(GOOD);
f78e116c
KM
768}
769
770readhdr(b)
771 struct s_spcl *b;
772{
773
5c5f44c7 774 if (gethead(b) == FAIL) {
768eb687 775 dprintf(stdout, "readhdr fails at %d blocks\n", blksread);
2cb5dabb 776 return(FAIL);
5c5f44c7 777 }
2cb5dabb 778 return(GOOD);
f78e116c
KM
779}
780
781/*
782 * read the tape into buf, then return whether or
783 * or not it is a header block.
784 */
785gethead(buf)
786 struct s_spcl *buf;
787{
b4c41341 788 long i, *j;
f78e116c
KM
789 union u_ospcl {
790 char dummy[TP_BSIZE];
791 struct s_ospcl {
2cb5dabb
KM
792 long c_type;
793 long c_date;
794 long c_ddate;
795 long c_volume;
796 long c_tapea;
cf6db0ab 797 u_short c_inumber;
2cb5dabb
KM
798 long c_magic;
799 long c_checksum;
f78e116c
KM
800 struct odinode {
801 unsigned short odi_mode;
cf6db0ab
KM
802 u_short odi_nlink;
803 u_short odi_uid;
804 u_short odi_gid;
2cb5dabb
KM
805 long odi_size;
806 long odi_rdev;
f78e116c 807 char odi_addr[36];
2cb5dabb
KM
808 long odi_atime;
809 long odi_mtime;
810 long odi_ctime;
f78e116c 811 } c_dinode;
2cb5dabb
KM
812 long c_count;
813 char c_addr[256];
f78e116c
KM
814 } s_ospcl;
815 } u_ospcl;
816
817 if (!cvtflag) {
818 readtape((char *)buf);
b4c41341
KS
819 if (buf->c_magic != NFS_MAGIC) {
820 if (swabl(buf->c_magic) != NFS_MAGIC)
821 return (FAIL);
822 if (!Bcvt) {
823 vprintf(stdout, "Note: Doing Byte swapping\n");
824 Bcvt = 1;
825 }
826 }
827 if (checksum((int *)buf) == FAIL)
828 return (FAIL);
829 if (Bcvt)
830 swabst("8l4s31l", (char *)buf);
5c5f44c7 831 goto good;
f78e116c
KM
832 }
833 readtape((char *)(&u_ospcl.s_ospcl));
834 bzero((char *)buf, (long)TP_BSIZE);
835 buf->c_type = u_ospcl.s_ospcl.c_type;
836 buf->c_date = u_ospcl.s_ospcl.c_date;
837 buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
838 buf->c_volume = u_ospcl.s_ospcl.c_volume;
839 buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
840 buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
841 buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
842 buf->c_magic = u_ospcl.s_ospcl.c_magic;
843 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
844 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
845 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
846 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
847 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
848 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
849 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
850 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
851 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
852 buf->c_count = u_ospcl.s_ospcl.c_count;
2cb5dabb 853 bcopy(u_ospcl.s_ospcl.c_addr, buf->c_addr, (long)256);
f78e116c 854 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
5c5f44c7 855 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
2cb5dabb 856 return(FAIL);
f78e116c 857 buf->c_magic = NFS_MAGIC;
5c5f44c7
KM
858
859good:
b4c41341
KS
860 j = buf->c_dinode.di_ic.ic_size.val;
861 i = j[1];
862 if (buf->c_dinode.di_size == 0 &&
863 (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt==0) {
864 if (*j || i) {
865 printf("Note: Doing Quad swapping\n");
866 Qcvt = 1;
867 }
868 }
869 if (Qcvt) {
870 j[1] = *j; *j = i;
871 }
5c5f44c7
KM
872 switch (buf->c_type) {
873
874 case TS_CLRI:
875 case TS_BITS:
876 /*
877 * Have to patch up missing information in bit map headers
878 */
879 buf->c_inumber = 0;
880 buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
881 for (i = 0; i < buf->c_count; i++)
882 buf->c_addr[i]++;
883 break;
884
885 case TS_TAPE:
886 case TS_END:
887 buf->c_inumber = 0;
888 break;
889
890 case TS_INODE:
891 case TS_ADDR:
892 break;
893
894 default:
895 panic("gethead: unknown inode type %d\n", buf->c_type);
896 break;
897 }
2cb5dabb
KM
898 if (dflag)
899 accthdr(buf);
900 return(GOOD);
901}
902
903/*
904 * Check that a header is where it belongs and predict the next header
905 */
906accthdr(header)
907 struct s_spcl *header;
908{
7851e15d 909 static ino_t previno = 0x7fffffff;
2cb5dabb
KM
910 static int prevtype;
911 static long predict;
912 long blks, i;
913
8d412b7c 914 if (header->c_type == TS_TAPE) {
5c5f44c7 915 fprintf(stderr, "Volume header\n");
b8f4e820 916 previno = 0x7fffffff;
5c5f44c7
KM
917 return;
918 }
7851e15d 919 if (previno == 0x7fffffff)
2cb5dabb
KM
920 goto newcalc;
921 switch (prevtype) {
2cb5dabb 922 case TS_BITS:
5c5f44c7 923 fprintf(stderr, "Dump mask header");
2cb5dabb
KM
924 break;
925 case TS_CLRI:
5c5f44c7 926 fprintf(stderr, "Remove mask header");
2cb5dabb
KM
927 break;
928 case TS_INODE:
5c5f44c7 929 fprintf(stderr, "File header, ino %d", previno);
2cb5dabb
KM
930 break;
931 case TS_ADDR:
5c5f44c7 932 fprintf(stderr, "File continuation header, ino %d", previno);
2cb5dabb
KM
933 break;
934 case TS_END:
5c5f44c7 935 fprintf(stderr, "End of tape header");
2cb5dabb
KM
936 break;
937 }
2cb5dabb
KM
938 if (predict != blksread - 1)
939 fprintf(stderr, "; predicted %d blocks, got %d blocks",
940 predict, blksread - 1);
941 fprintf(stderr, "\n");
942newcalc:
943 blks = 0;
5c5f44c7 944 if (header->c_type != TS_END)
2cb5dabb
KM
945 for (i = 0; i < header->c_count; i++)
946 if (header->c_addr[i] != 0)
947 blks++;
948 predict = blks;
949 blksread = 0;
950 prevtype = header->c_type;
951 previno = header->c_inumber;
f78e116c
KM
952}
953
954/*
955 * Find an inode header.
956 * Complain if had to skip, and complain is set.
957 */
b32320ae 958findinode(header)
f78e116c 959 struct s_spcl *header;
f78e116c 960{
2cb5dabb 961 static long skipcnt = 0;
b8f4e820
KM
962 long i;
963 char buf[TP_BSIZE];
f78e116c
KM
964
965 curfile.name = "<name unknown>";
966 curfile.action = UNKNOWN;
967 curfile.dip = (struct dinode *)NIL;
968 curfile.ino = 0;
2cb5dabb
KM
969 if (ishead(header) == FAIL) {
970 skipcnt++;
7702e9a8 971 while (gethead(header) == FAIL || header->c_date != dumpdate)
f78e116c 972 skipcnt++;
2cb5dabb 973 }
f78e116c 974 for (;;) {
b8f4e820
KM
975 if (checktype(header, TS_ADDR) == GOOD) {
976 /*
977 * Skip up to the beginning of the next record
978 */
979 for (i = 0; i < header->c_count; i++)
980 if (header->c_addr[i])
981 readtape(buf);
982 (void) gethead(header);
983 continue;
984 }
2cb5dabb 985 if (checktype(header, TS_INODE) == GOOD) {
f78e116c
KM
986 curfile.dip = &header->c_dinode;
987 curfile.ino = header->c_inumber;
988 break;
989 }
2cb5dabb 990 if (checktype(header, TS_END) == GOOD) {
f78e116c
KM
991 curfile.ino = maxino;
992 break;
993 }
2cb5dabb 994 if (checktype(header, TS_CLRI) == GOOD) {
f78e116c 995 curfile.name = "<file removal list>";
e108d3a2 996 break;
f78e116c 997 }
2cb5dabb 998 if (checktype(header, TS_BITS) == GOOD) {
f78e116c 999 curfile.name = "<file dump list>";
e108d3a2 1000 break;
f78e116c 1001 }
2cb5dabb 1002 while (gethead(header) == FAIL)
f78e116c
KM
1003 skipcnt++;
1004 }
b32320ae 1005 if (skipcnt > 0)
dd1900f1 1006 fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
f78e116c
KM
1007 skipcnt = 0;
1008}
1009
1010/*
1011 * return whether or not the buffer contains a header block
1012 */
1013ishead(buf)
1014 struct s_spcl *buf;
1015{
1016
1017 if (buf->c_magic != NFS_MAGIC)
2cb5dabb
KM
1018 return(FAIL);
1019 return(GOOD);
f78e116c
KM
1020}
1021
1022checktype(b, t)
1023 struct s_spcl *b;
1024 int t;
1025{
1026
2cb5dabb
KM
1027 if (b->c_type != t)
1028 return(FAIL);
1029 return(GOOD);
f78e116c
KM
1030}
1031
1032checksum(b)
1033 register int *b;
1034{
1035 register int i, j;
1036
1037 j = sizeof(union u_spcl) / sizeof(int);
1038 i = 0;
b4c41341
KS
1039 if(!Bcvt) {
1040 do
1041 i += *b++;
1042 while (--j);
1043 } else {
1044 /* What happens if we want to read restore tapes
1045 for a 16bit int machine??? */
1046 do
1047 i += swabl(*b++);
1048 while (--j);
1049 }
1050
f78e116c
KM
1051 if (i != CHECKSUM) {
1052 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1053 curfile.ino, curfile.name);
2cb5dabb 1054 return(FAIL);
f78e116c 1055 }
2cb5dabb 1056 return(GOOD);
f78e116c
KM
1057}
1058
e9e7ecc4 1059#ifdef RRESTORE
74025ab9 1060/* VARARGS1 */
f78e116c
KM
1061msg(cp, a1, a2, a3)
1062 char *cp;
1063{
1064
1065 fprintf(stderr, cp, a1, a2, a3);
1066}
e9e7ecc4 1067#endif RRESTORE
b4c41341
KS
1068
1069swabst(cp, sp)
1070register char *cp, *sp;
1071{
1072 int n = 0;
1073 char c;
1074 while(*cp) {
1075 switch (*cp) {
1076 case '0': case '1': case '2': case '3': case '4':
1077 case '5': case '6': case '7': case '8': case '9':
1078 n = (n * 10) + (*cp++ - '0');
1079 continue;
1080
1081 case 's': case 'w': case 'h':
1082 c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1083 sp++;
1084 break;
1085
1086 case 'l':
1087 c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1088 c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1089 sp += 3;
1090 }
1091 sp++; /* Any other character, like 'b' counts as byte. */
1092 if (n <= 1) {
1093 n = 0; cp++;
1094 } else
1095 n--;
1096 }
1097}
1098swabl(x) { unsigned long l = x; swabst("l", (char *)&l); return l; }