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