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