00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 #include "gwlib/gwlib.h"
00065
00066
00067 #include <sys/types.h>
00068 #include <sys/stat.h>
00069 #include <unistd.h>
00070 #include <dirent.h>
00071
00072 struct CfgGroup {
00073 Octstr *name;
00074 Dict *vars;
00075 Octstr *configfile;
00076 long line;
00077 };
00078
00079
00080 static CfgGroup *create_group(void)
00081 {
00082 CfgGroup *grp;
00083
00084 grp = gw_malloc(sizeof(*grp));
00085 grp->name = NULL;
00086 grp->vars = dict_create(64, octstr_destroy_item);
00087 grp->configfile = NULL;
00088 grp->line = 0;
00089 return grp;
00090 }
00091
00092 static void destroy_group(void *arg)
00093 {
00094 CfgGroup *grp;
00095
00096 if (arg != NULL) {
00097 grp = arg;
00098 octstr_destroy(grp->name);
00099 octstr_destroy(grp->configfile);
00100 dict_destroy(grp->vars);
00101 gw_free(grp);
00102 }
00103 }
00104
00105
00106 struct CfgLoc {
00107 Octstr *filename;
00108 long line_no;
00109 Octstr *line;
00110 };
00111
00112
00113 static CfgLoc *cfgloc_create(Octstr *filename)
00114 {
00115 CfgLoc *cfgloc;
00116
00117 cfgloc = gw_malloc(sizeof(*cfgloc));
00118 cfgloc->filename = octstr_duplicate(filename);
00119 cfgloc->line_no = 0;
00120 cfgloc->line = NULL;
00121 return cfgloc;
00122 }
00123
00124
00125 static void cfgloc_destroy(CfgLoc *cfgloc)
00126 {
00127 if (cfgloc != NULL) {
00128 octstr_destroy(cfgloc->filename);
00129 octstr_destroy(cfgloc->line);
00130 gw_free(cfgloc);
00131 }
00132 }
00133
00134
00135 static void destroy_group_list(void *arg)
00136 {
00137 gwlist_destroy(arg, destroy_group);
00138 }
00139
00140
00141 static void set_group_name(CfgGroup *grp, Octstr *name)
00142 {
00143 octstr_destroy(grp->name);
00144 grp->name = octstr_duplicate(name);
00145 }
00146
00147
00148 struct Cfg {
00149 Octstr *filename;
00150 Dict *single_groups;
00151 Dict *multi_groups;
00152 };
00153
00154
00155
00156
00157
00158
00159
00160
00161 static List *allowed_hooks;
00162 static List *single_hooks;
00163
00164 static int core_is_allowed_in_group(Octstr *group, Octstr *variable)
00165 {
00166 Octstr *groupstr;
00167
00168 groupstr = octstr_imm("group");
00169
00170 #define OCTSTR(name) \
00171 if (octstr_compare(octstr_imm(#name), variable) == 0) \
00172 return 1;
00173 #define SINGLE_GROUP(name, fields) \
00174 if (octstr_compare(octstr_imm(#name), group) == 0) { \
00175 if (octstr_compare(groupstr, variable) == 0) \
00176 return 1; \
00177 fields \
00178 return 0; \
00179 }
00180 #define MULTI_GROUP(name, fields) \
00181 if (octstr_compare(octstr_imm(#name), group) == 0) { \
00182 if (octstr_compare(groupstr, variable) == 0) \
00183 return 1; \
00184 fields \
00185 return 0; \
00186 }
00187 #include "cfg.def"
00188
00189
00190 return -1;
00191 }
00192
00193
00194 static int core_is_single_group(Octstr *query)
00195 {
00196 #define OCTSTR(name)
00197 #define SINGLE_GROUP(name, fields) \
00198 if (octstr_compare(octstr_imm(#name), query) == 0) \
00199 return 1;
00200 #define MULTI_GROUP(name, fields) \
00201 if (octstr_compare(octstr_imm(#name), query) == 0) \
00202 return 0;
00203 #include "cfg.def"
00204 return 0;
00205 }
00206
00207
00208 static int is_allowed_in_group(Octstr *group, Octstr *variable)
00209 {
00210 long i;
00211 int x, r = -1;
00212
00213 for (i = 0; i < gwlist_len(allowed_hooks); ++i) {
00214 x = ((int(*)(Octstr *, Octstr *))
00215 gwlist_get(allowed_hooks, i))(group, variable);
00216 r = (x == -1 ? (r == -1 ? x : r) : (r == -1 ? x : r + x));
00217 }
00218
00219 return r;
00220 }
00221
00222
00223 static int is_single_group(Octstr *query)
00224 {
00225 long i;
00226 int r = 0;
00227
00228 for (i = 0; i < gwlist_len(single_hooks); ++i) {
00229 r += ((int(*)(Octstr *))
00230 gwlist_get(single_hooks, i))(query);
00231 }
00232
00233 return (r > 0);
00234 }
00235
00236
00237 void cfg_add_hooks(void *allowed, void *single)
00238 {
00239 gwlist_append(allowed_hooks, allowed);
00240 gwlist_append(single_hooks, single);
00241 }
00242
00243
00244 static int add_group(Cfg *cfg, CfgGroup *grp)
00245 {
00246 Octstr *groupname;
00247 Octstr *name;
00248 List *names;
00249 List *list;
00250
00251 groupname = cfg_get(grp, octstr_imm("group"));
00252 if (groupname == NULL) {
00253 error(0, "Group does not contain variable 'group'.");
00254 return -1;
00255 }
00256 set_group_name(grp, groupname);
00257
00258 names = dict_keys(grp->vars);
00259
00260 while ((name = gwlist_extract_first(names)) != NULL) {
00261 int a = is_allowed_in_group(groupname, name);
00262 switch (a) {
00263 case 0:
00264 error(0, "Group '%s' may not contain field '%s'.",
00265 octstr_get_cstr(groupname), octstr_get_cstr(name));
00266 octstr_destroy(name);
00267 octstr_destroy(groupname);
00268 gwlist_destroy(names, octstr_destroy_item);
00269 return -1;
00270 break;
00271 case -1:
00272 error(0, "Group '%s' is no valid group identifier.",
00273 octstr_get_cstr(groupname));
00274 octstr_destroy(name);
00275 octstr_destroy(groupname);
00276 gwlist_destroy(names, octstr_destroy_item);
00277 return -1;
00278 break;
00279 default:
00280 octstr_destroy(name);
00281 break;
00282 }
00283 }
00284 gwlist_destroy(names, NULL);
00285
00286 if (is_single_group(groupname)) {
00287 dict_put(cfg->single_groups, groupname, grp);
00288 } else {
00289 list = dict_get(cfg->multi_groups, groupname);
00290 if (list == NULL) {
00291 list = gwlist_create();
00292 dict_put(cfg->multi_groups, groupname, list);
00293 }
00294 gwlist_append(list, grp);
00295 }
00296
00297 octstr_destroy(groupname);
00298 return 0;
00299 }
00300
00301
00302 Cfg *cfg_create(Octstr *filename)
00303 {
00304 Cfg *cfg;
00305
00306 cfg = gw_malloc(sizeof(*cfg));
00307 cfg->filename = octstr_duplicate(filename);
00308 cfg->single_groups = dict_create(64, destroy_group);
00309 cfg->multi_groups = dict_create(64, destroy_group_list);
00310
00311 return cfg;
00312 }
00313
00314
00315 void cfg_destroy(Cfg *cfg)
00316 {
00317 if (cfg != NULL) {
00318 octstr_destroy(cfg->filename);
00319 dict_destroy(cfg->single_groups);
00320 dict_destroy(cfg->multi_groups);
00321 gw_free(cfg);
00322 }
00323 }
00324
00325
00326 static void parse_value(Octstr *value)
00327 {
00328 Octstr *temp;
00329 long len;
00330 int c;
00331
00332 octstr_strip_blanks(value);
00333
00334 len = octstr_len(value);
00335 if (octstr_get_char(value, 0) != '"' ||
00336 octstr_get_char(value, len - 1) != '"')
00337 return;
00338
00339 octstr_delete(value, len - 1, 1);
00340 octstr_delete(value, 0, 1);
00341
00342 temp = octstr_duplicate(value);
00343 octstr_truncate(value, 0);
00344
00345 while (octstr_len(temp) > 0) {
00346 c = octstr_get_char(temp, 0);
00347 octstr_delete(temp, 0, 1);
00348
00349 if (c != '\\' || octstr_len(temp) == 0)
00350 octstr_append_char(value, c);
00351 else {
00352 c = octstr_get_char(temp, 0);
00353 octstr_delete(temp, 0, 1);
00354
00355 switch (c) {
00356 case '\\':
00357 case '"':
00358 octstr_append_char(value, c);
00359 break;
00360
00361 default:
00362 octstr_append_char(value, '\\');
00363 octstr_append_char(value, c);
00364 break;
00365 }
00366 }
00367 }
00368
00369 octstr_destroy(temp);
00370 }
00371
00372
00373 static List *expand_file(Octstr *file, int forward)
00374 {
00375 Octstr *os;
00376 Octstr *line;
00377 List *lines;
00378 List *expand;
00379 long lineno;
00380 CfgLoc *loc = NULL;
00381
00382 os = octstr_read_file(octstr_get_cstr(file));
00383 if (os == NULL)
00384 return NULL;
00385
00386 lines = octstr_split(os, octstr_imm("\n"));
00387 lineno = 0;
00388 expand = gwlist_create();
00389
00390 while ((line = gwlist_extract_first(lines)) != NULL) {
00391 if (loc == NULL) {
00392 ++lineno;
00393 loc = cfgloc_create(file);
00394 loc->line_no = lineno;
00395 loc->line = octstr_create("");
00396 if (forward)
00397 gwlist_append(expand, loc);
00398 else
00399 gwlist_insert(expand, 0, loc);
00400 }
00401
00402 if (octstr_get_char(line, octstr_len(line) - 1) == '\\') {
00403 octstr_delete(line, octstr_len(line) - 1, 1);
00404 octstr_append(loc->line, line);
00405
00406 if (octstr_get_char(line, octstr_len(line) - 1) == '\\')
00407 loc = NULL;
00408 } else {
00409 octstr_append(loc->line, line);
00410 loc = NULL;
00411 }
00412 octstr_destroy(line);
00413 }
00414
00415
00416
00417
00418
00419 if (lineno > 0) {
00420 loc = cfgloc_create(file);
00421 loc->line_no = lineno;
00422 loc->line = octstr_create("\n");
00423 if (forward)
00424 gwlist_append(expand, loc);
00425 else
00426 gwlist_insert(expand, 0, loc);
00427 }
00428
00429 gwlist_destroy(lines, octstr_destroy_item);
00430 octstr_destroy(os);
00431
00432 return expand;
00433 }
00434
00435
00436 int cfg_read(Cfg *cfg)
00437 {
00438 CfgLoc *loc;
00439 CfgLoc *loc_inc;
00440 List *lines;
00441 List *expand;
00442 List *stack;
00443 Octstr *name;
00444 Octstr *value;
00445 Octstr *filename;
00446 CfgGroup *grp;
00447 long equals;
00448 long lineno;
00449 long error_lineno;
00450
00451 loc = loc_inc = NULL;
00452
00453
00454
00455
00456
00457 if ((lines = expand_file(cfg->filename, 1)) == NULL) {
00458 panic(0, "Failed to load main configuration file `%s'. Aborting!",
00459 octstr_get_cstr(cfg->filename));
00460 }
00461 stack = gwlist_create();
00462 gwlist_insert(stack, 0, octstr_duplicate(cfg->filename));
00463
00464 grp = NULL;
00465 lineno = 0;
00466 error_lineno = 0;
00467 while (error_lineno == 0 && (loc = gwlist_extract_first(lines)) != NULL) {
00468 octstr_strip_blanks(loc->line);
00469 if (octstr_len(loc->line) == 0) {
00470 if (grp != NULL && add_group(cfg, grp) == -1) {
00471 error_lineno = loc->line_no;
00472 destroy_group(grp);
00473 }
00474 grp = NULL;
00475 } else if (octstr_get_char(loc->line, 0) != '#') {
00476 equals = octstr_search_char(loc->line, '=', 0);
00477 if (equals == -1) {
00478 error(0, "An equals sign ('=') is missing on line %ld of file %s.",
00479 loc->line_no, octstr_get_cstr(loc->filename));
00480 error_lineno = loc->line_no;
00481 } else
00482
00483
00484
00485
00486
00487 if (octstr_search(loc->line, octstr_imm("include"), 0) != -1) {
00488 filename = octstr_copy(loc->line, equals + 1, octstr_len(loc->line));
00489 parse_value(filename);
00490
00491
00492 if (gwlist_search(stack, filename, octstr_item_match) != NULL) {
00493 panic(0, "Recursive include for config file `%s' detected "
00494 "(on line %ld of file %s).",
00495 octstr_get_cstr(filename), loc->line_no,
00496 octstr_get_cstr(loc->filename));
00497 } else {
00498 List *files = gwlist_create();
00499 Octstr *file;
00500 struct stat filestat;
00501
00502
00503 lstat(octstr_get_cstr(filename), &filestat);
00504
00505
00506
00507
00508
00509
00510 if (S_ISDIR(filestat.st_mode)) {
00511 DIR *dh;
00512 struct dirent *diritem;
00513
00514 debug("gwlib.cfg", 0, "Loading include dir `%s' "
00515 "(on line %ld of file %s).",
00516 octstr_get_cstr(filename), loc->line_no,
00517 octstr_get_cstr(loc->filename));
00518
00519 dh = opendir(octstr_get_cstr(filename));
00520 while ((diritem = readdir(dh))) {
00521 Octstr *fileitem;
00522
00523 fileitem = octstr_duplicate(filename);
00524 octstr_append_cstr(fileitem, "/");
00525 octstr_append_cstr(fileitem, diritem->d_name);
00526
00527 lstat(octstr_get_cstr(fileitem), &filestat);
00528 if (!S_ISDIR(filestat.st_mode)) {
00529 gwlist_insert(files, 0, fileitem);
00530 } else {
00531 octstr_destroy(fileitem);
00532 }
00533 }
00534 closedir(dh);
00535 }
00536
00537
00538 else {
00539 gwlist_insert(files, 0, octstr_duplicate(filename));
00540 }
00541
00542
00543 while ((file = gwlist_extract_first(files)) != NULL) {
00544
00545 gwlist_insert(stack, 0, octstr_duplicate(file));
00546 debug("gwlib.cfg", 0, "Loading include file `%s' (on line %ld of file %s).",
00547 octstr_get_cstr(file), loc->line_no,
00548 octstr_get_cstr(loc->filename));
00549
00550
00551
00552
00553
00554 if ((expand = expand_file(file, 0)) != NULL) {
00555 while ((loc_inc = gwlist_extract_first(expand)) != NULL)
00556 gwlist_insert(lines, 0, loc_inc);
00557 } else {
00558 panic(0, "Failed to load whole configuration. Aborting!");
00559 }
00560
00561 gwlist_destroy(expand, NULL);
00562 cfgloc_destroy(loc_inc);
00563 octstr_destroy(file);
00564 }
00565 gwlist_destroy(files, octstr_destroy_item);
00566 }
00567 octstr_destroy(filename);
00568 }
00569
00570
00571
00572
00573 else {
00574 name = octstr_copy(loc->line, 0, equals);
00575 octstr_strip_blanks(name);
00576 value = octstr_copy(loc->line, equals + 1, octstr_len(loc->line));
00577 parse_value(value);
00578
00579 if (grp == NULL)
00580 grp = create_group();
00581
00582 if (grp->configfile != NULL) {
00583 octstr_destroy(grp->configfile);
00584 grp->configfile = NULL;
00585 }
00586 grp->configfile = octstr_duplicate(cfg->filename);
00587
00588 cfg_set(grp, name, value);
00589 octstr_destroy(name);
00590 octstr_destroy(value);
00591 }
00592 }
00593
00594 cfgloc_destroy(loc);
00595 }
00596
00597 if (grp != NULL && add_group(cfg, grp) == -1) {
00598 error_lineno = 1;
00599 destroy_group(grp);
00600 }
00601
00602 gwlist_destroy(lines, NULL);
00603 gwlist_destroy(stack, octstr_destroy_item);
00604
00605 if (error_lineno != 0) {
00606 error(0, "Error found on line %ld of file `%s'.",
00607 error_lineno, octstr_get_cstr(cfg->filename));
00608 return -1;
00609 }
00610
00611 return 0;
00612 }
00613
00614
00615 CfgGroup *cfg_get_single_group(Cfg *cfg, Octstr *name)
00616 {
00617 return dict_get(cfg->single_groups, name);
00618 }
00619
00620
00621 List *cfg_get_multi_group(Cfg *cfg, Octstr *name)
00622 {
00623 List *list, *copy;
00624 long i;
00625
00626 list = dict_get(cfg->multi_groups, name);
00627 if (list == NULL)
00628 return NULL;
00629
00630 copy = gwlist_create();
00631 for (i = 0; i < gwlist_len(list); ++i)
00632 gwlist_append(copy, gwlist_get(list, i));
00633 return copy;
00634 }
00635
00636
00637 Octstr *cfg_get_group_name(CfgGroup *grp)
00638 {
00639 return octstr_duplicate(grp->name);
00640 }
00641
00642 Octstr *cfg_get_configfile(CfgGroup *grp)
00643 {
00644 return octstr_duplicate(grp->configfile);
00645 }
00646
00647
00648 Octstr *cfg_get_real(CfgGroup *grp, Octstr *varname, const char *file,
00649 long line, const char *func)
00650 {
00651 Octstr *os;
00652
00653 if(grp == NULL)
00654 panic(0, "Trying to fetch variable `%s' in non-existing group",
00655 octstr_get_cstr(varname));
00656
00657 if (grp->name != NULL && !is_allowed_in_group(grp->name, varname))
00658 panic(0, "Trying to fetch variable `%s' in group `%s', not allowed.",
00659 octstr_get_cstr(varname), octstr_get_cstr(grp->name));
00660
00661 os = dict_get(grp->vars, varname);
00662 if (os == NULL)
00663 return NULL;
00664 return gw_claim_area_for(octstr_duplicate(os), file, line, func);
00665 }
00666
00667
00668 int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
00669 {
00670 Octstr *os;
00671 int ret;
00672
00673 os = cfg_get(grp, varname);
00674 if (os == NULL)
00675 return -1;
00676 if (octstr_parse_long(n, os, 0, 0) == -1)
00677 ret = -1;
00678 else
00679 ret = 0;
00680 octstr_destroy(os);
00681 return ret;
00682 }
00683
00684
00685 int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname)
00686 {
00687 Octstr *os;
00688
00689 os = cfg_get(grp, varname);
00690 if (os == NULL) {
00691 *n = 0;
00692 return -1;
00693 }
00694 if (octstr_case_compare(os, octstr_imm("true")) == 0
00695 || octstr_case_compare(os, octstr_imm("yes")) == 0
00696 || octstr_case_compare(os, octstr_imm("on")) == 0
00697 || octstr_case_compare(os, octstr_imm("1")) == 0)
00698 {
00699 *n = 1;
00700 } else if (octstr_case_compare(os, octstr_imm("false")) == 0
00701 || octstr_case_compare(os, octstr_imm("no")) == 0
00702 || octstr_case_compare(os, octstr_imm("off")) == 0
00703 || octstr_case_compare(os, octstr_imm("0")) == 0)
00704 {
00705 *n = 0;
00706 }
00707 else {
00708 *n = 1;
00709 warning(0, "bool variable set to strange value, assuming 'true'");
00710 }
00711 octstr_destroy(os);
00712 return 0;
00713 }
00714
00715
00716 List *cfg_get_list(CfgGroup *grp, Octstr *varname)
00717 {
00718 Octstr *os;
00719 List *list;
00720
00721 os = cfg_get(grp, varname);
00722 if (os == NULL)
00723 return NULL;
00724
00725 list = octstr_split_words(os);
00726 octstr_destroy(os);
00727 return list;
00728 }
00729
00730
00731 void cfg_set(CfgGroup *grp, Octstr *varname, Octstr *value)
00732 {
00733 dict_put(grp->vars, varname, octstr_duplicate(value));
00734 }
00735
00736
00737 void grp_dump(CfgGroup *grp)
00738 {
00739 List *names;
00740 Octstr *name;
00741 Octstr *value;
00742
00743 if (grp->name == NULL)
00744 debug("gwlib.cfg", 0, " dumping group (name not set):");
00745 else
00746 debug("gwlib.cfg", 0, " dumping group (%s):",
00747 octstr_get_cstr(grp->name));
00748 names = dict_keys(grp->vars);
00749 while ((name = gwlist_extract_first(names)) != NULL) {
00750 value = cfg_get(grp, name);
00751 debug("gwlib.cfg", 0, " <%s> = <%s>",
00752 octstr_get_cstr(name),
00753 octstr_get_cstr(value));
00754 octstr_destroy(value);
00755 octstr_destroy(name);
00756 }
00757 gwlist_destroy(names, NULL);
00758 }
00759
00760
00761 void cfg_dump(Cfg *cfg)
00762 {
00763 CfgGroup *grp;
00764 List *list;
00765 List *names;
00766 Octstr *name;
00767
00768 debug("gwlib.cfg", 0, "Dumping Cfg %p", (void *) cfg);
00769 debug("gwlib.cfg", 0, " filename = <%s>",
00770 octstr_get_cstr(cfg->filename));
00771
00772 names = dict_keys(cfg->single_groups);
00773 while ((name = gwlist_extract_first(names)) != NULL) {
00774 grp = cfg_get_single_group(cfg, name);
00775 if (grp != NULL)
00776 grp_dump(grp);
00777 octstr_destroy(name);
00778 }
00779 gwlist_destroy(names, NULL);
00780
00781 names = dict_keys(cfg->multi_groups);
00782 while ((name = gwlist_extract_first(names)) != NULL) {
00783 list = cfg_get_multi_group(cfg, name);
00784 while ((grp = gwlist_extract_first(list)) != NULL)
00785 grp_dump(grp);
00786 gwlist_destroy(list, NULL);
00787 octstr_destroy(name);
00788 }
00789 gwlist_destroy(names, NULL);
00790
00791 debug("gwlib.cfg", 0, "Dump ends.");
00792 }
00793
00794
00795 void cfg_dump_all(void)
00796 {
00797 #define OCTSTR(name) \
00798 printf("%s = <please consult user doc>\n", #name);
00799 #define SINGLE_GROUP(name, fields) \
00800 printf("#\n# Single Group\n#\n"); \
00801 printf("group = %s\n", #name); \
00802 fields; \
00803 printf("\n\n");
00804 #define MULTI_GROUP(name, fields) \
00805 printf("#\n# Multi Group\n#\n"); \
00806 printf("group = %s\n", #name); \
00807 fields; \
00808 printf("\n\n");
00809 #include "cfg.def"
00810 }
00811
00812
00813 void cfg_init(void)
00814 {
00815
00816 allowed_hooks = gwlist_create();
00817 single_hooks = gwlist_create();
00818
00819 gwlist_append(allowed_hooks, &core_is_allowed_in_group);
00820 gwlist_append(single_hooks, &core_is_single_group);
00821 }
00822
00823
00824 void cfg_shutdown(void)
00825 {
00826 gwlist_destroy(allowed_hooks, NULL);
00827 gwlist_destroy(single_hooks, NULL);
00828 allowed_hooks = single_hooks = NULL;
00829 }
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.