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