xref: /original-bsd/old/tar/tar.c (revision 6c57d260)
1 static	char *sccsid = "@(#)tar.c	4.5 (Berkeley) 81/04/02";
2 #include <stdio.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <sys/dir.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 dbuf;
323 	int i, j;
324 
325 	infile = open(shortname, 0);
326 	if (infile < 0) {
327 		fprintf(stderr, "tar: %s: cannot open file\n", longname);
328 		return;
329 	}
330 
331 	fstat(infile, &stbuf);
332 
333 	if (tfile != NULL && checkupdate(longname) == 0) {
334 		close(infile);
335 		return;
336 	}
337 	if (checkw('r', longname) == 0) {
338 		close(infile);
339 		return;
340 	}
341 
342 	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
343 		for (i = 0, cp = buf; *cp++ = longname[i++];);
344 		*--cp = '/';
345 		*++cp = 0  ;
346 		i = 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 		while (read(infile, (char *)&dbuf, sizeof(dbuf)) > 0 && !term) {
361 			if (dbuf.d_ino == 0) {
362 				i++;
363 				continue;
364 			}
365 			if (strcmp(".", dbuf.d_name) == 0 || strcmp("..", dbuf.d_name) == 0) {
366 				i++;
367 				continue;
368 			}
369 			cp2 = cp;
370 			for (j=0; j < DIRSIZ; j++)
371 				*cp2++ = dbuf.d_name[j];
372 			*cp2 = '\0';
373 			close(infile);
374 			putfile(buf, cp);
375 			infile = open(".", 0);
376 			i++;
377 			lseek(infile, (long) (sizeof(dbuf) * i), 0);
378 		}
379 		close(infile);
380 		chdir("..");
381 		return;
382 	}
383 	if ((stbuf.st_mode & S_IFMT) != S_IFREG) {
384 		fprintf(stderr, "tar: %s is not a file. Not dumped\n", longname);
385 		return;
386 	}
387 
388 	tomodes(&stbuf);
389 
390 	cp2 = longname;
391 	for (cp = dblock.dbuf.name, i=0; (*cp++ = *cp2++) && i < NAMSIZ; i++);
392 	if (i >= NAMSIZ) {
393 		fprintf(stderr, "%s: file name too long\n", longname);
394 		close(infile);
395 		return;
396 	}
397 
398 	if (stbuf.st_nlink > 1) {
399 		struct linkbuf *lp;
400 		int found = 0;
401 
402 		for (lp = ihead; lp != NULL; lp = lp->nextp) {
403 			if (lp->inum == stbuf.st_ino && lp->devnum == stbuf.st_dev) {
404 				found++;
405 				break;
406 			}
407 		}
408 		if (found) {
409 			strcpy(dblock.dbuf.linkname, lp->pathname);
410 			dblock.dbuf.linkflag = '1';
411 			sprintf(dblock.dbuf.chksum, "%6o", checksum());
412 			writetape( (char *) &dblock);
413 			if (vflag) {
414 				fprintf(stderr, "a %s ", longname);
415 				fprintf(stderr, "link to %s\n", lp->pathname);
416 			}
417 			lp->count--;
418 			close(infile);
419 			return;
420 		}
421 		else {
422 			lp = (struct linkbuf *) malloc(sizeof(*lp));
423 			if (lp == NULL) {
424 				if (freemem) {
425 					fprintf(stderr, "Out of memory. Link information lost\n");
426 					freemem = 0;
427 				}
428 			}
429 			else {
430 				lp->nextp = ihead;
431 				ihead = lp;
432 				lp->inum = stbuf.st_ino;
433 				lp->devnum = stbuf.st_dev;
434 				lp->count = stbuf.st_nlink - 1;
435 				strcpy(lp->pathname, longname);
436 			}
437 		}
438 	}
439 
440 	blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK;
441 	if (vflag) {
442 		fprintf(stderr, "a %s ", longname);
443 		fprintf(stderr, "%ld blocks\n", blocks);
444 	}
445 	sprintf(dblock.dbuf.chksum, "%6o", checksum());
446 	writetape( (char *) &dblock);
447 
448 	while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) {
449 		writetape(buf);
450 		blocks--;
451 	}
452 	close(infile);
453 	if (blocks != 0 || i != 0)
454 		fprintf(stderr, "%s: file changed size\n", longname);
455 	while (blocks-- >  0)
456 		putempty();
457 }
458 
459 
460 
461 doxtract(argv)
462 char	*argv[];
463 {
464 	long blocks, bytes;
465 	char buf[TBLOCK];
466 	char **cp;
467 	int ofile;
468 
469 	for (;;) {
470 		getdir();
471 		if (endtape())
472 			break;
473 
474 		if (*argv == 0)
475 			goto gotit;
476 
477 		for (cp = argv; *cp; cp++)
478 			if (prefix(*cp, dblock.dbuf.name))
479 				goto gotit;
480 		passtape();
481 		continue;
482 
483 gotit:
484 		if (checkw('x', dblock.dbuf.name) == 0) {
485 			passtape();
486 			continue;
487 		}
488 
489 		if(checkdir(dblock.dbuf.name))
490 			continue;
491 
492 		if (dblock.dbuf.linkflag == '1') {
493 			unlink(dblock.dbuf.name);
494 			if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) {
495 				fprintf(stderr, "%s: cannot link\n", dblock.dbuf.name);
496 				continue;
497 			}
498 			if (vflag)
499 				fprintf(stderr, "%s linked to %s\n",
500 					dblock.dbuf.name, dblock.dbuf.linkname);
501 			continue;
502 		}
503 		if ((ofile = creat(dblock.dbuf.name, stbuf.st_mode & 07777)) < 0) {
504 			fprintf(stderr, "tar: %s - cannot create\n", dblock.dbuf.name);
505 			passtape();
506 			continue;
507 		}
508 		chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
509 
510 		blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK;
511 		if (vflag)
512 			fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n",
513 				dblock.dbuf.name, bytes, blocks);
514 		while (blocks-- > 0) {
515 			readtape(buf);
516 			if (bytes > TBLOCK) {
517 				if (write(ofile, buf, TBLOCK) < 0) {
518 					fprintf(stderr, "tar: %s: HELP - extract write error\n", dblock.dbuf.name);
519 					done(2);
520 				}
521 			} else
522 				if (write(ofile, buf, (int) bytes) < 0) {
523 					fprintf(stderr, "tar: %s: HELP - extract write error\n", dblock.dbuf.name);
524 					done(2);
525 				}
526 			bytes -= TBLOCK;
527 		}
528 		close(ofile);
529 		if (mflag == 0) {
530 			time_t timep[2];
531 
532 			timep[0] = time(NULL);
533 			timep[1] = stbuf.st_mtime;
534 			utime(dblock.dbuf.name, timep);
535 		}
536 		if (pflag)
537 		    chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
538 	}
539 }
540 
541 dotable()
542 {
543 	for (;;) {
544 		getdir();
545 		if (endtape())
546 			break;
547 		if (vflag)
548 			longt(&stbuf);
549 		printf("%s", dblock.dbuf.name);
550 		if (dblock.dbuf.linkflag == '1')
551 			printf(" linked to %s", dblock.dbuf.linkname);
552 		printf("\n");
553 		passtape();
554 	}
555 }
556 
557 putempty()
558 {
559 	char buf[TBLOCK];
560 	char *cp;
561 
562 	for (cp = buf; cp < &buf[TBLOCK]; )
563 		*cp++ = '\0';
564 	writetape(buf);
565 }
566 
567 longt(st)
568 register struct stat *st;
569 {
570 	register char *cp;
571 	char *ctime();
572 
573 	pmode(st);
574 	printf("%3d/%1d", st->st_uid, st->st_gid);
575 	printf("%7D", st->st_size);
576 	cp = ctime(&st->st_mtime);
577 	printf(" %-12.12s %-4.4s ", cp+4, cp+20);
578 }
579 
580 #define	SUID	04000
581 #define	SGID	02000
582 #define	ROWN	0400
583 #define	WOWN	0200
584 #define	XOWN	0100
585 #define	RGRP	040
586 #define	WGRP	020
587 #define	XGRP	010
588 #define	ROTH	04
589 #define	WOTH	02
590 #define	XOTH	01
591 #define	STXT	01000
592 int	m1[] = { 1, ROWN, 'r', '-' };
593 int	m2[] = { 1, WOWN, 'w', '-' };
594 int	m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
595 int	m4[] = { 1, RGRP, 'r', '-' };
596 int	m5[] = { 1, WGRP, 'w', '-' };
597 int	m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
598 int	m7[] = { 1, ROTH, 'r', '-' };
599 int	m8[] = { 1, WOTH, 'w', '-' };
600 int	m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
601 
602 int	*m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
603 
604 pmode(st)
605 register struct stat *st;
606 {
607 	register int **mp;
608 
609 	for (mp = &m[0]; mp < &m[9];)
610 		select(*mp++, st);
611 }
612 
613 select(pairp, st)
614 int *pairp;
615 struct stat *st;
616 {
617 	register int n, *ap;
618 
619 	ap = pairp;
620 	n = *ap++;
621 	while (--n>=0 && (st->st_mode&*ap++)==0)
622 		ap++;
623 	printf("%c", *ap);
624 }
625 
626 checkdir(name)
627 register char *name;
628 {
629 	register char *cp;
630 	int i;
631 	for (cp = name; *cp; cp++) {
632 		if (*cp == '/') {
633 			*cp = '\0';
634 			if (access(name, 01) < 0) {
635 				register int pid, rp;
636 
637 				if ((pid = fork()) == 0) {
638 					execl("/bin/mkdir", "mkdir", name, 0);
639 					execl("/usr/bin/mkdir", "mkdir", name, 0);
640 					fprintf(stderr, "tar: cannot find mkdir!\n");
641 					done(0);
642 				}
643 				while ((rp = wait(&i)) >= 0 && rp != pid)
644 					;
645 				chown(name, stbuf.st_uid, stbuf.st_gid);
646 				if (pflag)
647 					chmod(dblock.dbuf.name,
648 					    stbuf.st_mode & 0777);
649 			}
650 			*cp = '/';
651 		}
652 	}
653 	return(cp[-1]=='/');
654 }
655 
656 onintr()
657 {
658 	signal(SIGINT, SIG_IGN);
659 	term++;
660 }
661 
662 onquit()
663 {
664 	signal(SIGQUIT, SIG_IGN);
665 	term++;
666 }
667 
668 onhup()
669 {
670 	signal(SIGHUP, SIG_IGN);
671 	term++;
672 }
673 
674 onterm()
675 {
676 	signal(SIGTERM, SIG_IGN);
677 	term++;
678 }
679 
680 tomodes(sp)
681 register struct stat *sp;
682 {
683 	register char *cp;
684 
685 	for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
686 		*cp = '\0';
687 	sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777);
688 	sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid);
689 	sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid);
690 	sprintf(dblock.dbuf.size, "%11lo ", sp->st_size);
691 	sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime);
692 }
693 
694 checksum()
695 {
696 	register i;
697 	register char *cp;
698 
699 	for (cp = dblock.dbuf.chksum; cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
700 		*cp = ' ';
701 	i = 0;
702 	for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
703 		i += *cp;
704 	return(i);
705 }
706 
707 checkw(c, name)
708 char *name;
709 {
710 	if (wflag) {
711 		printf("%c ", c);
712 		if (vflag)
713 			longt(&stbuf);
714 		printf("%s: ", name);
715 		if (response() == 'y'){
716 			return(1);
717 		}
718 		return(0);
719 	}
720 	return(1);
721 }
722 
723 response()
724 {
725 	char c;
726 
727 	c = getchar();
728 	if (c != '\n')
729 		while (getchar() != '\n');
730 	else c = 'n';
731 	return(c);
732 }
733 
734 checkupdate(arg)
735 char	*arg;
736 {
737 	char name[100];
738 	long	mtime;
739 	daddr_t seekp;
740 	daddr_t	lookup();
741 
742 	rewind(tfile);
743 	for (;;) {
744 		if ((seekp = lookup(arg)) < 0)
745 			return(1);
746 		fseek(tfile, seekp, 0);
747 		fscanf(tfile, "%s %lo", name, &mtime);
748 		if (stbuf.st_mtime > mtime)
749 			return(1);
750 		else
751 			return(0);
752 	}
753 }
754 
755 done(n)
756 {
757 	unlink(tname);
758 	exit(n);
759 }
760 
761 prefix(s1, s2)
762 register char *s1, *s2;
763 {
764 	while (*s1)
765 		if (*s1++ != *s2++)
766 			return(0);
767 	if (*s2)
768 		return(*s2 == '/');
769 	return(1);
770 }
771 
772 getwdir(s)
773 char *s;
774 {
775 	int i;
776 	int	pipdes[2];
777 
778 	pipe(pipdes);
779 	if ((i = fork()) == 0) {
780 		close(1);
781 		dup(pipdes[1]);
782 		execl("/bin/pwd", "pwd", 0);
783 		execl("/usr/bin/pwd", "pwd", 0);
784 		fprintf(stderr, "pwd failed!\n");
785 		printf("/\n");
786 		exit(1);
787 	}
788 	while (wait((int *)NULL) != -1)
789 			;
790 	read(pipdes[0], s, 50);
791 	while(*s != '\n')
792 		s++;
793 	*s = '\0';
794 	close(pipdes[0]);
795 	close(pipdes[1]);
796 }
797 
798 #define	N	200
799 int	njab;
800 daddr_t
801 lookup(s)
802 char *s;
803 {
804 	register i;
805 	daddr_t a;
806 
807 	for(i=0; s[i]; i++)
808 		if(s[i] == ' ')
809 			break;
810 	a = bsrch(s, i, low, high);
811 	return(a);
812 }
813 
814 daddr_t
815 bsrch(s, n, l, h)
816 daddr_t l, h;
817 char *s;
818 {
819 	register i, j;
820 	char b[N];
821 	daddr_t m, m1;
822 
823 	njab = 0;
824 
825 loop:
826 	if(l >= h)
827 		return(-1L);
828 	m = l + (h-l)/2 - N/2;
829 	if(m < l)
830 		m = l;
831 	fseek(tfile, m, 0);
832 	fread(b, 1, N, tfile);
833 	njab++;
834 	for(i=0; i<N; i++) {
835 		if(b[i] == '\n')
836 			break;
837 		m++;
838 	}
839 	if(m >= h)
840 		return(-1L);
841 	m1 = m;
842 	j = i;
843 	for(i++; i<N; i++) {
844 		m1++;
845 		if(b[i] == '\n')
846 			break;
847 	}
848 	i = cmp(b+j, s, n);
849 	if(i < 0) {
850 		h = m;
851 		goto loop;
852 	}
853 	if(i > 0) {
854 		l = m1;
855 		goto loop;
856 	}
857 	return(m);
858 }
859 
860 cmp(b, s, n)
861 char *b, *s;
862 {
863 	register i;
864 
865 	if(b[0] != '\n')
866 		exit(2);
867 	for(i=0; i<n; i++) {
868 		if(b[i+1] > s[i])
869 			return(-1);
870 		if(b[i+1] < s[i])
871 			return(1);
872 	}
873 	return(b[i+1] == ' '? 0 : -1);
874 }
875 
876 readtape(buffer)
877 char *buffer;
878 {
879 	register int i;
880 
881 	if (recno >= nblock || first == 0) {
882 		if ((i = read(mt, tbuf, TBLOCK*nblock)) < 0) {
883 			fprintf(stderr, "Tar: tape read error\n");
884 			done(3);
885 		}
886 		if (first == 0) {
887 			if ((i % TBLOCK) != 0) {
888 				fprintf(stderr, "Tar: tape blocksize error\n");
889 				done(3);
890 			}
891 			i /= TBLOCK;
892 			if (i != nblock) {
893 				fprintf(stderr, "Tar: blocksize = %d\n", i);
894 				nblock = i;
895 			}
896 		}
897 		recno = 0;
898 	}
899 	first = 1;
900 	copy(buffer, &tbuf[recno++]);
901 	return(TBLOCK);
902 }
903 
904 writetape(buffer)
905 char *buffer;
906 {
907 	first = 1;
908 	if (recno >= nblock) {
909 		if (write(mt, tbuf, TBLOCK*nblock) < 0) {
910 			fprintf(stderr, "Tar: tape write error\n");
911 			done(2);
912 		}
913 		recno = 0;
914 	}
915 	copy(&tbuf[recno++], buffer);
916 	if (recno >= nblock) {
917 		if (write(mt, tbuf, TBLOCK*nblock) < 0) {
918 			fprintf(stderr, "Tar: tape write error\n");
919 			done(2);
920 		}
921 		recno = 0;
922 	}
923 	return(TBLOCK);
924 }
925 
926 backtape()
927 {
928 	static int mtdev = 1;
929 	static struct mtop mtop = {MTBSR, 1};
930 	struct mtget mtget;
931 
932 	if (mtdev == 1)
933 		mtdev = ioctl(mt, MTIOCGET, &mtget);
934 	if (mtdev == 0) {
935 		if (ioctl(mt, MTIOCTOP, &mtop) < 0) {
936 			fprintf(stderr, "Tar: tape backspace error\n");
937 			done(4);
938 		}
939 	} else
940 		lseek(mt, (long) -TBLOCK*nblock, 1);
941 	recno--;
942 }
943 
944 flushtape()
945 {
946 	write(mt, tbuf, TBLOCK*nblock);
947 }
948 
949 copy(to, from)
950 register char *to, *from;
951 {
952 	register i;
953 
954 	i = TBLOCK;
955 	do {
956 		*to++ = *from++;
957 	} while (--i);
958 }
959