xref: /illumos-gate/usr/src/cmd/sgs/libconv/common/config.c (revision 29e83d4b25fd82feb8e0e0fbe89f7e2a8438533d)
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	<stdlib.h>
29 #include	<sys/types.h>
30 #include	<string.h>
31 #include	"rtc.h"
32 #include	"_conv.h"
33 #include	"config_msg.h"
34 
35 #define	FEATSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
36 		MSG_CONF_EDLIBPATH_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
37 		MSG_CONF_ESLIBPATH_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
38 		MSG_CONF_ADLIBPATH_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
39 		MSG_CONF_ASLIBPATH_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
40 		MSG_CONF_DIRCFG_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
41 		MSG_CONF_OBJALT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
42 		MSG_CONF_MEMRESV_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
43 		MSG_CONF_ENVS_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
44 		MSG_CONF_FLTR_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
45 		CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
46 
47 /*
48  * Ensure that Conv_config_feat_buf_t is large enough:
49  *
50  * FEATSZ is the real minimum size of the buffer required by conv_config_feat().
51  * However, Conv_config_feat_buf_t uses CONV_CONFIG_FEAT_BUFSIZE to set the
52  * buffer size. We do things this way because the definition of FEATSZ uses
53  * information that is not available in the environment of other programs
54  * that include the conv.h header file.
55  */
56 #if (CONV_CONFIG_FEAT_BUFSIZE < FEATSZ) && !defined(__lint)
57 #error "CONV_CONFIG_FEAT_BUFSIZE is not large enough"
58 #endif
59 
60 /*
61  * String conversion routine for configuration file information.
62  */
63 const char *
64 conv_config_feat(int features, Conv_config_feat_buf_t *config_feat_buf)
65 {
66 	static Val_desc	vda[] = {
67 		{ CONF_EDLIBPATH,	MSG_ORIG(MSG_CONF_EDLIBPATH) },
68 		{ CONF_ESLIBPATH,	MSG_ORIG(MSG_CONF_ESLIBPATH) },
69 		{ CONF_ADLIBPATH,	MSG_ORIG(MSG_CONF_ADLIBPATH) },
70 		{ CONF_ASLIBPATH,	MSG_ORIG(MSG_CONF_ASLIBPATH) },
71 		{ CONF_DIRCFG,		MSG_ORIG(MSG_CONF_DIRCFG) },
72 		{ CONF_OBJALT,		MSG_ORIG(MSG_CONF_OBJALT) },
73 		{ CONF_MEMRESV,		MSG_ORIG(MSG_CONF_MEMRESV) },
74 		{ CONF_ENVS,		MSG_ORIG(MSG_CONF_ENVS) },
75 		{ CONF_FLTR,		MSG_ORIG(MSG_CONF_FLTR) },
76 		{ 0,			0 }
77 	};
78 	static CONV_EXPN_FIELD_ARG conv_arg = {
79 	    NULL, sizeof (config_feat_buf->buf), vda };
80 
81 	conv_arg.buf = config_feat_buf->buf;
82 	conv_arg.oflags = conv_arg.rflags = features;
83 	(void) conv_expn_field(&conv_arg);
84 
85 	return ((const char *)config_feat_buf->buf);
86 }
87 
88 #define	FLAGSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
89 		MSG_CONF_DIRENT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
90 		MSG_CONF_ALLENTS_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
91 		MSG_CONF_NOEXIST_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
92 		MSG_CONF_EXEC_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
93 		MSG_CONF_ALTER_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
94 		MSG_CONF_OPTIONAL_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
95 		MSG_CONF_DUMP_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
96 		MSG_CONF_REALPATH_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
97 		MSG_CONF_NOALTER_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
98 		MSG_CONF_GROUP_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
99 		MSG_CONF_APP_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
100 		MSG_CONF_CMDLINE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
101 		MSG_CONF_FILTER_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
102 		MSG_CONF_FILTEE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
103 		CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
104 
105 /*
106  * Ensure that Conv_config_obj_buf_t is large enough:
107  *
108  * FLAGSZ is the real minimum size of the buffer required by conv_config_obj().
109  * However, Conv_config_obj_buf_t uses CONV_CONFIG_OBJ_BUFSIZE to set the
110  * buffer size. We do things this way because the definition of FLAGSZ uses
111  * information that is not available in the environment of other programs
112  * that include the conv.h header file.
113  */
114 #if (CONV_CONFIG_OBJ_BUFSIZE < FLAGSZ) && !defined(__lint)
115 #error "CONV_CONFIG_OBJ_BUFSIZE is not large enough"
116 #endif
117 
118 /*
119  * String conversion routine for object flags.
120  */
121 const char *
122 conv_config_obj(ushort_t flags, Conv_config_obj_buf_t *config_obj_buf)
123 {
124 	static Val_desc vda[] = {
125 		{ RTC_OBJ_DIRENT,	MSG_ORIG(MSG_CONF_DIRENT) },
126 		{ RTC_OBJ_ALLENTS,	MSG_ORIG(MSG_CONF_ALLENTS) },
127 		{ RTC_OBJ_NOEXIST,	MSG_ORIG(MSG_CONF_NOEXIST) },
128 		{ RTC_OBJ_EXEC,		MSG_ORIG(MSG_CONF_EXEC) },
129 		{ RTC_OBJ_ALTER,	MSG_ORIG(MSG_CONF_ALTER) },
130 		{ RTC_OBJ_DUMP,		MSG_ORIG(MSG_CONF_DUMP) },
131 		{ RTC_OBJ_NOALTER,	MSG_ORIG(MSG_CONF_NOALTER) },
132 		{ RTC_OBJ_REALPTH,	MSG_ORIG(MSG_CONF_REALPATH) },
133 		{ RTC_OBJ_GROUP,	MSG_ORIG(MSG_CONF_GROUP) },
134 		{ RTC_OBJ_APP,		MSG_ORIG(MSG_CONF_APP) },
135 		{ RTC_OBJ_CMDLINE,	MSG_ORIG(MSG_CONF_CMDLINE) },
136 		{ RTC_OBJ_FILTER,	MSG_ORIG(MSG_CONF_FILTER) },
137 		{ RTC_OBJ_FILTEE,	MSG_ORIG(MSG_CONF_FILTEE) },
138 		{ 0,			0 }
139 	};
140 	static const char *leading_str_arr[2];
141 	static CONV_EXPN_FIELD_ARG conv_arg = {
142 	    NULL, sizeof (config_obj_buf->buf), vda, leading_str_arr };
143 
144 	const char **lstr = leading_str_arr;
145 
146 	if ((flags == 0) || (flags == RTC_OBJ_OPTINAL))
147 		return (MSG_ORIG(MSG_GBL_NULL));
148 
149 	conv_arg.buf = config_obj_buf->buf;
150 	conv_arg.rflags = flags;
151 
152 	/*
153 	 * Print an alternative-optional object simply as optional.
154 	 */
155 	if ((flags & (RTC_OBJ_ALTER | RTC_OBJ_OPTINAL)) ==
156 	    (RTC_OBJ_ALTER | RTC_OBJ_OPTINAL)) {
157 		*lstr++ = MSG_ORIG(MSG_CONF_OPTIONAL);
158 		conv_arg.rflags &= ~(RTC_OBJ_ALTER | RTC_OBJ_OPTINAL);
159 	}
160 	*lstr = NULL;
161 	conv_arg.oflags = conv_arg.rflags &= ~RTC_OBJ_OPTINAL;
162 
163 	(void) conv_expn_field(&conv_arg);
164 
165 	return ((const char *)config_obj_buf->buf);
166 }
167 
168 /*
169  * Determine whether and old pathname exists within a search path string,
170  * without a new pathname, i.e., does the search path string contain "/usr/lib"
171  * but not "/lib".  If so, add the new pathname before the old pathname.  For
172  * example, convert:
173  *
174  *	/local/lib:/opt/sfw/lib:/usr/lib
175  * to:
176  *	/local/lib:/opt/sfw/lib:/lib:/usr/lib
177  */
178 const char *
179 conv_config_upm(const char *str, const char *old, const char *new,
180     size_t newlen)
181 {
182 	const char	*curstr, *ptr;
183 	const char	*curold = 0, *curnew = 0;
184 	const char	*ptrold = old, * ptrnew = new;
185 	int		chkold = 1, chknew = 1;
186 
187 	for (curstr = ptr = str; *ptr; ptr++) {
188 		if (*ptr == ':') {
189 			/*
190 			 * We've come to the end of a token within the string.
191 			 */
192 			if ((uintptr_t)ptr - (uintptr_t)curstr) {
193 				/*
194 				 * If the old or new string checking is still
195 				 * enabled, we've found a match.
196 				 */
197 				if (chkold)
198 					curold = curstr;
199 				if (chknew)
200 					curnew = curstr;
201 			}
202 			curstr = (char *)(ptr + 1);
203 
204 			/*
205 			 * If an old or new string hasn't yet been matched,
206 			 * re-enable the checking for either.
207 			 */
208 			if (curold == 0) {
209 				ptrold = old;
210 				chkold = 1;
211 			}
212 			if (curnew == 0) {
213 				ptrnew = new;
214 				chknew = 1;
215 			}
216 			continue;
217 		}
218 
219 		/*
220 		 * Determine if the current token matches the old or new string.
221 		 * If not, disable the checking for each string.
222 		 */
223 		if (chkold && (*ptr != *ptrold++))
224 			chkold = 0;
225 		if (chknew && (*ptr != *ptrnew++))
226 			chknew = 0;
227 	}
228 
229 	/*
230 	 * We've come to the end of the string, if the old or new string
231 	 * checking is still enabled, we've found a match.
232 	 */
233 	if ((uintptr_t)ptr - (uintptr_t)curstr) {
234 		if (chkold)
235 			curold = curstr;
236 		if (chknew)
237 			curnew = curstr;
238 	}
239 
240 	/*
241 	 * If an old string hasn't been found, or it has and a new string has
242 	 * been found, return the original string.
243 	 */
244 	if ((curold == 0) || curnew)
245 		return (str);
246 	else {
247 		char	*newstr;
248 		size_t	len;
249 
250 		/*
251 		 * Allocate a new string, enlarged to accommodate the new string
252 		 * that will be inserted, and an associated separator.
253 		 */
254 		if ((curstr = malloc(newlen + 2 +
255 		    (uintptr_t)ptr - (uintptr_t)str)) == 0)
256 			return (str);
257 
258 		newstr = (char *)curstr;
259 		for (len = (uintptr_t)curold - (uintptr_t)str; len; len--)
260 			*(newstr++) = *(str++);		/* copy up to */
261 							/*    insertion point */
262 		for (len = newlen; len; len--)
263 			*(newstr++) = *(new++);		/* add new string and */
264 		*(newstr++) = ':';			/*    separator */
265 		for (len = (uintptr_t)ptr - (uintptr_t)str; len; len--)
266 			*(newstr++) = *(str++);		/* add remaining */
267 		*(newstr++) = '\0';			/*	string */
268 
269 		return (curstr);
270 	}
271 }
272