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