1: /*
   2:  * Copyright (c) 1980 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: char copyright[] =
   9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\
  10:  All rights reserved.\n";
  11: #endif not lint
  12: 
  13: #ifndef lint
  14: static char sccsid[] = "@(#)tar.c	5.7 (Berkeley) 4/26/86";
  15: #endif not lint
  16: 
  17: /*
  18:  * Tape Archival Program
  19:  */
  20: #include <stdio.h>
  21: #include <sys/param.h>
  22: #include <sys/stat.h>
  23: #include <sys/dir.h>
  24: #include <sys/ioctl.h>
  25: #include <sys/mtio.h>
  26: #include <sys/time.h>
  27: #include <signal.h>
  28: #include <errno.h>
  29: #include <fcntl.h>
  30: 
  31: #define TBLOCK  512
  32: #define NBLOCK  20
  33: #define NAMSIZ  100
  34: 
  35: #define writetape(b)    writetbuf(b, 1)
  36: #define min(a,b)  ((a) < (b) ? (a) : (b))
  37: #define max(a,b)  ((a) > (b) ? (a) : (b))
  38: 
  39: union hblock {
  40:     char dummy[TBLOCK];
  41:     struct header {
  42:         char name[NAMSIZ];
  43:         char mode[8];
  44:         char uid[8];
  45:         char gid[8];
  46:         char size[12];
  47:         char mtime[12];
  48:         char chksum[8];
  49:         char linkflag;
  50:         char linkname[NAMSIZ];
  51:     } dbuf;
  52: };
  53: 
  54: struct linkbuf {
  55:     ino_t   inum;
  56:     dev_t   devnum;
  57:     int count;
  58:     char    pathname[NAMSIZ];
  59:     struct  linkbuf *nextp;
  60: };
  61: 
  62: union   hblock dblock;
  63: union   hblock *tbuf;
  64: struct  linkbuf *ihead;
  65: struct  stat stbuf;
  66: 
  67: int rflag;
  68: int xflag;
  69: int vflag;
  70: int tflag;
  71: int cflag;
  72: int mflag;
  73: int fflag;
  74: int iflag;
  75: int oflag;
  76: int pflag;
  77: int wflag;
  78: int hflag;
  79: int Bflag;
  80: int Fflag;
  81: 
  82: int mt;
  83: int term;
  84: int chksum;
  85: int recno;
  86: int first;
  87: int prtlinkerr;
  88: int freemem = 1;
  89: int nblock = 0;
  90: int onintr();
  91: int onquit();
  92: int onhup();
  93: #ifdef notdef
  94: int onterm();
  95: #endif
  96: 
  97: daddr_t low;
  98: daddr_t high;
  99: daddr_t bsrch();
 100: 
 101: FILE    *vfile = stdout;
 102: FILE    *tfile;
 103: char    tname[] = "/tmp/tarXXXXXX";
 104: char    *usefile;
 105: char    magtape[] = "/dev/rmt8";
 106: char    *malloc();
 107: long    time();
 108: off_t   lseek();
 109: char    *mktemp();
 110: char    *sprintf();
 111: char    *strcat();
 112: char    *strcpy();
 113: char    *rindex();
 114: char    *getcwd();
 115: char    *getwd();
 116: char    *getmem();
 117: 
 118: main(argc, argv)
 119: int argc;
 120: char    *argv[];
 121: {
 122:     char *cp;
 123: 
 124:     if (argc < 2)
 125:         usage();
 126: 
 127:     tfile = NULL;
 128:     usefile =  magtape;
 129:     argv[argc] = 0;
 130:     argv++;
 131:     for (cp = *argv++; *cp; cp++)
 132:         switch(*cp) {
 133: 
 134:         case 'f':
 135:             if (*argv == 0) {
 136:                 fprintf(stderr,
 137:             "tar: tapefile must be specified with 'f' option\n");
 138:                 usage();
 139:             }
 140:             usefile = *argv++;
 141:             fflag++;
 142:             break;
 143: 
 144:         case 'c':
 145:             cflag++;
 146:             rflag++;
 147:             break;
 148: 
 149:         case 'o':
 150:             oflag++;
 151:             break;
 152: 
 153:         case 'p':
 154:             pflag++;
 155:             break;
 156: 
 157:         case 'u':
 158:             mktemp(tname);
 159:             if ((tfile = fopen(tname, "w")) == NULL) {
 160:                 fprintf(stderr,
 161:                  "tar: cannot create temporary file (%s)\n",
 162:                  tname);
 163:                 done(1);
 164:             }
 165:             fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n");
 166:             /*FALL THRU*/
 167: 
 168:         case 'r':
 169:             rflag++;
 170:             break;
 171: 
 172:         case 'v':
 173:             vflag++;
 174:             break;
 175: 
 176:         case 'w':
 177:             wflag++;
 178:             break;
 179: 
 180:         case 'x':
 181:             xflag++;
 182:             break;
 183: 
 184:         case 't':
 185:             tflag++;
 186:             break;
 187: 
 188:         case 'm':
 189:             mflag++;
 190:             break;
 191: 
 192:         case '-':
 193:             break;
 194: 
 195:         case '0':
 196:         case '1':
 197:         case '4':
 198:         case '5':
 199:         case '7':
 200:         case '8':
 201:             magtape[8] = *cp;
 202:             usefile = magtape;
 203:             break;
 204: 
 205:         case 'b':
 206:             if (*argv == 0) {
 207:                 fprintf(stderr,
 208:             "tar: blocksize must be specified with 'b' option\n");
 209:                 usage();
 210:             }
 211:             nblock = atoi(*argv);
 212:             if (nblock <= 0) {
 213:                 fprintf(stderr,
 214:                     "tar: invalid blocksize \"%s\"\n", *argv);
 215:                 done(1);
 216:             }
 217:             argv++;
 218:             break;
 219: 
 220:         case 'l':
 221:             prtlinkerr++;
 222:             break;
 223: 
 224:         case 'h':
 225:             hflag++;
 226:             break;
 227: 
 228:         case 'i':
 229:             iflag++;
 230:             break;
 231: 
 232:         case 'B':
 233:             Bflag++;
 234:             break;
 235: 
 236:         case 'F':
 237:             Fflag++;
 238:             break;
 239: 
 240:         default:
 241:             fprintf(stderr, "tar: %c: unknown option\n", *cp);
 242:             usage();
 243:         }
 244: 
 245:     if (!rflag && !xflag && !tflag)
 246:         usage();
 247:     if (rflag) {
 248:         if (cflag && tfile != NULL)
 249:             usage();
 250:         if (signal(SIGINT, SIG_IGN) != SIG_IGN)
 251:             (void) signal(SIGINT, onintr);
 252:         if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
 253:             (void) signal(SIGHUP, onhup);
 254:         if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
 255:             (void) signal(SIGQUIT, onquit);
 256: #ifdef notdef
 257:         if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
 258:             (void) signal(SIGTERM, onterm);
 259: #endif
 260:         mt = openmt(usefile, 1);
 261:         dorep(argv);
 262:         done(0);
 263:     }
 264:     mt = openmt(usefile, 0);
 265:     if (xflag)
 266:         doxtract(argv);
 267:     else
 268:         dotable(argv);
 269:     done(0);
 270: }
 271: 
 272: usage()
 273: {
 274:     fprintf(stderr,
 275: "tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n");
 276:     done(1);
 277: }
 278: 
 279: int
 280: openmt(tape, writing)
 281:     char *tape;
 282:     int writing;
 283: {
 284: 
 285:     if (strcmp(tape, "-") == 0) {
 286:         /*
 287: 		 * Read from standard input or write to standard output.
 288: 		 */
 289:         if (writing) {
 290:             if (cflag == 0) {
 291:                 fprintf(stderr,
 292:              "tar: can only create standard output archives\n");
 293:                 done(1);
 294:             }
 295:             vfile = stderr;
 296:             setlinebuf(vfile);
 297:             mt = dup(1);
 298:         } else {
 299:             mt = dup(0);
 300:             Bflag++;
 301:         }
 302:     } else {
 303:         /*
 304: 		 * Use file or tape on local machine.
 305: 		 */
 306:         if (writing) {
 307:             if (cflag)
 308:                 mt = open(tape, O_RDWR|O_CREAT|O_TRUNC, 0666);
 309:             else
 310:                 mt = open(tape, O_RDWR);
 311:         } else
 312:             mt = open(tape, O_RDONLY);
 313:         if (mt < 0) {
 314:             fprintf(stderr, "tar: ");
 315:             perror(tape);
 316:             done(1);
 317:         }
 318:     }
 319:     return(mt);
 320: }
 321: 
 322: dorep(argv)
 323:     char *argv[];
 324: {
 325:     register char *cp, *cp2;
 326:     char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent;
 327: 
 328:     if (!cflag) {
 329:         getdir();
 330:         do {
 331:             passtape();
 332:             if (term)
 333:                 done(0);
 334:             getdir();
 335:         } while (!endtape());
 336:         backtape();
 337:         if (tfile != NULL) {
 338:             char buf[200];
 339: 
 340:             sprintf(buf,
 341: "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s",
 342:                 tname, tname, tname, tname, tname, tname);
 343:             fflush(tfile);
 344:             system(buf);
 345:             freopen(tname, "r", tfile);
 346:             fstat(fileno(tfile), &stbuf);
 347:             high = stbuf.st_size;
 348:         }
 349:     }
 350: 
 351:     (void) getcwd(wdir);
 352:     while (*argv && ! term) {
 353:         cp2 = *argv;
 354:         if (!strcmp(cp2, "-C") && argv[1]) {
 355:             argv++;
 356:             if (chdir(*argv) < 0) {
 357:                 fprintf(stderr, "tar: can't change directories to ");
 358:                 perror(*argv);
 359:             } else
 360:                 (void) getcwd(wdir);
 361:             argv++;
 362:             continue;
 363:         }
 364: 
 365:         if (*argv[0] == '/'){
 366:             parent = "";
 367:         } else {
 368:             parent = wdir;
 369:         }
 370: 
 371:         for (cp = *argv; *cp; cp++)
 372:             if (*cp == '/')
 373:                 cp2 = cp;
 374:         if (cp2 != *argv) {
 375:             *cp2 = '\0';
 376:             if (chdir(*argv) < 0) {
 377:                 fprintf(stderr, "tar: can't change directories to ");
 378:                 perror(*argv);
 379:                 continue;
 380:             }
 381:             parent = getcwd(tempdir);
 382:             *cp2 = '/';
 383:             cp2++;
 384:         }
 385:         putfile(*argv++, cp2, parent);
 386:         if (chdir(wdir) < 0) {
 387:             fprintf(stderr, "tar: cannot change back?: ");
 388:             perror(wdir);
 389:         }
 390:     }
 391:     putempty();
 392:     putempty();
 393:     flushtape();
 394:     if (prtlinkerr == 0)
 395:         return;
 396:     for (; ihead != NULL; ihead = ihead->nextp) {
 397:         if (ihead->count == 0)
 398:             continue;
 399:         fprintf(stderr, "tar: missing links to %s\n", ihead->pathname);
 400:     }
 401: }
 402: 
 403: endtape()
 404: {
 405:     return (dblock.dbuf.name[0] == '\0');
 406: }
 407: 
 408: getdir()
 409: {
 410:     register struct stat *sp;
 411:     int i;
 412: 
 413: top:
 414:     readtape((char *)&dblock);
 415:     if (dblock.dbuf.name[0] == '\0')
 416:         return;
 417:     sp = &stbuf;
 418:     sscanf(dblock.dbuf.mode, "%o", &i);
 419:     sp->st_mode = i;
 420:     sscanf(dblock.dbuf.uid, "%o", &i);
 421:     sp->st_uid = i;
 422:     sscanf(dblock.dbuf.gid, "%o", &i);
 423:     sp->st_gid = i;
 424:     sscanf(dblock.dbuf.size, "%lo", &sp->st_size);
 425:     sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime);
 426:     sscanf(dblock.dbuf.chksum, "%o", &chksum);
 427:     if (chksum != (i = checksum())) {
 428:         fprintf(stderr, "tar: directory checksum error (%d != %d)\n",
 429:             chksum, i);
 430:         if (iflag)
 431:             goto top;
 432:         done(2);
 433:     }
 434:     if (tfile != NULL)
 435:         fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime);
 436: }
 437: 
 438: passtape()
 439: {
 440:     long blocks;
 441:     char *bufp;
 442: 
 443:     if (dblock.dbuf.linkflag == '1')
 444:         return;
 445:     blocks = stbuf.st_size;
 446:     blocks += TBLOCK-1;
 447:     blocks /= TBLOCK;
 448: 
 449:     while (blocks-- > 0)
 450:         (void) readtbuf(&bufp, TBLOCK);
 451: }
 452: 
 453: putfile(longname, shortname, parent)
 454:     char *longname;
 455:     char *shortname;
 456:     char *parent;
 457: {
 458:     int infile = 0;
 459:     long blocks;
 460:     char buf[TBLOCK];
 461:     char *bigbuf;
 462:     register char *cp;
 463:     struct direct *dp;
 464:     DIR *dirp;
 465:     register int i;
 466:     long l;
 467:     char newparent[NAMSIZ+64];
 468:     extern int errno;
 469:     int maxread;
 470:     int hint;       /* amount to write to get "in sync" */
 471: 
 472:     if (!hflag)
 473:         i = lstat(shortname, &stbuf);
 474:     else
 475:         i = stat(shortname, &stbuf);
 476:     if (i < 0) {
 477:         fprintf(stderr, "tar: ");
 478:         perror(longname);
 479:         return;
 480:     }
 481:     if (tfile != NULL && checkupdate(longname) == 0)
 482:         return;
 483:     if (checkw('r', longname) == 0)
 484:         return;
 485:     if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0)
 486:         return;
 487: 
 488:     switch (stbuf.st_mode & S_IFMT) {
 489:     case S_IFDIR:
 490:         for (i = 0, cp = buf; *cp++ = longname[i++];)
 491:             ;
 492:         *--cp = '/';
 493:         *++cp = 0  ;
 494:         if (!oflag) {
 495:             if ((cp - buf) >= NAMSIZ) {
 496:                 fprintf(stderr, "tar: %s: file name too long\n",
 497:                     longname);
 498:                 return;
 499:             }
 500:             stbuf.st_size = 0;
 501:             tomodes(&stbuf);
 502:             strcpy(dblock.dbuf.name,buf);
 503:             sprintf(dblock.dbuf.chksum, "%6o", checksum());
 504:             (void) writetape((char *)&dblock);
 505:         }
 506:         sprintf(newparent, "%s/%s", parent, shortname);
 507:         if (chdir(shortname) < 0) {
 508:             perror(shortname);
 509:             return;
 510:         }
 511:         if ((dirp = opendir(".")) == NULL) {
 512:             fprintf(stderr, "tar: %s: directory read error\n",
 513:                 longname);
 514:             if (chdir(parent) < 0) {
 515:                 fprintf(stderr, "tar: cannot change back?: ");
 516:                 perror(parent);
 517:             }
 518:             return;
 519:         }
 520:         while ((dp = readdir(dirp)) != NULL && !term) {
 521:             if (dp->d_ino == 0)
 522:                 continue;
 523:             if (!strcmp(".", dp->d_name) ||
 524:                 !strcmp("..", dp->d_name))
 525:                 continue;
 526:             strcpy(cp, dp->d_name);
 527:             l = telldir(dirp);
 528:             closedir(dirp);
 529:             putfile(buf, cp, newparent);
 530:             dirp = opendir(".");
 531:             seekdir(dirp, l);
 532:         }
 533:         closedir(dirp);
 534:         if (chdir(parent) < 0) {
 535:             fprintf(stderr, "tar: cannot change back?: ");
 536:             perror(parent);
 537:         }
 538:         break;
 539: 
 540:     case S_IFLNK:
 541:         tomodes(&stbuf);
 542:         if (strlen(longname) >= NAMSIZ) {
 543:             fprintf(stderr, "tar: %s: file name too long\n",
 544:                 longname);
 545:             return;
 546:         }
 547:         strcpy(dblock.dbuf.name, longname);
 548:         if (stbuf.st_size + 1 >= NAMSIZ) {
 549:             fprintf(stderr, "tar: %s: symbolic link too long\n",
 550:                 longname);
 551:             return;
 552:         }
 553:         i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1);
 554:         if (i < 0) {
 555:             fprintf(stderr, "tar: can't read symbolic link ");
 556:             perror(longname);
 557:             return;
 558:         }
 559:         dblock.dbuf.linkname[i] = '\0';
 560:         dblock.dbuf.linkflag = '2';
 561:         if (vflag)
 562:             fprintf(vfile, "a %s symbolic link to %s\n",
 563:                 longname, dblock.dbuf.linkname);
 564:         sprintf(dblock.dbuf.size, "%11lo", 0L);
 565:         sprintf(dblock.dbuf.chksum, "%6o", checksum());
 566:         (void) writetape((char *)&dblock);
 567:         break;
 568: 
 569:     case S_IFREG:
 570:         if ((infile = open(shortname, 0)) < 0) {
 571:             fprintf(stderr, "tar: ");
 572:             perror(longname);
 573:             return;
 574:         }
 575:         tomodes(&stbuf);
 576:         if (strlen(longname) >= NAMSIZ) {
 577:             fprintf(stderr, "tar: %s: file name too long\n",
 578:                 longname);
 579:             close(infile);
 580:             return;
 581:         }
 582:         strcpy(dblock.dbuf.name, longname);
 583:         if (stbuf.st_nlink > 1) {
 584:             struct linkbuf *lp;
 585:             int found = 0;
 586: 
 587:             for (lp = ihead; lp != NULL; lp = lp->nextp)
 588:                 if (lp->inum == stbuf.st_ino &&
 589:                     lp->devnum == stbuf.st_dev) {
 590:                     found++;
 591:                     break;
 592:                 }
 593:             if (found) {
 594:                 strcpy(dblock.dbuf.linkname, lp->pathname);
 595:                 dblock.dbuf.linkflag = '1';
 596:                 sprintf(dblock.dbuf.chksum, "%6o", checksum());
 597:                 (void) writetape( (char *) &dblock);
 598:                 if (vflag)
 599:                     fprintf(vfile, "a %s link to %s\n",
 600:                         longname, lp->pathname);
 601:                 lp->count--;
 602:                 close(infile);
 603:                 return;
 604:             }
 605:             lp = (struct linkbuf *) getmem(sizeof(*lp));
 606:             if (lp != NULL) {
 607:                 lp->nextp = ihead;
 608:                 ihead = lp;
 609:                 lp->inum = stbuf.st_ino;
 610:                 lp->devnum = stbuf.st_dev;
 611:                 lp->count = stbuf.st_nlink - 1;
 612:                 strcpy(lp->pathname, longname);
 613:             }
 614:         }
 615:         blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK;
 616:         if (vflag)
 617:             fprintf(vfile, "a %s %ld blocks\n", longname, blocks);
 618:         sprintf(dblock.dbuf.chksum, "%6o", checksum());
 619:         hint = writetape((char *)&dblock);
 620:         maxread = max(stbuf.st_blksize, (nblock * TBLOCK));
 621:         if ((bigbuf = malloc((unsigned)maxread)) == 0) {
 622:             maxread = TBLOCK;
 623:             bigbuf = buf;
 624:         }
 625: 
 626:         while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0
 627:           && blocks > 0) {
 628:             register int nblks;
 629: 
 630:             nblks = ((i-1)/TBLOCK)+1;
 631:             if (nblks > blocks)
 632:                 nblks = blocks;
 633:             hint = writetbuf(bigbuf, nblks);
 634:             blocks -= nblks;
 635:         }
 636:         close(infile);
 637:         if (bigbuf != buf)
 638:             free(bigbuf);
 639:         if (i < 0) {
 640:             fprintf(stderr, "tar: Read error on ");
 641:             perror(longname);
 642:         } else if (blocks != 0 || i != 0)
 643:             fprintf(stderr, "tar: %s: file changed size\n",
 644:                 longname);
 645:         while (--blocks >=  0)
 646:             putempty();
 647:         break;
 648: 
 649:     default:
 650:         fprintf(stderr, "tar: %s is not a file. Not dumped\n",
 651:             longname);
 652:         break;
 653:     }
 654: }
 655: 
 656: doxtract(argv)
 657:     char *argv[];
 658: {
 659:     long blocks, bytes;
 660:     int ofile, i;
 661:     extern int errno;
 662: 
 663:     for (;;) {
 664:         if ((i = wantit(argv)) == 0)
 665:             continue;
 666:         if (i == -1)
 667:             break;      /* end of tape */
 668:         if (checkw('x', dblock.dbuf.name) == 0) {
 669:             passtape();
 670:             continue;
 671:         }
 672:         if (Fflag) {
 673:             char *s;
 674: 
 675:             if ((s = rindex(dblock.dbuf.name, '/')) == 0)
 676:                 s = dblock.dbuf.name;
 677:             else
 678:                 s++;
 679:             if (checkf(s, stbuf.st_mode, Fflag) == 0) {
 680:                 passtape();
 681:                 continue;
 682:             }
 683:         }
 684:         if (checkdir(dblock.dbuf.name)) {   /* have a directory */
 685:             if (mflag == 0)
 686:                 dodirtimes(&dblock);
 687:             continue;
 688:         }
 689:         if (dblock.dbuf.linkflag == '2') {  /* symlink */
 690:             /*
 691: 			 * only unlink non directories or empty
 692: 			 * directories
 693: 			 */
 694:             if (rmdir(dblock.dbuf.name) < 0) {
 695:                 if (errno == ENOTDIR)
 696:                     unlink(dblock.dbuf.name);
 697:             }
 698:             if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) {
 699:                 fprintf(stderr, "tar: %s: symbolic link failed: ",
 700:                     dblock.dbuf.name);
 701:                 perror("");
 702:                 continue;
 703:             }
 704:             if (vflag)
 705:                 fprintf(vfile, "x %s symbolic link to %s\n",
 706:                     dblock.dbuf.name, dblock.dbuf.linkname);
 707: #ifdef notdef
 708:             /* ignore alien orders */
 709:             chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
 710:             if (mflag == 0)
 711:                 setimes(dblock.dbuf.name, stbuf.st_mtime);
 712:             if (pflag)
 713:                 chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
 714: #endif
 715:             continue;
 716:         }
 717:         if (dblock.dbuf.linkflag == '1') {  /* regular link */
 718:             /*
 719: 			 * only unlink non directories or empty
 720: 			 * directories
 721: 			 */
 722:             if (rmdir(dblock.dbuf.name) < 0) {
 723:                 if (errno == ENOTDIR)
 724:                     unlink(dblock.dbuf.name);
 725:             }
 726:             if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) {
 727:                 fprintf(stderr, "tar: can't link %s to %s: ",
 728:                     dblock.dbuf.name, dblock.dbuf.linkname);
 729:                 perror("");
 730:                 continue;
 731:             }
 732:             if (vflag)
 733:                 fprintf(vfile, "%s linked to %s\n",
 734:                     dblock.dbuf.name, dblock.dbuf.linkname);
 735:             continue;
 736:         }
 737:         if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) {
 738:             fprintf(stderr, "tar: can't create %s: ",
 739:                 dblock.dbuf.name);
 740:             perror("");
 741:             passtape();
 742:             continue;
 743:         }
 744:         chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
 745:         blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK;
 746:         if (vflag)
 747:             fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n",
 748:                 dblock.dbuf.name, bytes, blocks);
 749:         for (; blocks > 0;) {
 750:             register int nread;
 751:             char    *bufp;
 752:             register int nwant;
 753: 
 754:             nwant = NBLOCK*TBLOCK;
 755:             if (nwant > (blocks*TBLOCK))
 756:                 nwant = (blocks*TBLOCK);
 757:             nread = readtbuf(&bufp, nwant);
 758:             if (write(ofile, bufp, (int)min(nread, bytes)) < 0) {
 759:                 fprintf(stderr,
 760:                     "tar: %s: HELP - extract write error",
 761:                     dblock.dbuf.name);
 762:                 perror("");
 763:                 done(2);
 764:             }
 765:             bytes -= nread;
 766:             blocks -= (((nread-1)/TBLOCK)+1);
 767:         }
 768:         close(ofile);
 769:         if (mflag == 0)
 770:             setimes(dblock.dbuf.name, stbuf.st_mtime);
 771:         if (pflag)
 772:             chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
 773:     }
 774:     if (mflag == 0) {
 775:         dblock.dbuf.name[0] = '\0'; /* process the whole stack */
 776:         dodirtimes(&dblock);
 777:     }
 778: }
 779: 
 780: dotable(argv)
 781:     char *argv[];
 782: {
 783:     register int i;
 784: 
 785:     for (;;) {
 786:         if ((i = wantit(argv)) == 0)
 787:             continue;
 788:         if (i == -1)
 789:             break;      /* end of tape */
 790:         if (vflag)
 791:             longt(&stbuf);
 792:         printf("%s", dblock.dbuf.name);
 793:         if (dblock.dbuf.linkflag == '1')
 794:             printf(" linked to %s", dblock.dbuf.linkname);
 795:         if (dblock.dbuf.linkflag == '2')
 796:             printf(" symbolic link to %s", dblock.dbuf.linkname);
 797:         printf("\n");
 798:         passtape();
 799:     }
 800: }
 801: 
 802: putempty()
 803: {
 804:     char buf[TBLOCK];
 805: 
 806:     bzero(buf, sizeof (buf));
 807:     (void) writetape(buf);
 808: }
 809: 
 810: longt(st)
 811:     register struct stat *st;
 812: {
 813:     register char *cp;
 814:     char *ctime();
 815: 
 816:     pmode(st);
 817:     printf("%3d/%1d", st->st_uid, st->st_gid);
 818:     printf("%7ld", st->st_size);
 819:     cp = ctime(&st->st_mtime);
 820:     printf(" %-12.12s %-4.4s ", cp+4, cp+20);
 821: }
 822: 
 823: #define SUID    04000
 824: #define SGID    02000
 825: #define ROWN    0400
 826: #define WOWN    0200
 827: #define XOWN    0100
 828: #define RGRP    040
 829: #define WGRP    020
 830: #define XGRP    010
 831: #define ROTH    04
 832: #define WOTH    02
 833: #define XOTH    01
 834: #define STXT    01000
 835: int m1[] = { 1, ROWN, 'r', '-' };
 836: int m2[] = { 1, WOWN, 'w', '-' };
 837: int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
 838: int m4[] = { 1, RGRP, 'r', '-' };
 839: int m5[] = { 1, WGRP, 'w', '-' };
 840: int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
 841: int m7[] = { 1, ROTH, 'r', '-' };
 842: int m8[] = { 1, WOTH, 'w', '-' };
 843: int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
 844: 
 845: int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
 846: 
 847: pmode(st)
 848:     register struct stat *st;
 849: {
 850:     register int **mp;
 851: 
 852:     for (mp = &m[0]; mp < &m[9];)
 853:         selectbits(*mp++, st);
 854: }
 855: 
 856: selectbits(pairp, st)
 857:     int *pairp;
 858:     struct stat *st;
 859: {
 860:     register int n, *ap;
 861: 
 862:     ap = pairp;
 863:     n = *ap++;
 864:     while (--n>=0 && (st->st_mode&*ap++)==0)
 865:         ap++;
 866:     putchar(*ap);
 867: }
 868: 
 869: /*
 870:  * Make all directories needed by `name'.  If `name' is itself
 871:  * a directory on the tar tape (indicated by a trailing '/'),
 872:  * return 1; else 0.
 873:  */
 874: checkdir(name)
 875:     register char *name;
 876: {
 877:     register char *cp;
 878: 
 879:     /*
 880: 	 * Quick check for existence of directory.
 881: 	 */
 882:     if ((cp = rindex(name, '/')) == 0)
 883:         return (0);
 884:     *cp = '\0';
 885:     if (access(name, 0) == 0) { /* already exists */
 886:         *cp = '/';
 887:         return (cp[1] == '\0'); /* return (lastchar == '/') */
 888:     }
 889:     *cp = '/';
 890: 
 891:     /*
 892: 	 * No luck, try to make all directories in path.
 893: 	 */
 894:     for (cp = name; *cp; cp++) {
 895:         if (*cp != '/')
 896:             continue;
 897:         *cp = '\0';
 898:         if (access(name, 0) < 0) {
 899:             if (mkdir(name, 0777) < 0) {
 900:                 perror(name);
 901:                 *cp = '/';
 902:                 return (0);
 903:             }
 904:             chown(name, stbuf.st_uid, stbuf.st_gid);
 905:             if (pflag && cp[1] == '\0') /* dir on the tape */
 906:                 chmod(name, stbuf.st_mode & 07777);
 907:         }
 908:         *cp = '/';
 909:     }
 910:     return (cp[-1]=='/');
 911: }
 912: 
 913: onintr()
 914: {
 915:     (void) signal(SIGINT, SIG_IGN);
 916:     term++;
 917: }
 918: 
 919: onquit()
 920: {
 921:     (void) signal(SIGQUIT, SIG_IGN);
 922:     term++;
 923: }
 924: 
 925: onhup()
 926: {
 927:     (void) signal(SIGHUP, SIG_IGN);
 928:     term++;
 929: }
 930: 
 931: #ifdef notdef
 932: onterm()
 933: {
 934:     (void) signal(SIGTERM, SIG_IGN);
 935:     term++;
 936: }
 937: #endif
 938: 
 939: tomodes(sp)
 940: register struct stat *sp;
 941: {
 942:     register char *cp;
 943: 
 944:     for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
 945:         *cp = '\0';
 946:     sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777);
 947:     sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid);
 948:     sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid);
 949:     sprintf(dblock.dbuf.size, "%11lo ", sp->st_size);
 950:     sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime);
 951: }
 952: 
 953: checksum()
 954: {
 955:     register i;
 956:     register char *cp;
 957: 
 958:     for (cp = dblock.dbuf.chksum;
 959:          cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
 960:         *cp = ' ';
 961:     i = 0;
 962:     for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
 963:         i += *cp;
 964:     return (i);
 965: }
 966: 
 967: checkw(c, name)
 968:     char *name;
 969: {
 970:     if (!wflag)
 971:         return (1);
 972:     printf("%c ", c);
 973:     if (vflag)
 974:         longt(&stbuf);
 975:     printf("%s: ", name);
 976:     return (response() == 'y');
 977: }
 978: 
 979: response()
 980: {
 981:     char c;
 982: 
 983:     c = getchar();
 984:     if (c != '\n')
 985:         while (getchar() != '\n')
 986:             ;
 987:     else
 988:         c = 'n';
 989:     return (c);
 990: }
 991: 
 992: checkf(name, mode, howmuch)
 993:     char *name;
 994:     int mode, howmuch;
 995: {
 996:     int l;
 997: 
 998:     if ((mode & S_IFMT) == S_IFDIR){
 999:         if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0))
1000:             return(0);
1001:         return(1);
1002:     }
1003:     if ((l = strlen(name)) < 3)
1004:         return (1);
1005:     if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o')
1006:         return (0);
1007:     if (strcmp(name, "core") == 0 ||
1008:         strcmp(name, "errs") == 0 ||
1009:         (howmuch > 1 && strcmp(name, "a.out") == 0))
1010:         return (0);
1011:     /* SHOULD CHECK IF IT IS EXECUTABLE */
1012:     return (1);
1013: }
1014: 
1015: /* Is the current file a new file, or the newest one of the same name? */
1016: checkupdate(arg)
1017:     char *arg;
1018: {
1019:     char name[100];
1020:     long mtime;
1021:     daddr_t seekp;
1022:     daddr_t lookup();
1023: 
1024:     rewind(tfile);
1025:     for (;;) {
1026:         if ((seekp = lookup(arg)) < 0)
1027:             return (1);
1028:         fseek(tfile, seekp, 0);
1029:         fscanf(tfile, "%s %lo", name, &mtime);
1030:         return (stbuf.st_mtime > mtime);
1031:     }
1032: }
1033: 
1034: done(n)
1035: {
1036:     unlink(tname);
1037:     exit(n);
1038: }
1039: 
1040: /*
1041:  * Do we want the next entry on the tape, i.e. is it selected?  If
1042:  * not, skip over the entire entry.  Return -1 if reached end of tape.
1043:  */
1044: wantit(argv)
1045:     char *argv[];
1046: {
1047:     register char **cp;
1048: 
1049:     getdir();
1050:     if (endtape())
1051:         return (-1);
1052:     if (*argv == 0)
1053:         return (1);
1054:     for (cp = argv; *cp; cp++)
1055:         if (prefix(*cp, dblock.dbuf.name))
1056:             return (1);
1057:     passtape();
1058:     return (0);
1059: }
1060: 
1061: /*
1062:  * Does s2 begin with the string s1, on a directory boundary?
1063:  */
1064: prefix(s1, s2)
1065:     register char *s1, *s2;
1066: {
1067:     while (*s1)
1068:         if (*s1++ != *s2++)
1069:             return (0);
1070:     if (*s2)
1071:         return (*s2 == '/');
1072:     return (1);
1073: }
1074: 
1075: #define N   200
1076: int njab;
1077: 
1078: daddr_t
1079: lookup(s)
1080:     char *s;
1081: {
1082:     register i;
1083:     daddr_t a;
1084: 
1085:     for(i=0; s[i]; i++)
1086:         if (s[i] == ' ')
1087:             break;
1088:     a = bsrch(s, i, low, high);
1089:     return (a);
1090: }
1091: 
1092: daddr_t
1093: bsrch(s, n, l, h)
1094:     daddr_t l, h;
1095:     char *s;
1096: {
1097:     register i, j;
1098:     char b[N];
1099:     daddr_t m, m1;
1100: 
1101:     njab = 0;
1102: 
1103: loop:
1104:     if (l >= h)
1105:         return ((daddr_t) -1);
1106:     m = l + (h-l)/2 - N/2;
1107:     if (m < l)
1108:         m = l;
1109:     fseek(tfile, m, 0);
1110:     fread(b, 1, N, tfile);
1111:     njab++;
1112:     for(i=0; i<N; i++) {
1113:         if (b[i] == '\n')
1114:             break;
1115:         m++;
1116:     }
1117:     if (m >= h)
1118:         return ((daddr_t) -1);
1119:     m1 = m;
1120:     j = i;
1121:     for(i++; i<N; i++) {
1122:         m1++;
1123:         if (b[i] == '\n')
1124:             break;
1125:     }
1126:     i = cmp(b+j, s, n);
1127:     if (i < 0) {
1128:         h = m;
1129:         goto loop;
1130:     }
1131:     if (i > 0) {
1132:         l = m1;
1133:         goto loop;
1134:     }
1135:     return (m);
1136: }
1137: 
1138: cmp(b, s, n)
1139:     char *b, *s;
1140: {
1141:     register i;
1142: 
1143:     if (b[0] != '\n')
1144:         exit(2);
1145:     for(i=0; i<n; i++) {
1146:         if (b[i+1] > s[i])
1147:             return (-1);
1148:         if (b[i+1] < s[i])
1149:             return (1);
1150:     }
1151:     return (b[i+1] == ' '? 0 : -1);
1152: }
1153: 
1154: readtape(buffer)
1155:     char *buffer;
1156: {
1157:     char *bufp;
1158: 
1159:     if (first == 0)
1160:         getbuf();
1161:     (void) readtbuf(&bufp, TBLOCK);
1162:     bcopy(bufp, buffer, TBLOCK);
1163:     return(TBLOCK);
1164: }
1165: 
1166: readtbuf(bufpp, size)
1167:     char **bufpp;
1168:     int size;
1169: {
1170:     register int i;
1171: 
1172:     if (recno >= nblock || first == 0) {
1173:         if ((i = bread(mt, (char *)tbuf, TBLOCK*nblock)) < 0)
1174:             mterr("read", i, 3);
1175:         if (first == 0) {
1176:             if ((i % TBLOCK) != 0) {
1177:                 fprintf(stderr, "tar: tape blocksize error\n");
1178:                 done(3);
1179:             }
1180:             i /= TBLOCK;
1181:             if (i != nblock) {
1182:                 fprintf(stderr, "tar: blocksize = %d\n", i);
1183:                 nblock = i;
1184:             }
1185:             first = 1;
1186:         }
1187:         recno = 0;
1188:     }
1189:     if (size > ((nblock-recno)*TBLOCK))
1190:         size = (nblock-recno)*TBLOCK;
1191:     *bufpp = (char *)&tbuf[recno];
1192:     recno += (size/TBLOCK);
1193:     return (size);
1194: }
1195: 
1196: writetbuf(buffer, n)
1197:     register char *buffer;
1198:     register int n;
1199: {
1200:     int i;
1201: 
1202:     if (first == 0) {
1203:         getbuf();
1204:         first = 1;
1205:     }
1206:     if (recno >= nblock) {
1207:         i = write(mt, (char *)tbuf, TBLOCK*nblock);
1208:         if (i != TBLOCK*nblock)
1209:             mterr("write", i, 2);
1210:         recno = 0;
1211:     }
1212: 
1213:     /*
1214: 	 *  Special case:  We have an empty tape buffer, and the
1215: 	 *  users data size is >= the tape block size:  Avoid
1216: 	 *  the bcopy and dma direct to tape.  BIG WIN.  Add the
1217: 	 *  residual to the tape buffer.
1218: 	 */
1219:     while (recno == 0 && n >= nblock) {
1220:         i = write(mt, buffer, TBLOCK*nblock);
1221:         if (i != TBLOCK*nblock)
1222:             mterr("write", i, 2);
1223:         n -= nblock;
1224:         buffer += (nblock * TBLOCK);
1225:     }
1226: 
1227:     while (n-- > 0) {
1228:         bcopy(buffer, (char *)&tbuf[recno++], TBLOCK);
1229:         buffer += TBLOCK;
1230:         if (recno >= nblock) {
1231:             i = write(mt, (char *)tbuf, TBLOCK*nblock);
1232:             if (i != TBLOCK*nblock)
1233:                 mterr("write", i, 2);
1234:             recno = 0;
1235:         }
1236:     }
1237: 
1238:     /* Tell the user how much to write to get in sync */
1239:     return (nblock - recno);
1240: }
1241: 
1242: backtape()
1243: {
1244:     static int mtdev = 1;
1245:     static struct mtop mtop = {MTBSR, 1};
1246:     struct mtget mtget;
1247: 
1248:     if (mtdev == 1)
1249:         mtdev = ioctl(mt, MTIOCGET, (char *)&mtget);
1250:     if (mtdev == 0) {
1251:         if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) {
1252:             fprintf(stderr, "tar: tape backspace error: ");
1253:             perror("");
1254:             done(4);
1255:         }
1256:     } else
1257:         lseek(mt, (daddr_t) -TBLOCK*nblock, 1);
1258:     recno--;
1259: }
1260: 
1261: flushtape()
1262: {
1263:     int i;
1264: 
1265:     i = write(mt, (char *)tbuf, TBLOCK*nblock);
1266:     if (i != TBLOCK*nblock)
1267:         mterr("write", i, 2);
1268: }
1269: 
1270: mterr(operation, i, exitcode)
1271:     char *operation;
1272:     int i;
1273: {
1274:     fprintf(stderr, "tar: tape %s error: ", operation);
1275:     if (i < 0)
1276:         perror("");
1277:     else
1278:         fprintf(stderr, "unexpected EOF\n");
1279:     done(exitcode);
1280: }
1281: 
1282: bread(fd, buf, size)
1283:     int fd;
1284:     char *buf;
1285:     int size;
1286: {
1287:     int count;
1288:     static int lastread = 0;
1289: 
1290:     if (!Bflag)
1291:         return (read(fd, buf, size));
1292: 
1293:     for (count = 0; count < size; count += lastread) {
1294:         lastread = read(fd, buf, size - count);
1295:         if (lastread <= 0) {
1296:             if (count > 0)
1297:                 return (count);
1298:             return (lastread);
1299:         }
1300:         buf += lastread;
1301:     }
1302:     return (count);
1303: }
1304: 
1305: char *
1306: getcwd(buf)
1307:     char *buf;
1308: {
1309:     if (getwd(buf) == NULL) {
1310:         fprintf(stderr, "tar: %s\n", buf);
1311:         exit(1);
1312:     }
1313:     return (buf);
1314: }
1315: 
1316: getbuf()
1317: {
1318: 
1319:     if (nblock == 0) {
1320:         fstat(mt, &stbuf);
1321:         if ((stbuf.st_mode & S_IFMT) == S_IFCHR)
1322:             nblock = NBLOCK;
1323:         else {
1324:             nblock = stbuf.st_blksize / TBLOCK;
1325:             if (nblock == 0)
1326:                 nblock = NBLOCK;
1327:         }
1328:     }
1329:     tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK);
1330:     if (tbuf == NULL) {
1331:         fprintf(stderr, "tar: blocksize %d too big, can't get memory\n",
1332:             nblock);
1333:         done(1);
1334:     }
1335: }
1336: 
1337: /*
1338:  * Save this directory and its mtime on the stack, popping and setting
1339:  * the mtimes of any stacked dirs which aren't parents of this one.
1340:  * A null directory causes the entire stack to be unwound and set.
1341:  *
1342:  * Since all the elements of the directory "stack" share a common
1343:  * prefix, we can make do with one string.  We keep only the current
1344:  * directory path, with an associated array of mtime's, one for each
1345:  * '/' in the path.  A negative mtime means no mtime.  The mtime's are
1346:  * offset by one (first index 1, not 0) because calling this with a null
1347:  * directory causes mtime[0] to be set.
1348:  *
1349:  * This stack algorithm is not guaranteed to work for tapes created
1350:  * with the 'r' option, but the vast majority of tapes with
1351:  * directories are not.  This avoids saving every directory record on
1352:  * the tape and setting all the times at the end.
1353:  */
1354: char dirstack[NAMSIZ];
1355: #define NTIM (NAMSIZ/2+1)       /* a/b/c/d/... */
1356: time_t mtime[NTIM];
1357: 
1358: dodirtimes(hp)
1359:     union hblock *hp;
1360: {
1361:     register char *p = dirstack;
1362:     register char *q = hp->dbuf.name;
1363:     register int ndir = 0;
1364:     char *savp;
1365:     int savndir;
1366: 
1367:     /* Find common prefix */
1368:     while (*p == *q) {
1369:         if (*p++ == '/')
1370:             ++ndir;
1371:         q++;
1372:     }
1373: 
1374:     savp = p;
1375:     savndir = ndir;
1376:     while (*p) {
1377:         /*
1378: 		 * Not a child: unwind the stack, setting the times.
1379: 		 * The order we do this doesn't matter, so we go "forward."
1380: 		 */
1381:         if (*p++ == '/')
1382:             if (mtime[++ndir] >= 0) {
1383:                 *--p = '\0';    /* zap the slash */
1384:                 setimes(dirstack, mtime[ndir]);
1385:                 *p++ = '/';
1386:             }
1387:     }
1388:     p = savp;
1389:     ndir = savndir;
1390: 
1391:     /* Push this one on the "stack" */
1392:     while (*p = *q++)   /* append the rest of the new dir */
1393:         if (*p++ == '/')
1394:             mtime[++ndir] = -1;
1395:     mtime[ndir] = stbuf.st_mtime;   /* overwrite the last one */
1396: }
1397: 
1398: setimes(path, mt)
1399:     char *path;
1400:     time_t mt;
1401: {
1402:     struct timeval tv[2];
1403: 
1404:     tv[0].tv_sec = time((time_t *) 0);
1405:     tv[1].tv_sec = mt;
1406:     tv[0].tv_usec = tv[1].tv_usec = 0;
1407:     if (utimes(path, tv) < 0) {
1408:         fprintf(stderr, "tar: can't set time on %s: ", path);
1409:         perror("");
1410:     }
1411: }
1412: 
1413: char *
1414: getmem(size)
1415: {
1416:     char *p = malloc((unsigned) size);
1417: 
1418:     if (p == NULL && freemem) {
1419:         fprintf(stderr,
1420:             "tar: out of memory, link and directory modtime info lost\n");
1421:         freemem = 0;
1422:     }
1423:     return (p);
1424: }

Defined functions

backtape defined in line 1242; used 1 times
bread defined in line 1282; used 1 times
bsrch defined in line 1092; used 2 times
checkdir defined in line 874; used 1 times
checkf defined in line 992; used 2 times
checksum defined in line 953; used 5 times
checkupdate defined in line 1016; used 1 times
checkw defined in line 967; used 2 times
cmp defined in line 1138; used 1 times
dodirtimes defined in line 1358; used 2 times
done defined in line 1034; used 14 times
dorep defined in line 322; used 1 times
dotable defined in line 780; used 1 times
doxtract defined in line 656; used 1 times
endtape defined in line 403; used 2 times
flushtape defined in line 1261; used 1 times
getbuf defined in line 1316; used 2 times
getcwd defined in line 1305; used 4 times
getdir defined in line 408; used 3 times
getmem defined in line 1413; used 2 times
longt defined in line 810; used 2 times
lookup defined in line 1078; used 2 times
main defined in line 118; never used
mterr defined in line 1270; used 5 times
onhup defined in line 925; used 2 times
onintr defined in line 913; used 2 times
onquit defined in line 919; used 2 times
onterm defined in line 932; used 2 times
openmt defined in line 279; used 2 times
passtape defined in line 438; used 6 times
pmode defined in line 847; used 1 times
prefix defined in line 1064; used 1 times
putempty defined in line 802; used 3 times
putfile defined in line 453; used 2 times
readtape defined in line 1154; used 1 times
readtbuf defined in line 1166; used 3 times
response defined in line 979; used 1 times
selectbits defined in line 856; used 1 times
setimes defined in line 1398; used 3 times
tomodes defined in line 939; used 3 times
usage defined in line 272; used 6 times
wantit defined in line 1044; used 2 times
writetbuf defined in line 1196; used 2 times

Defined variables

Bflag defined in line 79; used 3 times
Fflag defined in line 80; used 5 times
cflag defined in line 71; used 5 times
chksum defined in line 84; used 12 times
copyright defined in line 8; never used
dblock defined in line 62; used 82 times
dirstack defined in line 1354; used 2 times
fflag defined in line 73; used 1 times
first defined in line 86; used 6 times
freemem defined in line 88; used 2 times
hflag defined in line 78; used 2 times
high defined in line 98; used 2 times
iflag defined in line 74; used 2 times
ihead defined in line 64; used 8 times
low defined in line 97; used 1 times
m defined in line 845; used 12 times
m1 defined in line 835; used 5 times
m2 defined in line 836; used 1 times
m3 defined in line 837; used 1 times
m4 defined in line 838; used 1 times
m5 defined in line 839; used 1 times
m6 defined in line 840; used 1 times
m7 defined in line 841; used 1 times
m8 defined in line 842; used 1 times
m9 defined in line 843; used 1 times
magtape defined in line 105; used 3 times
mflag defined in line 72; used 5 times
mt defined in line 82; used 21 times
mtime defined in line 1356; used 11 times
nblock defined in line 89; used 31 times
njab defined in line 1076; used 2 times
oflag defined in line 75; used 2 times
pflag defined in line 76; used 4 times
prtlinkerr defined in line 87; used 2 times
recno defined in line 85; used 14 times
rflag defined in line 67; used 4 times
sccsid defined in line 14; never used
stbuf defined in line 65; used 42 times
tbuf defined in line 63; used 8 times
term defined in line 83; used 7 times
tflag defined in line 70; used 2 times
tname defined in line 103; used 11 times
usefile defined in line 104; used 5 times
vflag defined in line 69; used 9 times
wflag defined in line 77; used 2 times
xflag defined in line 68; used 3 times

Defined struct's

header defined in line 41; never used
linkbuf defined in line 54; used 8 times

Defined union's

hblock defined in line 39; used 8 times

Defined macros

N defined in line 1075; used 5 times
NAMSIZ defined in line 33; used 11 times
NBLOCK defined in line 32; used 3 times
NTIM defined in line 1355; used 1 times
RGRP defined in line 828; used 1 times
ROTH defined in line 831; used 1 times
ROWN defined in line 825; used 1 times
SGID defined in line 824; used 1 times
STXT defined in line 834; used 1 times
SUID defined in line 823; used 1 times
TBLOCK defined in line 31; used 43 times
WGRP defined in line 829; used 1 times
WOTH defined in line 832; used 1 times
WOWN defined in line 826; used 1 times
XGRP defined in line 830; used 1 times
XOTH defined in line 833; used 1 times
XOWN defined in line 827; used 1 times
max defined in line 37; used 1 times
min defined in line 36; used 2 times
writetape defined in line 35; used 5 times
Last modified: 1989-10-03
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1240
Valid CSS Valid XHTML 1.0 Strict