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