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:         parent = wdir;
 365:         for (cp = *argv; *cp; cp++)
 366:             if (*cp == '/')
 367:                 cp2 = cp;
 368:         if (cp2 != *argv) {
 369:             *cp2 = '\0';
 370:             if (chdir(*argv) < 0) {
 371:                 fprintf(stderr, "tar: can't change directories to ");
 372:                 perror(*argv);
 373:                 continue;
 374:             }
 375:             parent = getcwd(tempdir);
 376:             *cp2 = '/';
 377:             cp2++;
 378:         }
 379:         putfile(*argv++, cp2, parent);
 380:         if (chdir(wdir) < 0) {
 381:             fprintf(stderr, "tar: cannot change back?: ");
 382:             perror(wdir);
 383:         }
 384:     }
 385:     putempty();
 386:     putempty();
 387:     flushtape();
 388:     if (prtlinkerr == 0)
 389:         return;
 390:     for (; ihead != NULL; ihead = ihead->nextp) {
 391:         if (ihead->count == 0)
 392:             continue;
 393:         fprintf(stderr, "tar: missing links to %s\n", ihead->pathname);
 394:     }
 395: }
 396: 
 397: endtape()
 398: {
 399:     return (dblock.dbuf.name[0] == '\0');
 400: }
 401: 
 402: getdir()
 403: {
 404:     register struct stat *sp;
 405:     int i;
 406: 
 407: top:
 408:     readtape((char *)&dblock);
 409:     if (dblock.dbuf.name[0] == '\0')
 410:         return;
 411:     sp = &stbuf;
 412:     sscanf(dblock.dbuf.mode, "%o", &i);
 413:     sp->st_mode = i;
 414:     sscanf(dblock.dbuf.uid, "%o", &i);
 415:     sp->st_uid = i;
 416:     sscanf(dblock.dbuf.gid, "%o", &i);
 417:     sp->st_gid = i;
 418:     sscanf(dblock.dbuf.size, "%lo", &sp->st_size);
 419:     sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime);
 420:     sscanf(dblock.dbuf.chksum, "%o", &chksum);
 421:     if (chksum != (i = checksum())) {
 422:         fprintf(stderr, "tar: directory checksum error (%d != %d)\n",
 423:             chksum, i);
 424:         if (iflag)
 425:             goto top;
 426:         done(2);
 427:     }
 428:     if (tfile != NULL)
 429:         fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime);
 430: }
 431: 
 432: passtape()
 433: {
 434:     long blocks;
 435:     char *bufp;
 436: 
 437:     if (dblock.dbuf.linkflag == '1')
 438:         return;
 439:     blocks = stbuf.st_size;
 440:     blocks += TBLOCK-1;
 441:     blocks /= TBLOCK;
 442: 
 443:     while (blocks-- > 0)
 444:         (void) readtbuf(&bufp, TBLOCK);
 445: }
 446: 
 447: putfile(longname, shortname, parent)
 448:     char *longname;
 449:     char *shortname;
 450:     char *parent;
 451: {
 452:     int infile = 0;
 453:     long blocks;
 454:     char buf[TBLOCK];
 455:     char *bigbuf;
 456:     register char *cp;
 457:     struct direct *dp;
 458:     DIR *dirp;
 459:     register int i;
 460:     long l;
 461:     char newparent[NAMSIZ+64];
 462:     extern int errno;
 463:     int maxread;
 464:     int hint;       /* amount to write to get "in sync" */
 465: 
 466:     if (!hflag)
 467:         i = lstat(shortname, &stbuf);
 468:     else
 469:         i = stat(shortname, &stbuf);
 470:     if (i < 0) {
 471:         fprintf(stderr, "tar: ");
 472:         perror(longname);
 473:         return;
 474:     }
 475:     if (tfile != NULL && checkupdate(longname) == 0)
 476:         return;
 477:     if (checkw('r', longname) == 0)
 478:         return;
 479:     if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0)
 480:         return;
 481: 
 482:     switch (stbuf.st_mode & S_IFMT) {
 483:     case S_IFDIR:
 484:         for (i = 0, cp = buf; *cp++ = longname[i++];)
 485:             ;
 486:         *--cp = '/';
 487:         *++cp = 0  ;
 488:         if (!oflag) {
 489:             if ((cp - buf) >= NAMSIZ) {
 490:                 fprintf(stderr, "tar: %s: file name too long\n",
 491:                     longname);
 492:                 return;
 493:             }
 494:             stbuf.st_size = 0;
 495:             tomodes(&stbuf);
 496:             strcpy(dblock.dbuf.name,buf);
 497:             sprintf(dblock.dbuf.chksum, "%6o", checksum());
 498:             (void) writetape((char *)&dblock);
 499:         }
 500:         sprintf(newparent, "%s/%s", parent, shortname);
 501:         if (chdir(shortname) < 0) {
 502:             perror(shortname);
 503:             return;
 504:         }
 505:         if ((dirp = opendir(".")) == NULL) {
 506:             fprintf(stderr, "tar: %s: directory read error\n",
 507:                 longname);
 508:             if (chdir(parent) < 0) {
 509:                 fprintf(stderr, "tar: cannot change back?: ");
 510:                 perror(parent);
 511:             }
 512:             return;
 513:         }
 514:         while ((dp = readdir(dirp)) != NULL && !term) {
 515:             if (dp->d_ino == 0)
 516:                 continue;
 517:             if (!strcmp(".", dp->d_name) ||
 518:                 !strcmp("..", dp->d_name))
 519:                 continue;
 520:             strcpy(cp, dp->d_name);
 521:             l = telldir(dirp);
 522:             closedir(dirp);
 523:             putfile(buf, cp, newparent);
 524:             dirp = opendir(".");
 525:             seekdir(dirp, l);
 526:         }
 527:         closedir(dirp);
 528:         if (chdir(parent) < 0) {
 529:             fprintf(stderr, "tar: cannot change back?: ");
 530:             perror(parent);
 531:         }
 532:         break;
 533: 
 534:     case S_IFLNK:
 535:         tomodes(&stbuf);
 536:         if (strlen(longname) >= NAMSIZ) {
 537:             fprintf(stderr, "tar: %s: file name too long\n",
 538:                 longname);
 539:             return;
 540:         }
 541:         strcpy(dblock.dbuf.name, longname);
 542:         if (stbuf.st_size + 1 >= NAMSIZ) {
 543:             fprintf(stderr, "tar: %s: symbolic link too long\n",
 544:                 longname);
 545:             return;
 546:         }
 547:         i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1);
 548:         if (i < 0) {
 549:             fprintf(stderr, "tar: can't read symbolic link ");
 550:             perror(longname);
 551:             return;
 552:         }
 553:         dblock.dbuf.linkname[i] = '\0';
 554:         dblock.dbuf.linkflag = '2';
 555:         if (vflag)
 556:             fprintf(vfile, "a %s symbolic link to %s\n",
 557:                 longname, dblock.dbuf.linkname);
 558:         sprintf(dblock.dbuf.size, "%11lo", 0);
 559:         sprintf(dblock.dbuf.chksum, "%6o", checksum());
 560:         (void) writetape((char *)&dblock);
 561:         break;
 562: 
 563:     case S_IFREG:
 564:         if ((infile = open(shortname, 0)) < 0) {
 565:             fprintf(stderr, "tar: ");
 566:             perror(longname);
 567:             return;
 568:         }
 569:         tomodes(&stbuf);
 570:         if (strlen(longname) >= NAMSIZ) {
 571:             fprintf(stderr, "tar: %s: file name too long\n",
 572:                 longname);
 573:             close(infile);
 574:             return;
 575:         }
 576:         strcpy(dblock.dbuf.name, longname);
 577:         if (stbuf.st_nlink > 1) {
 578:             struct linkbuf *lp;
 579:             int found = 0;
 580: 
 581:             for (lp = ihead; lp != NULL; lp = lp->nextp)
 582:                 if (lp->inum == stbuf.st_ino &&
 583:                     lp->devnum == stbuf.st_dev) {
 584:                     found++;
 585:                     break;
 586:                 }
 587:             if (found) {
 588:                 strcpy(dblock.dbuf.linkname, lp->pathname);
 589:                 dblock.dbuf.linkflag = '1';
 590:                 sprintf(dblock.dbuf.chksum, "%6o", checksum());
 591:                 (void) writetape( (char *) &dblock);
 592:                 if (vflag)
 593:                     fprintf(vfile, "a %s link to %s\n",
 594:                         longname, lp->pathname);
 595:                 lp->count--;
 596:                 close(infile);
 597:                 return;
 598:             }
 599:             lp = (struct linkbuf *) getmem(sizeof(*lp));
 600:             if (lp != NULL) {
 601:                 lp->nextp = ihead;
 602:                 ihead = lp;
 603:                 lp->inum = stbuf.st_ino;
 604:                 lp->devnum = stbuf.st_dev;
 605:                 lp->count = stbuf.st_nlink - 1;
 606:                 strcpy(lp->pathname, longname);
 607:             }
 608:         }
 609:         blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK;
 610:         if (vflag)
 611:             fprintf(vfile, "a %s %ld blocks\n", longname, blocks);
 612:         sprintf(dblock.dbuf.chksum, "%6o", checksum());
 613:         hint = writetape((char *)&dblock);
 614:         maxread = max(stbuf.st_blksize, (nblock * TBLOCK));
 615:         if ((bigbuf = malloc((unsigned)maxread)) == 0) {
 616:             maxread = TBLOCK;
 617:             bigbuf = buf;
 618:         }
 619: 
 620:         while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0
 621:           && blocks > 0) {
 622:             register int nblks;
 623: 
 624:             nblks = ((i-1)/TBLOCK)+1;
 625:             if (nblks > blocks)
 626:                 nblks = blocks;
 627:             hint = writetbuf(bigbuf, nblks);
 628:             blocks -= nblks;
 629:         }
 630:         close(infile);
 631:         if (bigbuf != buf)
 632:             free(bigbuf);
 633:         if (i < 0) {
 634:             fprintf(stderr, "tar: Read error on ");
 635:             perror(longname);
 636:         } else if (blocks != 0 || i != 0)
 637:             fprintf(stderr, "tar: %s: file changed size\n",
 638:                 longname);
 639:         while (--blocks >=  0)
 640:             putempty();
 641:         break;
 642: 
 643:     default:
 644:         fprintf(stderr, "tar: %s is not a file. Not dumped\n",
 645:             longname);
 646:         break;
 647:     }
 648: }
 649: 
 650: doxtract(argv)
 651:     char *argv[];
 652: {
 653:     long blocks, bytes;
 654:     int ofile, i;
 655: 
 656:     for (;;) {
 657:         if ((i = wantit(argv)) == 0)
 658:             continue;
 659:         if (i == -1)
 660:             break;      /* end of tape */
 661:         if (checkw('x', dblock.dbuf.name) == 0) {
 662:             passtape();
 663:             continue;
 664:         }
 665:         if (Fflag) {
 666:             char *s;
 667: 
 668:             if ((s = rindex(dblock.dbuf.name, '/')) == 0)
 669:                 s = dblock.dbuf.name;
 670:             else
 671:                 s++;
 672:             if (checkf(s, stbuf.st_mode, Fflag) == 0) {
 673:                 passtape();
 674:                 continue;
 675:             }
 676:         }
 677:         if (checkdir(dblock.dbuf.name)) {   /* have a directory */
 678:             if (mflag == 0)
 679:                 dodirtimes(&dblock);
 680:             continue;
 681:         }
 682:         if (dblock.dbuf.linkflag == '2') {  /* symlink */
 683:             /*
 684: 			 * only unlink non directories or empty
 685: 			 * directories
 686: 			 */
 687:             if (rmdir(dblock.dbuf.name) < 0) {
 688:                 if (errno == ENOTDIR)
 689:                     unlink(dblock.dbuf.name);
 690:             }
 691:             if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) {
 692:                 fprintf(stderr, "tar: %s: symbolic link failed: ",
 693:                     dblock.dbuf.name);
 694:                 perror("");
 695:                 continue;
 696:             }
 697:             if (vflag)
 698:                 fprintf(vfile, "x %s symbolic link to %s\n",
 699:                     dblock.dbuf.name, dblock.dbuf.linkname);
 700: #ifdef notdef
 701:             /* ignore alien orders */
 702:             chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
 703:             if (mflag == 0)
 704:                 setimes(dblock.dbuf.name, stbuf.st_mtime);
 705:             if (pflag)
 706:                 chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
 707: #endif
 708:             continue;
 709:         }
 710:         if (dblock.dbuf.linkflag == '1') {  /* regular link */
 711:             /*
 712: 			 * only unlink non directories or empty
 713: 			 * directories
 714: 			 */
 715:             if (rmdir(dblock.dbuf.name) < 0) {
 716:                 if (errno == ENOTDIR)
 717:                     unlink(dblock.dbuf.name);
 718:             }
 719:             if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) {
 720:                 fprintf(stderr, "tar: can't link %s to %s: ",
 721:                     dblock.dbuf.name, dblock.dbuf.linkname);
 722:                 perror("");
 723:                 continue;
 724:             }
 725:             if (vflag)
 726:                 fprintf(vfile, "%s linked to %s\n",
 727:                     dblock.dbuf.name, dblock.dbuf.linkname);
 728:             continue;
 729:         }
 730:         if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) {
 731:             fprintf(stderr, "tar: can't create %s: ",
 732:                 dblock.dbuf.name);
 733:             perror("");
 734:             passtape();
 735:             continue;
 736:         }
 737:         chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
 738:         blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK;
 739:         if (vflag)
 740:             fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n",
 741:                 dblock.dbuf.name, bytes, blocks);
 742:         for (; blocks > 0;) {
 743:             register int nread;
 744:             char    *bufp;
 745:             register int nwant;
 746: 
 747:             nwant = NBLOCK*TBLOCK;
 748:             if (nwant > (blocks*TBLOCK))
 749:                 nwant = (blocks*TBLOCK);
 750:             nread = readtbuf(&bufp, nwant);
 751:             if (write(ofile, bufp, (int)min(nread, bytes)) < 0) {
 752:                 fprintf(stderr,
 753:                     "tar: %s: HELP - extract write error",
 754:                     dblock.dbuf.name);
 755:                 perror("");
 756:                 done(2);
 757:             }
 758:             bytes -= nread;
 759:             blocks -= (((nread-1)/TBLOCK)+1);
 760:         }
 761:         close(ofile);
 762:         if (mflag == 0)
 763:             setimes(dblock.dbuf.name, stbuf.st_mtime);
 764:         if (pflag)
 765:             chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
 766:     }
 767:     if (mflag == 0) {
 768:         dblock.dbuf.name[0] = '\0'; /* process the whole stack */
 769:         dodirtimes(&dblock);
 770:     }
 771: }
 772: 
 773: dotable(argv)
 774:     char *argv[];
 775: {
 776:     register int i;
 777: 
 778:     for (;;) {
 779:         if ((i = wantit(argv)) == 0)
 780:             continue;
 781:         if (i == -1)
 782:             break;      /* end of tape */
 783:         if (vflag)
 784:             longt(&stbuf);
 785:         printf("%s", dblock.dbuf.name);
 786:         if (dblock.dbuf.linkflag == '1')
 787:             printf(" linked to %s", dblock.dbuf.linkname);
 788:         if (dblock.dbuf.linkflag == '2')
 789:             printf(" symbolic link to %s", dblock.dbuf.linkname);
 790:         printf("\n");
 791:         passtape();
 792:     }
 793: }
 794: 
 795: putempty()
 796: {
 797:     char buf[TBLOCK];
 798: 
 799:     bzero(buf, sizeof (buf));
 800:     (void) writetape(buf);
 801: }
 802: 
 803: longt(st)
 804:     register struct stat *st;
 805: {
 806:     register char *cp;
 807:     char *ctime();
 808: 
 809:     pmode(st);
 810:     printf("%3d/%1d", st->st_uid, st->st_gid);
 811:     printf("%7ld", st->st_size);
 812:     cp = ctime(&st->st_mtime);
 813:     printf(" %-12.12s %-4.4s ", cp+4, cp+20);
 814: }
 815: 
 816: #define SUID    04000
 817: #define SGID    02000
 818: #define ROWN    0400
 819: #define WOWN    0200
 820: #define XOWN    0100
 821: #define RGRP    040
 822: #define WGRP    020
 823: #define XGRP    010
 824: #define ROTH    04
 825: #define WOTH    02
 826: #define XOTH    01
 827: #define STXT    01000
 828: int m1[] = { 1, ROWN, 'r', '-' };
 829: int m2[] = { 1, WOWN, 'w', '-' };
 830: int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
 831: int m4[] = { 1, RGRP, 'r', '-' };
 832: int m5[] = { 1, WGRP, 'w', '-' };
 833: int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
 834: int m7[] = { 1, ROTH, 'r', '-' };
 835: int m8[] = { 1, WOTH, 'w', '-' };
 836: int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
 837: 
 838: int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
 839: 
 840: pmode(st)
 841:     register struct stat *st;
 842: {
 843:     register int **mp;
 844: 
 845:     for (mp = &m[0]; mp < &m[9];)
 846:         selectbits(*mp++, st);
 847: }
 848: 
 849: selectbits(pairp, st)
 850:     int *pairp;
 851:     struct stat *st;
 852: {
 853:     register int n, *ap;
 854: 
 855:     ap = pairp;
 856:     n = *ap++;
 857:     while (--n>=0 && (st->st_mode&*ap++)==0)
 858:         ap++;
 859:     putchar(*ap);
 860: }
 861: 
 862: /*
 863:  * Make all directories needed by `name'.  If `name' is itself
 864:  * a directory on the tar tape (indicated by a trailing '/'),
 865:  * return 1; else 0.
 866:  */
 867: checkdir(name)
 868:     register char *name;
 869: {
 870:     register char *cp;
 871: 
 872:     /*
 873: 	 * Quick check for existence of directory.
 874: 	 */
 875:     if ((cp = rindex(name, '/')) == 0)
 876:         return (0);
 877:     *cp = '\0';
 878:     if (access(name, 0) == 0) { /* already exists */
 879:         *cp = '/';
 880:         return (cp[1] == '\0'); /* return (lastchar == '/') */
 881:     }
 882:     *cp = '/';
 883: 
 884:     /*
 885: 	 * No luck, try to make all directories in path.
 886: 	 */
 887:     for (cp = name; *cp; cp++) {
 888:         if (*cp != '/')
 889:             continue;
 890:         *cp = '\0';
 891:         if (access(name, 0) < 0) {
 892:             if (mkdir(name, 0777) < 0) {
 893:                 perror(name);
 894:                 *cp = '/';
 895:                 return (0);
 896:             }
 897:             chown(name, stbuf.st_uid, stbuf.st_gid);
 898:             if (pflag && cp[1] == '\0') /* dir on the tape */
 899:                 chmod(name, stbuf.st_mode & 07777);
 900:         }
 901:         *cp = '/';
 902:     }
 903:     return (cp[-1]=='/');
 904: }
 905: 
 906: onintr()
 907: {
 908:     (void) signal(SIGINT, SIG_IGN);
 909:     term++;
 910: }
 911: 
 912: onquit()
 913: {
 914:     (void) signal(SIGQUIT, SIG_IGN);
 915:     term++;
 916: }
 917: 
 918: onhup()
 919: {
 920:     (void) signal(SIGHUP, SIG_IGN);
 921:     term++;
 922: }
 923: 
 924: #ifdef notdef
 925: onterm()
 926: {
 927:     (void) signal(SIGTERM, SIG_IGN);
 928:     term++;
 929: }
 930: #endif
 931: 
 932: tomodes(sp)
 933: register struct stat *sp;
 934: {
 935:     register char *cp;
 936: 
 937:     for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
 938:         *cp = '\0';
 939:     sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777);
 940:     sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid);
 941:     sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid);
 942:     sprintf(dblock.dbuf.size, "%11lo ", sp->st_size);
 943:     sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime);
 944: }
 945: 
 946: checksum()
 947: {
 948:     register i;
 949:     register char *cp;
 950: 
 951:     for (cp = dblock.dbuf.chksum;
 952:          cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
 953:         *cp = ' ';
 954:     i = 0;
 955:     for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
 956:         i += *cp;
 957:     return (i);
 958: }
 959: 
 960: checkw(c, name)
 961:     char *name;
 962: {
 963:     if (!wflag)
 964:         return (1);
 965:     printf("%c ", c);
 966:     if (vflag)
 967:         longt(&stbuf);
 968:     printf("%s: ", name);
 969:     return (response() == 'y');
 970: }
 971: 
 972: response()
 973: {
 974:     char c;
 975: 
 976:     c = getchar();
 977:     if (c != '\n')
 978:         while (getchar() != '\n')
 979:             ;
 980:     else
 981:         c = 'n';
 982:     return (c);
 983: }
 984: 
 985: checkf(name, mode, howmuch)
 986:     char *name;
 987:     int mode, howmuch;
 988: {
 989:     int l;
 990: 
 991:     if ((mode & S_IFMT) == S_IFDIR){
 992:         if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0))
 993:             return(0);
 994:         return(1);
 995:     }
 996:     if ((l = strlen(name)) < 3)
 997:         return (1);
 998:     if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o')
 999:         return (0);
1000:     if (strcmp(name, "core") == 0 ||
1001:         strcmp(name, "errs") == 0 ||
1002:         (howmuch > 1 && strcmp(name, "a.out") == 0))
1003:         return (0);
1004:     /* SHOULD CHECK IF IT IS EXECUTABLE */
1005:     return (1);
1006: }
1007: 
1008: /* Is the current file a new file, or the newest one of the same name? */
1009: checkupdate(arg)
1010:     char *arg;
1011: {
1012:     char name[100];
1013:     long mtime;
1014:     daddr_t seekp;
1015:     daddr_t lookup();
1016: 
1017:     rewind(tfile);
1018:     for (;;) {
1019:         if ((seekp = lookup(arg)) < 0)
1020:             return (1);
1021:         fseek(tfile, seekp, 0);
1022:         fscanf(tfile, "%s %lo", name, &mtime);
1023:         return (stbuf.st_mtime > mtime);
1024:     }
1025: }
1026: 
1027: done(n)
1028: {
1029:     unlink(tname);
1030:     exit(n);
1031: }
1032: 
1033: /*
1034:  * Do we want the next entry on the tape, i.e. is it selected?  If
1035:  * not, skip over the entire entry.  Return -1 if reached end of tape.
1036:  */
1037: wantit(argv)
1038:     char *argv[];
1039: {
1040:     register char **cp;
1041: 
1042:     getdir();
1043:     if (endtape())
1044:         return (-1);
1045:     if (*argv == 0)
1046:         return (1);
1047:     for (cp = argv; *cp; cp++)
1048:         if (prefix(*cp, dblock.dbuf.name))
1049:             return (1);
1050:     passtape();
1051:     return (0);
1052: }
1053: 
1054: /*
1055:  * Does s2 begin with the string s1, on a directory boundary?
1056:  */
1057: prefix(s1, s2)
1058:     register char *s1, *s2;
1059: {
1060:     while (*s1)
1061:         if (*s1++ != *s2++)
1062:             return (0);
1063:     if (*s2)
1064:         return (*s2 == '/');
1065:     return (1);
1066: }
1067: 
1068: #define N   200
1069: int njab;
1070: 
1071: daddr_t
1072: lookup(s)
1073:     char *s;
1074: {
1075:     register i;
1076:     daddr_t a;
1077: 
1078:     for(i=0; s[i]; i++)
1079:         if (s[i] == ' ')
1080:             break;
1081:     a = bsrch(s, i, low, high);
1082:     return (a);
1083: }
1084: 
1085: daddr_t
1086: bsrch(s, n, l, h)
1087:     daddr_t l, h;
1088:     char *s;
1089: {
1090:     register i, j;
1091:     char b[N];
1092:     daddr_t m, m1;
1093: 
1094:     njab = 0;
1095: 
1096: loop:
1097:     if (l >= h)
1098:         return ((daddr_t) -1);
1099:     m = l + (h-l)/2 - N/2;
1100:     if (m < l)
1101:         m = l;
1102:     fseek(tfile, m, 0);
1103:     fread(b, 1, N, tfile);
1104:     njab++;
1105:     for(i=0; i<N; i++) {
1106:         if (b[i] == '\n')
1107:             break;
1108:         m++;
1109:     }
1110:     if (m >= h)
1111:         return ((daddr_t) -1);
1112:     m1 = m;
1113:     j = i;
1114:     for(i++; i<N; i++) {
1115:         m1++;
1116:         if (b[i] == '\n')
1117:             break;
1118:     }
1119:     i = cmp(b+j, s, n);
1120:     if (i < 0) {
1121:         h = m;
1122:         goto loop;
1123:     }
1124:     if (i > 0) {
1125:         l = m1;
1126:         goto loop;
1127:     }
1128:     return (m);
1129: }
1130: 
1131: cmp(b, s, n)
1132:     char *b, *s;
1133: {
1134:     register i;
1135: 
1136:     if (b[0] != '\n')
1137:         exit(2);
1138:     for(i=0; i<n; i++) {
1139:         if (b[i+1] > s[i])
1140:             return (-1);
1141:         if (b[i+1] < s[i])
1142:             return (1);
1143:     }
1144:     return (b[i+1] == ' '? 0 : -1);
1145: }
1146: 
1147: readtape(buffer)
1148:     char *buffer;
1149: {
1150:     char *bufp;
1151: 
1152:     if (first == 0)
1153:         getbuf();
1154:     (void) readtbuf(&bufp, TBLOCK);
1155:     bcopy(bufp, buffer, TBLOCK);
1156:     return(TBLOCK);
1157: }
1158: 
1159: readtbuf(bufpp, size)
1160:     char **bufpp;
1161:     int size;
1162: {
1163:     register int i;
1164: 
1165:     if (recno >= nblock || first == 0) {
1166:         if ((i = bread(mt, (char *)tbuf, TBLOCK*nblock)) < 0)
1167:             mterr("read", i, 3);
1168:         if (first == 0) {
1169:             if ((i % TBLOCK) != 0) {
1170:                 fprintf(stderr, "tar: tape blocksize error\n");
1171:                 done(3);
1172:             }
1173:             i /= TBLOCK;
1174:             if (i != nblock) {
1175:                 fprintf(stderr, "tar: blocksize = %d\n", i);
1176:                 nblock = i;
1177:             }
1178:             first = 1;
1179:         }
1180:         recno = 0;
1181:     }
1182:     if (size > ((nblock-recno)*TBLOCK))
1183:         size = (nblock-recno)*TBLOCK;
1184:     *bufpp = (char *)&tbuf[recno];
1185:     recno += (size/TBLOCK);
1186:     return (size);
1187: }
1188: 
1189: writetbuf(buffer, n)
1190:     register char *buffer;
1191:     register int n;
1192: {
1193:     int i;
1194: 
1195:     if (first == 0) {
1196:         getbuf();
1197:         first = 1;
1198:     }
1199:     if (recno >= nblock) {
1200:         i = write(mt, (char *)tbuf, TBLOCK*nblock);
1201:         if (i != TBLOCK*nblock)
1202:             mterr("write", i, 2);
1203:         recno = 0;
1204:     }
1205: 
1206:     /*
1207: 	 *  Special case:  We have an empty tape buffer, and the
1208: 	 *  users data size is >= the tape block size:  Avoid
1209: 	 *  the bcopy and dma direct to tape.  BIG WIN.  Add the
1210: 	 *  residual to the tape buffer.
1211: 	 */
1212:     while (recno == 0 && n >= nblock) {
1213:         i = write(mt, buffer, TBLOCK*nblock);
1214:         if (i != TBLOCK*nblock)
1215:             mterr("write", i, 2);
1216:         n -= nblock;
1217:         buffer += (nblock * TBLOCK);
1218:     }
1219: 
1220:     while (n-- > 0) {
1221:         bcopy(buffer, (char *)&tbuf[recno++], TBLOCK);
1222:         buffer += TBLOCK;
1223:         if (recno >= nblock) {
1224:             i = write(mt, (char *)tbuf, TBLOCK*nblock);
1225:             if (i != TBLOCK*nblock)
1226:                 mterr("write", i, 2);
1227:             recno = 0;
1228:         }
1229:     }
1230: 
1231:     /* Tell the user how much to write to get in sync */
1232:     return (nblock - recno);
1233: }
1234: 
1235: backtape()
1236: {
1237:     static int mtdev = 1;
1238:     static struct mtop mtop = {MTBSR, 1};
1239:     struct mtget mtget;
1240: 
1241:     if (mtdev == 1)
1242:         mtdev = ioctl(mt, MTIOCGET, (char *)&mtget);
1243:     if (mtdev == 0) {
1244:         if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) {
1245:             fprintf(stderr, "tar: tape backspace error: ");
1246:             perror("");
1247:             done(4);
1248:         }
1249:     } else
1250:         lseek(mt, (daddr_t) -TBLOCK*nblock, 1);
1251:     recno--;
1252: }
1253: 
1254: flushtape()
1255: {
1256:     int i;
1257: 
1258:     i = write(mt, (char *)tbuf, TBLOCK*nblock);
1259:     if (i != TBLOCK*nblock)
1260:         mterr("write", i, 2);
1261: }
1262: 
1263: mterr(operation, i, exitcode)
1264:     char *operation;
1265:     int i;
1266: {
1267:     fprintf(stderr, "tar: tape %s error: ", operation);
1268:     if (i < 0)
1269:         perror("");
1270:     else
1271:         fprintf(stderr, "unexpected EOF\n");
1272:     done(exitcode);
1273: }
1274: 
1275: bread(fd, buf, size)
1276:     int fd;
1277:     char *buf;
1278:     int size;
1279: {
1280:     int count;
1281:     static int lastread = 0;
1282: 
1283:     if (!Bflag)
1284:         return (read(fd, buf, size));
1285: 
1286:     for (count = 0; count < size; count += lastread) {
1287:         lastread = read(fd, buf, size - count);
1288:         if (lastread <= 0) {
1289:             if (count > 0)
1290:                 return (count);
1291:             return (lastread);
1292:         }
1293:         buf += lastread;
1294:     }
1295:     return (count);
1296: }
1297: 
1298: char *
1299: getcwd(buf)
1300:     char *buf;
1301: {
1302:     if (getwd(buf) == NULL) {
1303:         fprintf(stderr, "tar: %s\n", buf);
1304:         exit(1);
1305:     }
1306:     return (buf);
1307: }
1308: 
1309: getbuf()
1310: {
1311: 
1312:     if (nblock == 0) {
1313:         fstat(mt, &stbuf);
1314:         if ((stbuf.st_mode & S_IFMT) == S_IFCHR)
1315:             nblock = NBLOCK;
1316:         else {
1317:             nblock = stbuf.st_blksize / TBLOCK;
1318:             if (nblock == 0)
1319:                 nblock = NBLOCK;
1320:         }
1321:     }
1322:     tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK);
1323:     if (tbuf == NULL) {
1324:         fprintf(stderr, "tar: blocksize %d too big, can't get memory\n",
1325:             nblock);
1326:         done(1);
1327:     }
1328: }
1329: 
1330: /*
1331:  * Save this directory and its mtime on the stack, popping and setting
1332:  * the mtimes of any stacked dirs which aren't parents of this one.
1333:  * A null directory causes the entire stack to be unwound and set.
1334:  *
1335:  * Since all the elements of the directory "stack" share a common
1336:  * prefix, we can make do with one string.  We keep only the current
1337:  * directory path, with an associated array of mtime's, one for each
1338:  * '/' in the path.  A negative mtime means no mtime.  The mtime's are
1339:  * offset by one (first index 1, not 0) because calling this with a null
1340:  * directory causes mtime[0] to be set.
1341:  *
1342:  * This stack algorithm is not guaranteed to work for tapes created
1343:  * with the 'r' option, but the vast majority of tapes with
1344:  * directories are not.  This avoids saving every directory record on
1345:  * the tape and setting all the times at the end.
1346:  */
1347: char dirstack[NAMSIZ];
1348: #define NTIM (NAMSIZ/2+1)       /* a/b/c/d/... */
1349: time_t mtime[NTIM];
1350: 
1351: dodirtimes(hp)
1352:     union hblock *hp;
1353: {
1354:     register char *p = dirstack;
1355:     register char *q = hp->dbuf.name;
1356:     register int ndir = 0;
1357:     char *savp;
1358:     int savndir;
1359: 
1360:     /* Find common prefix */
1361:     while (*p == *q) {
1362:         if (*p++ == '/')
1363:             ++ndir;
1364:         q++;
1365:     }
1366: 
1367:     savp = p;
1368:     savndir = ndir;
1369:     while (*p) {
1370:         /*
1371: 		 * Not a child: unwind the stack, setting the times.
1372: 		 * The order we do this doesn't matter, so we go "forward."
1373: 		 */
1374:         if (*p++ == '/')
1375:             if (mtime[++ndir] >= 0) {
1376:                 *--p = '\0';    /* zap the slash */
1377:                 setimes(dirstack, mtime[ndir]);
1378:                 *p++ = '/';
1379:             }
1380:     }
1381:     p = savp;
1382:     ndir = savndir;
1383: 
1384:     /* Push this one on the "stack" */
1385:     while (*p = *q++)   /* append the rest of the new dir */
1386:         if (*p++ == '/')
1387:             mtime[++ndir] = -1;
1388:     mtime[ndir] = stbuf.st_mtime;   /* overwrite the last one */
1389: }
1390: 
1391: setimes(path, mt)
1392:     char *path;
1393:     time_t mt;
1394: {
1395:     struct timeval tv[2];
1396: 
1397:     tv[0].tv_sec = time((time_t *) 0);
1398:     tv[1].tv_sec = mt;
1399:     tv[0].tv_usec = tv[1].tv_usec = 0;
1400:     if (utimes(path, tv) < 0) {
1401:         fprintf(stderr, "tar: can't set time on %s: ", path);
1402:         perror("");
1403:     }
1404: }
1405: 
1406: char *
1407: getmem(size)
1408: {
1409:     char *p = malloc((unsigned) size);
1410: 
1411:     if (p == NULL && freemem) {
1412:         fprintf(stderr,
1413:             "tar: out of memory, link and directory modtime info lost\n");
1414:         freemem = 0;
1415:     }
1416:     return (p);
1417: }

Defined functions

backtape defined in line 1235; used 1 times
bread defined in line 1275; used 1 times
bsrch defined in line 1085; used 2 times
checkdir defined in line 867; used 1 times
checkf defined in line 985; used 2 times
checksum defined in line 946; used 5 times
checkupdate defined in line 1009; used 1 times
checkw defined in line 960; used 2 times
cmp defined in line 1131; used 1 times
dodirtimes defined in line 1351; used 2 times
done defined in line 1027; used 14 times
dorep defined in line 322; used 1 times
dotable defined in line 773; used 1 times
doxtract defined in line 650; used 1 times
endtape defined in line 397; used 2 times
flushtape defined in line 1254; used 1 times
getbuf defined in line 1309; used 2 times
getcwd defined in line 1298; used 4 times
getdir defined in line 402; used 3 times
getmem defined in line 1406; used 2 times
longt defined in line 803; used 2 times
lookup defined in line 1071; used 2 times
main defined in line 118; never used
mterr defined in line 1263; used 5 times
onhup defined in line 918; used 2 times
onintr defined in line 906; used 2 times
onquit defined in line 912; used 2 times
onterm defined in line 925; used 2 times
openmt defined in line 279; used 2 times
passtape defined in line 432; used 6 times
pmode defined in line 840; used 1 times
prefix defined in line 1057; used 1 times
putempty defined in line 795; used 3 times
putfile defined in line 447; used 2 times
readtape defined in line 1147; used 1 times
readtbuf defined in line 1159; used 3 times
response defined in line 972; used 1 times
selectbits defined in line 849; used 1 times
setimes defined in line 1391; used 3 times
tomodes defined in line 932; used 3 times
usage defined in line 272; used 6 times
wantit defined in line 1037; used 2 times
writetbuf defined in line 1189; 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 1347; 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
iflag defined in line 74; used 2 times
ihead defined in line 64; used 8 times
m defined in line 838; used 12 times
m1 defined in line 828; used 5 times
m2 defined in line 829; used 1 times
m3 defined in line 830; used 1 times
m4 defined in line 831; used 1 times
m5 defined in line 832; used 1 times
m6 defined in line 833; used 1 times
m7 defined in line 834; used 1 times
m8 defined in line 835; used 1 times
m9 defined in line 836; 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
nblock defined in line 89; used 31 times
njab defined in line 1069; 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 1068; used 5 times
NAMSIZ defined in line 33; used 11 times
NBLOCK defined in line 32; used 3 times
NTIM defined in line 1348; used 1 times
RGRP defined in line 821; used 1 times
ROTH defined in line 824; used 1 times
ROWN defined in line 818; used 1 times
SGID defined in line 817; used 1 times
STXT defined in line 827; used 1 times
SUID defined in line 816; used 1 times
TBLOCK defined in line 31; used 43 times
WGRP defined in line 822; used 1 times
WOTH defined in line 825; used 1 times
WOWN defined in line 819; used 1 times
XGRP defined in line 823; used 1 times
XOTH defined in line 826; used 1 times
XOWN defined in line 820; 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: 1986-04-26
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4092
Valid CSS Valid XHTML 1.0 Strict