1*8737Smckusick static char *sccsid = "@(#)tar.c 4.11 (Berkeley) 82/10/20"; 26250Sroot 36250Sroot /* 46250Sroot * Tape Archival Program 56250Sroot */ 61119Sbill #include <stdio.h> 76413Smckusic #include <sys/param.h> 81119Sbill #include <sys/stat.h> 96654Smckusick #include <dir.h> 108150Smckusick #include <sys/ioctl.h> 113457Swnj #include <sys/mtio.h> 121119Sbill #include <signal.h> 131119Sbill 141119Sbill #define TBLOCK 512 153355Swnj #define NBLOCK 20 161119Sbill #define NAMSIZ 100 176250Sroot 181119Sbill union hblock { 191119Sbill char dummy[TBLOCK]; 201119Sbill struct header { 211119Sbill char name[NAMSIZ]; 221119Sbill char mode[8]; 231119Sbill char uid[8]; 241119Sbill char gid[8]; 251119Sbill char size[12]; 261119Sbill char mtime[12]; 271119Sbill char chksum[8]; 281119Sbill char linkflag; 291119Sbill char linkname[NAMSIZ]; 301119Sbill } dbuf; 316250Sroot }; 321119Sbill 331119Sbill struct linkbuf { 341119Sbill ino_t inum; 351119Sbill dev_t devnum; 361119Sbill int count; 371119Sbill char pathname[NAMSIZ]; 381119Sbill struct linkbuf *nextp; 396250Sroot }; 401119Sbill 416250Sroot union hblock dblock; 426250Sroot union hblock tbuf[NBLOCK]; 436250Sroot struct linkbuf *ihead; 446250Sroot struct stat stbuf; 451119Sbill 466250Sroot int rflag; 476250Sroot int xflag; 486250Sroot int vflag; 496250Sroot int tflag; 506250Sroot int cflag; 516250Sroot int mflag; 526250Sroot int fflag; 536250Sroot int oflag; 546250Sroot int pflag; 556250Sroot int wflag; 566250Sroot int hflag; 57*8737Smckusick int Bflag; 586250Sroot 596250Sroot int mt; 606250Sroot int term; 616250Sroot int chksum; 626250Sroot int recno; 636250Sroot int first; 646250Sroot int linkerrok; 651119Sbill int freemem = 1; 663457Swnj int nblock = NBLOCK; 676250Sroot int onintr(); 686250Sroot int onquit(); 696250Sroot int onhup(); 706250Sroot int onterm(); 711119Sbill 721119Sbill daddr_t low; 731119Sbill daddr_t high; 746250Sroot daddr_t bsrch(); 751119Sbill 761119Sbill FILE *tfile; 771119Sbill char tname[] = "/tmp/tarXXXXXX"; 781119Sbill char *usefile; 796250Sroot char magtape[] = "/dev/rmt8"; 801119Sbill char *malloc(); 816250Sroot char *sprintf(); 826250Sroot char *strcat(); 831119Sbill 841119Sbill main(argc, argv) 851119Sbill int argc; 861119Sbill char *argv[]; 871119Sbill { 881119Sbill char *cp; 891119Sbill 901119Sbill if (argc < 2) 911119Sbill usage(); 921119Sbill 931119Sbill tfile = NULL; 941119Sbill usefile = magtape; 951119Sbill argv[argc] = 0; 961119Sbill argv++; 971119Sbill for (cp = *argv++; *cp; cp++) 981119Sbill switch(*cp) { 996250Sroot 1001119Sbill case 'f': 1011119Sbill usefile = *argv++; 1021119Sbill fflag++; 1031119Sbill break; 1046250Sroot 1051119Sbill case 'c': 1061119Sbill cflag++; 1071119Sbill rflag++; 1081119Sbill break; 1096250Sroot 1101119Sbill case 'o': 1111119Sbill oflag++; 1121119Sbill break; 1136250Sroot 1141119Sbill case 'p': 1151119Sbill pflag++; 1161119Sbill break; 1176250Sroot 1181119Sbill case 'u': 1191119Sbill mktemp(tname); 1201119Sbill if ((tfile = fopen(tname, "w")) == NULL) { 1216250Sroot fprintf(stderr, 1226250Sroot "Tar: cannot create temporary file (%s)\n", 1236250Sroot tname); 1241119Sbill done(1); 1251119Sbill } 1261119Sbill fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 1276250Sroot /*FALL THRU*/ 1286250Sroot 1291119Sbill case 'r': 1301119Sbill rflag++; 1311119Sbill break; 1326250Sroot 1331119Sbill case 'v': 1341119Sbill vflag++; 1351119Sbill break; 1366250Sroot 1371119Sbill case 'w': 1381119Sbill wflag++; 1391119Sbill break; 1406250Sroot 1411119Sbill case 'x': 1421119Sbill xflag++; 1431119Sbill break; 1446250Sroot 1451119Sbill case 't': 1461119Sbill tflag++; 1471119Sbill break; 1486250Sroot 1491119Sbill case 'm': 1501119Sbill mflag++; 1511119Sbill break; 1526250Sroot 1531119Sbill case '-': 1541119Sbill break; 1556250Sroot 1561119Sbill case '0': 1571119Sbill case '1': 1581119Sbill case '4': 1591119Sbill case '5': 1601119Sbill case '7': 1611119Sbill case '8': 1621119Sbill magtape[8] = *cp; 1631119Sbill usefile = magtape; 1641119Sbill break; 1656250Sroot 1661119Sbill case 'b': 1671119Sbill nblock = atoi(*argv++); 1681119Sbill if (nblock > NBLOCK || nblock <= 0) { 1696250Sroot fprintf(stderr, "Invalid blocksize. (Max %d)\n", 1706250Sroot NBLOCK); 1711119Sbill done(1); 1721119Sbill } 1731119Sbill break; 1746250Sroot 1751119Sbill case 'l': 1761119Sbill linkerrok++; 1771119Sbill break; 1786250Sroot 1796250Sroot case 'h': 1806250Sroot hflag++; 1816250Sroot break; 1826250Sroot 183*8737Smckusick case 'B': 184*8737Smckusick Bflag++; 185*8737Smckusick break; 186*8737Smckusick 1871119Sbill default: 1881119Sbill fprintf(stderr, "tar: %c: unknown option\n", *cp); 1891119Sbill usage(); 1901119Sbill } 1911119Sbill 1926250Sroot if (!rflag && !xflag && !tflag) 1936250Sroot usage(); 1941119Sbill if (rflag) { 1956250Sroot if (cflag && tfile != NULL) 1961119Sbill usage(); 1971119Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 1981119Sbill signal(SIGINT, onintr); 1991119Sbill if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 2001119Sbill signal(SIGHUP, onhup); 2011119Sbill if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 2021119Sbill signal(SIGQUIT, onquit); 2036250Sroot #ifdef notdef 2041119Sbill if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 2051119Sbill signal(SIGTERM, onterm); 2066250Sroot #endif 2071119Sbill if (strcmp(usefile, "-") == 0) { 2081119Sbill if (cflag == 0) { 2096250Sroot fprintf(stderr, 2106250Sroot "Can only create standard output archives\n"); 2111119Sbill done(1); 2121119Sbill } 2131119Sbill mt = dup(1); 2141119Sbill nblock = 1; 2156250Sroot } else if ((mt = open(usefile, 2)) < 0) { 2161119Sbill if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) { 2176250Sroot fprintf(stderr, 2186250Sroot "tar: cannot open %s\n", usefile); 2191119Sbill done(1); 2201119Sbill } 2211119Sbill } 2221119Sbill dorep(argv); 2236250Sroot done(0); 2241119Sbill } 2256250Sroot if (strcmp(usefile, "-") == 0) { 2266250Sroot mt = dup(0); 2276250Sroot nblock = 1; 2286250Sroot } else if ((mt = open(usefile, 0)) < 0) { 2296250Sroot fprintf(stderr, "tar: cannot open %s\n", usefile); 2306250Sroot done(1); 2316250Sroot } 2326250Sroot if (xflag) 2331119Sbill doxtract(argv); 2346250Sroot else 2351119Sbill dotable(); 2361119Sbill done(0); 2371119Sbill } 2381119Sbill 2391119Sbill usage() 2401119Sbill { 2416250Sroot fprintf(stderr, 242*8737Smckusick "tar: usage tar -{txruB}[cvfblmh] [tapefile] [blocksize] file1 file2...\n"); 2431119Sbill done(1); 2441119Sbill } 2451119Sbill 2461119Sbill dorep(argv) 2476250Sroot char *argv[]; 2481119Sbill { 2491119Sbill register char *cp, *cp2; 2501119Sbill char wdir[60]; 2511119Sbill 2521119Sbill if (!cflag) { 2531119Sbill getdir(); 2541119Sbill do { 2551119Sbill passtape(); 2561119Sbill if (term) 2571119Sbill done(0); 2581119Sbill getdir(); 2591119Sbill } while (!endtape()); 2601119Sbill if (tfile != NULL) { 2611119Sbill char buf[200]; 2621119Sbill 2636250Sroot sprintf(buf, 2646250Sroot "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 2651119Sbill tname, tname, tname, tname, tname, tname); 2661119Sbill fflush(tfile); 2671119Sbill system(buf); 2681119Sbill freopen(tname, "r", tfile); 2691119Sbill fstat(fileno(tfile), &stbuf); 2701119Sbill high = stbuf.st_size; 2711119Sbill } 2721119Sbill } 2731119Sbill 2741119Sbill getwdir(wdir); 2751119Sbill while (*argv && ! term) { 2761119Sbill cp2 = *argv; 2771119Sbill if (!strcmp(cp2, "-C") && argv[1]) { 2781119Sbill argv++; 2791119Sbill if (chdir(*argv) < 0) 2801119Sbill perror(*argv); 2811119Sbill else 2821119Sbill getwdir(wdir); 2831119Sbill argv++; 2841119Sbill continue; 2851119Sbill } 2861119Sbill for (cp = *argv; *cp; cp++) 2871119Sbill if (*cp == '/') 2881119Sbill cp2 = cp; 2891119Sbill if (cp2 != *argv) { 2901119Sbill *cp2 = '\0'; 2911119Sbill chdir(*argv); 2921119Sbill *cp2 = '/'; 2931119Sbill cp2++; 2941119Sbill } 2951119Sbill putfile(*argv++, cp2); 2961119Sbill chdir(wdir); 2971119Sbill } 2981119Sbill putempty(); 2991119Sbill putempty(); 3001119Sbill flushtape(); 3016250Sroot if (linkerrok == 0) 3026250Sroot return; 3036250Sroot for (; ihead != NULL; ihead = ihead->nextp) { 3046250Sroot if (ihead->count == 0) 3056250Sroot continue; 3066250Sroot fprintf(stderr, "Missing links to %s\n", ihead->pathname); 3076250Sroot } 3081119Sbill } 3091119Sbill 3101119Sbill endtape() 3111119Sbill { 3126250Sroot if (dblock.dbuf.name[0] != '\0') 3136250Sroot return (0); 3146250Sroot backtape(); 3156250Sroot return (1); 3161119Sbill } 3171119Sbill 3181119Sbill getdir() 3191119Sbill { 3201119Sbill register struct stat *sp; 3211119Sbill int i; 3221119Sbill 3236250Sroot readtape((char *)&dblock); 3241119Sbill if (dblock.dbuf.name[0] == '\0') 3251119Sbill return; 3261119Sbill sp = &stbuf; 3271119Sbill sscanf(dblock.dbuf.mode, "%o", &i); 3281119Sbill sp->st_mode = i; 3291119Sbill sscanf(dblock.dbuf.uid, "%o", &i); 3301119Sbill sp->st_uid = i; 3311119Sbill sscanf(dblock.dbuf.gid, "%o", &i); 3321119Sbill sp->st_gid = i; 3331119Sbill sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 3341119Sbill sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 3351119Sbill sscanf(dblock.dbuf.chksum, "%o", &chksum); 3361119Sbill if (chksum != checksum()) { 3371119Sbill fprintf(stderr, "directory checksum error\n"); 3381119Sbill done(2); 3391119Sbill } 3401119Sbill if (tfile != NULL) 3411119Sbill fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 3421119Sbill } 3431119Sbill 3441119Sbill passtape() 3451119Sbill { 3461119Sbill long blocks; 3471119Sbill char buf[TBLOCK]; 3481119Sbill 3491119Sbill if (dblock.dbuf.linkflag == '1') 3501119Sbill return; 3511119Sbill blocks = stbuf.st_size; 3521119Sbill blocks += TBLOCK-1; 3531119Sbill blocks /= TBLOCK; 3541119Sbill 3551119Sbill while (blocks-- > 0) 3561119Sbill readtape(buf); 3571119Sbill } 3581119Sbill 3591119Sbill putfile(longname, shortname) 3606250Sroot char *longname; 3616250Sroot char *shortname; 3621119Sbill { 3631119Sbill int infile; 3641119Sbill long blocks; 3651119Sbill char buf[TBLOCK]; 3661119Sbill register char *cp, *cp2; 3675931Smckusic struct direct *dp; 3685931Smckusic DIR *dirp; 3691119Sbill int i, j; 3701119Sbill 3711119Sbill infile = open(shortname, 0); 3721119Sbill if (infile < 0) { 3731119Sbill fprintf(stderr, "tar: %s: cannot open file\n", longname); 3741119Sbill return; 3751119Sbill } 3768150Smckusick lstat(shortname, &stbuf); 3771119Sbill if (tfile != NULL && checkupdate(longname) == 0) { 3781119Sbill close(infile); 3791119Sbill return; 3801119Sbill } 3811119Sbill if (checkw('r', longname) == 0) { 3821119Sbill close(infile); 3831119Sbill return; 3841119Sbill } 3851119Sbill 3861119Sbill if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 3876250Sroot for (i = 0, cp = buf; *cp++ = longname[i++];) 3886250Sroot ; 3891119Sbill *--cp = '/'; 3901119Sbill *++cp = 0 ; 3911119Sbill if (!oflag) { 3926250Sroot if ((cp - buf) >= NAMSIZ) { 3936250Sroot fprintf(stderr, "%s: file name too long\n", 3946250Sroot longname); 3956250Sroot close(infile); 3966250Sroot return; 3976250Sroot } 3986250Sroot stbuf.st_size = 0; 3996250Sroot tomodes(&stbuf); 4006250Sroot strcpy(dblock.dbuf.name,buf); 4016250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 4026250Sroot writetape((char *)&dblock); 4031119Sbill } 4041119Sbill chdir(shortname); 4055931Smckusic close(infile); 4065931Smckusic if ((dirp = opendir(".")) == NULL) { 4075931Smckusic fprintf(stderr, "%s: directory read error\n", longname); 4085931Smckusic return; 4095931Smckusic } 4105931Smckusic while ((dp = readdir(dirp)) != NULL && !term) { 4115931Smckusic if (dp->d_ino == 0) 4121119Sbill continue; 4136250Sroot if (!strcmp(".", dp->d_name) || 4146250Sroot !strcmp("..", dp->d_name)) 4151119Sbill continue; 4165931Smckusic strcpy(cp, dp->d_name); 4175931Smckusic i = telldir(dirp); 4185931Smckusic closedir(dirp); 4191119Sbill putfile(buf, cp); 4205931Smckusic dirp = opendir("."); 4215931Smckusic seekdir(dirp, i); 4221119Sbill } 4235931Smckusic closedir(dirp); 4241119Sbill chdir(".."); 4251119Sbill return; 4261119Sbill } 4276250Sroot i = stbuf.st_mode & S_IFMT; 4286250Sroot if (i != S_IFREG && i != S_IFLNK) { 4296250Sroot fprintf(stderr, "tar: %s is not a file. Not dumped\n", 4306250Sroot longname); 4311119Sbill return; 4321119Sbill } 4331119Sbill tomodes(&stbuf); 4346250Sroot cp2 = longname; cp = dblock.dbuf.name; i = 0; 4356250Sroot while ((*cp++ = *cp2++) && i < NAMSIZ) 4366250Sroot i++; 4371119Sbill if (i >= NAMSIZ) { 4381119Sbill fprintf(stderr, "%s: file name too long\n", longname); 4391119Sbill close(infile); 4401119Sbill return; 4411119Sbill } 4426250Sroot if ((stbuf.st_mode & S_IFMT) == S_IFLNK) { 4436250Sroot if (stbuf.st_size + 1 >= NAMSIZ) { 4446250Sroot fprintf(stderr, "%s: symbolic link too long\n", 4456250Sroot longname); 4466250Sroot close(infile); 4476250Sroot return; 4486250Sroot } 4496250Sroot i = readlink(longname, dblock.dbuf.linkname, NAMSIZ - 1); 4506250Sroot if (i < 0) { 4516250Sroot perror("readlink"); 4526250Sroot close(infile); 4536250Sroot return; 4546250Sroot } 4556250Sroot dblock.dbuf.linkname[i] = '\0'; 4566250Sroot dblock.dbuf.linkflag = '2'; 4576250Sroot if (vflag) { 4586250Sroot fprintf(stderr, "a %s ", longname); 4596250Sroot fprintf(stderr, "symbolic link to %s\n", 4606250Sroot dblock.dbuf.linkname); 4616250Sroot } 4626250Sroot sprintf(dblock.dbuf.size, "%11lo", 0); 4636250Sroot sprintf(dblock.dbuf.chksum, "%6o", checksum()); 4646250Sroot writetape((char *)&dblock); 4656250Sroot close(infile); 4666250Sroot return; 4676250Sroot } 4681119Sbill if (stbuf.st_nlink > 1) { 4691119Sbill struct linkbuf *lp; 4701119Sbill int found = 0; 4711119Sbill 4726250Sroot for (lp = ihead; lp != NULL; lp = lp->nextp) 4736250Sroot if (lp->inum == stbuf.st_ino && 4746250Sroot lp->devnum == stbuf.st_dev) { 4751119Sbill found++; 4761119Sbill break; 4771119Sbill } 4781119Sbill if (found) { 4791119Sbill strcpy(dblock.dbuf.linkname, lp->pathname); 4801119Sbill dblock.dbuf.linkflag = '1'; 4811119Sbill sprintf(dblock.dbuf.chksum, "%6o", checksum()); 4821119Sbill writetape( (char *) &dblock); 4831119Sbill if (vflag) { 4841119Sbill fprintf(stderr, "a %s ", longname); 4851119Sbill fprintf(stderr, "link to %s\n", lp->pathname); 4861119Sbill } 4871119Sbill lp->count--; 4881119Sbill close(infile); 4891119Sbill return; 4901119Sbill } 4916250Sroot lp = (struct linkbuf *) malloc(sizeof(*lp)); 4926250Sroot if (lp == NULL) { 4936250Sroot if (freemem) { 4946250Sroot fprintf(stderr, 4956250Sroot "Out of memory. Link information lost\n"); 4966250Sroot freemem = 0; 4971119Sbill } 4986250Sroot } else { 4996250Sroot lp->nextp = ihead; 5006250Sroot ihead = lp; 5016250Sroot lp->inum = stbuf.st_ino; 5026250Sroot lp->devnum = stbuf.st_dev; 5036250Sroot lp->count = stbuf.st_nlink - 1; 5046250Sroot strcpy(lp->pathname, longname); 5051119Sbill } 5061119Sbill } 5071119Sbill blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 5081119Sbill if (vflag) { 5091119Sbill fprintf(stderr, "a %s ", longname); 5101119Sbill fprintf(stderr, "%ld blocks\n", blocks); 5111119Sbill } 5121119Sbill sprintf(dblock.dbuf.chksum, "%6o", checksum()); 5136250Sroot writetape((char *)&dblock); 5141119Sbill 5151119Sbill while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) { 5161119Sbill writetape(buf); 5171119Sbill blocks--; 5181119Sbill } 5191119Sbill close(infile); 5201119Sbill if (blocks != 0 || i != 0) 5211119Sbill fprintf(stderr, "%s: file changed size\n", longname); 5226250Sroot while (--blocks >= 0) 5231119Sbill putempty(); 5241119Sbill } 5251119Sbill 5261119Sbill doxtract(argv) 5276250Sroot char *argv[]; 5281119Sbill { 5291119Sbill long blocks, bytes; 5301119Sbill char buf[TBLOCK]; 5311119Sbill char **cp; 5321119Sbill int ofile; 5331119Sbill 5341119Sbill for (;;) { 5351119Sbill getdir(); 5361119Sbill if (endtape()) 5371119Sbill break; 5381119Sbill if (*argv == 0) 5391119Sbill goto gotit; 5401119Sbill for (cp = argv; *cp; cp++) 5411119Sbill if (prefix(*cp, dblock.dbuf.name)) 5421119Sbill goto gotit; 5431119Sbill passtape(); 5441119Sbill continue; 5451119Sbill 5461119Sbill gotit: 5471119Sbill if (checkw('x', dblock.dbuf.name) == 0) { 5481119Sbill passtape(); 5491119Sbill continue; 5501119Sbill } 5516250Sroot if (checkdir(dblock.dbuf.name)) 5526250Sroot continue; 5536250Sroot if (dblock.dbuf.linkflag == '2') { 5546250Sroot unlink(dblock.dbuf.name); 5556250Sroot if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 5566250Sroot fprintf(stderr, "%s: symbolic link failed\n", 5576250Sroot dblock.dbuf.name); 5586250Sroot continue; 5596250Sroot } 5606250Sroot if (vflag) 5616250Sroot fprintf(stderr, "x %s symbolic link to %s\n", 5626250Sroot dblock.dbuf.name, dblock.dbuf.linkname); 5638150Smckusick #ifdef notdef 5648150Smckusick /* ignore alien orders */ 5656250Sroot chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 5666250Sroot if (mflag == 0) { 5676250Sroot time_t timep[2]; 5681119Sbill 5696250Sroot timep[0] = time(0); 5706250Sroot timep[1] = stbuf.st_mtime; 5716250Sroot utime(dblock.dbuf.name, timep); 5726250Sroot } 5736250Sroot if (pflag) 5746250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 5758150Smckusick #endif 5761119Sbill continue; 5776250Sroot } 5781119Sbill if (dblock.dbuf.linkflag == '1') { 5791119Sbill unlink(dblock.dbuf.name); 5801119Sbill if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 5816250Sroot fprintf(stderr, "%s: cannot link\n", 5826250Sroot dblock.dbuf.name); 5831119Sbill continue; 5841119Sbill } 5851119Sbill if (vflag) 5863457Swnj fprintf(stderr, "%s linked to %s\n", 5873457Swnj dblock.dbuf.name, dblock.dbuf.linkname); 5881119Sbill continue; 5891119Sbill } 5906250Sroot if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 5916250Sroot fprintf(stderr, "tar: %s - cannot create\n", 5926250Sroot dblock.dbuf.name); 5931119Sbill passtape(); 5941119Sbill continue; 5951119Sbill } 5961926Swnj chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 5971119Sbill blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 5981119Sbill if (vflag) 5993457Swnj fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n", 6003457Swnj dblock.dbuf.name, bytes, blocks); 6016250Sroot for (; blocks-- > 0; bytes -= TBLOCK) { 6021119Sbill readtape(buf); 6031119Sbill if (bytes > TBLOCK) { 6041119Sbill if (write(ofile, buf, TBLOCK) < 0) { 6056250Sroot fprintf(stderr, 6066250Sroot "tar: %s: HELP - extract write error\n", 6076250Sroot dblock.dbuf.name); 6081119Sbill done(2); 6091119Sbill } 6106250Sroot continue; 6116250Sroot } 6126250Sroot if (write(ofile, buf, (int) bytes) < 0) { 6136250Sroot fprintf(stderr, 6146250Sroot "tar: %s: HELP - extract write error\n", 6156250Sroot dblock.dbuf.name); 6166250Sroot done(2); 6176250Sroot } 6181119Sbill } 6191119Sbill close(ofile); 6201119Sbill if (mflag == 0) { 6211119Sbill time_t timep[2]; 6221119Sbill 6231119Sbill timep[0] = time(NULL); 6241119Sbill timep[1] = stbuf.st_mtime; 6251119Sbill utime(dblock.dbuf.name, timep); 6261119Sbill } 6271926Swnj if (pflag) 6286250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 6291119Sbill } 6301119Sbill } 6311119Sbill 6321119Sbill dotable() 6331119Sbill { 6341119Sbill for (;;) { 6351119Sbill getdir(); 6361119Sbill if (endtape()) 6371119Sbill break; 6381119Sbill if (vflag) 6391119Sbill longt(&stbuf); 6401119Sbill printf("%s", dblock.dbuf.name); 6411119Sbill if (dblock.dbuf.linkflag == '1') 6421119Sbill printf(" linked to %s", dblock.dbuf.linkname); 6436250Sroot if (dblock.dbuf.linkflag == '2') 6446250Sroot printf(" symbolic link to %s", dblock.dbuf.linkname); 6451119Sbill printf("\n"); 6461119Sbill passtape(); 6471119Sbill } 6481119Sbill } 6491119Sbill 6501119Sbill putempty() 6511119Sbill { 6521119Sbill char buf[TBLOCK]; 6531119Sbill char *cp; 6541119Sbill 6551119Sbill for (cp = buf; cp < &buf[TBLOCK]; ) 6561119Sbill *cp++ = '\0'; 6571119Sbill writetape(buf); 6581119Sbill } 6591119Sbill 6601119Sbill longt(st) 6616250Sroot register struct stat *st; 6621119Sbill { 6631119Sbill register char *cp; 6641119Sbill char *ctime(); 6651119Sbill 6661119Sbill pmode(st); 6671119Sbill printf("%3d/%1d", st->st_uid, st->st_gid); 6681119Sbill printf("%7D", st->st_size); 6691119Sbill cp = ctime(&st->st_mtime); 6701119Sbill printf(" %-12.12s %-4.4s ", cp+4, cp+20); 6711119Sbill } 6721119Sbill 6731119Sbill #define SUID 04000 6741119Sbill #define SGID 02000 6751119Sbill #define ROWN 0400 6761119Sbill #define WOWN 0200 6771119Sbill #define XOWN 0100 6781119Sbill #define RGRP 040 6791119Sbill #define WGRP 020 6801119Sbill #define XGRP 010 6811119Sbill #define ROTH 04 6821119Sbill #define WOTH 02 6831119Sbill #define XOTH 01 6841119Sbill #define STXT 01000 6851119Sbill int m1[] = { 1, ROWN, 'r', '-' }; 6861119Sbill int m2[] = { 1, WOWN, 'w', '-' }; 6871119Sbill int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 6881119Sbill int m4[] = { 1, RGRP, 'r', '-' }; 6891119Sbill int m5[] = { 1, WGRP, 'w', '-' }; 6901119Sbill int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 6911119Sbill int m7[] = { 1, ROTH, 'r', '-' }; 6921119Sbill int m8[] = { 1, WOTH, 'w', '-' }; 6931119Sbill int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 6941119Sbill 6951119Sbill int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 6961119Sbill 6971119Sbill pmode(st) 6986250Sroot register struct stat *st; 6991119Sbill { 7001119Sbill register int **mp; 7011119Sbill 7021119Sbill for (mp = &m[0]; mp < &m[9];) 7031119Sbill select(*mp++, st); 7041119Sbill } 7051119Sbill 7061119Sbill select(pairp, st) 7076250Sroot int *pairp; 7086250Sroot struct stat *st; 7091119Sbill { 7101119Sbill register int n, *ap; 7111119Sbill 7121119Sbill ap = pairp; 7131119Sbill n = *ap++; 7141119Sbill while (--n>=0 && (st->st_mode&*ap++)==0) 7151119Sbill ap++; 7161119Sbill printf("%c", *ap); 7171119Sbill } 7181119Sbill 7191119Sbill checkdir(name) 7206250Sroot register char *name; 7211119Sbill { 7221119Sbill register char *cp; 7236250Sroot 7241119Sbill for (cp = name; *cp; cp++) { 7256250Sroot if (*cp != '/') 7266250Sroot continue; 7276250Sroot *cp = '\0'; 7286250Sroot if (access(name, 1) < 0) { 7296250Sroot register int pid, rp; 7306250Sroot int i; 7311119Sbill 7326250Sroot if ((pid = fork()) == 0) { 7336250Sroot execl("/bin/mkdir", "mkdir", name, 0); 7346250Sroot execl("/usr/bin/mkdir", "mkdir", name, 0); 7356250Sroot fprintf(stderr, "tar: cannot find mkdir!\n"); 7366250Sroot done(0); 7371119Sbill } 7386250Sroot while ((rp = wait(&i)) >= 0 && rp != pid) 7396250Sroot ; 7406250Sroot chown(name, stbuf.st_uid, stbuf.st_gid); 7416250Sroot if (pflag) 7426250Sroot chmod(dblock.dbuf.name, stbuf.st_mode & 0777); 7431119Sbill } 7446250Sroot *cp = '/'; 7451119Sbill } 7466250Sroot return (cp[-1]=='/'); 7471119Sbill } 7481119Sbill 7491119Sbill onintr() 7501119Sbill { 7511119Sbill signal(SIGINT, SIG_IGN); 7521119Sbill term++; 7531119Sbill } 7541119Sbill 7551119Sbill onquit() 7561119Sbill { 7571119Sbill signal(SIGQUIT, SIG_IGN); 7581119Sbill term++; 7591119Sbill } 7601119Sbill 7611119Sbill onhup() 7621119Sbill { 7631119Sbill signal(SIGHUP, SIG_IGN); 7641119Sbill term++; 7651119Sbill } 7661119Sbill 7671119Sbill onterm() 7681119Sbill { 7691119Sbill signal(SIGTERM, SIG_IGN); 7701119Sbill term++; 7711119Sbill } 7721119Sbill 7731119Sbill tomodes(sp) 7741119Sbill register struct stat *sp; 7751119Sbill { 7761119Sbill register char *cp; 7771119Sbill 7781119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 7791119Sbill *cp = '\0'; 7801119Sbill sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 7811119Sbill sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 7821119Sbill sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 7831119Sbill sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 7841119Sbill sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 7851119Sbill } 7861119Sbill 7871119Sbill checksum() 7881119Sbill { 7891119Sbill register i; 7901119Sbill register char *cp; 7911119Sbill 7926250Sroot for (cp = dblock.dbuf.chksum; 7936250Sroot cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 7941119Sbill *cp = ' '; 7951119Sbill i = 0; 7961119Sbill for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 7971119Sbill i += *cp; 7986250Sroot return (i); 7991119Sbill } 8001119Sbill 8011119Sbill checkw(c, name) 8026250Sroot char *name; 8031119Sbill { 8046250Sroot if (!wflag) 8056250Sroot return (1); 8066250Sroot printf("%c ", c); 8076250Sroot if (vflag) 8086250Sroot longt(&stbuf); 8096250Sroot printf("%s: ", name); 8106250Sroot return (response() == 'y'); 8111119Sbill } 8121119Sbill 8131119Sbill response() 8141119Sbill { 8151119Sbill char c; 8161119Sbill 8171119Sbill c = getchar(); 8181119Sbill if (c != '\n') 8196250Sroot while (getchar() != '\n') 8206250Sroot ; 8216250Sroot else 8226250Sroot c = 'n'; 8236250Sroot return (c); 8241119Sbill } 8251119Sbill 8261119Sbill checkupdate(arg) 8276250Sroot char *arg; 8281119Sbill { 8291119Sbill char name[100]; 8306250Sroot long mtime; 8311119Sbill daddr_t seekp; 8321119Sbill daddr_t lookup(); 8331119Sbill 8341119Sbill rewind(tfile); 8351119Sbill for (;;) { 8361119Sbill if ((seekp = lookup(arg)) < 0) 8376250Sroot return (1); 8381119Sbill fseek(tfile, seekp, 0); 8391119Sbill fscanf(tfile, "%s %lo", name, &mtime); 8406250Sroot return (stbuf.st_mtime > mtime); 8411119Sbill } 8421119Sbill } 8431119Sbill 8441119Sbill done(n) 8451119Sbill { 8461119Sbill unlink(tname); 8471119Sbill exit(n); 8481119Sbill } 8491119Sbill 8501119Sbill prefix(s1, s2) 8516250Sroot register char *s1, *s2; 8521119Sbill { 8531119Sbill while (*s1) 8541119Sbill if (*s1++ != *s2++) 8556250Sroot return (0); 8561119Sbill if (*s2) 8576250Sroot return (*s2 == '/'); 8586250Sroot return (1); 8591119Sbill } 8601119Sbill 8611119Sbill getwdir(s) 8626250Sroot char *s; 8631119Sbill { 8646250Sroot int i, pipdes[2]; 8651119Sbill 8661119Sbill pipe(pipdes); 8671119Sbill if ((i = fork()) == 0) { 8681119Sbill close(1); 8691119Sbill dup(pipdes[1]); 8701119Sbill execl("/bin/pwd", "pwd", 0); 8711119Sbill execl("/usr/bin/pwd", "pwd", 0); 8721119Sbill fprintf(stderr, "pwd failed!\n"); 8731119Sbill printf("/\n"); 8741119Sbill exit(1); 8751119Sbill } 8761119Sbill while (wait((int *)NULL) != -1) 8771119Sbill ; 8781119Sbill read(pipdes[0], s, 50); 8796250Sroot while (*s != '\n') 8801119Sbill s++; 8811119Sbill *s = '\0'; 8821119Sbill close(pipdes[0]); 8831119Sbill close(pipdes[1]); 8841119Sbill } 8851119Sbill 8861119Sbill #define N 200 8871119Sbill int njab; 8886250Sroot 8891119Sbill daddr_t 8901119Sbill lookup(s) 8916250Sroot char *s; 8921119Sbill { 8931119Sbill register i; 8941119Sbill daddr_t a; 8951119Sbill 8961119Sbill for(i=0; s[i]; i++) 8976250Sroot if (s[i] == ' ') 8981119Sbill break; 8991119Sbill a = bsrch(s, i, low, high); 9006250Sroot return (a); 9011119Sbill } 9021119Sbill 9031119Sbill daddr_t 9041119Sbill bsrch(s, n, l, h) 9056250Sroot daddr_t l, h; 9066250Sroot char *s; 9071119Sbill { 9081119Sbill register i, j; 9091119Sbill char b[N]; 9101119Sbill daddr_t m, m1; 9111119Sbill 9121119Sbill njab = 0; 9131119Sbill 9141119Sbill loop: 9156250Sroot if (l >= h) 9166250Sroot return (-1L); 9171119Sbill m = l + (h-l)/2 - N/2; 9186250Sroot if (m < l) 9191119Sbill m = l; 9201119Sbill fseek(tfile, m, 0); 9211119Sbill fread(b, 1, N, tfile); 9221119Sbill njab++; 9231119Sbill for(i=0; i<N; i++) { 9246250Sroot if (b[i] == '\n') 9251119Sbill break; 9261119Sbill m++; 9271119Sbill } 9286250Sroot if (m >= h) 9296250Sroot return (-1L); 9301119Sbill m1 = m; 9311119Sbill j = i; 9321119Sbill for(i++; i<N; i++) { 9331119Sbill m1++; 9346250Sroot if (b[i] == '\n') 9351119Sbill break; 9361119Sbill } 9371119Sbill i = cmp(b+j, s, n); 9386250Sroot if (i < 0) { 9391119Sbill h = m; 9401119Sbill goto loop; 9411119Sbill } 9426250Sroot if (i > 0) { 9431119Sbill l = m1; 9441119Sbill goto loop; 9451119Sbill } 9466250Sroot return (m); 9471119Sbill } 9481119Sbill 9491119Sbill cmp(b, s, n) 9506250Sroot char *b, *s; 9511119Sbill { 9521119Sbill register i; 9531119Sbill 9546250Sroot if (b[0] != '\n') 9551119Sbill exit(2); 9561119Sbill for(i=0; i<n; i++) { 9576250Sroot if (b[i+1] > s[i]) 9586250Sroot return (-1); 9596250Sroot if (b[i+1] < s[i]) 9606250Sroot return (1); 9611119Sbill } 9626250Sroot return (b[i+1] == ' '? 0 : -1); 9631119Sbill } 9641119Sbill 9651119Sbill readtape(buffer) 9666250Sroot char *buffer; 9671119Sbill { 9683457Swnj register int i; 9691119Sbill 9701119Sbill if (recno >= nblock || first == 0) { 971*8737Smckusick if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) { 9721119Sbill fprintf(stderr, "Tar: tape read error\n"); 9731119Sbill done(3); 9741119Sbill } 9751119Sbill if (first == 0) { 9761119Sbill if ((i % TBLOCK) != 0) { 9771119Sbill fprintf(stderr, "Tar: tape blocksize error\n"); 9781119Sbill done(3); 9791119Sbill } 9801119Sbill i /= TBLOCK; 9813457Swnj if (i != nblock) { 9821119Sbill fprintf(stderr, "Tar: blocksize = %d\n", i); 9831119Sbill nblock = i; 9841119Sbill } 9851119Sbill } 9861119Sbill recno = 0; 9871119Sbill } 9881119Sbill first = 1; 9891119Sbill copy(buffer, &tbuf[recno++]); 9906250Sroot return (TBLOCK); 9911119Sbill } 9921119Sbill 9931119Sbill writetape(buffer) 9946250Sroot char *buffer; 9951119Sbill { 9961119Sbill first = 1; 9971119Sbill if (recno >= nblock) { 9981119Sbill if (write(mt, tbuf, TBLOCK*nblock) < 0) { 9991119Sbill fprintf(stderr, "Tar: tape write error\n"); 10001119Sbill done(2); 10011119Sbill } 10021119Sbill recno = 0; 10031119Sbill } 10041119Sbill copy(&tbuf[recno++], buffer); 10051119Sbill if (recno >= nblock) { 10061119Sbill if (write(mt, tbuf, TBLOCK*nblock) < 0) { 10071119Sbill fprintf(stderr, "Tar: tape write error\n"); 10081119Sbill done(2); 10091119Sbill } 10101119Sbill recno = 0; 10111119Sbill } 10126250Sroot return (TBLOCK); 10131119Sbill } 10141119Sbill 10151119Sbill backtape() 10161119Sbill { 10173457Swnj static int mtdev = 1; 10183457Swnj static struct mtop mtop = {MTBSR, 1}; 10193457Swnj struct mtget mtget; 10203457Swnj 10213457Swnj if (mtdev == 1) 10223457Swnj mtdev = ioctl(mt, MTIOCGET, &mtget); 10233457Swnj if (mtdev == 0) { 10243457Swnj if (ioctl(mt, MTIOCTOP, &mtop) < 0) { 10253457Swnj fprintf(stderr, "Tar: tape backspace error\n"); 10261119Sbill done(4); 10271119Sbill } 10283457Swnj } else 10293457Swnj lseek(mt, (long) -TBLOCK*nblock, 1); 10303457Swnj recno--; 10311119Sbill } 10321119Sbill 10331119Sbill flushtape() 10341119Sbill { 10351119Sbill write(mt, tbuf, TBLOCK*nblock); 10361119Sbill } 10371119Sbill 10381119Sbill copy(to, from) 10396250Sroot register char *to, *from; 10401119Sbill { 10411119Sbill register i; 10421119Sbill 10431119Sbill i = TBLOCK; 10441119Sbill do { 10451119Sbill *to++ = *from++; 10461119Sbill } while (--i); 10471119Sbill } 1048*8737Smckusick 1049*8737Smckusick bread(fd, buf, size) 1050*8737Smckusick int fd; 1051*8737Smckusick char *buf; 1052*8737Smckusick int size; 1053*8737Smckusick { 1054*8737Smckusick int count; 1055*8737Smckusick static int lastread = 0; 1056*8737Smckusick 1057*8737Smckusick if (!Bflag) 1058*8737Smckusick return (read(fd, buf, size)); 1059*8737Smckusick for (count = 0; count < size; count += lastread) { 1060*8737Smckusick if (lastread < 0) { 1061*8737Smckusick if (count > 0) 1062*8737Smckusick return (count); 1063*8737Smckusick return (lastread); 1064*8737Smckusick } 1065*8737Smckusick lastread = read(fd, buf, size - count); 1066*8737Smckusick buf += lastread; 1067*8737Smckusick } 1068*8737Smckusick return (count); 1069*8737Smckusick } 1070