1 /* $NetBSD: cfg_parser.c,v 1.1.1.1 2009/06/23 10:08:45 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 <stdio.h> 88 #include <string.h> 89 90 #ifdef STRCASECMP_IN_STRINGS_H 91 #include <strings.h> 92 #endif 93 94 /* Utility library. */ 95 96 #include "msg.h" 97 #include "mymalloc.h" 98 #include "vstring.h" 99 #include "dict.h" 100 101 /* Global library. */ 102 103 #include "mail_conf.h" 104 105 /* Application-specific. */ 106 107 #include "cfg_parser.h" 108 109 /* get string from file */ 110 111 static char *get_dict_str(const struct CFG_PARSER *parser, 112 const char *name, const char *defval, 113 int min, int max) 114 { 115 const char *strval; 116 int len; 117 118 if ((strval = (char *) dict_lookup(parser->name, name)) == 0) 119 strval = defval; 120 121 len = strlen(strval); 122 if (min && len < min) 123 msg_fatal("%s: bad string length %d < %d: %s = %s", 124 parser->name, len, min, name, strval); 125 if (max && len > max) 126 msg_fatal("%s: bad string length %d > %d: %s = %s", 127 parser->name, len, max, name, strval); 128 return (mystrdup(strval)); 129 } 130 131 /* get string from main.cf */ 132 133 static char *get_main_str(const struct CFG_PARSER *parser, 134 const char *name, const char *defval, 135 int min, int max) 136 { 137 static VSTRING *buf = 0; 138 139 if (buf == 0) 140 buf = vstring_alloc(15); 141 vstring_sprintf(buf, "%s_%s", parser->name, name); 142 return ((char *) get_mail_conf_str(vstring_str(buf), defval, min, max)); 143 } 144 145 /* get integer from file */ 146 147 static int get_dict_int(const struct CFG_PARSER *parser, 148 const char *name, int defval, int min, int max) 149 { 150 const char *strval; 151 int intval; 152 char junk; 153 154 if ((strval = (char *) dict_lookup(parser->name, name)) != 0) { 155 if (sscanf(strval, "%d%c", &intval, &junk) != 1) 156 msg_fatal("%s: bad numerical configuration: %s = %s", 157 parser->name, name, strval); 158 } else 159 intval = defval; 160 if (min && intval < min) 161 msg_fatal("%s: invalid %s parameter value %d < %d", 162 parser->name, name, intval, min); 163 if (max && intval > max) 164 msg_fatal("%s: invalid %s parameter value %d > %d", 165 parser->name, name, intval, max); 166 return (intval); 167 } 168 169 /* get integer from main.cf */ 170 171 static int get_main_int(const struct CFG_PARSER *parser, 172 const char *name, int defval, int min, int max) 173 { 174 static VSTRING *buf = 0; 175 176 if (buf == 0) 177 buf = vstring_alloc(15); 178 vstring_sprintf(buf, "%s_%s", parser->name, name); 179 return (get_mail_conf_int(vstring_str(buf), defval, min, max)); 180 } 181 182 /* get boolean option from file */ 183 184 static int get_dict_bool(const struct CFG_PARSER *parser, 185 const char *name, int defval) 186 { 187 const char *strval; 188 int intval; 189 190 if ((strval = (char *) dict_lookup(parser->name, name)) != 0) { 191 if (strcasecmp(strval, CONFIG_BOOL_YES) == 0) { 192 intval = 1; 193 } else if (strcasecmp(strval, CONFIG_BOOL_NO) == 0) { 194 intval = 0; 195 } else { 196 msg_fatal("%s: bad boolean configuration: %s = %s", 197 parser->name, name, strval); 198 } 199 } else 200 intval = defval; 201 return (intval); 202 } 203 204 /* get boolean option from main.cf */ 205 206 static int get_main_bool(const struct CFG_PARSER *parser, 207 const char *name, int defval) 208 { 209 static VSTRING *buf = 0; 210 211 if (buf == 0) 212 buf = vstring_alloc(15); 213 vstring_sprintf(buf, "%s_%s", parser->name, name); 214 return (get_mail_conf_bool(vstring_str(buf), defval)); 215 } 216 217 /* initialize parser */ 218 219 CFG_PARSER *cfg_parser_alloc(const char *pname) 220 { 221 const char *myname = "cfg_parser_alloc"; 222 CFG_PARSER *parser; 223 224 if (pname == 0 || *pname == 0) 225 msg_fatal("%s: null parser name", myname); 226 parser = (CFG_PARSER *) mymalloc(sizeof(*parser)); 227 parser->name = mystrdup(pname); 228 if (*parser->name == '/' || *parser->name == '.') { 229 dict_load_file(parser->name, parser->name); 230 parser->get_str = get_dict_str; 231 parser->get_int = get_dict_int; 232 parser->get_bool = get_dict_bool; 233 } else { 234 parser->get_str = get_main_str; 235 parser->get_int = get_main_int; 236 parser->get_bool = get_main_bool; 237 } 238 return (parser); 239 } 240 241 /* get string */ 242 243 char *cfg_get_str(const CFG_PARSER *parser, const char *name, 244 const char *defval, int min, int max) 245 { 246 const char *myname = "cfg_get_str"; 247 char *strval; 248 249 strval = parser->get_str(parser, name, (defval ? defval : ""), min, max); 250 if (defval == 0 && *strval == 0) { 251 /* the caller wants NULL instead of "" */ 252 myfree(strval); 253 strval = 0; 254 } 255 if (msg_verbose) 256 msg_info("%s: %s: %s = %s", myname, parser->name, name, 257 (strval ? strval : "<NULL>")); 258 return (strval); 259 } 260 261 /* get integer */ 262 263 int cfg_get_int(const CFG_PARSER *parser, const char *name, int defval, 264 int min, int max) 265 { 266 const char *myname = "cfg_get_int"; 267 int intval; 268 269 intval = parser->get_int(parser, name, defval, min, max); 270 if (msg_verbose) 271 msg_info("%s: %s: %s = %d", myname, parser->name, name, intval); 272 return (intval); 273 } 274 275 /* get boolean option */ 276 277 int cfg_get_bool(const CFG_PARSER *parser, const char *name, int defval) 278 { 279 const char *myname = "cfg_get_bool"; 280 int intval; 281 282 intval = parser->get_bool(parser, name, defval); 283 if (msg_verbose) 284 msg_info("%s: %s: %s = %s", myname, parser->name, name, 285 (intval ? "on" : "off")); 286 return (intval); 287 } 288 289 /* release parser */ 290 291 CFG_PARSER *cfg_parser_free(CFG_PARSER *parser) 292 { 293 const char *myname = "cfg_parser_free"; 294 295 if (parser->name == 0 || *parser->name == 0) 296 msg_panic("%s: null parser name", myname); 297 if (*parser->name == '/' || *parser->name == '.') { 298 if (dict_handle(parser->name)) 299 dict_unregister(parser->name); 300 } 301 myfree(parser->name); 302 myfree((char *) parser); 303 return (0); 304 } 305