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