1 /* Copyright (c) 1982 Regents of the University of California */ 2 3 #ifndef lint 4 char version[] = "@(#)main.c 2.15 12/02/82"; 5 #endif 6 7 /* Modified to include h option (recursively extract all files within 8 * a subtree) and m option (recreate the heirarchical structure of 9 * that subtree and move extracted files to their proper homes). 10 * 8/29/80 by Mike Litzkow 11 * 12 * Modified to work on the new file system 13 * 1/19/82 by Kirk McKusick 14 * 15 * Includes the s (skip files) option for use with multiple dumps on 16 * a single tape. 17 */ 18 19 #define MAXINO 3000 20 #define BITS 8 21 #define NCACHE 3 22 #define SIZEINC 10 23 24 #include <stdio.h> 25 #include <signal.h> 26 #include <fstab.h> 27 #ifndef SIMFS 28 #include <sys/param.h> 29 #include <sys/inode.h> 30 #include <sys/fs.h> 31 #include <dir.h> 32 #include <stat.h> 33 #include <dumprestor.h> 34 #else 35 #include "../h/param.h" 36 #include "../h/dir.h" 37 #include "../h/stat.h" 38 #include "../h/inode.h" 39 #include "../h/fs.h" 40 #include "../h/dumprestor.h" 41 #endif 42 #include <sys/ioctl.h> 43 #include <sys/mtio.h> 44 45 #define ODIRSIZ 14 46 struct odirect { 47 u_short d_ino; 48 char d_name[ODIRSIZ]; 49 }; 50 51 #define MWORD(m,i) (m[(unsigned)(i-1)/NBBY]) 52 #define MBIT(i) (1<<((unsigned)(i-1)%NBBY)) 53 #define BIS(i,w) (MWORD(w,i) |= MBIT(i)) 54 #define BIC(i,w) (MWORD(w,i) &= ~MBIT(i)) 55 #define BIT(i,w) (MWORD(w,i) & MBIT(i)) 56 57 ino_t ino; 58 59 int eflag = 0, hflag = 0, mflag = 0, vflag = 0, yflag = 0; 60 int cvtflag = 0, cvtdir = 0; 61 62 long fssize; 63 char tapename[] = "/dev/rmt8"; 64 char *magtape = tapename; 65 int mt; 66 int dumpnum = 1; 67 int volno = 1; 68 int curblk = 0; 69 int bct = NTREC+1; 70 char tbf[NTREC*TP_BSIZE]; 71 72 daddr_t seekpt; 73 FILE *df; 74 DIR *dirp; 75 int ofile; 76 char dirfile[] = "/tmp/rstaXXXXXX"; 77 char lnkbuf[MAXPATHLEN + 1]; 78 int pathlen; 79 80 #define INOHASH(val) (val % MAXINO) 81 struct inotab { 82 struct inotab *t_next; 83 ino_t t_ino; 84 daddr_t t_seekpt; 85 } *inotab[MAXINO]; 86 int maxino = 0; 87 88 #define XISDIR 1 89 #define XTRACTD 2 90 #define XINUSE 4 91 #define XLINKED 8 92 struct xtrlist { 93 struct xtrlist *x_next; 94 struct xtrlist *x_linkedto; 95 time_t x_timep[2]; 96 ino_t x_ino; 97 char x_flags; 98 char x_name[1]; 99 /* actually longer */ 100 } *xtrlist[MAXINO]; 101 int xtrcnt = 0; 102 struct xtrlist *entry; 103 struct xtrlist *unknown; 104 struct xtrlist *allocxtr(); 105 106 char *dumpmap; 107 char *clrimap; 108 109 char clearedbuf[MAXBSIZE]; 110 111 extern char *ctime(); 112 extern int seek(); 113 ino_t search(); 114 int dirwrite(); 115 #ifdef RRESTOR 116 char *host; 117 #endif 118 119 main(argc, argv) 120 int argc; 121 char *argv[]; 122 { 123 register char *cp; 124 char command; 125 int (*signal())(); 126 int done(); 127 128 if (signal(SIGINT, done) == SIG_IGN) 129 signal(SIGINT, SIG_IGN); 130 if (signal(SIGTERM, done) == SIG_IGN) 131 signal(SIGTERM, SIG_IGN); 132 mktemp(dirfile); 133 if (argc < 2) { 134 usage: 135 fprintf(stderr, "Usage: restor x[s|m|h|v] file file..., restor r|R filesys, or restor t\n"); 136 done(1); 137 } 138 argv++; 139 argc -= 2; 140 for (cp = *argv++; *cp; cp++) { 141 switch (*cp) { 142 case '-': 143 break; 144 case 'c': 145 cvtflag++; 146 break; 147 case 'f': 148 magtape = *argv++; 149 #ifdef RRESTOR 150 { char *index(); 151 host = magtape; 152 magtape = index(host, ':'); 153 if (magtape == 0) { 154 nohost: 155 msg("need keyletter ``f'' and device ``host:tape''"); 156 done(1); 157 } 158 *magtape++ = 0; 159 if (rmthost(host) == 0) 160 done(1); 161 } 162 #endif 163 argc--; 164 break; 165 /* s dumpnum (skip to) for multifile dump tapes */ 166 case 's': 167 dumpnum = atoi(*argv++); 168 if (dumpnum <= 0) { 169 fprintf(stderr, "Dump number must be a positive integer\n"); 170 done(1); 171 } 172 argc--; 173 break; 174 case 'h': 175 hflag++; 176 break; 177 case 'm': 178 mflag++; 179 break; 180 case 'x': 181 command = *cp; 182 /* set verbose mode by default */ 183 case 'v': 184 vflag++; 185 break; 186 case 'y': 187 yflag++; 188 break; 189 case 'r': 190 case 'R': 191 hflag++; 192 mflag++; 193 case 't': 194 command = *cp; 195 break; 196 default: 197 fprintf(stderr, "Bad key character %c\n", *cp); 198 goto usage; 199 } 200 } 201 #ifdef RRESTOR 202 if (host == 0) 203 goto nohost; 204 #endif 205 setuid(getuid()); /* no longer need or want root privileges */ 206 doit(command, argc, argv); 207 done(0); 208 } 209 210 doit(command, argc, argv) 211 char command; 212 int argc; 213 char *argv[]; 214 { 215 struct mtop tcom; 216 217 #ifdef RRESTOR 218 if ((mt = rmtopen(magtape, 0)) < 0) { 219 #else 220 if ((mt = open(magtape, 0)) < 0) { 221 #endif 222 fprintf(stderr, "%s: cannot open tape\n", magtape); 223 done(1); 224 } 225 if (dumpnum != 1) { 226 tcom.mt_op = MTFSF; 227 tcom.mt_count = dumpnum -1; 228 #ifdef RRESTOR 229 rmtioctl(MTFSF,dumpnum - 1); 230 #else 231 if (ioctl(mt,MTIOCTOP,&tcom) < 0) 232 perror("ioctl MTFSF"); 233 #endif 234 } 235 blkclr(clearedbuf, (long)MAXBSIZE); 236 if (readhdr(&spcl) == 0) { 237 bct--; /* push back this block */ 238 cvtflag++; 239 if (readhdr(&spcl) == 0) { 240 fprintf(stderr, "Tape is not a dump tape\n"); 241 done(1); 242 } 243 fprintf(stderr, "Converting to new file system format.\n"); 244 } 245 switch(command) { 246 case 't': 247 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date)); 248 fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate)); 249 return; 250 case 'R': 251 case 'r': 252 setdir(*argv); 253 argc = 1; 254 *argv = "."; 255 /* and then extract it all */ 256 case 'x': 257 df = fopen(dirfile, "w"); 258 if (df == 0) { 259 fprintf(stderr, "restor: %s - cannot create directory temporary\n", dirfile); 260 done(1); 261 } 262 extractfiles(argc, argv); 263 return; 264 } 265 } 266 267 extractfiles(argc, argv) 268 int argc; 269 char **argv; 270 { 271 char *ststore(); 272 register struct xtrlist *xp; 273 struct xtrlist **xpp; 274 ino_t d; 275 int xtrfile(), xtrskip(), xtrcvtdir(), xtrcvtskip(), 276 xtrlnkfile(), xtrlnkskip(), null(); 277 int mode, uid, gid, i; 278 struct stat stbuf; 279 char name[BUFSIZ + 1]; 280 281 if (stat(".", &stbuf) < 0) { 282 fprintf(stderr, "cannot stat .\n"); 283 done(1); 284 } 285 fssize = stbuf.st_blksize; 286 if (fssize <= 0 || ((fssize - 1) & fssize) != 0) { 287 fprintf(stderr, "bad block size %d\n", fssize); 288 done(1); 289 } 290 if (checkvol(&spcl, 1) == 0) { 291 fprintf(stderr, "Tape is not volume 1 of the dump\n"); 292 } 293 clrimap = 0; 294 dumpmap = 0; 295 unknown = allocxtr(0, "name unknown - not extracted", 0); 296 pass1(1); /* This sets the various maps on the way by */ 297 while (argc--) { 298 if ((d = psearch(*argv)) == 0 || BIT(d,dumpmap) == 0) { 299 fprintf(stderr, "%s: not on tape\n", *argv++); 300 continue; 301 } 302 if (mflag) 303 checkdir(*argv); 304 if (hflag) 305 getleaves(d, *argv++); 306 else 307 (void)allocxtr(d, *argv++, XINUSE); 308 } 309 if (dumpnum > 1) { 310 /* 311 * if this is a multi-dump tape we always start with 312 * volume 1, so as to avoid accidentally restoring 313 * from a different dump! 314 */ 315 resetmt(); 316 dumpnum = 1; 317 volno = 1; 318 readhdr(&spcl); 319 goto rbits; 320 } 321 newvol: 322 #ifdef RRESTOR 323 rmtclose(); 324 #else 325 close(mt); 326 #endif 327 getvol: 328 fprintf(stderr, "Mount desired tape volume; Specify volume #: "); 329 if (gets(tbf) == NULL) 330 return; 331 volno = atoi(tbf); 332 if (volno <= 0) { 333 fprintf(stderr, "Volume numbers are positive numerics\n"); 334 goto getvol; 335 } 336 #ifdef RRESTOR 337 if ((mt = rmtopen(magtape, 0)) == -1) { 338 #else 339 if ((mt = open(magtape, 0)) == -1) { 340 #endif 341 fprintf(stderr, "Cannot open tape!\n"); 342 goto getvol; 343 } 344 if (dumpnum > 1) 345 resetmt(); 346 if (readhdr(&spcl) == 0) { 347 fprintf(stderr, "tape is not dump tape\n"); 348 goto newvol; 349 } 350 if (checkvol(&spcl, volno) == 0) { 351 fprintf(stderr, "Wrong volume (%d)\n", spcl.c_volume); 352 goto newvol; 353 } 354 rbits: 355 while (gethead(&spcl) == 0) 356 ; 357 if (checktype(&spcl, TS_INODE) == 1) { 358 fprintf(stderr, "Can't find inode mask!\n"); 359 goto newvol; 360 } 361 if (checktype(&spcl, TS_BITS) == 0) 362 goto rbits; 363 readbits(&dumpmap); 364 while (xtrcnt > 0) { 365 again: 366 if (ishead(&spcl) == 0) { 367 i = 0; 368 while (gethead(&spcl) == 0) 369 i++; 370 fprintf(stderr, "resync restor, skipped %d blocks\n", 371 i); 372 } 373 if (checktype(&spcl, TS_END) == 1) { 374 fprintf(stderr, "end of tape\n"); 375 break; 376 } 377 if (checktype(&spcl, TS_INODE) == 0) { 378 gethead(&spcl); 379 goto again; 380 } 381 d = spcl.c_inumber; 382 entry = unknown; 383 entry->x_ino = d; 384 for (xp = xtrlist[INOHASH(d)]; xp; xp = xp->x_next) { 385 if (d != xp->x_ino || (xp->x_flags & XLINKED)) 386 continue; 387 entry = xp; 388 xp->x_timep[0] = spcl.c_dinode.di_atime; 389 xp->x_timep[1] = spcl.c_dinode.di_mtime; 390 mode = spcl.c_dinode.di_mode; 391 if (mflag) 392 strcpy(name, xp->x_name); 393 else 394 sprintf(name, "%u", xp->x_ino); 395 switch (mode & IFMT) { 396 default: 397 fprintf(stderr, "%s: unknown file mode 0%o\n", 398 name, mode); 399 xp->x_flags |= XTRACTD; 400 xtrcnt--; 401 goto skipfile; 402 case IFCHR: 403 case IFBLK: 404 if (vflag) 405 fprintf(stdout, "extract special file %s\n", name); 406 if (mknod(name, mode, spcl.c_dinode.di_rdev)) { 407 fprintf(stderr, "%s: cannot create special file\n", name); 408 xp->x_flags |= XTRACTD; 409 xtrcnt--; 410 goto skipfile; 411 } 412 getfile(null, null, spcl.c_dinode.di_size); 413 break; 414 case IFDIR: 415 if (mflag) { 416 if (vflag) 417 fprintf(stdout, "extract directory %s\n", name); 418 strncat(name, "/.", BUFSIZ); 419 checkdir(name); 420 chown(xp->x_name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid); 421 getfile(null, null, spcl.c_dinode.di_size); 422 break; 423 } 424 if (vflag) 425 fprintf(stdout, "extract file %s\n", name); 426 if ((ofile = creat(name, 0666)) < 0) { 427 fprintf(stderr, "%s: cannot create file\n", name); 428 xp->x_flags |= XTRACTD; 429 xtrcnt--; 430 goto skipfile; 431 } 432 chown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid); 433 if (cvtdir) { 434 getfile(xtrcvtdir, xtrcvtskip, 435 spcl.c_dinode.di_size); 436 flushent(xtrfile); 437 } else 438 getfile(xtrfile, xtrskip, 439 spcl.c_dinode.di_size); 440 close(ofile); 441 break; 442 case IFLNK: 443 /* 444 * Some early dump tapes have symbolic links 445 * present without the associated data blocks. 446 * This hack avoids trashing a file system with 447 * inodes with missing data blocks. 448 */ 449 if (spcl.c_count == 0) { 450 if (vflag) 451 printf("%s: 0 length symbolic link (ignored)\n", name); 452 xp->x_flags |= XTRACTD; 453 xtrcnt--; 454 goto skipfile; 455 } 456 if (vflag) 457 fprintf(stdout, "extract symbolic link %s\n", name); 458 uid = spcl.c_dinode.di_uid; 459 gid = spcl.c_dinode.di_gid; 460 lnkbuf[0] = '\0'; 461 pathlen = 0; 462 getfile(xtrlnkfile, xtrlnkskip, spcl.c_dinode.di_size); 463 if (symlink(lnkbuf, name) < 0) { 464 fprintf(stderr, "%s: cannot create symbolic link\n", name); 465 xp->x_flags |= XTRACTD; 466 xtrcnt--; 467 goto finished; 468 } 469 chown(name, uid, gid); 470 break; 471 case IFREG: 472 if (vflag) 473 fprintf(stdout, "extract file %s\n", name); 474 if ((ofile = creat(name, 0666)) < 0) { 475 fprintf(stderr, "%s: cannot create file\n", name); 476 xp->x_flags |= XTRACTD; 477 xtrcnt--; 478 goto skipfile; 479 } 480 chown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid); 481 getfile(xtrfile, xtrskip, spcl.c_dinode.di_size); 482 close(ofile); 483 break; 484 } 485 chmod(name, mode); 486 utime(name, xp->x_timep); 487 xp->x_flags |= XTRACTD; 488 xtrcnt--; 489 goto finished; 490 } 491 skipfile: 492 getfile(null, null, spcl.c_dinode.di_size); 493 finished: 494 ; 495 } 496 if (xtrcnt == 0 && !mflag) 497 return; 498 for (xpp = xtrlist; xpp < &xtrlist[MAXINO]; xpp++) { 499 for (xp = *xpp; xp; xp = xp->x_next) { 500 if (mflag && (xp->x_flags & XISDIR)) 501 utime(xp->x_name, xp->x_timep); 502 if (xp->x_flags & XTRACTD) 503 continue; 504 if ((xp->x_flags & XLINKED) == 0) { 505 fprintf(stderr, "cannot find file %s\n", 506 xp->x_name); 507 continue; 508 } 509 if (!mflag) 510 continue; 511 if (vflag) 512 fprintf(stdout, "link %s to %s\n", 513 xp->x_linkedto->x_name, xp->x_name); 514 if (link(xp->x_linkedto->x_name, xp->x_name) < 0) 515 fprintf(stderr, "link %s to %s failed\n", 516 xp->x_linkedto->x_name, xp->x_name); 517 } 518 } 519 } 520 521 /* 522 * Read the tape, bulding up a directory structure for extraction 523 * by name 524 */ 525 pass1(savedir) 526 int savedir; 527 { 528 register int i; 529 register struct dinode *ip; 530 struct direct nulldir; 531 char buf[TP_BSIZE]; 532 int putdir(), null(), dirwrite(); 533 534 nulldir.d_ino = 1; 535 nulldir.d_namlen = 1; 536 strncpy(nulldir.d_name, "/", nulldir.d_namlen); 537 nulldir.d_reclen = DIRSIZ(&nulldir); 538 while (gethead(&spcl) == 0) { 539 fprintf(stderr, "Can't find directory header!\n"); 540 } 541 for (;;) { 542 if (checktype(&spcl, TS_BITS) == 1) { 543 readbits(&dumpmap); 544 continue; 545 } 546 if (checktype(&spcl, TS_CLRI) == 1) { 547 readbits(&clrimap); 548 continue; 549 } 550 if (checktype(&spcl, TS_INODE) == 0) { 551 finish: 552 if (savedir) { 553 fclose(df); 554 dirp = opendir(dirfile); 555 if (dirp == NULL) 556 perror("opendir"); 557 } 558 resetmt(); 559 return; 560 } 561 ip = &spcl.c_dinode; 562 i = ip->di_mode & IFMT; 563 if (i != IFDIR) { 564 goto finish; 565 } 566 if (spcl.c_inumber == ROOTINO) { 567 readtape(buf); 568 bct--; /* push back this block */ 569 if (((struct direct *)buf)->d_ino != ROOTINO) { 570 if (((struct odirect *)buf)->d_ino != ROOTINO) { 571 fprintf(stderr, "bad root directory\n"); 572 done(1); 573 } 574 fprintf(stderr, "converting to new directory format\n"); 575 cvtdir = 1; 576 cvtflag = 1; 577 } 578 if (!savedir && !cvtdir) { 579 /* if no conversion, just return */ 580 goto finish; 581 } 582 } 583 allocinotab(spcl.c_inumber, seekpt); 584 if (savedir) { 585 getfile(putdir, null, spcl.c_dinode.di_size); 586 putent(&nulldir, dirwrite); 587 flushent(dirwrite); 588 } else { 589 getfile(null, null, spcl.c_dinode.di_size); 590 } 591 } 592 } 593 594 /* 595 * Put the directory entries in the directory file 596 */ 597 putdir(buf, size) 598 char *buf; 599 int size; 600 { 601 struct direct cvtbuf; 602 register struct odirect *odp; 603 struct odirect *eodp; 604 register struct direct *dp; 605 long loc, i; 606 607 if (cvtdir) { 608 eodp = (struct odirect *)&buf[size]; 609 for (odp = (struct odirect *)buf; odp < eodp; odp++) 610 if (odp->d_ino != 0) { 611 dcvt(odp, &cvtbuf); 612 putent(&cvtbuf, dirwrite); 613 } 614 } else { 615 for (loc = 0; loc < size; ) { 616 dp = (struct direct *)(buf + loc); 617 i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 618 if (dp->d_reclen <= 0 || dp->d_reclen > i) { 619 loc += i; 620 continue; 621 } 622 loc += dp->d_reclen; 623 if (dp->d_ino != 0) { 624 putent(dp, dirwrite); 625 } 626 } 627 } 628 } 629 630 /* 631 * Recursively find names and inumbers of all files in subtree 632 * pname and put them in xtrlist[] 633 */ 634 getleaves(ino, pname) 635 ino_t ino; 636 char *pname; 637 { 638 register struct inotab *itp; 639 int namelen; 640 daddr_t bpt; 641 register struct direct *dp; 642 char locname[BUFSIZ + 1]; 643 644 if (BIT(ino, dumpmap) == 0) { 645 if (vflag) 646 fprintf(stdout, "%s: not on the tape\n", pname); 647 return; 648 } 649 for (itp = inotab[INOHASH(ino)]; itp; itp = itp->t_next) { 650 if (itp->t_ino != ino) 651 continue; 652 /* 653 * pname is a directory name 654 */ 655 (void)allocxtr(ino, pname, XISDIR); 656 /* 657 * begin search through the directory 658 * skipping over "." and ".." 659 */ 660 strncpy(locname, pname, BUFSIZ); 661 strncat(locname, "/", BUFSIZ); 662 namelen = strlen(locname); 663 seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 664 dp = readdir(dirp); 665 dp = readdir(dirp); 666 dp = readdir(dirp); 667 bpt = telldir(dirp); 668 /* 669 * "/" signals end of directory 670 */ 671 while (dp->d_namlen != 1 || dp->d_name[0] != '/') { 672 locname[namelen] = '\0'; 673 if (namelen + dp->d_namlen >= BUFSIZ) { 674 fprintf(stderr, "%s%s: name exceedes %d char\n", 675 locname, dp->d_name, BUFSIZ); 676 continue; 677 } 678 strncat(locname, dp->d_name, dp->d_namlen); 679 getleaves(dp->d_ino, locname); 680 seekdir(dirp, bpt, itp->t_seekpt); 681 dp = readdir(dirp); 682 bpt = telldir(dirp); 683 } 684 return; 685 } 686 /* 687 * locname is name of a simple file 688 */ 689 (void)allocxtr(ino, pname, XINUSE); 690 } 691 692 /* 693 * Search the directory tree rooted at inode ROOTINO 694 * for the path pointed at by n 695 */ 696 psearch(n) 697 char *n; 698 { 699 register char *cp, *cp1; 700 char c; 701 702 ino = ROOTINO; 703 if (*(cp = n) == '/') 704 cp++; 705 next: 706 cp1 = cp + 1; 707 while (*cp1 != '/' && *cp1) 708 cp1++; 709 c = *cp1; 710 *cp1 = 0; 711 ino = search(ino, cp); 712 if (ino == 0) { 713 *cp1 = c; 714 return(0); 715 } 716 *cp1 = c; 717 if (c == '/') { 718 cp = cp1+1; 719 goto next; 720 } 721 return(ino); 722 } 723 724 /* 725 * search the directory inode ino 726 * looking for entry cp 727 */ 728 ino_t 729 search(inum, cp) 730 ino_t inum; 731 char *cp; 732 { 733 register struct direct *dp; 734 register struct inotab *itp; 735 int len; 736 737 for (itp = inotab[INOHASH(inum)]; itp; itp = itp->t_next) 738 if (itp->t_ino == inum) 739 goto found; 740 return(0); 741 found: 742 seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 743 len = strlen(cp); 744 do { 745 dp = readdir(dirp); 746 if (dp->d_namlen == 1 && dp->d_name[0] == '/') 747 return(0); 748 } while (dp->d_namlen != len || strncmp(dp->d_name, cp, len)); 749 return(dp->d_ino); 750 } 751 752 /* 753 * Do the file extraction, calling the supplied functions 754 * with the blocks 755 */ 756 getfile(f1, f2, size) 757 int (*f2)(), (*f1)(); 758 off_t size; 759 { 760 register int i; 761 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 762 union u_spcl addrblk; 763 # define addrblock addrblk.s_spcl 764 765 addrblock = spcl; 766 for (;;) { 767 for (i = 0; i < addrblock.c_count; i++) { 768 if (addrblock.c_addr[i]) { 769 readtape(&buf[curblk++][0]); 770 if (curblk == fssize / TP_BSIZE) { 771 (*f1)(buf, size > TP_BSIZE ? 772 (long) (fssize) : 773 (curblk - 1) * TP_BSIZE + size); 774 curblk = 0; 775 } 776 } else { 777 if (curblk > 0) { 778 (*f1)(buf, size > TP_BSIZE ? 779 (long) (curblk * TP_BSIZE) : 780 (curblk - 1) * TP_BSIZE + size); 781 curblk = 0; 782 } 783 (*f2)(clearedbuf, size > TP_BSIZE ? 784 (long) TP_BSIZE : size); 785 } 786 if ((size -= TP_BSIZE) <= 0) { 787 gethead(&spcl); 788 goto out; 789 } 790 } 791 if (gethead(&addrblock) == 0) { 792 fprintf(stderr, "Missing address (header) block for %s\n", 793 entry->x_name); 794 spcl.c_magic = 0; 795 goto out; 796 } 797 if (checktype(&addrblock, TS_ADDR) == 0) { 798 spcl = addrblock; 799 goto out; 800 } 801 } 802 out: 803 if (curblk > 0) { 804 (*f1)(buf, (curblk * TP_BSIZE) + size); 805 curblk = 0; 806 } 807 } 808 809 /* 810 * The next routines are called during file extraction to 811 * put the data into the right form and place. 812 */ 813 xtrfile(buf, size) 814 char *buf; 815 long size; 816 { 817 818 if (write(ofile, buf, (int) size) == -1) { 819 perror("extract write"); 820 done(1); 821 } 822 } 823 824 xtrskip(buf, size) 825 char *buf; 826 long size; 827 { 828 829 #ifdef lint 830 buf = buf; 831 #endif 832 if (lseek(ofile, size, 1) == -1) { 833 perror("extract seek"); 834 done(1); 835 } 836 } 837 838 xtrcvtdir(buf, size) 839 struct odirect *buf; 840 long size; 841 { 842 struct odirect *odp, *edp; 843 struct direct cvtbuf; 844 845 edp = &buf[size / sizeof(struct odirect)]; 846 for (odp = buf; odp < edp; odp++) { 847 dcvt(odp, &cvtbuf); 848 putent(&cvtbuf, xtrfile); 849 } 850 } 851 852 xtrcvtskip(buf, size) 853 char *buf; 854 long size; 855 { 856 857 fprintf(stderr, "unallocated block in directory %s\n", 858 entry->x_name); 859 xtrskip(buf, size); 860 } 861 862 xtrlnkfile(buf, size) 863 char *buf; 864 long size; 865 { 866 867 pathlen += size; 868 if (pathlen > MAXPATHLEN) { 869 fprintf(stderr, "symbolic link name: %s; too long %d\n", 870 buf, size); 871 done(1); 872 } 873 strcat(lnkbuf, buf); 874 } 875 876 xtrlnkskip(buf, size) 877 char *buf; 878 long size; 879 { 880 881 #ifdef lint 882 buf = buf, size = size; 883 #endif 884 fprintf(stderr, "unallocated block in symbolic link %s\n", 885 entry->x_name); 886 done(1); 887 } 888 889 null() {;} 890 891 /* 892 * Do the tape i/o, dealing with volume changes 893 * etc.. 894 */ 895 readtape(b) 896 char *b; 897 { 898 register long i; 899 struct u_spcl tmpbuf; 900 char c; 901 902 if (bct >= NTREC) { 903 for (i = 0; i < NTREC; i++) 904 ((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0; 905 bct = 0; 906 #ifdef RRESTOR 907 if ((i = rmtread(tbf, NTREC*TP_BSIZE)) < 0) { 908 #else 909 if ((i = read(mt, tbf, NTREC*TP_BSIZE)) < 0) { 910 #endif 911 fprintf(stderr, "Tape read error while restoring %s\n", 912 entry->x_name); 913 if (!yflag) { 914 fprintf(stderr, "continue? "); 915 do { 916 fprintf(stderr, "[yn] "); 917 c = getchar(); 918 while (getchar() != '\n') 919 /* void */; 920 } while (c != 'y' && c != 'n'); 921 if (c == 'n') 922 done(1); 923 } 924 eflag++; 925 i = NTREC*TP_BSIZE; 926 blkclr(tbf, i); 927 #ifdef RRESTOR 928 if (rmtseek(i, 1) < 0) { 929 #else 930 if (lseek(mt, i, 1) < 0) { 931 #endif 932 fprintf(stderr, "continuation failed\n"); 933 done(1); 934 } 935 } 936 if (i == 0) { 937 bct = NTREC + 1; 938 volno++; 939 loop: 940 flsht(); 941 #ifdef RRESTOR 942 rmtclose(); 943 #else 944 close(mt); 945 #endif 946 fprintf(stderr, "Mount volume %d\n", volno); 947 while (getchar() != '\n') 948 ; 949 #ifdef RRESTOR 950 if ((mt = rmtopen(magtape, 0)) == -1) { 951 #else 952 if ((mt = open(magtape, 0)) == -1) { 953 #endif 954 fprintf(stderr, "Cannot open tape!\n"); 955 goto loop; 956 } 957 if (readhdr(&tmpbuf) == 0) { 958 fprintf(stderr, "Not a dump tape.Try again\n"); 959 goto loop; 960 } 961 if (checkvol(&tmpbuf, volno) == 0) { 962 fprintf(stderr, "Wrong tape. Try again\n"); 963 goto loop; 964 } 965 readtape(b); 966 return; 967 } 968 } 969 blkcpy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE); 970 } 971 972 flsht() 973 { 974 975 bct = NTREC+1; 976 } 977 978 blkcpy(from, to, size) 979 char *from, *to; 980 long size; 981 { 982 983 #ifdef lint 984 from = from, to = to, size = size; 985 #endif 986 asm(" movc3 12(ap),*4(ap),*8(ap)"); 987 } 988 989 blkclr(buf, size) 990 char *buf; 991 long size; 992 { 993 994 #ifdef lint 995 buf = buf, size = size; 996 #endif 997 asm("movc5 $0,(r0),$0,8(ap),*4(ap)"); 998 } 999 1000 resetmt() 1001 { 1002 struct mtop tcom; 1003 1004 if (dumpnum > 1) 1005 tcom.mt_op = MTBSF; 1006 else 1007 tcom.mt_op = MTREW; 1008 tcom.mt_count = 1; 1009 flsht(); 1010 #ifdef RRESTOR 1011 if (rmtioctl(tcom.mt_op, 1) == -1) { 1012 /* kludge for disk dumps */ 1013 rmtseek((long)0, 0); 1014 } 1015 #else 1016 if (ioctl(mt,MTIOCTOP,&tcom) == -1) { 1017 /* kludge for disk dumps */ 1018 lseek(mt, (long)0, 0); 1019 } 1020 #endif 1021 if (dumpnum > 1) { 1022 #ifdef RRESTOR 1023 rmtioctl(MTFSF, 1); 1024 #else 1025 tcom.mt_op = MTFSF; 1026 tcom.mt_count = 1; 1027 ioctl(mt,MTIOCTOP,&tcom); 1028 #endif 1029 } 1030 } 1031 1032 checkvol(b, t) 1033 struct s_spcl *b; 1034 int t; 1035 { 1036 1037 if (b->c_volume == t) 1038 return(1); 1039 return(0); 1040 } 1041 1042 readhdr(b) 1043 struct s_spcl *b; 1044 { 1045 1046 if (gethead(b) == 0) 1047 return(0); 1048 if (checktype(b, TS_TAPE) == 0) 1049 return(0); 1050 return(1); 1051 } 1052 1053 /* 1054 * read the tape into buf, then return whether or 1055 * or not it is a header block. 1056 */ 1057 gethead(buf) 1058 struct s_spcl *buf; 1059 { 1060 union u_ospcl { 1061 char dummy[TP_BSIZE]; 1062 struct s_ospcl { 1063 int c_type; 1064 time_t c_date; 1065 time_t c_ddate; 1066 int c_volume; 1067 daddr_t c_tapea; 1068 ino_t c_inumber; 1069 int c_magic; 1070 int c_checksum; 1071 struct odinode { 1072 unsigned short odi_mode; 1073 short odi_nlink; 1074 short odi_uid; 1075 short odi_gid; 1076 off_t odi_size; 1077 daddr_t odi_rdev; 1078 char odi_addr[36]; 1079 time_t odi_atime; 1080 time_t odi_mtime; 1081 time_t odi_ctime; 1082 } c_dinode; 1083 int c_count; 1084 char c_addr[TP_NINDIR]; 1085 } s_ospcl; 1086 } u_ospcl; 1087 1088 if (!cvtflag) { 1089 readtape((char *)buf); 1090 if (buf->c_magic != NFS_MAGIC || checksum((int *)buf) == 0) 1091 return(0); 1092 return(1); 1093 } 1094 readtape((char *)(&u_ospcl.s_ospcl)); 1095 blkclr((char *)buf, TP_BSIZE); 1096 buf->c_type = u_ospcl.s_ospcl.c_type; 1097 buf->c_date = u_ospcl.s_ospcl.c_date; 1098 buf->c_ddate = u_ospcl.s_ospcl.c_ddate; 1099 buf->c_volume = u_ospcl.s_ospcl.c_volume; 1100 buf->c_tapea = u_ospcl.s_ospcl.c_tapea; 1101 buf->c_inumber = u_ospcl.s_ospcl.c_inumber; 1102 buf->c_checksum = u_ospcl.s_ospcl.c_checksum; 1103 buf->c_magic = u_ospcl.s_ospcl.c_magic; 1104 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode; 1105 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink; 1106 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid; 1107 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid; 1108 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size; 1109 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev; 1110 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime; 1111 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime; 1112 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime; 1113 buf->c_count = u_ospcl.s_ospcl.c_count; 1114 blkcpy(u_ospcl.s_ospcl.c_addr, buf->c_addr, TP_NINDIR); 1115 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC || 1116 checksum((int *)(&u_ospcl.s_ospcl)) == 0) 1117 return(0); 1118 buf->c_magic = NFS_MAGIC; 1119 return(1); 1120 } 1121 1122 /* 1123 * return whether or not the buffer contains a header block 1124 */ 1125 ishead(buf) 1126 struct s_spcl *buf; 1127 { 1128 1129 if (buf->c_magic != NFS_MAGIC) 1130 return(0); 1131 return(1); 1132 } 1133 1134 checktype(b, t) 1135 struct s_spcl *b; 1136 int t; 1137 { 1138 1139 return(b->c_type == t); 1140 } 1141 1142 /* 1143 * read a bit mask from the tape into m. 1144 */ 1145 readbits(mapp) 1146 char **mapp; 1147 { 1148 register int i; 1149 char *m; 1150 1151 i = spcl.c_count; 1152 1153 if (*mapp == 0) 1154 *mapp = (char *)calloc(i, (TP_BSIZE/(NBBY/BITS))); 1155 m = *mapp; 1156 while (i--) { 1157 readtape((char *) m); 1158 m += (TP_BSIZE/(NBBY/BITS)); 1159 } 1160 while (gethead(&spcl) == 0) 1161 ; 1162 } 1163 1164 checksum(b) 1165 register int *b; 1166 { 1167 register int i, j; 1168 1169 j = sizeof(union u_spcl) / sizeof(int); 1170 i = 0; 1171 do 1172 i += *b++; 1173 while (--j); 1174 if (i != CHECKSUM) { 1175 fprintf(stderr, "Checksum error %o, file %s\n", i, 1176 entry->x_name); 1177 return(0); 1178 } 1179 return(1); 1180 } 1181 1182 /* 1183 * Check for access into each directory in the pathname of an extracted 1184 * file and create such a directory if needed in preparation for moving 1185 * the file to its proper home. 1186 */ 1187 checkdir(name) 1188 register char *name; 1189 { 1190 register char *cp; 1191 int i; 1192 1193 for (cp = name; *cp; cp++) { 1194 if (*cp == '/') { 1195 *cp = '\0'; 1196 if (access(name, 01) < 0) { 1197 register int pid, rp; 1198 1199 if ((pid = vfork()) == 0) { 1200 execl("/bin/mkdir", "mkdir", name, 0); 1201 execl("/usr/bin/mkdir", "mkdir", name, 0); 1202 fprintf(stderr, "restor: cannot find mkdir!\n"); 1203 done(0); 1204 } 1205 while ((rp = wait(&i)) >= 0 && rp != pid) 1206 ; 1207 } 1208 *cp = '/'; 1209 } 1210 } 1211 } 1212 1213 setdir(dev) 1214 char *dev; 1215 { 1216 struct fstab *fsp; 1217 1218 if (setfsent() == 0) { 1219 fprintf(stderr, "Can't open checklist file: %s\n", FSTAB); 1220 done(1); 1221 } 1222 while ((fsp = getfsent()) != 0) { 1223 if (strcmp(fsp->fs_spec, dev) == 0) { 1224 fprintf(stderr, "%s mounted on %s\n", dev, fsp->fs_file); 1225 if (chdir(fsp->fs_file) >= 0) 1226 return; 1227 fprintf(stderr, "%s cannot chdir to %s\n", 1228 fsp->fs_file); 1229 done(1); 1230 } 1231 } 1232 fprintf(stderr, "%s not mounted\n", dev); 1233 done(1); 1234 } 1235 1236 /* 1237 * These variables are "local" to the following two functions. 1238 */ 1239 char dirbuf[DIRBLKSIZ]; 1240 long dirloc = 0; 1241 long prev = 0; 1242 1243 /* 1244 * add a new directory entry to a file. 1245 */ 1246 putent(dp, wrtfunc) 1247 struct direct *dp; 1248 int (*wrtfunc)(); 1249 { 1250 1251 if (dp->d_ino == 0) 1252 return; 1253 if (dirloc + dp->d_reclen > DIRBLKSIZ) { 1254 ((struct direct *)(dirbuf + prev))->d_reclen = 1255 DIRBLKSIZ - prev; 1256 (*wrtfunc)(dirbuf, DIRBLKSIZ); 1257 dirloc = 0; 1258 } 1259 blkcpy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen); 1260 prev = dirloc; 1261 dirloc += dp->d_reclen; 1262 } 1263 1264 /* 1265 * flush out a directory that is finished. 1266 */ 1267 flushent(wrtfunc) 1268 int (*wrtfunc)(); 1269 { 1270 1271 ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 1272 (*wrtfunc)(dirbuf, dirloc); 1273 dirloc = 0; 1274 } 1275 1276 dirwrite(buf, size) 1277 char *buf; 1278 int size; 1279 { 1280 1281 fwrite(buf, 1, size, df); 1282 seekpt = ftell(df); 1283 } 1284 1285 dcvt(odp, ndp) 1286 register struct odirect *odp; 1287 register struct direct *ndp; 1288 { 1289 1290 blkclr((char *)ndp, (long)(sizeof *ndp)); 1291 ndp->d_ino = odp->d_ino; 1292 strncpy(ndp->d_name, odp->d_name, ODIRSIZ); 1293 ndp->d_namlen = strlen(ndp->d_name); 1294 ndp->d_reclen = DIRSIZ(ndp); 1295 /* 1296 * this quickly calculates if this inode is a directory. 1297 * Currently not maintained. 1298 * 1299 for (itp = inotab[INOHASH(odp->d_ino)]; itp; itp = itp->t_next) { 1300 if (itp->t_ino != odp->d_ino) 1301 continue; 1302 ndp->d_fmt = IFDIR; 1303 break; 1304 } 1305 */ 1306 } 1307 1308 /* 1309 * Open a directory. 1310 * Modified to allow any random file to be a legal directory. 1311 */ 1312 DIR * 1313 opendir(name) 1314 char *name; 1315 { 1316 register DIR *dirp; 1317 1318 dirp = (DIR *)malloc(sizeof(DIR)); 1319 dirp->dd_fd = open(name, 0); 1320 if (dirp->dd_fd == -1) { 1321 free((char *)dirp); 1322 return NULL; 1323 } 1324 dirp->dd_loc = 0; 1325 return dirp; 1326 } 1327 1328 /* 1329 * Seek to an entry in a directory. 1330 * Only values returned by ``telldir'' should be passed to seekdir. 1331 * Modified to have many directories based in one file. 1332 */ 1333 void 1334 seekdir(dirp, loc, base) 1335 register DIR *dirp; 1336 daddr_t loc, base; 1337 { 1338 1339 if (loc == telldir(dirp)) 1340 return; 1341 loc -= base; 1342 if (loc < 0) 1343 fprintf(stderr, "bad seek pointer to seekdir %d\n", loc); 1344 (void)lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0); 1345 dirp->dd_loc = loc & (DIRBLKSIZ - 1); 1346 if (dirp->dd_loc != 0) 1347 dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); 1348 } 1349 1350 /* 1351 * get next entry in a directory. 1352 */ 1353 struct direct * 1354 readdir(dirp) 1355 register DIR *dirp; 1356 { 1357 register struct direct *dp; 1358 1359 for (;;) { 1360 if (dirp->dd_loc == 0) { 1361 dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 1362 DIRBLKSIZ); 1363 if (dirp->dd_size <= 0) 1364 return NULL; 1365 } 1366 if (dirp->dd_loc >= dirp->dd_size) { 1367 dirp->dd_loc = 0; 1368 continue; 1369 } 1370 dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); 1371 if (dp->d_reclen <= 0 || 1372 dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) 1373 return NULL; 1374 dirp->dd_loc += dp->d_reclen; 1375 if (dp->d_ino == 0) 1376 continue; 1377 return (dp); 1378 } 1379 } 1380 1381 allocinotab(ino, seekpt) 1382 ino_t ino; 1383 daddr_t seekpt; 1384 { 1385 register struct inotab *itp; 1386 1387 itp = (struct inotab *)calloc(1, sizeof(struct inotab)); 1388 itp->t_next = inotab[INOHASH(ino)]; 1389 inotab[INOHASH(ino)] = itp; 1390 itp->t_ino = ino; 1391 itp->t_seekpt = seekpt; 1392 } 1393 1394 struct xtrlist * 1395 allocxtr(ino, name, flags) 1396 ino_t ino; 1397 char *name; 1398 char flags; 1399 { 1400 register struct xtrlist *xp, *pxp; 1401 int size; 1402 1403 size = sizeof(struct xtrlist) + strlen(name); 1404 xp = (struct xtrlist *)calloc(1, size); 1405 xp->x_ino = ino; 1406 xp->x_flags = flags; 1407 strcpy(xp->x_name, name); 1408 if (flags == 0) 1409 return (xp); 1410 xp->x_next = xtrlist[INOHASH(ino)]; 1411 xtrlist[INOHASH(ino)] = xp; 1412 xtrcnt++; 1413 for (pxp = xp->x_next; pxp; pxp = pxp->x_next) 1414 if (pxp->x_ino == ino && (pxp->x_flags & XLINKED) == 0) { 1415 xp->x_flags |= XLINKED; 1416 xp->x_linkedto = pxp; 1417 xtrcnt--; 1418 break; 1419 } 1420 if (!vflag) 1421 return (xp); 1422 if (xp->x_flags & XLINKED) 1423 fprintf(stdout, "%s: linked to %s\n", xp->x_name, pxp->x_name); 1424 else if (xp->x_flags & XISDIR) 1425 fprintf(stdout, "%s: directory inode %u\n", xp->x_name, ino); 1426 else 1427 fprintf(stdout, "%s: inode %u\n", xp->x_name, ino); 1428 return (xp); 1429 } 1430 1431 #ifdef RRESTOR 1432 msg(cp, a1, a2, a3) 1433 char *cp; 1434 { 1435 1436 fprintf(stderr, cp, a1, a2, a3); 1437 } 1438 #endif RRESTOR 1439 1440 done(exitcode) 1441 int exitcode; 1442 { 1443 1444 unlink(dirfile); 1445 exit(exitcode); 1446 } 1447