xref: /onnv-gate/usr/src/tools/protocmp/protocmp.c (revision 3517:79d66aa80b8b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <stdio.h>
300Sstevel@tonic-gate #include <fcntl.h>
310Sstevel@tonic-gate #include <stdlib.h>
320Sstevel@tonic-gate #include <string.h>
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <sys/stat.h>
350Sstevel@tonic-gate #include <dirent.h>
360Sstevel@tonic-gate #include <sys/param.h>
370Sstevel@tonic-gate #include <errno.h>
380Sstevel@tonic-gate #include <unistd.h>
390Sstevel@tonic-gate #include <ftw.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #include "list.h"
420Sstevel@tonic-gate #include "protocmp.h"
430Sstevel@tonic-gate #include "proto_list.h"
440Sstevel@tonic-gate #include "protodir.h"
450Sstevel@tonic-gate #include "exception_list.h"
460Sstevel@tonic-gate #include "stdusers.h"
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #define	MAX_PROTO_REFS			5
490Sstevel@tonic-gate #define	MAX_EXCEPTION_FILES		5
500Sstevel@tonic-gate #define	MAX_DEPTH			50
510Sstevel@tonic-gate 
520Sstevel@tonic-gate /*
530Sstevel@tonic-gate  * default flag values
540Sstevel@tonic-gate  */
550Sstevel@tonic-gate static int check_group = 1;
560Sstevel@tonic-gate static int set_group = 0;
570Sstevel@tonic-gate static int check_user = 1;
580Sstevel@tonic-gate static int set_user = 0;
590Sstevel@tonic-gate static int check_perm = 1;
600Sstevel@tonic-gate static int set_perm = 0;
610Sstevel@tonic-gate static int check_link = 1;
620Sstevel@tonic-gate static int check_sym = 1;
630Sstevel@tonic-gate static int check_majmin = 1;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate static elem_list first_list;
660Sstevel@tonic-gate static char *first_file_name;
670Sstevel@tonic-gate 
680Sstevel@tonic-gate static elem_list second_list;
690Sstevel@tonic-gate static char *second_file_name;
700Sstevel@tonic-gate 
710Sstevel@tonic-gate static FILE *need_add_fp;
720Sstevel@tonic-gate static char *need_add_file;
730Sstevel@tonic-gate static FILE *need_rm_fp;
740Sstevel@tonic-gate static char *need_rm_file;
750Sstevel@tonic-gate static FILE *differ_fp;
760Sstevel@tonic-gate static char *differ_file;
770Sstevel@tonic-gate 
780Sstevel@tonic-gate static char *myname;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate  * default flag values
820Sstevel@tonic-gate  */
830Sstevel@tonic-gate static int verbose = 0;
840Sstevel@tonic-gate 
850Sstevel@tonic-gate static void
usage(void)860Sstevel@tonic-gate usage(void)
870Sstevel@tonic-gate {
880Sstevel@tonic-gate 	(void) fputs("usage: protocmp [-gupGUPlmsLv] "
890Sstevel@tonic-gate 	    "[-e <exception-list> ...] "
900Sstevel@tonic-gate 	    "-d <protolist|pkg dir>\n\t[-d <protolist|pkg dir> ...] "
910Sstevel@tonic-gate 	    "[<protolist|pkg dir>...]|<root>]\n",
920Sstevel@tonic-gate 	    stderr);
930Sstevel@tonic-gate 	(void) fputs("   where:\n", stderr);
940Sstevel@tonic-gate 	(void) fputs("\t-g       : don't compare group\n", stderr);
950Sstevel@tonic-gate 	(void) fputs("\t-u       : don't compare owner\n", stderr);
960Sstevel@tonic-gate 	(void) fputs("\t-p       : don't compare permissions\n", stderr);
970Sstevel@tonic-gate 	(void) fputs("\t-G       : set group\n", stderr);
980Sstevel@tonic-gate 	(void) fputs("\t-U       : set owner\n", stderr);
990Sstevel@tonic-gate 	(void) fputs("\t-P       : set permissions\n", stderr);
1000Sstevel@tonic-gate 	(void) fputs("\t-l       : don't compare link counts\n", stderr);
1010Sstevel@tonic-gate 	(void) fputs("\t-m       : don't compare major/minor numbers\n",
1020Sstevel@tonic-gate 	    stderr);
1030Sstevel@tonic-gate 	(void) fputs("\t-s       : don't compare symlink values\n", stderr);
1040Sstevel@tonic-gate 	(void) fputs("\t-d <protolist|pkg dir>:\n", stderr);
1050Sstevel@tonic-gate 	(void) fputs("\t           proto list or packaging to check\n", stderr);
1060Sstevel@tonic-gate 	(void) fputs("\t-e <file>: exceptions file\n", stderr);
1070Sstevel@tonic-gate 	(void) fputs("\t-L       : list filtered exceptions\n", stderr);
1080Sstevel@tonic-gate 	(void) fputs("\t-v       : verbose output\n", stderr);
1090Sstevel@tonic-gate 	(void) fputs("\n"
1100Sstevel@tonic-gate "If any of the -[GUP] flags are given, then the final argument must be the\n"
1110Sstevel@tonic-gate "proto root directory itself on which to set permissions according to the\n"
1120Sstevel@tonic-gate "packaging data specified via -d options.\n", stderr);
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate static void
open_output_files(void)1170Sstevel@tonic-gate open_output_files(void)
1180Sstevel@tonic-gate {
1190Sstevel@tonic-gate 	if ((need_add_fp =
1200Sstevel@tonic-gate 	    fopen((need_add_file = tempnam(NULL, "add")), "w")) == NULL) {
1210Sstevel@tonic-gate 		perror(need_add_file);
1220Sstevel@tonic-gate 		exit(1);
1230Sstevel@tonic-gate 	}
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	if ((need_rm_fp =
1260Sstevel@tonic-gate 	    fopen((need_rm_file = tempnam(NULL, "rm")), "w")) == NULL) {
1270Sstevel@tonic-gate 		perror(need_rm_file);
1280Sstevel@tonic-gate 		exit(1);
1290Sstevel@tonic-gate 	}
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 	if ((differ_fp =
1320Sstevel@tonic-gate 	    fopen((differ_file = tempnam(NULL, "diff")), "w")) == NULL) {
1330Sstevel@tonic-gate 		perror(differ_file);
1340Sstevel@tonic-gate 		exit(1);
1350Sstevel@tonic-gate 	}
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate static void
close_output_files(void)1390Sstevel@tonic-gate close_output_files(void)
1400Sstevel@tonic-gate {
1410Sstevel@tonic-gate 	(void) fclose(need_add_fp);
1420Sstevel@tonic-gate 	(void) fclose(need_rm_fp);
1430Sstevel@tonic-gate 	(void) fclose(differ_fp);
1440Sstevel@tonic-gate }
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate static void
print_file(char * file)1470Sstevel@tonic-gate print_file(char *file)
1480Sstevel@tonic-gate {
1490Sstevel@tonic-gate 	FILE	*fp;
1500Sstevel@tonic-gate 	int	count;
1510Sstevel@tonic-gate 	char	buff[BUF_SIZE];
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	if ((fp = fopen(file, "r")) == NULL) {
1540Sstevel@tonic-gate 		perror(need_add_file);
1550Sstevel@tonic-gate 	}
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	while (count = fread(buff, sizeof (char), BUF_SIZE, fp))
1580Sstevel@tonic-gate 		(void) fwrite(buff, sizeof (char), count, stdout);
1590Sstevel@tonic-gate 	(void) fclose(fp);
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate static void
print_header(void)1630Sstevel@tonic-gate print_header(void)
1640Sstevel@tonic-gate {
1650Sstevel@tonic-gate 	(void) printf("%c %-30s %-20s %-4s %-5s %-5s %-5s %-2s %2s %2s %-9s\n",
1660Sstevel@tonic-gate 	    'T', "File Name", "Reloc/Sym name", "perm", "owner", "group",
1670Sstevel@tonic-gate 	    "inode", "lnk", "maj", "min", "package(s)");
1680Sstevel@tonic-gate 	(void) puts("-------------------------------------------------------"
1690Sstevel@tonic-gate 	    "-----------------------------------------------------");
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate static void
print_results(void)1730Sstevel@tonic-gate print_results(void)
1740Sstevel@tonic-gate {
1750Sstevel@tonic-gate 	(void) puts("*******************************************************");
1760Sstevel@tonic-gate 	(void) puts("*");
1770Sstevel@tonic-gate 	(void) printf("* Entries found in %s, but not found in %s\n",
1780Sstevel@tonic-gate 	    first_file_name, second_file_name);
1790Sstevel@tonic-gate 	(void) puts("*");
1800Sstevel@tonic-gate 	(void) puts("*******************************************************");
1810Sstevel@tonic-gate 	print_header();
1820Sstevel@tonic-gate 	print_file(need_add_file);
1830Sstevel@tonic-gate 	(void) puts("*******************************************************");
1840Sstevel@tonic-gate 	(void) puts("*");
1850Sstevel@tonic-gate 	(void) printf("* Entries found in %s, but not found in %s\n",
1860Sstevel@tonic-gate 	    second_file_name, first_file_name);
1870Sstevel@tonic-gate 	(void) puts("*");
1880Sstevel@tonic-gate 	(void) puts("*******************************************************");
1890Sstevel@tonic-gate 	print_header();
1900Sstevel@tonic-gate 	print_file(need_rm_file);
1910Sstevel@tonic-gate 	(void) puts("*******************************************************");
1920Sstevel@tonic-gate 	(void) puts("*");
1930Sstevel@tonic-gate 	(void) printf("* Entries that differ between %s and %s\n",
1940Sstevel@tonic-gate 	    first_file_name, second_file_name);
1950Sstevel@tonic-gate 	(void) puts("*");
1960Sstevel@tonic-gate 	(void) printf("* filea == %s\n", first_file_name);
1970Sstevel@tonic-gate 	(void) printf("* fileb == %s\n", second_file_name);
1980Sstevel@tonic-gate 	(void) puts("*");
1990Sstevel@tonic-gate 	(void) puts("*******************************************************");
2000Sstevel@tonic-gate 	(void) fputs("Unit   ", stdout);
2010Sstevel@tonic-gate 	print_header();
2020Sstevel@tonic-gate 	print_file(differ_file);
2030Sstevel@tonic-gate }
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate static void
clean_up(void)2060Sstevel@tonic-gate clean_up(void)
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate 	(void) unlink(need_add_file);
2090Sstevel@tonic-gate 	(void) unlink(need_rm_file);
2100Sstevel@tonic-gate 	(void) unlink(differ_file);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate /*
2140Sstevel@tonic-gate  * elem_compare(a,b)
2150Sstevel@tonic-gate  *
2160Sstevel@tonic-gate  * Args:
2170Sstevel@tonic-gate  *	a 		- element a
2180Sstevel@tonic-gate  *	b 		- element b
2190Sstevel@tonic-gate  *	different_types -
2200Sstevel@tonic-gate  *		value = 0  -> comparing two elements of same
2210Sstevel@tonic-gate  *			      type (eg: protodir elem vs. protodir elem).
2220Sstevel@tonic-gate  *		value != 0 -> comparing two elements of different type
2230Sstevel@tonic-gate  *			      (eg: protodir elem vs. protolist elem).
2240Sstevel@tonic-gate  *
2250Sstevel@tonic-gate  * Returns:
2260Sstevel@tonic-gate  *	0   - elements are identical
2270Sstevel@tonic-gate  *	>0  - elements differ
2280Sstevel@tonic-gate  *	      check flags to see which fields differ.
2290Sstevel@tonic-gate  */
2300Sstevel@tonic-gate static int
elem_compare(elem * a,elem * b,int different_types)2310Sstevel@tonic-gate elem_compare(elem *a, elem *b, int different_types)
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate 	int	res = 0;
2340Sstevel@tonic-gate 	elem	*i, *j;
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	/*
2370Sstevel@tonic-gate 	 * if these are hard links to other files - those are the
2380Sstevel@tonic-gate 	 * files that should be compared.
2390Sstevel@tonic-gate 	 */
2400Sstevel@tonic-gate 	i = a->link_parent ? a->link_parent : a;
2410Sstevel@tonic-gate 	j = b->link_parent ? b->link_parent : b;
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	/*
2440Sstevel@tonic-gate 	 * We do not compare inodes - they always differ.
2450Sstevel@tonic-gate 	 * We do not compare names because we assume that was
2460Sstevel@tonic-gate 	 * checked before.
2470Sstevel@tonic-gate 	 */
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	/*
2500Sstevel@tonic-gate 	 * Special rules for comparison:
2510Sstevel@tonic-gate 	 *
2520Sstevel@tonic-gate 	 * 1) if directory - ignore ref_cnt.
2530Sstevel@tonic-gate 	 * 2) if sym_link - only check file_type & symlink
2540Sstevel@tonic-gate 	 * 3) elem type of FILE_T, EDIT_T, & VOLATILE_T are equivilant when
2550Sstevel@tonic-gate 	 *    comparing a protodir entry to a protolist entry.
2560Sstevel@tonic-gate 	 */
2570Sstevel@tonic-gate 	if (i->file_type != j->file_type) {
2580Sstevel@tonic-gate 		if (different_types) {
2590Sstevel@tonic-gate 			/*
2600Sstevel@tonic-gate 			 * Check to see if filetypes are FILE_T vs.
2610Sstevel@tonic-gate 			 * EDIT_T/VOLATILE_T/LINK_T comparisons.
2620Sstevel@tonic-gate 			 */
2630Sstevel@tonic-gate 			if ((i->file_type == FILE_T) &&
2640Sstevel@tonic-gate 			    ((j->file_type == EDIT_T) ||
2650Sstevel@tonic-gate 			    (j->file_type == VOLATILE_T) ||
2660Sstevel@tonic-gate 			    (j->file_type == LINK_T))) {
2670Sstevel@tonic-gate 				/*EMPTY*/
2680Sstevel@tonic-gate 			} else if ((j->file_type == FILE_T) &&
2690Sstevel@tonic-gate 			    ((i->file_type == EDIT_T) ||
2700Sstevel@tonic-gate 			    (i->file_type == VOLATILE_T) ||
2710Sstevel@tonic-gate 			    (i->file_type == LINK_T))) {
2720Sstevel@tonic-gate 				/*EMPTY*/
2730Sstevel@tonic-gate 			} else
2740Sstevel@tonic-gate 				res |= TYPE_F;
2750Sstevel@tonic-gate 		} else
2760Sstevel@tonic-gate 			res |= TYPE_F;
2770Sstevel@tonic-gate 	}
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	/*
2800Sstevel@tonic-gate 	 * if symlink - check the symlink value and then
2810Sstevel@tonic-gate 	 * return.  symlink is the only field of concern
2820Sstevel@tonic-gate 	 * in SYMLINKS.
2830Sstevel@tonic-gate 	 */
2840Sstevel@tonic-gate 	if (check_sym && ((res == 0) && (i->file_type == SYM_LINK_T))) {
2850Sstevel@tonic-gate 		if ((!i->symsrc) || (!j->symsrc))
2860Sstevel@tonic-gate 			res |= SYM_F;
2870Sstevel@tonic-gate 		else {
2880Sstevel@tonic-gate 			/*
2890Sstevel@tonic-gate 			 * if either symlink starts with a './' strip it off,
290*3517Smp204432 			 * its irrelevant.
2910Sstevel@tonic-gate 			 */
2920Sstevel@tonic-gate 			if ((i->symsrc[0] == '.') && (i->symsrc[1] == '/'))
2930Sstevel@tonic-gate 				i->symsrc += 2;
2940Sstevel@tonic-gate 			if ((j->symsrc[0] == '.') && (j->symsrc[1] == '/'))
2950Sstevel@tonic-gate 				j->symsrc += 2;
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 			if (strncmp(i->symsrc, j->symsrc, MAXNAME) != 0)
2980Sstevel@tonic-gate 				res |= SYM_F;
2990Sstevel@tonic-gate 		}
3000Sstevel@tonic-gate 		return (res);
3010Sstevel@tonic-gate 	}
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	if ((i->file_type != DIR_T) && check_link &&
3040Sstevel@tonic-gate 	    (i->ref_cnt != j->ref_cnt))
3050Sstevel@tonic-gate 		res |= REF_F;
3060Sstevel@tonic-gate 	if (check_user && (strncmp(i->owner, j->owner, TYPESIZE) != 0))
3070Sstevel@tonic-gate 		res |= OWNER_F;
3080Sstevel@tonic-gate 	if (check_group && (strncmp(i->group, j->group, TYPESIZE) != 0))
3090Sstevel@tonic-gate 		res |= GROUP_F;
3100Sstevel@tonic-gate 	if (check_perm && (i->perm != j->perm))
3110Sstevel@tonic-gate 		res |= PERM_F;
3120Sstevel@tonic-gate 	if (check_majmin && ((i->major != j->major) || (i->minor != j->minor)))
3130Sstevel@tonic-gate 		res |= MAJMIN_F;
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	return (res);
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate static void
print_elem(FILE * fp,elem * e)3190Sstevel@tonic-gate print_elem(FILE *fp, elem *e)
3200Sstevel@tonic-gate {
3210Sstevel@tonic-gate 	elem		p;
3220Sstevel@tonic-gate 	pkg_list	*l;
3230Sstevel@tonic-gate 	char		maj[TYPESIZE], min[TYPESIZE];
3240Sstevel@tonic-gate 	char		perm[12], ref_cnt[12];
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	/*
3270Sstevel@tonic-gate 	 * If this is a LINK to another file, then adopt
3280Sstevel@tonic-gate 	 * the permissions of that file.
3290Sstevel@tonic-gate 	 */
3300Sstevel@tonic-gate 	if (e->link_parent) {
3310Sstevel@tonic-gate 		p = *((elem *)e->link_parent);
3320Sstevel@tonic-gate 		(void) strcpy(p.name, e->name);
3330Sstevel@tonic-gate 		p.symsrc = e->symsrc;
3340Sstevel@tonic-gate 		p.file_type = e->file_type;
3350Sstevel@tonic-gate 		e = &p;
3360Sstevel@tonic-gate 	}
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	if (!check_majmin || e->major == -1) {
3390Sstevel@tonic-gate 		maj[0] = '-';
3400Sstevel@tonic-gate 		maj[1] = '\0';
3410Sstevel@tonic-gate 	} else {
3420Sstevel@tonic-gate 		(void) sprintf(maj, "%d", e->major);
3430Sstevel@tonic-gate 	}
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	if (!check_majmin || e->minor == -1) {
3460Sstevel@tonic-gate 		min[0] = '-';
3470Sstevel@tonic-gate 		min[1] = '\0';
3480Sstevel@tonic-gate 	} else {
3490Sstevel@tonic-gate 		(void) sprintf(min, "%d", e->minor);
3500Sstevel@tonic-gate 	}
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	if (!check_perm) {
3530Sstevel@tonic-gate 		perm[0] = '-';
3540Sstevel@tonic-gate 		perm[1] = '\0';
3550Sstevel@tonic-gate 	} else {
3560Sstevel@tonic-gate 		(void) snprintf(perm, sizeof (perm), "%o", e->perm);
3570Sstevel@tonic-gate 	}
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	if (!check_link) {
3600Sstevel@tonic-gate 		ref_cnt[0] = '-';
3610Sstevel@tonic-gate 		ref_cnt[1] = '\0';
3620Sstevel@tonic-gate 	} else {
3630Sstevel@tonic-gate 		(void) snprintf(ref_cnt, sizeof (ref_cnt), "%d", e->ref_cnt);
3640Sstevel@tonic-gate 	}
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	(void) fprintf(fp, "%c %-30s %-20s %4s %-5s %-5s %6d %2s %2s %2s   ",
3670Sstevel@tonic-gate 	    e->file_type, e->name,
3680Sstevel@tonic-gate 	    check_sym && e->symsrc != NULL ? e->symsrc : "-", perm,
3690Sstevel@tonic-gate 	    check_user ? e->owner : "-",
3700Sstevel@tonic-gate 	    check_group ? e->group : "-",
3710Sstevel@tonic-gate 	    e->inode, ref_cnt, maj, min);
3720Sstevel@tonic-gate 	/*
3730Sstevel@tonic-gate 	 * dump package list - if any.
3740Sstevel@tonic-gate 	 */
3750Sstevel@tonic-gate 	if (!e->pkgs)
3760Sstevel@tonic-gate 		(void) fputs(" proto", fp);
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	for (l = e->pkgs; l; l = l->next) {
3790Sstevel@tonic-gate 		(void) fputc(' ', fp);
3800Sstevel@tonic-gate 		(void) fputs(l->pkg_name, fp);
3810Sstevel@tonic-gate 	}
3820Sstevel@tonic-gate 	(void) fputc('\n', fp);
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate /*
3860Sstevel@tonic-gate  * do_compare(a,b)
3870Sstevel@tonic-gate  *
3880Sstevel@tonic-gate  * Args:
3890Sstevel@tonic-gate  *	different_types - see elem_compare() for explanation.
3900Sstevel@tonic-gate  */
3910Sstevel@tonic-gate static void
do_compare(elem * a,elem * b,int different_types)3920Sstevel@tonic-gate do_compare(elem *a, elem *b, int different_types)
3930Sstevel@tonic-gate {
3940Sstevel@tonic-gate 	int	rc;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	if ((rc = elem_compare(a, b, different_types)) != 0) {
3970Sstevel@tonic-gate 		(void) fputs("filea: ", differ_fp);
3980Sstevel@tonic-gate 		print_elem(differ_fp, a);
3990Sstevel@tonic-gate 		(void) fputs("fileb: ", differ_fp);
4000Sstevel@tonic-gate 		print_elem(differ_fp, b);
4010Sstevel@tonic-gate 		(void) fputs("    differ: ", differ_fp);
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 		if (rc & SYM_F)
4040Sstevel@tonic-gate 			(void) fputs("symlink", differ_fp);
4050Sstevel@tonic-gate 		if (rc & PERM_F)
4060Sstevel@tonic-gate 			(void) fputs("perm ", differ_fp);
4070Sstevel@tonic-gate 		if (rc & REF_F)
4080Sstevel@tonic-gate 			(void) fputs("ref_cnt ", differ_fp);
4090Sstevel@tonic-gate 		if (rc & TYPE_F)
4100Sstevel@tonic-gate 			(void) fputs("file_type ", differ_fp);
4110Sstevel@tonic-gate 		if (rc & OWNER_F)
4120Sstevel@tonic-gate 			(void) fputs("owner ", differ_fp);
4130Sstevel@tonic-gate 		if (rc & GROUP_F)
4140Sstevel@tonic-gate 			(void) fputs("group ", differ_fp);
4150Sstevel@tonic-gate 		if (rc & MAJMIN_F)
4160Sstevel@tonic-gate 			(void) fputs("major/minor ", differ_fp);
4170Sstevel@tonic-gate 		(void) putc('\n', differ_fp);
4180Sstevel@tonic-gate 		(void) putc('\n', differ_fp);
4190Sstevel@tonic-gate 	}
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate static void
check_second_vs_first(int verbose)4230Sstevel@tonic-gate check_second_vs_first(int verbose)
4240Sstevel@tonic-gate {
4250Sstevel@tonic-gate 	int	i;
4260Sstevel@tonic-gate 	elem	*cur;
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	for (i = 0; i < second_list.num_of_buckets; i++) {
4290Sstevel@tonic-gate 		for (cur = second_list.list[i]; cur; cur = cur->next) {
4300Sstevel@tonic-gate 			if (!(cur->flag & VISITED_F)) {
4310Sstevel@tonic-gate 				if ((first_list.type != second_list.type) &&
4320Sstevel@tonic-gate 				    find_elem(&exception_list, cur,
4330Sstevel@tonic-gate 				    FOLLOW_LINK)) {
4340Sstevel@tonic-gate 					/*
4350Sstevel@tonic-gate 					 * this entry is filtered, we don't
4360Sstevel@tonic-gate 					 * need to do any more processing.
4370Sstevel@tonic-gate 					 */
4380Sstevel@tonic-gate 					if (verbose) {
4390Sstevel@tonic-gate 						(void) printf(
4400Sstevel@tonic-gate 						    "Filtered: Need Deletion "
4410Sstevel@tonic-gate 						    "of:\n\t");
4420Sstevel@tonic-gate 						print_elem(stdout, cur);
4430Sstevel@tonic-gate 					}
4440Sstevel@tonic-gate 					continue;
4450Sstevel@tonic-gate 				}
4460Sstevel@tonic-gate 				/*
4470Sstevel@tonic-gate 				 * It is possible for arch specific files to be
4480Sstevel@tonic-gate 				 * found in a protodir but listed as arch
4490Sstevel@tonic-gate 				 * independent in a protolist file.  If this is
4500Sstevel@tonic-gate 				 * a protodir vs. a protolist we will make
4510Sstevel@tonic-gate 				 * that check.
4520Sstevel@tonic-gate 				 */
4530Sstevel@tonic-gate 				if ((second_list.type == PROTODIR_LIST) &&
4540Sstevel@tonic-gate 				    (cur->arch != P_ISA) &&
4550Sstevel@tonic-gate 				    (first_list.type != PROTODIR_LIST)) {
4560Sstevel@tonic-gate 					/*
4570Sstevel@tonic-gate 					 * do a lookup for same file, but as
4580Sstevel@tonic-gate 					 * type ISA.
4590Sstevel@tonic-gate 					 */
4600Sstevel@tonic-gate 					elem	*e;
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 					e = find_elem_isa(&first_list, cur,
4630Sstevel@tonic-gate 					    NO_FOLLOW_LINK);
4640Sstevel@tonic-gate 					if (e) {
4650Sstevel@tonic-gate 						do_compare(e, cur,
4660Sstevel@tonic-gate 						    first_list.type -
4670Sstevel@tonic-gate 						    second_list.type);
4680Sstevel@tonic-gate 						continue;
4690Sstevel@tonic-gate 					}
4700Sstevel@tonic-gate 				}
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 				print_elem(need_rm_fp, cur);
4730Sstevel@tonic-gate 			}
4740Sstevel@tonic-gate 		}
4750Sstevel@tonic-gate 	}
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate static void
check_first_vs_second(int verbose)4790Sstevel@tonic-gate check_first_vs_second(int verbose)
4800Sstevel@tonic-gate {
4810Sstevel@tonic-gate 	int	i;
4820Sstevel@tonic-gate 	elem	*e;
4830Sstevel@tonic-gate 	elem	*cur;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	for (i = 0; i < first_list.num_of_buckets; i++) {
4860Sstevel@tonic-gate 		for (cur = first_list.list[i]; cur; cur = cur->next) {
4870Sstevel@tonic-gate 			if ((first_list.type != second_list.type) &&
4880Sstevel@tonic-gate 			    find_elem(&exception_list, cur, FOLLOW_LINK)) {
4890Sstevel@tonic-gate 				/*
4900Sstevel@tonic-gate 				 * this entry is filtered, we don't need to do
4910Sstevel@tonic-gate 				 * any more processing.
4920Sstevel@tonic-gate 				 */
4930Sstevel@tonic-gate 				if (verbose) {
4940Sstevel@tonic-gate 					(void) printf("Filtered: Need "
4950Sstevel@tonic-gate 					    "Addition of:\n\t");
4960Sstevel@tonic-gate 					print_elem(stdout, cur);
4970Sstevel@tonic-gate 				}
4980Sstevel@tonic-gate 				continue;
4990Sstevel@tonic-gate 			}
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 			/*
5020Sstevel@tonic-gate 			 * Search package database for file.
5030Sstevel@tonic-gate 			 */
5040Sstevel@tonic-gate 			e = find_elem(&second_list, cur, NO_FOLLOW_LINK);
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 			/*
5070Sstevel@tonic-gate 			 * It is possible for arch specific files to be found
5080Sstevel@tonic-gate 			 * in a protodir but listed as arch independent in a
5090Sstevel@tonic-gate 			 * protolist file.  If this is a protodir vs. a
5100Sstevel@tonic-gate 			 * protolist we will make that check.
5110Sstevel@tonic-gate 			 */
5120Sstevel@tonic-gate 			if (!e && (first_list.type == PROTODIR_LIST) &&
5130Sstevel@tonic-gate 			    (cur->arch != P_ISA) &&
5140Sstevel@tonic-gate 			    (second_list.type != PROTODIR_LIST)) {
5150Sstevel@tonic-gate 				/*
5160Sstevel@tonic-gate 				 * do a lookup for same file, but as type ISA.
5170Sstevel@tonic-gate 				 */
5180Sstevel@tonic-gate 				e = find_elem_isa(&second_list, cur,
5190Sstevel@tonic-gate 				    NO_FOLLOW_LINK);
5200Sstevel@tonic-gate 			}
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 			if (!e && (first_list.type != PROTODIR_LIST) &&
5230Sstevel@tonic-gate 			    (cur->arch == P_ISA) &&
5240Sstevel@tonic-gate 			    (second_list.type == PROTODIR_LIST)) {
5250Sstevel@tonic-gate 				/*
5260Sstevel@tonic-gate 				 * do a lookup for same file, but as any
5270Sstevel@tonic-gate 				 * type but ISA
5280Sstevel@tonic-gate 				 */
5290Sstevel@tonic-gate 				e = find_elem_mach(&second_list, cur,
5300Sstevel@tonic-gate 				    NO_FOLLOW_LINK);
5310Sstevel@tonic-gate 			}
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 			if (e == NULL)
5340Sstevel@tonic-gate 				print_elem(need_add_fp, cur);
5350Sstevel@tonic-gate 			else {
5360Sstevel@tonic-gate 				do_compare(cur, e,
5370Sstevel@tonic-gate 				    first_list.type - second_list.type);
5380Sstevel@tonic-gate 				e->flag |= VISITED_F;
5390Sstevel@tonic-gate 			}
5400Sstevel@tonic-gate 		}
5410Sstevel@tonic-gate 	}
5420Sstevel@tonic-gate }
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate static int
read_in_file(const char * file_name,elem_list * list)5450Sstevel@tonic-gate read_in_file(const char *file_name, elem_list *list)
5460Sstevel@tonic-gate {
5470Sstevel@tonic-gate 	struct stat	st_buf;
5480Sstevel@tonic-gate 	int		count = 0;
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	if (stat(file_name, &st_buf) == 0) {
5510Sstevel@tonic-gate 		if (S_ISREG(st_buf.st_mode)) {
5520Sstevel@tonic-gate 			if (verbose) {
5530Sstevel@tonic-gate 				(void) printf("file(%s): trying to process "
5540Sstevel@tonic-gate 				    "as protolist...\n", file_name);
5550Sstevel@tonic-gate 			}
5560Sstevel@tonic-gate 			count = read_in_protolist(file_name, list, verbose);
5570Sstevel@tonic-gate 		} else if (S_ISDIR(st_buf.st_mode)) {
5580Sstevel@tonic-gate 			if (verbose)
5590Sstevel@tonic-gate 				(void) printf("directory(%s): trying to "
5600Sstevel@tonic-gate 				    "process as protodir...\n", file_name);
5610Sstevel@tonic-gate 			count = read_in_protodir(file_name, list, verbose);
5620Sstevel@tonic-gate 		} else {
5630Sstevel@tonic-gate 			(void) fprintf(stderr,
5640Sstevel@tonic-gate 			    "%s not a file or a directory.\n", file_name);
5650Sstevel@tonic-gate 			usage();
5660Sstevel@tonic-gate 			exit(1);
5670Sstevel@tonic-gate 		}
5680Sstevel@tonic-gate 	} else {
5690Sstevel@tonic-gate 		perror(file_name);
5700Sstevel@tonic-gate 		usage();
5710Sstevel@tonic-gate 		exit(1);
5720Sstevel@tonic-gate 	}
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	return (count);
5750Sstevel@tonic-gate }
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate /* ARGSUSED */
5780Sstevel@tonic-gate static int
set_values(const char * fname,const struct stat * sbp,int otype,struct FTW * ftw)5790Sstevel@tonic-gate set_values(const char *fname, const struct stat *sbp, int otype,
5800Sstevel@tonic-gate     struct FTW *ftw)
5810Sstevel@tonic-gate {
5820Sstevel@tonic-gate 	elem *ep;
5830Sstevel@tonic-gate 	uid_t uid;
5840Sstevel@tonic-gate 	gid_t gid;
5850Sstevel@tonic-gate 	elem keyelem;
5860Sstevel@tonic-gate 	mode_t perm;
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	if (fname[0] == '\0' || fname[1] == '\0' || fname[2] == '\0')
5890Sstevel@tonic-gate 		return (0);
5900Sstevel@tonic-gate 	/* skip leading "./" */
5910Sstevel@tonic-gate 	fname += 2;
5920Sstevel@tonic-gate 	switch (otype) {
5930Sstevel@tonic-gate 	case FTW_F:
5940Sstevel@tonic-gate 	case FTW_D:
5950Sstevel@tonic-gate 	case FTW_DP:
5960Sstevel@tonic-gate 		if (strlcpy(keyelem.name, fname, sizeof (keyelem.name)) >=
5970Sstevel@tonic-gate 		    sizeof (keyelem.name)) {
5980Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: %s: name too long\n",
5990Sstevel@tonic-gate 			    myname, fname);
6000Sstevel@tonic-gate 			return (1);
6010Sstevel@tonic-gate 		}
6020Sstevel@tonic-gate 		keyelem.arch = P_ISA;
6030Sstevel@tonic-gate 		ep = find_elem(&first_list, &keyelem, NO_FOLLOW_LINK);
6040Sstevel@tonic-gate 		if (ep == NULL) {
6050Sstevel@tonic-gate 			ep = find_elem_mach(&first_list, &keyelem,
6060Sstevel@tonic-gate 			    NO_FOLLOW_LINK);
6070Sstevel@tonic-gate 		}
6080Sstevel@tonic-gate 		/*
6090Sstevel@tonic-gate 		 * Do nothing if this is a hard or symbolic link,
6100Sstevel@tonic-gate 		 * since links don't have this information.
6110Sstevel@tonic-gate 		 *
6120Sstevel@tonic-gate 		 * Assume it's a file on the exception list if it's
6130Sstevel@tonic-gate 		 * not found in the packaging.  Those are root:bin 755.
6140Sstevel@tonic-gate 		 */
6150Sstevel@tonic-gate 		if (ep != NULL &&
6160Sstevel@tonic-gate 		    (ep->file_type == SYM_LINK_T || ep->file_type == LINK_T)) {
6170Sstevel@tonic-gate 			return (0);
6180Sstevel@tonic-gate 		}
6190Sstevel@tonic-gate 		if (!set_group) {
6200Sstevel@tonic-gate 			gid = -1;
6210Sstevel@tonic-gate 		} else if (ep == NULL) {
6220Sstevel@tonic-gate 			gid = 0;
6230Sstevel@tonic-gate 		} else if ((gid = stdfind(ep->group, groupnames)) == -1) {
6240Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: %s: group '%s' unknown\n",
6250Sstevel@tonic-gate 			    myname, fname, ep->group);
6260Sstevel@tonic-gate 			return (1);
6270Sstevel@tonic-gate 		}
6280Sstevel@tonic-gate 		if (!set_user) {
6290Sstevel@tonic-gate 			uid = -1;
6300Sstevel@tonic-gate 		} else if (ep == NULL) {
6310Sstevel@tonic-gate 			uid = 2;
6320Sstevel@tonic-gate 		} else if ((uid = stdfind(ep->owner, usernames)) == -1) {
6330Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: %s: user '%s' unknown\n",
6340Sstevel@tonic-gate 			    myname, fname, ep->owner);
6350Sstevel@tonic-gate 			return (1);
6360Sstevel@tonic-gate 		}
6370Sstevel@tonic-gate 		if ((set_group && gid != -1 && gid != sbp->st_gid) ||
6380Sstevel@tonic-gate 		    (set_user && uid != -1 && uid != sbp->st_uid)) {
6390Sstevel@tonic-gate 			if (verbose) {
6400Sstevel@tonic-gate 				const char *owner, *group;
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 				owner = ep == NULL ? "root" : ep->owner;
6430Sstevel@tonic-gate 				group = ep == NULL ? "bin" : ep->group;
6440Sstevel@tonic-gate 				if (set_group && set_user) {
6450Sstevel@tonic-gate 					(void) printf("chown %s:%s %s\n",
6460Sstevel@tonic-gate 					    owner, group, fname);
6470Sstevel@tonic-gate 				} else if (set_user) {
6480Sstevel@tonic-gate 					(void) printf("chown %s %s\n", owner,
6490Sstevel@tonic-gate 					    fname);
6500Sstevel@tonic-gate 				} else {
6510Sstevel@tonic-gate 					(void) printf("chgrp %s %s\n", group,
6520Sstevel@tonic-gate 					    fname);
6530Sstevel@tonic-gate 				}
6540Sstevel@tonic-gate 			}
6550Sstevel@tonic-gate 			if (lchown(fname, uid, gid) == -1) {
6560Sstevel@tonic-gate 				perror(fname);
6570Sstevel@tonic-gate 				return (1);
6580Sstevel@tonic-gate 			}
6590Sstevel@tonic-gate 		}
6600Sstevel@tonic-gate 		perm = ep == NULL ? 0755 : ep->perm;
6610Sstevel@tonic-gate 		if (set_perm && ((perm ^ sbp->st_mode) & ~S_IFMT) != 0) {
6620Sstevel@tonic-gate 			if (verbose)
6630Sstevel@tonic-gate 				(void) printf("chmod %lo %s\n", perm, fname);
6640Sstevel@tonic-gate 			if (chmod(fname, perm) == -1) {
6650Sstevel@tonic-gate 				perror(fname);
6660Sstevel@tonic-gate 				return (1);
6670Sstevel@tonic-gate 			}
6680Sstevel@tonic-gate 		}
6690Sstevel@tonic-gate 		return (0);
6700Sstevel@tonic-gate 	case FTW_DNR:
6710Sstevel@tonic-gate 	case FTW_NS:
6720Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: %s: permission denied\n",
6730Sstevel@tonic-gate 		    myname, fname);
6740Sstevel@tonic-gate 		return (1);
6750Sstevel@tonic-gate 	case FTW_SL:
6760Sstevel@tonic-gate 	case FTW_SLN:
6770Sstevel@tonic-gate 		return (0);
6780Sstevel@tonic-gate 	default:
6790Sstevel@tonic-gate 		return (1);
6800Sstevel@tonic-gate 	}
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate int
main(int argc,char ** argv)6840Sstevel@tonic-gate main(int argc, char **argv)
6850Sstevel@tonic-gate {
6860Sstevel@tonic-gate 	int	errflg = 0;
6870Sstevel@tonic-gate 	int	i, c;
6880Sstevel@tonic-gate 	int	list_filtered_exceptions = NULL;
6890Sstevel@tonic-gate 	int	n_proto_refs = 0;
6900Sstevel@tonic-gate 	int	n_exception_files = 0;
6910Sstevel@tonic-gate 	char	*proto_refs[MAX_PROTO_REFS];
6920Sstevel@tonic-gate 	char	*exception_files[MAX_EXCEPTION_FILES];
6930Sstevel@tonic-gate 	struct stat st_buf;
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	if ((myname = argv[0]) == NULL)
6960Sstevel@tonic-gate 		myname = "protocmp";
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "gupGUPlmsLe:vd:")) != EOF) {
6990Sstevel@tonic-gate 		switch (c) {
7000Sstevel@tonic-gate 		case 's':
7010Sstevel@tonic-gate 			check_sym = 0;
7020Sstevel@tonic-gate 			break;
7030Sstevel@tonic-gate 		case 'm':
7040Sstevel@tonic-gate 			check_majmin = 0;
7050Sstevel@tonic-gate 			break;
7060Sstevel@tonic-gate 		case 'g':
7070Sstevel@tonic-gate 			check_group = 0;
7080Sstevel@tonic-gate 			break;
7090Sstevel@tonic-gate 		case 'G':
7100Sstevel@tonic-gate 			set_group = 1;
7110Sstevel@tonic-gate 			break;
7120Sstevel@tonic-gate 		case 'u':
7130Sstevel@tonic-gate 			check_user = 0;
7140Sstevel@tonic-gate 			break;
7150Sstevel@tonic-gate 		case 'U':
7160Sstevel@tonic-gate 			set_user = 1;
7170Sstevel@tonic-gate 			break;
7180Sstevel@tonic-gate 		case 'l':
7190Sstevel@tonic-gate 			check_link = 0;
7200Sstevel@tonic-gate 			break;
7210Sstevel@tonic-gate 		case 'p':
7220Sstevel@tonic-gate 			check_perm = 0;
7230Sstevel@tonic-gate 			break;
7240Sstevel@tonic-gate 		case 'P':
7250Sstevel@tonic-gate 			set_perm = 1;
7260Sstevel@tonic-gate 			break;
7270Sstevel@tonic-gate 		case 'e':
7280Sstevel@tonic-gate 			if (n_exception_files >= MAX_EXCEPTION_FILES) {
7290Sstevel@tonic-gate 				errflg++;
7300Sstevel@tonic-gate 				(void) fprintf(stderr,
7310Sstevel@tonic-gate 				    "Only %d exception files supported\n",
7320Sstevel@tonic-gate 					MAX_EXCEPTION_FILES);
7330Sstevel@tonic-gate 			} else {
7340Sstevel@tonic-gate 				exception_files[n_exception_files++] = optarg;
7350Sstevel@tonic-gate 			}
7360Sstevel@tonic-gate 			break;
7370Sstevel@tonic-gate 		case 'L':
7380Sstevel@tonic-gate 			list_filtered_exceptions++;
7390Sstevel@tonic-gate 			break;
7400Sstevel@tonic-gate 		case 'v':
7410Sstevel@tonic-gate 			verbose++;
7420Sstevel@tonic-gate 			break;
7430Sstevel@tonic-gate 		case 'd':
7440Sstevel@tonic-gate 			if (n_proto_refs >= MAX_PROTO_REFS) {
7450Sstevel@tonic-gate 				errflg++;
7460Sstevel@tonic-gate 				(void) fprintf(stderr,
7470Sstevel@tonic-gate 				    "Only %d proto references supported\n",
7480Sstevel@tonic-gate 					MAX_PROTO_REFS);
7490Sstevel@tonic-gate 			} else {
7500Sstevel@tonic-gate 				proto_refs[n_proto_refs++] = optarg;
7510Sstevel@tonic-gate 			}
7520Sstevel@tonic-gate 			break;
7530Sstevel@tonic-gate 		case '?':
7540Sstevel@tonic-gate 		default:
7550Sstevel@tonic-gate 			errflg++;
7560Sstevel@tonic-gate 			break;
7570Sstevel@tonic-gate 		}
7580Sstevel@tonic-gate 	}
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	if (argc == optind || n_proto_refs == 0) {
7610Sstevel@tonic-gate 		usage();
7620Sstevel@tonic-gate 		exit(1);
7630Sstevel@tonic-gate 	}
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	if (set_group || set_user || set_perm) {
7660Sstevel@tonic-gate 		if (optind != argc - 1) {
7670Sstevel@tonic-gate 			usage();
7680Sstevel@tonic-gate 			exit(1);
7690Sstevel@tonic-gate 		}
7700Sstevel@tonic-gate 		if (stat(argv[optind], &st_buf) == -1) {
7710Sstevel@tonic-gate 			perror(argv[optind]);
7720Sstevel@tonic-gate 			exit(1);
7730Sstevel@tonic-gate 		}
7740Sstevel@tonic-gate 		if (!S_ISDIR(st_buf.st_mode)) {
7750Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: %s: not a directory\n",
7760Sstevel@tonic-gate 			    myname, argv[optind]);
7770Sstevel@tonic-gate 			exit(1);
7780Sstevel@tonic-gate 		}
7790Sstevel@tonic-gate 	}
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	init_list(&first_list, HASH_SIZE);
7820Sstevel@tonic-gate 	init_list(&second_list, HASH_SIZE);
7830Sstevel@tonic-gate 	init_list(&exception_list, HASH_SIZE);
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	for (i = 0; i < n_exception_files; i++) {
7860Sstevel@tonic-gate 		(void) read_in_exceptions(exception_files[i], verbose);
7870Sstevel@tonic-gate 	}
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	for (i = 0; i < n_proto_refs; i++) {
7900Sstevel@tonic-gate 		first_file_name = proto_refs[i];
7910Sstevel@tonic-gate 		(void) read_in_file(first_file_name, &first_list);
7920Sstevel@tonic-gate 	}
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	if (set_group || set_user || set_perm) {
7950Sstevel@tonic-gate 		if (chdir(argv[optind]) == -1) {
7960Sstevel@tonic-gate 			perror(argv[optind]);
7970Sstevel@tonic-gate 			exit(1);
7980Sstevel@tonic-gate 		}
7990Sstevel@tonic-gate 		i = nftw(".", set_values, MAX_DEPTH, FTW_PHYS|FTW_DEPTH);
8000Sstevel@tonic-gate 		if (i == -1) {
8010Sstevel@tonic-gate 			perror("nftw");
8020Sstevel@tonic-gate 			i = 1;
8030Sstevel@tonic-gate 		}
8040Sstevel@tonic-gate 		exit(i);
8050Sstevel@tonic-gate 	}
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 	for (i = optind; i < argc; i++) {
8080Sstevel@tonic-gate 		second_file_name = argv[i];
8090Sstevel@tonic-gate 		(void) read_in_file(second_file_name, &second_list);
8100Sstevel@tonic-gate 	}
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	open_output_files();
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	if (verbose)
8150Sstevel@tonic-gate 		(void) puts("comparing build to packages...");
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	check_first_vs_second(list_filtered_exceptions);
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	if (verbose)
8200Sstevel@tonic-gate 		(void) puts("checking over packages...");
8210Sstevel@tonic-gate 	check_second_vs_first(list_filtered_exceptions);
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	close_output_files();
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 	print_results();
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	clean_up();
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	return (0);
8300Sstevel@tonic-gate }
831