xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/cfg_parser.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*	$NetBSD: cfg_parser.c,v 1.1.1.2 2011/03/02 19:32:13 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	cfg_parser 3
6 /* SUMMARY
7 /*	configuration parser utilities
8 /* SYNOPSIS
9 /*	#include "cfg_parser.h"
10 /*
11 /*	CFG_PARSER *cfg_parser_alloc(pname)
12 /*	const char *pname;
13 /*
14 /*	CFG_PARSER *cfg_parser_free(parser)
15 /*	CFG_PARSER *parser;
16 /*
17 /*	char *cfg_get_str(parser, name, defval, min, max)
18 /*	const CFG_PARSER *parser;
19 /*	const char *name;
20 /*	const char *defval;
21 /*	int min;
22 /*	int max;
23 /*
24 /*	int cfg_get_int(parser, name, defval, min, max)
25 /*	const CFG_PARSER *parser;
26 /*	const char *name;
27 /*	int defval;
28 /*	int min;
29 /*	int max;
30 /*
31 /*	int cfg_get_bool(parser, name, defval)
32 /*	const CFG_PARSER *parser;
33 /*	const char *name;
34 /*	int defval;
35 /* DESCRIPTION
36 /*	This module implements utilities for parsing parameters defined
37 /*	either as "\fIname\fR = \fBvalue\fR" in a file pointed to by
38 /*	\fIpname\fR (the old MySQL style), or as "\fIpname\fR_\fIname\fR =
39 /*	\fBvalue\fR" in main.cf (the old LDAP style).  It unifies the
40 /*	two styles and provides support for range checking.
41 /*
42 /*	\fIcfg_parser_alloc\fR initializes the parser.
43 /*
44 /*	\fIcfg_parser_free\fR releases the parser.
45 /*
46 /*	\fIcfg_get_str\fR looks up a string.
47 /*
48 /*	\fIcfg_get_int\fR looks up an integer.
49 /*
50 /*	\fIcfg_get_bool\fR looks up a boolean value.
51 /*
52 /*	\fIdefval\fR is returned when no value was found. \fImin\fR is
53 /*	zero or specifies a lower limit on the integer value or string
54 /*	length; \fImax\fR is zero or specifies an upper limit on the
55 /*	integer value or string length.
56 /*
57 /*	Conveniently, \fIcfg_get_str\fR returns \fBNULL\fR if
58 /*	\fIdefval\fR is \fBNULL\fR and no value was found.  The returned
59 /*	string has to be freed by the caller if not \fBNULL\fR.
60 /* DIAGNOSTICS
61 /*	Fatal errors: bad string length, malformed numerical value, malformed
62 /*	boolean value.
63 /* SEE ALSO
64 /*	mail_conf_str(3) string-valued global configuration parameter support
65 /*	mail_conf_int(3) integer-valued configuration parameter support
66 /*	mail_conf_bool(3) boolean-valued configuration parameter support
67 /* LICENSE
68 /* .ad
69 /* .fi
70 /*	The Secure Mailer license must be distributed with this software.
71 /* AUTHOR(S)
72 /*	Wietse Venema
73 /*	IBM T.J. Watson Research
74 /*	P.O. Box 704
75 /*	Yorktown Heights, NY 10598, USA
76 /*
77 /*	Liviu Daia
78 /*	Institute of Mathematics of the Romanian Academy
79 /*	P.O. BOX 1-764
80 /*	RO-014700 Bucharest, ROMANIA
81 /*--*/
82 
83 /* System library. */
84 
85 #include "sys_defs.h"
86 
87 #include <stdlib.h>
88 #include <errno.h>
89 #include <string.h>
90 
91 #ifdef STRCASECMP_IN_STRINGS_H
92 #include <strings.h>
93 #endif
94 
95 /* Utility library. */
96 
97 #include "msg.h"
98 #include "mymalloc.h"
99 #include "vstring.h"
100 #include "dict.h"
101 
102 /* Global library. */
103 
104 #include "mail_conf.h"
105 
106 /* Application-specific. */
107 
108 #include "cfg_parser.h"
109 
110 /* get string from file */
111 
112 static char *get_dict_str(const struct CFG_PARSER *parser,
113 			          const char *name, const char *defval,
114 			          int min, int max)
115 {
116     const char *strval;
117     int     len;
118 
119     if ((strval = (char *) dict_lookup(parser->name, name)) == 0)
120 	strval = defval;
121 
122     len = strlen(strval);
123     if (min && len < min)
124 	msg_fatal("%s: bad string length %d < %d: %s = %s",
125 		  parser->name, len, min, name, strval);
126     if (max && len > max)
127 	msg_fatal("%s: bad string length %d > %d: %s = %s",
128 		  parser->name, len, max, name, strval);
129     return (mystrdup(strval));
130 }
131 
132 /* get string from main.cf */
133 
134 static char *get_main_str(const struct CFG_PARSER *parser,
135 			          const char *name, const char *defval,
136 			          int min, int max)
137 {
138     static VSTRING *buf = 0;
139 
140     if (buf == 0)
141 	buf = vstring_alloc(15);
142     vstring_sprintf(buf, "%s_%s", parser->name, name);
143     return ((char *) get_mail_conf_str(vstring_str(buf), defval, min, max));
144 }
145 
146 /* get integer from file */
147 
148 static int get_dict_int(const struct CFG_PARSER *parser,
149 		             const char *name, int defval, int min, int max)
150 {
151     const char *strval;
152     char   *end;
153     int     intval;
154     long    longval;
155 
156     if ((strval = (char *) dict_lookup(parser->name, name)) != 0) {
157 	errno = 0;
158 	intval = longval = strtol(strval, &end, 10);
159 	if (*strval == 0 || *end != 0 || errno == ERANGE || longval != intval)
160 	    msg_fatal("%s: bad numerical configuration: %s = %s",
161 		      parser->name, name, strval);
162     } else
163 	intval = defval;
164     if (min && intval < min)
165 	msg_fatal("%s: invalid %s parameter value %d < %d",
166 		  parser->name, name, intval, min);
167     if (max && intval > max)
168 	msg_fatal("%s: invalid %s parameter value %d > %d",
169 		  parser->name, name, intval, max);
170     return (intval);
171 }
172 
173 /* get integer from main.cf */
174 
175 static int get_main_int(const struct CFG_PARSER *parser,
176 		             const char *name, int defval, int min, int max)
177 {
178     static VSTRING *buf = 0;
179 
180     if (buf == 0)
181 	buf = vstring_alloc(15);
182     vstring_sprintf(buf, "%s_%s", parser->name, name);
183     return (get_mail_conf_int(vstring_str(buf), defval, min, max));
184 }
185 
186 /* get boolean option from file */
187 
188 static int get_dict_bool(const struct CFG_PARSER *parser,
189 			         const char *name, int defval)
190 {
191     const char *strval;
192     int     intval;
193 
194     if ((strval = (char *) dict_lookup(parser->name, name)) != 0) {
195 	if (strcasecmp(strval, CONFIG_BOOL_YES) == 0) {
196 	    intval = 1;
197 	} else if (strcasecmp(strval, CONFIG_BOOL_NO) == 0) {
198 	    intval = 0;
199 	} else {
200 	    msg_fatal("%s: bad boolean configuration: %s = %s",
201 		      parser->name, name, strval);
202 	}
203     } else
204 	intval = defval;
205     return (intval);
206 }
207 
208 /* get boolean option from main.cf */
209 
210 static int get_main_bool(const struct CFG_PARSER *parser,
211 			         const char *name, int defval)
212 {
213     static VSTRING *buf = 0;
214 
215     if (buf == 0)
216 	buf = vstring_alloc(15);
217     vstring_sprintf(buf, "%s_%s", parser->name, name);
218     return (get_mail_conf_bool(vstring_str(buf), defval));
219 }
220 
221 /* initialize parser */
222 
223 CFG_PARSER *cfg_parser_alloc(const char *pname)
224 {
225     const char *myname = "cfg_parser_alloc";
226     CFG_PARSER *parser;
227 
228     if (pname == 0 || *pname == 0)
229 	msg_fatal("%s: null parser name", myname);
230     parser = (CFG_PARSER *) mymalloc(sizeof(*parser));
231     parser->name = mystrdup(pname);
232     if (*parser->name == '/' || *parser->name == '.') {
233 	dict_load_file(parser->name, parser->name);
234 	parser->get_str = get_dict_str;
235 	parser->get_int = get_dict_int;
236 	parser->get_bool = get_dict_bool;
237     } else {
238 	parser->get_str = get_main_str;
239 	parser->get_int = get_main_int;
240 	parser->get_bool = get_main_bool;
241     }
242     return (parser);
243 }
244 
245 /* get string */
246 
247 char   *cfg_get_str(const CFG_PARSER *parser, const char *name,
248 		            const char *defval, int min, int max)
249 {
250     const char *myname = "cfg_get_str";
251     char   *strval;
252 
253     strval = parser->get_str(parser, name, (defval ? defval : ""), min, max);
254     if (defval == 0 && *strval == 0) {
255 	/* the caller wants NULL instead of "" */
256 	myfree(strval);
257 	strval = 0;
258     }
259     if (msg_verbose)
260 	msg_info("%s: %s: %s = %s", myname, parser->name, name,
261 		 (strval ? strval : "<NULL>"));
262     return (strval);
263 }
264 
265 /* get integer */
266 
267 int     cfg_get_int(const CFG_PARSER *parser, const char *name, int defval,
268 		            int min, int max)
269 {
270     const char *myname = "cfg_get_int";
271     int     intval;
272 
273     intval = parser->get_int(parser, name, defval, min, max);
274     if (msg_verbose)
275 	msg_info("%s: %s: %s = %d", myname, parser->name, name, intval);
276     return (intval);
277 }
278 
279 /* get boolean option */
280 
281 int     cfg_get_bool(const CFG_PARSER *parser, const char *name, int defval)
282 {
283     const char *myname = "cfg_get_bool";
284     int     intval;
285 
286     intval = parser->get_bool(parser, name, defval);
287     if (msg_verbose)
288 	msg_info("%s: %s: %s = %s", myname, parser->name, name,
289 		 (intval ? "on" : "off"));
290     return (intval);
291 }
292 
293 /* release parser */
294 
295 CFG_PARSER *cfg_parser_free(CFG_PARSER *parser)
296 {
297     const char *myname = "cfg_parser_free";
298 
299     if (parser->name == 0 || *parser->name == 0)
300 	msg_panic("%s: null parser name", myname);
301     if (*parser->name == '/' || *parser->name == '.') {
302 	if (dict_handle(parser->name))
303 	    dict_unregister(parser->name);
304     }
305     myfree(parser->name);
306     myfree((char *) parser);
307     return (0);
308 }
309