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