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