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