modern syntax for asgops and inits; sccs keywords
[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
8d412b7c 8static char sccsid[] = "@(#)tape.c 5.10 (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 }
b32320ae
KM
154 if (vflag || command == 't')
155 printdumpinfo();
f78e116c 156 dumptime = spcl.c_ddate;
2cb5dabb 157 dumpdate = spcl.c_date;
f78e116c 158 if (stat(".", &stbuf) < 0) {
e9e7ecc4 159 perror("cannot stat .");
f78e116c
KM
160 done(1);
161 }
bdeceadb
KM
162 if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
163 fssize = stbuf.st_blksize;
164 if (((fssize - 1) & fssize) != 0) {
f78e116c
KM
165 fprintf(stderr, "bad block size %d\n", fssize);
166 done(1);
167 }
2cb5dabb 168 if (checkvol(&spcl, (long)1) == FAIL) {
f78e116c
KM
169 fprintf(stderr, "Tape is not volume 1 of the dump\n");
170 done(1);
171 }
2cb5dabb
KM
172 if (readhdr(&spcl) == FAIL)
173 panic("no header after volume mark!\n");
b32320ae 174 findinode(&spcl);
2cb5dabb 175 if (checktype(&spcl, TS_CLRI) == FAIL) {
f78e116c
KM
176 fprintf(stderr, "Cannot find file removal list\n");
177 done(1);
178 }
2cb5dabb 179 maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
768eb687 180 dprintf(stdout, "maxino = %d\n", maxino);
7851e15d 181 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
f78e116c
KM
182 if (map == (char *)NIL)
183 panic("no memory for file removal list\n");
cf6db0ab 184 clrimap = map;
f78e116c
KM
185 curfile.action = USING;
186 getfile(xtrmap, xtrmapskip);
2cb5dabb 187 if (checktype(&spcl, TS_BITS) == FAIL) {
f78e116c
KM
188 fprintf(stderr, "Cannot find file dump list\n");
189 done(1);
190 }
7851e15d 191 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
f78e116c
KM
192 if (map == (char *)NULL)
193 panic("no memory for file dump list\n");
cf6db0ab 194 dumpmap = map;
f78e116c
KM
195 curfile.action = USING;
196 getfile(xtrmap, xtrmapskip);
f78e116c
KM
197}
198
170639fd
KM
199/*
200 * Prompt user to load a new dump volume.
201 * "Nextvol" is the next suggested volume to use.
202 * This suggested volume is enforced when doing full
203 * or incremental restores, but can be overrridden by
204 * the user when only extracting a subset of the files.
205 */
f78e116c
KM
206getvol(nextvol)
207 long nextvol;
208{
209 long newvol;
170639fd 210 long savecnt, i;
f78e116c
KM
211 union u_spcl tmpspcl;
212# define tmpbuf tmpspcl.s_spcl
b32320ae 213 char buf[TP_BSIZE];
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{
358
359 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date));
360 fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
361 if (spcl.c_host[0] == '\0')
362 return;
363 fprintf(stderr, "Level %d dump of %s on %s:%s\n",
364 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
365 fprintf(stderr, "Label: %s\n", spcl.c_label);
366}
367
f78e116c
KM
368extractfile(name)
369 char *name;
370{
371 int mode;
372 time_t timep[2];
373 struct entry *ep;
374 extern int xtrlnkfile(), xtrlnkskip();
375 extern int xtrfile(), xtrskip();
376
377 curfile.name = name;
378 curfile.action = USING;
379 timep[0] = curfile.dip->di_atime;
380 timep[1] = curfile.dip->di_mtime;
381 mode = curfile.dip->di_mode;
382 switch (mode & IFMT) {
383
384 default:
385 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
386 skipfile();
387 return (FAIL);
388
74e940f5
KM
389 case IFSOCK:
390 vprintf(stdout, "skipped socket %s\n", name);
391 skipfile();
392 return (GOOD);
393
f78e116c
KM
394 case IFDIR:
395 if (mflag) {
396 ep = lookupname(name);
397 if (ep == NIL || ep->e_flags & EXTRACT)
398 panic("unextracted directory %s\n", name);
399 skipfile();
400 return (GOOD);
401 }
402 vprintf(stdout, "extract file %s\n", name);
403 return (genliteraldir(name, curfile.ino));
404
405 case IFLNK:
406 lnkbuf[0] = '\0';
407 pathlen = 0;
408 getfile(xtrlnkfile, xtrlnkskip);
409 if (pathlen == 0) {
410 vprintf(stdout,
411 "%s: zero length symbolic link (ignored)\n", name);
bdeceadb
KM
412 return (GOOD);
413 }
414 return (linkit(lnkbuf, name, SYMLINK));
f78e116c
KM
415
416 case IFCHR:
417 case IFBLK:
418 vprintf(stdout, "extract special file %s\n", name);
419 if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
e9e7ecc4
KM
420 fprintf(stderr, "%s: ", name);
421 (void) fflush(stderr);
422 perror("cannot create special file");
f78e116c
KM
423 skipfile();
424 return (FAIL);
425 }
768eb687
KM
426 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
427 (void) chmod(name, mode);
f78e116c
KM
428 skipfile();
429 utime(name, timep);
430 return (GOOD);
431
432 case IFREG:
433 vprintf(stdout, "extract file %s\n", name);
15aeb519 434 if ((ofile = creat(name, 0666)) < 0) {
e9e7ecc4
KM
435 fprintf(stderr, "%s: ", name);
436 (void) fflush(stderr);
437 perror("cannot create file");
f78e116c
KM
438 skipfile();
439 return (FAIL);
440 }
768eb687
KM
441 (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
442 (void) fchmod(ofile, mode);
f78e116c 443 getfile(xtrfile, xtrskip);
768eb687 444 (void) close(ofile);
f78e116c
KM
445 utime(name, timep);
446 return (GOOD);
447 }
448 /* NOTREACHED */
449}
450
e108d3a2
KM
451/*
452 * skip over bit maps on the tape
453 */
454skipmaps()
455{
456
457 while (checktype(&spcl, TS_CLRI) == GOOD ||
458 checktype(&spcl, TS_BITS) == GOOD)
459 skipfile();
460}
461
462/*
463 * skip over a file on the tape
464 */
f78e116c
KM
465skipfile()
466{
467 extern int null();
468
469 curfile.action = SKIP;
470 getfile(null, null);
471}
472
473/*
474 * Do the file extraction, calling the supplied functions
475 * with the blocks
476 */
477getfile(f1, f2)
478 int (*f2)(), (*f1)();
479{
480 register int i;
481 int curblk = 0;
482 off_t size = spcl.c_dinode.di_size;
483 static char clearedbuf[MAXBSIZE];
484 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
4f8ea093 485 char junk[TP_BSIZE];
f78e116c 486
2cb5dabb 487 if (checktype(&spcl, TS_END) == GOOD)
f78e116c 488 panic("ran off end of tape\n");
e108d3a2 489 if (ishead(&spcl) == FAIL)
f78e116c 490 panic("not at beginning of a file\n");
e108d3a2 491 if (!gettingfile && setjmp(restart) != 0)
f78e116c
KM
492 return;
493 gettingfile++;
494loop:
495 for (i = 0; i < spcl.c_count; i++) {
496 if (spcl.c_addr[i]) {
497 readtape(&buf[curblk++][0]);
498 if (curblk == fssize / TP_BSIZE) {
499 (*f1)(buf, size > TP_BSIZE ?
500 (long) (fssize) :
501 (curblk - 1) * TP_BSIZE + size);
502 curblk = 0;
503 }
504 } else {
505 if (curblk > 0) {
506 (*f1)(buf, size > TP_BSIZE ?
507 (long) (curblk * TP_BSIZE) :
508 (curblk - 1) * TP_BSIZE + size);
509 curblk = 0;
510 }
511 (*f2)(clearedbuf, size > TP_BSIZE ?
512 (long) TP_BSIZE : size);
513 }
4f8ea093
KM
514 if ((size -= TP_BSIZE) <= 0) {
515 for (i++; i < spcl.c_count; i++)
516 if (spcl.c_addr[i])
517 readtape(junk);
9f13f26d 518 break;
4f8ea093 519 }
f78e116c 520 }
5c5f44c7 521 if (readhdr(&spcl) == GOOD && size > 0) {
9f13f26d
KM
522 if (checktype(&spcl, TS_ADDR) == GOOD)
523 goto loop;
768eb687 524 dprintf(stdout, "Missing address (header) block for %s\n",
f78e116c 525 curfile.name);
f78e116c 526 }
9f13f26d 527 if (curblk > 0)
f78e116c 528 (*f1)(buf, (curblk * TP_BSIZE) + size);
b32320ae 529 findinode(&spcl);
f78e116c
KM
530 gettingfile = 0;
531}
532
533/*
534 * The next routines are called during file extraction to
535 * put the data into the right form and place.
536 */
537xtrfile(buf, size)
538 char *buf;
539 long size;
540{
541
542 if (write(ofile, buf, (int) size) == -1) {
543 fprintf(stderr, "write error extracting inode %d, name %s\n",
544 curfile.ino, curfile.name);
545 perror("write");
546 done(1);
547 }
548}
549
550xtrskip(buf, size)
551 char *buf;
552 long size;
553{
554
555#ifdef lint
556 buf = buf;
557#endif
558 if (lseek(ofile, size, 1) == (long)-1) {
559 fprintf(stderr, "seek error extracting inode %d, name %s\n",
560 curfile.ino, curfile.name);
561 perror("lseek");
562 done(1);
563 }
564}
565
566xtrlnkfile(buf, size)
567 char *buf;
568 long size;
569{
570
571 pathlen += size;
572 if (pathlen > MAXPATHLEN) {
573 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
574 curfile.name, lnkbuf, buf, pathlen);
575 done(1);
576 }
538cb7bb 577 (void) strcat(lnkbuf, buf);
f78e116c
KM
578}
579
580xtrlnkskip(buf, size)
581 char *buf;
582 long size;
583{
584
585#ifdef lint
586 buf = buf, size = size;
587#endif
588 fprintf(stderr, "unallocated block in symbolic link %s\n",
589 curfile.name);
590 done(1);
591}
592
593xtrmap(buf, size)
594 char *buf;
595 long size;
596{
597
598 bcopy(buf, map, size);
cf6db0ab 599 map += size;
f78e116c
KM
600}
601
602xtrmapskip(buf, size)
603 char *buf;
604 long size;
605{
606
607#ifdef lint
608 buf = buf;
f78e116c
KM
609#endif
610 panic("hole in map\n");
cf6db0ab 611 map += size;
f78e116c
KM
612}
613
614null() {;}
615
616/*
617 * Do the tape i/o, dealing with volume changes
618 * etc..
619 */
620readtape(b)
621 char *b;
622{
623 register long i;
7851e15d
KM
624 long rd, newvol;
625 int cnt;
f78e116c 626
b97e998a
KM
627 if (bct < ntrec) {
628 bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
629 blksread++;
630 return;
631 }
632 for (i = 0; i < ntrec; i++)
633 ((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
634 bct = 0;
635 cnt = ntrec*TP_BSIZE;
636 rd = 0;
637getmore:
e9e7ecc4 638#ifdef RRESTORE
b97e998a 639 i = rmtread(&tbf[rd], cnt);
f78e116c 640#else
b97e998a 641 i = read(mt, &tbf[rd], cnt);
f78e116c 642#endif
b97e998a
KM
643 if (i > 0 && i != ntrec*TP_BSIZE) {
644 if (pipein) {
74025ab9
KM
645 rd += i;
646 cnt -= i;
647 if (cnt > 0)
648 goto getmore;
649 i = rd;
b97e998a
KM
650 } else {
651 if (i % TP_BSIZE != 0)
652 panic("partial block read: %d should be %d\n",
653 i, ntrec * TP_BSIZE);
654 bcopy((char *)&endoftapemark, &tbf[i],
655 (long)TP_BSIZE);
74025ab9 656 }
b97e998a
KM
657 }
658 if (i < 0) {
659 fprintf(stderr, "Tape read error while ");
660 switch (curfile.action) {
661 default:
662 fprintf(stderr, "trying to set up tape\n");
663 break;
664 case UNKNOWN:
665 fprintf(stderr, "trying to resyncronize\n");
666 break;
667 case USING:
668 fprintf(stderr, "restoring %s\n", curfile.name);
669 break;
670 case SKIP:
671 fprintf(stderr, "skipping over inode %d\n",
672 curfile.ino);
673 break;
674 }
675 if (!yflag && !reply("continue"))
676 done(1);
677 i = ntrec*TP_BSIZE;
678 bzero(tbf, i);
e9e7ecc4 679#ifdef RRESTORE
b97e998a 680 if (rmtseek(i, 1) < 0)
f78e116c 681#else
b97e998a 682 if (lseek(mt, i, 1) == (long)-1)
f78e116c 683#endif
b97e998a
KM
684 {
685 perror("continuation failed");
686 done(1);
f78e116c 687 }
b97e998a
KM
688 }
689 if (i == 0) {
ad073f89
KM
690 if (!pipein) {
691 newvol = volno + 1;
692 volno = 0;
693 getvol(newvol);
694 readtape(b);
f78e116c
KM
695 return;
696 }
ad073f89
KM
697 if (rd % TP_BSIZE != 0)
698 panic("partial block read: %d should be %d\n",
699 rd, ntrec * TP_BSIZE);
700 bcopy((char *)&endoftapemark, &tbf[rd], (long)TP_BSIZE);
f78e116c
KM
701 }
702 bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
2cb5dabb 703 blksread++;
f78e116c
KM
704}
705
b97e998a
KM
706findtapeblksize()
707{
708 register long i;
709
710 for (i = 0; i < ntrec; i++)
711 ((struct s_spcl *)&tbf[i * TP_BSIZE])->c_magic = 0;
712 bct = 0;
713#ifdef RRESTORE
714 i = rmtread(tbf, ntrec * TP_BSIZE);
715#else
716 i = read(mt, tbf, ntrec * TP_BSIZE);
717#endif
718 if (i <= 0) {
719 perror("Tape read error");
720 done(1);
721 }
722 if (i % TP_BSIZE != 0) {
723 fprintf(stderr, "Tape block size (%d) %s (%d)\n",
724 i, "is not a multiple of dump block size", TP_BSIZE);
725 done(1);
726 }
727 ntrec = i / TP_BSIZE;
728 vprintf(stdout, "Tape block size is %d\n", ntrec);
729}
730
f78e116c
KM
731flsht()
732{
733
19230a53 734 bct = ntrec+1;
f78e116c
KM
735}
736
f78e116c
KM
737closemt()
738{
739 if (mt < 0)
740 return;
e9e7ecc4 741#ifdef RRESTORE
f78e116c
KM
742 rmtclose();
743#else
768eb687 744 (void) close(mt);
f78e116c
KM
745#endif
746}
747
748checkvol(b, t)
749 struct s_spcl *b;
750 long t;
751{
752
2cb5dabb
KM
753 if (b->c_volume != t)
754 return(FAIL);
755 return(GOOD);
f78e116c
KM
756}
757
758readhdr(b)
759 struct s_spcl *b;
760{
761
5c5f44c7 762 if (gethead(b) == FAIL) {
768eb687 763 dprintf(stdout, "readhdr fails at %d blocks\n", blksread);
2cb5dabb 764 return(FAIL);
5c5f44c7 765 }
2cb5dabb 766 return(GOOD);
f78e116c
KM
767}
768
769/*
770 * read the tape into buf, then return whether or
771 * or not it is a header block.
772 */
773gethead(buf)
774 struct s_spcl *buf;
775{
b4c41341 776 long i, *j;
f78e116c
KM
777 union u_ospcl {
778 char dummy[TP_BSIZE];
779 struct s_ospcl {
2cb5dabb
KM
780 long c_type;
781 long c_date;
782 long c_ddate;
783 long c_volume;
784 long c_tapea;
cf6db0ab 785 u_short c_inumber;
2cb5dabb
KM
786 long c_magic;
787 long c_checksum;
f78e116c
KM
788 struct odinode {
789 unsigned short odi_mode;
cf6db0ab
KM
790 u_short odi_nlink;
791 u_short odi_uid;
792 u_short odi_gid;
2cb5dabb
KM
793 long odi_size;
794 long odi_rdev;
f78e116c 795 char odi_addr[36];
2cb5dabb
KM
796 long odi_atime;
797 long odi_mtime;
798 long odi_ctime;
f78e116c 799 } c_dinode;
2cb5dabb
KM
800 long c_count;
801 char c_addr[256];
f78e116c
KM
802 } s_ospcl;
803 } u_ospcl;
804
805 if (!cvtflag) {
806 readtape((char *)buf);
b4c41341
KS
807 if (buf->c_magic != NFS_MAGIC) {
808 if (swabl(buf->c_magic) != NFS_MAGIC)
809 return (FAIL);
810 if (!Bcvt) {
811 vprintf(stdout, "Note: Doing Byte swapping\n");
812 Bcvt = 1;
813 }
814 }
815 if (checksum((int *)buf) == FAIL)
816 return (FAIL);
817 if (Bcvt)
818 swabst("8l4s31l", (char *)buf);
5c5f44c7 819 goto good;
f78e116c
KM
820 }
821 readtape((char *)(&u_ospcl.s_ospcl));
822 bzero((char *)buf, (long)TP_BSIZE);
823 buf->c_type = u_ospcl.s_ospcl.c_type;
824 buf->c_date = u_ospcl.s_ospcl.c_date;
825 buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
826 buf->c_volume = u_ospcl.s_ospcl.c_volume;
827 buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
828 buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
829 buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
830 buf->c_magic = u_ospcl.s_ospcl.c_magic;
831 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
832 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
833 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
834 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
835 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
836 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
837 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
838 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
839 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
840 buf->c_count = u_ospcl.s_ospcl.c_count;
2cb5dabb 841 bcopy(u_ospcl.s_ospcl.c_addr, buf->c_addr, (long)256);
f78e116c 842 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
5c5f44c7 843 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
2cb5dabb 844 return(FAIL);
f78e116c 845 buf->c_magic = NFS_MAGIC;
5c5f44c7
KM
846
847good:
b4c41341
KS
848 j = buf->c_dinode.di_ic.ic_size.val;
849 i = j[1];
850 if (buf->c_dinode.di_size == 0 &&
851 (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt==0) {
852 if (*j || i) {
853 printf("Note: Doing Quad swapping\n");
854 Qcvt = 1;
855 }
856 }
857 if (Qcvt) {
858 j[1] = *j; *j = i;
859 }
5c5f44c7
KM
860 switch (buf->c_type) {
861
862 case TS_CLRI:
863 case TS_BITS:
864 /*
865 * Have to patch up missing information in bit map headers
866 */
867 buf->c_inumber = 0;
868 buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
869 for (i = 0; i < buf->c_count; i++)
870 buf->c_addr[i]++;
871 break;
872
873 case TS_TAPE:
874 case TS_END:
875 buf->c_inumber = 0;
876 break;
877
878 case TS_INODE:
879 case TS_ADDR:
880 break;
881
882 default:
883 panic("gethead: unknown inode type %d\n", buf->c_type);
884 break;
885 }
2cb5dabb
KM
886 if (dflag)
887 accthdr(buf);
888 return(GOOD);
889}
890
891/*
892 * Check that a header is where it belongs and predict the next header
893 */
894accthdr(header)
895 struct s_spcl *header;
896{
7851e15d 897 static ino_t previno = 0x7fffffff;
2cb5dabb
KM
898 static int prevtype;
899 static long predict;
900 long blks, i;
901
8d412b7c 902 if (header->c_type == TS_TAPE) {
5c5f44c7 903 fprintf(stderr, "Volume header\n");
b8f4e820 904 previno = 0x7fffffff;
5c5f44c7
KM
905 return;
906 }
7851e15d 907 if (previno == 0x7fffffff)
2cb5dabb
KM
908 goto newcalc;
909 switch (prevtype) {
2cb5dabb 910 case TS_BITS:
5c5f44c7 911 fprintf(stderr, "Dump mask header");
2cb5dabb
KM
912 break;
913 case TS_CLRI:
5c5f44c7 914 fprintf(stderr, "Remove mask header");
2cb5dabb
KM
915 break;
916 case TS_INODE:
5c5f44c7 917 fprintf(stderr, "File header, ino %d", previno);
2cb5dabb
KM
918 break;
919 case TS_ADDR:
5c5f44c7 920 fprintf(stderr, "File continuation header, ino %d", previno);
2cb5dabb
KM
921 break;
922 case TS_END:
5c5f44c7 923 fprintf(stderr, "End of tape header");
2cb5dabb
KM
924 break;
925 }
2cb5dabb
KM
926 if (predict != blksread - 1)
927 fprintf(stderr, "; predicted %d blocks, got %d blocks",
928 predict, blksread - 1);
929 fprintf(stderr, "\n");
930newcalc:
931 blks = 0;
5c5f44c7 932 if (header->c_type != TS_END)
2cb5dabb
KM
933 for (i = 0; i < header->c_count; i++)
934 if (header->c_addr[i] != 0)
935 blks++;
936 predict = blks;
937 blksread = 0;
938 prevtype = header->c_type;
939 previno = header->c_inumber;
f78e116c
KM
940}
941
942/*
943 * Find an inode header.
944 * Complain if had to skip, and complain is set.
945 */
b32320ae 946findinode(header)
f78e116c 947 struct s_spcl *header;
f78e116c 948{
2cb5dabb 949 static long skipcnt = 0;
b8f4e820
KM
950 long i;
951 char buf[TP_BSIZE];
f78e116c
KM
952
953 curfile.name = "<name unknown>";
954 curfile.action = UNKNOWN;
955 curfile.dip = (struct dinode *)NIL;
956 curfile.ino = 0;
2cb5dabb
KM
957 if (ishead(header) == FAIL) {
958 skipcnt++;
7702e9a8 959 while (gethead(header) == FAIL || header->c_date != dumpdate)
f78e116c 960 skipcnt++;
2cb5dabb 961 }
f78e116c 962 for (;;) {
b8f4e820
KM
963 if (checktype(header, TS_ADDR) == GOOD) {
964 /*
965 * Skip up to the beginning of the next record
966 */
967 for (i = 0; i < header->c_count; i++)
968 if (header->c_addr[i])
969 readtape(buf);
970 (void) gethead(header);
971 continue;
972 }
2cb5dabb 973 if (checktype(header, TS_INODE) == GOOD) {
f78e116c
KM
974 curfile.dip = &header->c_dinode;
975 curfile.ino = header->c_inumber;
976 break;
977 }
2cb5dabb 978 if (checktype(header, TS_END) == GOOD) {
f78e116c
KM
979 curfile.ino = maxino;
980 break;
981 }
2cb5dabb 982 if (checktype(header, TS_CLRI) == GOOD) {
f78e116c 983 curfile.name = "<file removal list>";
e108d3a2 984 break;
f78e116c 985 }
2cb5dabb 986 if (checktype(header, TS_BITS) == GOOD) {
f78e116c 987 curfile.name = "<file dump list>";
e108d3a2 988 break;
f78e116c 989 }
2cb5dabb 990 while (gethead(header) == FAIL)
f78e116c
KM
991 skipcnt++;
992 }
b32320ae 993 if (skipcnt > 0)
dd1900f1 994 fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
f78e116c
KM
995 skipcnt = 0;
996}
997
998/*
999 * return whether or not the buffer contains a header block
1000 */
1001ishead(buf)
1002 struct s_spcl *buf;
1003{
1004
1005 if (buf->c_magic != NFS_MAGIC)
2cb5dabb
KM
1006 return(FAIL);
1007 return(GOOD);
f78e116c
KM
1008}
1009
1010checktype(b, t)
1011 struct s_spcl *b;
1012 int t;
1013{
1014
2cb5dabb
KM
1015 if (b->c_type != t)
1016 return(FAIL);
1017 return(GOOD);
f78e116c
KM
1018}
1019
1020checksum(b)
1021 register int *b;
1022{
1023 register int i, j;
1024
1025 j = sizeof(union u_spcl) / sizeof(int);
1026 i = 0;
b4c41341
KS
1027 if(!Bcvt) {
1028 do
1029 i += *b++;
1030 while (--j);
1031 } else {
1032 /* What happens if we want to read restore tapes
1033 for a 16bit int machine??? */
1034 do
1035 i += swabl(*b++);
1036 while (--j);
1037 }
1038
f78e116c
KM
1039 if (i != CHECKSUM) {
1040 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1041 curfile.ino, curfile.name);
2cb5dabb 1042 return(FAIL);
f78e116c 1043 }
2cb5dabb 1044 return(GOOD);
f78e116c
KM
1045}
1046
e9e7ecc4 1047#ifdef RRESTORE
74025ab9 1048/* VARARGS1 */
f78e116c
KM
1049msg(cp, a1, a2, a3)
1050 char *cp;
1051{
1052
1053 fprintf(stderr, cp, a1, a2, a3);
1054}
e9e7ecc4 1055#endif RRESTORE
b4c41341
KS
1056
1057swabst(cp, sp)
1058register char *cp, *sp;
1059{
1060 int n = 0;
1061 char c;
1062 while(*cp) {
1063 switch (*cp) {
1064 case '0': case '1': case '2': case '3': case '4':
1065 case '5': case '6': case '7': case '8': case '9':
1066 n = (n * 10) + (*cp++ - '0');
1067 continue;
1068
1069 case 's': case 'w': case 'h':
1070 c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1071 sp++;
1072 break;
1073
1074 case 'l':
1075 c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1076 c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1077 sp += 3;
1078 }
1079 sp++; /* Any other character, like 'b' counts as byte. */
1080 if (n <= 1) {
1081 n = 0; cp++;
1082 } else
1083 n--;
1084 }
1085}
1086swabl(x) { unsigned long l = x; swabst("l", (char *)&l); return l; }