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