xref: /illumos-gate/usr/src/cmd/sgs/crle/common/print.c (revision 4eaa471005973e11a6110b69fe990530b3b95a38)
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 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include	<sys/types.h>
28 #include	<sys/stat.h>
29 #include	<sys/mman.h>
30 #include	<fcntl.h>
31 #include	<stdio.h>
32 #include	<string.h>
33 #include	<unistd.h>
34 #include	<errno.h>
35 #include	<limits.h>
36 #include	<alloca.h>
37 #include	"sgs.h"
38 #include	"rtc.h"
39 #include	"conv.h"
40 #include	"_crle.h"
41 #include	"msg.h"
42 
43 
44 /*
45  * Display the command line required to regenerate the configuration file.
46  *
47  * Under normal mode the command is printed on one line to make it more
48  * available for grep(1) use.  Under verbose mode the command is separated
49  * into each argument (a little more readable perhaps when the arguments are
50  * numerous of have long pathnames).
51  *
52  * Note that for version 1 configuration files we never used to generate any
53  * command-line information, and as the attempt to do so is only a best effort
54  * don't bother printing anything.
55  */
56 static void
57 printcmd(Crle_desc *crle, Rtc_head * head, APlist *cmdline)
58 {
59 	Aliste		idx, lidx;
60 	const char	*fmto, *fmtb, *fmtm, *fmte;
61 	char		*cmd;
62 	int		output = 0;
63 
64 	if (crle->c_flags & CRLE_VERBOSE) {
65 		fmto = MSG_INTL(MSG_DMP_CMD_ONE_V);
66 		fmtb = MSG_INTL(MSG_DMP_CMD_BGN_V);
67 		fmtm = MSG_INTL(MSG_DMP_CMD_MID_V);
68 		fmte = MSG_INTL(MSG_DMP_CMD_END_V);
69 
70 	} else if (head->ch_version > RTC_VER_ONE) {
71 		fmto = MSG_INTL(MSG_DMP_CMD_ONE);
72 		fmtb = MSG_INTL(MSG_DMP_CMD_BGN);
73 		fmtm = MSG_INTL(MSG_DMP_CMD_MID);
74 		fmte = MSG_INTL(MSG_DMP_CMD_END);
75 
76 	} else {
77 		(void) printf(MSG_ORIG(MSG_STR_NL));
78 		return;
79 	}
80 
81 	(void) printf(MSG_INTL(MSG_DMP_CMD_TITLE));
82 
83 	lidx = aplist_nitems(cmdline) - 1;
84 	for (APLIST_TRAVERSE(cmdline, idx, cmd)) {
85 		if (output++ == 0) {
86 			if (idx < lidx)
87 				(void) printf(fmtb, cmd);
88 			else
89 				(void) printf(fmto, cmd);
90 		} else {
91 			if (idx < lidx)
92 				(void) printf(fmtm, cmd);
93 			else
94 				(void) printf(fmte, cmd);
95 		}
96 	}
97 }
98 
99 /*
100  * Establish the argument required to generate the associated object.
101  */
102 static const char *
103 getformat(Half flags)
104 {
105 	if (flags & RTC_OBJ_ALTER) {
106 		if (flags & RTC_OBJ_DUMP) {
107 			if (flags & RTC_OBJ_GROUP)
108 				return (MSG_ORIG(MSG_CMD_DUMPGRP));
109 			else
110 				return (MSG_ORIG(MSG_CMD_DUMPIND));
111 		} else {
112 			if (flags & RTC_OBJ_OPTINAL)
113 				return (MSG_ORIG(MSG_CMD_OPTIONAL));
114 			else
115 				return (MSG_ORIG(MSG_CMD_ALTER));
116 		}
117 	} else {
118 		if (flags & RTC_OBJ_GROUP)
119 			return (MSG_ORIG(MSG_CMD_GRP));
120 		else
121 			return (MSG_ORIG(MSG_CMD_IND));
122 	}
123 }
124 
125 /*
126  * Fabricate a system default search path.  If an update is requested, and
127  * new search paths are specified while no configuration file exists, or if a
128  * configuration file does exist but doesn't specify this particular search
129  * path, create any system defaults.  The intent is to allow
130  * "crle -u -l/usr/local/lib" and have this append the search path to the
131  * system default, rather than have the user have to determine and specify
132  * this default themselves.
133  */
134 static int
135 fablib(Crle_desc * crle, int flag)
136 {
137 	const char	*path;
138 	char		**list;
139 
140 	switch (flag) {
141 	case CRLE_EDLIB:
142 #if M_CLASS == ELFCLASS64
143 #ifndef	SGS_PRE_UNIFIED_PROCESS
144 		path = MSG_ORIG(MSG_PTH_NEWDLP_64);
145 #else
146 		path = MSG_ORIG(MSG_PTH_OLDDLP_64);
147 #endif
148 #else
149 #ifndef	SGS_PRE_UNIFIED_PROCESS
150 		path = MSG_ORIG(MSG_PTH_NEWDLP);
151 #else
152 		path = MSG_ORIG(MSG_PTH_OLDDLP);
153 #endif
154 #endif
155 		list = &crle->c_edlibpath;
156 		break;
157 
158 	case CRLE_ESLIB:
159 #if M_CLASS == ELFCLASS64
160 #ifndef	SGS_PRE_UNIFIED_PROCESS
161 		path = MSG_ORIG(MSG_PTH_NEWTD_64);
162 #else
163 		path = MSG_ORIG(MSG_PTH_OLDTD_64);
164 #endif
165 #else
166 #ifndef	SGS_PRE_UNIFIED_PROCESS
167 		path = MSG_ORIG(MSG_PTH_NEWTD);
168 #else
169 		path = MSG_ORIG(MSG_PTH_OLDTD);
170 #endif
171 #endif
172 		list = &crle->c_eslibpath;
173 		break;
174 
175 	case CRLE_ADLIB:
176 		path = MSG_ORIG(MSG_PTH_AOUTDLP);
177 		list = &crle->c_adlibpath;
178 		break;
179 
180 	case CRLE_ASLIB:
181 #ifndef	SGS_PRE_UNIFIED_PROCESS
182 		path = MSG_ORIG(MSG_PTH_NEWTD);
183 #else
184 		path = MSG_ORIG(MSG_PTH_OLDTD);
185 #endif
186 		list = &crle->c_aslibpath;
187 		break;
188 
189 	default:
190 		return (1);
191 	}
192 
193 	return (addlib(crle, list, path));
194 }
195 
196 /*
197  * Establish the flags required to generate the associated object.  Actually
198  * the flags are already part of the object being inspected from the present
199  * configuration file, but instead of using them all, which can cause some
200  * unsuspected propagation down the inspect() family, only use those flags that
201  * would have been contributed from crle()'s calls to inspect.
202  */
203 static Half
204 getflags(Half flags)
205 {
206 	flags &=
207 	    (RTC_OBJ_ALTER | RTC_OBJ_DUMP | RTC_OBJ_GROUP | RTC_OBJ_OPTINAL);
208 	return (flags | RTC_OBJ_CMDLINE);
209 }
210 
211 /*
212  * Dump a configuration files information.  This routine is very close to the
213  * scanconfig() in libcrle.
214  */
215 /*ARGSUSED2*/
216 static INSCFG_RET
217 scanconfig(Crle_desc * crle, Addr addr, int c_class)
218 {
219 	Conv_inv_buf_t 		inv_buf1, inv_buf2, inv_buf3, inv_buf4;
220 	Conv_dl_flag_buf_t	dl_flag_buf;
221 	Rtc_id		*id;
222 	Rtc_head	*head;
223 	Rtc_dir		*dirtbl;
224 	Rtc_file	*filetbl;
225 	Rtc_obj		*objtbl, *obj;
226 	Word		*hash, *chain;
227 	const char	*strtbl;
228 	int		ndx, bkts;
229 	APlist		*cmdline = NULL;
230 	char		_cmd[PATH_MAX], *cmd;
231 	char		_objdir[PATH_MAX], *objdir = NULL;
232 
233 	/*
234 	 * If there is an Rtc_id present, the Rtc_head follows it.
235 	 * Otherwise, it is at the top.
236 	 */
237 	if (RTC_ID_TEST(addr)) {
238 		id = (Rtc_id *) addr;
239 		addr += sizeof (*id);	/* Rtc_head follows */
240 	} else {
241 		id = NULL;
242 		/*
243 		 * When updating an existing config file that is lacking
244 		 * the Rtc_id block, don't put one into the resulting file.
245 		 */
246 		crle->c_flags &= ~CRLE_ADDID;
247 	}
248 	head = (Rtc_head *) addr;
249 
250 
251 	/*
252 	 * The rest of the configuration file can only be examined by
253 	 * a program of the same ELFCLASS, byte order, and hardware
254 	 * architecture as the one that created it.
255 	 */
256 #ifdef _ELF64
257 	/* 64-bit program with an existing 32-bit file? Abort. */
258 	if (!(head->ch_cnflags & RTC_HDR_64)) {
259 		(void) fprintf(stderr, MSG_INTL(MSG_ARG_CLASS),
260 		    crle->c_name, crle->c_confil);
261 		return (INSCFG_RET_FAIL);
262 	}
263 #else
264 	/* 32-bit program with an existing 64-bit file? Restart. */
265 	if (head->ch_cnflags & RTC_HDR_64)
266 		return (INSCFG_RET_NEED64);
267 
268 	/*
269 	 * 32-bit program with an existing 32-bit file, but the
270 	 * user specified the -64 option? Abort
271 	 */
272 	if (c_class != ELFCLASS32) {
273 		(void) fprintf(stderr, MSG_INTL(MSG_ARG_CLASS),
274 		    crle->c_name, crle->c_confil);
275 		return (INSCFG_RET_FAIL);
276 	}
277 #endif
278 	/*
279 	 * Now that the ELFCLASS has been settled, ensure that the
280 	 * byte order and hardware match. Unlike ELFCLASS, where restarting
281 	 * the other version is an option, we cannot work around a mismatch
282 	 * of these attributes.
283 	 */
284 	if (id) {		/* Rtc_id is present */
285 		/*
286 		 * Was the file produced by compatible hardware?
287 		 * ELFCLASS doesn't matter here, because we can
288 		 * adjust for that, but byte order and machine type do.
289 		 */
290 		if ((id->id_data != M_DATA) || (id->id_machine != M_MACH)) {
291 			(void) fprintf(stderr, MSG_INTL(MSG_ARG_WRONGARCH),
292 			    crle->c_name, crle->c_confil,
293 			    conv_ehdr_data(id->id_data, CONV_FMT_ALT_FILE,
294 			    &inv_buf1),
295 			    conv_ehdr_mach(id->id_machine, CONV_FMT_ALT_FILE,
296 			    &inv_buf2),
297 			    conv_ehdr_data(M_DATA, CONV_FMT_ALT_FILE,
298 			    &inv_buf3),
299 			    conv_ehdr_mach(M_MACH, CONV_FMT_ALT_FILE,
300 			    &inv_buf4));
301 			return (INSCFG_RET_FAIL);
302 		}
303 	}
304 
305 
306 	/* LINTED */
307 	objtbl = (Rtc_obj *)(CAST_PTRINT(char *, head->ch_obj) + addr);
308 	strtbl = (const char *)(CAST_PTRINT(char *, head->ch_str) + addr);
309 
310 	/*
311 	 * If the configuration file has a version higher than we
312 	 * recognise, we face two issues:
313 	 *	(1) Updates are not possible because we have no
314 	 *		way to recognise or propagate the new features.
315 	 *		This has to be a fatal error.
316 	 *	(2) Printing has the risk that we may have been
317 	 *		handed something other than a real config file, as
318 	 *		well as the fact that we can't display the information
319 	 *		for the new features. So, we print a warning, but
320 	 *		continue on to do the best we can with it.
321 	 */
322 	if (head->ch_version > RTC_VER_CURRENT) {
323 		if (crle->c_flags & CRLE_UPDATE) {
324 			(void) fprintf(stderr, MSG_INTL(MSG_ARG_UPDATEVER),
325 			    crle->c_name, crle->c_confil,
326 			    (int)head->ch_version, RTC_VER_CURRENT);
327 			return (INSCFG_RET_FAIL);
328 		} else {
329 			(void) fprintf(stderr, MSG_INTL(MSG_ARG_PRINTVER),
330 			    crle->c_name, crle->c_confil,
331 			    (int)head->ch_version, RTC_VER_CURRENT);
332 		}
333 	}
334 
335 	/*
336 	 * If this is a version 1 configuration file we can't generate accurate
337 	 * update information, or the command-line used to create the file.
338 	 */
339 	if (head->ch_version == RTC_VER_ONE) {
340 		(void) printf(MSG_INTL(MSG_ARG_UPDATE), crle->c_name,
341 		    crle->c_confil, (int)head->ch_version);
342 	}
343 
344 
345 	if (!(crle->c_flags & CRLE_UPDATE) && (head->ch_cnflags & RTC_HDR_64)) {
346 		/*
347 		 * Construct the original command line argument.
348 		 */
349 		cmd = strcpy(alloca(MSG_CMD_64_SIZE + 1), MSG_ORIG(MSG_CMD_64));
350 		if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
351 			return (INSCFG_RET_FAIL);
352 	}
353 
354 
355 	/*
356 	 * Start analyzing the configuration files header information.
357 	 */
358 	if ((crle->c_flags & CRLE_UPDATE) == 0) {
359 		const char	*fmt;
360 
361 		if (head->ch_dlflags)
362 			fmt = conv_dl_flag(head->ch_dlflags, 0, &dl_flag_buf);
363 		else
364 			fmt = MSG_ORIG(MSG_STR_EMPTY);
365 
366 		(void) printf(MSG_INTL(MSG_DMP_HEAD), (int)head->ch_version,
367 		    crle->c_confil, fmt);
368 
369 		/*
370 		 * If the file has an id block, show the information
371 		 */
372 		if (id)
373 			(void) printf(MSG_INTL(MSG_DMP_PLATFORM),
374 			    conv_ehdr_class(id->id_class, CONV_FMT_ALT_FILE,
375 			    &inv_buf1),
376 			    conv_ehdr_data(id->id_data, CONV_FMT_ALT_FILE,
377 			    &inv_buf2),
378 			    conv_ehdr_mach(id->id_machine, CONV_FMT_ALT_FILE,
379 			    &inv_buf3));
380 
381 		/*
382 		 * Construct the original command line argument.
383 		 */
384 		(void) snprintf(_cmd, PATH_MAX, MSG_ORIG(MSG_CMD_CONF),
385 		    crle->c_confil);
386 		cmd = strcpy(alloca(strlen(_cmd) + 1), _cmd);
387 		if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
388 			return (INSCFG_RET_FAIL);
389 
390 		/*
391 		 * Construct any -f usage.
392 		 */
393 		if (head->ch_dlflags &&
394 		    (head->ch_dlflags != RTLD_REL_RELATIVE)) {
395 			(void) snprintf(_cmd, PATH_MAX, MSG_ORIG(MSG_CMD_FLAGS),
396 			    conv_dl_flag(head->ch_dlflags, CONV_FMT_ALT_CRLE,
397 			    &dl_flag_buf));
398 			cmd = strcpy(alloca(strlen(_cmd) + 1), _cmd);
399 			if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
400 				return (INSCFG_RET_FAIL);
401 		}
402 	} else {
403 		/*
404 		 * Establish any -f usage.
405 		 */
406 		if (head->ch_dlflags &&
407 		    (head->ch_dlflags != RTLD_REL_RELATIVE))
408 			crle->c_dlflags = head->ch_dlflags;
409 	}
410 
411 
412 	/*
413 	 * Determine if this configuration file is only applicable to a specific
414 	 * application.
415 	 */
416 	if (head->ch_app) {
417 		char	*alter;
418 
419 		obj = (Rtc_obj *)(head->ch_app + addr);
420 
421 		/*
422 		 * Determine the output directory for the files
423 		 * alternative name.
424 		 */
425 		alter = (char *)(strtbl + obj->co_alter);
426 		(void) strcpy(_objdir, alter);
427 		alter = strrchr(_objdir, '/');
428 		*alter = '\0';
429 
430 		crle->c_objdir = objdir = _objdir;
431 
432 		if (crle->c_flags & CRLE_UPDATE) {
433 			if (inspect(crle, (strtbl + obj->co_name),
434 			    (RTC_OBJ_DUMP | RTC_OBJ_ALTER |
435 			    RTC_OBJ_GROUP | RTC_OBJ_CMDLINE)) != 0)
436 				return (INSCFG_RET_FAIL);
437 		} else {
438 			(void) printf(MSG_INTL(MSG_DMP_APP),
439 			    (strtbl + obj->co_alter), (strtbl + obj->co_name));
440 
441 			/*
442 			 * Construct the original command line arguments.
443 			 */
444 			(void) snprintf(_cmd, PATH_MAX,
445 			    MSG_ORIG(MSG_CMD_OUTPUT), crle->c_objdir);
446 			cmd = strcpy(alloca(strlen(_cmd) + 1), _cmd);
447 			if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
448 				return (INSCFG_RET_FAIL);
449 
450 			(void) snprintf(_cmd, PATH_MAX,
451 			    MSG_ORIG(MSG_CMD_DUMPGRP), (strtbl + obj->co_name));
452 			cmd = strcpy(alloca(strlen(_cmd) + 1), _cmd);
453 			if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
454 				return (INSCFG_RET_FAIL);
455 		}
456 	}
457 
458 	/*
459 	 * Analyze any alternative library path and trusted directory entries.
460 	 */
461 	if (head->ch_edlibpath) {
462 		const char	*str;
463 
464 		str = (const char *)(head->ch_edlibpath + addr);
465 
466 		if (crle->c_flags & CRLE_UPDATE) {
467 			crle->c_flags &= ~CRLE_AOUT;
468 
469 #ifndef	SGS_PRE_UNIFIED_PROCESS
470 			if ((head->ch_cnflags & RTC_HDR_UPM) == 0) {
471 				if (head->ch_cnflags & RTC_HDR_64)
472 					str = conv_config_upm(str,
473 					    MSG_ORIG(MSG_PTH_OLDDLP_64),
474 					    MSG_ORIG(MSG_PTH_UPDLP_64),
475 					    MSG_PTH_UPDLP_64_SIZE);
476 				else
477 					str = conv_config_upm(str,
478 					    MSG_ORIG(MSG_PTH_OLDDLP),
479 					    MSG_ORIG(MSG_PTH_UPDLP),
480 					    MSG_PTH_UPDLP_SIZE);
481 			}
482 #endif
483 			if (addlib(crle, &crle->c_edlibpath, str) != 0)
484 				return (INSCFG_RET_FAIL);
485 		} else {
486 			(void) printf(MSG_INTL(MSG_DMP_DLIBPTH),
487 			    MSG_ORIG(MSG_STR_ELF), str);
488 
489 			(void) snprintf(_cmd, PATH_MAX,
490 			    MSG_ORIG(MSG_CMD_EDLIB), str);
491 			cmd = strcpy(alloca(strlen(_cmd) + 1), _cmd);
492 			if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
493 				return (INSCFG_RET_FAIL);
494 		}
495 	} else {
496 		if (crle->c_flags & CRLE_UPDATE) {
497 			if (crle->c_flags & CRLE_EDLIB) {
498 				/*
499 				 * If we've been asked to update a configuration
500 				 * file, and no existing default ELF search
501 				 * path exists, but the user is going to add new
502 				 * entries, fabricate the system defaults so
503 				 * that the users get added to them.
504 				 */
505 				if (fablib(crle, CRLE_EDLIB) != 0)
506 					return (INSCFG_RET_FAIL);
507 			}
508 		} else {
509 			/*
510 			 * Indicate any system default.
511 			 */
512 #if M_CLASS == ELFCLASS64
513 #ifndef	SGS_PRE_UNIFIED_PROCESS
514 			(void) printf(MSG_INTL(MSG_DEF_NEWDLP_64));
515 #else
516 			(void) printf(MSG_INTL(MSG_DEF_OLDDLP_64));
517 #endif
518 #else
519 #ifndef	SGS_PRE_UNIFIED_PROCESS
520 			(void) printf(MSG_INTL(MSG_DEF_NEWDLP));
521 #else
522 			(void) printf(MSG_INTL(MSG_DEF_OLDDLP));
523 #endif
524 #endif
525 		}
526 	}
527 
528 	if (head->ch_eslibpath) {
529 		const char	*str;
530 
531 		str = (const char *)(head->ch_eslibpath + addr);
532 
533 		if (crle->c_flags & CRLE_UPDATE) {
534 			crle->c_flags &= ~CRLE_AOUT;
535 
536 #ifndef	SGS_PRE_UNIFIED_PROCESS
537 			if ((head->ch_cnflags & RTC_HDR_UPM) == 0) {
538 				if (head->ch_cnflags & RTC_HDR_64)
539 					str = conv_config_upm(str,
540 					    MSG_ORIG(MSG_PTH_OLDTD_64),
541 					    MSG_ORIG(MSG_PTH_UPTD_64),
542 					    MSG_PTH_UPTD_64_SIZE);
543 				else
544 					str = conv_config_upm(str,
545 					    MSG_ORIG(MSG_PTH_OLDTD),
546 					    MSG_ORIG(MSG_PTH_UPTD),
547 					    MSG_PTH_UPTD_SIZE);
548 			}
549 #endif
550 			if (addlib(crle, &crle->c_eslibpath, str) != 0)
551 				return (INSCFG_RET_FAIL);
552 		} else {
553 			(void) printf(MSG_INTL(MSG_DMP_TLIBPTH),
554 			    MSG_ORIG(MSG_STR_ELF), str);
555 
556 			(void) snprintf(_cmd, PATH_MAX,
557 			    MSG_ORIG(MSG_CMD_ESLIB), str);
558 			cmd = strcpy(alloca(strlen(_cmd) + 1), _cmd);
559 			if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
560 				return (INSCFG_RET_FAIL);
561 		}
562 	} else {
563 		if (crle->c_flags & CRLE_UPDATE) {
564 			if (crle->c_flags & CRLE_ESLIB) {
565 				/*
566 				 * If we've been asked to update a configuration
567 				 * file, and no existing default ELF secure
568 				 * path exists, but the user is going to add new
569 				 * entries, fabricate the system defaults so
570 				 * that the users get added to them.
571 				 */
572 				if (fablib(crle, CRLE_ESLIB) != 0)
573 					return (INSCFG_RET_FAIL);
574 			}
575 		} else {
576 			/*
577 			 * Indicate any system default.
578 			 */
579 #if M_CLASS == ELFCLASS64
580 #ifndef	SGS_PRE_UNIFIED_PROCESS
581 			(void) printf(MSG_INTL(MSG_DEF_NEWTD_64));
582 #else
583 			(void) printf(MSG_INTL(MSG_DEF_OLDTD_64));
584 #endif
585 #else
586 #ifndef	SGS_PRE_UNIFIED_PROCESS
587 			(void) printf(MSG_INTL(MSG_DEF_NEWTD));
588 #else
589 			(void) printf(MSG_INTL(MSG_DEF_OLDTD));
590 #endif
591 #endif
592 		}
593 	}
594 
595 	if (head->ch_adlibpath) {
596 		const char	*str;
597 
598 		str = (const char *)(head->ch_adlibpath + addr);
599 
600 		if (crle->c_flags & CRLE_UPDATE) {
601 			crle->c_flags |= CRLE_AOUT;
602 			if (addlib(crle, &crle->c_adlibpath, str) != 0)
603 				return (INSCFG_RET_FAIL);
604 		} else {
605 			(void) printf(MSG_INTL(MSG_DMP_DLIBPTH),
606 			    MSG_ORIG(MSG_STR_AOUT), str);
607 
608 			(void) snprintf(_cmd, PATH_MAX,
609 			    MSG_ORIG(MSG_CMD_ADLIB), str);
610 			cmd = strcpy(alloca(strlen(_cmd) + 1), _cmd);
611 			if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
612 				return (INSCFG_RET_FAIL);
613 		}
614 	} else {
615 		if (crle->c_flags & CRLE_UPDATE) {
616 			if (crle->c_flags & CRLE_ADLIB) {
617 				/*
618 				 * If we've been asked to update a configuration
619 				 * file, and no existing default AOUT search
620 				 * path exists, but the user is going to add new
621 				 * entries, fabricate the system defaults so
622 				 * that the users get added to them.
623 				 */
624 				if (fablib(crle, CRLE_ADLIB) != 0)
625 					return (INSCFG_RET_FAIL);
626 			}
627 		} else if (crle->c_flags & CRLE_AOUT) {
628 			/*
629 			 * Indicate any system default.
630 			 */
631 			(void) printf(MSG_INTL(MSG_DEF_AOUTDLP));
632 		}
633 	}
634 
635 	if (head->ch_aslibpath) {
636 		const char	*str;
637 
638 		str = (const char *)(head->ch_aslibpath + addr);
639 
640 		if (crle->c_flags & CRLE_UPDATE) {
641 			crle->c_flags |= CRLE_AOUT;
642 			if (addlib(crle, &crle->c_aslibpath, str) != 0)
643 				return (INSCFG_RET_FAIL);
644 		} else {
645 			(void) printf(MSG_INTL(MSG_DMP_TLIBPTH),
646 			    MSG_ORIG(MSG_STR_AOUT), str);
647 
648 			(void) snprintf(_cmd, PATH_MAX,
649 			    MSG_ORIG(MSG_CMD_ASLIB), str);
650 			cmd = strcpy(alloca(strlen(_cmd) + 1), _cmd);
651 			if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
652 				return (INSCFG_RET_FAIL);
653 		}
654 	} else {
655 		if (crle->c_flags & CRLE_UPDATE) {
656 			if (crle->c_flags & CRLE_ASLIB) {
657 				/*
658 				 * If we've been asked to update a configuration
659 				 * file, and no existing default AOUT secure
660 				 * path exists, but the user is going to add new
661 				 * entries, fabricate the system defaults so
662 				 * that the users get added to them.
663 				 */
664 				if (fablib(crle, CRLE_ASLIB) != 0)
665 					return (INSCFG_RET_FAIL);
666 			}
667 		} else if (crle->c_flags & CRLE_AOUT) {
668 			/*
669 			 * Indicate any system default.
670 			 */
671 #ifndef	SGS_PRE_UNIFIED_PROCESS
672 			(void) printf(MSG_INTL(MSG_DEF_AOUTNEWTD));
673 #else
674 			(void) printf(MSG_INTL(MSG_DEF_AOUTOLDTD));
675 #endif
676 		}
677 	}
678 
679 	/*
680 	 * Display any environment variables.
681 	 */
682 	if ((head->ch_version >= RTC_VER_THREE) && head->ch_env) {
683 		Rtc_env	*envtbl;
684 
685 		if ((crle->c_flags & CRLE_UPDATE) == 0)
686 			(void) printf(MSG_INTL(MSG_ENV_TITLE));
687 
688 		for (envtbl = (Rtc_env *)(head->ch_env + addr);
689 		    envtbl->env_str; envtbl++) {
690 			const char	*str;
691 
692 			str = (const char *)(envtbl->env_str + addr);
693 
694 			if (crle->c_flags & CRLE_UPDATE) {
695 				if (addenv(crle, str,
696 				    (envtbl->env_flags | RTC_ENV_CONFIG)) == 0)
697 					return (INSCFG_RET_FAIL);
698 			} else {
699 				const char	*pfmt, *sfmt;
700 
701 				if (envtbl->env_flags & RTC_ENV_PERMANT) {
702 					pfmt = MSG_INTL(MSG_ENV_PRM);
703 					sfmt = MSG_ORIG(MSG_CMD_PRMENV);
704 				} else {
705 					pfmt = MSG_INTL(MSG_ENV_RPL);
706 					sfmt = MSG_ORIG(MSG_CMD_RPLENV);
707 				}
708 				(void) printf(pfmt, str);
709 				(void) snprintf(_cmd, PATH_MAX, sfmt, str);
710 				cmd = strcpy(alloca(strlen(_cmd) + 1), _cmd);
711 				if (aplist_append(&cmdline, cmd,
712 				    AL_CNT_CRLE) == NULL)
713 					return (INSCFG_RET_FAIL);
714 			}
715 		}
716 	}
717 
718 	/*
719 	 * Display any filter/filtee associations.
720 	 */
721 	if ((head->ch_version >= RTC_VER_FOUR) && head->ch_fltr) {
722 		if ((crle->c_flags & CRLE_UPDATE) == 0) {
723 			Rtc_fltr	*fltrtbl;
724 			Rtc_flte	*fltetbl;
725 
726 			/* LINTED */
727 			fltrtbl = (Rtc_fltr *)
728 			    (CAST_PTRINT(char *, head->ch_fltr) + addr);
729 			/* LINTED */
730 			fltetbl = (Rtc_flte *)
731 			    (CAST_PTRINT(char *, head->ch_flte) + addr);
732 
733 			(void) printf(MSG_INTL(MSG_FLT_TITLE));
734 
735 			while (fltrtbl->fr_filter) {
736 				Rtc_flte	*_fltetbl;
737 
738 				/*
739 				 * Print the filter and filtee string pair.
740 				 */
741 				(void) printf(MSG_INTL(MSG_FLT_FILTER),
742 				    (strtbl + fltrtbl->fr_filter),
743 				    (strtbl + fltrtbl->fr_string));
744 
745 				/*
746 				 * Print each filtee.
747 				 */
748 				/* LINTED */
749 				for (_fltetbl = (Rtc_flte *)((char *)fltetbl +
750 				    fltrtbl->fr_filtee); _fltetbl->fe_filtee;
751 				    _fltetbl++) {
752 					(void) printf(MSG_INTL(MSG_FLT_FILTEE),
753 					    (strtbl + _fltetbl->fe_filtee));
754 				}
755 				fltrtbl++;
756 			}
757 		}
758 	}
759 
760 	/*
761 	 * Display any memory reservations required for any alternative
762 	 * objects.
763 	 */
764 	if (head->ch_resbgn && ((crle->c_flags & CRLE_UPDATE) == 0))
765 		(void) printf(MSG_INTL(MSG_DMP_RESV),
766 		    (u_longlong_t)head->ch_resbgn,
767 		    (u_longlong_t)head->ch_resend,
768 		    (u_longlong_t)(head->ch_resend - head->ch_resbgn));
769 
770 	/*
771 	 * If there's no hash table there's nothing else to process.
772 	 */
773 	if (head->ch_hash == 0) {
774 		if ((crle->c_flags & CRLE_UPDATE) == 0)
775 			printcmd(crle, head, cmdline);
776 		return (INSCFG_RET_OK);
777 	}
778 
779 	/*
780 	 * Traverse the directory and filename arrays.
781 	 */
782 	for (dirtbl = (Rtc_dir *)(head->ch_dir + addr);
783 	    dirtbl->cd_obj; dirtbl++) {
784 		struct stat	status;
785 		Rtc_obj		*dobj;
786 		const char	*str;
787 
788 		dobj = (Rtc_obj *)(dirtbl->cd_obj + addr);
789 		filetbl = (Rtc_file *)(dirtbl->cd_file + addr);
790 		str = strtbl + dobj->co_name;
791 
792 		/*
793 		 * Simplify recreation by using any command-line directories.
794 		 * If we're dealing with a version 1 configuration file use
795 		 * every directory.
796 		 */
797 		if ((dobj->co_flags & RTC_OBJ_CMDLINE) ||
798 		    (head->ch_version == RTC_VER_ONE)) {
799 			if (crle->c_flags & CRLE_UPDATE) {
800 				if (inspect(crle, str,
801 				    getflags(dobj->co_flags)) != 0)
802 					return (INSCFG_RET_FAIL);
803 				if ((dobj->co_flags &
804 				    (RTC_OBJ_NOEXIST | RTC_OBJ_ALTER)) ==
805 				    RTC_OBJ_NOEXIST)
806 					continue;
807 			} else {
808 				/* LINTED */
809 				(void) snprintf(_cmd, PATH_MAX,
810 				    getformat(dobj->co_flags), str);
811 				cmd = strcpy(alloca(strlen(_cmd) + 1), _cmd);
812 				if (aplist_append(&cmdline, cmd,
813 				    AL_CNT_CRLE) == NULL)
814 					return (INSCFG_RET_FAIL);
815 			}
816 		}
817 
818 		/*
819 		 * If this isn't an update print the directory name.  If the
820 		 * directory has no entries (possible if the directory is a
821 		 * symlink to another directory, in which case we record the
822 		 * real path also), don't bother printing it unless we're in
823 		 * verbose mode.
824 		 */
825 		if ((crle->c_flags & CRLE_UPDATE) == 0) {
826 			if ((dobj->co_flags &
827 			    (RTC_OBJ_NOEXIST | RTC_OBJ_ALTER)) ==
828 			    RTC_OBJ_NOEXIST) {
829 				(void) printf(MSG_INTL(MSG_DMP_DIR_2), str);
830 				continue;
831 			} else if (filetbl->cf_obj ||
832 			    (crle->c_flags & CRLE_VERBOSE))
833 				(void) printf(MSG_INTL(MSG_DMP_DIR_1), str);
834 		}
835 
836 		/*
837 		 * Under verbose mode validate any real directory entry - the
838 		 * same test will be carried out by ld.so.1.
839 		 */
840 		if (((crle->c_flags & CRLE_UPDATE) == 0) &&
841 		    (crle->c_flags & CRLE_VERBOSE) &&
842 		    (dobj->co_flags & RTC_OBJ_REALPTH)) {
843 			if (stat(str, &status) != 0) {
844 				int err = errno;
845 				(void) printf(MSG_INTL(MSG_DMP_STAT), str,
846 				    strerror(err));
847 			} else if (status.st_mtime != dobj->co_info) {
848 				(void) printf(MSG_INTL(MSG_DMP_DCMP), str);
849 			}
850 		}
851 
852 		for (; filetbl->cf_obj; filetbl++) {
853 			Rtc_obj	*fobj;
854 			Half	flags;
855 
856 			fobj = (Rtc_obj *)(filetbl->cf_obj + addr);
857 			str = strtbl + fobj->co_name;
858 			flags = fobj->co_flags;
859 
860 			/*
861 			 * Only update individual files that were originally
862 			 * specified on the command-line.  Or, if this is a
863 			 * version 1 configuration file use every file that
864 			 * isn't part of an all-entries directory.
865 			 */
866 			if (((flags & RTC_OBJ_CMDLINE) &&
867 			    ((fobj->co_flags & RTC_OBJ_APP) == 0)) ||
868 			    ((head->ch_version == RTC_VER_ONE) &&
869 			    ((dobj->co_flags & RTC_OBJ_ALLENTS) == 0))) {
870 				char	*alter = NULL, altdir[PATH_MAX];
871 
872 				/*
873 				 * Determine whether this file requires an
874 				 * alternative, and if so, and we haven't
875 				 * already an alternative in affect, create one.
876 				 */
877 				if (fobj->co_flags & RTC_OBJ_ALTER) {
878 					alter = (char *)(strtbl +
879 					    fobj->co_alter);
880 					(void) strcpy(altdir, alter);
881 					alter = strrchr(altdir, '/');
882 					*alter = '\0';
883 
884 					if ((objdir == NULL) ||
885 					    (strcmp(objdir, altdir) != 0)) {
886 						(void) strcpy(_objdir, altdir);
887 						crle->c_objdir = alter =
888 						    objdir = _objdir;
889 					} else
890 						alter = NULL;
891 				}
892 
893 				if (crle->c_flags & CRLE_UPDATE) {
894 					if (inspect(crle, str,
895 					    getflags(flags)) != 0)
896 						return (INSCFG_RET_FAIL);
897 					continue;
898 				}
899 
900 				if (alter) {
901 					(void) snprintf(_cmd, PATH_MAX,
902 					    MSG_ORIG(MSG_CMD_OUTPUT),
903 					    crle->c_objdir);
904 					cmd = strcpy(alloca(strlen(_cmd) + 1),
905 					    _cmd);
906 					if (aplist_append(&cmdline, cmd,
907 					    AL_CNT_CRLE) == NULL)
908 						return (INSCFG_RET_FAIL);
909 				}
910 
911 				/* LINTED */
912 				(void) snprintf(_cmd, PATH_MAX,
913 				    getformat(flags), str);
914 				cmd = strcpy(alloca(strlen(_cmd) + 1), _cmd);
915 				if (aplist_append(&cmdline, cmd,
916 				    AL_CNT_CRLE) == NULL)
917 					return (INSCFG_RET_FAIL);
918 			}
919 
920 			if (crle->c_flags & CRLE_UPDATE)
921 				continue;
922 
923 			/*
924 			 * Although we record both full pathnames and their
925 			 * simple filenames (basename), only print the simple
926 			 * names unless we're under verbose mode.
927 			 */
928 			if ((strchr(str, '/') == 0) ||
929 			    (crle->c_flags & CRLE_VERBOSE)) {
930 				if (fobj->co_flags & RTC_OBJ_ALTER)
931 					(void) printf(MSG_INTL(MSG_DMP_FILE_2),
932 					    str, (strtbl + fobj->co_alter));
933 				else
934 					(void) printf(MSG_INTL(MSG_DMP_FILE_1),
935 					    str);
936 			}
937 
938 			/*
939 			 * Under verbose mode validate any real file entry - the
940 			 * same test will be carried out by ld.so.1.
941 			 */
942 			if ((crle->c_flags & CRLE_VERBOSE) &&
943 			    (fobj->co_flags & RTC_OBJ_REALPTH)) {
944 				if (stat(str, &status) != 0) {
945 					int err = errno;
946 					(void) printf(MSG_INTL(MSG_DMP_STAT),
947 					    str, strerror(err));
948 				} else if (status.st_size != fobj->co_info) {
949 					(void) printf(MSG_INTL(MSG_DMP_FCMP),
950 					    str);
951 				}
952 			}
953 		}
954 	}
955 
956 	if ((crle->c_flags & CRLE_UPDATE) == 0)
957 		printcmd(crle, head, cmdline);
958 
959 	if ((crle->c_flags & CRLE_VERBOSE) == 0)
960 		return (INSCFG_RET_OK);
961 
962 	/*
963 	 * If we've in verbose mode scan the hash list.
964 	 */
965 	/* LINTED */
966 	hash = (Word *)(CAST_PTRINT(char *, head->ch_hash) + addr);
967 	bkts = hash[0];
968 	chain = &hash[2 + bkts];
969 	hash += 2;
970 
971 	(void) printf(MSG_INTL(MSG_DMP_HASH));
972 
973 	/*
974 	 * Scan the hash buckets looking for valid entries.
975 	 */
976 	for (ndx = 0; ndx < bkts; ndx++, hash++) {
977 		Conv_config_obj_buf_t	config_obj_buf;
978 		Rtc_obj			*obj;
979 		const char		*str;
980 		Word			_ndx;
981 
982 		if (*hash == NULL)
983 			continue;
984 
985 		obj = objtbl + *hash;
986 		str = strtbl + obj->co_name;
987 
988 		(void) printf(MSG_INTL(MSG_DMP_HASHENT_1), obj->co_id, ndx,
989 		    str, conv_config_obj(obj->co_flags, &config_obj_buf));
990 
991 		/*
992 		 * Determine whether there are other objects chained to this
993 		 * bucket.
994 		 */
995 		for (_ndx = chain[*hash]; _ndx; _ndx = chain[_ndx]) {
996 			obj = objtbl + _ndx;
997 			str = strtbl + obj->co_name;
998 
999 			(void) printf(MSG_INTL(MSG_DMP_HASHENT_2), obj->co_id,
1000 			    str, conv_config_obj(obj->co_flags,
1001 			    &config_obj_buf));
1002 		}
1003 	}
1004 	(void) printf(MSG_ORIG(MSG_STR_NL));
1005 
1006 	return (INSCFG_RET_OK);
1007 }
1008 
1009 
1010 INSCFG_RET
1011 inspectconfig(Crle_desc * crle, int c_class)
1012 {
1013 	INSCFG_RET	error;
1014 	int		fd;
1015 	Addr		addr;
1016 	struct stat	status;
1017 	const char	*caller = crle->c_name, *file = crle->c_confil;
1018 	Conv_inv_buf_t	inv_buf1, inv_buf2, inv_buf3;
1019 
1020 	/*
1021 	 * Open the configuration file, determine its size and map it in.
1022 	 */
1023 	if ((fd = open(file, O_RDONLY, 0)) == -1) {
1024 		int	err = errno;
1025 
1026 		if (err == ENOENT) {
1027 #ifndef _ELF64
1028 			/* Must restart if user requested a 64-bit file */
1029 			if (c_class == ELFCLASS64)
1030 				return (INSCFG_RET_NEED64);
1031 #endif
1032 
1033 			/*
1034 			 * To allow an update (-u) from scratch, fabricate any
1035 			 * default search and secure paths that the user
1036 			 * intends to add to.
1037 			 */
1038 			if (crle->c_flags & CRLE_UPDATE) {
1039 				if (crle->c_flags & CRLE_EDLIB) {
1040 					if (fablib(crle, CRLE_EDLIB))
1041 						return (INSCFG_RET_FAIL);
1042 				}
1043 				if (crle->c_flags & CRLE_ESLIB) {
1044 					if (fablib(crle, CRLE_ESLIB))
1045 						return (INSCFG_RET_FAIL);
1046 				}
1047 				if (crle->c_flags & CRLE_ADLIB) {
1048 					if (fablib(crle, CRLE_ADLIB))
1049 						return (INSCFG_RET_FAIL);
1050 				}
1051 				if (crle->c_flags & CRLE_ASLIB) {
1052 					if (fablib(crle, CRLE_ASLIB))
1053 						return (INSCFG_RET_FAIL);
1054 				}
1055 				return (INSCFG_RET_OK);
1056 
1057 			} else if (crle->c_flags & CRLE_CONFDEF) {
1058 				const char	*fmt1, *fmt2;
1059 
1060 				/*
1061 				 * Otherwise if the user is inspecting a default
1062 				 * configuration file that doesn't exist inform
1063 				 * them and display the ELF defaults.
1064 				 */
1065 				(void) printf(MSG_INTL(MSG_DEF_NOCONF), file);
1066 				(void) printf(MSG_INTL(MSG_DMP_PLATFORM),
1067 				    conv_ehdr_class(M_CLASS,
1068 				    CONV_FMT_ALT_FILE, &inv_buf1),
1069 				    conv_ehdr_data(M_DATA,
1070 				    CONV_FMT_ALT_FILE, &inv_buf2),
1071 				    conv_ehdr_mach(M_MACH,
1072 				    CONV_FMT_ALT_FILE, &inv_buf3));
1073 
1074 
1075 				if (crle->c_flags & CRLE_AOUT) {
1076 					fmt1 = MSG_INTL(MSG_DEF_AOUTDLP);
1077 #ifndef SGS_PRE_UNIFIED_PROCESS
1078 					fmt2 = MSG_INTL(MSG_DEF_AOUTNEWTD);
1079 #else
1080 					fmt2 = MSG_INTL(MSG_DEF_AOUTOLDTD);
1081 #endif
1082 				} else {
1083 #if M_CLASS == ELFCLASS64
1084 #ifndef	SGS_PRE_UNIFIED_PROCESS
1085 					fmt1 = MSG_INTL(MSG_DEF_NEWDLP_64);
1086 					fmt2 = MSG_INTL(MSG_DEF_NEWTD_64);
1087 #else
1088 					fmt1 = MSG_INTL(MSG_DEF_OLDDLP_64);
1089 					fmt2 = MSG_INTL(MSG_DEF_OLDTD_64);
1090 #endif
1091 #else
1092 #ifndef	SGS_PRE_UNIFIED_PROCESS
1093 					fmt1 = MSG_INTL(MSG_DEF_NEWDLP);
1094 					fmt2 = MSG_INTL(MSG_DEF_NEWTD);
1095 #else
1096 					fmt1 = MSG_INTL(MSG_DEF_OLDDLP);
1097 					fmt2 = MSG_INTL(MSG_DEF_OLDTD);
1098 #endif
1099 #endif
1100 				}
1101 				(void) printf(fmt1);
1102 				(void) printf(fmt2);
1103 
1104 				return (INSCFG_RET_OK);
1105 			}
1106 		}
1107 
1108 		/*
1109 		 * Otherwise there's an error condition in accessing the file.
1110 		 */
1111 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), caller, file,
1112 		    strerror(err));
1113 
1114 		return (INSCFG_RET_FAIL);
1115 	}
1116 
1117 	(void) fstat(fd, &status);
1118 	if (status.st_size < sizeof (Rtc_head)) {
1119 		(void) close(fd);
1120 		(void) fprintf(stderr, MSG_INTL(MSG_COR_TRUNC), caller, file);
1121 		return (INSCFG_RET_FAIL);
1122 	}
1123 	if ((addr = (Addr)mmap(0, status.st_size, PROT_READ, MAP_SHARED,
1124 	    fd, 0)) == (Addr)MAP_FAILED) {
1125 		int err = errno;
1126 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_MMAP), caller, file,
1127 		    strerror(err));
1128 		(void) close(fd);
1129 		return (INSCFG_RET_FAIL);
1130 	}
1131 	(void) close(fd);
1132 
1133 	/*
1134 	 * Print the contents of the configuration file.
1135 	 */
1136 	error = scanconfig(crle, addr, c_class);
1137 
1138 	(void) munmap((void *)addr, status.st_size);
1139 	return (error);
1140 }
1141