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