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