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