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