xref: /original-bsd/usr.bin/ar/ar.c (revision 23a40993)
1 #ifndef lint
2 static	char sccsid[] = "@(#)ar.c 4.4 06/10/83";
3 #endif
4 
5 /*
6  * ar - portable (ascii) format version
7  */
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <sys/time.h>
11 
12 #include <stdio.h>
13 #include <ar.h>
14 #include <signal.h>
15 
16 struct	stat	stbuf;
17 struct	ar_hdr	arbuf;
18 struct	lar_hdr {
19 	char	lar_name[16];
20 	long	lar_date;
21 	u_short	lar_uid;
22 	u_short	lar_gid;
23 	u_short	lar_mode;
24 	long	lar_size;
25 } larbuf;
26 
27 #define	SKIP	1
28 #define	IODD	2
29 #define	OODD	4
30 #define	HEAD	8
31 
32 char	*man	=	{ "mrxtdpq" };
33 char	*opt	=	{ "uvnbailo" };
34 
35 int	signum[] = {SIGHUP, SIGINT, SIGQUIT, 0};
36 int	sigdone();
37 long	lseek();
38 int	rcmd();
39 int	dcmd();
40 int	xcmd();
41 int	tcmd();
42 int	pcmd();
43 int	mcmd();
44 int	qcmd();
45 int	(*comfun)();
46 char	flg[26];
47 char	**namv;
48 int	namc;
49 char	*arnam;
50 char	*ponam;
51 char	*tmpnam		=	{ "/tmp/vXXXXX" };
52 char	*tmp1nam	=	{ "/tmp/v1XXXXX" };
53 char	*tmp2nam	=	{ "/tmp/v2XXXXX" };
54 char	*tfnam;
55 char	*tf1nam;
56 char	*tf2nam;
57 char	*file;
58 char	name[16];
59 int	af;
60 int	tf;
61 int	tf1;
62 int	tf2;
63 int	qf;
64 int	bastate;
65 char	buf[BUFSIZ];
66 
67 char	*trim();
68 char	*mktemp();
69 char	*ctime();
70 
71 main(argc, argv)
72 char *argv[];
73 {
74 	register i;
75 	register char *cp;
76 
77 	for(i=0; signum[i]; i++)
78 		if(signal(signum[i], SIG_IGN) != SIG_IGN)
79 			signal(signum[i], sigdone);
80 	if(argc < 3)
81 		usage();
82 	cp = argv[1];
83 	for(cp = argv[1]; *cp; cp++)
84 	switch(*cp) {
85 	case 'o':
86 	case 'l':
87 	case 'v':
88 	case 'u':
89 	case 'n':
90 	case 'a':
91 	case 'b':
92 	case 'c':
93 	case 'i':
94 		flg[*cp - 'a']++;
95 		continue;
96 
97 	case 'r':
98 		setcom(rcmd);
99 		continue;
100 
101 	case 'd':
102 		setcom(dcmd);
103 		continue;
104 
105 	case 'x':
106 		setcom(xcmd);
107 		continue;
108 
109 	case 't':
110 		setcom(tcmd);
111 		continue;
112 
113 	case 'p':
114 		setcom(pcmd);
115 		continue;
116 
117 	case 'm':
118 		setcom(mcmd);
119 		continue;
120 
121 	case 'q':
122 		setcom(qcmd);
123 		continue;
124 
125 	default:
126 		fprintf(stderr, "ar: bad option `%c'\n", *cp);
127 		done(1);
128 	}
129 	if(flg['l'-'a']) {
130 		tmpnam = "vXXXXX";
131 		tmp1nam = "v1XXXXX";
132 		tmp2nam = "v2XXXXX";
133 	}
134 	if(flg['i'-'a'])
135 		flg['b'-'a']++;
136 	if(flg['a'-'a'] || flg['b'-'a']) {
137 		bastate = 1;
138 		ponam = trim(argv[2]);
139 		argv++;
140 		argc--;
141 		if(argc < 3)
142 			usage();
143 	}
144 	arnam = argv[2];
145 	namv = argv+3;
146 	namc = argc-3;
147 	if(comfun == 0) {
148 		if(flg['u'-'a'] == 0) {
149 			fprintf(stderr, "ar: one of [%s] must be specified\n", man);
150 			done(1);
151 		}
152 		setcom(rcmd);
153 	}
154 	(*comfun)();
155 	done(notfound());
156 }
157 
158 setcom(fun)
159 int (*fun)();
160 {
161 
162 	if(comfun != 0) {
163 		fprintf(stderr, "ar: only one of [%s] allowed\n", man);
164 		done(1);
165 	}
166 	comfun = fun;
167 }
168 
169 rcmd()
170 {
171 	register f;
172 
173 	init();
174 	getaf();
175 	while(!getdir()) {
176 		bamatch();
177 		if(namc == 0 || match()) {
178 			f = stats();
179 			if(f < 0) {
180 				if(namc)
181 					fprintf(stderr, "ar: cannot open %s\n", file);
182 				goto cp;
183 			}
184 			if(flg['u'-'a'])
185 				if(stbuf.st_mtime <= larbuf.lar_date) {
186 					close(f);
187 					goto cp;
188 				}
189 			mesg('r');
190 			copyfil(af, -1, IODD+SKIP);
191 			movefil(f);
192 			continue;
193 		}
194 	cp:
195 		mesg('c');
196 		copyfil(af, tf, IODD+OODD+HEAD);
197 	}
198 	cleanup();
199 }
200 
201 dcmd()
202 {
203 
204 	init();
205 	if(getaf())
206 		noar();
207 	while(!getdir()) {
208 		if(match()) {
209 			mesg('d');
210 			copyfil(af, -1, IODD+SKIP);
211 			continue;
212 		}
213 		mesg('c');
214 		copyfil(af, tf, IODD+OODD+HEAD);
215 	}
216 	install();
217 }
218 
219 xcmd()
220 {
221 	register f;
222 	struct timeval tv[2];
223 
224 	if(getaf())
225 		noar();
226 	while(!getdir()) {
227 		if(namc == 0 || match()) {
228 			f = creat(file, larbuf.lar_mode & 0777);
229 			if(f < 0) {
230 				fprintf(stderr, "ar: %s cannot create\n", file);
231 				goto sk;
232 			}
233 			mesg('x');
234 			copyfil(af, f, IODD);
235 			close(f);
236 			if (flg['o'-'a']) {
237 				tv[0].tv_sec = tv[1].tv_sec = larbuf.lar_date;
238 				tv[0].tv_usec = tv[1].tv_usec = 0;
239 				utimes(file, tv);
240 			}
241 			continue;
242 		}
243 	sk:
244 		mesg('c');
245 		copyfil(af, -1, IODD+SKIP);
246 		if (namc > 0  &&  !morefil())
247 			done(0);
248 	}
249 }
250 
251 pcmd()
252 {
253 
254 	if(getaf())
255 		noar();
256 	while(!getdir()) {
257 		if(namc == 0 || match()) {
258 			if(flg['v'-'a']) {
259 				printf("\n<%s>\n\n", file);
260 				fflush(stdout);
261 			}
262 			copyfil(af, 1, IODD);
263 			continue;
264 		}
265 		copyfil(af, -1, IODD+SKIP);
266 	}
267 }
268 
269 mcmd()
270 {
271 
272 	init();
273 	if(getaf())
274 		noar();
275 	tf2nam = mktemp(tmp2nam);
276 	close(creat(tf2nam, 0600));
277 	tf2 = open(tf2nam, 2);
278 	if(tf2 < 0) {
279 		fprintf(stderr, "ar: cannot create third temp\n");
280 		done(1);
281 	}
282 	while(!getdir()) {
283 		bamatch();
284 		if(match()) {
285 			mesg('m');
286 			copyfil(af, tf2, IODD+OODD+HEAD);
287 			continue;
288 		}
289 		mesg('c');
290 		copyfil(af, tf, IODD+OODD+HEAD);
291 	}
292 	install();
293 }
294 
295 tcmd()
296 {
297 
298 	if(getaf())
299 		noar();
300 	while(!getdir()) {
301 		if(namc == 0 || match()) {
302 			if(flg['v'-'a'])
303 				longt();
304 			printf("%s\n", trim(file));
305 		}
306 		copyfil(af, -1, IODD+SKIP);
307 	}
308 }
309 
310 qcmd()
311 {
312 	register i, f;
313 
314 	if (flg['a'-'a'] || flg['b'-'a']) {
315 		fprintf(stderr, "ar: abi not allowed with q\n");
316 		done(1);
317 	}
318 	getqf();
319 	for(i=0; signum[i]; i++)
320 		signal(signum[i], SIG_IGN);
321 	lseek(qf, 0l, 2);
322 	for(i=0; i<namc; i++) {
323 		file = namv[i];
324 		if(file == 0)
325 			continue;
326 		namv[i] = 0;
327 		mesg('q');
328 		f = stats();
329 		if(f < 0) {
330 			fprintf(stderr, "ar: %s cannot open\n", file);
331 			continue;
332 		}
333 		tf = qf;
334 		movefil(f);
335 		qf = tf;
336 	}
337 }
338 
339 init()
340 {
341 
342 	tfnam = mktemp(tmpnam);
343 	close(creat(tfnam, 0600));
344 	tf = open(tfnam, 2);
345 	if(tf < 0) {
346 		fprintf(stderr, "ar: cannot create temp file\n");
347 		done(1);
348 	}
349 	if (write(tf, ARMAG, SARMAG) != SARMAG)
350 		wrerr();
351 }
352 
353 getaf()
354 {
355 	char mbuf[SARMAG];
356 
357 	af = open(arnam, 0);
358 	if(af < 0)
359 		return(1);
360 	if (read(af, mbuf, SARMAG) != SARMAG || strncmp(mbuf, ARMAG, SARMAG)) {
361 		fprintf(stderr, "ar: %s not in archive format\n", arnam);
362 		done(1);
363 	}
364 	return(0);
365 }
366 
367 getqf()
368 {
369 	char mbuf[SARMAG];
370 
371 	if ((qf = open(arnam, 2)) < 0) {
372 		if(!flg['c'-'a'])
373 			fprintf(stderr, "ar: creating %s\n", arnam);
374 		if ((qf = creat(arnam, 0666)) < 0) {
375 			fprintf(stderr, "ar: cannot create %s\n", arnam);
376 			done(1);
377 		}
378 		if (write(qf, ARMAG, SARMAG) != SARMAG)
379 			wrerr();
380 	} else if (read(qf, mbuf, SARMAG) != SARMAG
381 		|| strncmp(mbuf, ARMAG, SARMAG)) {
382 		fprintf(stderr, "ar: %s not in archive format\n", arnam);
383 		done(1);
384 	}
385 }
386 
387 usage()
388 {
389 	printf("usage: ar [%s][%s] archive files ...\n", man, opt);
390 	done(1);
391 }
392 
393 noar()
394 {
395 
396 	fprintf(stderr, "ar: %s does not exist\n", arnam);
397 	done(1);
398 }
399 
400 sigdone()
401 {
402 	done(100);
403 }
404 
405 done(c)
406 {
407 
408 	if(tfnam)
409 		unlink(tfnam);
410 	if(tf1nam)
411 		unlink(tf1nam);
412 	if(tf2nam)
413 		unlink(tf2nam);
414 	exit(c);
415 }
416 
417 notfound()
418 {
419 	register i, n;
420 
421 	n = 0;
422 	for(i=0; i<namc; i++)
423 		if(namv[i]) {
424 			fprintf(stderr, "ar: %s not found\n", namv[i]);
425 			n++;
426 		}
427 	return(n);
428 }
429 
430 morefil()
431 {
432 	register i, n;
433 
434 	n = 0;
435 	for(i=0; i<namc; i++)
436 		if(namv[i])
437 			n++;
438 	return(n);
439 }
440 
441 cleanup()
442 {
443 	register i, f;
444 
445 	for(i=0; i<namc; i++) {
446 		file = namv[i];
447 		if(file == 0)
448 			continue;
449 		namv[i] = 0;
450 		mesg('a');
451 		f = stats();
452 		if(f < 0) {
453 			fprintf(stderr, "ar: %s cannot open\n", file);
454 			continue;
455 		}
456 		movefil(f);
457 	}
458 	install();
459 }
460 
461 install()
462 {
463 	register i;
464 
465 	for(i=0; signum[i]; i++)
466 		signal(signum[i], SIG_IGN);
467 	if(af < 0)
468 		if(!flg['c'-'a'])
469 			fprintf(stderr, "ar: creating %s\n", arnam);
470 	close(af);
471 	af = creat(arnam, 0666);
472 	if(af < 0) {
473 		fprintf(stderr, "ar: cannot create %s\n", arnam);
474 		done(1);
475 	}
476 	if(tfnam) {
477 		lseek(tf, 0l, 0);
478 		while((i = read(tf, buf, BUFSIZ)) > 0)
479 			if (write(af, buf, i) != i)
480 				wrerr();
481 	}
482 	if(tf2nam) {
483 		lseek(tf2, 0l, 0);
484 		while((i = read(tf2, buf, BUFSIZ)) > 0)
485 			if (write(af, buf, i) != i)
486 				wrerr();
487 	}
488 	if(tf1nam) {
489 		lseek(tf1, 0l, 0);
490 		while((i = read(tf1, buf, BUFSIZ)) > 0)
491 			if (write(af, buf, i) != i)
492 				wrerr();
493 	}
494 }
495 
496 /*
497  * insert the file 'file'
498  * into the temporary file
499  */
500 movefil(f)
501 {
502 	char buf[sizeof(arbuf)+1];
503 
504 	sprintf(buf, "%-16s%-12ld%-6u%-6u%-8o%-10ld%-2s",
505 	   trim(file),
506 	   stbuf.st_mtime,
507 	   stbuf.st_uid,
508 	   stbuf.st_gid,
509 	   stbuf.st_mode,
510 	   stbuf.st_size,
511 	   ARFMAG);
512 	strncpy((char *)&arbuf, buf, sizeof(arbuf));
513 	larbuf.lar_size = stbuf.st_size;
514 	copyfil(f, tf, OODD+HEAD);
515 	close(f);
516 }
517 
518 stats()
519 {
520 	register f;
521 
522 	f = open(file, 0);
523 	if(f < 0)
524 		return(f);
525 	if(fstat(f, &stbuf) < 0) {
526 		close(f);
527 		return(-1);
528 	}
529 	return(f);
530 }
531 
532 /*
533  * copy next file
534  * size given in arbuf
535  */
536 copyfil(fi, fo, flag)
537 {
538 	register i, o;
539 	int pe;
540 
541 	if(flag & HEAD) {
542 		for (i=sizeof(arbuf.ar_name)-1; i>=0; i--) {
543 			if (arbuf.ar_name[i]==' ')
544 				continue;
545 			else if (arbuf.ar_name[i]=='\0')
546 				arbuf.ar_name[i] = ' ';
547 			else
548 				break;
549 		}
550 		if (write(fo, (char *)&arbuf, sizeof arbuf) != sizeof arbuf)
551 			wrerr();
552 	}
553 	pe = 0;
554 	while(larbuf.lar_size > 0) {
555 		i = o = BUFSIZ;
556 		if(larbuf.lar_size < i) {
557 			i = o = larbuf.lar_size;
558 			if(i&1) {
559 				buf[i] = '\n';
560 				if(flag & IODD)
561 					i++;
562 				if(flag & OODD)
563 					o++;
564 			}
565 		}
566 		if(read(fi, buf, i) != i)
567 			pe++;
568 		if((flag & SKIP) == 0)
569 			if (write(fo, buf, o) != o)
570 				wrerr();
571 		larbuf.lar_size -= BUFSIZ;
572 	}
573 	if(pe)
574 		phserr();
575 }
576 
577 getdir()
578 {
579 	register char *cp;
580 	register i;
581 
582 	i = read(af, (char *)&arbuf, sizeof arbuf);
583 	if(i != sizeof arbuf) {
584 		if(tf1nam) {
585 			i = tf;
586 			tf = tf1;
587 			tf1 = i;
588 		}
589 		return(1);
590 	}
591 	if (strncmp(arbuf.ar_fmag, ARFMAG, sizeof(arbuf.ar_fmag))) {
592 		fprintf(stderr, "ar: malformed archive (at %ld)\n", lseek(af, 0L, 1));
593 		done(1);
594 	}
595 	cp = arbuf.ar_name + sizeof(arbuf.ar_name);
596 	while (*--cp==' ')
597 		;
598 	*++cp = '\0';
599 	strncpy(name, arbuf.ar_name, sizeof(arbuf.ar_name));
600 	file = name;
601 	strncpy(larbuf.lar_name, name, sizeof(larbuf.lar_name));
602 	sscanf(arbuf.ar_date, "%ld", &larbuf.lar_date);
603 	sscanf(arbuf.ar_uid, "%hd", &larbuf.lar_uid);
604 	sscanf(arbuf.ar_gid, "%hd", &larbuf.lar_gid);
605 	sscanf(arbuf.ar_mode, "%ho", &larbuf.lar_mode);
606 	sscanf(arbuf.ar_size, "%ld", &larbuf.lar_size);
607 	return(0);
608 }
609 
610 match()
611 {
612 	register i;
613 
614 	for(i=0; i<namc; i++) {
615 		if(namv[i] == 0)
616 			continue;
617 		if(strcmp(trim(namv[i]), file) == 0) {
618 			file = namv[i];
619 			namv[i] = 0;
620 			return(1);
621 		}
622 	}
623 	return(0);
624 }
625 
626 bamatch()
627 {
628 	register f;
629 
630 	switch(bastate) {
631 
632 	case 1:
633 		if(strcmp(file, ponam) != 0)
634 			return;
635 		bastate = 2;
636 		if(flg['a'-'a'])
637 			return;
638 
639 	case 2:
640 		bastate = 0;
641 		tf1nam = mktemp(tmp1nam);
642 		close(creat(tf1nam, 0600));
643 		f = open(tf1nam, 2);
644 		if(f < 0) {
645 			fprintf(stderr, "ar: cannot create second temp\n");
646 			return;
647 		}
648 		tf1 = tf;
649 		tf = f;
650 	}
651 }
652 
653 phserr()
654 {
655 
656 	fprintf(stderr, "ar: phase error on %s\n", file);
657 }
658 
659 mesg(c)
660 {
661 
662 	if(flg['v'-'a'])
663 		if(c != 'c' || flg['v'-'a'] > 1)
664 			printf("%c - %s\n", c, file);
665 }
666 
667 char *
668 trim(s)
669 char *s;
670 {
671 	register char *p1, *p2;
672 
673 	for(p1 = s; *p1; p1++)
674 		;
675 	while(p1 > s) {
676 		if(*--p1 != '/')
677 			break;
678 		*p1 = 0;
679 	}
680 	p2 = s;
681 	for(p1 = s; *p1; p1++)
682 		if(*p1 == '/')
683 			p2 = p1+1;
684 	return(p2);
685 }
686 
687 #define	IFMT	060000
688 #define	ISARG	01000
689 #define	LARGE	010000
690 #define	SUID	04000
691 #define	SGID	02000
692 #define	ROWN	0400
693 #define	WOWN	0200
694 #define	XOWN	0100
695 #define	RGRP	040
696 #define	WGRP	020
697 #define	XGRP	010
698 #define	ROTH	04
699 #define	WOTH	02
700 #define	XOTH	01
701 #define	STXT	01000
702 
703 longt()
704 {
705 	register char *cp;
706 
707 	pmode();
708 	printf("%3d/%1d", larbuf.lar_uid, larbuf.lar_gid);
709 	printf("%7ld", larbuf.lar_size);
710 	cp = ctime(&larbuf.lar_date);
711 	printf(" %-12.12s %-4.4s ", cp+4, cp+20);
712 }
713 
714 int	m1[] = { 1, ROWN, 'r', '-' };
715 int	m2[] = { 1, WOWN, 'w', '-' };
716 int	m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
717 int	m4[] = { 1, RGRP, 'r', '-' };
718 int	m5[] = { 1, WGRP, 'w', '-' };
719 int	m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
720 int	m7[] = { 1, ROTH, 'r', '-' };
721 int	m8[] = { 1, WOTH, 'w', '-' };
722 int	m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
723 
724 int	*m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
725 
726 pmode()
727 {
728 	register int **mp;
729 
730 	for (mp = &m[0]; mp < &m[9];)
731 		select(*mp++);
732 }
733 
734 select(pairp)
735 int *pairp;
736 {
737 	register int n, *ap;
738 
739 	ap = pairp;
740 	n = *ap++;
741 	while (--n>=0 && (larbuf.lar_mode&*ap++)==0)
742 		ap++;
743 	putchar(*ap);
744 }
745 
746 wrerr()
747 {
748 	perror("ar write error");
749 	done(1);
750 }
751