date and time created 83/09/07 13:20:12 by ralph
[unix-history] / usr / src / usr.bin / ar / ar.c
CommitLineData
d059363b 1#ifndef lint
828d5b76 2static char sccsid[] = "@(#)ar.c 4.4 %G%";
d059363b 3#endif
828d5b76 4
be40ff3d
BJ
5/*
6 * ar - portable (ascii) format version
7 */
be40ff3d
BJ
8#include <sys/types.h>
9#include <sys/stat.h>
828d5b76
SL
10#include <sys/time.h>
11
12#include <stdio.h>
3d4622f1 13#include <ar.h>
be40ff3d
BJ
14#include <signal.h>
15
be40ff3d
BJ
16struct stat stbuf;
17struct ar_hdr arbuf;
18struct lar_hdr {
19 char lar_name[16];
20 long lar_date;
d059363b
SL
21 u_short lar_uid;
22 u_short lar_gid;
23 u_short lar_mode;
be40ff3d
BJ
24 long lar_size;
25} larbuf;
26
27#define SKIP 1
28#define IODD 2
29#define OODD 4
30#define HEAD 8
31
32char *man = { "mrxtdpq" };
71762efd 33char *opt = { "uvnbailo" };
be40ff3d
BJ
34
35int signum[] = {SIGHUP, SIGINT, SIGQUIT, 0};
36int sigdone();
37long lseek();
38int rcmd();
39int dcmd();
40int xcmd();
41int tcmd();
42int pcmd();
43int mcmd();
44int qcmd();
45int (*comfun)();
46char flg[26];
47char **namv;
48int namc;
49char *arnam;
50char *ponam;
51char *tmpnam = { "/tmp/vXXXXX" };
52char *tmp1nam = { "/tmp/v1XXXXX" };
53char *tmp2nam = { "/tmp/v2XXXXX" };
54char *tfnam;
55char *tf1nam;
56char *tf2nam;
57char *file;
58char name[16];
59int af;
60int tf;
61int tf1;
62int tf2;
63int qf;
64int bastate;
65char buf[BUFSIZ];
66
67char *trim();
68char *mktemp();
69char *ctime();
70
71main(argc, argv)
72char *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) {
71762efd 85 case 'o':
be40ff3d
BJ
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
158setcom(fun)
159int (*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
169rcmd()
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
201dcmd()
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
219xcmd()
220{
221 register f;
828d5b76 222 struct timeval tv[2];
be40ff3d
BJ
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);
71762efd 236 if (flg['o'-'a']) {
828d5b76
SL
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);
71762efd 240 }
be40ff3d
BJ
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
251pcmd()
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
269mcmd()
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
295tcmd()
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
310qcmd()
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
339init()
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
353getaf()
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
367getqf()
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
387usage()
388{
71762efd 389 printf("usage: ar [%s][%s] archive files ...\n", man, opt);
be40ff3d
BJ
390 done(1);
391}
392
393noar()
394{
395
396 fprintf(stderr, "ar: %s does not exist\n", arnam);
397 done(1);
398}
399
400sigdone()
401{
402 done(100);
403}
404
405done(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
417notfound()
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
430morefil()
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
441cleanup()
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
461install()
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 */
500movefil(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
518stats()
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 */
536copyfil(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
577getdir()
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
610match()
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
626bamatch()
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
653phserr()
654{
655
656 fprintf(stderr, "ar: phase error on %s\n", file);
657}
658
659mesg(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
667char *
668trim(s)
669char *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
703longt()
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
714int m1[] = { 1, ROWN, 'r', '-' };
715int m2[] = { 1, WOWN, 'w', '-' };
716int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
717int m4[] = { 1, RGRP, 'r', '-' };
718int m5[] = { 1, WGRP, 'w', '-' };
719int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
720int m7[] = { 1, ROTH, 'r', '-' };
721int m8[] = { 1, WOTH, 'w', '-' };
722int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
723
724int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
725
726pmode()
727{
728 register int **mp;
729
730 for (mp = &m[0]; mp < &m[9];)
731 select(*mp++);
732}
733
734select(pairp)
735int *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
746wrerr()
747{
748 perror("ar write error");
749 done(1);
750}