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