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