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