date and time created 83/02/24 12:55:54 by mckusick
[unix-history] / usr / src / usr.bin / ar / ar.c
CommitLineData
def89b26 1static char sccsid[] = "@(#)ar.c 4.1 %G%";
be40ff3d
BJ
2/*
3 * ar - portable (ascii) format version
4 */
5#include <stdio.h>
6#include <sys/types.h>
7#include <sys/stat.h>
3d4622f1 8#include <ar.h>
be40ff3d
BJ
9#include <signal.h>
10
11typedef unsigned short ushort;
12struct stat stbuf;
13struct ar_hdr arbuf;
14struct 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
28char *man = { "mrxtdpq" };
29char *opt = { "uvnbail" };
30
31int signum[] = {SIGHUP, SIGINT, SIGQUIT, 0};
32int sigdone();
33long lseek();
34int rcmd();
35int dcmd();
36int xcmd();
37int tcmd();
38int pcmd();
39int mcmd();
40int qcmd();
41int (*comfun)();
42char flg[26];
43char **namv;
44int namc;
45char *arnam;
46char *ponam;
47char *tmpnam = { "/tmp/vXXXXX" };
48char *tmp1nam = { "/tmp/v1XXXXX" };
49char *tmp2nam = { "/tmp/v2XXXXX" };
50char *tfnam;
51char *tf1nam;
52char *tf2nam;
53char *file;
54char name[16];
55int af;
56int tf;
57int tf1;
58int tf2;
59int qf;
60int bastate;
61char buf[BUFSIZ];
62
63char *trim();
64char *mktemp();
65char *ctime();
66
67main(argc, argv)
68char *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
153setcom(fun)
154int (*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
164rcmd()
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
196dcmd()
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
214xcmd()
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
240pcmd()
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
258mcmd()
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
284tcmd()
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
299qcmd()
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
328init()
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
342getaf()
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
356getqf()
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
376usage()
377{
378 printf("usage: ar [%s][%s] archive files ...\n", opt, man);
379 done(1);
380}
381
382noar()
383{
384
385 fprintf(stderr, "ar: %s does not exist\n", arnam);
386 done(1);
387}
388
389sigdone()
390{
391 done(100);
392}
393
394done(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
406notfound()
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
419morefil()
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
430cleanup()
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
450install()
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 */
489movefil(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
507stats()
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 */
525copyfil(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
566getdir()
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
599match()
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
615bamatch()
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
642phserr()
643{
644
645 fprintf(stderr, "ar: phase error on %s\n", file);
646}
647
648mesg(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
656char *
657trim(s)
658char *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
692longt()
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
703int m1[] = { 1, ROWN, 'r', '-' };
704int m2[] = { 1, WOWN, 'w', '-' };
705int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
706int m4[] = { 1, RGRP, 'r', '-' };
707int m5[] = { 1, WGRP, 'w', '-' };
708int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
709int m7[] = { 1, ROTH, 'r', '-' };
710int m8[] = { 1, WOTH, 'w', '-' };
711int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
712
713int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
714
715pmode()
716{
717 register int **mp;
718
719 for (mp = &m[0]; mp < &m[9];)
720 select(*mp++);
721}
722
723select(pairp)
724int *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
735wrerr()
736{
737 perror("ar write error");
738 done(1);
739}