xref: /onnv-gate/usr/src/cmd/sgs/ldd/common/ldd.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  *	Copyright (c) 1988 AT&T
24*0Sstevel@tonic-gate  *	  All Rights Reserved
25*0Sstevel@tonic-gate  *
26*0Sstevel@tonic-gate  *
27*0Sstevel@tonic-gate  *	Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
28*0Sstevel@tonic-gate  *	Use is subject to license terms.
29*0Sstevel@tonic-gate  */
30*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate /*
33*0Sstevel@tonic-gate  * Print the list of shared objects required by a dynamic executable or shared
34*0Sstevel@tonic-gate  * object.
35*0Sstevel@tonic-gate  *
36*0Sstevel@tonic-gate  * usage is: ldd [-d | -r] [-c] [-e envar] [-i] [-f] [-L] [-l] [-s]
37*0Sstevel@tonic-gate  *		[-U | -u] [-v] file(s)
38*0Sstevel@tonic-gate  *
39*0Sstevel@tonic-gate  * ldd opens the file and verifies the information in the elf header.
40*0Sstevel@tonic-gate  * If the file is a dynamic executable, we set up some environment variables
41*0Sstevel@tonic-gate  * and exec(2) the file.  If the file is a shared object, we preload the
42*0Sstevel@tonic-gate  * file with a dynamic executable stub. The runtime linker (ld.so.1) actually
43*0Sstevel@tonic-gate  * provides the diagnostic output, according to the environment variables set.
44*0Sstevel@tonic-gate  *
45*0Sstevel@tonic-gate  * If neither -d nor -r is specified, we set only LD_TRACE_LOADED_OBJECTS_[AE].
46*0Sstevel@tonic-gate  * The runtime linker will print the pathnames of all dynamic objects it
47*0Sstevel@tonic-gate  * loads, and then exit.  Note that we distiguish between ELF and AOUT objects
48*0Sstevel@tonic-gate  * when setting this environment variable - AOUT executables cause the mapping
49*0Sstevel@tonic-gate  * of sbcp, the dependencies of which the user isn't interested in.
50*0Sstevel@tonic-gate  *
51*0Sstevel@tonic-gate  * If -d or -r is specified, we also set LD_WARN=1; the runtime linker will
52*0Sstevel@tonic-gate  * perform its normal relocations and issue warning messages for unresolved
53*0Sstevel@tonic-gate  * references. It will then exit.
54*0Sstevel@tonic-gate  * If -r is specified, we set LD_BIND_NOW=1, so that the runtime linker
55*0Sstevel@tonic-gate  * will perform all relocations, otherwise (under -d) the runtime linker
56*0Sstevel@tonic-gate  * will not perform PLT (function) type relocations.
57*0Sstevel@tonic-gate  *
58*0Sstevel@tonic-gate  * If -c is specified we also set LD_NOCONFIG=1, thus disabling any
59*0Sstevel@tonic-gate  * configuration file use.
60*0Sstevel@tonic-gate  *
61*0Sstevel@tonic-gate  * If -e is specified the associated environment variable is set for the
62*0Sstevel@tonic-gate  * child process that will produce ldd's diagnostics.
63*0Sstevel@tonic-gate  *
64*0Sstevel@tonic-gate  * If -i is specified, we set LD_INIT=1. The order of inititialization
65*0Sstevel@tonic-gate  * sections to be executed is printed. We also set LD_WARN=1.
66*0Sstevel@tonic-gate  *
67*0Sstevel@tonic-gate  * If -f is specified, we will run ldd as root on executables that have
68*0Sstevel@tonic-gate  * an unsercure runtime linker that does not live under the "/usr/lib"
69*0Sstevel@tonic-gate  * directory.  By default we will not let this happen.
70*0Sstevel@tonic-gate  *
71*0Sstevel@tonic-gate  * If -l is specified it generates a warning for any auxiliary filter not found.
72*0Sstevel@tonic-gate  * Prior to 2.8 this forced any filters to load (all) their filtees.  This is
73*0Sstevel@tonic-gate  * now the default, however missing auxiliary filters don't generate any error
74*0Sstevel@tonic-gate  * diagniostic.  See also -L.
75*0Sstevel@tonic-gate  *
76*0Sstevel@tonic-gate  * If -L is specified we revert to lazy loading, thus any filtee or lazy
77*0Sstevel@tonic-gate  * dependency loading is deferred until relocations cause loading.  Without
78*0Sstevel@tonic-gate  * this option we set LD_LOADFLTR=1, thus forcing any filters to load (all)
79*0Sstevel@tonic-gate  * their filtees, and LD_NOLAZYLOAD=1 thus forcing immediate processing of
80*0Sstevel@tonic-gate  * any lazy loaded dependencies.
81*0Sstevel@tonic-gate  *
82*0Sstevel@tonic-gate  * If -s is specified we also set LD_TRACE_SEARCH_PATH=1, thus enabling
83*0Sstevel@tonic-gate  * the runtime linker to indicate the search algorithm used.
84*0Sstevel@tonic-gate  *
85*0Sstevel@tonic-gate  * If -v is specified we also set LD_VERBOSE=1, thus enabling the runtime
86*0Sstevel@tonic-gate  * linker to indicate all object dependencies (not just the first object
87*0Sstevel@tonic-gate  * loaded) together with any versionig requirements.
88*0Sstevel@tonic-gate  *
89*0Sstevel@tonic-gate  * If -U or -u is specified unused dependencies are detected.  -u causes
90*0Sstevel@tonic-gate  * LD_UNUSED=1 to be set, which causes dependencies that are unused within the
91*0Sstevel@tonic-gate  * process to be detected.  -U causes LD_UNREF=1 to be set, which causes
92*0Sstevel@tonic-gate  * unreferenced objects, and unreferenced cyclic dependencies to be detected.
93*0Sstevel@tonic-gate  * These options assert that at least -d is set as relocation references are
94*0Sstevel@tonic-gate  * what determine an objects use.
95*0Sstevel@tonic-gate  */
96*0Sstevel@tonic-gate #include	<fcntl.h>
97*0Sstevel@tonic-gate #include	<stdio.h>
98*0Sstevel@tonic-gate #include	<string.h>
99*0Sstevel@tonic-gate #include	<libelf.h>
100*0Sstevel@tonic-gate #include	<gelf.h>
101*0Sstevel@tonic-gate #include	<stdlib.h>
102*0Sstevel@tonic-gate #include	<unistd.h>
103*0Sstevel@tonic-gate #include	<wait.h>
104*0Sstevel@tonic-gate #include	<locale.h>
105*0Sstevel@tonic-gate #include	<errno.h>
106*0Sstevel@tonic-gate #include	<signal.h>
107*0Sstevel@tonic-gate #include	"machdep.h"
108*0Sstevel@tonic-gate #include	"sgs.h"
109*0Sstevel@tonic-gate #include	"conv.h"
110*0Sstevel@tonic-gate #include	"a.out.h"
111*0Sstevel@tonic-gate #include	"msg.h"
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate static int	elf_check(int, char *, char *, Elf *, int);
114*0Sstevel@tonic-gate static int	aout_check(int, char *, char *, int, int);
115*0Sstevel@tonic-gate static int	run(int, char *, char *, const char *, int);
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate /*
119*0Sstevel@tonic-gate  * The following size definitions provide for allocating space for the string,
120*0Sstevel@tonic-gate  * or the string position at which any modifications to the variable will occur.
121*0Sstevel@tonic-gate  */
122*0Sstevel@tonic-gate #define	LD_LOAD_SIZE		27
123*0Sstevel@tonic-gate #define	LD_PATH_SIZE		23
124*0Sstevel@tonic-gate #define	LD_BIND_SIZE		13
125*0Sstevel@tonic-gate #define	LD_VERB_SIZE		12
126*0Sstevel@tonic-gate #define	LD_WARN_SIZE		9
127*0Sstevel@tonic-gate #define	LD_CONF_SIZE		13
128*0Sstevel@tonic-gate #define	LD_FLTR_SIZE		13
129*0Sstevel@tonic-gate #define	LD_LAZY_SIZE		15
130*0Sstevel@tonic-gate #define	LD_INIT_SIZE		9
131*0Sstevel@tonic-gate #define	LD_UREF_SIZE		10
132*0Sstevel@tonic-gate #define	LD_USED_SIZE		11
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate static char	bind[] =	"LD_BIND_NOW= ",
135*0Sstevel@tonic-gate 		load_elf[] =	"LD_TRACE_LOADED_OBJECTS_E= ",
136*0Sstevel@tonic-gate 		load_aout[] =	"LD_TRACE_LOADED_OBJECTS_A= ",
137*0Sstevel@tonic-gate 		path[] =	"LD_TRACE_SEARCH_PATHS= ",
138*0Sstevel@tonic-gate 		verb[] =	"LD_VERBOSE= ",
139*0Sstevel@tonic-gate 		warn[] =	"LD_WARN= ",
140*0Sstevel@tonic-gate 		conf[] =	"LD_NOCONFIG= ",
141*0Sstevel@tonic-gate 		fltr[] =	"LD_LOADFLTR= ",
142*0Sstevel@tonic-gate 		lazy[] =	"LD_NOLAZYLOAD=1",
143*0Sstevel@tonic-gate 		init[] =	"LD_INIT= ",
144*0Sstevel@tonic-gate 		uref[] =	"LD_UNREF= ",
145*0Sstevel@tonic-gate 		used[] =	"LD_UNUSED= ";
146*0Sstevel@tonic-gate static char	*load;
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate static const char	*prefile_32, *prefile_64, *prefile;
149*0Sstevel@tonic-gate static List		eopts = { 0, 0 };
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate /*
152*0Sstevel@tonic-gate  * Append an item to the specified list, and return a pointer to the list
153*0Sstevel@tonic-gate  * node created.
154*0Sstevel@tonic-gate  */
155*0Sstevel@tonic-gate Listnode *
156*0Sstevel@tonic-gate list_append(List *lst, const void *item)
157*0Sstevel@tonic-gate {
158*0Sstevel@tonic-gate 	Listnode	*lnp;
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	if ((lnp = malloc(sizeof (Listnode))) == (Listnode *)0)
161*0Sstevel@tonic-gate 		return (0);
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 	lnp->data = (void *)item;
164*0Sstevel@tonic-gate 	lnp->next = NULL;
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	if (lst->head == NULL)
167*0Sstevel@tonic-gate 		lst->tail = lst->head = lnp;
168*0Sstevel@tonic-gate 	else {
169*0Sstevel@tonic-gate 		lst->tail->next = lnp;
170*0Sstevel@tonic-gate 		lst->tail = lst->tail->next;
171*0Sstevel@tonic-gate 	}
172*0Sstevel@tonic-gate 	return (lnp);
173*0Sstevel@tonic-gate }
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate int
176*0Sstevel@tonic-gate main(int argc, char **argv)
177*0Sstevel@tonic-gate {
178*0Sstevel@tonic-gate 	char	*str, *cname = argv[0];
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	Elf	*elf;
181*0Sstevel@tonic-gate 	int	cflag = 0, dflag = 0, fflag = 0, iflag = 0, Lflag = 0;
182*0Sstevel@tonic-gate 	int	lflag = 0, rflag = 0, sflag = 0, Uflag = 0, uflag = 0;
183*0Sstevel@tonic-gate 	int	vflag = 0, nfile, var, error = 0;
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 	Listnode	*lnp;
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	/*
188*0Sstevel@tonic-gate 	 * Establish locale.
189*0Sstevel@tonic-gate 	 */
190*0Sstevel@tonic-gate 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
191*0Sstevel@tonic-gate 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	/*
194*0Sstevel@tonic-gate 	 * verify command line syntax and process arguments
195*0Sstevel@tonic-gate 	 */
196*0Sstevel@tonic-gate 	opterr = 0;				/* disable getopt error mesg */
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_GETOPT))) != EOF) {
199*0Sstevel@tonic-gate 		switch (var) {
200*0Sstevel@tonic-gate 		case 'c' :			/* enable config search */
201*0Sstevel@tonic-gate 			cflag = 1;
202*0Sstevel@tonic-gate 			break;
203*0Sstevel@tonic-gate 		case 'd' :			/* perform data relocations */
204*0Sstevel@tonic-gate 			dflag = 1;
205*0Sstevel@tonic-gate 			if (rflag)
206*0Sstevel@tonic-gate 				error++;
207*0Sstevel@tonic-gate 			break;
208*0Sstevel@tonic-gate 		case 'e' :
209*0Sstevel@tonic-gate 			if (list_append(&eopts, optarg) == 0) {
210*0Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
211*0Sstevel@tonic-gate 				    cname);
212*0Sstevel@tonic-gate 				exit(1);
213*0Sstevel@tonic-gate 			}
214*0Sstevel@tonic-gate 			break;
215*0Sstevel@tonic-gate 		case 'f' :
216*0Sstevel@tonic-gate 			fflag = 1;
217*0Sstevel@tonic-gate 			break;
218*0Sstevel@tonic-gate 		case 'L' :
219*0Sstevel@tonic-gate 			Lflag = 1;
220*0Sstevel@tonic-gate 			break;
221*0Sstevel@tonic-gate 		case 'l' :
222*0Sstevel@tonic-gate 			lflag = 1;
223*0Sstevel@tonic-gate 			break;
224*0Sstevel@tonic-gate 		case 'i' :			/* print the order of .init */
225*0Sstevel@tonic-gate 			iflag = 1;
226*0Sstevel@tonic-gate 			break;
227*0Sstevel@tonic-gate 		case 'r' :			/* perform all relocations */
228*0Sstevel@tonic-gate 			rflag = 1;
229*0Sstevel@tonic-gate 			if (dflag)
230*0Sstevel@tonic-gate 				error++;
231*0Sstevel@tonic-gate 			break;
232*0Sstevel@tonic-gate 		case 's' :			/* enable search path output */
233*0Sstevel@tonic-gate 			sflag = 1;
234*0Sstevel@tonic-gate 			break;
235*0Sstevel@tonic-gate 		case 'U' :			/* list unreferenced */
236*0Sstevel@tonic-gate 			Uflag = 1;		/*	dependencies */
237*0Sstevel@tonic-gate 			if (uflag)
238*0Sstevel@tonic-gate 				error++;
239*0Sstevel@tonic-gate 			break;
240*0Sstevel@tonic-gate 		case 'u' :			/* list unused dependencies */
241*0Sstevel@tonic-gate 			uflag = 1;
242*0Sstevel@tonic-gate 			if (Uflag)
243*0Sstevel@tonic-gate 				error++;
244*0Sstevel@tonic-gate 			break;
245*0Sstevel@tonic-gate 		case 'v' :			/* enable verbose output */
246*0Sstevel@tonic-gate 			vflag = 1;
247*0Sstevel@tonic-gate 			break;
248*0Sstevel@tonic-gate 		default :
249*0Sstevel@tonic-gate 			error++;
250*0Sstevel@tonic-gate 			break;
251*0Sstevel@tonic-gate 		}
252*0Sstevel@tonic-gate 		if (error)
253*0Sstevel@tonic-gate 			break;
254*0Sstevel@tonic-gate 	}
255*0Sstevel@tonic-gate 	if (error) {
256*0Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ARG_USAGE), cname);
257*0Sstevel@tonic-gate 		exit(1);
258*0Sstevel@tonic-gate 	}
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	/*
261*0Sstevel@tonic-gate 	 * Determine if any of the LD_PRELOAD family is already set in the
262*0Sstevel@tonic-gate 	 * environment, if so we'll continue to analyze each object with the
263*0Sstevel@tonic-gate 	 * appropriate setting.
264*0Sstevel@tonic-gate 	 */
265*0Sstevel@tonic-gate 	if (((prefile_32 = getenv(MSG_ORIG(MSG_LD_PRELOAD_32))) == NULL) ||
266*0Sstevel@tonic-gate 	    (*prefile_32 == '\0')) {
267*0Sstevel@tonic-gate 		prefile_32 = MSG_ORIG(MSG_STR_EMPTY);
268*0Sstevel@tonic-gate 	}
269*0Sstevel@tonic-gate 	if (((prefile_64 = getenv(MSG_ORIG(MSG_LD_PRELOAD_64))) == NULL) ||
270*0Sstevel@tonic-gate 	    (*prefile_64 == '\0')) {
271*0Sstevel@tonic-gate 		prefile_64 = MSG_ORIG(MSG_STR_EMPTY);
272*0Sstevel@tonic-gate 	}
273*0Sstevel@tonic-gate 	if (((prefile = getenv(MSG_ORIG(MSG_LD_PRELOAD))) == NULL) ||
274*0Sstevel@tonic-gate 	    (*prefile == '\0')) {
275*0Sstevel@tonic-gate 		prefile = MSG_ORIG(MSG_STR_EMPTY);
276*0Sstevel@tonic-gate 	}
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	/*
279*0Sstevel@tonic-gate 	 * Determine if any environment requests are for the LD_PRELOAD family,
280*0Sstevel@tonic-gate 	 * and if so override any environment settings we've established above.
281*0Sstevel@tonic-gate 	 */
282*0Sstevel@tonic-gate 	for (LIST_TRAVERSE(&eopts, lnp, str)) {
283*0Sstevel@tonic-gate 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD_32),
284*0Sstevel@tonic-gate 		    MSG_LD_PRELOAD_32_SIZE)) == 0) {
285*0Sstevel@tonic-gate 			str += MSG_LD_PRELOAD_32_SIZE;
286*0Sstevel@tonic-gate 			if ((*str++ == '=') && (*str != '\0'))
287*0Sstevel@tonic-gate 				prefile_32 = str;
288*0Sstevel@tonic-gate 			continue;
289*0Sstevel@tonic-gate 		}
290*0Sstevel@tonic-gate 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD_64),
291*0Sstevel@tonic-gate 		    MSG_LD_PRELOAD_64_SIZE)) == 0) {
292*0Sstevel@tonic-gate 			str += MSG_LD_PRELOAD_64_SIZE;
293*0Sstevel@tonic-gate 			if ((*str++ == '=') && (*str != '\0'))
294*0Sstevel@tonic-gate 				prefile_64 = str;
295*0Sstevel@tonic-gate 			continue;
296*0Sstevel@tonic-gate 		}
297*0Sstevel@tonic-gate 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD),
298*0Sstevel@tonic-gate 		    MSG_LD_PRELOAD_SIZE)) == 0) {
299*0Sstevel@tonic-gate 			str += MSG_LD_PRELOAD_SIZE;
300*0Sstevel@tonic-gate 			if ((*str++ == '=') && (*str != '\0'))
301*0Sstevel@tonic-gate 				prefile = str;
302*0Sstevel@tonic-gate 			continue;
303*0Sstevel@tonic-gate 		}
304*0Sstevel@tonic-gate 	}
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	/*
307*0Sstevel@tonic-gate 	 * Set the appropriate relocation environment variables (Note unsetting
308*0Sstevel@tonic-gate 	 * the environment variables is done just in case the user already
309*0Sstevel@tonic-gate 	 * has these in their environment ... sort of thing the test folks
310*0Sstevel@tonic-gate 	 * would do :-)
311*0Sstevel@tonic-gate 	 */
312*0Sstevel@tonic-gate 	warn[LD_WARN_SIZE - 1] = (dflag || rflag || Uflag || uflag) ? '1' :
313*0Sstevel@tonic-gate 	    '\0';
314*0Sstevel@tonic-gate 	bind[LD_BIND_SIZE - 1] = (rflag) ? '1' : '\0';
315*0Sstevel@tonic-gate 	path[LD_PATH_SIZE - 1] = (sflag) ? '1' : '\0';
316*0Sstevel@tonic-gate 	verb[LD_VERB_SIZE - 1] = (vflag) ? '1' : '\0';
317*0Sstevel@tonic-gate 	fltr[LD_FLTR_SIZE - 1] = (Lflag) ? '\0' : (lflag) ? '2' : '1';
318*0Sstevel@tonic-gate 	init[LD_INIT_SIZE - 1] = (iflag) ? '1' : '\0';
319*0Sstevel@tonic-gate 	conf[LD_CONF_SIZE - 1] = (cflag) ? '1' : '\0';
320*0Sstevel@tonic-gate 	lazy[LD_LAZY_SIZE - 1] = (Lflag) ? '\0' : '1';
321*0Sstevel@tonic-gate 	uref[LD_UREF_SIZE - 1] = (Uflag) ? '1' : '\0';
322*0Sstevel@tonic-gate 	used[LD_USED_SIZE - 1] = (uflag) ? '1' : '\0';
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 	/*
325*0Sstevel@tonic-gate 	 * coordinate libelf's version information
326*0Sstevel@tonic-gate 	 */
327*0Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
328*0Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_LIBELF), cname,
329*0Sstevel@tonic-gate 		    EV_CURRENT);
330*0Sstevel@tonic-gate 		exit(1);
331*0Sstevel@tonic-gate 	}
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 	/*
334*0Sstevel@tonic-gate 	 * Loop through remaining arguments.  Note that from here on there
335*0Sstevel@tonic-gate 	 * are no exit conditions so that we can process a list of files,
336*0Sstevel@tonic-gate 	 * any error condition is retained for a final exit status.
337*0Sstevel@tonic-gate 	 */
338*0Sstevel@tonic-gate 	nfile = argc - optind;
339*0Sstevel@tonic-gate 	for (; optind < argc; optind++) {
340*0Sstevel@tonic-gate 		char	*fname = argv[optind];
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 		/*
343*0Sstevel@tonic-gate 		 * Open file (do this before checking access so that we can
344*0Sstevel@tonic-gate 		 * provide the user with better diagnostics).
345*0Sstevel@tonic-gate 		 */
346*0Sstevel@tonic-gate 		if ((var = open(fname, O_RDONLY)) == -1) {
347*0Sstevel@tonic-gate 			int	err = errno;
348*0Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), cname,
349*0Sstevel@tonic-gate 			    fname, strerror(err));
350*0Sstevel@tonic-gate 			error = 1;
351*0Sstevel@tonic-gate 			continue;
352*0Sstevel@tonic-gate 		}
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 		/*
355*0Sstevel@tonic-gate 		 * Get the files elf descriptor and process it as an elf or
356*0Sstevel@tonic-gate 		 * a.out (4.x) file.
357*0Sstevel@tonic-gate 		 */
358*0Sstevel@tonic-gate 		elf = elf_begin(var, ELF_C_READ, (Elf *)0);
359*0Sstevel@tonic-gate 		switch (elf_kind(elf)) {
360*0Sstevel@tonic-gate 		case ELF_K_AR :
361*0Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO),
362*0Sstevel@tonic-gate 			    cname, fname);
363*0Sstevel@tonic-gate 			error = 1;
364*0Sstevel@tonic-gate 			break;
365*0Sstevel@tonic-gate 		case ELF_K_COFF:
366*0Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN),
367*0Sstevel@tonic-gate 			    cname, fname);
368*0Sstevel@tonic-gate 			error = 1;
369*0Sstevel@tonic-gate 			break;
370*0Sstevel@tonic-gate 		case ELF_K_ELF:
371*0Sstevel@tonic-gate 			if (elf_check(nfile, fname, cname, elf, fflag) != NULL)
372*0Sstevel@tonic-gate 				error = 1;
373*0Sstevel@tonic-gate 			break;
374*0Sstevel@tonic-gate 		default:
375*0Sstevel@tonic-gate 			/*
376*0Sstevel@tonic-gate 			 * This is either an unknown file or an aout format
377*0Sstevel@tonic-gate 			 */
378*0Sstevel@tonic-gate 			if (aout_check(nfile, fname, cname, var, fflag) != NULL)
379*0Sstevel@tonic-gate 				error = 1;
380*0Sstevel@tonic-gate 			break;
381*0Sstevel@tonic-gate 		}
382*0Sstevel@tonic-gate 		(void) elf_end(elf);
383*0Sstevel@tonic-gate 		(void) close(var);
384*0Sstevel@tonic-gate 	}
385*0Sstevel@tonic-gate 	return (error);
386*0Sstevel@tonic-gate }
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate static int
391*0Sstevel@tonic-gate is_runnable(GElf_Ehdr *ehdr)
392*0Sstevel@tonic-gate {
393*0Sstevel@tonic-gate 	if ((ehdr->e_ident[EI_CLASS] == M_CLASS) &&
394*0Sstevel@tonic-gate 	    (ehdr->e_ident[EI_DATA] == M_DATA))
395*0Sstevel@tonic-gate 		return (ELFCLASS32);
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate #if	defined(sparc)
398*0Sstevel@tonic-gate 	if ((ehdr->e_machine == EM_SPARCV9) &&
399*0Sstevel@tonic-gate 	    (ehdr->e_ident[EI_DATA] == M_DATA) &&
400*0Sstevel@tonic-gate 	    (conv_sys_eclass() == ELFCLASS64))
401*0Sstevel@tonic-gate 		return (ELFCLASS64);
402*0Sstevel@tonic-gate #elif	defined(i386) || defined(__amd64)
403*0Sstevel@tonic-gate 	if ((ehdr->e_machine == EM_AMD64) &&
404*0Sstevel@tonic-gate 	    (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) &&
405*0Sstevel@tonic-gate 	    (conv_sys_eclass() == ELFCLASS64))
406*0Sstevel@tonic-gate 		return (ELFCLASS64);
407*0Sstevel@tonic-gate #endif
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 	return (ELFCLASSNONE);
410*0Sstevel@tonic-gate }
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate static int
414*0Sstevel@tonic-gate elf_check(int nfile, char *fname, char *cname, Elf *elf, int fflag)
415*0Sstevel@tonic-gate {
416*0Sstevel@tonic-gate 	GElf_Ehdr 	ehdr;
417*0Sstevel@tonic-gate 	GElf_Phdr 	phdr;
418*0Sstevel@tonic-gate 	int		dynamic = 0, interp = 0, cnt, class;
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	/*
421*0Sstevel@tonic-gate 	 * verify information in file header
422*0Sstevel@tonic-gate 	 */
423*0Sstevel@tonic-gate 	if (gelf_getehdr(elf, &ehdr) == NULL) {
424*0Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETEHDR),
425*0Sstevel@tonic-gate 			cname, fname, elf_errmsg(-1));
426*0Sstevel@tonic-gate 		return (1);
427*0Sstevel@tonic-gate 	}
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate 	/*
430*0Sstevel@tonic-gate 	 * check class and encoding
431*0Sstevel@tonic-gate 	 */
432*0Sstevel@tonic-gate 	if ((class = is_runnable(&ehdr)) == ELFCLASSNONE) {
433*0Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_CLASSDATA),
434*0Sstevel@tonic-gate 			cname, fname);
435*0Sstevel@tonic-gate 		return (1);
436*0Sstevel@tonic-gate 	}
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate 	/*
439*0Sstevel@tonic-gate 	 * check type
440*0Sstevel@tonic-gate 	 */
441*0Sstevel@tonic-gate 	if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN) &&
442*0Sstevel@tonic-gate 	    (ehdr.e_type != ET_REL)) {
443*0Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_BADMAGIC),
444*0Sstevel@tonic-gate 			cname, fname);
445*0Sstevel@tonic-gate 		return (1);
446*0Sstevel@tonic-gate 	}
447*0Sstevel@tonic-gate 	if ((class == ELFCLASS32) && (ehdr.e_machine != M_MACH)) {
448*0Sstevel@tonic-gate 		if (ehdr.e_machine != M_MACHPLUS) {
449*0Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_MACHTYPE),
450*0Sstevel@tonic-gate 				cname, fname);
451*0Sstevel@tonic-gate 			return (1);
452*0Sstevel@tonic-gate 		}
453*0Sstevel@tonic-gate 		if ((ehdr.e_flags & M_FLAGSPLUS) == 0) {
454*0Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_MACHFLAGS),
455*0Sstevel@tonic-gate 				cname, fname);
456*0Sstevel@tonic-gate 			return (1);
457*0Sstevel@tonic-gate 		}
458*0Sstevel@tonic-gate 	}
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 	/*
461*0Sstevel@tonic-gate 	 * Check that the file is executable.  Dynamic executables must be
462*0Sstevel@tonic-gate 	 * executable to be exec'ed.  Shared objects need not be executable to
463*0Sstevel@tonic-gate 	 * be mapped with a dynamic executable, however, by convention they're
464*0Sstevel@tonic-gate 	 * supposed to be executable.
465*0Sstevel@tonic-gate 	 */
466*0Sstevel@tonic-gate 	if (access(fname, X_OK) != 0) {
467*0Sstevel@tonic-gate 		if (ehdr.e_type == ET_EXEC) {
468*0Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USP_NOTEXEC_1),
469*0Sstevel@tonic-gate 				cname, fname);
470*0Sstevel@tonic-gate 			return (1);
471*0Sstevel@tonic-gate 		}
472*0Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NOTEXEC_2), cname,
473*0Sstevel@tonic-gate 		    fname);
474*0Sstevel@tonic-gate 	}
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 	/*
477*0Sstevel@tonic-gate 	 * Determine whether we have a dynamic section or interpretor.
478*0Sstevel@tonic-gate 	 */
479*0Sstevel@tonic-gate 	for (cnt = 0; cnt < (int)ehdr.e_phnum; cnt++) {
480*0Sstevel@tonic-gate 		if (dynamic && interp)
481*0Sstevel@tonic-gate 			break;
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 		if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
484*0Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETPHDR),
485*0Sstevel@tonic-gate 				cname, fname, elf_errmsg(-1));
486*0Sstevel@tonic-gate 			return (1);
487*0Sstevel@tonic-gate 		}
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 		if (phdr.p_type == PT_DYNAMIC) {
490*0Sstevel@tonic-gate 			dynamic = 1;
491*0Sstevel@tonic-gate 			continue;
492*0Sstevel@tonic-gate 		}
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 		if (phdr.p_type != PT_INTERP)
495*0Sstevel@tonic-gate 			continue;
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 		interp = 1;
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 		/*
500*0Sstevel@tonic-gate 		 * If fflag is not set, and euid == root, and the interpreter
501*0Sstevel@tonic-gate 		 * does not live under /lib, /usr/lib or /etc/lib then don't
502*0Sstevel@tonic-gate 		 * allow ldd to execute the image.  This prevents someone
503*0Sstevel@tonic-gate 		 * creating a `trojan horse' by substituting their own
504*0Sstevel@tonic-gate 		 * interpreter that could preform privileged operations
505*0Sstevel@tonic-gate 		 * when ldd is against it.
506*0Sstevel@tonic-gate 		 */
507*0Sstevel@tonic-gate 		if ((fflag == 0) && (geteuid() == 0) &&
508*0Sstevel@tonic-gate 		    (strcmp(fname, conv_lddstub(class)) != 0)) {
509*0Sstevel@tonic-gate 			char	*interpreter;
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 			/*
512*0Sstevel@tonic-gate 			 * Does the interpreter live under a trusted directory.
513*0Sstevel@tonic-gate 			 */
514*0Sstevel@tonic-gate 			interpreter = elf_getident(elf, 0) + phdr.p_offset;
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 			if ((strncmp(interpreter, MSG_ORIG(MSG_PTH_USRLIB),
517*0Sstevel@tonic-gate 			    MSG_PTH_USRLIB_SIZE) != 0) &&
518*0Sstevel@tonic-gate 			    (strncmp(interpreter, MSG_ORIG(MSG_PTH_LIB),
519*0Sstevel@tonic-gate 			    MSG_PTH_LIB_SIZE) != 0) &&
520*0Sstevel@tonic-gate 			    (strncmp(interpreter, MSG_ORIG(MSG_PTH_ETCLIB),
521*0Sstevel@tonic-gate 			    MSG_PTH_ETCLIB_SIZE) != 0)) {
522*0Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_USP_ELFINS),
523*0Sstevel@tonic-gate 					cname, fname, interpreter);
524*0Sstevel@tonic-gate 				return (1);
525*0Sstevel@tonic-gate 			}
526*0Sstevel@tonic-gate 		}
527*0Sstevel@tonic-gate 	}
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate 	/*
530*0Sstevel@tonic-gate 	 * Catch the case of a static executable (ie, an ET_EXEC that has a set
531*0Sstevel@tonic-gate 	 * of program headers but no PT_DYNAMIC).
532*0Sstevel@tonic-gate 	 */
533*0Sstevel@tonic-gate 	if (ehdr.e_phnum && !dynamic) {
534*0Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO), cname,
535*0Sstevel@tonic-gate 		    fname);
536*0Sstevel@tonic-gate 		return (1);
537*0Sstevel@tonic-gate 	}
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate 	load = load_elf;
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate 	/*
542*0Sstevel@tonic-gate 	 * Run the required program (shared and relocatable objects require the
543*0Sstevel@tonic-gate 	 * use of lddstub).
544*0Sstevel@tonic-gate 	 */
545*0Sstevel@tonic-gate 	if ((ehdr.e_type == ET_EXEC) && interp)
546*0Sstevel@tonic-gate 		return (run(nfile, cname, fname, (const char *)fname, class));
547*0Sstevel@tonic-gate 	else
548*0Sstevel@tonic-gate 		return (run(nfile, cname, fname, conv_lddstub(class), class));
549*0Sstevel@tonic-gate }
550*0Sstevel@tonic-gate 
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate static int
553*0Sstevel@tonic-gate aout_check(int nfile, char *fname, char *cname, int fd, int fflag)
554*0Sstevel@tonic-gate {
555*0Sstevel@tonic-gate 	struct exec	aout;
556*0Sstevel@tonic-gate 	int		err;
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate 	if (lseek(fd, 0, SEEK_SET) != 0) {
559*0Sstevel@tonic-gate 		err = errno;
560*0Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_LSEEK), cname, fname,
561*0Sstevel@tonic-gate 		    strerror(err));
562*0Sstevel@tonic-gate 		return (1);
563*0Sstevel@tonic-gate 	}
564*0Sstevel@tonic-gate 	if (read(fd, (char *)&aout, sizeof (struct exec)) !=
565*0Sstevel@tonic-gate 	    sizeof (struct exec)) {
566*0Sstevel@tonic-gate 		err = errno;
567*0Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_READ), cname, fname,
568*0Sstevel@tonic-gate 		    strerror(err));
569*0Sstevel@tonic-gate 		return (1);
570*0Sstevel@tonic-gate 	}
571*0Sstevel@tonic-gate 	if (aout.a_machtype != M_SPARC) {
572*0Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN), cname, fname);
573*0Sstevel@tonic-gate 		return (1);
574*0Sstevel@tonic-gate 	}
575*0Sstevel@tonic-gate 	if (N_BADMAG(aout) || !aout.a_dynamic) {
576*0Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO), cname,
577*0Sstevel@tonic-gate 		    fname);
578*0Sstevel@tonic-gate 		return (1);
579*0Sstevel@tonic-gate 	}
580*0Sstevel@tonic-gate 	if (!fflag && (geteuid() == 0)) {
581*0Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_AOUTINS), cname, fname);
582*0Sstevel@tonic-gate 		return (1);
583*0Sstevel@tonic-gate 	}
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 	/*
586*0Sstevel@tonic-gate 	 * Run the required program.
587*0Sstevel@tonic-gate 	 */
588*0Sstevel@tonic-gate 	if ((aout.a_magic == ZMAGIC) &&
589*0Sstevel@tonic-gate 	    (aout.a_entry <= sizeof (struct exec))) {
590*0Sstevel@tonic-gate 		load = load_elf;
591*0Sstevel@tonic-gate 		return (run(nfile, cname, fname, conv_lddstub(ELFCLASS32),
592*0Sstevel@tonic-gate 		    ELFCLASS32));
593*0Sstevel@tonic-gate 	} else {
594*0Sstevel@tonic-gate 		load = load_aout;
595*0Sstevel@tonic-gate 		return (run(nfile, cname, fname, (const char *)fname,
596*0Sstevel@tonic-gate 		    ELFCLASS32));
597*0Sstevel@tonic-gate 	}
598*0Sstevel@tonic-gate }
599*0Sstevel@tonic-gate 
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate /*
602*0Sstevel@tonic-gate  * Run the required program, setting the preload and trace environment
603*0Sstevel@tonic-gate  * variables accordingly.
604*0Sstevel@tonic-gate  */
605*0Sstevel@tonic-gate static int
606*0Sstevel@tonic-gate run(int nfile, char *cname, char *fname, const char *ename, int class)
607*0Sstevel@tonic-gate {
608*0Sstevel@tonic-gate 	const char	*preload = 0;
609*0Sstevel@tonic-gate 	int		pid, status;
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate 	if ((pid = fork()) == -1) {
612*0Sstevel@tonic-gate 		int	err = errno;
613*0Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_FORK), cname,
614*0Sstevel@tonic-gate 		    strerror(err));
615*0Sstevel@tonic-gate 		return (1);
616*0Sstevel@tonic-gate 	}
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate 	if (pid) {				/* parent */
619*0Sstevel@tonic-gate 		while (wait(&status) != pid)
620*0Sstevel@tonic-gate 			;
621*0Sstevel@tonic-gate 		if (WIFSIGNALED(status) && ((WSIGMASK & status) != SIGPIPE)) {
622*0Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
623*0Sstevel@tonic-gate 			    fname);
624*0Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC_SIG),
625*0Sstevel@tonic-gate 			    (WSIGMASK & status), ((status & WCOREFLG) ?
626*0Sstevel@tonic-gate 			    MSG_INTL(MSG_SYS_EXEC_CORE) :
627*0Sstevel@tonic-gate 			    MSG_ORIG(MSG_STR_EMPTY)));
628*0Sstevel@tonic-gate 			status = 1;
629*0Sstevel@tonic-gate 		} else if (WHIBYTE(status)) {
630*0Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
631*0Sstevel@tonic-gate 			    fname);
632*0Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC_STAT),
633*0Sstevel@tonic-gate 			    WHIBYTE(status));
634*0Sstevel@tonic-gate 			status = 1;
635*0Sstevel@tonic-gate 		}
636*0Sstevel@tonic-gate 	} else {				/* child */
637*0Sstevel@tonic-gate 		Listnode	*lnp;
638*0Sstevel@tonic-gate 		char		*str;
639*0Sstevel@tonic-gate 		size_t		size;
640*0Sstevel@tonic-gate 
641*0Sstevel@tonic-gate 		/*
642*0Sstevel@tonic-gate 		 * When using ldd(1) to analyze a shared object we preload the
643*0Sstevel@tonic-gate 		 * shared object with lddstub.  Any additional preload
644*0Sstevel@tonic-gate 		 * requirements are added after the object being analyzed, this
645*0Sstevel@tonic-gate 		 * allows us to skip the first object but produce diagnostics
646*0Sstevel@tonic-gate 		 * for each other preloaded object.
647*0Sstevel@tonic-gate 		 */
648*0Sstevel@tonic-gate 		if (fname != ename) {
649*0Sstevel@tonic-gate 			char		*str;
650*0Sstevel@tonic-gate 			const char	*files = prefile;
651*0Sstevel@tonic-gate 			const char	*format = MSG_ORIG(MSG_STR_FMT1);
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 			for (str = fname; *str; str++)
654*0Sstevel@tonic-gate 				if (*str == '/') {
655*0Sstevel@tonic-gate 					format = MSG_ORIG(MSG_STR_FMT2);
656*0Sstevel@tonic-gate 					break;
657*0Sstevel@tonic-gate 			}
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 			preload = MSG_ORIG(MSG_LD_PRELOAD);
660*0Sstevel@tonic-gate 
661*0Sstevel@tonic-gate 			/*
662*0Sstevel@tonic-gate 			 * Determine which preload files and preload environment
663*0Sstevel@tonic-gate 			 * variable to use.
664*0Sstevel@tonic-gate 			 */
665*0Sstevel@tonic-gate 			if (class == ELFCLASS64) {
666*0Sstevel@tonic-gate 				if (prefile_64 != MSG_ORIG(MSG_STR_EMPTY)) {
667*0Sstevel@tonic-gate 					files = prefile_64;
668*0Sstevel@tonic-gate 					preload = MSG_ORIG(MSG_LD_PRELOAD_64);
669*0Sstevel@tonic-gate 				}
670*0Sstevel@tonic-gate 			} else {
671*0Sstevel@tonic-gate 				if (prefile_32 != MSG_ORIG(MSG_STR_EMPTY)) {
672*0Sstevel@tonic-gate 					files = prefile_32;
673*0Sstevel@tonic-gate 					preload = MSG_ORIG(MSG_LD_PRELOAD_32);
674*0Sstevel@tonic-gate 				}
675*0Sstevel@tonic-gate 			}
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate 			if ((str = (char *)malloc(strlen(preload) +
678*0Sstevel@tonic-gate 			    strlen(fname) + strlen(files) + 5)) == 0) {
679*0Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
680*0Sstevel@tonic-gate 				    cname);
681*0Sstevel@tonic-gate 				exit(1);
682*0Sstevel@tonic-gate 			}
683*0Sstevel@tonic-gate 
684*0Sstevel@tonic-gate 			(void) sprintf(str, format, preload, fname, files);
685*0Sstevel@tonic-gate 			if (putenv(str) != 0) {
686*0Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED),
687*0Sstevel@tonic-gate 				    cname);
688*0Sstevel@tonic-gate 				exit(1);
689*0Sstevel@tonic-gate 			}
690*0Sstevel@tonic-gate 			load[LD_LOAD_SIZE - 1] = '2';
691*0Sstevel@tonic-gate 		} else
692*0Sstevel@tonic-gate 			load[LD_LOAD_SIZE - 1] = '1';
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 
695*0Sstevel@tonic-gate 		/*
696*0Sstevel@tonic-gate 		 * Establish new environment variables to affect the child
697*0Sstevel@tonic-gate 		 * process.
698*0Sstevel@tonic-gate 		 */
699*0Sstevel@tonic-gate 		if ((putenv(warn) != 0) || (putenv(bind) != 0) ||
700*0Sstevel@tonic-gate 		    (putenv(path) != 0) || (putenv(verb) != 0) ||
701*0Sstevel@tonic-gate 		    (putenv(fltr) != 0) || (putenv(conf) != 0) ||
702*0Sstevel@tonic-gate 		    (putenv(init) != 0) || (putenv(lazy) != 0) ||
703*0Sstevel@tonic-gate 		    (putenv(uref) != 0) || (putenv(used) != 0) ||
704*0Sstevel@tonic-gate 		    (putenv(load) != 0)) {
705*0Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED), cname);
706*0Sstevel@tonic-gate 			exit(1);
707*0Sstevel@tonic-gate 		}
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate 		/*
710*0Sstevel@tonic-gate 		 * Establish explicit environment requires (but don't override
711*0Sstevel@tonic-gate 		 * any preload request established to process a shared object).
712*0Sstevel@tonic-gate 		 */
713*0Sstevel@tonic-gate 		size = 0;
714*0Sstevel@tonic-gate 		for (LIST_TRAVERSE(&eopts, lnp, str)) {
715*0Sstevel@tonic-gate 			if (preload) {
716*0Sstevel@tonic-gate 				if (size == 0)
717*0Sstevel@tonic-gate 					size = strlen(preload);
718*0Sstevel@tonic-gate 				if ((strncmp(preload, str, size) == 0) &&
719*0Sstevel@tonic-gate 				    (str[size] == '=')) {
720*0Sstevel@tonic-gate 					continue;
721*0Sstevel@tonic-gate 				}
722*0Sstevel@tonic-gate 			}
723*0Sstevel@tonic-gate 			if (putenv(str) != 0) {
724*0Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED),
725*0Sstevel@tonic-gate 				    cname);
726*0Sstevel@tonic-gate 				exit(1);
727*0Sstevel@tonic-gate 			}
728*0Sstevel@tonic-gate 		}
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 		/*
731*0Sstevel@tonic-gate 		 * Execute the object and let ld.so.1 do the rest.
732*0Sstevel@tonic-gate 		 */
733*0Sstevel@tonic-gate 		if (nfile > 1)
734*0Sstevel@tonic-gate 			(void) printf(MSG_ORIG(MSG_STR_FMT3), fname);
735*0Sstevel@tonic-gate 		(void) fflush(stdout);
736*0Sstevel@tonic-gate 		if ((execl(ename, ename, (char *)0)) == -1) {
737*0Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
738*0Sstevel@tonic-gate 			    fname);
739*0Sstevel@tonic-gate 			perror(ename);
740*0Sstevel@tonic-gate 			_exit(0);
741*0Sstevel@tonic-gate 			/* NOTREACHED */
742*0Sstevel@tonic-gate 		}
743*0Sstevel@tonic-gate 	}
744*0Sstevel@tonic-gate 	return (status);
745*0Sstevel@tonic-gate }
746*0Sstevel@tonic-gate 
747*0Sstevel@tonic-gate const char *
748*0Sstevel@tonic-gate _ldd_msg(Msg mid)
749*0Sstevel@tonic-gate {
750*0Sstevel@tonic-gate 	return (gettext(MSG_ORIG(mid)));
751*0Sstevel@tonic-gate }
752