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