1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #ifndef lint 40 /*static char sccsid[] = "from: @(#)tape.c 8.3 (Berkeley) 4/1/94";*/ 41 static char *rcsid = "$Id: tape.c,v 1.13 1994/09/23 14:27:57 mycroft Exp $"; 42 #endif /* not lint */ 43 44 #include <sys/param.h> 45 #include <sys/file.h> 46 #include <sys/ioctl.h> 47 #include <sys/mtio.h> 48 #include <sys/stat.h> 49 50 #include <ufs/ufs/dinode.h> 51 #include <protocols/dumprestore.h> 52 53 #include <errno.h> 54 #include <setjmp.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <unistd.h> 59 60 #include "restore.h" 61 #include "extern.h" 62 #include "pathnames.h" 63 64 static long fssize = MAXBSIZE; 65 static int mt = -1; 66 static int pipein = 0; 67 static char magtape[BUFSIZ]; 68 static int blkcnt; 69 static int numtrec; 70 static char *tapebuf; 71 static union u_spcl endoftapemark; 72 static long blksread; /* blocks read since last header */ 73 static long tpblksread = 0; /* TP_BSIZE blocks read */ 74 static long tapesread; 75 static jmp_buf restart; 76 static int gettingfile = 0; /* restart has a valid frame */ 77 static char *host = NULL; 78 79 static int ofile; 80 static char *map; 81 static char lnkbuf[MAXPATHLEN + 1]; 82 static int pathlen; 83 84 int oldinofmt; /* old inode format conversion required */ 85 int Bcvt; /* Swap Bytes (for CCI or sun) */ 86 static int Qcvt; /* Swap quads (for sun) */ 87 88 #define FLUSHTAPEBUF() blkcnt = ntrec + 1 89 90 static void accthdr __P((struct s_spcl *)); 91 static int checksum __P((int *)); 92 static void findinode __P((struct s_spcl *)); 93 static void findtapeblksize __P((void)); 94 static int gethead __P((struct s_spcl *)); 95 static void readtape __P((char *)); 96 static void setdumpnum __P((void)); 97 static u_long swabl __P((u_long)); 98 static u_char *swablong __P((u_char *, int)); 99 static u_char *swabshort __P((u_char *, int)); 100 static void terminateinput __P((void)); 101 static void xtrfile __P((char *, long)); 102 static void xtrlnkfile __P((char *, long)); 103 static void xtrlnkskip __P((char *, long)); 104 static void xtrmap __P((char *, long)); 105 static void xtrmapskip __P((char *, long)); 106 static void xtrskip __P((char *, long)); 107 108 /* 109 * Set up an input source 110 */ 111 void 112 setinput(source) 113 char *source; 114 { 115 FLUSHTAPEBUF(); 116 if (bflag) 117 newtapebuf(ntrec); 118 else 119 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC); 120 terminal = stdin; 121 122 #ifdef RRESTORE 123 if (strchr(source, ':')) { 124 host = source; 125 source = strchr(host, ':'); 126 *source++ = '\0'; 127 if (rmthost(host) == 0) 128 done(1); 129 } else 130 #endif 131 if (strcmp(source, "-") == 0) { 132 /* 133 * Since input is coming from a pipe we must establish 134 * our own connection to the terminal. 135 */ 136 terminal = fopen(_PATH_TTY, "r"); 137 if (terminal == NULL) { 138 (void)fprintf(stderr, "cannot open %s: %s\n", 139 _PATH_TTY, strerror(errno)); 140 terminal = fopen(_PATH_DEVNULL, "r"); 141 if (terminal == NULL) { 142 (void)fprintf(stderr, "cannot open %s: %s\n", 143 _PATH_DEVNULL, strerror(errno)); 144 done(1); 145 } 146 } 147 pipein++; 148 } 149 setuid(getuid()); /* no longer need or want root privileges */ 150 (void) strcpy(magtape, source); 151 } 152 153 void 154 newtapebuf(size) 155 long size; 156 { 157 static tapebufsize = -1; 158 159 ntrec = size; 160 if (size <= tapebufsize) 161 return; 162 if (tapebuf != NULL) 163 free(tapebuf); 164 tapebuf = malloc(size * TP_BSIZE); 165 if (tapebuf == NULL) { 166 fprintf(stderr, "Cannot allocate space for tape buffer\n"); 167 done(1); 168 } 169 tapebufsize = size; 170 } 171 172 /* 173 * Verify that the tape drive can be accessed and 174 * that it actually is a dump tape. 175 */ 176 void 177 setup() 178 { 179 int i, j, *ip; 180 struct stat stbuf; 181 182 vprintf(stdout, "Verify tape and initialize maps\n"); 183 #ifdef RRESTORE 184 if (host) 185 mt = rmtopen(magtape, 0); 186 else 187 #endif 188 if (pipein) 189 mt = 0; 190 else 191 mt = open(magtape, O_RDONLY, 0); 192 if (mt < 0) { 193 fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); 194 done(1); 195 } 196 volno = 1; 197 setdumpnum(); 198 FLUSHTAPEBUF(); 199 if (!pipein && !bflag) 200 findtapeblksize(); 201 if (gethead(&spcl) == FAIL) { 202 blkcnt--; /* push back this block */ 203 blksread--; 204 tpblksread--; 205 cvtflag++; 206 if (gethead(&spcl) == FAIL) { 207 fprintf(stderr, "Tape is not a dump tape\n"); 208 done(1); 209 } 210 fprintf(stderr, "Converting to new file system format.\n"); 211 } 212 if (pipein) { 213 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC; 214 endoftapemark.s_spcl.c_type = TS_END; 215 ip = (int *)&endoftapemark; 216 j = sizeof(union u_spcl) / sizeof(int); 217 i = 0; 218 do 219 i += *ip++; 220 while (--j); 221 endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 222 } 223 if (vflag || command == 't') 224 printdumpinfo(); 225 dumptime = spcl.c_ddate; 226 dumpdate = spcl.c_date; 227 if (stat(".", &stbuf) < 0) { 228 fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); 229 done(1); 230 } 231 if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE) 232 fssize = stbuf.st_blksize; 233 if (((fssize - 1) & fssize) != 0) { 234 fprintf(stderr, "bad block size %d\n", fssize); 235 done(1); 236 } 237 if (spcl.c_volume != 1) { 238 fprintf(stderr, "Tape is not volume 1 of the dump\n"); 239 done(1); 240 } 241 if (gethead(&spcl) == FAIL) { 242 dprintf(stdout, "header read failed at %d blocks\n", blksread); 243 panic("no header after volume mark!\n"); 244 } 245 findinode(&spcl); 246 if (spcl.c_type != TS_CLRI) { 247 fprintf(stderr, "Cannot find file removal list\n"); 248 done(1); 249 } 250 maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; 251 dprintf(stdout, "maxino = %d\n", maxino); 252 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 253 if (map == NULL) 254 panic("no memory for file removal list\n"); 255 clrimap = map; 256 curfile.action = USING; 257 getfile(xtrmap, xtrmapskip); 258 if (spcl.c_type != TS_BITS) { 259 fprintf(stderr, "Cannot find file dump list\n"); 260 done(1); 261 } 262 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 263 if (map == (char *)NULL) 264 panic("no memory for file dump list\n"); 265 dumpmap = map; 266 curfile.action = USING; 267 getfile(xtrmap, xtrmapskip); 268 } 269 270 /* 271 * Prompt user to load a new dump volume. 272 * "Nextvol" is the next suggested volume to use. 273 * This suggested volume is enforced when doing full 274 * or incremental restores, but can be overrridden by 275 * the user when only extracting a subset of the files. 276 */ 277 void 278 getvol(nextvol) 279 long nextvol; 280 { 281 long newvol, savecnt, wantnext, i; 282 union u_spcl tmpspcl; 283 # define tmpbuf tmpspcl.s_spcl 284 char buf[TP_BSIZE]; 285 286 if (nextvol == 1) { 287 tapesread = 0; 288 gettingfile = 0; 289 } 290 if (pipein) { 291 if (nextvol != 1) 292 panic("Changing volumes on pipe input?\n"); 293 if (volno == 1) 294 return; 295 goto gethdr; 296 } 297 savecnt = blksread; 298 again: 299 if (pipein) 300 done(1); /* pipes do not get a second chance */ 301 if (command == 'R' || command == 'r' || curfile.action != SKIP) { 302 newvol = nextvol; 303 wantnext = 1; 304 } else { 305 newvol = 0; 306 wantnext = 0; 307 } 308 while (newvol <= 0) { 309 if (tapesread == 0) { 310 fprintf(stderr, "%s%s%s%s%s", 311 "You have not read any tapes yet.\n", 312 "Unless you know which volume your", 313 " file(s) are on you should start\n", 314 "with the last volume and work", 315 " towards towards the first.\n"); 316 } else { 317 fprintf(stderr, "You have read volumes"); 318 strcpy(buf, ": "); 319 for (i = 1; i < 32; i++) 320 if (tapesread & (1 << i)) { 321 fprintf(stderr, "%s%d", buf, i); 322 strcpy(buf, ", "); 323 } 324 fprintf(stderr, "\n"); 325 } 326 do { 327 fprintf(stderr, "Specify next volume #: "); 328 (void) fflush(stderr); 329 (void) fgets(buf, BUFSIZ, terminal); 330 } while (!feof(terminal) && buf[0] == '\n'); 331 if (feof(terminal)) 332 done(1); 333 newvol = atoi(buf); 334 if (newvol <= 0) { 335 fprintf(stderr, 336 "Volume numbers are positive numerics\n"); 337 } 338 } 339 if (newvol == volno) { 340 tapesread |= 1 << volno; 341 return; 342 } 343 closemt(); 344 fprintf(stderr, "Mount tape volume %d\n", newvol); 345 fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); 346 fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); 347 (void) fflush(stderr); 348 (void) fgets(buf, BUFSIZ, terminal); 349 if (feof(terminal)) 350 done(1); 351 if (!strcmp(buf, "none\n")) { 352 terminateinput(); 353 return; 354 } 355 if (buf[0] != '\n') { 356 (void) strcpy(magtape, buf); 357 magtape[strlen(magtape) - 1] = '\0'; 358 } 359 #ifdef RRESTORE 360 if (host) 361 mt = rmtopen(magtape, 0); 362 else 363 #endif 364 mt = open(magtape, O_RDONLY, 0); 365 366 if (mt == -1) { 367 fprintf(stderr, "Cannot open %s\n", magtape); 368 volno = -1; 369 goto again; 370 } 371 gethdr: 372 volno = newvol; 373 setdumpnum(); 374 FLUSHTAPEBUF(); 375 if (gethead(&tmpbuf) == FAIL) { 376 dprintf(stdout, "header read failed at %d blocks\n", blksread); 377 fprintf(stderr, "tape is not dump tape\n"); 378 volno = 0; 379 goto again; 380 } 381 if (tmpbuf.c_volume != volno) { 382 fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume); 383 volno = 0; 384 goto again; 385 } 386 if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) { 387 fprintf(stderr, "Wrong dump date\n\tgot: %s", 388 ctime(&tmpbuf.c_date)); 389 fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); 390 volno = 0; 391 goto again; 392 } 393 tapesread |= 1 << volno; 394 blksread = savecnt; 395 /* 396 * If continuing from the previous volume, skip over any 397 * blocks read already at the end of the previous volume. 398 * 399 * If coming to this volume at random, skip to the beginning 400 * of the next record. 401 */ 402 dprintf(stdout, "read %ld recs, tape starts with %ld\n", 403 tpblksread, tmpbuf.c_firstrec); 404 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) { 405 if (!wantnext) { 406 tpblksread = tmpbuf.c_firstrec; 407 for (i = tmpbuf.c_count; i > 0; i--) 408 readtape(buf); 409 } else if (tmpbuf.c_firstrec > 0 && 410 tmpbuf.c_firstrec < tpblksread - 1) { 411 /* 412 * -1 since we've read the volume header 413 */ 414 i = tpblksread - tmpbuf.c_firstrec - 1; 415 dprintf(stderr, "Skipping %d duplicate record%s.\n", 416 i, i > 1 ? "s" : ""); 417 while (--i >= 0) 418 readtape(buf); 419 } 420 } 421 if (curfile.action == USING) { 422 if (volno == 1) 423 panic("active file into volume 1\n"); 424 return; 425 } 426 /* 427 * Skip up to the beginning of the next record 428 */ 429 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) 430 for (i = tmpbuf.c_count; i > 0; i--) 431 readtape(buf); 432 (void) gethead(&spcl); 433 findinode(&spcl); 434 if (gettingfile) { 435 gettingfile = 0; 436 longjmp(restart, 1); 437 } 438 } 439 440 /* 441 * Handle unexpected EOF. 442 */ 443 static void 444 terminateinput() 445 { 446 447 if (gettingfile && curfile.action == USING) { 448 printf("Warning: %s %s\n", 449 "End-of-input encountered while extracting", curfile.name); 450 } 451 curfile.name = "<name unknown>"; 452 curfile.action = UNKNOWN; 453 curfile.dip = NULL; 454 curfile.ino = maxino; 455 if (gettingfile) { 456 gettingfile = 0; 457 longjmp(restart, 1); 458 } 459 } 460 461 /* 462 * handle multiple dumps per tape by skipping forward to the 463 * appropriate one. 464 */ 465 static void 466 setdumpnum() 467 { 468 struct mtop tcom; 469 470 if (dumpnum == 1 || volno != 1) 471 return; 472 if (pipein) { 473 fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); 474 done(1); 475 } 476 tcom.mt_op = MTFSF; 477 tcom.mt_count = dumpnum - 1; 478 #ifdef RRESTORE 479 if (host) 480 rmtioctl(MTFSF, dumpnum - 1); 481 else 482 #endif 483 if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0) 484 fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno)); 485 } 486 487 void 488 printdumpinfo() 489 { 490 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date)); 491 fprintf(stdout, "Dumped from: %s", 492 (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate)); 493 if (spcl.c_host[0] == '\0') 494 return; 495 fprintf(stderr, "Level %d dump of %s on %s:%s\n", 496 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); 497 fprintf(stderr, "Label: %s\n", spcl.c_label); 498 } 499 500 int 501 extractfile(name) 502 char *name; 503 { 504 int mode; 505 struct timeval timep[2]; 506 struct entry *ep; 507 508 curfile.name = name; 509 curfile.action = USING; 510 timep[0].tv_sec = curfile.dip->di_atime.ts_sec; 511 timep[0].tv_usec = curfile.dip->di_atime.ts_nsec / 1000; 512 timep[1].tv_sec = curfile.dip->di_mtime.ts_sec; 513 timep[1].tv_usec = curfile.dip->di_mtime.ts_nsec / 1000; 514 mode = curfile.dip->di_mode; 515 switch (mode & IFMT) { 516 517 default: 518 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); 519 skipfile(); 520 return (FAIL); 521 522 case IFSOCK: 523 vprintf(stdout, "skipped socket %s\n", name); 524 skipfile(); 525 return (GOOD); 526 527 case IFDIR: 528 if (mflag) { 529 ep = lookupname(name); 530 if (ep == NULL || ep->e_flags & EXTRACT) 531 panic("unextracted directory %s\n", name); 532 skipfile(); 533 return (GOOD); 534 } 535 vprintf(stdout, "extract file %s\n", name); 536 return (genliteraldir(name, curfile.ino)); 537 538 case IFLNK: 539 lnkbuf[0] = '\0'; 540 pathlen = 0; 541 getfile(xtrlnkfile, xtrlnkskip); 542 if (pathlen == 0) { 543 vprintf(stdout, 544 "%s: zero length symbolic link (ignored)\n", name); 545 return (GOOD); 546 } 547 return (linkit(lnkbuf, name, SYMLINK)); 548 549 case IFIFO: 550 vprintf(stdout, "extract fifo %s\n", name); 551 if (Nflag) { 552 skipfile(); 553 return (GOOD); 554 } 555 if (mkfifo(name, mode) < 0) { 556 fprintf(stderr, "%s: cannot create fifo: %s\n", 557 name, strerror(errno)); 558 skipfile(); 559 return (FAIL); 560 } 561 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); 562 (void) chmod(name, mode); 563 skipfile(); 564 utimes(name, timep); 565 return (GOOD); 566 567 case IFCHR: 568 case IFBLK: 569 vprintf(stdout, "extract special file %s\n", name); 570 if (Nflag) { 571 skipfile(); 572 return (GOOD); 573 } 574 if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) { 575 fprintf(stderr, "%s: cannot create special file: %s\n", 576 name, strerror(errno)); 577 skipfile(); 578 return (FAIL); 579 } 580 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); 581 (void) chmod(name, mode); 582 skipfile(); 583 utimes(name, timep); 584 return (GOOD); 585 586 case IFREG: 587 vprintf(stdout, "extract file %s\n", name); 588 if (Nflag) { 589 skipfile(); 590 return (GOOD); 591 } 592 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 593 0666)) < 0) { 594 fprintf(stderr, "%s: cannot create file: %s\n", 595 name, strerror(errno)); 596 skipfile(); 597 return (FAIL); 598 } 599 (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid); 600 (void) fchmod(ofile, mode); 601 getfile(xtrfile, xtrskip); 602 (void) close(ofile); 603 utimes(name, timep); 604 return (GOOD); 605 } 606 /* NOTREACHED */ 607 } 608 609 /* 610 * skip over bit maps on the tape 611 */ 612 void 613 skipmaps() 614 { 615 616 while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) 617 skipfile(); 618 } 619 620 /* 621 * skip over a file on the tape 622 */ 623 void 624 skipfile() 625 { 626 627 curfile.action = SKIP; 628 getfile(xtrnull, xtrnull); 629 } 630 631 /* 632 * Extract a file from the tape. 633 * When an allocated block is found it is passed to the fill function; 634 * when an unallocated block (hole) is found, a zeroed buffer is passed 635 * to the skip function. 636 */ 637 void 638 getfile(fill, skip) 639 void (*fill) __P((char *, long)); 640 void (*skip) __P((char *, long)); 641 { 642 register int i; 643 int curblk = 0; 644 long size = spcl.c_dinode.di_size; 645 static char clearedbuf[MAXBSIZE]; 646 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 647 char junk[TP_BSIZE]; 648 649 if (spcl.c_type == TS_END) 650 panic("ran off end of tape\n"); 651 if (spcl.c_magic != NFS_MAGIC) 652 panic("not at beginning of a file\n"); 653 if (!gettingfile && setjmp(restart) != 0) 654 return; 655 gettingfile++; 656 loop: 657 for (i = 0; i < spcl.c_count; i++) { 658 if (spcl.c_addr[i]) { 659 readtape(&buf[curblk++][0]); 660 if (curblk == fssize / TP_BSIZE) { 661 (*fill)((char *)buf, size > TP_BSIZE ? 662 (long) (fssize) : 663 (curblk - 1) * TP_BSIZE + size); 664 curblk = 0; 665 } 666 } else { 667 if (curblk > 0) { 668 (*fill)((char *)buf, size > TP_BSIZE ? 669 (long) (curblk * TP_BSIZE) : 670 (curblk - 1) * TP_BSIZE + size); 671 curblk = 0; 672 } 673 (*skip)(clearedbuf, size > TP_BSIZE ? 674 (long) TP_BSIZE : size); 675 } 676 if ((size -= TP_BSIZE) <= 0) { 677 for (i++; i < spcl.c_count; i++) 678 if (spcl.c_addr[i]) 679 readtape(junk); 680 break; 681 } 682 } 683 if (gethead(&spcl) == GOOD && size > 0) { 684 if (spcl.c_type == TS_ADDR) 685 goto loop; 686 dprintf(stdout, 687 "Missing address (header) block for %s at %d blocks\n", 688 curfile.name, blksread); 689 } 690 if (curblk > 0) 691 (*fill)((char *)buf, (curblk * TP_BSIZE) + size); 692 findinode(&spcl); 693 gettingfile = 0; 694 } 695 696 /* 697 * Write out the next block of a file. 698 */ 699 static void 700 xtrfile(buf, size) 701 char *buf; 702 long size; 703 { 704 705 if (Nflag) 706 return; 707 if (write(ofile, buf, (int) size) == -1) { 708 fprintf(stderr, 709 "write error extracting inode %d, name %s\nwrite: %s\n", 710 curfile.ino, curfile.name, strerror(errno)); 711 done(1); 712 } 713 } 714 715 /* 716 * Skip over a hole in a file. 717 */ 718 /* ARGSUSED */ 719 static void 720 xtrskip(buf, size) 721 char *buf; 722 long size; 723 { 724 725 if (lseek(ofile, size, SEEK_CUR) == -1) { 726 fprintf(stderr, 727 "seek error extracting inode %d, name %s\nlseek: %s\n", 728 curfile.ino, curfile.name, strerror(errno)); 729 done(1); 730 } 731 } 732 733 /* 734 * Collect the next block of a symbolic link. 735 */ 736 static void 737 xtrlnkfile(buf, size) 738 char *buf; 739 long size; 740 { 741 742 pathlen += size; 743 if (pathlen > MAXPATHLEN) { 744 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", 745 curfile.name, lnkbuf, buf, pathlen); 746 done(1); 747 } 748 (void) strcat(lnkbuf, buf); 749 } 750 751 /* 752 * Skip over a hole in a symbolic link (should never happen). 753 */ 754 /* ARGSUSED */ 755 static void 756 xtrlnkskip(buf, size) 757 char *buf; 758 long size; 759 { 760 761 fprintf(stderr, "unallocated block in symbolic link %s\n", 762 curfile.name); 763 done(1); 764 } 765 766 /* 767 * Collect the next block of a bit map. 768 */ 769 static void 770 xtrmap(buf, size) 771 char *buf; 772 long size; 773 { 774 775 memcpy(map, buf, size); 776 map += size; 777 } 778 779 /* 780 * Skip over a hole in a bit map (should never happen). 781 */ 782 /* ARGSUSED */ 783 static void 784 xtrmapskip(buf, size) 785 char *buf; 786 long size; 787 { 788 789 panic("hole in map\n"); 790 map += size; 791 } 792 793 /* 794 * Noop, when an extraction function is not needed. 795 */ 796 /* ARGSUSED */ 797 void 798 xtrnull(buf, size) 799 char *buf; 800 long size; 801 { 802 803 return; 804 } 805 806 /* 807 * Read TP_BSIZE blocks from the input. 808 * Handle read errors, and end of media. 809 */ 810 static void 811 readtape(buf) 812 char *buf; 813 { 814 long rd, newvol, i; 815 int cnt, seek_failed; 816 817 if (blkcnt < numtrec) { 818 memcpy(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 819 blksread++; 820 tpblksread++; 821 return; 822 } 823 for (i = 0; i < ntrec; i++) 824 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 825 if (numtrec == 0) 826 numtrec = ntrec; 827 cnt = ntrec * TP_BSIZE; 828 rd = 0; 829 getmore: 830 #ifdef RRESTORE 831 if (host) 832 i = rmtread(&tapebuf[rd], cnt); 833 else 834 #endif 835 i = read(mt, &tapebuf[rd], cnt); 836 /* 837 * Check for mid-tape short read error. 838 * If found, skip rest of buffer and start with the next. 839 */ 840 if (!pipein && numtrec < ntrec && i > 0) { 841 dprintf(stdout, "mid-media short read error.\n"); 842 numtrec = ntrec; 843 } 844 /* 845 * Handle partial block read. 846 */ 847 if (pipein && i == 0 && rd > 0) 848 i = rd; 849 else if (i > 0 && i != ntrec * TP_BSIZE) { 850 if (pipein) { 851 rd += i; 852 cnt -= i; 853 if (cnt > 0) 854 goto getmore; 855 i = rd; 856 } else { 857 /* 858 * Short read. Process the blocks read. 859 */ 860 if (i % TP_BSIZE != 0) 861 vprintf(stdout, 862 "partial block read: %d should be %d\n", 863 i, ntrec * TP_BSIZE); 864 numtrec = i / TP_BSIZE; 865 } 866 } 867 /* 868 * Handle read error. 869 */ 870 if (i < 0) { 871 fprintf(stderr, "Tape read error while "); 872 switch (curfile.action) { 873 default: 874 fprintf(stderr, "trying to set up tape\n"); 875 break; 876 case UNKNOWN: 877 fprintf(stderr, "trying to resynchronize\n"); 878 break; 879 case USING: 880 fprintf(stderr, "restoring %s\n", curfile.name); 881 break; 882 case SKIP: 883 fprintf(stderr, "skipping over inode %d\n", 884 curfile.ino); 885 break; 886 } 887 if (!yflag && !reply("continue")) 888 done(1); 889 i = ntrec * TP_BSIZE; 890 memset(tapebuf, 0, i); 891 #ifdef RRESTORE 892 if (host) 893 seek_failed = (rmtseek(i, 1) < 0); 894 else 895 #endif 896 seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1); 897 898 if (seek_failed) { 899 fprintf(stderr, 900 "continuation failed: %s\n", strerror(errno)); 901 done(1); 902 } 903 } 904 /* 905 * Handle end of tape. 906 */ 907 if (i == 0) { 908 vprintf(stdout, "End-of-tape encountered\n"); 909 if (!pipein) { 910 newvol = volno + 1; 911 volno = 0; 912 numtrec = 0; 913 getvol(newvol); 914 readtape(buf); 915 return; 916 } 917 if (rd % TP_BSIZE != 0) 918 panic("partial block read: %d should be %d\n", 919 rd, ntrec * TP_BSIZE); 920 terminateinput(); 921 memcpy(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); 922 } 923 blkcnt = 0; 924 memcpy(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 925 blksread++; 926 tpblksread++; 927 } 928 929 static void 930 findtapeblksize() 931 { 932 register long i; 933 934 for (i = 0; i < ntrec; i++) 935 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 936 blkcnt = 0; 937 #ifdef RRESTORE 938 if (host) 939 i = rmtread(tapebuf, ntrec * TP_BSIZE); 940 else 941 #endif 942 i = read(mt, tapebuf, ntrec * TP_BSIZE); 943 944 if (i <= 0) { 945 fprintf(stderr, "tape read error: %s\n", strerror(errno)); 946 done(1); 947 } 948 if (i % TP_BSIZE != 0) { 949 fprintf(stderr, "Tape block size (%d) %s (%d)\n", 950 i, "is not a multiple of dump block size", TP_BSIZE); 951 done(1); 952 } 953 ntrec = i / TP_BSIZE; 954 numtrec = ntrec; 955 vprintf(stdout, "Tape block size is %d\n", ntrec); 956 } 957 958 void 959 closemt() 960 { 961 962 if (mt < 0) 963 return; 964 #ifdef RRESTORE 965 if (host) 966 rmtclose(); 967 else 968 #endif 969 (void) close(mt); 970 } 971 972 /* 973 * Read the next block from the tape. 974 * Check to see if it is one of several vintage headers. 975 * If it is an old style header, convert it to a new style header. 976 * If it is not any valid header, return an error. 977 */ 978 static int 979 gethead(buf) 980 struct s_spcl *buf; 981 { 982 long i; 983 union { 984 quad_t qval; 985 long val[2]; 986 } qcvt; 987 union u_ospcl { 988 char dummy[TP_BSIZE]; 989 struct s_ospcl { 990 long c_type; 991 long c_date; 992 long c_ddate; 993 long c_volume; 994 long c_tapea; 995 u_short c_inumber; 996 long c_magic; 997 long c_checksum; 998 struct odinode { 999 unsigned short odi_mode; 1000 u_short odi_nlink; 1001 u_short odi_uid; 1002 u_short odi_gid; 1003 long odi_size; 1004 long odi_rdev; 1005 char odi_addr[36]; 1006 long odi_atime; 1007 long odi_mtime; 1008 long odi_ctime; 1009 } c_dinode; 1010 long c_count; 1011 char c_addr[256]; 1012 } s_ospcl; 1013 } u_ospcl; 1014 1015 if (!cvtflag) { 1016 readtape((char *)buf); 1017 if (buf->c_magic != NFS_MAGIC) { 1018 if (swabl(buf->c_magic) != NFS_MAGIC) 1019 return (FAIL); 1020 if (!Bcvt) { 1021 vprintf(stdout, "Note: Doing Byte swapping\n"); 1022 Bcvt = 1; 1023 } 1024 } 1025 if (checksum((int *)buf) == FAIL) 1026 return (FAIL); 1027 if (Bcvt) 1028 swabst((u_char *)"8l4s31l", (u_char *)buf); 1029 goto good; 1030 } 1031 readtape((char *)(&u_ospcl.s_ospcl)); 1032 memset(buf, 0, (long)TP_BSIZE); 1033 buf->c_type = u_ospcl.s_ospcl.c_type; 1034 buf->c_date = u_ospcl.s_ospcl.c_date; 1035 buf->c_ddate = u_ospcl.s_ospcl.c_ddate; 1036 buf->c_volume = u_ospcl.s_ospcl.c_volume; 1037 buf->c_tapea = u_ospcl.s_ospcl.c_tapea; 1038 buf->c_inumber = u_ospcl.s_ospcl.c_inumber; 1039 buf->c_checksum = u_ospcl.s_ospcl.c_checksum; 1040 buf->c_magic = u_ospcl.s_ospcl.c_magic; 1041 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode; 1042 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink; 1043 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid; 1044 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid; 1045 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size; 1046 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev; 1047 buf->c_dinode.di_atime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_atime; 1048 buf->c_dinode.di_mtime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime; 1049 buf->c_dinode.di_ctime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime; 1050 buf->c_count = u_ospcl.s_ospcl.c_count; 1051 memcpy(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256); 1052 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC || 1053 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL) 1054 return(FAIL); 1055 buf->c_magic = NFS_MAGIC; 1056 1057 good: 1058 if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) && 1059 (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) { 1060 qcvt.qval = buf->c_dinode.di_size; 1061 if (qcvt.val[0] || qcvt.val[1]) { 1062 printf("Note: Doing Quad swapping\n"); 1063 Qcvt = 1; 1064 } 1065 } 1066 if (Qcvt) { 1067 qcvt.qval = buf->c_dinode.di_size; 1068 i = qcvt.val[1]; 1069 qcvt.val[1] = qcvt.val[0]; 1070 qcvt.val[0] = i; 1071 buf->c_dinode.di_size = qcvt.qval; 1072 } 1073 1074 switch (buf->c_type) { 1075 1076 case TS_CLRI: 1077 case TS_BITS: 1078 /* 1079 * Have to patch up missing information in bit map headers 1080 */ 1081 buf->c_inumber = 0; 1082 buf->c_dinode.di_size = buf->c_count * TP_BSIZE; 1083 for (i = 0; i < buf->c_count; i++) 1084 buf->c_addr[i]++; 1085 break; 1086 1087 case TS_TAPE: 1088 if ((buf->c_flags & DR_NEWINODEFMT) == 0) 1089 oldinofmt = 1; 1090 /* fall through */ 1091 case TS_END: 1092 buf->c_inumber = 0; 1093 break; 1094 1095 case TS_INODE: 1096 case TS_ADDR: 1097 break; 1098 1099 default: 1100 panic("gethead: unknown inode type %d\n", buf->c_type); 1101 break; 1102 } 1103 /* 1104 * If we are restoring a filesystem with old format inodes, 1105 * copy the uid/gid to the new location. 1106 */ 1107 if (oldinofmt) { 1108 buf->c_dinode.di_uid = buf->c_dinode.di_ouid; 1109 buf->c_dinode.di_gid = buf->c_dinode.di_ogid; 1110 } 1111 if (dflag) 1112 accthdr(buf); 1113 return(GOOD); 1114 } 1115 1116 /* 1117 * Check that a header is where it belongs and predict the next header 1118 */ 1119 static void 1120 accthdr(header) 1121 struct s_spcl *header; 1122 { 1123 static ino_t previno = 0x7fffffff; 1124 static int prevtype; 1125 static long predict; 1126 long blks, i; 1127 1128 if (header->c_type == TS_TAPE) { 1129 fprintf(stderr, "Volume header (%s inode format) ", 1130 oldinofmt ? "old" : "new"); 1131 if (header->c_firstrec) 1132 fprintf(stderr, "begins with record %d", 1133 header->c_firstrec); 1134 fprintf(stderr, "\n"); 1135 previno = 0x7fffffff; 1136 return; 1137 } 1138 if (previno == 0x7fffffff) 1139 goto newcalc; 1140 switch (prevtype) { 1141 case TS_BITS: 1142 fprintf(stderr, "Dump mask header"); 1143 break; 1144 case TS_CLRI: 1145 fprintf(stderr, "Remove mask header"); 1146 break; 1147 case TS_INODE: 1148 fprintf(stderr, "File header, ino %d", previno); 1149 break; 1150 case TS_ADDR: 1151 fprintf(stderr, "File continuation header, ino %d", previno); 1152 break; 1153 case TS_END: 1154 fprintf(stderr, "End of tape header"); 1155 break; 1156 } 1157 if (predict != blksread - 1) 1158 fprintf(stderr, "; predicted %d blocks, got %d blocks", 1159 predict, blksread - 1); 1160 fprintf(stderr, "\n"); 1161 newcalc: 1162 blks = 0; 1163 if (header->c_type != TS_END) 1164 for (i = 0; i < header->c_count; i++) 1165 if (header->c_addr[i] != 0) 1166 blks++; 1167 predict = blks; 1168 blksread = 0; 1169 prevtype = header->c_type; 1170 previno = header->c_inumber; 1171 } 1172 1173 /* 1174 * Find an inode header. 1175 * Complain if had to skip, and complain is set. 1176 */ 1177 static void 1178 findinode(header) 1179 struct s_spcl *header; 1180 { 1181 static long skipcnt = 0; 1182 long i; 1183 char buf[TP_BSIZE]; 1184 1185 curfile.name = "<name unknown>"; 1186 curfile.action = UNKNOWN; 1187 curfile.dip = NULL; 1188 curfile.ino = 0; 1189 do { 1190 if (header->c_magic != NFS_MAGIC) { 1191 skipcnt++; 1192 while (gethead(header) == FAIL || 1193 header->c_date != dumpdate) 1194 skipcnt++; 1195 } 1196 switch (header->c_type) { 1197 1198 case TS_ADDR: 1199 /* 1200 * Skip up to the beginning of the next record 1201 */ 1202 for (i = 0; i < header->c_count; i++) 1203 if (header->c_addr[i]) 1204 readtape(buf); 1205 while (gethead(header) == FAIL || 1206 header->c_date != dumpdate) 1207 skipcnt++; 1208 break; 1209 1210 case TS_INODE: 1211 curfile.dip = &header->c_dinode; 1212 curfile.ino = header->c_inumber; 1213 break; 1214 1215 case TS_END: 1216 curfile.ino = maxino; 1217 break; 1218 1219 case TS_CLRI: 1220 curfile.name = "<file removal list>"; 1221 break; 1222 1223 case TS_BITS: 1224 curfile.name = "<file dump list>"; 1225 break; 1226 1227 case TS_TAPE: 1228 panic("unexpected tape header\n"); 1229 /* NOTREACHED */ 1230 1231 default: 1232 panic("unknown tape header type %d\n", spcl.c_type); 1233 /* NOTREACHED */ 1234 1235 } 1236 } while (header->c_type == TS_ADDR); 1237 if (skipcnt > 0) 1238 fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt); 1239 skipcnt = 0; 1240 } 1241 1242 static int 1243 checksum(buf) 1244 register int *buf; 1245 { 1246 register int i, j; 1247 1248 j = sizeof(union u_spcl) / sizeof(int); 1249 i = 0; 1250 if(!Bcvt) { 1251 do 1252 i += *buf++; 1253 while (--j); 1254 } else { 1255 /* What happens if we want to read restore tapes 1256 for a 16bit int machine??? */ 1257 do 1258 i += swabl(*buf++); 1259 while (--j); 1260 } 1261 1262 if (i != CHECKSUM) { 1263 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i, 1264 curfile.ino, curfile.name); 1265 return(FAIL); 1266 } 1267 return(GOOD); 1268 } 1269 1270 #ifdef RRESTORE 1271 #if __STDC__ 1272 #include <stdarg.h> 1273 #else 1274 #include <varargs.h> 1275 #endif 1276 1277 void 1278 #if __STDC__ 1279 msg(const char *fmt, ...) 1280 #else 1281 msg(fmt, va_alist) 1282 char *fmt; 1283 va_dcl 1284 #endif 1285 { 1286 va_list ap; 1287 #if __STDC__ 1288 va_start(ap, fmt); 1289 #else 1290 va_start(ap); 1291 #endif 1292 (void)vfprintf(stderr, fmt, ap); 1293 va_end(ap); 1294 } 1295 #endif /* RRESTORE */ 1296 1297 static u_char * 1298 swabshort(sp, n) 1299 register u_char *sp; 1300 register int n; 1301 { 1302 char c; 1303 1304 while (--n >= 0) { 1305 c = sp[0]; sp[0] = sp[1]; sp[1] = c; 1306 sp += 2; 1307 } 1308 return (sp); 1309 } 1310 1311 static u_char * 1312 swablong(sp, n) 1313 register u_char *sp; 1314 register int n; 1315 { 1316 char c; 1317 1318 while (--n >= 0) { 1319 c = sp[0]; sp[0] = sp[3]; sp[3] = c; 1320 c = sp[2]; sp[2] = sp[1]; sp[1] = c; 1321 sp += 4; 1322 } 1323 return (sp); 1324 } 1325 1326 void 1327 swabst(cp, sp) 1328 register u_char *cp, *sp; 1329 { 1330 int n = 0; 1331 1332 while (*cp) { 1333 switch (*cp) { 1334 case '0': case '1': case '2': case '3': case '4': 1335 case '5': case '6': case '7': case '8': case '9': 1336 n = (n * 10) + (*cp++ - '0'); 1337 continue; 1338 1339 case 's': case 'w': case 'h': 1340 if (n == 0) 1341 n = 1; 1342 sp = swabshort(sp, n); 1343 break; 1344 1345 case 'l': 1346 if (n == 0) 1347 n = 1; 1348 sp = swablong(sp, n); 1349 break; 1350 1351 default: /* Any other character, like 'b' counts as byte. */ 1352 if (n == 0) 1353 n = 1; 1354 sp += n; 1355 break; 1356 } 1357 cp++; 1358 n = 0; 1359 } 1360 } 1361 1362 static u_long 1363 swabl(x) 1364 u_long x; 1365 { 1366 swabst((u_char *)"l", (u_char *)&x); 1367 return (x); 1368 } 1369