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