xref: /original-bsd/old/tar/tar.c (revision 957a0273)
1 static	char *sccsid = "@(#)tar.c	4.11 (Berkeley) 82/10/20";
2 
3 /*
4  * Tape Archival Program
5  */
6 #include <stdio.h>
7 #include <sys/param.h>
8 #include <sys/stat.h>
9 #include <dir.h>
10 #include <sys/ioctl.h>
11 #include <sys/mtio.h>
12 #include <signal.h>
13 
14 #define TBLOCK	512
15 #define NBLOCK	20
16 #define NAMSIZ	100
17 
18 union hblock {
19 	char dummy[TBLOCK];
20 	struct header {
21 		char name[NAMSIZ];
22 		char mode[8];
23 		char uid[8];
24 		char gid[8];
25 		char size[12];
26 		char mtime[12];
27 		char chksum[8];
28 		char linkflag;
29 		char linkname[NAMSIZ];
30 	} dbuf;
31 };
32 
33 struct linkbuf {
34 	ino_t	inum;
35 	dev_t	devnum;
36 	int	count;
37 	char	pathname[NAMSIZ];
38 	struct	linkbuf *nextp;
39 };
40 
41 union	hblock dblock;
42 union	hblock tbuf[NBLOCK];
43 struct	linkbuf *ihead;
44 struct	stat stbuf;
45 
46 int	rflag;
47 int	xflag;
48 int	vflag;
49 int	tflag;
50 int	cflag;
51 int	mflag;
52 int	fflag;
53 int	oflag;
54 int	pflag;
55 int	wflag;
56 int	hflag;
57 int	Bflag;
58 
59 int	mt;
60 int	term;
61 int	chksum;
62 int	recno;
63 int	first;
64 int	linkerrok;
65 int	freemem = 1;
66 int	nblock = NBLOCK;
67 int	onintr();
68 int	onquit();
69 int	onhup();
70 int	onterm();
71 
72 daddr_t	low;
73 daddr_t	high;
74 daddr_t	bsrch();
75 
76 FILE	*tfile;
77 char	tname[] = "/tmp/tarXXXXXX";
78 char	*usefile;
79 char	magtape[] = "/dev/rmt8";
80 char	*malloc();
81 char	*sprintf();
82 char	*strcat();
83 
84 main(argc, argv)
85 int	argc;
86 char	*argv[];
87 {
88 	char *cp;
89 
90 	if (argc < 2)
91 		usage();
92 
93 	tfile = NULL;
94 	usefile =  magtape;
95 	argv[argc] = 0;
96 	argv++;
97 	for (cp = *argv++; *cp; cp++)
98 		switch(*cp) {
99 
100 		case 'f':
101 			usefile = *argv++;
102 			fflag++;
103 			break;
104 
105 		case 'c':
106 			cflag++;
107 			rflag++;
108 			break;
109 
110 		case 'o':
111 			oflag++;
112 			break;
113 
114 		case 'p':
115 			pflag++;
116 			break;
117 
118 		case 'u':
119 			mktemp(tname);
120 			if ((tfile = fopen(tname, "w")) == NULL) {
121 				fprintf(stderr,
122 				 "Tar: cannot create temporary file (%s)\n",
123 				 tname);
124 				done(1);
125 			}
126 			fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n");
127 			/*FALL THRU*/
128 
129 		case 'r':
130 			rflag++;
131 			break;
132 
133 		case 'v':
134 			vflag++;
135 			break;
136 
137 		case 'w':
138 			wflag++;
139 			break;
140 
141 		case 'x':
142 			xflag++;
143 			break;
144 
145 		case 't':
146 			tflag++;
147 			break;
148 
149 		case 'm':
150 			mflag++;
151 			break;
152 
153 		case '-':
154 			break;
155 
156 		case '0':
157 		case '1':
158 		case '4':
159 		case '5':
160 		case '7':
161 		case '8':
162 			magtape[8] = *cp;
163 			usefile = magtape;
164 			break;
165 
166 		case 'b':
167 			nblock = atoi(*argv++);
168 			if (nblock > NBLOCK || nblock <= 0) {
169 				fprintf(stderr, "Invalid blocksize. (Max %d)\n",
170 					NBLOCK);
171 				done(1);
172 			}
173 			break;
174 
175 		case 'l':
176 			linkerrok++;
177 			break;
178 
179 		case 'h':
180 			hflag++;
181 			break;
182 
183 		case 'B':
184 			Bflag++;
185 			break;
186 
187 		default:
188 			fprintf(stderr, "tar: %c: unknown option\n", *cp);
189 			usage();
190 		}
191 
192 	if (!rflag && !xflag && !tflag)
193 		usage();
194 	if (rflag) {
195 		if (cflag && tfile != NULL)
196 			usage();
197 		if (signal(SIGINT, SIG_IGN) != SIG_IGN)
198 			signal(SIGINT, onintr);
199 		if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
200 			signal(SIGHUP, onhup);
201 		if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
202 			signal(SIGQUIT, onquit);
203 #ifdef notdef
204 		if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
205 			signal(SIGTERM, onterm);
206 #endif
207 		if (strcmp(usefile, "-") == 0) {
208 			if (cflag == 0) {
209 				fprintf(stderr,
210 				 "Can only create standard output archives\n");
211 				done(1);
212 			}
213 			mt = dup(1);
214 			nblock = 1;
215 		} else if ((mt = open(usefile, 2)) < 0) {
216 			if (cflag == 0 || (mt =  creat(usefile, 0666)) < 0) {
217 				fprintf(stderr,
218 					"tar: cannot open %s\n", usefile);
219 				done(1);
220 			}
221 		}
222 		dorep(argv);
223 		done(0);
224 	}
225 	if (strcmp(usefile, "-") == 0) {
226 		mt = dup(0);
227 		nblock = 1;
228 	} else if ((mt = open(usefile, 0)) < 0) {
229 		fprintf(stderr, "tar: cannot open %s\n", usefile);
230 		done(1);
231 	}
232 	if (xflag)
233 		doxtract(argv);
234 	else
235 		dotable();
236 	done(0);
237 }
238 
239 usage()
240 {
241 	fprintf(stderr,
242 "tar: usage  tar -{txruB}[cvfblmh] [tapefile] [blocksize] file1 file2...\n");
243 	done(1);
244 }
245 
246 dorep(argv)
247 	char *argv[];
248 {
249 	register char *cp, *cp2;
250 	char wdir[60];
251 
252 	if (!cflag) {
253 		getdir();
254 		do {
255 			passtape();
256 			if (term)
257 				done(0);
258 			getdir();
259 		} while (!endtape());
260 		if (tfile != NULL) {
261 			char buf[200];
262 
263 			sprintf(buf,
264 "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s",
265 				tname, tname, tname, tname, tname, tname);
266 			fflush(tfile);
267 			system(buf);
268 			freopen(tname, "r", tfile);
269 			fstat(fileno(tfile), &stbuf);
270 			high = stbuf.st_size;
271 		}
272 	}
273 
274 	getwdir(wdir);
275 	while (*argv && ! term) {
276 		cp2 = *argv;
277 		if (!strcmp(cp2, "-C") && argv[1]) {
278 			argv++;
279 			if (chdir(*argv) < 0)
280 				perror(*argv);
281 			else
282 				getwdir(wdir);
283 			argv++;
284 			continue;
285 		}
286 		for (cp = *argv; *cp; cp++)
287 			if (*cp == '/')
288 				cp2 = cp;
289 		if (cp2 != *argv) {
290 			*cp2 = '\0';
291 			chdir(*argv);
292 			*cp2 = '/';
293 			cp2++;
294 		}
295 		putfile(*argv++, cp2);
296 		chdir(wdir);
297 	}
298 	putempty();
299 	putempty();
300 	flushtape();
301 	if (linkerrok == 0)
302 		return;
303 	for (; ihead != NULL; ihead = ihead->nextp) {
304 		if (ihead->count == 0)
305 			continue;
306 		fprintf(stderr, "Missing links to %s\n", ihead->pathname);
307 	}
308 }
309 
310 endtape()
311 {
312 	if (dblock.dbuf.name[0] != '\0')
313 		return (0);
314 	backtape();
315 	return (1);
316 }
317 
318 getdir()
319 {
320 	register struct stat *sp;
321 	int i;
322 
323 	readtape((char *)&dblock);
324 	if (dblock.dbuf.name[0] == '\0')
325 		return;
326 	sp = &stbuf;
327 	sscanf(dblock.dbuf.mode, "%o", &i);
328 	sp->st_mode = i;
329 	sscanf(dblock.dbuf.uid, "%o", &i);
330 	sp->st_uid = i;
331 	sscanf(dblock.dbuf.gid, "%o", &i);
332 	sp->st_gid = i;
333 	sscanf(dblock.dbuf.size, "%lo", &sp->st_size);
334 	sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime);
335 	sscanf(dblock.dbuf.chksum, "%o", &chksum);
336 	if (chksum != checksum()) {
337 		fprintf(stderr, "directory checksum error\n");
338 		done(2);
339 	}
340 	if (tfile != NULL)
341 		fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime);
342 }
343 
344 passtape()
345 {
346 	long blocks;
347 	char buf[TBLOCK];
348 
349 	if (dblock.dbuf.linkflag == '1')
350 		return;
351 	blocks = stbuf.st_size;
352 	blocks += TBLOCK-1;
353 	blocks /= TBLOCK;
354 
355 	while (blocks-- > 0)
356 		readtape(buf);
357 }
358 
359 putfile(longname, shortname)
360 	char *longname;
361 	char *shortname;
362 {
363 	int infile;
364 	long blocks;
365 	char buf[TBLOCK];
366 	register char *cp, *cp2;
367 	struct direct *dp;
368 	DIR *dirp;
369 	int i, j;
370 
371 	infile = open(shortname, 0);
372 	if (infile < 0) {
373 		fprintf(stderr, "tar: %s: cannot open file\n", longname);
374 		return;
375 	}
376 	lstat(shortname, &stbuf);
377 	if (tfile != NULL && checkupdate(longname) == 0) {
378 		close(infile);
379 		return;
380 	}
381 	if (checkw('r', longname) == 0) {
382 		close(infile);
383 		return;
384 	}
385 
386 	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
387 		for (i = 0, cp = buf; *cp++ = longname[i++];)
388 			;
389 		*--cp = '/';
390 		*++cp = 0  ;
391 		if (!oflag) {
392 			if ((cp - buf) >= NAMSIZ) {
393 				fprintf(stderr, "%s: file name too long\n",
394 					longname);
395 				close(infile);
396 				return;
397 			}
398 			stbuf.st_size = 0;
399 			tomodes(&stbuf);
400 			strcpy(dblock.dbuf.name,buf);
401 			sprintf(dblock.dbuf.chksum, "%6o", checksum());
402 			writetape((char *)&dblock);
403 		}
404 		chdir(shortname);
405 		close(infile);
406 		if ((dirp = opendir(".")) == NULL) {
407 			fprintf(stderr, "%s: directory read error\n", longname);
408 			return;
409 		}
410 		while ((dp = readdir(dirp)) != NULL && !term) {
411 			if (dp->d_ino == 0)
412 				continue;
413 			if (!strcmp(".", dp->d_name) ||
414 			    !strcmp("..", dp->d_name))
415 				continue;
416 			strcpy(cp, dp->d_name);
417 			i = telldir(dirp);
418 			closedir(dirp);
419 			putfile(buf, cp);
420 			dirp = opendir(".");
421 			seekdir(dirp, i);
422 		}
423 		closedir(dirp);
424 		chdir("..");
425 		return;
426 	}
427 	i = stbuf.st_mode & S_IFMT;
428 	if (i != S_IFREG && i != S_IFLNK) {
429 		fprintf(stderr, "tar: %s is not a file. Not dumped\n",
430 			longname);
431 		return;
432 	}
433 	tomodes(&stbuf);
434 	cp2 = longname; cp = dblock.dbuf.name; i = 0;
435 	while ((*cp++ = *cp2++) && i < NAMSIZ)
436 		i++;
437 	if (i >= NAMSIZ) {
438 		fprintf(stderr, "%s: file name too long\n", longname);
439 		close(infile);
440 		return;
441 	}
442 	if ((stbuf.st_mode & S_IFMT) == S_IFLNK) {
443 		if (stbuf.st_size + 1 >= NAMSIZ) {
444 			fprintf(stderr, "%s: symbolic link too long\n",
445 				longname);
446 			close(infile);
447 			return;
448 		}
449 		i = readlink(longname, dblock.dbuf.linkname, NAMSIZ - 1);
450 		if (i < 0) {
451 			perror("readlink");
452 			close(infile);
453 			return;
454 		}
455 		dblock.dbuf.linkname[i] = '\0';
456 		dblock.dbuf.linkflag = '2';
457 		if (vflag) {
458 			fprintf(stderr, "a %s ", longname);
459 			fprintf(stderr, "symbolic link to %s\n",
460 				dblock.dbuf.linkname);
461 		}
462 		sprintf(dblock.dbuf.size, "%11lo", 0);
463 		sprintf(dblock.dbuf.chksum, "%6o", checksum());
464 		writetape((char *)&dblock);
465 		close(infile);
466 		return;
467 	}
468 	if (stbuf.st_nlink > 1) {
469 		struct linkbuf *lp;
470 		int found = 0;
471 
472 		for (lp = ihead; lp != NULL; lp = lp->nextp)
473 			if (lp->inum == stbuf.st_ino &&
474 			    lp->devnum == stbuf.st_dev) {
475 				found++;
476 				break;
477 			}
478 		if (found) {
479 			strcpy(dblock.dbuf.linkname, lp->pathname);
480 			dblock.dbuf.linkflag = '1';
481 			sprintf(dblock.dbuf.chksum, "%6o", checksum());
482 			writetape( (char *) &dblock);
483 			if (vflag) {
484 				fprintf(stderr, "a %s ", longname);
485 				fprintf(stderr, "link to %s\n", lp->pathname);
486 			}
487 			lp->count--;
488 			close(infile);
489 			return;
490 		}
491 		lp = (struct linkbuf *) malloc(sizeof(*lp));
492 		if (lp == NULL) {
493 			if (freemem) {
494 				fprintf(stderr,
495 				  "Out of memory. Link information lost\n");
496 				freemem = 0;
497 			}
498 		} else {
499 			lp->nextp = ihead;
500 			ihead = lp;
501 			lp->inum = stbuf.st_ino;
502 			lp->devnum = stbuf.st_dev;
503 			lp->count = stbuf.st_nlink - 1;
504 			strcpy(lp->pathname, longname);
505 		}
506 	}
507 	blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK;
508 	if (vflag) {
509 		fprintf(stderr, "a %s ", longname);
510 		fprintf(stderr, "%ld blocks\n", blocks);
511 	}
512 	sprintf(dblock.dbuf.chksum, "%6o", checksum());
513 	writetape((char *)&dblock);
514 
515 	while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) {
516 		writetape(buf);
517 		blocks--;
518 	}
519 	close(infile);
520 	if (blocks != 0 || i != 0)
521 		fprintf(stderr, "%s: file changed size\n", longname);
522 	while (--blocks >=  0)
523 		putempty();
524 }
525 
526 doxtract(argv)
527 	char *argv[];
528 {
529 	long blocks, bytes;
530 	char buf[TBLOCK];
531 	char **cp;
532 	int ofile;
533 
534 	for (;;) {
535 		getdir();
536 		if (endtape())
537 			break;
538 		if (*argv == 0)
539 			goto gotit;
540 		for (cp = argv; *cp; cp++)
541 			if (prefix(*cp, dblock.dbuf.name))
542 				goto gotit;
543 		passtape();
544 		continue;
545 
546 gotit:
547 		if (checkw('x', dblock.dbuf.name) == 0) {
548 			passtape();
549 			continue;
550 		}
551 		if (checkdir(dblock.dbuf.name))
552 			continue;
553 		if (dblock.dbuf.linkflag == '2') {
554 			unlink(dblock.dbuf.name);
555 			if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) {
556 				fprintf(stderr, "%s: symbolic link failed\n",
557 					dblock.dbuf.name);
558 				continue;
559 			}
560 			if (vflag)
561 				fprintf(stderr, "x %s symbolic link to %s\n",
562 				  dblock.dbuf.name, dblock.dbuf.linkname);
563 #ifdef notdef
564 			/* ignore alien orders */
565 			chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
566 			if (mflag == 0) {
567 				time_t timep[2];
568 
569 				timep[0] = time(0);
570 				timep[1] = stbuf.st_mtime;
571 				utime(dblock.dbuf.name, timep);
572 			}
573 			if (pflag)
574 				chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
575 #endif
576 			continue;
577 		}
578 		if (dblock.dbuf.linkflag == '1') {
579 			unlink(dblock.dbuf.name);
580 			if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) {
581 				fprintf(stderr, "%s: cannot link\n",
582 					dblock.dbuf.name);
583 				continue;
584 			}
585 			if (vflag)
586 				fprintf(stderr, "%s linked to %s\n",
587 					dblock.dbuf.name, dblock.dbuf.linkname);
588 			continue;
589 		}
590 		if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) {
591 			fprintf(stderr, "tar: %s - cannot create\n",
592 				dblock.dbuf.name);
593 			passtape();
594 			continue;
595 		}
596 		chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
597 		blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK;
598 		if (vflag)
599 			fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n",
600 				dblock.dbuf.name, bytes, blocks);
601 		for (; blocks-- > 0; bytes -= TBLOCK) {
602 			readtape(buf);
603 			if (bytes > TBLOCK) {
604 				if (write(ofile, buf, TBLOCK) < 0) {
605 					fprintf(stderr,
606 					"tar: %s: HELP - extract write error\n",
607 					 dblock.dbuf.name);
608 					done(2);
609 				}
610 				continue;
611 			}
612 			if (write(ofile, buf, (int) bytes) < 0) {
613 				fprintf(stderr,
614 					"tar: %s: HELP - extract write error\n",
615 					dblock.dbuf.name);
616 				done(2);
617 			}
618 		}
619 		close(ofile);
620 		if (mflag == 0) {
621 			time_t timep[2];
622 
623 			timep[0] = time(NULL);
624 			timep[1] = stbuf.st_mtime;
625 			utime(dblock.dbuf.name, timep);
626 		}
627 		if (pflag)
628 			chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
629 	}
630 }
631 
632 dotable()
633 {
634 	for (;;) {
635 		getdir();
636 		if (endtape())
637 			break;
638 		if (vflag)
639 			longt(&stbuf);
640 		printf("%s", dblock.dbuf.name);
641 		if (dblock.dbuf.linkflag == '1')
642 			printf(" linked to %s", dblock.dbuf.linkname);
643 		if (dblock.dbuf.linkflag == '2')
644 			printf(" symbolic link to %s", dblock.dbuf.linkname);
645 		printf("\n");
646 		passtape();
647 	}
648 }
649 
650 putempty()
651 {
652 	char buf[TBLOCK];
653 	char *cp;
654 
655 	for (cp = buf; cp < &buf[TBLOCK]; )
656 		*cp++ = '\0';
657 	writetape(buf);
658 }
659 
660 longt(st)
661 	register struct stat *st;
662 {
663 	register char *cp;
664 	char *ctime();
665 
666 	pmode(st);
667 	printf("%3d/%1d", st->st_uid, st->st_gid);
668 	printf("%7D", st->st_size);
669 	cp = ctime(&st->st_mtime);
670 	printf(" %-12.12s %-4.4s ", cp+4, cp+20);
671 }
672 
673 #define	SUID	04000
674 #define	SGID	02000
675 #define	ROWN	0400
676 #define	WOWN	0200
677 #define	XOWN	0100
678 #define	RGRP	040
679 #define	WGRP	020
680 #define	XGRP	010
681 #define	ROTH	04
682 #define	WOTH	02
683 #define	XOTH	01
684 #define	STXT	01000
685 int	m1[] = { 1, ROWN, 'r', '-' };
686 int	m2[] = { 1, WOWN, 'w', '-' };
687 int	m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
688 int	m4[] = { 1, RGRP, 'r', '-' };
689 int	m5[] = { 1, WGRP, 'w', '-' };
690 int	m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
691 int	m7[] = { 1, ROTH, 'r', '-' };
692 int	m8[] = { 1, WOTH, 'w', '-' };
693 int	m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
694 
695 int	*m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
696 
697 pmode(st)
698 	register struct stat *st;
699 {
700 	register int **mp;
701 
702 	for (mp = &m[0]; mp < &m[9];)
703 		select(*mp++, st);
704 }
705 
706 select(pairp, st)
707 	int *pairp;
708 	struct stat *st;
709 {
710 	register int n, *ap;
711 
712 	ap = pairp;
713 	n = *ap++;
714 	while (--n>=0 && (st->st_mode&*ap++)==0)
715 		ap++;
716 	printf("%c", *ap);
717 }
718 
719 checkdir(name)
720 	register char *name;
721 {
722 	register char *cp;
723 
724 	for (cp = name; *cp; cp++) {
725 		if (*cp != '/')
726 			continue;
727 		*cp = '\0';
728 		if (access(name, 1) < 0) {
729 			register int pid, rp;
730 			int i;
731 
732 			if ((pid = fork()) == 0) {
733 				execl("/bin/mkdir", "mkdir", name, 0);
734 				execl("/usr/bin/mkdir", "mkdir", name, 0);
735 				fprintf(stderr, "tar: cannot find mkdir!\n");
736 				done(0);
737 			}
738 			while ((rp = wait(&i)) >= 0 && rp != pid)
739 				;
740 			chown(name, stbuf.st_uid, stbuf.st_gid);
741 			if (pflag)
742 				chmod(dblock.dbuf.name, stbuf.st_mode & 0777);
743 		}
744 		*cp = '/';
745 	}
746 	return (cp[-1]=='/');
747 }
748 
749 onintr()
750 {
751 	signal(SIGINT, SIG_IGN);
752 	term++;
753 }
754 
755 onquit()
756 {
757 	signal(SIGQUIT, SIG_IGN);
758 	term++;
759 }
760 
761 onhup()
762 {
763 	signal(SIGHUP, SIG_IGN);
764 	term++;
765 }
766 
767 onterm()
768 {
769 	signal(SIGTERM, SIG_IGN);
770 	term++;
771 }
772 
773 tomodes(sp)
774 register struct stat *sp;
775 {
776 	register char *cp;
777 
778 	for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
779 		*cp = '\0';
780 	sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777);
781 	sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid);
782 	sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid);
783 	sprintf(dblock.dbuf.size, "%11lo ", sp->st_size);
784 	sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime);
785 }
786 
787 checksum()
788 {
789 	register i;
790 	register char *cp;
791 
792 	for (cp = dblock.dbuf.chksum;
793 	     cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
794 		*cp = ' ';
795 	i = 0;
796 	for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
797 		i += *cp;
798 	return (i);
799 }
800 
801 checkw(c, name)
802 	char *name;
803 {
804 	if (!wflag)
805 		return (1);
806 	printf("%c ", c);
807 	if (vflag)
808 		longt(&stbuf);
809 	printf("%s: ", name);
810 	return (response() == 'y');
811 }
812 
813 response()
814 {
815 	char c;
816 
817 	c = getchar();
818 	if (c != '\n')
819 		while (getchar() != '\n')
820 			;
821 	else
822 		c = 'n';
823 	return (c);
824 }
825 
826 checkupdate(arg)
827 	char *arg;
828 {
829 	char name[100];
830 	long mtime;
831 	daddr_t seekp;
832 	daddr_t	lookup();
833 
834 	rewind(tfile);
835 	for (;;) {
836 		if ((seekp = lookup(arg)) < 0)
837 			return (1);
838 		fseek(tfile, seekp, 0);
839 		fscanf(tfile, "%s %lo", name, &mtime);
840 		return (stbuf.st_mtime > mtime);
841 	}
842 }
843 
844 done(n)
845 {
846 	unlink(tname);
847 	exit(n);
848 }
849 
850 prefix(s1, s2)
851 	register char *s1, *s2;
852 {
853 	while (*s1)
854 		if (*s1++ != *s2++)
855 			return (0);
856 	if (*s2)
857 		return (*s2 == '/');
858 	return (1);
859 }
860 
861 getwdir(s)
862 	char *s;
863 {
864 	int i, pipdes[2];
865 
866 	pipe(pipdes);
867 	if ((i = fork()) == 0) {
868 		close(1);
869 		dup(pipdes[1]);
870 		execl("/bin/pwd", "pwd", 0);
871 		execl("/usr/bin/pwd", "pwd", 0);
872 		fprintf(stderr, "pwd failed!\n");
873 		printf("/\n");
874 		exit(1);
875 	}
876 	while (wait((int *)NULL) != -1)
877 			;
878 	read(pipdes[0], s, 50);
879 	while (*s != '\n')
880 		s++;
881 	*s = '\0';
882 	close(pipdes[0]);
883 	close(pipdes[1]);
884 }
885 
886 #define	N	200
887 int	njab;
888 
889 daddr_t
890 lookup(s)
891 	char *s;
892 {
893 	register i;
894 	daddr_t a;
895 
896 	for(i=0; s[i]; i++)
897 		if (s[i] == ' ')
898 			break;
899 	a = bsrch(s, i, low, high);
900 	return (a);
901 }
902 
903 daddr_t
904 bsrch(s, n, l, h)
905 	daddr_t l, h;
906 	char *s;
907 {
908 	register i, j;
909 	char b[N];
910 	daddr_t m, m1;
911 
912 	njab = 0;
913 
914 loop:
915 	if (l >= h)
916 		return (-1L);
917 	m = l + (h-l)/2 - N/2;
918 	if (m < l)
919 		m = l;
920 	fseek(tfile, m, 0);
921 	fread(b, 1, N, tfile);
922 	njab++;
923 	for(i=0; i<N; i++) {
924 		if (b[i] == '\n')
925 			break;
926 		m++;
927 	}
928 	if (m >= h)
929 		return (-1L);
930 	m1 = m;
931 	j = i;
932 	for(i++; i<N; i++) {
933 		m1++;
934 		if (b[i] == '\n')
935 			break;
936 	}
937 	i = cmp(b+j, s, n);
938 	if (i < 0) {
939 		h = m;
940 		goto loop;
941 	}
942 	if (i > 0) {
943 		l = m1;
944 		goto loop;
945 	}
946 	return (m);
947 }
948 
949 cmp(b, s, n)
950 	char *b, *s;
951 {
952 	register i;
953 
954 	if (b[0] != '\n')
955 		exit(2);
956 	for(i=0; i<n; i++) {
957 		if (b[i+1] > s[i])
958 			return (-1);
959 		if (b[i+1] < s[i])
960 			return (1);
961 	}
962 	return (b[i+1] == ' '? 0 : -1);
963 }
964 
965 readtape(buffer)
966 	char *buffer;
967 {
968 	register int i;
969 
970 	if (recno >= nblock || first == 0) {
971 		if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) {
972 			fprintf(stderr, "Tar: tape read error\n");
973 			done(3);
974 		}
975 		if (first == 0) {
976 			if ((i % TBLOCK) != 0) {
977 				fprintf(stderr, "Tar: tape blocksize error\n");
978 				done(3);
979 			}
980 			i /= TBLOCK;
981 			if (i != nblock) {
982 				fprintf(stderr, "Tar: blocksize = %d\n", i);
983 				nblock = i;
984 			}
985 		}
986 		recno = 0;
987 	}
988 	first = 1;
989 	copy(buffer, &tbuf[recno++]);
990 	return (TBLOCK);
991 }
992 
993 writetape(buffer)
994 	char *buffer;
995 {
996 	first = 1;
997 	if (recno >= nblock) {
998 		if (write(mt, tbuf, TBLOCK*nblock) < 0) {
999 			fprintf(stderr, "Tar: tape write error\n");
1000 			done(2);
1001 		}
1002 		recno = 0;
1003 	}
1004 	copy(&tbuf[recno++], buffer);
1005 	if (recno >= nblock) {
1006 		if (write(mt, tbuf, TBLOCK*nblock) < 0) {
1007 			fprintf(stderr, "Tar: tape write error\n");
1008 			done(2);
1009 		}
1010 		recno = 0;
1011 	}
1012 	return (TBLOCK);
1013 }
1014 
1015 backtape()
1016 {
1017 	static int mtdev = 1;
1018 	static struct mtop mtop = {MTBSR, 1};
1019 	struct mtget mtget;
1020 
1021 	if (mtdev == 1)
1022 		mtdev = ioctl(mt, MTIOCGET, &mtget);
1023 	if (mtdev == 0) {
1024 		if (ioctl(mt, MTIOCTOP, &mtop) < 0) {
1025 			fprintf(stderr, "Tar: tape backspace error\n");
1026 			done(4);
1027 		}
1028 	} else
1029 		lseek(mt, (long) -TBLOCK*nblock, 1);
1030 	recno--;
1031 }
1032 
1033 flushtape()
1034 {
1035 	write(mt, tbuf, TBLOCK*nblock);
1036 }
1037 
1038 copy(to, from)
1039 	register char *to, *from;
1040 {
1041 	register i;
1042 
1043 	i = TBLOCK;
1044 	do {
1045 		*to++ = *from++;
1046 	} while (--i);
1047 }
1048 
1049 bread(fd, buf, size)
1050 	int fd;
1051 	char *buf;
1052 	int size;
1053 {
1054 	int count;
1055 	static int lastread = 0;
1056 
1057 	if (!Bflag)
1058 		return (read(fd, buf, size));
1059 	for (count = 0; count < size; count += lastread) {
1060 		if (lastread < 0) {
1061 			if (count > 0)
1062 				return (count);
1063 			return (lastread);
1064 		}
1065 		lastread = read(fd, buf, size - count);
1066 		buf += lastread;
1067 	}
1068 	return (count);
1069 }
1070