xref: /onnv-gate/usr/src/cmd/sgs/crle/common/inspect.c (revision 1976:f0691a145b7e)
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
51698Sab196087  * Common Development and Distribution License (the "License").
61698Sab196087  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
221698Sab196087  *	Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  *	Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * Routines to add file and directory entries into the internal configuration
290Sstevel@tonic-gate  * information.  This information is maintained in a number of hash tables which
300Sstevel@tonic-gate  * after completion of input file processing will be processed and written to
310Sstevel@tonic-gate  * the output configuration file.
320Sstevel@tonic-gate  *
330Sstevel@tonic-gate  * Each hash table is defined via a Hash_tbl structure.  These are organized:
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  *  c_strtbl	contains a hash entry for every file, directory, pathname and
360Sstevel@tonic-gate  *		alternative path (dldump(3dl) image) processed.
370Sstevel@tonic-gate  *		c_strsize and c_objnum maintain the size and count of the
380Sstevel@tonic-gate  *		strings added to this table and are used to size the output
390Sstevel@tonic-gate  *		configuration file.
400Sstevel@tonic-gate  *
410Sstevel@tonic-gate  *  c_inotbls	contains a list of inode hash tables.  Each element of the list
420Sstevel@tonic-gate  *		identifies a unique device.  Thus, for each file processed its
430Sstevel@tonic-gate  *		st_dev and st_ino are used to assign its entry to the correct
440Sstevel@tonic-gate  *		hash table.
450Sstevel@tonic-gate  *
460Sstevel@tonic-gate  *		Each directory processed is assigned a unique id (c_dirnum)
470Sstevel@tonic-gate  *		which insures each file also becomes uniquely identified.
480Sstevel@tonic-gate  *
490Sstevel@tonic-gate  * All file and directory additions come through the inspect() entry point.
500Sstevel@tonic-gate  */
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #include	<sys/types.h>
530Sstevel@tonic-gate #include	<sys/stat.h>
540Sstevel@tonic-gate #include	<fcntl.h>
550Sstevel@tonic-gate #include	<dirent.h>
561698Sab196087 #include	<_libelf.h>
570Sstevel@tonic-gate #include	<errno.h>
580Sstevel@tonic-gate #include	<stdio.h>
590Sstevel@tonic-gate #include	<string.h>
600Sstevel@tonic-gate #include	<unistd.h>
610Sstevel@tonic-gate #include	<limits.h>
620Sstevel@tonic-gate #include	"machdep.h"
630Sstevel@tonic-gate #include	"sgs.h"
640Sstevel@tonic-gate #include	"rtc.h"
650Sstevel@tonic-gate #include	"_crle.h"
660Sstevel@tonic-gate #include	"msg.h"
670Sstevel@tonic-gate 
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate  * Add an alternative pathname for an object.  Although a configuration file
700Sstevel@tonic-gate  * may contain several pathnames that resolve to the same real file, there can
710Sstevel@tonic-gate  * only be one real file.  Consequently, there can only be one alternative.
720Sstevel@tonic-gate  * For multiple pathnames that resolve to the same real file, multiple alter-
730Sstevel@tonic-gate  * natives may be specified.  Always take the alternative for the real file
740Sstevel@tonic-gate  * over any others.
750Sstevel@tonic-gate  */
760Sstevel@tonic-gate static int
770Sstevel@tonic-gate enteralt(Crle_desc * crle, const char *path, const char *file, Half flags,
780Sstevel@tonic-gate     Hash_obj * obj)
790Sstevel@tonic-gate {
800Sstevel@tonic-gate 	const char	*fmt;
810Sstevel@tonic-gate 	char		alter[PATH_MAX];
820Sstevel@tonic-gate 	size_t		altsz;
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	if (obj->o_alter) {
850Sstevel@tonic-gate 		/*
860Sstevel@tonic-gate 		 * If an alternative has already been captured, only override
870Sstevel@tonic-gate 		 * it if the specified file is the real file.
880Sstevel@tonic-gate 		 */
890Sstevel@tonic-gate 		if (strcmp(path, obj->o_path))
900Sstevel@tonic-gate 			return (1);
910Sstevel@tonic-gate 	}
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	/*
940Sstevel@tonic-gate 	 * Create an alternative pathname from the file and object destination
950Sstevel@tonic-gate 	 * directory.  If we're dumping an alternative don't allow it to
960Sstevel@tonic-gate 	 * override the original.
970Sstevel@tonic-gate 	 */
980Sstevel@tonic-gate 	if (flags & RTC_OBJ_DUMP) {
990Sstevel@tonic-gate 		char	_alter[PATH_MAX];
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 		(void) strcpy(_alter, crle->c_objdir);
1020Sstevel@tonic-gate 		(void) realpath(_alter, _alter);
1030Sstevel@tonic-gate 		(void) snprintf(alter, PATH_MAX, MSG_ORIG(MSG_FMT_PATH),
1040Sstevel@tonic-gate 		    _alter, file);
1050Sstevel@tonic-gate 		if (strcmp(alter, obj->o_path) == 0) {
1060Sstevel@tonic-gate 			(void) printf(MSG_INTL(MSG_ARG_ALT), crle->c_name,
1070Sstevel@tonic-gate 			    obj->o_path);
1080Sstevel@tonic-gate 			return (0);
1090Sstevel@tonic-gate 		}
1100Sstevel@tonic-gate 		obj->o_flags |= RTC_OBJ_DUMP;
1110Sstevel@tonic-gate 	} else
1120Sstevel@tonic-gate 		(void) snprintf(alter, PATH_MAX, MSG_ORIG(MSG_FMT_PATH),
1130Sstevel@tonic-gate 		    crle->c_objdir, file);
1140Sstevel@tonic-gate 	obj->o_flags |= RTC_OBJ_ALTER;
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	/*
1170Sstevel@tonic-gate 	 * If we're overriding an existing alternative with the real path, free
1180Sstevel@tonic-gate 	 * up any previous alternative.
1190Sstevel@tonic-gate 	 */
1200Sstevel@tonic-gate 	if (obj->o_alter) {
1210Sstevel@tonic-gate 		crle->c_strsize -= strlen(alter) + 1;
1220Sstevel@tonic-gate 		fmt = MSG_INTL(MSG_DIA_ALTUPDATE);
1230Sstevel@tonic-gate 	} else
1240Sstevel@tonic-gate 		fmt = MSG_INTL(MSG_DIA_ALTCREATE);
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	/*
1270Sstevel@tonic-gate 	 * Allocate the new alternative and update the string table size.
1280Sstevel@tonic-gate 	 */
1290Sstevel@tonic-gate 	altsz = strlen(alter) + 1;
1300Sstevel@tonic-gate 	if ((obj->o_alter = malloc(altsz)) == 0)
1310Sstevel@tonic-gate 		return (0);
1320Sstevel@tonic-gate 	(void) strcpy(obj->o_alter, alter);
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	crle->c_strsize += altsz;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	if (crle->c_flags & CRLE_VERBOSE)
1370Sstevel@tonic-gate 		(void) printf(fmt, alter, obj->o_path);
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	return (1);
1400Sstevel@tonic-gate }
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate /*
1440Sstevel@tonic-gate  * Establish an inode hash entry, this is unique for each dev hash table, and
1450Sstevel@tonic-gate  * establishes the unique object descriptor.
1460Sstevel@tonic-gate  */
1470Sstevel@tonic-gate static Hash_ent *
1480Sstevel@tonic-gate enterino(Crle_desc * crle, const char *name, struct stat *status, Half flags)
1490Sstevel@tonic-gate {
1500Sstevel@tonic-gate 	Hash_ent *	ent;
1510Sstevel@tonic-gate 	Hash_obj *	obj;
1520Sstevel@tonic-gate 	Hash_tbl *	tbl;
1530Sstevel@tonic-gate 	Listnode *	lnp = 0;
1540Sstevel@tonic-gate 	Addr		ino = (Addr)status->st_ino;
1550Sstevel@tonic-gate 	ulong_t		dev = status->st_dev;
1560Sstevel@tonic-gate 	Lword		info;
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	/*
1590Sstevel@tonic-gate 	 * For configuration file verification we retain information about the
1600Sstevel@tonic-gate 	 * file or directory.
1610Sstevel@tonic-gate 	 */
1620Sstevel@tonic-gate 	if (flags & RTC_OBJ_DIRENT)
1630Sstevel@tonic-gate 		info = (Lword)status->st_mtime;
1640Sstevel@tonic-gate 	else
1650Sstevel@tonic-gate 		info = (Lword)status->st_size;
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	/*
1680Sstevel@tonic-gate 	 * Determine the objects device number and establish a hash table for
1690Sstevel@tonic-gate 	 * for this devices inodes.
1700Sstevel@tonic-gate 	 */
1710Sstevel@tonic-gate 	for (LIST_TRAVERSE(&crle->c_inotbls, lnp, tbl)) {
1720Sstevel@tonic-gate 		if (tbl->t_ident == dev)
1730Sstevel@tonic-gate 			break;
1740Sstevel@tonic-gate 	}
1750Sstevel@tonic-gate 	if (lnp == 0) {
1760Sstevel@tonic-gate 		if ((tbl = make_hash(crle->c_inobkts, HASH_INT, dev)) == 0)
1770Sstevel@tonic-gate 			return (0);
1780Sstevel@tonic-gate 		if (list_append(&crle->c_inotbls, tbl) == 0)
1790Sstevel@tonic-gate 			return (0);
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	/*
1830Sstevel@tonic-gate 	 * Reuse or add this new object to the inode hash table.
1840Sstevel@tonic-gate 	 */
1850Sstevel@tonic-gate 	if ((ent = get_hash(tbl, ino, 0, (HASH_FND_ENT | HASH_ADD_ENT))) == 0)
1860Sstevel@tonic-gate 		return (0);
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	/*
1890Sstevel@tonic-gate 	 * If an object descriptor doesn't yet exist create one.
1900Sstevel@tonic-gate 	 */
1910Sstevel@tonic-gate 	if ((obj = ent->e_obj) == 0) {
1920Sstevel@tonic-gate 		if ((obj = calloc(sizeof (Hash_obj), 1)) == 0)
1930Sstevel@tonic-gate 			return (0);
1940Sstevel@tonic-gate 		obj->o_tbl = tbl;
1950Sstevel@tonic-gate 		obj->o_flags = flags;
1960Sstevel@tonic-gate 		obj->o_info = info;
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 		/*
1990Sstevel@tonic-gate 		 * Reallocate the objects name, as it might have been composed
2000Sstevel@tonic-gate 		 * and passed to us on the stack.
2010Sstevel@tonic-gate 		 */
2020Sstevel@tonic-gate 		if ((obj->o_path = strdup(name)) == 0)
2030Sstevel@tonic-gate 			return (0);
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 		/*
2060Sstevel@tonic-gate 		 * Assign this object to the original ino hash entry.
2070Sstevel@tonic-gate 		 */
2080Sstevel@tonic-gate 		ent->e_obj = obj;
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate 	return (ent);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate /*
2150Sstevel@tonic-gate  * Basic directory entry, establishes entry information, updated global counts
2160Sstevel@tonic-gate  * and provides any diagnostics.
2170Sstevel@tonic-gate  */
2180Sstevel@tonic-gate static int
2190Sstevel@tonic-gate _enterdir(Crle_desc * crle, const char *dir, Hash_ent * ent, Hash_obj * obj)
2200Sstevel@tonic-gate {
2210Sstevel@tonic-gate 	size_t	size = strlen(dir) + 1;
2220Sstevel@tonic-gate 	char	*ndir;
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	/*
2250Sstevel@tonic-gate 	 * Establish this hash entries key (which is the directory name itself),
2260Sstevel@tonic-gate 	 * assign the next available directory number, and its object.
2270Sstevel@tonic-gate 	 */
2280Sstevel@tonic-gate 	if ((ndir = malloc(size)) == 0)
2290Sstevel@tonic-gate 		return (0);
2300Sstevel@tonic-gate 	(void) strcpy(ndir, dir);
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	ent->e_key = (Addr)ndir;
2330Sstevel@tonic-gate 	ent->e_id = crle->c_dirnum++;
2340Sstevel@tonic-gate 	ent->e_obj = obj;
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	/*
2370Sstevel@tonic-gate 	 * Update string table information.  We add a dummy filename for each
2380Sstevel@tonic-gate 	 * real directory so as to have a null terminated file table array for
2390Sstevel@tonic-gate 	 * this directory.
2400Sstevel@tonic-gate 	 */
2410Sstevel@tonic-gate 	crle->c_strsize += size;
2420Sstevel@tonic-gate 	crle->c_hashstrnum++;
2430Sstevel@tonic-gate 	crle->c_filenum++;
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	/*
2460Sstevel@tonic-gate 	 * Provide any diagnostics.
2470Sstevel@tonic-gate 	 */
2480Sstevel@tonic-gate 	if (crle->c_flags & CRLE_VERBOSE) {
2490Sstevel@tonic-gate 		const char	*fmt;
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 		if (obj->o_flags & RTC_OBJ_NOEXIST)
2520Sstevel@tonic-gate 			fmt = MSG_INTL(MSG_DIA_NOEXIST);
2530Sstevel@tonic-gate 		else
2540Sstevel@tonic-gate 			fmt = MSG_INTL(MSG_DIA_DIR);
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 		(void) printf(fmt, ent->e_id, dir);
2570Sstevel@tonic-gate 	}
2580Sstevel@tonic-gate 	return (1);
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate /*
2630Sstevel@tonic-gate  * Establish a string hash entry for a directory.
2640Sstevel@tonic-gate  */
2650Sstevel@tonic-gate static Hash_ent *
2660Sstevel@tonic-gate enterdir(Crle_desc * crle, const char *odir, Half flags, struct stat *status)
2670Sstevel@tonic-gate {
2680Sstevel@tonic-gate 	Hash_tbl *	stbl = crle->c_strtbl;
2690Sstevel@tonic-gate 	Hash_ent *	ent;
2700Sstevel@tonic-gate 	Hash_obj *	obj;
2710Sstevel@tonic-gate 	char		rdir[PATH_MAX], * ndir;
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	/*
2740Sstevel@tonic-gate 	 * Establish the directories real name, this is the name that will be
2750Sstevel@tonic-gate 	 * recorded in the object identifier.
2760Sstevel@tonic-gate 	 */
2770Sstevel@tonic-gate 	if (realpath(odir, rdir) == 0)
2780Sstevel@tonic-gate 		return (0);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	if (strcmp(odir, rdir))
2810Sstevel@tonic-gate 		ndir = rdir;
2820Sstevel@tonic-gate 	else
2830Sstevel@tonic-gate 		ndir = (char *)odir;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	/*
2860Sstevel@tonic-gate 	 * If we're not dealing with an all-entries directory (i.e., we're
2870Sstevel@tonic-gate 	 * recording this directory because of its explicitly specified
2880Sstevel@tonic-gate 	 * filename) leave off any filename specific attributes.
2890Sstevel@tonic-gate 	 */
2900Sstevel@tonic-gate 	if ((flags & RTC_OBJ_ALLENTS) == 0)
2910Sstevel@tonic-gate 		flags &= ~(RTC_OBJ_ALTER | RTC_OBJ_DUMP | RTC_OBJ_GROUP);
2920Sstevel@tonic-gate 	flags |= RTC_OBJ_DIRENT;
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	/*
2950Sstevel@tonic-gate 	 * Establish a inode table entry, and the objects unique descriptor.
2960Sstevel@tonic-gate 	 */
2970Sstevel@tonic-gate 	if ((ent = enterino(crle, ndir, status, flags)) == 0)
2980Sstevel@tonic-gate 		return (0);
2990Sstevel@tonic-gate 	obj = ent->e_obj;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	/*
3020Sstevel@tonic-gate 	 * Create a string table entry for the real directory.
3030Sstevel@tonic-gate 	 */
3040Sstevel@tonic-gate 	if ((ent = get_hash(stbl, (Addr)ndir, 0,
3050Sstevel@tonic-gate 	    (HASH_FND_ENT | HASH_ADD_ENT))) == 0)
3060Sstevel@tonic-gate 		return (0);
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	/*
3090Sstevel@tonic-gate 	 * If this is a new entry reassign the directory name and assign a
3100Sstevel@tonic-gate 	 * unique directory id.
3110Sstevel@tonic-gate 	 */
3120Sstevel@tonic-gate 	if (ent->e_id == 0) {
3130Sstevel@tonic-gate 		if (_enterdir(crle, ndir, ent, obj) == 0)
3140Sstevel@tonic-gate 			return (0);
3150Sstevel@tonic-gate 	}
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	/*
3180Sstevel@tonic-gate 	 * If the directory name supplied is different than the real name we've
3190Sstevel@tonic-gate 	 * just entered, continue to create an entry for it.
3200Sstevel@tonic-gate 	 */
3210Sstevel@tonic-gate 	if (ndir == odir)
3220Sstevel@tonic-gate 		return (ent);
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	/*
3250Sstevel@tonic-gate 	 * Create a string table entry for this real directory.
3260Sstevel@tonic-gate 	 */
3270Sstevel@tonic-gate 	if ((ent = get_hash(stbl, (Addr)odir, 0,
3280Sstevel@tonic-gate 	    (HASH_FND_ENT | HASH_ADD_ENT))) == 0)
3290Sstevel@tonic-gate 		return (0);
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	/*
3320Sstevel@tonic-gate 	 * If this is a new entry reassign the directory name and assign a
3330Sstevel@tonic-gate 	 * unique directory id.
3340Sstevel@tonic-gate 	 */
3350Sstevel@tonic-gate 	if (ent->e_id == 0) {
3360Sstevel@tonic-gate 		if (_enterdir(crle, odir, ent, obj) == 0)
3370Sstevel@tonic-gate 			return (0);
3380Sstevel@tonic-gate 	}
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	return (ent);
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate /*
3450Sstevel@tonic-gate  * Establish a non-existent directory entry.  There is no inode entry created
3460Sstevel@tonic-gate  * for this, just a directory and its associated object.
3470Sstevel@tonic-gate  */
3480Sstevel@tonic-gate static Hash_ent *
3490Sstevel@tonic-gate enternoexistdir(Crle_desc * crle, const char *dir)
3500Sstevel@tonic-gate {
3510Sstevel@tonic-gate 	Hash_ent *	ent;
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	/*
3540Sstevel@tonic-gate 	 * Reuse or add this new non-existent directory to the string table.
3550Sstevel@tonic-gate 	 */
3560Sstevel@tonic-gate 	if ((ent = get_hash(crle->c_strtbl, (Addr)dir, 0,
3570Sstevel@tonic-gate 	    (HASH_FND_ENT | HASH_ADD_ENT))) == 0)
3580Sstevel@tonic-gate 		return (0);
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	/*
3610Sstevel@tonic-gate 	 * If this is a new entry, assign both the object and the directory
3620Sstevel@tonic-gate 	 * entry information.
3630Sstevel@tonic-gate 	 */
3640Sstevel@tonic-gate 	if (ent->e_id == 0) {
3650Sstevel@tonic-gate 		Hash_obj *	obj;
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 		if ((obj = calloc(sizeof (Hash_obj), 1)) == 0)
3680Sstevel@tonic-gate 			return (0);
3690Sstevel@tonic-gate 		obj->o_flags = (RTC_OBJ_NOEXIST | RTC_OBJ_DIRENT);
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 		if (_enterdir(crle, dir, ent, obj) == 0)
3720Sstevel@tonic-gate 			return (0);
3730Sstevel@tonic-gate 	}
3740Sstevel@tonic-gate 	return (ent);
3750Sstevel@tonic-gate }
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate /*
3790Sstevel@tonic-gate  * Basic file entry, establishes entry information, updated global counts
3800Sstevel@tonic-gate  * and provides any diagnostics.
3810Sstevel@tonic-gate  */
3820Sstevel@tonic-gate static int
3830Sstevel@tonic-gate _enterfile(Crle_desc * crle, const char *file, int off, Hash_ent * fent,
3840Sstevel@tonic-gate     Hash_ent * rent, Hash_ent * dent, Hash_obj * obj)
3850Sstevel@tonic-gate {
3860Sstevel@tonic-gate 	size_t	size = strlen(file) + 1;
3870Sstevel@tonic-gate 	char	*nfile;
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	/*
3900Sstevel@tonic-gate 	 * If this is a full file name reallocate it, as it might have been
3910Sstevel@tonic-gate 	 * composed and passed to us on the stack.  Otherwise reuse the original
3920Sstevel@tonic-gate 	 * directory name to satisfy the filename, here we record the offset of
3930Sstevel@tonic-gate 	 * the file in the directory name so that we can reduce the string table
3940Sstevel@tonic-gate 	 * in the final configuration file.
3950Sstevel@tonic-gate 	 */
3960Sstevel@tonic-gate 	if (off == 0) {
3970Sstevel@tonic-gate 		if ((nfile = malloc(size)) == 0)
3980Sstevel@tonic-gate 			return (0);
3990Sstevel@tonic-gate 		(void) strcpy(nfile, file);
4000Sstevel@tonic-gate 	} else
4010Sstevel@tonic-gate 		nfile = (char *)file;
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	fent->e_key = (Addr)nfile;
4040Sstevel@tonic-gate 	fent->e_off = off;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	/*
4070Sstevel@tonic-gate 	 * Assign directory and directory id, and any real (full) path
4080Sstevel@tonic-gate 	 * association.
4090Sstevel@tonic-gate 	 */
4100Sstevel@tonic-gate 	fent->e_dir = dent;
4110Sstevel@tonic-gate 	fent->e_id = dent->e_id;
4120Sstevel@tonic-gate 	fent->e_path = rent;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	/*
4150Sstevel@tonic-gate 	 * Increment the file count for this directory.
4160Sstevel@tonic-gate 	 */
4170Sstevel@tonic-gate 	dent->e_cnt++;
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	/*
4200Sstevel@tonic-gate 	 * Assign this object to the new string hash entry.
4210Sstevel@tonic-gate 	 */
4220Sstevel@tonic-gate 	fent->e_obj = obj;
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	/*
4250Sstevel@tonic-gate 	 * Update string table information.
4260Sstevel@tonic-gate 	 */
4270Sstevel@tonic-gate 	crle->c_strsize += size;
4280Sstevel@tonic-gate 	crle->c_hashstrnum++;
4290Sstevel@tonic-gate 	crle->c_filenum++;
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	/*
4320Sstevel@tonic-gate 	 * Provide any diagnostics.
4330Sstevel@tonic-gate 	 */
4340Sstevel@tonic-gate 	if (crle->c_flags & CRLE_VERBOSE)
4350Sstevel@tonic-gate 		(void) printf(MSG_INTL(MSG_DIA_FILE), fent->e_id, nfile);
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	return (1);
4380Sstevel@tonic-gate }
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate /*
4420Sstevel@tonic-gate  * Establish a non-existent file entry.  There is no inode entry created for
4430Sstevel@tonic-gate  * this, just the files full and simple name, and its associated object.
4440Sstevel@tonic-gate  */
4450Sstevel@tonic-gate static Hash_ent *
4460Sstevel@tonic-gate enternoexistfile(Crle_desc * crle, const char *path, const char *file,
4470Sstevel@tonic-gate     Hash_ent * dent)
4480Sstevel@tonic-gate {
4490Sstevel@tonic-gate 	Hash_ent *	rent, * ent;
4500Sstevel@tonic-gate 	Hash_obj *	obj;
4510Sstevel@tonic-gate 	int		off;
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	/*
4540Sstevel@tonic-gate 	 * Create a string table entry for the full filename.
4550Sstevel@tonic-gate 	 */
4560Sstevel@tonic-gate 	if ((rent = get_hash(crle->c_strtbl, (Addr)path, 0,
4570Sstevel@tonic-gate 	    (HASH_FND_ENT | HASH_ADD_ENT))) == 0)
4580Sstevel@tonic-gate 		return (0);
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	/*
4610Sstevel@tonic-gate 	 * If this is a new entry, assign both the object and the full filename
4620Sstevel@tonic-gate 	 * entry information.
4630Sstevel@tonic-gate 	 */
4640Sstevel@tonic-gate 	if (rent->e_id == 0) {
4650Sstevel@tonic-gate 		if ((obj = calloc(sizeof (Hash_obj), 1)) == 0)
4660Sstevel@tonic-gate 			return (0);
4670Sstevel@tonic-gate 		obj->o_flags = RTC_OBJ_NOEXIST;
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 		if (_enterfile(crle, path, 0, rent, 0, dent, obj) == 0)
4700Sstevel@tonic-gate 			return (0);
4710Sstevel@tonic-gate 	}
4720Sstevel@tonic-gate 	obj = rent->e_obj;
4730Sstevel@tonic-gate 	if ((obj->o_path = strdup(path)) == 0)
4740Sstevel@tonic-gate 		return (0);
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	/*
4770Sstevel@tonic-gate 	 * Express the filename in terms of the full pathname.  By reusing the
4780Sstevel@tonic-gate 	 * name within the full filename we can reduce the overall string table
4790Sstevel@tonic-gate 	 * size in the output configuration file.
4800Sstevel@tonic-gate 	 */
4810Sstevel@tonic-gate 	off = file - path;
4820Sstevel@tonic-gate 	file = (char *)rent->e_key + off;
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	/*
4850Sstevel@tonic-gate 	 * Create a entry for the individual file within this directory.
4860Sstevel@tonic-gate 	 */
4870Sstevel@tonic-gate 	if ((ent = get_hash(crle->c_strtbl, (Addr)file, dent->e_id,
4880Sstevel@tonic-gate 	    (HASH_FND_ENT | HASH_ADD_ENT))) == 0)
4890Sstevel@tonic-gate 		return (0);
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	if (ent->e_id == 0) {
4920Sstevel@tonic-gate 		if (_enterfile(crle, file, off, ent, rent, dent, obj) == 0)
4930Sstevel@tonic-gate 			return (0);
4940Sstevel@tonic-gate 	}
4950Sstevel@tonic-gate 	return (ent);
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate /*
5000Sstevel@tonic-gate  * Establish a string hash entry for a file.
5010Sstevel@tonic-gate  */
5020Sstevel@tonic-gate static Hash_ent *
5030Sstevel@tonic-gate enterfile(Crle_desc * crle, const char *opath, const char *ofile, Half flags,
5040Sstevel@tonic-gate     Hash_ent * odent, struct stat *status)
5050Sstevel@tonic-gate {
5060Sstevel@tonic-gate 	Hash_tbl *	stbl = crle->c_strtbl;
5070Sstevel@tonic-gate 	Hash_ent *	ent, * rent, * ndent = odent;
5080Sstevel@tonic-gate 	Hash_obj *	obj;
5090Sstevel@tonic-gate 	size_t		size;
5100Sstevel@tonic-gate 	char		rpath[PATH_MAX], * npath, * nfile;
5110Sstevel@tonic-gate 	int		off;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	/*
5140Sstevel@tonic-gate 	 * Establish the files real name, this is the name that will be
5150Sstevel@tonic-gate 	 * recorded in the object identifier.
5160Sstevel@tonic-gate 	 */
5170Sstevel@tonic-gate 	if (realpath(opath, rpath) == 0)
5180Sstevel@tonic-gate 		return (0);
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	if (strcmp(opath, rpath)) {
5210Sstevel@tonic-gate 		npath = rpath;
5220Sstevel@tonic-gate 		if (nfile = strrchr(npath, '/'))
5230Sstevel@tonic-gate 			nfile++;
5240Sstevel@tonic-gate 		else
5250Sstevel@tonic-gate 			nfile = npath;
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 		/*
5280Sstevel@tonic-gate 		 * Determine if the real pathname has a different directory to
5290Sstevel@tonic-gate 		 * the original passed to us.
5300Sstevel@tonic-gate 		 */
5310Sstevel@tonic-gate 		size = nfile - npath;
5320Sstevel@tonic-gate 		if (strncmp(opath, npath, size)) {
5330Sstevel@tonic-gate 			char		_npath[PATH_MAX];
5340Sstevel@tonic-gate 			struct stat	_status;
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 			(void) strncpy(_npath, npath, size);
5370Sstevel@tonic-gate 			_npath[size - 1] = '\0';
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 			(void) stat(_npath, &_status);
5400Sstevel@tonic-gate 			if ((ndent = enterdir(crle, _npath, flags,
5410Sstevel@tonic-gate 			    &_status)) == 0)
5420Sstevel@tonic-gate 				return (0);
5430Sstevel@tonic-gate 		}
5440Sstevel@tonic-gate 	} else {
5450Sstevel@tonic-gate 		npath = (char *)opath;
5460Sstevel@tonic-gate 		nfile = (char *)ofile;
5470Sstevel@tonic-gate 	}
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	/*
5500Sstevel@tonic-gate 	 * Establish an inode table entry, and the objects unique descriptor.
5510Sstevel@tonic-gate 	 */
5520Sstevel@tonic-gate 	if ((ent = enterino(crle, npath, status, flags)) == 0)
5530Sstevel@tonic-gate 		return (0);
5540Sstevel@tonic-gate 	obj = ent->e_obj;
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	/*
5570Sstevel@tonic-gate 	 * Create a string table entry for the full filename.
5580Sstevel@tonic-gate 	 */
5590Sstevel@tonic-gate 	if ((rent = get_hash(stbl, (Addr)npath, 0,
5600Sstevel@tonic-gate 	    (HASH_FND_ENT | HASH_ADD_ENT))) == 0)
5610Sstevel@tonic-gate 		return (0);
5620Sstevel@tonic-gate 	if (rent->e_id == 0) {
5630Sstevel@tonic-gate 		if (_enterfile(crle, npath, 0, rent, 0, ndent, obj) == 0)
5640Sstevel@tonic-gate 			return (0);
5650Sstevel@tonic-gate 	}
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	/*
5680Sstevel@tonic-gate 	 * Identify this entry and its directory as real paths.  If dldump(3dl)
5690Sstevel@tonic-gate 	 * processing is required this flag is checked, as we only need to dump
5700Sstevel@tonic-gate 	 * the real pathname.  Many other objects may point to the same
5710Sstevel@tonic-gate 	 * alternative, but only one needs to be dumped.  In addition, during
5720Sstevel@tonic-gate 	 * ld.so.1 validation, only this directory and file need be checked.
5730Sstevel@tonic-gate 	 */
5740Sstevel@tonic-gate 	rent->e_flags |= RTC_OBJ_REALPTH;
5750Sstevel@tonic-gate 	ndent->e_flags |= RTC_OBJ_REALPTH;
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	/*
5780Sstevel@tonic-gate 	 * Express the filename in terms of the full pathname.  By reusing the
5790Sstevel@tonic-gate 	 * name within the full filename we can reduce the overall string table
5800Sstevel@tonic-gate 	 * size in the output configuration file.
5810Sstevel@tonic-gate 	 */
5820Sstevel@tonic-gate 	off = nfile - npath;
5830Sstevel@tonic-gate 	nfile = (char *)rent->e_key + off;
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	/*
5860Sstevel@tonic-gate 	 * Create a entry for the individual file within this directory.
5870Sstevel@tonic-gate 	 */
5880Sstevel@tonic-gate 	if ((ent = get_hash(stbl, (Addr)nfile, ndent->e_id,
5890Sstevel@tonic-gate 	    (HASH_FND_ENT | HASH_ADD_ENT))) == 0)
5900Sstevel@tonic-gate 		return (0);
5910Sstevel@tonic-gate 	if (ent->e_id == 0) {
5920Sstevel@tonic-gate 		if (_enterfile(crle, nfile, off, ent, rent, ndent, obj) == 0)
5930Sstevel@tonic-gate 			return (0);
5940Sstevel@tonic-gate 	}
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	/*
5970Sstevel@tonic-gate 	 * If the original path name is not equivalent to the real path name,
5980Sstevel@tonic-gate 	 * then we had an alias (typically it's a symlink).  Add the path name
5990Sstevel@tonic-gate 	 * to the string hash table and reference the object data structure.
6000Sstevel@tonic-gate 	 */
6010Sstevel@tonic-gate 	if (nfile == ofile)
6020Sstevel@tonic-gate 		return (ent);
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	/*
6050Sstevel@tonic-gate 	 * Establish an inode table entry, and the objects unique descriptor.
6060Sstevel@tonic-gate 	 */
6070Sstevel@tonic-gate 	if ((ent = enterino(crle, opath, status, 0)) == 0)
6080Sstevel@tonic-gate 		return (0);
6090Sstevel@tonic-gate 	obj = ent->e_obj;
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	/*
6120Sstevel@tonic-gate 	 * Create a string table entry for the full filename.
6130Sstevel@tonic-gate 	 */
6140Sstevel@tonic-gate 	if ((rent = get_hash(stbl, (Addr)opath, 0,
6150Sstevel@tonic-gate 	    (HASH_FND_ENT | HASH_ADD_ENT))) == 0)
6160Sstevel@tonic-gate 		return (0);
6170Sstevel@tonic-gate 	if (rent->e_id == 0) {
6180Sstevel@tonic-gate 		if (_enterfile(crle, opath, 0, rent, 0, odent, obj) == 0)
6190Sstevel@tonic-gate 			return (0);
6200Sstevel@tonic-gate 	}
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	/*
6230Sstevel@tonic-gate 	 * Express the filename in terms of the full pathname.  By reusing the
6240Sstevel@tonic-gate 	 * name within the full filename we can reduce the overall string table
6250Sstevel@tonic-gate 	 * size in the output configuration file.
6260Sstevel@tonic-gate 	 */
6270Sstevel@tonic-gate 	off = ofile - opath;
6280Sstevel@tonic-gate 	ofile = (char *)rent->e_key + off;
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	/*
6310Sstevel@tonic-gate 	 * Create a entry for the individual file within this directory.
6320Sstevel@tonic-gate 	 */
6330Sstevel@tonic-gate 	if ((ent = get_hash(stbl, (Addr)ofile, odent->e_id,
6340Sstevel@tonic-gate 	    (HASH_FND_ENT | HASH_ADD_ENT))) == 0)
6350Sstevel@tonic-gate 		return (0);
6360Sstevel@tonic-gate 	if (ent->e_id == 0) {
6370Sstevel@tonic-gate 		if (_enterfile(crle, ofile, off, ent, rent, odent, obj) == 0)
6380Sstevel@tonic-gate 			return (0);
6390Sstevel@tonic-gate 	}
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	return (ent);
6420Sstevel@tonic-gate }
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate /*
6460Sstevel@tonic-gate  * Add a file to configuration information.
6470Sstevel@tonic-gate  */
6480Sstevel@tonic-gate static int
6490Sstevel@tonic-gate inspect_file(Crle_desc * crle, const char *path, const char *file, Half flags,
6500Sstevel@tonic-gate     Hash_ent * dent, struct stat *status, int error)
6510Sstevel@tonic-gate {
6520Sstevel@tonic-gate 	Hash_ent *	ent;
6530Sstevel@tonic-gate 	Hash_obj *	obj;
6540Sstevel@tonic-gate 	int		fd;
6550Sstevel@tonic-gate 	Elf *		elf;
6560Sstevel@tonic-gate 	GElf_Ehdr	ehdr;
6571698Sab196087 	GElf_Xword	dyflags = 0;
6580Sstevel@tonic-gate 	Listnode *	lnp;
6590Sstevel@tonic-gate 	Hash_tbl *	tbl;
6600Sstevel@tonic-gate 	Addr		ino = (Addr)status->st_ino;
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	/*
6630Sstevel@tonic-gate 	 * Determine whether this file (inode) has already been processed.
6640Sstevel@tonic-gate 	 */
6650Sstevel@tonic-gate 	for (LIST_TRAVERSE(&crle->c_inotbls, lnp, tbl)) {
6660Sstevel@tonic-gate 		if (tbl->t_ident != status->st_dev)
6670Sstevel@tonic-gate 			continue;
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 		if ((ent = get_hash(tbl, ino, 0, HASH_FND_ENT)) == 0)
6700Sstevel@tonic-gate 			break;
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 		/*
6730Sstevel@tonic-gate 		 * This files inode object does exist, make sure it has a file
6740Sstevel@tonic-gate 		 * entry for this directory.
6750Sstevel@tonic-gate 		 */
6760Sstevel@tonic-gate 		if ((ent = enterfile(crle, path, file, flags, dent,
6770Sstevel@tonic-gate 		    status)) == 0)
6780Sstevel@tonic-gate 			return (error);
6790Sstevel@tonic-gate 		obj = ent->e_obj;
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 		/*
6820Sstevel@tonic-gate 		 * If an alternative has been asked for, and one has not yet
6830Sstevel@tonic-gate 		 * been established, create one.
6840Sstevel@tonic-gate 		 */
6850Sstevel@tonic-gate 		if ((flags & RTC_OBJ_ALTER) &&
6860Sstevel@tonic-gate 		    ((obj->o_flags & RTC_OBJ_NOALTER) == 0)) {
6870Sstevel@tonic-gate 			if (enteralt(crle, path, file, flags, obj) == 0)
6880Sstevel@tonic-gate 				return (error);
6890Sstevel@tonic-gate 		}
6900Sstevel@tonic-gate 		return (0);
6910Sstevel@tonic-gate 	}
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	/*
6940Sstevel@tonic-gate 	 * This is a new file, determine if it's a valid ELF file.
6950Sstevel@tonic-gate 	 */
6960Sstevel@tonic-gate 	if ((fd = open(path, O_RDONLY, 0)) == -1) {
6970Sstevel@tonic-gate 		if (error) {
6980Sstevel@tonic-gate 			int err = errno;
6990Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
7000Sstevel@tonic-gate 			    crle->c_name, path, strerror(err));
7010Sstevel@tonic-gate 		}
7020Sstevel@tonic-gate 		return (error);
7030Sstevel@tonic-gate 	}
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	/*
7060Sstevel@tonic-gate 	 * Obtain an ELF descriptor and determine if we have a shared object.
7070Sstevel@tonic-gate 	 */
7080Sstevel@tonic-gate 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
7090Sstevel@tonic-gate 		if (error)
7100Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_BEGIN),
7110Sstevel@tonic-gate 			    crle->c_name, path, elf_errmsg(-1));
7120Sstevel@tonic-gate 		(void) close(fd);
7130Sstevel@tonic-gate 		return (error);
7140Sstevel@tonic-gate 	}
7150Sstevel@tonic-gate 	if ((elf_kind(elf) != ELF_K_ELF) ||
7160Sstevel@tonic-gate 	    (gelf_getehdr(elf, &ehdr) == NULL) ||
7170Sstevel@tonic-gate 	    (!((ehdr.e_type == ET_EXEC) || (ehdr.e_type == ET_DYN))) ||
718*1976Sab196087 	    (!((ehdr.e_ident[EI_CLASS] == M_CLASS) ||
719*1976Sab196087 	    (ehdr.e_machine == M_MACH)))) {
7200Sstevel@tonic-gate 		if (error)
7210Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_TYPE),
7220Sstevel@tonic-gate 			    crle->c_name, path);
7230Sstevel@tonic-gate 		(void) close(fd);
7240Sstevel@tonic-gate 		(void) elf_end(elf);
7250Sstevel@tonic-gate 		return (error);
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	(void) close(fd);
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	/*
7310Sstevel@tonic-gate 	 * If we're generating alternative objects find this objects DT_FLAGS
7320Sstevel@tonic-gate 	 * to insure it isn't marked as non-dumpable (libdl.so.1 falls into
7330Sstevel@tonic-gate 	 * this category).
7340Sstevel@tonic-gate 	 */
7351698Sab196087 	if (flags & RTC_OBJ_DUMP)
7361698Sab196087 		dyflags = _gelf_getdyndtflags_1(elf);
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 	/*
7390Sstevel@tonic-gate 	 * Dynamic executables can be examined to determine their dependencies,
7400Sstevel@tonic-gate 	 * dldump(3dl) their dependencies, and may even be dldump(3dl)'ed
7410Sstevel@tonic-gate 	 * themselves.
7420Sstevel@tonic-gate 	 *
7430Sstevel@tonic-gate 	 * If we come across an executable while searching a directory
7440Sstevel@tonic-gate 	 * (error == 0) it is ignored.
7450Sstevel@tonic-gate 	 */
7460Sstevel@tonic-gate 	if (ehdr.e_type == ET_EXEC) {
7470Sstevel@tonic-gate 		if (error == 0) {
7480Sstevel@tonic-gate 			(void) elf_end(elf);
7490Sstevel@tonic-gate 			return (0);
7500Sstevel@tonic-gate 		}
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 		/*
7530Sstevel@tonic-gate 		 * If we're not dumping the application itself, or we've not
7540Sstevel@tonic-gate 		 * asked to gather its dependencies then its rather useless.
7550Sstevel@tonic-gate 		 */
7560Sstevel@tonic-gate 		if ((flags & (RTC_OBJ_GROUP | RTC_OBJ_DUMP)) == 0) {
7570Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_GEN_INVFILE),
7580Sstevel@tonic-gate 			    crle->c_name, path);
7590Sstevel@tonic-gate 			(void) elf_end(elf);
7600Sstevel@tonic-gate 			return (error);
7610Sstevel@tonic-gate 		}
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 		/*
7640Sstevel@tonic-gate 		 * If we're dumping the application under RTLD_REL_EXEC then the
7650Sstevel@tonic-gate 		 * configuration file becomes specific to this application, so
7660Sstevel@tonic-gate 		 * make sure we haven't been here before.
7670Sstevel@tonic-gate 		 */
7680Sstevel@tonic-gate 		if (crle->c_app && (flags & RTC_OBJ_DUMP) &&
7690Sstevel@tonic-gate 		    (crle->c_dlflags & RTLD_REL_EXEC)) {
7700Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ARG_MODE),
7710Sstevel@tonic-gate 			    crle->c_name, crle->c_app, path);
7720Sstevel@tonic-gate 			(void) elf_end(elf);
7730Sstevel@tonic-gate 			return (error);
7740Sstevel@tonic-gate 		}
7750Sstevel@tonic-gate 	}
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	/*
7780Sstevel@tonic-gate 	 * Enter the file in the string hash table.
7790Sstevel@tonic-gate 	 */
7800Sstevel@tonic-gate 	if ((ent = enterfile(crle, path, file, flags, dent, status)) == 0) {
7810Sstevel@tonic-gate 		(void) elf_end(elf);
7820Sstevel@tonic-gate 		return (error);
7830Sstevel@tonic-gate 	}
7840Sstevel@tonic-gate 	obj = ent->e_obj;
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	if (flags & RTC_OBJ_ALTER) {
7870Sstevel@tonic-gate 		/*
7880Sstevel@tonic-gate 		 * If this object is marked as non-dumpable make sure we don't
7890Sstevel@tonic-gate 		 * create a dldump(3dl) alternative.  A user requested
7900Sstevel@tonic-gate 		 * alternative is acceptable.
7910Sstevel@tonic-gate 		 */
7920Sstevel@tonic-gate 		if ((flags & RTC_OBJ_DUMP) && (dyflags & DF_1_NODUMP)) {
7930Sstevel@tonic-gate 			obj->o_flags |= RTC_OBJ_NOALTER;
7940Sstevel@tonic-gate 			obj->o_flags &= ~(RTC_OBJ_ALTER | RTC_OBJ_DUMP);
7950Sstevel@tonic-gate 		} else {
7960Sstevel@tonic-gate 			if (enteralt(crle, path, file, flags, obj) == 0) {
7970Sstevel@tonic-gate 				(void) elf_end(elf);
7980Sstevel@tonic-gate 				return (error);
7990Sstevel@tonic-gate 			}
8000Sstevel@tonic-gate 		}
8010Sstevel@tonic-gate 	}
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	/*
8040Sstevel@tonic-gate 	 * Executables are recorded in the configuration file either to allow
8050Sstevel@tonic-gate 	 * for the configuration files update, or may indicate that the
8060Sstevel@tonic-gate 	 * configuration file is specific to their use.
8070Sstevel@tonic-gate 	 */
8080Sstevel@tonic-gate 	if (ehdr.e_type == ET_EXEC) {
8090Sstevel@tonic-gate 		obj->o_flags |= RTC_OBJ_EXEC;
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 		if ((flags & RTC_OBJ_DUMP) &&
8120Sstevel@tonic-gate 		    (crle->c_dlflags & RTLD_REL_EXEC)) {
8130Sstevel@tonic-gate 			/*
8140Sstevel@tonic-gate 			 * Get the reallocated pathname rather than using the
8150Sstevel@tonic-gate 			 * original (the original might be from an existing
8160Sstevel@tonic-gate 			 * configuration file being updated, in which case the
8170Sstevel@tonic-gate 			 * pointer will be unmapped before we get to use it).
8180Sstevel@tonic-gate 			 */
8190Sstevel@tonic-gate 			ent = get_hash(crle->c_strtbl, (Addr)path, 0,
8200Sstevel@tonic-gate 			    HASH_FND_ENT);
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 			obj->o_flags |= RTC_OBJ_APP;
8230Sstevel@tonic-gate 			crle->c_app = (char *)ent->e_key;
8240Sstevel@tonic-gate 		}
8250Sstevel@tonic-gate 	}
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	/*
8280Sstevel@tonic-gate 	 * If we've been asked to process this object as a group determine its
8290Sstevel@tonic-gate 	 * dependencies.
8300Sstevel@tonic-gate 	 */
8310Sstevel@tonic-gate 	if (flags & RTC_OBJ_GROUP) {
8320Sstevel@tonic-gate 		if (depend(crle, path, flags, &ehdr)) {
8330Sstevel@tonic-gate 			(void) elf_end(elf);
8340Sstevel@tonic-gate 			return (error);
8350Sstevel@tonic-gate 		}
8360Sstevel@tonic-gate 	}
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	(void) elf_end(elf);
8390Sstevel@tonic-gate 	return (0);
8400Sstevel@tonic-gate }
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate /*
8440Sstevel@tonic-gate  * Add a directory to configuration information.
8450Sstevel@tonic-gate  */
8460Sstevel@tonic-gate static int
8470Sstevel@tonic-gate inspect_dir(Crle_desc * crle, const char *name, Half flags, struct stat *status)
8480Sstevel@tonic-gate {
8490Sstevel@tonic-gate 	Hash_tbl *	stbl = crle->c_strtbl;
8500Sstevel@tonic-gate 	DIR *		dir;
8510Sstevel@tonic-gate 	struct dirent	*dirent;
8520Sstevel@tonic-gate 	Hash_ent *	ent;
8530Sstevel@tonic-gate 	int		error = 0;
8540Sstevel@tonic-gate 	struct stat	_status;
8550Sstevel@tonic-gate 	char		path[PATH_MAX], * dst;
8560Sstevel@tonic-gate 	const char	*src;
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	/*
8590Sstevel@tonic-gate 	 * Determine whether we've already visited this directory to process
8600Sstevel@tonic-gate 	 * all its entries.
8610Sstevel@tonic-gate 	 */
8620Sstevel@tonic-gate 	if ((ent = get_hash(stbl, (Addr)name, 0, HASH_FND_ENT)) != 0) {
8630Sstevel@tonic-gate 		if (ent->e_obj->o_flags & RTC_OBJ_ALLENTS)
8640Sstevel@tonic-gate 			return (0);
8650Sstevel@tonic-gate 	} else {
8660Sstevel@tonic-gate 		/*
8670Sstevel@tonic-gate 		 * Create a directory hash entry.
8680Sstevel@tonic-gate 		 */
8690Sstevel@tonic-gate 		if ((ent = enterdir(crle, name, (flags | RTC_OBJ_ALLENTS),
8700Sstevel@tonic-gate 		    status)) == 0)
8710Sstevel@tonic-gate 			return (1);
8720Sstevel@tonic-gate 	}
8730Sstevel@tonic-gate 	ent->e_obj->o_flags |= RTC_OBJ_ALLENTS;
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	/*
8760Sstevel@tonic-gate 	 * Establish the pathname buffer.
8770Sstevel@tonic-gate 	 */
8780Sstevel@tonic-gate 	for (dst = path, dst--, src = name; *src; src++)
8790Sstevel@tonic-gate 		*++dst = *src;
8800Sstevel@tonic-gate 	if (*dst++ != '/')
8810Sstevel@tonic-gate 		*dst++ = '/';
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	/*
8840Sstevel@tonic-gate 	 * Access the directory in preparation for reading its entries.
8850Sstevel@tonic-gate 	 */
8860Sstevel@tonic-gate 	if ((dir = opendir(name)) == 0)
8870Sstevel@tonic-gate 		return (1);
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	/*
8900Sstevel@tonic-gate 	 * Read each entry from the directory looking for ELF files.
8910Sstevel@tonic-gate 	 */
8920Sstevel@tonic-gate 	while ((dirent = readdir(dir)) != NULL) {
8930Sstevel@tonic-gate 		const char	*file = dirent->d_name;
8940Sstevel@tonic-gate 		char		*_dst;
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 		/*
8970Sstevel@tonic-gate 		 * Ignore "." and ".." entries.
8980Sstevel@tonic-gate 		 */
8990Sstevel@tonic-gate 		if ((file[0] == '.') && ((file[1] == '\0') ||
9000Sstevel@tonic-gate 		    ((file[1] == '.') && (file[2] == '\0'))))
9010Sstevel@tonic-gate 			continue;
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 		/*
9040Sstevel@tonic-gate 		 * Complete full pathname, and reassign file to the new path.
9050Sstevel@tonic-gate 		 */
9060Sstevel@tonic-gate 		for (_dst = dst, src = file, file = dst; *src; _dst++, src++)
9070Sstevel@tonic-gate 			*_dst = *src;
9080Sstevel@tonic-gate 		*_dst = '\0';
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 		if (stat(path, &_status) == -1)
9110Sstevel@tonic-gate 			continue;
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 		if ((_status.st_mode & S_IFMT) != S_IFREG)
9140Sstevel@tonic-gate 			continue;
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 		if (inspect_file(crle, path, file, flags, ent, &_status, 0)) {
9170Sstevel@tonic-gate 			error = 1;
9180Sstevel@tonic-gate 			break;
9190Sstevel@tonic-gate 		}
9200Sstevel@tonic-gate 	}
9210Sstevel@tonic-gate 	return (error);
9220Sstevel@tonic-gate }
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate /*
9260Sstevel@tonic-gate  * Inspect a file/dir name.  A stat(name) results in the following actions:
9270Sstevel@tonic-gate  *
9280Sstevel@tonic-gate  * The name doesn't exist:
9290Sstevel@tonic-gate  *	The name is assummed to be a non-existent directory and a directory
9300Sstevel@tonic-gate  *	cache entry is created to indicate this.
9310Sstevel@tonic-gate  *
9320Sstevel@tonic-gate  * The name is a directory:
9330Sstevel@tonic-gate  *	The directory is searched for appropriate files.
9340Sstevel@tonic-gate  *
9350Sstevel@tonic-gate  * The name is a file:
9360Sstevel@tonic-gate  *	The file is processed and added to the cache if appropriate.
9370Sstevel@tonic-gate  */
9380Sstevel@tonic-gate int
9390Sstevel@tonic-gate inspect(Crle_desc * crle, const char *name, Half flags)
9400Sstevel@tonic-gate {
9410Sstevel@tonic-gate 	Hash_ent *	ent;
9420Sstevel@tonic-gate 	const char	*file, * dir;
9430Sstevel@tonic-gate 	struct stat	status;
9440Sstevel@tonic-gate 	char		_name[PATH_MAX], _dir[PATH_MAX];
9450Sstevel@tonic-gate 	Half		nflags = flags & ~RTC_OBJ_CMDLINE;
9460Sstevel@tonic-gate 	int		noexist;
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	/*
9490Sstevel@tonic-gate 	 * If this is the first time through here establish a string table
9500Sstevel@tonic-gate 	 * cache.
9510Sstevel@tonic-gate 	 */
9520Sstevel@tonic-gate 	if (crle->c_dirnum == 0) {
9530Sstevel@tonic-gate 		if ((crle->c_strtbl = make_hash(crle->c_strbkts,
9540Sstevel@tonic-gate 		    HASH_STR, 0)) == 0)
9550Sstevel@tonic-gate 			return (1);
9560Sstevel@tonic-gate 		crle->c_dirnum = 1;
9570Sstevel@tonic-gate 	}
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	if (crle->c_flags & CRLE_VERBOSE)
9600Sstevel@tonic-gate 		(void) printf(MSG_INTL(MSG_DIA_INSPECT), name);
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	/*
9630Sstevel@tonic-gate 	 * Determine whether the name exists.
9640Sstevel@tonic-gate 	 */
9650Sstevel@tonic-gate 	if ((noexist = stat(name, &status)) != 0) {
9660Sstevel@tonic-gate 		if (errno != ENOENT) {
9670Sstevel@tonic-gate 			int err = errno;
9680Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_STAT),
9690Sstevel@tonic-gate 			    crle->c_name, name, strerror(err));
9700Sstevel@tonic-gate 			return (1);
9710Sstevel@tonic-gate 		} else {
9720Sstevel@tonic-gate 			/*
9730Sstevel@tonic-gate 			 * If we've been asked to create an alternative object
9740Sstevel@tonic-gate 			 * assume the object is a file and create a valid
9750Sstevel@tonic-gate 			 * alternative entry.  This allows the creation of
9760Sstevel@tonic-gate 			 * alternatives for files that might not yet be
9770Sstevel@tonic-gate 			 * installed.
9780Sstevel@tonic-gate 			 *
9790Sstevel@tonic-gate 			 * Otherwise we have no idea whether the name specified
9800Sstevel@tonic-gate 			 * is a file or directory, so we assume a directory and
9810Sstevel@tonic-gate 			 * establish an object descriptor to mark this as
9820Sstevel@tonic-gate 			 * non-existent. This allows us to mark things like
9830Sstevel@tonic-gate 			 * platform specific directories as non-existent.
9840Sstevel@tonic-gate 			 */
9850Sstevel@tonic-gate 			if ((flags & (RTC_OBJ_DUMP | RTC_OBJ_ALTER)) !=
9860Sstevel@tonic-gate 			    RTC_OBJ_ALTER) {
9870Sstevel@tonic-gate 				if ((ent = enternoexistdir(crle, name)) == 0)
9880Sstevel@tonic-gate 					return (1);
9890Sstevel@tonic-gate 				ent->e_flags |= flags;
9900Sstevel@tonic-gate 				return (0);
9910Sstevel@tonic-gate 			}
9920Sstevel@tonic-gate 		}
9930Sstevel@tonic-gate 	}
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 	/*
9960Sstevel@tonic-gate 	 * Determine whether we're dealing with a directory or a file.
9970Sstevel@tonic-gate 	 */
9980Sstevel@tonic-gate 	if ((noexist == 0) && ((status.st_mode & S_IFMT) == S_IFDIR)) {
9990Sstevel@tonic-gate 		/*
10000Sstevel@tonic-gate 		 * Process the directory name to collect its shared objects into
10010Sstevel@tonic-gate 		 * the configuration file.
10020Sstevel@tonic-gate 		 */
10030Sstevel@tonic-gate 		if (inspect_dir(crle, name, nflags, &status))
10040Sstevel@tonic-gate 			return (1);
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 		ent = get_hash(crle->c_strtbl, (Addr)name, 0, HASH_FND_ENT);
10070Sstevel@tonic-gate 		ent->e_flags |= flags;
10080Sstevel@tonic-gate 		return (0);
10090Sstevel@tonic-gate 	}
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	/*
10120Sstevel@tonic-gate 	 * If this isn't a regular file we might as well bail now.  Note that
10130Sstevel@tonic-gate 	 * even if it is, we might still reject the file if it's not ELF later
10140Sstevel@tonic-gate 	 * in inspect_file().
10150Sstevel@tonic-gate 	 */
10160Sstevel@tonic-gate 	if ((noexist == 0) && ((status.st_mode & S_IFMT) != S_IFREG)) {
10170Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_GEN_INVFILE), crle->c_name,
10180Sstevel@tonic-gate 		    name);
10190Sstevel@tonic-gate 		return (1);
10200Sstevel@tonic-gate 	}
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	/*
10230Sstevel@tonic-gate 	 * Break the pathname into directory and filename components.
10240Sstevel@tonic-gate 	 */
10250Sstevel@tonic-gate 	if ((file = strrchr(name, '/')) == 0) {
10260Sstevel@tonic-gate 		dir = MSG_ORIG(MSG_DIR_DOT);
10270Sstevel@tonic-gate 		(void) strcpy(_name, MSG_ORIG(MSG_PTH_DOT));
10280Sstevel@tonic-gate 		(void) strcpy(&_name[MSG_PTH_DOT_SIZE], name);
10290Sstevel@tonic-gate 		name = (const char *)_name;
10300Sstevel@tonic-gate 		file = (const char *)&_name[MSG_PTH_DOT_SIZE];
10310Sstevel@tonic-gate 	} else {
10320Sstevel@tonic-gate 		size_t	off = file - name;
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 		if (file == name)
10350Sstevel@tonic-gate 			dir = MSG_ORIG(MSG_DIR_ROOT);
10360Sstevel@tonic-gate 		else {
10370Sstevel@tonic-gate 			(void) strncpy(_dir, name, off);
10380Sstevel@tonic-gate 			_dir[off] = '\0';
10390Sstevel@tonic-gate 			dir = (const char *)_dir;
10400Sstevel@tonic-gate 		}
10410Sstevel@tonic-gate 		file++;
10420Sstevel@tonic-gate 	}
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	/*
10450Sstevel@tonic-gate 	 * Determine whether we've already visited this directory and if not
10460Sstevel@tonic-gate 	 * create it.
10470Sstevel@tonic-gate 	 */
10480Sstevel@tonic-gate 	if ((ent = get_hash(crle->c_strtbl, (Addr)dir, 0, HASH_FND_ENT)) == 0) {
10490Sstevel@tonic-gate 		struct stat	_status;
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 		if (stat(dir, &_status) != 0) {
10520Sstevel@tonic-gate 			if (errno != ENOENT) {
10530Sstevel@tonic-gate 				int err = errno;
10540Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_STAT),
10550Sstevel@tonic-gate 				    crle->c_name, name, strerror(err));
10560Sstevel@tonic-gate 				return (1);
10570Sstevel@tonic-gate 			} else {
10580Sstevel@tonic-gate 				/*
10590Sstevel@tonic-gate 				 * Note that this directory will be tagged as
10600Sstevel@tonic-gate 				 * having an alternative - not that the
10610Sstevel@tonic-gate 				 * directory does, but supposedly it contains
10620Sstevel@tonic-gate 				 * a file that does.
10630Sstevel@tonic-gate 				 */
10640Sstevel@tonic-gate 				if ((ent = enternoexistdir(crle, dir)) == 0)
10650Sstevel@tonic-gate 					return (1);
10660Sstevel@tonic-gate 				ent->e_flags |= nflags;
10670Sstevel@tonic-gate 			}
10680Sstevel@tonic-gate 		} else {
10690Sstevel@tonic-gate 			if ((ent = enterdir(crle, dir, nflags, &_status)) == 0)
10700Sstevel@tonic-gate 				return (1);
10710Sstevel@tonic-gate 		}
10720Sstevel@tonic-gate 	}
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 	/*
10750Sstevel@tonic-gate 	 * Regardless of whether we've already processed this file (say from
10760Sstevel@tonic-gate 	 * an RTC_OBJ_ALLENTS which we could determine from the above), continue
10770Sstevel@tonic-gate 	 * to inspect the file.  It may require alternatives or something that
10780Sstevel@tonic-gate 	 * hadn't be specified from the directory entry.
10790Sstevel@tonic-gate 	 */
10800Sstevel@tonic-gate 	if (noexist) {
10810Sstevel@tonic-gate 		if ((ent = enternoexistfile(crle, name, file, ent)) == 0)
10820Sstevel@tonic-gate 			return (1);
10830Sstevel@tonic-gate 		ent->e_flags |= nflags;
10840Sstevel@tonic-gate 		if (enteralt(crle, name, file, flags, ent->e_obj) == 0)
10850Sstevel@tonic-gate 			return (1);
10860Sstevel@tonic-gate 	} else {
10870Sstevel@tonic-gate 		if (inspect_file(crle, name, file, nflags, ent, &status, 1))
10880Sstevel@tonic-gate 			return (1);
10890Sstevel@tonic-gate 	}
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 	/*
10920Sstevel@tonic-gate 	 * Make sure to propagate any RTC_OBJ_CMDLINE flag.
10930Sstevel@tonic-gate 	 */
10940Sstevel@tonic-gate 	if (ent = get_hash(crle->c_strtbl, (Addr)name, 0, HASH_FND_ENT))
10950Sstevel@tonic-gate 		ent->e_flags |= (flags & RTC_OBJ_CMDLINE);
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	return (0);
10980Sstevel@tonic-gate }
1099