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