xref: /titanic_44/usr/src/tools/protocmp/protocmp.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <stdio.h>
30*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
31*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
32*7c478bd9Sstevel@tonic-gate #include <string.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
35*7c478bd9Sstevel@tonic-gate #include <dirent.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
37*7c478bd9Sstevel@tonic-gate #include <errno.h>
38*7c478bd9Sstevel@tonic-gate #include <unistd.h>
39*7c478bd9Sstevel@tonic-gate #include <ftw.h>
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #include "list.h"
42*7c478bd9Sstevel@tonic-gate #include "protocmp.h"
43*7c478bd9Sstevel@tonic-gate #include "proto_list.h"
44*7c478bd9Sstevel@tonic-gate #include "protodir.h"
45*7c478bd9Sstevel@tonic-gate #include "exception_list.h"
46*7c478bd9Sstevel@tonic-gate #include "stdusers.h"
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate #define	MAX_PROTO_REFS			5
49*7c478bd9Sstevel@tonic-gate #define	MAX_EXCEPTION_FILES		5
50*7c478bd9Sstevel@tonic-gate #define	MAX_DEPTH			50
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate /*
53*7c478bd9Sstevel@tonic-gate  * default flag values
54*7c478bd9Sstevel@tonic-gate  */
55*7c478bd9Sstevel@tonic-gate static int check_group = 1;
56*7c478bd9Sstevel@tonic-gate static int set_group = 0;
57*7c478bd9Sstevel@tonic-gate static int check_user = 1;
58*7c478bd9Sstevel@tonic-gate static int set_user = 0;
59*7c478bd9Sstevel@tonic-gate static int check_perm = 1;
60*7c478bd9Sstevel@tonic-gate static int set_perm = 0;
61*7c478bd9Sstevel@tonic-gate static int check_link = 1;
62*7c478bd9Sstevel@tonic-gate static int check_sym = 1;
63*7c478bd9Sstevel@tonic-gate static int check_majmin = 1;
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate static elem_list first_list;
66*7c478bd9Sstevel@tonic-gate static char *first_file_name;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate static elem_list second_list;
69*7c478bd9Sstevel@tonic-gate static char *second_file_name;
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate static FILE *need_add_fp;
72*7c478bd9Sstevel@tonic-gate static char *need_add_file;
73*7c478bd9Sstevel@tonic-gate static FILE *need_rm_fp;
74*7c478bd9Sstevel@tonic-gate static char *need_rm_file;
75*7c478bd9Sstevel@tonic-gate static FILE *differ_fp;
76*7c478bd9Sstevel@tonic-gate static char *differ_file;
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate static char *myname;
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate /*
81*7c478bd9Sstevel@tonic-gate  * default flag values
82*7c478bd9Sstevel@tonic-gate  */
83*7c478bd9Sstevel@tonic-gate static int verbose = 0;
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate static void
86*7c478bd9Sstevel@tonic-gate usage(void)
87*7c478bd9Sstevel@tonic-gate {
88*7c478bd9Sstevel@tonic-gate 	(void) fputs("usage: protocmp [-gupGUPlmsLv] "
89*7c478bd9Sstevel@tonic-gate 	    "[-e <exception-list> ...] "
90*7c478bd9Sstevel@tonic-gate 	    "-d <protolist|pkg dir>\n\t[-d <protolist|pkg dir> ...] "
91*7c478bd9Sstevel@tonic-gate 	    "[<protolist|pkg dir>...]|<root>]\n",
92*7c478bd9Sstevel@tonic-gate 	    stderr);
93*7c478bd9Sstevel@tonic-gate 	(void) fputs("   where:\n", stderr);
94*7c478bd9Sstevel@tonic-gate 	(void) fputs("\t-g       : don't compare group\n", stderr);
95*7c478bd9Sstevel@tonic-gate 	(void) fputs("\t-u       : don't compare owner\n", stderr);
96*7c478bd9Sstevel@tonic-gate 	(void) fputs("\t-p       : don't compare permissions\n", stderr);
97*7c478bd9Sstevel@tonic-gate 	(void) fputs("\t-G       : set group\n", stderr);
98*7c478bd9Sstevel@tonic-gate 	(void) fputs("\t-U       : set owner\n", stderr);
99*7c478bd9Sstevel@tonic-gate 	(void) fputs("\t-P       : set permissions\n", stderr);
100*7c478bd9Sstevel@tonic-gate 	(void) fputs("\t-l       : don't compare link counts\n", stderr);
101*7c478bd9Sstevel@tonic-gate 	(void) fputs("\t-m       : don't compare major/minor numbers\n",
102*7c478bd9Sstevel@tonic-gate 	    stderr);
103*7c478bd9Sstevel@tonic-gate 	(void) fputs("\t-s       : don't compare symlink values\n", stderr);
104*7c478bd9Sstevel@tonic-gate 	(void) fputs("\t-d <protolist|pkg dir>:\n", stderr);
105*7c478bd9Sstevel@tonic-gate 	(void) fputs("\t           proto list or packaging to check\n", stderr);
106*7c478bd9Sstevel@tonic-gate 	(void) fputs("\t-e <file>: exceptions file\n", stderr);
107*7c478bd9Sstevel@tonic-gate 	(void) fputs("\t-L       : list filtered exceptions\n", stderr);
108*7c478bd9Sstevel@tonic-gate 	(void) fputs("\t-v       : verbose output\n", stderr);
109*7c478bd9Sstevel@tonic-gate 	(void) fputs("\n"
110*7c478bd9Sstevel@tonic-gate "If any of the -[GUP] flags are given, then the final argument must be the\n"
111*7c478bd9Sstevel@tonic-gate "proto root directory itself on which to set permissions according to the\n"
112*7c478bd9Sstevel@tonic-gate "packaging data specified via -d options.\n", stderr);
113*7c478bd9Sstevel@tonic-gate }
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate static void
117*7c478bd9Sstevel@tonic-gate open_output_files(void)
118*7c478bd9Sstevel@tonic-gate {
119*7c478bd9Sstevel@tonic-gate 	if ((need_add_fp =
120*7c478bd9Sstevel@tonic-gate 	    fopen((need_add_file = tempnam(NULL, "add")), "w")) == NULL) {
121*7c478bd9Sstevel@tonic-gate 		perror(need_add_file);
122*7c478bd9Sstevel@tonic-gate 		exit(1);
123*7c478bd9Sstevel@tonic-gate 	}
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	if ((need_rm_fp =
126*7c478bd9Sstevel@tonic-gate 	    fopen((need_rm_file = tempnam(NULL, "rm")), "w")) == NULL) {
127*7c478bd9Sstevel@tonic-gate 		perror(need_rm_file);
128*7c478bd9Sstevel@tonic-gate 		exit(1);
129*7c478bd9Sstevel@tonic-gate 	}
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 	if ((differ_fp =
132*7c478bd9Sstevel@tonic-gate 	    fopen((differ_file = tempnam(NULL, "diff")), "w")) == NULL) {
133*7c478bd9Sstevel@tonic-gate 		perror(differ_file);
134*7c478bd9Sstevel@tonic-gate 		exit(1);
135*7c478bd9Sstevel@tonic-gate 	}
136*7c478bd9Sstevel@tonic-gate }
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate static void
139*7c478bd9Sstevel@tonic-gate close_output_files(void)
140*7c478bd9Sstevel@tonic-gate {
141*7c478bd9Sstevel@tonic-gate 	(void) fclose(need_add_fp);
142*7c478bd9Sstevel@tonic-gate 	(void) fclose(need_rm_fp);
143*7c478bd9Sstevel@tonic-gate 	(void) fclose(differ_fp);
144*7c478bd9Sstevel@tonic-gate }
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate static void
147*7c478bd9Sstevel@tonic-gate print_file(char *file)
148*7c478bd9Sstevel@tonic-gate {
149*7c478bd9Sstevel@tonic-gate 	FILE	*fp;
150*7c478bd9Sstevel@tonic-gate 	int	count;
151*7c478bd9Sstevel@tonic-gate 	char	buff[BUF_SIZE];
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(file, "r")) == NULL) {
154*7c478bd9Sstevel@tonic-gate 		perror(need_add_file);
155*7c478bd9Sstevel@tonic-gate 	}
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 	while (count = fread(buff, sizeof (char), BUF_SIZE, fp))
158*7c478bd9Sstevel@tonic-gate 		(void) fwrite(buff, sizeof (char), count, stdout);
159*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
160*7c478bd9Sstevel@tonic-gate }
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate static void
163*7c478bd9Sstevel@tonic-gate print_header(void)
164*7c478bd9Sstevel@tonic-gate {
165*7c478bd9Sstevel@tonic-gate 	(void) printf("%c %-30s %-20s %-4s %-5s %-5s %-5s %-2s %2s %2s %-9s\n",
166*7c478bd9Sstevel@tonic-gate 	    'T', "File Name", "Reloc/Sym name", "perm", "owner", "group",
167*7c478bd9Sstevel@tonic-gate 	    "inode", "lnk", "maj", "min", "package(s)");
168*7c478bd9Sstevel@tonic-gate 	(void) puts("-------------------------------------------------------"
169*7c478bd9Sstevel@tonic-gate 	    "-----------------------------------------------------");
170*7c478bd9Sstevel@tonic-gate }
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate static void
173*7c478bd9Sstevel@tonic-gate print_results(void)
174*7c478bd9Sstevel@tonic-gate {
175*7c478bd9Sstevel@tonic-gate 	(void) puts("*******************************************************");
176*7c478bd9Sstevel@tonic-gate 	(void) puts("*");
177*7c478bd9Sstevel@tonic-gate 	(void) printf("* Entries found in %s, but not found in %s\n",
178*7c478bd9Sstevel@tonic-gate 	    first_file_name, second_file_name);
179*7c478bd9Sstevel@tonic-gate 	(void) puts("*");
180*7c478bd9Sstevel@tonic-gate 	(void) puts("*******************************************************");
181*7c478bd9Sstevel@tonic-gate 	print_header();
182*7c478bd9Sstevel@tonic-gate 	print_file(need_add_file);
183*7c478bd9Sstevel@tonic-gate 	(void) puts("*******************************************************");
184*7c478bd9Sstevel@tonic-gate 	(void) puts("*");
185*7c478bd9Sstevel@tonic-gate 	(void) printf("* Entries found in %s, but not found in %s\n",
186*7c478bd9Sstevel@tonic-gate 	    second_file_name, first_file_name);
187*7c478bd9Sstevel@tonic-gate 	(void) puts("*");
188*7c478bd9Sstevel@tonic-gate 	(void) puts("*******************************************************");
189*7c478bd9Sstevel@tonic-gate 	print_header();
190*7c478bd9Sstevel@tonic-gate 	print_file(need_rm_file);
191*7c478bd9Sstevel@tonic-gate 	(void) puts("*******************************************************");
192*7c478bd9Sstevel@tonic-gate 	(void) puts("*");
193*7c478bd9Sstevel@tonic-gate 	(void) printf("* Entries that differ between %s and %s\n",
194*7c478bd9Sstevel@tonic-gate 	    first_file_name, second_file_name);
195*7c478bd9Sstevel@tonic-gate 	(void) puts("*");
196*7c478bd9Sstevel@tonic-gate 	(void) printf("* filea == %s\n", first_file_name);
197*7c478bd9Sstevel@tonic-gate 	(void) printf("* fileb == %s\n", second_file_name);
198*7c478bd9Sstevel@tonic-gate 	(void) puts("*");
199*7c478bd9Sstevel@tonic-gate 	(void) puts("*******************************************************");
200*7c478bd9Sstevel@tonic-gate 	(void) fputs("Unit   ", stdout);
201*7c478bd9Sstevel@tonic-gate 	print_header();
202*7c478bd9Sstevel@tonic-gate 	print_file(differ_file);
203*7c478bd9Sstevel@tonic-gate }
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate static void
206*7c478bd9Sstevel@tonic-gate clean_up(void)
207*7c478bd9Sstevel@tonic-gate {
208*7c478bd9Sstevel@tonic-gate 	(void) unlink(need_add_file);
209*7c478bd9Sstevel@tonic-gate 	(void) unlink(need_rm_file);
210*7c478bd9Sstevel@tonic-gate 	(void) unlink(differ_file);
211*7c478bd9Sstevel@tonic-gate }
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate /*
214*7c478bd9Sstevel@tonic-gate  * elem_compare(a,b)
215*7c478bd9Sstevel@tonic-gate  *
216*7c478bd9Sstevel@tonic-gate  * Args:
217*7c478bd9Sstevel@tonic-gate  *	a 		- element a
218*7c478bd9Sstevel@tonic-gate  *	b 		- element b
219*7c478bd9Sstevel@tonic-gate  *	different_types -
220*7c478bd9Sstevel@tonic-gate  *		value = 0  -> comparing two elements of same
221*7c478bd9Sstevel@tonic-gate  *			      type (eg: protodir elem vs. protodir elem).
222*7c478bd9Sstevel@tonic-gate  *		value != 0 -> comparing two elements of different type
223*7c478bd9Sstevel@tonic-gate  *			      (eg: protodir elem vs. protolist elem).
224*7c478bd9Sstevel@tonic-gate  *
225*7c478bd9Sstevel@tonic-gate  * Returns:
226*7c478bd9Sstevel@tonic-gate  *	0   - elements are identical
227*7c478bd9Sstevel@tonic-gate  *	>0  - elements differ
228*7c478bd9Sstevel@tonic-gate  *	      check flags to see which fields differ.
229*7c478bd9Sstevel@tonic-gate  */
230*7c478bd9Sstevel@tonic-gate static int
231*7c478bd9Sstevel@tonic-gate elem_compare(elem *a, elem *b, int different_types)
232*7c478bd9Sstevel@tonic-gate {
233*7c478bd9Sstevel@tonic-gate 	int	res = 0;
234*7c478bd9Sstevel@tonic-gate 	elem	*i, *j;
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	/*
237*7c478bd9Sstevel@tonic-gate 	 * if these are hard links to other files - those are the
238*7c478bd9Sstevel@tonic-gate 	 * files that should be compared.
239*7c478bd9Sstevel@tonic-gate 	 */
240*7c478bd9Sstevel@tonic-gate 	i = a->link_parent ? a->link_parent : a;
241*7c478bd9Sstevel@tonic-gate 	j = b->link_parent ? b->link_parent : b;
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 	/*
244*7c478bd9Sstevel@tonic-gate 	 * We do not compare inodes - they always differ.
245*7c478bd9Sstevel@tonic-gate 	 * We do not compare names because we assume that was
246*7c478bd9Sstevel@tonic-gate 	 * checked before.
247*7c478bd9Sstevel@tonic-gate 	 */
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 	/*
250*7c478bd9Sstevel@tonic-gate 	 * Special rules for comparison:
251*7c478bd9Sstevel@tonic-gate 	 *
252*7c478bd9Sstevel@tonic-gate 	 * 1) if directory - ignore ref_cnt.
253*7c478bd9Sstevel@tonic-gate 	 * 2) if sym_link - only check file_type & symlink
254*7c478bd9Sstevel@tonic-gate 	 * 3) elem type of FILE_T, EDIT_T, & VOLATILE_T are equivilant when
255*7c478bd9Sstevel@tonic-gate 	 *    comparing a protodir entry to a protolist entry.
256*7c478bd9Sstevel@tonic-gate 	 */
257*7c478bd9Sstevel@tonic-gate 	if (i->file_type != j->file_type) {
258*7c478bd9Sstevel@tonic-gate 		if (different_types) {
259*7c478bd9Sstevel@tonic-gate 			/*
260*7c478bd9Sstevel@tonic-gate 			 * Check to see if filetypes are FILE_T vs.
261*7c478bd9Sstevel@tonic-gate 			 * EDIT_T/VOLATILE_T/LINK_T comparisons.
262*7c478bd9Sstevel@tonic-gate 			 */
263*7c478bd9Sstevel@tonic-gate 			if ((i->file_type == FILE_T) &&
264*7c478bd9Sstevel@tonic-gate 			    ((j->file_type == EDIT_T) ||
265*7c478bd9Sstevel@tonic-gate 			    (j->file_type == VOLATILE_T) ||
266*7c478bd9Sstevel@tonic-gate 			    (j->file_type == LINK_T))) {
267*7c478bd9Sstevel@tonic-gate 				/*EMPTY*/
268*7c478bd9Sstevel@tonic-gate 			} else if ((j->file_type == FILE_T) &&
269*7c478bd9Sstevel@tonic-gate 			    ((i->file_type == EDIT_T) ||
270*7c478bd9Sstevel@tonic-gate 			    (i->file_type == VOLATILE_T) ||
271*7c478bd9Sstevel@tonic-gate 			    (i->file_type == LINK_T))) {
272*7c478bd9Sstevel@tonic-gate 				/*EMPTY*/
273*7c478bd9Sstevel@tonic-gate 			} else
274*7c478bd9Sstevel@tonic-gate 				res |= TYPE_F;
275*7c478bd9Sstevel@tonic-gate 		} else
276*7c478bd9Sstevel@tonic-gate 			res |= TYPE_F;
277*7c478bd9Sstevel@tonic-gate 	}
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate 	/*
280*7c478bd9Sstevel@tonic-gate 	 * if symlink - check the symlink value and then
281*7c478bd9Sstevel@tonic-gate 	 * return.  symlink is the only field of concern
282*7c478bd9Sstevel@tonic-gate 	 * in SYMLINKS.
283*7c478bd9Sstevel@tonic-gate 	 */
284*7c478bd9Sstevel@tonic-gate 	if (check_sym && ((res == 0) && (i->file_type == SYM_LINK_T))) {
285*7c478bd9Sstevel@tonic-gate 		if ((!i->symsrc) || (!j->symsrc))
286*7c478bd9Sstevel@tonic-gate 			res |= SYM_F;
287*7c478bd9Sstevel@tonic-gate 		else {
288*7c478bd9Sstevel@tonic-gate 			/*
289*7c478bd9Sstevel@tonic-gate 			 * if either symlink starts with a './' strip it off,
290*7c478bd9Sstevel@tonic-gate 			 * its irrelavant.
291*7c478bd9Sstevel@tonic-gate 			 */
292*7c478bd9Sstevel@tonic-gate 			if ((i->symsrc[0] == '.') && (i->symsrc[1] == '/'))
293*7c478bd9Sstevel@tonic-gate 				i->symsrc += 2;
294*7c478bd9Sstevel@tonic-gate 			if ((j->symsrc[0] == '.') && (j->symsrc[1] == '/'))
295*7c478bd9Sstevel@tonic-gate 				j->symsrc += 2;
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 			if (strncmp(i->symsrc, j->symsrc, MAXNAME) != 0)
298*7c478bd9Sstevel@tonic-gate 				res |= SYM_F;
299*7c478bd9Sstevel@tonic-gate 		}
300*7c478bd9Sstevel@tonic-gate 		return (res);
301*7c478bd9Sstevel@tonic-gate 	}
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	if ((i->file_type != DIR_T) && check_link &&
304*7c478bd9Sstevel@tonic-gate 	    (i->ref_cnt != j->ref_cnt))
305*7c478bd9Sstevel@tonic-gate 		res |= REF_F;
306*7c478bd9Sstevel@tonic-gate 	if (check_user && (strncmp(i->owner, j->owner, TYPESIZE) != 0))
307*7c478bd9Sstevel@tonic-gate 		res |= OWNER_F;
308*7c478bd9Sstevel@tonic-gate 	if (check_group && (strncmp(i->group, j->group, TYPESIZE) != 0))
309*7c478bd9Sstevel@tonic-gate 		res |= GROUP_F;
310*7c478bd9Sstevel@tonic-gate 	if (check_perm && (i->perm != j->perm))
311*7c478bd9Sstevel@tonic-gate 		res |= PERM_F;
312*7c478bd9Sstevel@tonic-gate 	if (check_majmin && ((i->major != j->major) || (i->minor != j->minor)))
313*7c478bd9Sstevel@tonic-gate 		res |= MAJMIN_F;
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	return (res);
316*7c478bd9Sstevel@tonic-gate }
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate static void
319*7c478bd9Sstevel@tonic-gate print_elem(FILE *fp, elem *e)
320*7c478bd9Sstevel@tonic-gate {
321*7c478bd9Sstevel@tonic-gate 	elem		p;
322*7c478bd9Sstevel@tonic-gate 	pkg_list	*l;
323*7c478bd9Sstevel@tonic-gate 	char		maj[TYPESIZE], min[TYPESIZE];
324*7c478bd9Sstevel@tonic-gate 	char		perm[12], ref_cnt[12];
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 	/*
327*7c478bd9Sstevel@tonic-gate 	 * If this is a LINK to another file, then adopt
328*7c478bd9Sstevel@tonic-gate 	 * the permissions of that file.
329*7c478bd9Sstevel@tonic-gate 	 */
330*7c478bd9Sstevel@tonic-gate 	if (e->link_parent) {
331*7c478bd9Sstevel@tonic-gate 		p = *((elem *)e->link_parent);
332*7c478bd9Sstevel@tonic-gate 		(void) strcpy(p.name, e->name);
333*7c478bd9Sstevel@tonic-gate 		p.symsrc = e->symsrc;
334*7c478bd9Sstevel@tonic-gate 		p.file_type = e->file_type;
335*7c478bd9Sstevel@tonic-gate 		e = &p;
336*7c478bd9Sstevel@tonic-gate 	}
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 	if (!check_majmin || e->major == -1) {
339*7c478bd9Sstevel@tonic-gate 		maj[0] = '-';
340*7c478bd9Sstevel@tonic-gate 		maj[1] = '\0';
341*7c478bd9Sstevel@tonic-gate 	} else {
342*7c478bd9Sstevel@tonic-gate 		(void) sprintf(maj, "%d", e->major);
343*7c478bd9Sstevel@tonic-gate 	}
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	if (!check_majmin || e->minor == -1) {
346*7c478bd9Sstevel@tonic-gate 		min[0] = '-';
347*7c478bd9Sstevel@tonic-gate 		min[1] = '\0';
348*7c478bd9Sstevel@tonic-gate 	} else {
349*7c478bd9Sstevel@tonic-gate 		(void) sprintf(min, "%d", e->minor);
350*7c478bd9Sstevel@tonic-gate 	}
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	if (!check_perm) {
353*7c478bd9Sstevel@tonic-gate 		perm[0] = '-';
354*7c478bd9Sstevel@tonic-gate 		perm[1] = '\0';
355*7c478bd9Sstevel@tonic-gate 	} else {
356*7c478bd9Sstevel@tonic-gate 		(void) snprintf(perm, sizeof (perm), "%o", e->perm);
357*7c478bd9Sstevel@tonic-gate 	}
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 	if (!check_link) {
360*7c478bd9Sstevel@tonic-gate 		ref_cnt[0] = '-';
361*7c478bd9Sstevel@tonic-gate 		ref_cnt[1] = '\0';
362*7c478bd9Sstevel@tonic-gate 	} else {
363*7c478bd9Sstevel@tonic-gate 		(void) snprintf(ref_cnt, sizeof (ref_cnt), "%d", e->ref_cnt);
364*7c478bd9Sstevel@tonic-gate 	}
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "%c %-30s %-20s %4s %-5s %-5s %6d %2s %2s %2s   ",
367*7c478bd9Sstevel@tonic-gate 	    e->file_type, e->name,
368*7c478bd9Sstevel@tonic-gate 	    check_sym && e->symsrc != NULL ? e->symsrc : "-", perm,
369*7c478bd9Sstevel@tonic-gate 	    check_user ? e->owner : "-",
370*7c478bd9Sstevel@tonic-gate 	    check_group ? e->group : "-",
371*7c478bd9Sstevel@tonic-gate 	    e->inode, ref_cnt, maj, min);
372*7c478bd9Sstevel@tonic-gate 	/*
373*7c478bd9Sstevel@tonic-gate 	 * dump package list - if any.
374*7c478bd9Sstevel@tonic-gate 	 */
375*7c478bd9Sstevel@tonic-gate 	if (!e->pkgs)
376*7c478bd9Sstevel@tonic-gate 		(void) fputs(" proto", fp);
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	for (l = e->pkgs; l; l = l->next) {
379*7c478bd9Sstevel@tonic-gate 		(void) fputc(' ', fp);
380*7c478bd9Sstevel@tonic-gate 		(void) fputs(l->pkg_name, fp);
381*7c478bd9Sstevel@tonic-gate 	}
382*7c478bd9Sstevel@tonic-gate 	(void) fputc('\n', fp);
383*7c478bd9Sstevel@tonic-gate }
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate /*
386*7c478bd9Sstevel@tonic-gate  * do_compare(a,b)
387*7c478bd9Sstevel@tonic-gate  *
388*7c478bd9Sstevel@tonic-gate  * Args:
389*7c478bd9Sstevel@tonic-gate  *	different_types - see elem_compare() for explanation.
390*7c478bd9Sstevel@tonic-gate  */
391*7c478bd9Sstevel@tonic-gate static void
392*7c478bd9Sstevel@tonic-gate do_compare(elem *a, elem *b, int different_types)
393*7c478bd9Sstevel@tonic-gate {
394*7c478bd9Sstevel@tonic-gate 	int	rc;
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	if ((rc = elem_compare(a, b, different_types)) != 0) {
397*7c478bd9Sstevel@tonic-gate 		(void) fputs("filea: ", differ_fp);
398*7c478bd9Sstevel@tonic-gate 		print_elem(differ_fp, a);
399*7c478bd9Sstevel@tonic-gate 		(void) fputs("fileb: ", differ_fp);
400*7c478bd9Sstevel@tonic-gate 		print_elem(differ_fp, b);
401*7c478bd9Sstevel@tonic-gate 		(void) fputs("    differ: ", differ_fp);
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 		if (rc & SYM_F)
404*7c478bd9Sstevel@tonic-gate 			(void) fputs("symlink", differ_fp);
405*7c478bd9Sstevel@tonic-gate 		if (rc & PERM_F)
406*7c478bd9Sstevel@tonic-gate 			(void) fputs("perm ", differ_fp);
407*7c478bd9Sstevel@tonic-gate 		if (rc & REF_F)
408*7c478bd9Sstevel@tonic-gate 			(void) fputs("ref_cnt ", differ_fp);
409*7c478bd9Sstevel@tonic-gate 		if (rc & TYPE_F)
410*7c478bd9Sstevel@tonic-gate 			(void) fputs("file_type ", differ_fp);
411*7c478bd9Sstevel@tonic-gate 		if (rc & OWNER_F)
412*7c478bd9Sstevel@tonic-gate 			(void) fputs("owner ", differ_fp);
413*7c478bd9Sstevel@tonic-gate 		if (rc & GROUP_F)
414*7c478bd9Sstevel@tonic-gate 			(void) fputs("group ", differ_fp);
415*7c478bd9Sstevel@tonic-gate 		if (rc & MAJMIN_F)
416*7c478bd9Sstevel@tonic-gate 			(void) fputs("major/minor ", differ_fp);
417*7c478bd9Sstevel@tonic-gate 		(void) putc('\n', differ_fp);
418*7c478bd9Sstevel@tonic-gate 		(void) putc('\n', differ_fp);
419*7c478bd9Sstevel@tonic-gate 	}
420*7c478bd9Sstevel@tonic-gate }
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate static void
423*7c478bd9Sstevel@tonic-gate check_second_vs_first(int verbose)
424*7c478bd9Sstevel@tonic-gate {
425*7c478bd9Sstevel@tonic-gate 	int	i;
426*7c478bd9Sstevel@tonic-gate 	elem	*cur;
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < second_list.num_of_buckets; i++) {
429*7c478bd9Sstevel@tonic-gate 		for (cur = second_list.list[i]; cur; cur = cur->next) {
430*7c478bd9Sstevel@tonic-gate 			if (!(cur->flag & VISITED_F)) {
431*7c478bd9Sstevel@tonic-gate 				if ((first_list.type != second_list.type) &&
432*7c478bd9Sstevel@tonic-gate 				    find_elem(&exception_list, cur,
433*7c478bd9Sstevel@tonic-gate 				    FOLLOW_LINK)) {
434*7c478bd9Sstevel@tonic-gate 					/*
435*7c478bd9Sstevel@tonic-gate 					 * this entry is filtered, we don't
436*7c478bd9Sstevel@tonic-gate 					 * need to do any more processing.
437*7c478bd9Sstevel@tonic-gate 					 */
438*7c478bd9Sstevel@tonic-gate 					if (verbose) {
439*7c478bd9Sstevel@tonic-gate 						(void) printf(
440*7c478bd9Sstevel@tonic-gate 						    "Filtered: Need Deletion "
441*7c478bd9Sstevel@tonic-gate 						    "of:\n\t");
442*7c478bd9Sstevel@tonic-gate 						print_elem(stdout, cur);
443*7c478bd9Sstevel@tonic-gate 					}
444*7c478bd9Sstevel@tonic-gate 					continue;
445*7c478bd9Sstevel@tonic-gate 				}
446*7c478bd9Sstevel@tonic-gate 				/*
447*7c478bd9Sstevel@tonic-gate 				 * It is possible for arch specific files to be
448*7c478bd9Sstevel@tonic-gate 				 * found in a protodir but listed as arch
449*7c478bd9Sstevel@tonic-gate 				 * independent in a protolist file.  If this is
450*7c478bd9Sstevel@tonic-gate 				 * a protodir vs. a protolist we will make
451*7c478bd9Sstevel@tonic-gate 				 * that check.
452*7c478bd9Sstevel@tonic-gate 				 */
453*7c478bd9Sstevel@tonic-gate 				if ((second_list.type == PROTODIR_LIST) &&
454*7c478bd9Sstevel@tonic-gate 				    (cur->arch != P_ISA) &&
455*7c478bd9Sstevel@tonic-gate 				    (first_list.type != PROTODIR_LIST)) {
456*7c478bd9Sstevel@tonic-gate 					/*
457*7c478bd9Sstevel@tonic-gate 					 * do a lookup for same file, but as
458*7c478bd9Sstevel@tonic-gate 					 * type ISA.
459*7c478bd9Sstevel@tonic-gate 					 */
460*7c478bd9Sstevel@tonic-gate 					elem	*e;
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 					e = find_elem_isa(&first_list, cur,
463*7c478bd9Sstevel@tonic-gate 					    NO_FOLLOW_LINK);
464*7c478bd9Sstevel@tonic-gate 					if (e) {
465*7c478bd9Sstevel@tonic-gate 						do_compare(e, cur,
466*7c478bd9Sstevel@tonic-gate 						    first_list.type -
467*7c478bd9Sstevel@tonic-gate 						    second_list.type);
468*7c478bd9Sstevel@tonic-gate 						continue;
469*7c478bd9Sstevel@tonic-gate 					}
470*7c478bd9Sstevel@tonic-gate 				}
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 				print_elem(need_rm_fp, cur);
473*7c478bd9Sstevel@tonic-gate 			}
474*7c478bd9Sstevel@tonic-gate 		}
475*7c478bd9Sstevel@tonic-gate 	}
476*7c478bd9Sstevel@tonic-gate }
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate static void
479*7c478bd9Sstevel@tonic-gate check_first_vs_second(int verbose)
480*7c478bd9Sstevel@tonic-gate {
481*7c478bd9Sstevel@tonic-gate 	int	i;
482*7c478bd9Sstevel@tonic-gate 	elem	*e;
483*7c478bd9Sstevel@tonic-gate 	elem	*cur;
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < first_list.num_of_buckets; i++) {
486*7c478bd9Sstevel@tonic-gate 		for (cur = first_list.list[i]; cur; cur = cur->next) {
487*7c478bd9Sstevel@tonic-gate 			if ((first_list.type != second_list.type) &&
488*7c478bd9Sstevel@tonic-gate 			    find_elem(&exception_list, cur, FOLLOW_LINK)) {
489*7c478bd9Sstevel@tonic-gate 				/*
490*7c478bd9Sstevel@tonic-gate 				 * this entry is filtered, we don't need to do
491*7c478bd9Sstevel@tonic-gate 				 * any more processing.
492*7c478bd9Sstevel@tonic-gate 				 */
493*7c478bd9Sstevel@tonic-gate 				if (verbose) {
494*7c478bd9Sstevel@tonic-gate 					(void) printf("Filtered: Need "
495*7c478bd9Sstevel@tonic-gate 					    "Addition of:\n\t");
496*7c478bd9Sstevel@tonic-gate 					print_elem(stdout, cur);
497*7c478bd9Sstevel@tonic-gate 				}
498*7c478bd9Sstevel@tonic-gate 				continue;
499*7c478bd9Sstevel@tonic-gate 			}
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 			/*
502*7c478bd9Sstevel@tonic-gate 			 * Search package database for file.
503*7c478bd9Sstevel@tonic-gate 			 */
504*7c478bd9Sstevel@tonic-gate 			e = find_elem(&second_list, cur, NO_FOLLOW_LINK);
505*7c478bd9Sstevel@tonic-gate 
506*7c478bd9Sstevel@tonic-gate 			/*
507*7c478bd9Sstevel@tonic-gate 			 * It is possible for arch specific files to be found
508*7c478bd9Sstevel@tonic-gate 			 * in a protodir but listed as arch independent in a
509*7c478bd9Sstevel@tonic-gate 			 * protolist file.  If this is a protodir vs. a
510*7c478bd9Sstevel@tonic-gate 			 * protolist we will make that check.
511*7c478bd9Sstevel@tonic-gate 			 */
512*7c478bd9Sstevel@tonic-gate 			if (!e && (first_list.type == PROTODIR_LIST) &&
513*7c478bd9Sstevel@tonic-gate 			    (cur->arch != P_ISA) &&
514*7c478bd9Sstevel@tonic-gate 			    (second_list.type != PROTODIR_LIST)) {
515*7c478bd9Sstevel@tonic-gate 				/*
516*7c478bd9Sstevel@tonic-gate 				 * do a lookup for same file, but as type ISA.
517*7c478bd9Sstevel@tonic-gate 				 */
518*7c478bd9Sstevel@tonic-gate 				e = find_elem_isa(&second_list, cur,
519*7c478bd9Sstevel@tonic-gate 				    NO_FOLLOW_LINK);
520*7c478bd9Sstevel@tonic-gate 			}
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 			if (!e && (first_list.type != PROTODIR_LIST) &&
523*7c478bd9Sstevel@tonic-gate 			    (cur->arch == P_ISA) &&
524*7c478bd9Sstevel@tonic-gate 			    (second_list.type == PROTODIR_LIST)) {
525*7c478bd9Sstevel@tonic-gate 				/*
526*7c478bd9Sstevel@tonic-gate 				 * do a lookup for same file, but as any
527*7c478bd9Sstevel@tonic-gate 				 * type but ISA
528*7c478bd9Sstevel@tonic-gate 				 */
529*7c478bd9Sstevel@tonic-gate 				e = find_elem_mach(&second_list, cur,
530*7c478bd9Sstevel@tonic-gate 				    NO_FOLLOW_LINK);
531*7c478bd9Sstevel@tonic-gate 			}
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 			if (e == NULL)
534*7c478bd9Sstevel@tonic-gate 				print_elem(need_add_fp, cur);
535*7c478bd9Sstevel@tonic-gate 			else {
536*7c478bd9Sstevel@tonic-gate 				do_compare(cur, e,
537*7c478bd9Sstevel@tonic-gate 				    first_list.type - second_list.type);
538*7c478bd9Sstevel@tonic-gate 				e->flag |= VISITED_F;
539*7c478bd9Sstevel@tonic-gate 			}
540*7c478bd9Sstevel@tonic-gate 		}
541*7c478bd9Sstevel@tonic-gate 	}
542*7c478bd9Sstevel@tonic-gate }
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate static int
545*7c478bd9Sstevel@tonic-gate read_in_file(const char *file_name, elem_list *list)
546*7c478bd9Sstevel@tonic-gate {
547*7c478bd9Sstevel@tonic-gate 	struct stat	st_buf;
548*7c478bd9Sstevel@tonic-gate 	int		count = 0;
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	if (stat(file_name, &st_buf) == 0) {
551*7c478bd9Sstevel@tonic-gate 		if (S_ISREG(st_buf.st_mode)) {
552*7c478bd9Sstevel@tonic-gate 			if (verbose) {
553*7c478bd9Sstevel@tonic-gate 				(void) printf("file(%s): trying to process "
554*7c478bd9Sstevel@tonic-gate 				    "as protolist...\n", file_name);
555*7c478bd9Sstevel@tonic-gate 			}
556*7c478bd9Sstevel@tonic-gate 			count = read_in_protolist(file_name, list, verbose);
557*7c478bd9Sstevel@tonic-gate 		} else if (S_ISDIR(st_buf.st_mode)) {
558*7c478bd9Sstevel@tonic-gate 			if (verbose)
559*7c478bd9Sstevel@tonic-gate 				(void) printf("directory(%s): trying to "
560*7c478bd9Sstevel@tonic-gate 				    "process as protodir...\n", file_name);
561*7c478bd9Sstevel@tonic-gate 			count = read_in_protodir(file_name, list, verbose);
562*7c478bd9Sstevel@tonic-gate 		} else {
563*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
564*7c478bd9Sstevel@tonic-gate 			    "%s not a file or a directory.\n", file_name);
565*7c478bd9Sstevel@tonic-gate 			usage();
566*7c478bd9Sstevel@tonic-gate 			exit(1);
567*7c478bd9Sstevel@tonic-gate 		}
568*7c478bd9Sstevel@tonic-gate 	} else {
569*7c478bd9Sstevel@tonic-gate 		perror(file_name);
570*7c478bd9Sstevel@tonic-gate 		usage();
571*7c478bd9Sstevel@tonic-gate 		exit(1);
572*7c478bd9Sstevel@tonic-gate 	}
573*7c478bd9Sstevel@tonic-gate 
574*7c478bd9Sstevel@tonic-gate 	return (count);
575*7c478bd9Sstevel@tonic-gate }
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
578*7c478bd9Sstevel@tonic-gate static int
579*7c478bd9Sstevel@tonic-gate set_values(const char *fname, const struct stat *sbp, int otype,
580*7c478bd9Sstevel@tonic-gate     struct FTW *ftw)
581*7c478bd9Sstevel@tonic-gate {
582*7c478bd9Sstevel@tonic-gate 	elem *ep;
583*7c478bd9Sstevel@tonic-gate 	uid_t uid;
584*7c478bd9Sstevel@tonic-gate 	gid_t gid;
585*7c478bd9Sstevel@tonic-gate 	elem keyelem;
586*7c478bd9Sstevel@tonic-gate 	mode_t perm;
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 	if (fname[0] == '\0' || fname[1] == '\0' || fname[2] == '\0')
589*7c478bd9Sstevel@tonic-gate 		return (0);
590*7c478bd9Sstevel@tonic-gate 	/* skip leading "./" */
591*7c478bd9Sstevel@tonic-gate 	fname += 2;
592*7c478bd9Sstevel@tonic-gate 	switch (otype) {
593*7c478bd9Sstevel@tonic-gate 	case FTW_F:
594*7c478bd9Sstevel@tonic-gate 	case FTW_D:
595*7c478bd9Sstevel@tonic-gate 	case FTW_DP:
596*7c478bd9Sstevel@tonic-gate 		if (strlcpy(keyelem.name, fname, sizeof (keyelem.name)) >=
597*7c478bd9Sstevel@tonic-gate 		    sizeof (keyelem.name)) {
598*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: %s: name too long\n",
599*7c478bd9Sstevel@tonic-gate 			    myname, fname);
600*7c478bd9Sstevel@tonic-gate 			return (1);
601*7c478bd9Sstevel@tonic-gate 		}
602*7c478bd9Sstevel@tonic-gate 		keyelem.arch = P_ISA;
603*7c478bd9Sstevel@tonic-gate 		ep = find_elem(&first_list, &keyelem, NO_FOLLOW_LINK);
604*7c478bd9Sstevel@tonic-gate 		if (ep == NULL) {
605*7c478bd9Sstevel@tonic-gate 			ep = find_elem_mach(&first_list, &keyelem,
606*7c478bd9Sstevel@tonic-gate 			    NO_FOLLOW_LINK);
607*7c478bd9Sstevel@tonic-gate 		}
608*7c478bd9Sstevel@tonic-gate 		/*
609*7c478bd9Sstevel@tonic-gate 		 * Do nothing if this is a hard or symbolic link,
610*7c478bd9Sstevel@tonic-gate 		 * since links don't have this information.
611*7c478bd9Sstevel@tonic-gate 		 *
612*7c478bd9Sstevel@tonic-gate 		 * Assume it's a file on the exception list if it's
613*7c478bd9Sstevel@tonic-gate 		 * not found in the packaging.  Those are root:bin 755.
614*7c478bd9Sstevel@tonic-gate 		 */
615*7c478bd9Sstevel@tonic-gate 		if (ep != NULL &&
616*7c478bd9Sstevel@tonic-gate 		    (ep->file_type == SYM_LINK_T || ep->file_type == LINK_T)) {
617*7c478bd9Sstevel@tonic-gate 			return (0);
618*7c478bd9Sstevel@tonic-gate 		}
619*7c478bd9Sstevel@tonic-gate 		if (!set_group) {
620*7c478bd9Sstevel@tonic-gate 			gid = -1;
621*7c478bd9Sstevel@tonic-gate 		} else if (ep == NULL) {
622*7c478bd9Sstevel@tonic-gate 			gid = 0;
623*7c478bd9Sstevel@tonic-gate 		} else if ((gid = stdfind(ep->group, groupnames)) == -1) {
624*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: %s: group '%s' unknown\n",
625*7c478bd9Sstevel@tonic-gate 			    myname, fname, ep->group);
626*7c478bd9Sstevel@tonic-gate 			return (1);
627*7c478bd9Sstevel@tonic-gate 		}
628*7c478bd9Sstevel@tonic-gate 		if (!set_user) {
629*7c478bd9Sstevel@tonic-gate 			uid = -1;
630*7c478bd9Sstevel@tonic-gate 		} else if (ep == NULL) {
631*7c478bd9Sstevel@tonic-gate 			uid = 2;
632*7c478bd9Sstevel@tonic-gate 		} else if ((uid = stdfind(ep->owner, usernames)) == -1) {
633*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: %s: user '%s' unknown\n",
634*7c478bd9Sstevel@tonic-gate 			    myname, fname, ep->owner);
635*7c478bd9Sstevel@tonic-gate 			return (1);
636*7c478bd9Sstevel@tonic-gate 		}
637*7c478bd9Sstevel@tonic-gate 		if ((set_group && gid != -1 && gid != sbp->st_gid) ||
638*7c478bd9Sstevel@tonic-gate 		    (set_user && uid != -1 && uid != sbp->st_uid)) {
639*7c478bd9Sstevel@tonic-gate 			if (verbose) {
640*7c478bd9Sstevel@tonic-gate 				const char *owner, *group;
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 				owner = ep == NULL ? "root" : ep->owner;
643*7c478bd9Sstevel@tonic-gate 				group = ep == NULL ? "bin" : ep->group;
644*7c478bd9Sstevel@tonic-gate 				if (set_group && set_user) {
645*7c478bd9Sstevel@tonic-gate 					(void) printf("chown %s:%s %s\n",
646*7c478bd9Sstevel@tonic-gate 					    owner, group, fname);
647*7c478bd9Sstevel@tonic-gate 				} else if (set_user) {
648*7c478bd9Sstevel@tonic-gate 					(void) printf("chown %s %s\n", owner,
649*7c478bd9Sstevel@tonic-gate 					    fname);
650*7c478bd9Sstevel@tonic-gate 				} else {
651*7c478bd9Sstevel@tonic-gate 					(void) printf("chgrp %s %s\n", group,
652*7c478bd9Sstevel@tonic-gate 					    fname);
653*7c478bd9Sstevel@tonic-gate 				}
654*7c478bd9Sstevel@tonic-gate 			}
655*7c478bd9Sstevel@tonic-gate 			if (lchown(fname, uid, gid) == -1) {
656*7c478bd9Sstevel@tonic-gate 				perror(fname);
657*7c478bd9Sstevel@tonic-gate 				return (1);
658*7c478bd9Sstevel@tonic-gate 			}
659*7c478bd9Sstevel@tonic-gate 		}
660*7c478bd9Sstevel@tonic-gate 		perm = ep == NULL ? 0755 : ep->perm;
661*7c478bd9Sstevel@tonic-gate 		if (set_perm && ((perm ^ sbp->st_mode) & ~S_IFMT) != 0) {
662*7c478bd9Sstevel@tonic-gate 			if (verbose)
663*7c478bd9Sstevel@tonic-gate 				(void) printf("chmod %lo %s\n", perm, fname);
664*7c478bd9Sstevel@tonic-gate 			if (chmod(fname, perm) == -1) {
665*7c478bd9Sstevel@tonic-gate 				perror(fname);
666*7c478bd9Sstevel@tonic-gate 				return (1);
667*7c478bd9Sstevel@tonic-gate 			}
668*7c478bd9Sstevel@tonic-gate 		}
669*7c478bd9Sstevel@tonic-gate 		return (0);
670*7c478bd9Sstevel@tonic-gate 	case FTW_DNR:
671*7c478bd9Sstevel@tonic-gate 	case FTW_NS:
672*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: %s: permission denied\n",
673*7c478bd9Sstevel@tonic-gate 		    myname, fname);
674*7c478bd9Sstevel@tonic-gate 		return (1);
675*7c478bd9Sstevel@tonic-gate 	case FTW_SL:
676*7c478bd9Sstevel@tonic-gate 	case FTW_SLN:
677*7c478bd9Sstevel@tonic-gate 		return (0);
678*7c478bd9Sstevel@tonic-gate 	default:
679*7c478bd9Sstevel@tonic-gate 		return (1);
680*7c478bd9Sstevel@tonic-gate 	}
681*7c478bd9Sstevel@tonic-gate }
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate int
684*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
685*7c478bd9Sstevel@tonic-gate {
686*7c478bd9Sstevel@tonic-gate 	int	errflg = 0;
687*7c478bd9Sstevel@tonic-gate 	int	i, c;
688*7c478bd9Sstevel@tonic-gate 	int	list_filtered_exceptions = NULL;
689*7c478bd9Sstevel@tonic-gate 	int	n_proto_refs = 0;
690*7c478bd9Sstevel@tonic-gate 	int	n_exception_files = 0;
691*7c478bd9Sstevel@tonic-gate 	char	*proto_refs[MAX_PROTO_REFS];
692*7c478bd9Sstevel@tonic-gate 	char	*exception_files[MAX_EXCEPTION_FILES];
693*7c478bd9Sstevel@tonic-gate 	struct stat st_buf;
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate 	if ((myname = argv[0]) == NULL)
696*7c478bd9Sstevel@tonic-gate 		myname = "protocmp";
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "gupGUPlmsLe:vd:")) != EOF) {
699*7c478bd9Sstevel@tonic-gate 		switch (c) {
700*7c478bd9Sstevel@tonic-gate 		case 's':
701*7c478bd9Sstevel@tonic-gate 			check_sym = 0;
702*7c478bd9Sstevel@tonic-gate 			break;
703*7c478bd9Sstevel@tonic-gate 		case 'm':
704*7c478bd9Sstevel@tonic-gate 			check_majmin = 0;
705*7c478bd9Sstevel@tonic-gate 			break;
706*7c478bd9Sstevel@tonic-gate 		case 'g':
707*7c478bd9Sstevel@tonic-gate 			check_group = 0;
708*7c478bd9Sstevel@tonic-gate 			break;
709*7c478bd9Sstevel@tonic-gate 		case 'G':
710*7c478bd9Sstevel@tonic-gate 			set_group = 1;
711*7c478bd9Sstevel@tonic-gate 			break;
712*7c478bd9Sstevel@tonic-gate 		case 'u':
713*7c478bd9Sstevel@tonic-gate 			check_user = 0;
714*7c478bd9Sstevel@tonic-gate 			break;
715*7c478bd9Sstevel@tonic-gate 		case 'U':
716*7c478bd9Sstevel@tonic-gate 			set_user = 1;
717*7c478bd9Sstevel@tonic-gate 			break;
718*7c478bd9Sstevel@tonic-gate 		case 'l':
719*7c478bd9Sstevel@tonic-gate 			check_link = 0;
720*7c478bd9Sstevel@tonic-gate 			break;
721*7c478bd9Sstevel@tonic-gate 		case 'p':
722*7c478bd9Sstevel@tonic-gate 			check_perm = 0;
723*7c478bd9Sstevel@tonic-gate 			break;
724*7c478bd9Sstevel@tonic-gate 		case 'P':
725*7c478bd9Sstevel@tonic-gate 			set_perm = 1;
726*7c478bd9Sstevel@tonic-gate 			break;
727*7c478bd9Sstevel@tonic-gate 		case 'e':
728*7c478bd9Sstevel@tonic-gate 			if (n_exception_files >= MAX_EXCEPTION_FILES) {
729*7c478bd9Sstevel@tonic-gate 				errflg++;
730*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
731*7c478bd9Sstevel@tonic-gate 				    "Only %d exception files supported\n",
732*7c478bd9Sstevel@tonic-gate 					MAX_EXCEPTION_FILES);
733*7c478bd9Sstevel@tonic-gate 			} else {
734*7c478bd9Sstevel@tonic-gate 				exception_files[n_exception_files++] = optarg;
735*7c478bd9Sstevel@tonic-gate 			}
736*7c478bd9Sstevel@tonic-gate 			break;
737*7c478bd9Sstevel@tonic-gate 		case 'L':
738*7c478bd9Sstevel@tonic-gate 			list_filtered_exceptions++;
739*7c478bd9Sstevel@tonic-gate 			break;
740*7c478bd9Sstevel@tonic-gate 		case 'v':
741*7c478bd9Sstevel@tonic-gate 			verbose++;
742*7c478bd9Sstevel@tonic-gate 			break;
743*7c478bd9Sstevel@tonic-gate 		case 'd':
744*7c478bd9Sstevel@tonic-gate 			if (n_proto_refs >= MAX_PROTO_REFS) {
745*7c478bd9Sstevel@tonic-gate 				errflg++;
746*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
747*7c478bd9Sstevel@tonic-gate 				    "Only %d proto references supported\n",
748*7c478bd9Sstevel@tonic-gate 					MAX_PROTO_REFS);
749*7c478bd9Sstevel@tonic-gate 			} else {
750*7c478bd9Sstevel@tonic-gate 				proto_refs[n_proto_refs++] = optarg;
751*7c478bd9Sstevel@tonic-gate 			}
752*7c478bd9Sstevel@tonic-gate 			break;
753*7c478bd9Sstevel@tonic-gate 		case '?':
754*7c478bd9Sstevel@tonic-gate 		default:
755*7c478bd9Sstevel@tonic-gate 			errflg++;
756*7c478bd9Sstevel@tonic-gate 			break;
757*7c478bd9Sstevel@tonic-gate 		}
758*7c478bd9Sstevel@tonic-gate 	}
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate 	if (argc == optind || n_proto_refs == 0) {
761*7c478bd9Sstevel@tonic-gate 		usage();
762*7c478bd9Sstevel@tonic-gate 		exit(1);
763*7c478bd9Sstevel@tonic-gate 	}
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate 	if (set_group || set_user || set_perm) {
766*7c478bd9Sstevel@tonic-gate 		if (optind != argc - 1) {
767*7c478bd9Sstevel@tonic-gate 			usage();
768*7c478bd9Sstevel@tonic-gate 			exit(1);
769*7c478bd9Sstevel@tonic-gate 		}
770*7c478bd9Sstevel@tonic-gate 		if (stat(argv[optind], &st_buf) == -1) {
771*7c478bd9Sstevel@tonic-gate 			perror(argv[optind]);
772*7c478bd9Sstevel@tonic-gate 			exit(1);
773*7c478bd9Sstevel@tonic-gate 		}
774*7c478bd9Sstevel@tonic-gate 		if (!S_ISDIR(st_buf.st_mode)) {
775*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: %s: not a directory\n",
776*7c478bd9Sstevel@tonic-gate 			    myname, argv[optind]);
777*7c478bd9Sstevel@tonic-gate 			exit(1);
778*7c478bd9Sstevel@tonic-gate 		}
779*7c478bd9Sstevel@tonic-gate 	}
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 	init_list(&first_list, HASH_SIZE);
782*7c478bd9Sstevel@tonic-gate 	init_list(&second_list, HASH_SIZE);
783*7c478bd9Sstevel@tonic-gate 	init_list(&exception_list, HASH_SIZE);
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < n_exception_files; i++) {
786*7c478bd9Sstevel@tonic-gate 		(void) read_in_exceptions(exception_files[i], verbose);
787*7c478bd9Sstevel@tonic-gate 	}
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < n_proto_refs; i++) {
790*7c478bd9Sstevel@tonic-gate 		first_file_name = proto_refs[i];
791*7c478bd9Sstevel@tonic-gate 		(void) read_in_file(first_file_name, &first_list);
792*7c478bd9Sstevel@tonic-gate 	}
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 	if (set_group || set_user || set_perm) {
795*7c478bd9Sstevel@tonic-gate 		if (chdir(argv[optind]) == -1) {
796*7c478bd9Sstevel@tonic-gate 			perror(argv[optind]);
797*7c478bd9Sstevel@tonic-gate 			exit(1);
798*7c478bd9Sstevel@tonic-gate 		}
799*7c478bd9Sstevel@tonic-gate 		i = nftw(".", set_values, MAX_DEPTH, FTW_PHYS|FTW_DEPTH);
800*7c478bd9Sstevel@tonic-gate 		if (i == -1) {
801*7c478bd9Sstevel@tonic-gate 			perror("nftw");
802*7c478bd9Sstevel@tonic-gate 			i = 1;
803*7c478bd9Sstevel@tonic-gate 		}
804*7c478bd9Sstevel@tonic-gate 		exit(i);
805*7c478bd9Sstevel@tonic-gate 	}
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate 	for (i = optind; i < argc; i++) {
808*7c478bd9Sstevel@tonic-gate 		second_file_name = argv[i];
809*7c478bd9Sstevel@tonic-gate 		(void) read_in_file(second_file_name, &second_list);
810*7c478bd9Sstevel@tonic-gate 	}
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 	open_output_files();
813*7c478bd9Sstevel@tonic-gate 
814*7c478bd9Sstevel@tonic-gate 	if (verbose)
815*7c478bd9Sstevel@tonic-gate 		(void) puts("comparing build to packages...");
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 	check_first_vs_second(list_filtered_exceptions);
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 	if (verbose)
820*7c478bd9Sstevel@tonic-gate 		(void) puts("checking over packages...");
821*7c478bd9Sstevel@tonic-gate 	check_second_vs_first(list_filtered_exceptions);
822*7c478bd9Sstevel@tonic-gate 
823*7c478bd9Sstevel@tonic-gate 	close_output_files();
824*7c478bd9Sstevel@tonic-gate 
825*7c478bd9Sstevel@tonic-gate 	print_results();
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate 	clean_up();
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 	return (0);
830*7c478bd9Sstevel@tonic-gate }
831