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