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