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