4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
31 #include <sys/types.h>
34 #include <sys/param.h>
41 #include "proto_list.h"
43 #include "exception_list.h"
46 #define MAX_PROTO_REFS 5
47 #define MAX_EXCEPTION_FILES 5
53 static int check_group
= 1;
54 static int set_group
= 0;
55 static int check_user
= 1;
56 static int set_user
= 0;
57 static int check_perm
= 1;
58 static int set_perm
= 0;
59 static int check_link
= 1;
60 static int check_sym
= 1;
61 static int check_majmin
= 1;
63 static elem_list first_list
;
64 static char *first_file_name
;
66 static elem_list second_list
;
67 static char *second_file_name
;
69 static FILE *need_add_fp
;
70 static char *need_add_file
;
71 static FILE *need_rm_fp
;
72 static char *need_rm_file
;
73 static FILE *differ_fp
;
74 static char *differ_file
;
81 static int verbose
= 0;
86 (void) fputs("usage: protocmp [-gupGUPlmsLv] "
87 "[-e <exception-list> ...] "
88 "-d <protolist|pkg dir>\n\t[-d <protolist|pkg dir> ...] "
89 "[<protolist|pkg dir>...]|<root>]\n",
91 (void) fputs(" where:\n", stderr
);
92 (void) fputs("\t-g : don't compare group\n", stderr
);
93 (void) fputs("\t-u : don't compare owner\n", stderr
);
94 (void) fputs("\t-p : don't compare permissions\n", stderr
);
95 (void) fputs("\t-G : set group\n", stderr
);
96 (void) fputs("\t-U : set owner\n", stderr
);
97 (void) fputs("\t-P : set permissions\n", stderr
);
98 (void) fputs("\t-l : don't compare link counts\n", stderr
);
99 (void) fputs("\t-m : don't compare major/minor numbers\n",
101 (void) fputs("\t-s : don't compare symlink values\n", stderr
);
102 (void) fputs("\t-d <protolist|pkg dir>:\n", stderr
);
103 (void) fputs("\t proto list or packaging to check\n", stderr
);
104 (void) fputs("\t-e <file>: exceptions file\n", stderr
);
105 (void) fputs("\t-L : list filtered exceptions\n", stderr
);
106 (void) fputs("\t-v : verbose output\n", stderr
);
108 "If any of the -[GUP] flags are given, then the final argument must be the\n"
109 "proto root directory itself on which to set permissions according to the\n"
110 "packaging data specified via -d options.\n", stderr
);
115 open_output_files(void)
118 fopen((need_add_file
= tempnam(NULL
, "add")), "w")) == NULL
) {
119 perror(need_add_file
);
124 fopen((need_rm_file
= tempnam(NULL
, "rm")), "w")) == NULL
) {
125 perror(need_rm_file
);
130 fopen((differ_file
= tempnam(NULL
, "diff")), "w")) == NULL
) {
137 close_output_files(void)
139 (void) fclose(need_add_fp
);
140 (void) fclose(need_rm_fp
);
141 (void) fclose(differ_fp
);
145 print_file(char *file
)
151 if ((fp
= fopen(file
, "r")) == NULL
) {
152 perror(need_add_file
);
155 while (count
= fread(buff
, sizeof (char), BUF_SIZE
, fp
))
156 (void) fwrite(buff
, sizeof (char), count
, stdout
);
163 (void) printf("%c %-30s %-20s %-4s %-5s %-5s %-5s %-2s %2s %2s %-9s\n",
164 'T', "File Name", "Reloc/Sym name", "perm", "owner", "group",
165 "inode", "lnk", "maj", "min", "package(s)");
166 (void) puts("-------------------------------------------------------"
167 "-----------------------------------------------------");
173 (void) puts("*******************************************************");
175 (void) printf("* Entries found in %s, but not found in %s\n",
176 first_file_name
, second_file_name
);
178 (void) puts("*******************************************************");
180 print_file(need_add_file
);
181 (void) puts("*******************************************************");
183 (void) printf("* Entries found in %s, but not found in %s\n",
184 second_file_name
, first_file_name
);
186 (void) puts("*******************************************************");
188 print_file(need_rm_file
);
189 (void) puts("*******************************************************");
191 (void) printf("* Entries that differ between %s and %s\n",
192 first_file_name
, second_file_name
);
194 (void) printf("* filea == %s\n", first_file_name
);
195 (void) printf("* fileb == %s\n", second_file_name
);
197 (void) puts("*******************************************************");
198 (void) fputs("Unit ", stdout
);
200 print_file(differ_file
);
206 (void) unlink(need_add_file
);
207 (void) unlink(need_rm_file
);
208 (void) unlink(differ_file
);
218 * value = 0 -> comparing two elements of same
219 * type (eg: protodir elem vs. protodir elem).
220 * value != 0 -> comparing two elements of different type
221 * (eg: protodir elem vs. protolist elem).
224 * 0 - elements are identical
225 * >0 - elements differ
226 * check flags to see which fields differ.
229 elem_compare(elem
*a
, elem
*b
, int different_types
)
235 * if these are hard links to other files - those are the
236 * files that should be compared.
238 i
= a
->link_parent
? a
->link_parent
: a
;
239 j
= b
->link_parent
? b
->link_parent
: b
;
242 * We do not compare inodes - they always differ.
243 * We do not compare names because we assume that was
248 * Special rules for comparison:
250 * 1) if directory - ignore ref_cnt.
251 * 2) if sym_link - only check file_type & symlink
252 * 3) elem type of FILE_T, EDIT_T, & VOLATILE_T are equivilant when
253 * comparing a protodir entry to a protolist entry.
255 if (i
->file_type
!= j
->file_type
) {
256 if (different_types
) {
258 * Check to see if filetypes are FILE_T vs.
259 * EDIT_T/VOLATILE_T/LINK_T comparisons.
261 if ((i
->file_type
== FILE_T
) &&
262 ((j
->file_type
== EDIT_T
) ||
263 (j
->file_type
== VOLATILE_T
) ||
264 (j
->file_type
== LINK_T
))) {
266 } else if ((j
->file_type
== FILE_T
) &&
267 ((i
->file_type
== EDIT_T
) ||
268 (i
->file_type
== VOLATILE_T
) ||
269 (i
->file_type
== LINK_T
))) {
278 * if symlink - check the symlink value and then
279 * return. symlink is the only field of concern
282 if (check_sym
&& ((res
== 0) && (i
->file_type
== SYM_LINK_T
))) {
283 if ((!i
->symsrc
) || (!j
->symsrc
))
287 * if either symlink starts with a './' strip it off,
290 if ((i
->symsrc
[0] == '.') && (i
->symsrc
[1] == '/'))
292 if ((j
->symsrc
[0] == '.') && (j
->symsrc
[1] == '/'))
295 if (strncmp(i
->symsrc
, j
->symsrc
, MAXNAME
) != 0)
301 if ((i
->file_type
!= DIR_T
) && check_link
&&
302 (i
->ref_cnt
!= j
->ref_cnt
))
304 if (check_user
&& (strncmp(i
->owner
, j
->owner
, TYPESIZE
) != 0))
306 if (check_group
&& (strncmp(i
->group
, j
->group
, TYPESIZE
) != 0))
308 if (check_perm
&& (i
->perm
!= j
->perm
))
310 if (check_majmin
&& ((i
->major
!= j
->major
) || (i
->minor
!= j
->minor
)))
317 print_elem(FILE *fp
, elem
*e
)
321 char maj
[TYPESIZE
], min
[TYPESIZE
];
322 char perm
[12], ref_cnt
[12];
325 * If this is a LINK to another file, then adopt
326 * the permissions of that file.
328 if (e
->link_parent
) {
329 p
= *((elem
*)e
->link_parent
);
330 (void) strcpy(p
.name
, e
->name
);
331 p
.symsrc
= e
->symsrc
;
332 p
.file_type
= e
->file_type
;
336 if (!check_majmin
|| e
->major
== -1) {
340 (void) sprintf(maj
, "%d", e
->major
);
343 if (!check_majmin
|| e
->minor
== -1) {
347 (void) sprintf(min
, "%d", e
->minor
);
354 (void) snprintf(perm
, sizeof (perm
), "%o", e
->perm
);
361 (void) snprintf(ref_cnt
, sizeof (ref_cnt
), "%d", e
->ref_cnt
);
364 (void) fprintf(fp
, "%c %-30s %-20s %4s %-5s %-5s %6d %2s %2s %2s ",
365 e
->file_type
, e
->name
,
366 check_sym
&& e
->symsrc
!= NULL
? e
->symsrc
: "-", perm
,
367 check_user
? e
->owner
: "-",
368 check_group
? e
->group
: "-",
369 e
->inode
, ref_cnt
, maj
, min
);
371 * dump package list - if any.
374 (void) fputs(" proto", fp
);
376 for (l
= e
->pkgs
; l
; l
= l
->next
) {
377 (void) fputc(' ', fp
);
378 (void) fputs(l
->pkg_name
, fp
);
380 (void) fputc('\n', fp
);
387 * different_types - see elem_compare() for explanation.
390 do_compare(elem
*a
, elem
*b
, int different_types
)
394 if ((rc
= elem_compare(a
, b
, different_types
)) != 0) {
395 (void) fputs("filea: ", differ_fp
);
396 print_elem(differ_fp
, a
);
397 (void) fputs("fileb: ", differ_fp
);
398 print_elem(differ_fp
, b
);
399 (void) fputs(" differ: ", differ_fp
);
402 (void) fputs("symlink", differ_fp
);
404 (void) fputs("perm ", differ_fp
);
406 (void) fputs("ref_cnt ", differ_fp
);
408 (void) fputs("file_type ", differ_fp
);
410 (void) fputs("owner ", differ_fp
);
412 (void) fputs("group ", differ_fp
);
414 (void) fputs("major/minor ", differ_fp
);
415 (void) putc('\n', differ_fp
);
416 (void) putc('\n', differ_fp
);
421 check_second_vs_first(int verbose
)
426 for (i
= 0; i
< second_list
.num_of_buckets
; i
++) {
427 for (cur
= second_list
.list
[i
]; cur
; cur
= cur
->next
) {
428 if (!(cur
->flag
& VISITED_F
)) {
429 if ((first_list
.type
!= second_list
.type
) &&
430 find_elem(&exception_list
, cur
,
433 * this entry is filtered, we don't
434 * need to do any more processing.
438 "Filtered: Need Deletion "
440 print_elem(stdout
, cur
);
445 * It is possible for arch specific files to be
446 * found in a protodir but listed as arch
447 * independent in a protolist file. If this is
448 * a protodir vs. a protolist we will make
451 if ((second_list
.type
== PROTODIR_LIST
) &&
452 (cur
->arch
!= P_ISA
) &&
453 (first_list
.type
!= PROTODIR_LIST
)) {
455 * do a lookup for same file, but as
460 e
= find_elem_isa(&first_list
, cur
,
470 print_elem(need_rm_fp
, cur
);
477 check_first_vs_second(int verbose
)
483 for (i
= 0; i
< first_list
.num_of_buckets
; i
++) {
484 for (cur
= first_list
.list
[i
]; cur
; cur
= cur
->next
) {
485 if ((first_list
.type
!= second_list
.type
) &&
486 find_elem(&exception_list
, cur
, FOLLOW_LINK
)) {
488 * this entry is filtered, we don't need to do
489 * any more processing.
492 (void) printf("Filtered: Need "
494 print_elem(stdout
, cur
);
500 * Search package database for file.
502 e
= find_elem(&second_list
, cur
, NO_FOLLOW_LINK
);
505 * It is possible for arch specific files to be found
506 * in a protodir but listed as arch independent in a
507 * protolist file. If this is a protodir vs. a
508 * protolist we will make that check.
510 if (!e
&& (first_list
.type
== PROTODIR_LIST
) &&
511 (cur
->arch
!= P_ISA
) &&
512 (second_list
.type
!= PROTODIR_LIST
)) {
514 * do a lookup for same file, but as type ISA.
516 e
= find_elem_isa(&second_list
, cur
,
520 if (!e
&& (first_list
.type
!= PROTODIR_LIST
) &&
521 (cur
->arch
== P_ISA
) &&
522 (second_list
.type
== PROTODIR_LIST
)) {
524 * do a lookup for same file, but as any
527 e
= find_elem_mach(&second_list
, cur
,
532 print_elem(need_add_fp
, cur
);
535 first_list
.type
- second_list
.type
);
536 e
->flag
|= VISITED_F
;
543 read_in_file(const char *file_name
, elem_list
*list
)
548 if (stat(file_name
, &st_buf
) == 0) {
549 if (S_ISREG(st_buf
.st_mode
)) {
551 (void) printf("file(%s): trying to process "
552 "as protolist...\n", file_name
);
554 count
= read_in_protolist(file_name
, list
, verbose
);
555 } else if (S_ISDIR(st_buf
.st_mode
)) {
557 (void) printf("directory(%s): trying to "
558 "process as protodir...\n", file_name
);
559 count
= read_in_protodir(file_name
, list
, verbose
);
561 (void) fprintf(stderr
,
562 "%s not a file or a directory.\n", file_name
);
577 set_values(const char *fname
, const struct stat
*sbp
, int otype
,
586 if (fname
[0] == '\0' || fname
[1] == '\0' || fname
[2] == '\0')
588 /* skip leading "./" */
594 if (strlcpy(keyelem
.name
, fname
, sizeof (keyelem
.name
)) >=
595 sizeof (keyelem
.name
)) {
596 (void) fprintf(stderr
, "%s: %s: name too long\n",
600 keyelem
.arch
= P_ISA
;
601 ep
= find_elem(&first_list
, &keyelem
, NO_FOLLOW_LINK
);
603 ep
= find_elem_mach(&first_list
, &keyelem
,
607 * Do nothing if this is a hard or symbolic link,
608 * since links don't have this information.
610 * Assume it's a file on the exception list if it's
611 * not found in the packaging. Those are root:bin 755.
614 (ep
->file_type
== SYM_LINK_T
|| ep
->file_type
== LINK_T
)) {
619 } else if (ep
== NULL
) {
621 } else if ((gid
= stdfind(ep
->group
, groupnames
)) == -1) {
622 (void) fprintf(stderr
, "%s: %s: group '%s' unknown\n",
623 myname
, fname
, ep
->group
);
628 } else if (ep
== NULL
) {
630 } else if ((uid
= stdfind(ep
->owner
, usernames
)) == -1) {
631 (void) fprintf(stderr
, "%s: %s: user '%s' unknown\n",
632 myname
, fname
, ep
->owner
);
635 if ((set_group
&& gid
!= -1 && gid
!= sbp
->st_gid
) ||
636 (set_user
&& uid
!= -1 && uid
!= sbp
->st_uid
)) {
638 const char *owner
, *group
;
640 owner
= ep
== NULL
? "root" : ep
->owner
;
641 group
= ep
== NULL
? "bin" : ep
->group
;
642 if (set_group
&& set_user
) {
643 (void) printf("chown %s:%s %s\n",
644 owner
, group
, fname
);
645 } else if (set_user
) {
646 (void) printf("chown %s %s\n", owner
,
649 (void) printf("chgrp %s %s\n", group
,
653 if (lchown(fname
, uid
, gid
) == -1) {
658 perm
= ep
== NULL
? 0755 : ep
->perm
;
659 if (set_perm
&& ((perm
^ sbp
->st_mode
) & ~S_IFMT
) != 0) {
661 (void) printf("chmod %lo %s\n", perm
, fname
);
662 if (chmod(fname
, perm
) == -1) {
670 (void) fprintf(stderr
, "%s: %s: permission denied\n",
682 main(int argc
, char **argv
)
686 int list_filtered_exceptions
= 0;
687 int n_proto_refs
= 0;
688 int n_exception_files
= 0;
689 char *proto_refs
[MAX_PROTO_REFS
];
690 char *exception_files
[MAX_EXCEPTION_FILES
];
693 if ((myname
= argv
[0]) == NULL
)
696 while ((c
= getopt(argc
, argv
, "gupGUPlmsLe:vd:")) != EOF
) {
726 if (n_exception_files
>= MAX_EXCEPTION_FILES
) {
728 (void) fprintf(stderr
,
729 "Only %d exception files supported\n",
730 MAX_EXCEPTION_FILES
);
732 exception_files
[n_exception_files
++] = optarg
;
736 list_filtered_exceptions
++;
742 if (n_proto_refs
>= MAX_PROTO_REFS
) {
744 (void) fprintf(stderr
,
745 "Only %d proto references supported\n",
748 proto_refs
[n_proto_refs
++] = optarg
;
758 if (argc
== optind
|| n_proto_refs
== 0) {
763 if (set_group
|| set_user
|| set_perm
) {
764 if (optind
!= argc
- 1) {
768 if (stat(argv
[optind
], &st_buf
) == -1) {
769 perror(argv
[optind
]);
772 if (!S_ISDIR(st_buf
.st_mode
)) {
773 (void) fprintf(stderr
, "%s: %s: not a directory\n",
774 myname
, argv
[optind
]);
779 init_list(&first_list
, HASH_SIZE
);
780 init_list(&second_list
, HASH_SIZE
);
781 init_list(&exception_list
, HASH_SIZE
);
783 for (i
= 0; i
< n_exception_files
; i
++) {
784 (void) read_in_exceptions(exception_files
[i
], verbose
);
787 for (i
= 0; i
< n_proto_refs
; i
++) {
788 first_file_name
= proto_refs
[i
];
789 (void) read_in_file(first_file_name
, &first_list
);
792 if (set_group
|| set_user
|| set_perm
) {
793 if (chdir(argv
[optind
]) == -1) {
794 perror(argv
[optind
]);
797 i
= nftw(".", set_values
, MAX_DEPTH
, FTW_PHYS
|FTW_DEPTH
);
805 for (i
= optind
; i
< argc
; i
++) {
806 second_file_name
= argv
[i
];
807 (void) read_in_file(second_file_name
, &second_list
);
813 (void) puts("comparing build to packages...");
815 check_first_vs_second(list_filtered_exceptions
);
818 (void) puts("checking over packages...");
819 check_second_vs_first(list_filtered_exceptions
);
821 close_output_files();