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