8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / sgs / ar / common / cmd.c
blob4ed18765f6c72ec14cebd134cf22a7c7c35e9e0c
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
26 * Copyright (c) 1988 AT&T
27 * All Rights Reserved
32 * Incompatible Archive Header
34 * The archive file member header used in SunOS 4.1 archive files and
35 * Solaris archive files are incompatible. The header file is:
36 * /usr/include/ar.h, struct ar_hdr.
37 * The member ar_name[] in Solaris comforms with Standard and the
38 * member name terminates with '/'. The SunOS's member does not terminate
39 * with '/' character. A bug 4046054 was filed:
40 * The ar command in Solaris 2.5.1 is incompatible with archives
41 * created on 4.x.
43 * To handle archive files created in SunOS 4.1 system on Solaris, the
44 * following changes were made:
46 * 1. file.c/writefile()
47 * Before writing each member files into the output
48 * archive file, ar_name[] is checked. If it is NULL,
49 * it means that the original archive header for this
50 * member was incompatible with Solaris format.
52 * The original Solaris ar command ended up having
53 * NULL name for the header. The change here uses the
54 * ar_rawname, which is much closer to the original
55 * name.
57 * 2. cmd.c
58 * For the p command, the code used to use only ar_longname
59 * to seach the matching name. The member is set to NULL
60 * if the archive member header was incompatible.
61 * The ar_rawname is also used to find the matching member name.
63 * For commands to update the archive file, we do not
64 * use ar_rawname, and just use the ar_longname. The commands are
65 * r (replace), m (modify the position) and d (delete).
68 #include "inc.h"
71 * Forward Declarations
73 static void ar_select(int *, unsigned long);
74 static void cleanup(Cmd_info *);
75 static int create_extract(ARFILE *, int, int, Cmd_info *);
76 static char *match(char *, Cmd_info *);
77 static void mesg(int, char *, Cmd_info *);
78 static void movefil(ARFILE *, struct stat *);
79 static FILE *stats(char *, struct stat *);
82 * Commands
84 void
85 rcmd(Cmd_info *cmd_info)
87 FILE *f;
88 ARFILE *fileptr;
89 ARFILE *abifile = NULL;
90 ARFILE *backptr = NULL;
91 ARFILE *endptr;
92 ARFILE *moved_files;
93 ARFILE *prev_entry, *new_listhead, *new_listend;
94 int deleted;
95 struct stat stbuf;
96 char *gfile;
98 new_listhead = NULL;
99 new_listend = NULL;
100 prev_entry = NULL;
102 for (fileptr = getfile(cmd_info);
103 fileptr; fileptr = getfile(cmd_info)) {
104 deleted = 0;
105 if (!abifile && cmd_info->ponam &&
106 strcmp(fileptr->ar_longname, cmd_info->ponam) == 0)
107 abifile = fileptr;
108 else if (!abifile)
109 backptr = fileptr;
111 if (cmd_info->namc == 0 ||
112 (gfile = match(fileptr->ar_longname, cmd_info)) != NULL) {
114 * NOTE:
115 * Refer to "Incompatible Archive Header"
116 * blocked comment at the beginning of this file.
118 f = stats(gfile, &stbuf); /* gfile is set by match */
119 if (f == NULL) {
120 if (cmd_info->namc) {
121 int err = errno;
122 (void) fprintf(stderr,
123 MSG_INTL(MSG_SYS_OPEN),
124 gfile, strerror(err));
127 * Created
129 mesg('c', gfile, cmd_info);
130 } else {
131 if ((cmd_info->opt_flgs & u_FLAG) &&
132 stbuf.st_mtime <= fileptr->ar_date) {
133 (void) fclose(f);
134 continue;
137 * Replaced
139 mesg('r', fileptr->ar_longname, cmd_info);
140 movefil(fileptr, &stbuf);
142 * Clear the previous contents.
144 if (fileptr->ar_flag & F_ELFRAW) {
146 * clear ar_elf
148 (void) elf_end(fileptr->ar_elf);
149 fileptr->ar_elf = 0;
151 /* clear 'ar_flag' */
152 fileptr->ar_flag &= ~F_ELFRAW;
155 * Defer reading contents until needed, and
156 * then use an in-kernel file-to-file transfer
157 * to avoid excessive in-process memory use.
159 fileptr->ar_contents = NULL;
161 if (fileptr->ar_pathname != NULL)
162 free(fileptr->ar_pathname);
163 if ((fileptr->ar_pathname =
164 malloc(strlen(gfile) + 1)) == NULL) {
165 int err = errno;
166 (void) fprintf(stderr,
167 MSG_INTL(MSG_MALLOC),
168 strerror(err));
169 exit(1);
172 (void) strcpy(fileptr->ar_pathname, gfile);
173 (void) fclose(f);
175 if (cmd_info->ponam && (abifile != fileptr)) {
176 deleted = 1;
177 /* remove from archive list */
178 if (prev_entry != NULL)
179 prev_entry->ar_next = NULL;
180 else
181 listhead = NULL;
182 listend = prev_entry;
184 /* add to moved list */
185 if (new_listhead == NULL)
186 new_listhead = fileptr;
187 else
188 new_listend->ar_next = fileptr;
189 new_listend = fileptr;
191 cmd_info->modified++;
194 else
196 * Unchaged
198 mesg('u', fileptr->ar_longname, cmd_info);
200 if (deleted)
201 deleted = 0;
202 else
203 prev_entry = fileptr;
206 endptr = listend;
207 cleanup(cmd_info);
208 if (cmd_info->ponam && endptr &&
209 (((moved_files = endptr->ar_next) != NULL) || new_listhead)) {
210 if (!abifile) {
211 (void) fprintf(stderr, MSG_INTL(MSG_NOT_FOUND_POSNAM),
212 cmd_info->ponam);
213 exit(2);
215 endptr->ar_next = NULL;
218 * link new/moved files into archive entry list...
219 * 1: prepend newlist to moved/appended list
221 if (new_listhead) {
222 if (!moved_files)
223 listend = new_listend;
224 new_listend->ar_next = moved_files;
225 moved_files = new_listhead;
227 /* 2: insert at appropriate position... */
228 if (cmd_info->opt_flgs & b_FLAG)
229 abifile = backptr;
230 if (abifile) {
231 listend->ar_next = abifile->ar_next;
232 abifile->ar_next = moved_files;
233 } else {
234 listend->ar_next = listhead;
235 listhead = moved_files;
237 listend = endptr;
238 } else if (cmd_info->ponam && !abifile)
239 (void) fprintf(stderr, MSG_INTL(MSG_NOT_FOUND_POSNAM),
240 cmd_info->ponam);
243 void
244 dcmd(Cmd_info *cmd_info)
246 ARFILE *fptr;
247 ARFILE *backptr = NULL;
249 for (fptr = getfile(cmd_info); fptr; fptr = getfile(cmd_info)) {
250 if (match(fptr->ar_longname, cmd_info) != NULL) {
252 * NOTE:
253 * Refer to "Incompatible Archive Header"
254 * blocked comment at the beginning of this file.
258 * Deleted
260 mesg('d', fptr->ar_longname, cmd_info);
261 if (backptr == NULL) {
262 listhead = NULL;
263 listend = NULL;
264 } else {
265 backptr->ar_next = NULL;
266 listend = backptr;
268 cmd_info->modified = 1;
269 } else {
271 * Unchaged
273 mesg('u', fptr->ar_longname, cmd_info);
274 backptr = fptr;
279 void
280 xcmd(Cmd_info *cmd_info)
282 int f;
283 ARFILE *next;
284 int rawname = 0;
285 long f_len = 0;
288 * If -T is specified, get the maximum file name length.
290 if (cmd_info->opt_flgs & T_FLAG) {
291 f_len = pathconf(MSG_ORIG(MSG_STR_PERIOD), _PC_NAME_MAX);
292 if (f_len == -1) {
293 int err = errno;
294 (void) fprintf(stderr, MSG_INTL(MSG_PATHCONF),
295 strerror(err));
296 exit(1);
299 for (next = getfile(cmd_info); next; next = getfile(cmd_info)) {
300 if ((next->ar_longname[0] == 0) && (next->ar_rawname[0] != 0))
301 rawname = 1;
302 if (cmd_info->namc == 0 ||
303 match(next->ar_longname, cmd_info) != NULL ||
304 match(next->ar_rawname, cmd_info) != NULL) {
306 * NOTE:
307 * Refer to "Incompatible Archive Header"
308 * blocked comment at the beginning of this file.
310 f = create_extract(next, rawname, f_len, cmd_info);
311 if (f >= 0) {
312 if (rawname) {
314 * eXtracted
316 mesg('x', next->ar_rawname, cmd_info);
317 if (write(f, next->ar_contents,
318 (unsigned)next->ar_size) !=
319 next->ar_size) {
320 int err = errno;
321 (void) fprintf(stderr,
322 MSG_INTL(MSG_SYS_WRITE),
323 next->ar_rawname,
324 strerror(err));
325 exit(1);
327 } else {
329 * eXtracted
331 mesg('x', next->ar_longname, cmd_info);
332 if (write(f, next->ar_contents,
333 (unsigned)next->ar_size) !=
334 next->ar_size) {
335 int err = errno;
336 (void) fprintf(stderr,
337 MSG_INTL(MSG_SYS_WRITE),
338 next->ar_longname,
339 strerror(err));
340 exit(1);
343 (void) close(f);
344 } else
345 exit(1);
347 rawname = 0;
348 } /* for */
351 void
352 pcmd(Cmd_info *cmd_info)
354 ARFILE *next;
356 for (next = getfile(cmd_info); next; next = getfile(cmd_info)) {
357 if (cmd_info->namc == 0 ||
358 match(next->ar_longname, cmd_info) != NULL ||
359 match(next->ar_rawname, cmd_info) != NULL) {
361 * NOTE:
362 * Refer to "Incompatible Archive Header"
363 * blocked comment at the beginning of this file.
365 if (cmd_info->opt_flgs & v_FLAG) {
366 (void) fprintf(stdout,
367 MSG_ORIG(MSG_FMT_P_TITLE),
368 next->ar_longname);
369 (void) fflush(stdout);
371 (void) fwrite(next->ar_contents, sizeof (char),
372 next->ar_size, stdout);
377 void
378 mcmd(Cmd_info *cmd_info)
380 ARFILE *fileptr;
381 ARFILE *abifile = NULL;
382 ARFILE *tmphead = NULL;
383 ARFILE *tmpend = NULL;
384 ARFILE *backptr1 = NULL;
385 ARFILE *backptr2 = NULL;
387 for (fileptr = getfile(cmd_info);
388 fileptr; fileptr = getfile(cmd_info)) {
389 if (match(fileptr->ar_longname, cmd_info) != NULL) {
391 * position Modified
393 mesg('m', fileptr->ar_longname, cmd_info);
394 if (tmphead)
395 tmpend->ar_next = fileptr;
396 else
397 tmphead = fileptr;
398 tmpend = fileptr;
399 if (backptr1) {
400 listend = backptr1;
401 listend->ar_next = NULL;
403 else
404 listhead = NULL;
405 continue;
408 * position Unchaged
410 mesg('u', fileptr->ar_longname, cmd_info);
411 backptr1 = fileptr;
412 if (cmd_info->ponam && !abifile) {
413 if (strcmp(fileptr->ar_longname, cmd_info->ponam) == 0)
414 abifile = fileptr;
415 else
416 backptr2 = fileptr;
420 if (!tmphead)
421 return;
423 if (!cmd_info->ponam)
424 listend->ar_next = tmphead;
425 else {
426 if (!abifile) {
427 (void) fprintf(stderr, MSG_INTL(MSG_NOT_FOUND_POSNAM),
428 cmd_info->ponam);
429 exit(2);
431 if (cmd_info->opt_flgs & b_FLAG)
432 abifile = backptr2;
433 if (abifile) {
434 tmpend->ar_next = abifile->ar_next;
435 abifile->ar_next = tmphead;
436 } else {
437 tmphead->ar_next = listhead;
438 listhead = tmphead;
441 (cmd_info->modified)++;
444 void
445 tcmd(Cmd_info *cmd_info)
447 ARFILE *next;
448 int **mp;
449 char buf[DATESIZE];
450 int m1[] = {1, S_IRUSR, 'r', '-'};
451 int m2[] = {1, S_IWUSR, 'w', '-'};
452 int m3[] = {2, S_ISUID, 's', S_IXUSR, 'x', '-'};
453 int m4[] = {1, S_IRGRP, 'r', '-'};
454 int m5[] = {1, S_IWGRP, 'w', '-'};
455 int m6[] = {2, S_ISGID, 's', S_IXGRP, 'x', '-'};
456 int m7[] = {1, S_IROTH, 'r', '-'};
457 int m8[] = {1, S_IWOTH, 'w', '-'};
458 int m9[] = {2, S_ISVTX, 't', S_IXOTH, 'x', '-'};
459 int *m[10];
461 m[0] = m1;
462 m[1] = m2;
463 m[2] = m3;
464 m[3] = m4;
465 m[4] = m5;
466 m[5] = m6;
467 m[6] = m7;
468 m[7] = m8;
469 m[8] = m9;
470 m[9] = 0;
472 for (next = getfile(cmd_info); next; next = getfile(cmd_info)) {
473 if (cmd_info->namc == 0 ||
474 match(next->ar_longname, cmd_info) != NULL ||
475 match(next->ar_rawname, cmd_info) != NULL) {
477 * NOTE:
478 * Refer to "Incompatible Archive Header"
479 * blocked comment at the beginning of this file.
481 if (cmd_info->opt_flgs & v_FLAG) {
482 for (mp = &m[0]; mp < &m[9]; )
483 ar_select(*mp++, next->ar_mode);
485 (void) fprintf(stdout, MSG_ORIG(MSG_FMT_T_IDSZ),
486 next->ar_uid, next->ar_gid,
487 EC_XWORD(next->ar_size));
488 if ((strftime(buf,
489 DATESIZE, MSG_ORIG(MSG_FMT_T_DATE),
490 localtime(&(next->ar_date)))) == 0) {
491 (void) fprintf(stderr,
492 MSG_INTL(MSG_LOCALTIME));
493 exit(1);
495 (void) fprintf(stdout,
496 MSG_ORIG(MSG_FMT_SPSTRSP), buf);
498 if ((next->ar_longname[0] == 0) &&
499 (next->ar_rawname[0] != 0))
500 (void) fprintf(stdout,
501 MSG_ORIG(MSG_FMT_STRNL),
502 trim(next->ar_rawname));
503 else
504 (void) fprintf(stdout,
505 MSG_ORIG(MSG_FMT_STRNL),
506 trim(next->ar_longname));
508 } /* for */
511 void
512 qcmd(Cmd_info *cmd_info)
514 ARFILE *fptr;
516 if (cmd_info->opt_flgs & (a_FLAG | b_FLAG)) {
517 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_05));
518 exit(1);
520 for (fptr = getfile(cmd_info); fptr; fptr = getfile(cmd_info))
522 cleanup(cmd_info);
526 * Supplementary functions
528 static char *
529 match(char *file, Cmd_info *cmd_info)
531 int i;
533 for (i = 0; i < cmd_info->namc; i++) {
534 if (cmd_info->namv[i] == 0)
535 continue;
536 if (strcmp(trim(cmd_info->namv[i]), file) == 0) {
537 file = cmd_info->namv[i];
538 cmd_info->namv[i] = 0;
539 return (file);
542 return (NULL);
546 * puts the file which was in the list in the linked list
548 static void
549 cleanup(Cmd_info *cmd_info)
551 int i;
552 FILE *f;
553 ARFILE *fileptr;
554 struct stat stbuf;
556 for (i = 0; i < cmd_info->namc; i++) {
557 if (cmd_info->namv[i] == 0)
558 continue;
560 * Appended
562 mesg('a', cmd_info->namv[i], cmd_info);
563 f = stats(cmd_info->namv[i], &stbuf);
564 if (f == NULL) {
565 int err = errno;
566 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
567 cmd_info->namv[i], strerror(err));
568 } else {
569 fileptr = newfile();
570 /* if short name */
571 (void) strncpy(fileptr->ar_name,
572 trim(cmd_info->namv[i]), SNAME);
574 if ((fileptr->ar_longname =
575 malloc(strlen(trim(cmd_info->namv[i])) + 1)) ==
576 NULL) {
577 int err = errno;
578 (void) fprintf(stderr, MSG_INTL(MSG_MALLOC),
579 strerror(err));
580 exit(1);
583 (void) strcpy(fileptr->ar_longname,
584 trim(cmd_info->namv[i]));
586 if ((fileptr->ar_pathname =
587 malloc(strlen(cmd_info->namv[i]) + 1)) == NULL) {
588 int err = errno;
589 (void) fprintf(stderr, MSG_INTL(MSG_MALLOC),
590 strerror(err));
591 exit(1);
594 (void) strcpy(fileptr->ar_pathname, cmd_info->namv[i]);
596 movefil(fileptr, &stbuf);
598 /* clear 'ar_flag' */
599 fileptr->ar_flag &= ~F_ELFRAW;
602 * Defer reading contents until needed, and then use
603 * an in-kernel file-to-file transfer to avoid
604 * excessive in-process memory use.
606 fileptr->ar_contents = NULL;
608 (void) fclose(f);
609 (cmd_info->modified)++;
610 cmd_info->namv[i] = 0;
616 * insert the file 'file' into the temporary file
618 static void
619 movefil(ARFILE *fileptr, struct stat *stbuf)
621 fileptr->ar_size = stbuf->st_size;
622 fileptr->ar_date = stbuf->st_mtime;
623 fileptr->ar_mode = stbuf->st_mode;
626 * The format of an 'ar' file includes a 6 character
627 * decimal string to contain the uid.
629 * If the uid or gid is too big to fit, then set it to
630 * nobody (for want of a better value). Clear the
631 * setuid/setgid bits in the mode to avoid setuid nobody
632 * or setgid nobody files unexpectedly coming into existence.
634 if ((fileptr->ar_uid = stbuf->st_uid) > 999999) {
635 fileptr->ar_uid = UID_NOBODY;
636 if (S_ISREG(fileptr->ar_mode))
637 fileptr->ar_mode &= ~S_ISUID;
639 if ((fileptr->ar_gid = stbuf->st_gid) > 999999) {
640 fileptr->ar_gid = GID_NOBODY;
641 if (S_ISREG(fileptr->ar_mode))
642 fileptr->ar_mode &= ~S_ISGID;
646 static FILE *
647 stats(char *file, struct stat *stbuf)
649 FILE *f;
651 f = fopen(file, MSG_ORIG(MSG_STR_LCR));
652 if (f == NULL)
653 return (f);
654 if (stat(file, stbuf) < 0) {
655 (void) fclose(f);
656 return (NULL);
658 return (f);
662 * Used by xcmd()
665 create_extract(ARFILE *a, int rawname, int f_len, Cmd_info *cmd_info)
668 int f;
669 char *f_name;
670 char *dup = NULL;
671 if (rawname)
672 f_name = a->ar_rawname;
673 else
674 f_name = a->ar_longname;
677 * If -T is specified, check the file length.
679 if (cmd_info->opt_flgs & T_FLAG) {
680 int len;
681 len = strlen(f_name);
682 if (f_len <= len) {
683 dup = malloc(f_len+1);
684 if (dup == NULL) {
685 int err = errno;
686 (void) fprintf(stderr, MSG_INTL(MSG_MALLOC),
687 strerror(err));
688 exit(1);
690 (void) strncpy(dup, f_name, f_len);
692 f_name = dup;
696 * Bug 4052067 - If a file to be extracted has the same
697 * filename as the archive, the archive gets overwritten
698 * which can lead to a corrupted archive or worse, a ufs
699 * deadlock because libelf has mmap'ed the archive! We
700 * can't rely on strcmp() to test for this case because
701 * the archive could be prefixed with a partial or full
702 * path (and we could be using the rawname from the archive)
703 * This means we have to do the same thing we did for mv,
704 * which is to explicitly check if the file we would extract
705 * to is identical to the archive. Because part of this
706 * test is essentially what the -C flag does, I've merged
707 * the code together.
709 if (access(f_name, F_OK) != -1) {
710 struct stat s1, s2;
713 * If -C is specified, this is an error anyway
715 if (cmd_info->opt_flgs & C_FLAG) {
716 (void) fprintf(stderr, MSG_INTL(MSG_OVERRIDE_WARN),
717 f_name);
718 if (dup != NULL)
719 free(dup);
720 return (-1);
724 * Okay, -C wasn't specified. However, now we do
725 * the check to see if the archive would be overwritten
726 * by extracting this file. stat() both objects and
727 * test to see if their identical.
729 if ((stat(f_name, &s1) == 0) &&
730 (stat(cmd_info->arnam, &s2) == 0)) {
732 if ((s1.st_dev == s2.st_dev) &&
733 (s1.st_ino == s2.st_ino)) {
735 (void) fprintf(stderr,
736 MSG_INTL(MSG_OVERRIDE_WARN), f_name);
737 if (dup != NULL)
738 free(dup);
739 return (-1);
745 * Okay to create extraction file...
747 f = creat(f_name, (mode_t)a->ar_mode & 0777);
748 if (f < 0) {
749 int err = errno;
750 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), f_name,
751 strerror(err));
753 * Created
755 mesg('c', f_name, cmd_info);
757 if (dup)
758 free(dup);
759 return (f);
762 static void
763 mesg(int c, char *file, Cmd_info *cmd_info)
765 #ifdef XPG4
767 * XPG4 does not have any message defined for
768 * 'c' operation.
769 * In fact, XPG only defines messages for
770 * d, r, a and x at the present. (03/05/'96)
772 if (c == 'c' || c == 'u' || c == 'm')
773 return;
774 #endif
776 * If 'u' is passed, convert it to 'c'.
777 * 'u' makes more sense since the operation did not
778 * do anything, Unchanged, but 'c' has been used so
779 * I do no want to break the compatibility at this moment.
780 * (03/05/'96).
782 if (c == 'u')
783 c = 'c';
784 if (cmd_info->opt_flgs & v_FLAG)
785 if (c != 'c')
786 (void) fprintf(stdout, MSG_ORIG(MSG_FMT_FILE), c, file);
789 static void
790 ar_select(int *pairp, unsigned long mode)
792 int n, *ap;
794 ap = pairp;
795 n = *ap++;
796 while (--n >= 0 && (mode & *ap++) == 0)
797 ap++;
798 (void) putchar(*ap);