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