xref: /onnv-gate/usr/src/cmd/sgs/crle/common/crle.c (revision 238:265780cf7e76)
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 /*
23*238Sseizo  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include	<sys/types.h>
290Sstevel@tonic-gate #include	<sys/stat.h>
300Sstevel@tonic-gate #include	<fcntl.h>
310Sstevel@tonic-gate #include	<stdio.h>
320Sstevel@tonic-gate #include	<string.h>
330Sstevel@tonic-gate #include	<unistd.h>
340Sstevel@tonic-gate #include	<locale.h>
350Sstevel@tonic-gate #include	<dlfcn.h>
360Sstevel@tonic-gate #include	<errno.h>
370Sstevel@tonic-gate #include	"_crle.h"
380Sstevel@tonic-gate #include	"msg.h"
390Sstevel@tonic-gate 
400Sstevel@tonic-gate 
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate  * crle(1) entry point and argument processing.
430Sstevel@tonic-gate  *
440Sstevel@tonic-gate  * Two passes of the arguments are carried out; the first collects any single
450Sstevel@tonic-gate  * instance options and establishes defaults that might be appropriate for
460Sstevel@tonic-gate  * other arguments:
470Sstevel@tonic-gate  *
480Sstevel@tonic-gate  *  -64		operate on, or apply, 64-bit objects (default is 32-bit).
490Sstevel@tonic-gate  *
500Sstevel@tonic-gate  *  -c file	defines the output configuration file.
510Sstevel@tonic-gate  *
520Sstevel@tonic-gate  *  -f flag	flags for dldump(3dl).
530Sstevel@tonic-gate  *
540Sstevel@tonic-gate  *  -o dir	defines the output directory for any dldump(3dl) objects
550Sstevel@tonic-gate  *		that follow.  For backward compatibility (RTC_VER_ONE only
560Sstevel@tonic-gate  * 		allowed one output directory) allow the first occurrence of this
570Sstevel@tonic-gate  *		specification to catch any previous files.  If not specified,
580Sstevel@tonic-gate  *		the configuration files parent directory is used).
590Sstevel@tonic-gate  *
600Sstevel@tonic-gate  *  -u		update any existing configuration file.  Any additional
610Sstevel@tonic-gate  *		arguments supplied will be added to the new configuration
620Sstevel@tonic-gate  *		information.
630Sstevel@tonic-gate  *
640Sstevel@tonic-gate  *  -v		verbose mode.
650Sstevel@tonic-gate  *
660Sstevel@tonic-gate  * The second pass collects all other options and constructs an internal
670Sstevel@tonic-gate  * string table which will be used to create the eventual configuration file.
680Sstevel@tonic-gate  *
690Sstevel@tonic-gate  *  -a name	add the individual name, with an alternative to the
700Sstevel@tonic-gate  *		configuration cache.  No alternative is created via dldump(3dl),
710Sstevel@tonic-gate  *		it is the users responsibility to furnish the alternative.
720Sstevel@tonic-gate  *
730Sstevel@tonic-gate  *  -A name	add the individual name, with an optional alternative to the
740Sstevel@tonic-gate  *		configuration cache.  No alternative is created via dldump(3dl),
750Sstevel@tonic-gate  *		it is the users responsibility to furnish the alternative.
760Sstevel@tonic-gate  *
770Sstevel@tonic-gate  *  -e envar	replaceable environment variable
780Sstevel@tonic-gate  *
790Sstevel@tonic-gate  *  -E envar	permanent environment variable
800Sstevel@tonic-gate  *
810Sstevel@tonic-gate  *  -i name	add the individual name to the configuration cache.  If name
820Sstevel@tonic-gate  *		is a directory each shared object within the directory is added
830Sstevel@tonic-gate  *		to the cache.
840Sstevel@tonic-gate  *
850Sstevel@tonic-gate  *  -I name	same as -i, but in addition any ELF objects are dldump(3dl)'ed.
860Sstevel@tonic-gate  *
870Sstevel@tonic-gate  *  -g name	add the group name to the configuration cache.  Each object is
880Sstevel@tonic-gate  * 		expanded to determine its dependencies and these are added to
890Sstevel@tonic-gate  *		the cache.  If name is a directory each shared object within the
900Sstevel@tonic-gate  *		directory and its dependencies are added to the cache.
910Sstevel@tonic-gate  *
920Sstevel@tonic-gate  *  -G app	same as -g, but in addition any ELF objects are dldump(3dl)'ed.
930Sstevel@tonic-gate  *
940Sstevel@tonic-gate  *  -l dir	library search directory
950Sstevel@tonic-gate  *
960Sstevel@tonic-gate  *  -s dir	trusted (secure) directory
970Sstevel@tonic-gate  *
980Sstevel@tonic-gate  *  -t type	search directory type (ELF or AOUT).
990Sstevel@tonic-gate  */
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate /*
1020Sstevel@tonic-gate  * Establish a structure for maintaining current object directory attributes.
1030Sstevel@tonic-gate  * We wish to validate the access of any object directory that will be written
1040Sstevel@tonic-gate  * to (dldump(3dl), and thus by maintaining a current object directory and its
1050Sstevel@tonic-gate  * intended use we can perform this validation later.
1060Sstevel@tonic-gate  */
1070Sstevel@tonic-gate typedef struct {
1080Sstevel@tonic-gate 	char		*o_objdir;
1090Sstevel@tonic-gate 	unsigned int	o_flags;
1100Sstevel@tonic-gate } Objdir;
1110Sstevel@tonic-gate 
112*238Sseizo int
1130Sstevel@tonic-gate main(int argc, char ** argv)
1140Sstevel@tonic-gate {
1150Sstevel@tonic-gate 	Crle_desc	crle = { 0 };
1160Sstevel@tonic-gate 	int		c, error = 0;
1170Sstevel@tonic-gate 	char **		lib;
1180Sstevel@tonic-gate 	List		objdirs = { 0, 0 };
1190Sstevel@tonic-gate 	Objdir		_lobjdir = { 0, 0 }, * lobjdir = &_lobjdir;
1200Sstevel@tonic-gate 	struct stat	ostatus, nstatus;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	if (list_append(&objdirs, lobjdir) == 0)
1230Sstevel@tonic-gate 		return (1);
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	/*
1260Sstevel@tonic-gate 	 * Establish locale.
1270Sstevel@tonic-gate 	 */
1280Sstevel@tonic-gate 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
1290Sstevel@tonic-gate 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 	/*
1320Sstevel@tonic-gate 	 * Initialization configuration information.
1330Sstevel@tonic-gate 	 */
1340Sstevel@tonic-gate 	crle.c_name = argv[0];
1350Sstevel@tonic-gate 	crle.c_strbkts = 503;
1360Sstevel@tonic-gate 	crle.c_inobkts = 251;
1370Sstevel@tonic-gate 	crle.c_class = ELFCLASS32;
1380Sstevel@tonic-gate 	crle.c_machine = M_MACH;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 	/*
1410Sstevel@tonic-gate 	 * First argument pass.
1420Sstevel@tonic-gate 	 */
1430Sstevel@tonic-gate 	while ((c = getopt(argc, argv, MSG_ORIG(MSG_ARG_OPTIONS))) != -1) {
1440Sstevel@tonic-gate 		switch (c) {
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 		case '6':			/* operate on 64-bit objects */
1470Sstevel@tonic-gate 			if (optarg[0] != '4') {
1480Sstevel@tonic-gate 				(void) fprintf(stderr,
1490Sstevel@tonic-gate 				    MSG_INTL(MSG_ARG_ILLEGAL), crle.c_name,
1500Sstevel@tonic-gate 				    MSG_ORIG(MSG_ARG_6), optarg);
1510Sstevel@tonic-gate 				error = 1;
1520Sstevel@tonic-gate 			}
1530Sstevel@tonic-gate 			crle.c_class = ELFCLASS64;
1540Sstevel@tonic-gate #if	defined(sparc)
1550Sstevel@tonic-gate 			crle.c_machine = EM_SPARCV9;
1560Sstevel@tonic-gate #elif	defined(i386)
1570Sstevel@tonic-gate 			crle.c_machine = EM_IA_64;
1580Sstevel@tonic-gate #endif
1590Sstevel@tonic-gate 			break;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 		case 'A':			/* create optional */
1620Sstevel@tonic-gate 			/* FALLTHROUGH */	/*	alternative */
1630Sstevel@tonic-gate 		case 'a':			/* create alternative */
1640Sstevel@tonic-gate 			crle.c_flags |= (CRLE_CREAT | CRLE_ALTER);
1650Sstevel@tonic-gate 			lobjdir->o_flags |= (CRLE_CREAT | CRLE_ALTER);
1660Sstevel@tonic-gate 			break;
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 		case 'c':			/* define the config file */
1690Sstevel@tonic-gate 			if (crle.c_confil) {
1700Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ARG_MULT),
1710Sstevel@tonic-gate 				    crle.c_name, MSG_ORIG(MSG_ARG_C));
1720Sstevel@tonic-gate 				error = 1;
1730Sstevel@tonic-gate 			}
1740Sstevel@tonic-gate 			crle.c_confil = optarg;
1750Sstevel@tonic-gate 			break;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 		case 'e':			/* replaceable env variable */
1780Sstevel@tonic-gate 			crle.c_flags |= (CRLE_RPLENV | CRLE_CREAT);
1790Sstevel@tonic-gate 			break;
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 		case 'E':			/* permanent env variable */
1820Sstevel@tonic-gate 			crle.c_flags |= (CRLE_PRMENV | CRLE_CREAT);
1830Sstevel@tonic-gate 			break;
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 		case 'f':			/* dldump(3dl) flags */
1860Sstevel@tonic-gate 			if (crle.c_dlflags) {
1870Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ARG_MULT),
1880Sstevel@tonic-gate 				    crle.c_name, MSG_ORIG(MSG_ARG_F));
1890Sstevel@tonic-gate 				error = 1;
1900Sstevel@tonic-gate 			}
1910Sstevel@tonic-gate 			if ((crle.c_dlflags = dlflags(&crle,
1920Sstevel@tonic-gate 			    (const char *)optarg)) == 0)
1930Sstevel@tonic-gate 				error = 1;
1940Sstevel@tonic-gate 			break;
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 		case 'G':			/* group object */
1970Sstevel@tonic-gate 			crle.c_flags |= (CRLE_DUMP | CRLE_ALTER);
1980Sstevel@tonic-gate 			lobjdir->o_flags |= (CRLE_DUMP | CRLE_ALTER);
1990Sstevel@tonic-gate 			/* FALLTHROUGH */
2000Sstevel@tonic-gate 		case 'g':
2010Sstevel@tonic-gate 			crle.c_flags |= CRLE_CREAT;
2020Sstevel@tonic-gate 			lobjdir->o_flags |= CRLE_CREAT;
2030Sstevel@tonic-gate 			break;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 		case 'I':			/* individual object */
2060Sstevel@tonic-gate 			crle.c_flags |= (CRLE_DUMP | CRLE_ALTER);
2070Sstevel@tonic-gate 			lobjdir->o_flags |= (CRLE_DUMP | CRLE_ALTER);
2080Sstevel@tonic-gate 			/* FALLTHROUGH */
2090Sstevel@tonic-gate 		case 'i':
2100Sstevel@tonic-gate 			crle.c_flags |= CRLE_CREAT;
2110Sstevel@tonic-gate 			lobjdir->o_flags |= CRLE_CREAT;
2120Sstevel@tonic-gate 			break;
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 		case 'l':			/* library search path */
2150Sstevel@tonic-gate 			if (crle.c_flags & CRLE_AOUT)
2160Sstevel@tonic-gate 				crle.c_flags |= CRLE_ADLIB;
2170Sstevel@tonic-gate 			else
2180Sstevel@tonic-gate 				crle.c_flags |= CRLE_EDLIB;
2190Sstevel@tonic-gate 			crle.c_flags |= CRLE_CREAT;
2200Sstevel@tonic-gate 			break;
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 		case 'o':			/* define an object directory */
2230Sstevel@tonic-gate 			if (lobjdir->o_objdir) {
2240Sstevel@tonic-gate 				if ((lobjdir = calloc(sizeof (Objdir), 1)) == 0)
2250Sstevel@tonic-gate 					return (1);
2260Sstevel@tonic-gate 				if (list_append(&objdirs, lobjdir) == 0)
2270Sstevel@tonic-gate 					return (1);
2280Sstevel@tonic-gate 			}
2290Sstevel@tonic-gate 			lobjdir->o_objdir = optarg;
2300Sstevel@tonic-gate 			break;
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 		case 's':			/* trusted (secure) path */
2330Sstevel@tonic-gate 			if (crle.c_flags & CRLE_AOUT)
2340Sstevel@tonic-gate 				crle.c_flags |= CRLE_ASLIB;
2350Sstevel@tonic-gate 			else
2360Sstevel@tonic-gate 				crle.c_flags |= CRLE_ESLIB;
2370Sstevel@tonic-gate 			crle.c_flags |= CRLE_CREAT;
2380Sstevel@tonic-gate 			break;
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 		case 't':			/* search path type */
2410Sstevel@tonic-gate 			if (strcmp((const char *)optarg,
2420Sstevel@tonic-gate 			    MSG_ORIG(MSG_STR_ELF)) == 0)
2430Sstevel@tonic-gate 				crle.c_flags &= ~CRLE_AOUT;
2440Sstevel@tonic-gate 			else if (strcmp((const char *)optarg,
2450Sstevel@tonic-gate 			    MSG_ORIG(MSG_STR_AOUT)) == 0)
2460Sstevel@tonic-gate 				crle.c_flags |= CRLE_AOUT;
2470Sstevel@tonic-gate 			else {
2480Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ARG_TYPE),
2490Sstevel@tonic-gate 				    crle.c_name, optarg);
2500Sstevel@tonic-gate 				error = 1;
2510Sstevel@tonic-gate 			}
2520Sstevel@tonic-gate 			break;
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 		case 'u':			/* update mode */
2550Sstevel@tonic-gate 			crle.c_flags |= (CRLE_CREAT | CRLE_UPDATE);
2560Sstevel@tonic-gate 			break;
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 		case 'v':			/* verbose mode */
2590Sstevel@tonic-gate 			crle.c_flags |= CRLE_VERBOSE;
2600Sstevel@tonic-gate 			break;
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 		default:
2630Sstevel@tonic-gate 			error = 2;
2640Sstevel@tonic-gate 		}
2650Sstevel@tonic-gate 	}
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	if (optind != argc)
2680Sstevel@tonic-gate 		error = 2;
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	/*
2710Sstevel@tonic-gate 	 * Determine the configuration file, which in the case of an existing
2720Sstevel@tonic-gate 	 * error condition is required in the final error message.
2730Sstevel@tonic-gate 	 */
2740Sstevel@tonic-gate 	if (crle.c_confil == 0) {
2750Sstevel@tonic-gate 		crle.c_flags |= CRLE_CONFDEF;
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 		if (crle.c_class == ELFCLASS32)
2780Sstevel@tonic-gate 			crle.c_confil = (char *)MSG_ORIG(MSG_PTH_CONFIG);
2790Sstevel@tonic-gate 		else
2800Sstevel@tonic-gate 			crle.c_confil = (char *)MSG_ORIG(MSG_PTH_CONFIG_64);
2810Sstevel@tonic-gate 	}
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	/*
2840Sstevel@tonic-gate 	 * Now that we've generated as many file/directory processing errors
2850Sstevel@tonic-gate 	 * as we can, return if any fatal error conditions occurred.
2860Sstevel@tonic-gate 	 */
2870Sstevel@tonic-gate 	if (error) {
2880Sstevel@tonic-gate 		if (error == 2) {
2890Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ARG_USAGE),
2900Sstevel@tonic-gate 			    crle.c_name);
2910Sstevel@tonic-gate 		} else if (crle.c_flags & CRLE_CREAT) {
2920Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_GEN_CREATE),
2930Sstevel@tonic-gate 			    crle.c_name, crle.c_confil);
2940Sstevel@tonic-gate 		}
2950Sstevel@tonic-gate 		return (1);
2960Sstevel@tonic-gate 	}
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	/*
2990Sstevel@tonic-gate 	 * Apply any additional defaults.
3000Sstevel@tonic-gate 	 */
3010Sstevel@tonic-gate 	if (crle.c_dlflags == 0)
3020Sstevel@tonic-gate 		crle.c_dlflags = RTLD_REL_RELATIVE;
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	crle.c_audit = (char *)MSG_ORIG(MSG_ENV_LD_AUDIT);
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	(void) elf_version(EV_CURRENT);
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	/*
3090Sstevel@tonic-gate 	 * If we're updating an existing file or not creating a configuration
3100Sstevel@tonic-gate 	 * file at all, investigate the original.
3110Sstevel@tonic-gate 	 */
3120Sstevel@tonic-gate 	if ((crle.c_flags & CRLE_UPDATE) ||
3130Sstevel@tonic-gate 	    ((crle.c_flags & CRLE_CREAT) == 0)) {
3140Sstevel@tonic-gate 		if (inspectconfig(&crle))
3150Sstevel@tonic-gate 			return (1);
3160Sstevel@tonic-gate 		if ((crle.c_flags & CRLE_UPDATE) == 0)
3170Sstevel@tonic-gate 			return (0);
3180Sstevel@tonic-gate 	}
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	if (crle.c_flags & CRLE_VERBOSE)
3210Sstevel@tonic-gate 		(void) printf(MSG_INTL(MSG_DIA_CONFILE), crle.c_confil);
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	/*
3240Sstevel@tonic-gate 	 * Make sure the configuration file is accessible.  Stat the file to
3250Sstevel@tonic-gate 	 * determine its dev number - this is used to determine whether the
3260Sstevel@tonic-gate 	 * temporary configuration file we're about to build can be renamed or
3270Sstevel@tonic-gate 	 * must be copied to its final destination.
3280Sstevel@tonic-gate 	 */
3290Sstevel@tonic-gate 	(void) umask(022);
3300Sstevel@tonic-gate 	if (access(crle.c_confil, (R_OK | W_OK)) == 0) {
3310Sstevel@tonic-gate 		crle.c_flags |= CRLE_EXISTS;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 		if (stat(crle.c_confil, &ostatus) != 0) {
3340Sstevel@tonic-gate 			int err = errno;
3350Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
3360Sstevel@tonic-gate 			    crle.c_name, crle.c_confil, strerror(err));
3370Sstevel@tonic-gate 			return (1);
3380Sstevel@tonic-gate 		}
3390Sstevel@tonic-gate 	} else if (errno != ENOENT) {
3400Sstevel@tonic-gate 		int err = errno;
3410Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_ACCESS), crle.c_name,
3420Sstevel@tonic-gate 		    crle.c_confil, strerror(err));
3430Sstevel@tonic-gate 		return (1);
3440Sstevel@tonic-gate 	} else {
3450Sstevel@tonic-gate 		int	fd;
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 		/*
3480Sstevel@tonic-gate 		 * Try opening the file now, if it works delete it, there may
3490Sstevel@tonic-gate 		 * be a lot of processing ahead of us, so we'll come back and
3500Sstevel@tonic-gate 		 * create the real thing later.
3510Sstevel@tonic-gate 		 */
3520Sstevel@tonic-gate 		if ((fd = open(crle.c_confil, (O_RDWR | O_CREAT | O_TRUNC),
3530Sstevel@tonic-gate 		    0666)) == -1) {
3540Sstevel@tonic-gate 			int err = errno;
3550Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
3560Sstevel@tonic-gate 			    crle.c_name, crle.c_confil, strerror(err));
3570Sstevel@tonic-gate 			return (1);
3580Sstevel@tonic-gate 		}
3590Sstevel@tonic-gate 		if (fstat(fd, &ostatus) != 0) {
3600Sstevel@tonic-gate 			int err = errno;
3610Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
3620Sstevel@tonic-gate 			    crle.c_name, crle.c_confil, strerror(err));
3630Sstevel@tonic-gate 			return (1);
3640Sstevel@tonic-gate 		}
3650Sstevel@tonic-gate 		(void) close(fd);
3660Sstevel@tonic-gate 		(void) unlink(crle.c_confil);
3670Sstevel@tonic-gate 	}
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	/*
3700Sstevel@tonic-gate 	 * If an object directory is required to hold dldump(3dl) output assign
3710Sstevel@tonic-gate 	 * a default if necessary and insure we're able to write there.
3720Sstevel@tonic-gate 	 */
3730Sstevel@tonic-gate 	if (crle.c_flags & CRLE_ALTER) {
3740Sstevel@tonic-gate 		if (lobjdir->o_objdir == 0) {
3750Sstevel@tonic-gate 			char	*str;
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 			/*
3780Sstevel@tonic-gate 			 * Use the configuration files directory.
3790Sstevel@tonic-gate 			 */
3800Sstevel@tonic-gate 			if ((str = strrchr(crle.c_confil, '/')) == NULL)
3810Sstevel@tonic-gate 				lobjdir->o_objdir =
3820Sstevel@tonic-gate 				    (char *)MSG_ORIG(MSG_DIR_DOT);
3830Sstevel@tonic-gate 			else {
3840Sstevel@tonic-gate 				int	len = str - crle.c_confil;
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 				if ((lobjdir->o_objdir =
3870Sstevel@tonic-gate 				    malloc(len + 1)) == 0) {
3880Sstevel@tonic-gate 					int err = errno;
3890Sstevel@tonic-gate 					(void) fprintf(stderr,
3900Sstevel@tonic-gate 					    MSG_INTL(MSG_SYS_MALLOC),
3910Sstevel@tonic-gate 					    crle.c_name, strerror(err));
3920Sstevel@tonic-gate 					return (1);
3930Sstevel@tonic-gate 				}
3940Sstevel@tonic-gate 				(void) strncpy(lobjdir->o_objdir,
3950Sstevel@tonic-gate 				    crle.c_confil, len);
3960Sstevel@tonic-gate 				lobjdir->o_objdir[len] = '\0';
3970Sstevel@tonic-gate 			}
3980Sstevel@tonic-gate 		}
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 		/*
4010Sstevel@tonic-gate 		 * If we're going to dldump(3dl) images ourself make sure we
4020Sstevel@tonic-gate 		 * can access any directories.
4030Sstevel@tonic-gate 		 */
4040Sstevel@tonic-gate 		if (crle.c_flags & CRLE_DUMP) {
4050Sstevel@tonic-gate 			Objdir *	objdir;
4060Sstevel@tonic-gate 			Listnode *	lnp;
4070Sstevel@tonic-gate 			int		err = 0;
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 			for (LIST_TRAVERSE(&objdirs, lnp, objdir)) {
4100Sstevel@tonic-gate 				if (crle.c_flags & CRLE_VERBOSE)
4110Sstevel@tonic-gate 					(void) printf(MSG_INTL(MSG_DIA_OBJDIR),
4120Sstevel@tonic-gate 					    objdir->o_objdir);
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 				if ((objdir->o_flags & CRLE_DUMP) == 0)
4150Sstevel@tonic-gate 					continue;
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 				if (access(objdir->o_objdir,
4180Sstevel@tonic-gate 				    (R_OK | W_OK)) != 0) {
4190Sstevel@tonic-gate 					err = errno;
4200Sstevel@tonic-gate 					(void) fprintf(stderr,
4210Sstevel@tonic-gate 					    MSG_INTL(MSG_SYS_ACCESS),
4220Sstevel@tonic-gate 					    crle.c_name, objdir->o_objdir,
4230Sstevel@tonic-gate 					    strerror(err));
4240Sstevel@tonic-gate 				}
4250Sstevel@tonic-gate 			}
4260Sstevel@tonic-gate 			if (err)
4270Sstevel@tonic-gate 				return (1);
4280Sstevel@tonic-gate 		}
4290Sstevel@tonic-gate 	}
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	/*
4320Sstevel@tonic-gate 	 * Establish any initial object directory.
4330Sstevel@tonic-gate 	 */
4340Sstevel@tonic-gate 	crle.c_objdir = _lobjdir.o_objdir;
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	/*
4370Sstevel@tonic-gate 	 * Create a temporary file name in which to build the configuration
4380Sstevel@tonic-gate 	 * information.
4390Sstevel@tonic-gate 	 */
4400Sstevel@tonic-gate 	if ((crle.c_tempname = tempnam(MSG_ORIG(MSG_TMP_DIR),
4410Sstevel@tonic-gate 	    MSG_ORIG(MSG_TMP_PFX))) == NULL) {
4420Sstevel@tonic-gate 		int err = errno;
4430Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_TEMPNAME),
4440Sstevel@tonic-gate 		    crle.c_name, strerror(err));
4450Sstevel@tonic-gate 		return (1);
4460Sstevel@tonic-gate 	}
4470Sstevel@tonic-gate 	if ((crle.c_tempfd = open(crle.c_tempname, (O_RDWR | O_CREAT),
4480Sstevel@tonic-gate 	    0666)) == -1) {
4490Sstevel@tonic-gate 		int err = errno;
4500Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
4510Sstevel@tonic-gate 		    crle.c_name, crle.c_tempname, strerror(err));
4520Sstevel@tonic-gate 		return (1);
4530Sstevel@tonic-gate 	}
4540Sstevel@tonic-gate 	if (stat(crle.c_tempname, &nstatus) != 0) {
4550Sstevel@tonic-gate 		int err = errno;
4560Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
4570Sstevel@tonic-gate 		    crle.c_name, crle.c_tempname, strerror(err));
4580Sstevel@tonic-gate 		return (1);
4590Sstevel@tonic-gate 	}
4600Sstevel@tonic-gate 	if (ostatus.st_dev != nstatus.st_dev)
4610Sstevel@tonic-gate 		crle.c_flags |= CRLE_DIFFDEV;
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	/*
4640Sstevel@tonic-gate 	 * Second pass.
4650Sstevel@tonic-gate 	 */
4660Sstevel@tonic-gate 	error = 0;
4670Sstevel@tonic-gate 	optind = 1;
4680Sstevel@tonic-gate 	while ((c = getopt(argc, argv, MSG_ORIG(MSG_ARG_OPTIONS))) != -1) {
4690Sstevel@tonic-gate 		const char	*str;
4700Sstevel@tonic-gate 		int		flag = 0;
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 		switch (c) {
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 		case '6':
4750Sstevel@tonic-gate 			break;
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 		case 'A':			/* alternative is optional */
4780Sstevel@tonic-gate 			flag = RTC_OBJ_OPTINAL;
4790Sstevel@tonic-gate 			/* FALLTHROUGH */
4800Sstevel@tonic-gate 		case 'a':			/* alternative required */
4810Sstevel@tonic-gate 			flag |= (RTC_OBJ_ALTER | RTC_OBJ_CMDLINE);
4820Sstevel@tonic-gate 			if (inspect(&crle, (const char *)optarg, flag) != 0)
4830Sstevel@tonic-gate 				error = 1;
4840Sstevel@tonic-gate 			break;
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 		case 'c':
4870Sstevel@tonic-gate 			break;
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 		case 'e':
4900Sstevel@tonic-gate 			if ((flag = addenv(&crle, (const char *)optarg,
4910Sstevel@tonic-gate 			    RTC_ENV_REPLACE)) == 0)
4920Sstevel@tonic-gate 				error = 1;
4930Sstevel@tonic-gate 			else if ((crle.c_flags & CRLE_VERBOSE) && (flag == 1))
4940Sstevel@tonic-gate 				(void) printf(MSG_INTL(MSG_DIA_RPLENV),
4950Sstevel@tonic-gate 				    (const char *)optarg);
4960Sstevel@tonic-gate 			break;
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 		case 'E':
4990Sstevel@tonic-gate 			if ((flag = addenv(&crle, (const char *)optarg,
5000Sstevel@tonic-gate 			    RTC_ENV_PERMANT)) == 0)
5010Sstevel@tonic-gate 				error = 1;
5020Sstevel@tonic-gate 			else if ((crle.c_flags & CRLE_VERBOSE) && (flag == 1))
5030Sstevel@tonic-gate 				(void) printf(MSG_INTL(MSG_DIA_PRMENV),
5040Sstevel@tonic-gate 				    (const char *)optarg);
5050Sstevel@tonic-gate 			break;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 		case 'f':
5080Sstevel@tonic-gate 			break;
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 		case 'G':			/* group object */
5110Sstevel@tonic-gate 			flag = (RTC_OBJ_DUMP | RTC_OBJ_ALTER);
5120Sstevel@tonic-gate 			/* FALLTHROUGH */
5130Sstevel@tonic-gate 		case 'g':
5140Sstevel@tonic-gate 			flag |= (RTC_OBJ_GROUP | RTC_OBJ_CMDLINE);
5150Sstevel@tonic-gate 			if (inspect(&crle, (const char *)optarg, flag) != 0)
5160Sstevel@tonic-gate 				error = 1;
5170Sstevel@tonic-gate 			break;
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 		case 'I':			/* individual object */
5200Sstevel@tonic-gate 			flag = (RTC_OBJ_DUMP | RTC_OBJ_ALTER);
5210Sstevel@tonic-gate 			/* FALLTHROUGH */
5220Sstevel@tonic-gate 		case 'i':
5230Sstevel@tonic-gate 			flag |= RTC_OBJ_CMDLINE;
5240Sstevel@tonic-gate 			if (inspect(&crle, (const char *)optarg, flag) != 0)
5250Sstevel@tonic-gate 				error = 1;
5260Sstevel@tonic-gate 			break;
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 		case 'l':			/* library search path */
5290Sstevel@tonic-gate 			if (crle.c_flags & CRLE_AOUT) {
5300Sstevel@tonic-gate 				str = MSG_ORIG(MSG_STR_AOUT);
5310Sstevel@tonic-gate 				lib = &crle.c_adlibpath;
5320Sstevel@tonic-gate 			} else {
5330Sstevel@tonic-gate 				str = MSG_ORIG(MSG_STR_ELF);
5340Sstevel@tonic-gate 				lib = &crle.c_edlibpath;
5350Sstevel@tonic-gate 			}
5360Sstevel@tonic-gate 			if (addlib(&crle, lib, (const char *)optarg) != 0)
5370Sstevel@tonic-gate 				error = 1;
5380Sstevel@tonic-gate 			else if (crle.c_flags & CRLE_VERBOSE)
5390Sstevel@tonic-gate 				(void) printf(MSG_INTL(MSG_DIA_DLIBPTH),
5400Sstevel@tonic-gate 				    str, (const char *)optarg);
5410Sstevel@tonic-gate 			break;
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 		case 'o':
5440Sstevel@tonic-gate 			crle.c_objdir = optarg;
5450Sstevel@tonic-gate 			break;
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 		case 's':			/* trusted (secure) path */
5480Sstevel@tonic-gate 			if (crle.c_flags & CRLE_AOUT) {
5490Sstevel@tonic-gate 				str = MSG_ORIG(MSG_STR_AOUT);
5500Sstevel@tonic-gate 				lib = &crle.c_aslibpath;
5510Sstevel@tonic-gate 			} else {
5520Sstevel@tonic-gate 				str = MSG_ORIG(MSG_STR_ELF);
5530Sstevel@tonic-gate 				lib = &crle.c_eslibpath;
5540Sstevel@tonic-gate 			}
5550Sstevel@tonic-gate 			if (addlib(&crle, lib, (const char *)optarg) != 0)
5560Sstevel@tonic-gate 				error = 1;
5570Sstevel@tonic-gate 			else if (crle.c_flags & CRLE_VERBOSE)
5580Sstevel@tonic-gate 				(void) printf(MSG_INTL(MSG_DIA_TLIBPTH),
5590Sstevel@tonic-gate 				    str, (const char *)optarg);
5600Sstevel@tonic-gate 			break;
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 		case 't':			/* search path type */
5630Sstevel@tonic-gate 			if (strcmp((const char *)optarg,
5640Sstevel@tonic-gate 			    MSG_ORIG(MSG_STR_ELF)) == 0)
5650Sstevel@tonic-gate 				crle.c_flags &= ~CRLE_AOUT;
5660Sstevel@tonic-gate 			else
5670Sstevel@tonic-gate 				crle.c_flags |= CRLE_AOUT;
5680Sstevel@tonic-gate 			break;
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 		case 'u':
5710Sstevel@tonic-gate 			break;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 		case 'v':
5740Sstevel@tonic-gate 			break;
5750Sstevel@tonic-gate 		}
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	/*
5790Sstevel@tonic-gate 	 * Now that we've generated as many file/directory processing errors
5800Sstevel@tonic-gate 	 * as we can, return if any fatal error conditions occurred.
5810Sstevel@tonic-gate 	 */
5820Sstevel@tonic-gate 	if (error) {
5830Sstevel@tonic-gate 		(void) unlink(crle.c_tempname);
5840Sstevel@tonic-gate 		if (crle.c_flags & CRLE_CREAT) {
5850Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_GEN_CREATE),
5860Sstevel@tonic-gate 			    crle.c_name, crle.c_confil);
5870Sstevel@tonic-gate 		}
5880Sstevel@tonic-gate 		return (1);
5890Sstevel@tonic-gate 	}
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	/*
5920Sstevel@tonic-gate 	 * Create a temporary configuration file.
5930Sstevel@tonic-gate 	 */
5940Sstevel@tonic-gate 	if (genconfig(&crle) != 0) {
5950Sstevel@tonic-gate 		(void) unlink(crle.c_tempname);
5960Sstevel@tonic-gate 		return (1);
5970Sstevel@tonic-gate 	}
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	/*
6000Sstevel@tonic-gate 	 * If dldump(3dl) images are required spawn a process to create them.
6010Sstevel@tonic-gate 	 */
6020Sstevel@tonic-gate 	if (crle.c_flags & CRLE_DUMP) {
6030Sstevel@tonic-gate 		if (dump(&crle) != 0) {
6040Sstevel@tonic-gate 			(void) unlink(crle.c_tempname);
6050Sstevel@tonic-gate 			return (1);
6060Sstevel@tonic-gate 		}
6070Sstevel@tonic-gate 	}
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	/*
6100Sstevel@tonic-gate 	 * Copy the finished temporary configuration file to its final home.
6110Sstevel@tonic-gate 	 */
6120Sstevel@tonic-gate 	if (updateconfig(&crle) != 0)
6130Sstevel@tonic-gate 		return (1);
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	return (0);
6160Sstevel@tonic-gate }
617