xref: /original-bsd/old/ar11/ar11.c (revision 79cf7955)
1 static char *sccsid = "@(#)ar11.c	4.4 (Berkeley) 11/15/86";
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 
260 	init();
261 	if(getaf())
262 		noar();
263 	tf2nam = mktemp("/tmp/v2XXXXX");
264 	close(creat(tf2nam, 0600));
265 	tf2 = open(tf2nam, 2);
266 	if(tf2 < 0) {
267 		fprintf(stderr, "ar11: cannot create third temp\n");
268 		done(1);
269 	}
270 	while(!getdir()) {
271 		bamatch();
272 		if(match()) {
273 			mesg('m');
274 			copyfil(af, tf2, IODD+OODD+HEAD);
275 			continue;
276 		}
277 		mesg('c');
278 		copyfil(af, tf, IODD+OODD+HEAD);
279 	}
280 	install();
281 }
282 
283 tcmd()
284 {
285 
286 	if(getaf())
287 		noar();
288 	while(!getdir()) {
289 		if(namc == 0 || match()) {
290 			if(flg['v'-'a'])
291 				longt();
292 			printf("%s\n", trim(file));
293 		}
294 		copyfil(af, -1, IODD+SKIP);
295 	}
296 }
297 
298 init()
299 {
300 	static short mbuf = fixshort(ARMAG);
301 
302 	tfnam = mktemp("/tmp/vXXXXX");
303 	close(creat(tfnam, 0600));
304 	tf = open(tfnam, 2);
305 	if(tf < 0) {
306 		fprintf(stderr, "ar11: cannot create temp file\n");
307 		done(1);
308 	}
309 	if (write(tf, (char *)&mbuf, sizeof(short)) != sizeof(short))
310 		wrerr();
311 }
312 
313 getaf()
314 {
315 	short mbuf;
316 
317 	af = open(arnam, 0);
318 	if(af < 0)
319 		return(1);
320 	if (read(af, (char *)&mbuf, sizeof(short)) != sizeof(short) ||
321 	    mbuf != fixshort(ARMAG)) {
322 		fprintf(stderr, "ar11: %s not in PDP-11 archive format\n", arnam);
323 		done(1);
324 	}
325 	return(0);
326 }
327 
328 usage()
329 {
330 	printf("usage: ar11 [%s][%s] archive files ...\n", opt, man);
331 	done(1);
332 }
333 
334 noar()
335 {
336 
337 	fprintf(stderr, "ar11: %s does not exist\n", arnam);
338 	done(1);
339 }
340 
341 sigdone()
342 {
343 	done(100);
344 }
345 
346 done(c)
347 {
348 
349 	if(tfnam)
350 		unlink(tfnam);
351 	if(tf1nam)
352 		unlink(tf1nam);
353 	if(tf2nam)
354 		unlink(tf2nam);
355 	exit(c);
356 }
357 
358 notfound()
359 {
360 	register i, n;
361 
362 	n = 0;
363 	for(i=0; i<namc; i++)
364 		if(namv[i]) {
365 			fprintf(stderr, "ar11: %s not found\n", namv[i]);
366 			n++;
367 		}
368 	return(n);
369 }
370 
371 cleanup()
372 {
373 	register i, f;
374 
375 	for(i=0; i<namc; i++) {
376 		file = namv[i];
377 		if(file == 0)
378 			continue;
379 		namv[i] = 0;
380 		mesg('a');
381 		f = stats();
382 		if(f < 0) {
383 			fprintf(stderr, "ar11: %s cannot open\n", file);
384 			continue;
385 		}
386 		movefil(f);
387 	}
388 	install();
389 }
390 
391 install()
392 {
393 	register i;
394 
395 	for(i=0; signum[i]; i++)
396 		signal(signum[i], (int (*)())1);
397 	close(af);
398 	af = creat(arnam, 0666);
399 	if(af < 0) {
400 		fprintf(stderr, "ar11: cannot create %s\n", arnam);
401 		done(1);
402 	}
403 	lseek(tf, 0l, 0);
404 	while((i = read(tf, buf, 512)) > 0)
405 		if (write(af, buf, i) != i)
406 			wrerr();
407 	if(tf2nam) {
408 		lseek(tf2, 0l, 0);
409 		while((i = read(tf2, buf, 512)) > 0)
410 			if (write(af, buf, i) != i)
411 				wrerr();
412 	}
413 	if(tf1nam) {
414 		lseek(tf1, 0l, 0);
415 		while((i = read(tf1, buf, 512)) > 0)
416 			if (write(af, buf, i) != i)
417 				wrerr();
418 	}
419 }
420 
421 /*
422  * insert the file 'file'
423  * into the temporary file
424  */
425 movefil(f)
426 {
427 	register char *cp;
428 	register i;
429 
430 	cp = trim(file);
431 	for(i=0; i<14; i++)
432 		if(arbuf.ar_name[i] = *cp)
433 			cp++;
434 	ar_size =  stbuf.st_size;
435 	ar_date = stbuf.st_mtime;
436 	unmklong(arbuf.ar_ssize, ar_size);
437 	unmklong(arbuf.ar_sdate, ar_date);
438 	arbuf.ar_uid = stbuf.st_uid;
439 	arbuf.ar_gid = stbuf.st_gid;
440 	arbuf.ar_mode = stbuf.st_mode;
441 	copyfil(f, tf, OODD+HEAD);
442 	close(f);
443 }
444 
445 stats()
446 {
447 	register f;
448 
449 	f = open(file, 0);
450 	if(f < 0)
451 		return(f);
452 	if(fstat(f, &stbuf) < 0) {
453 		close(f);
454 		return(-1);
455 	}
456 	return(f);
457 }
458 
459 /*
460  * copy next file
461  * size given in arbuf
462  */
463 copyfil(fi, fo, flag)
464 {
465 	register i, o;
466 	int pe;
467 
468 	if(flag & HEAD) {
469 		struct ar_hdr tmpbuf;
470 
471 		tmpbuf = fixhdr(arbuf);
472 		if (write(fo, (char *)&tmpbuf, sizeof arbuf) != sizeof arbuf)
473 			wrerr();
474 	}
475 	pe = 0;
476 	while(ar_size > 0) {
477 		i = o = 512;
478 		if(ar_size < i) {
479 			i = o = ar_size;
480 			if(i&1) {
481 				if(flag & IODD)
482 					i++;
483 				if(flag & OODD)
484 					o++;
485 			}
486 		}
487 		if(read(fi, buf, i) != i)
488 			pe++;
489 		if((flag & SKIP) == 0)
490 			if (write(fo, buf, o) != o)
491 				wrerr();
492 		ar_size -= 512;
493 	}
494 	if(pe)
495 		phserr();
496 }
497 
498 getdir()
499 {
500 	register i;
501 
502 	i = read(af, (char *)&arbuf, sizeof arbuf);
503 	if(i != sizeof arbuf) {
504 		if(tf1nam) {
505 			i = tf;
506 			tf = tf1;
507 			tf1 = i;
508 		}
509 		return(1);
510 	}
511 	arbuf = fixhdr(arbuf);
512 	for(i=0; i<14; i++)
513 		name[i] = arbuf.ar_name[i];
514 	file = name;
515 	ar_date = mklong(arbuf.ar_sdate);
516 	ar_size = mklong(arbuf.ar_ssize);
517 	return(0);
518 }
519 
520 match()
521 {
522 	register i;
523 
524 	for(i=0; i<namc; i++) {
525 		if(namv[i] == 0)
526 			continue;
527 		if(strcmp(trim(namv[i]), file) == 0) {
528 			file = namv[i];
529 			namv[i] = 0;
530 			return(1);
531 		}
532 	}
533 	return(0);
534 }
535 
536 bamatch()
537 {
538 	register f;
539 
540 	switch(bastate) {
541 
542 	case 1:
543 		if(strcmp(file, ponam) != 0)
544 			return;
545 		bastate = 2;
546 		if(flg['a'-'a'])
547 			return;
548 
549 	case 2:
550 		bastate = 0;
551 		tf1nam = mktemp("/tmp/v1XXXXX");
552 		close(creat(tf1nam, 0600));
553 		f = open(tf1nam, 2);
554 		if(f < 0) {
555 			fprintf(stderr, "ar11: cannot create second temp\n");
556 			return;
557 		}
558 		tf1 = tf;
559 		tf = f;
560 	}
561 }
562 
563 phserr()
564 {
565 
566 	fprintf(stderr, "ar11: phase error on %s\n", file);
567 }
568 
569 mesg(c)
570 {
571 
572 	if(flg['v'-'a'])
573 		if(c != 'c' || flg['v'-'a'] > 1)
574 			printf("%c - %s\n", c, file);
575 }
576 
577 char *
578 trim(s)
579 char *s;
580 {
581 	register char *p1, *p2;
582 
583 	for(p1 = s; *p1; p1++)
584 		;
585 	while(p1 > s) {
586 		if(*--p1 != '/')
587 			break;
588 		*p1 = 0;
589 	}
590 	p2 = s;
591 	for(p1 = s; *p1; p1++)
592 		if(*p1 == '/')
593 			p2 = p1+1;
594 	return(p2);
595 }
596 
597 #define	IFMT	060000
598 #define	ISARG	01000
599 #define	LARGE	010000
600 #define	SUID	04000
601 #define	SGID	02000
602 #define	ROWN	0400
603 #define	WOWN	0200
604 #define	XOWN	0100
605 #define	RGRP	040
606 #define	WGRP	020
607 #define	XGRP	010
608 #define	ROTH	04
609 #define	WOTH	02
610 #define	XOTH	01
611 #define	STXT	01000
612 
613 longt()
614 {
615 	register char *cp;
616 
617 	pmode();
618 	printf("%3d/%1d", arbuf.ar_uid, arbuf.ar_gid);
619 	printf("%7D", ar_size);
620 	cp = ctime(&ar_date);
621 	printf(" %-12.12s %-4.4s ", cp+4, cp+20);
622 }
623 
624 int	m1[] = { 1, ROWN, 'r', '-' };
625 int	m2[] = { 1, WOWN, 'w', '-' };
626 int	m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
627 int	m4[] = { 1, RGRP, 'r', '-' };
628 int	m5[] = { 1, WGRP, 'w', '-' };
629 int	m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
630 int	m7[] = { 1, ROTH, 'r', '-' };
631 int	m8[] = { 1, WOTH, 'w', '-' };
632 int	m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
633 
634 int	*m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
635 
636 pmode()
637 {
638 	register int **mp;
639 
640 	for (mp = &m[0]; mp < &m[9];)
641 		select(*mp++);
642 }
643 
644 select(pairp)
645 int *pairp;
646 {
647 	register int n, *ap;
648 
649 	ap = pairp;
650 	n = *ap++;
651 	while (--n>=0 && (arbuf.ar_mode&*ap++)==0)
652 		ap++;
653 	putchar(*ap);
654 }
655 
656 wrerr()
657 {
658 	perror("ar write error");
659 	done(1);
660 }
661 
662 #if defined(mc68000) || defined(tahoe)
663 struct ar_hdr
664 swaphdr(hdr)
665 	struct ar_hdr hdr;
666 {
667 	hdr.ar_sdate[0] = fixshort(hdr.ar_sdate[0]);
668 	hdr.ar_sdate[1] = fixshort(hdr.ar_sdate[1]);
669 	hdr.ar_ssize[0] = fixshort(hdr.ar_ssize[0]);
670 	hdr.ar_ssize[1] = fixshort(hdr.ar_ssize[1]);
671 	hdr.ar_mode = fixshort(hdr.ar_mode);
672 	return (hdr);
673 }
674 #endif
675