1 /* 2 * profile.c -- A simple configuration file parsing "library in a file" 3 * 4 * The profile library was originally written by Theodore Ts'o in 1995 5 * for use in the MIT Kerberos v5 library. It has been 6 * modified/enhanced/bug-fixed over time by other members of the MIT 7 * Kerberos team. This version was originally taken from the Kerberos 8 * v5 distribution, version 1.4.2, and radically simplified for use in 9 * e2fsprogs. (Support for locking for multi-threaded operations, 10 * being able to modify and update the configuration file 11 * programmatically, and Mac/Windows portability have been removed. 12 * It has been folded into a single C source file to make it easier to 13 * fold into an application program.) 14 * 15 * Copyright (C) 2005, 2006 by Theodore Ts'o. 16 * 17 * %Begin-Header% 18 * This file may be redistributed under the terms of the GNU Public 19 * License. 20 * %End-Header% 21 * 22 * Copyright (C) 1985-2005 by the Massachusetts Institute of Technology. 23 * 24 * All rights reserved. 25 * 26 * Export of this software from the United States of America may require 27 * a specific license from the United States Government. It is the 28 * responsibility of any person or organization contemplating export to 29 * obtain such a license before exporting. 30 * 31 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 32 * distribute this software and its documentation for any purpose and 33 * without fee is hereby granted, provided that the above copyright 34 * notice appear in all copies and that both that copyright notice and 35 * this permission notice appear in supporting documentation, and that 36 * the name of M.I.T. not be used in advertising or publicity pertaining 37 * to distribution of the software without specific, written prior 38 * permission. Furthermore if you modify this software you must label 39 * your software as modified software and not distribute it in such a 40 * fashion that it might be confused with the original MIT software. 41 * M.I.T. makes no representations about the suitability of this software 42 * for any purpose. It is provided "as is" without express or implied 43 * warranty. 44 * 45 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 46 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 47 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 48 * 49 */ 50 51 #ifdef HAVE_UNISTD_H 52 #include <unistd.h> 53 #endif 54 #include <stdio.h> 55 #ifdef HAVE_STDLIB_H 56 #include <stdlib.h> 57 #endif 58 #include <time.h> 59 #include <string.h> 60 #include <errno.h> 61 #include <ctype.h> 62 #include <limits.h> 63 #include <stddef.h> 64 #include <sys/types.h> 65 #include <sys/stat.h> 66 #include <dirent.h> 67 #ifdef HAVE_PWD_H 68 #include <pwd.h> 69 #endif 70 71 #include <et/com_err.h> 72 #include "profile.h" 73 #include "prof_err.h" 74 75 #undef STAT_ONCE_PER_SECOND 76 #undef HAVE_STAT 77 78 /* 79 * prof_int.h 80 */ 81 82 typedef long prf_magic_t; 83 84 /* 85 * This is the structure which stores the profile information for a 86 * particular configuration file. 87 */ 88 struct _prf_file_t { 89 prf_magic_t magic; 90 char *filespec; 91 #ifdef STAT_ONCE_PER_SECOND 92 time_t last_stat; 93 #endif 94 time_t timestamp; /* time tree was last updated from file */ 95 int flags; /* r/w, dirty */ 96 int upd_serial; /* incremented when data changes */ 97 struct profile_node *root; 98 struct _prf_file_t *next; 99 }; 100 101 typedef struct _prf_file_t *prf_file_t; 102 103 /* 104 * The profile flags 105 */ 106 #define PROFILE_FILE_RW 0x0001 107 #define PROFILE_FILE_DIRTY 0x0002 108 #define PROFILE_FILE_NO_RELOAD 0x0004 109 110 /* 111 * This structure defines the high-level, user visible profile_t 112 * object, which is used as a handle by users who need to query some 113 * configuration file(s) 114 */ 115 struct _profile_t { 116 prf_magic_t magic; 117 prf_file_t first_file; 118 }; 119 120 /* 121 * Used by the profile iterator in prof_get.c 122 */ 123 #define PROFILE_ITER_LIST_SECTION 0x0001 124 #define PROFILE_ITER_SECTIONS_ONLY 0x0002 125 #define PROFILE_ITER_RELATIONS_ONLY 0x0004 126 127 #define PROFILE_ITER_FINAL_SEEN 0x0100 128 129 /* 130 * Check if a filespec is last in a list (NULL on UNIX, invalid FSSpec on MacOS 131 */ 132 133 #define PROFILE_LAST_FILESPEC(x) (((x) == NULL) || ((x)[0] == '\0')) 134 135 struct profile_node { 136 errcode_t magic; 137 char *name; 138 char *value; 139 int group_level; 140 unsigned int final:1; /* Indicate don't search next file */ 141 unsigned int deleted:1; 142 struct profile_node *first_child; 143 struct profile_node *parent; 144 struct profile_node *next, *prev; 145 }; 146 147 #define CHECK_MAGIC(node) \ 148 if ((node)->magic != PROF_MAGIC_NODE) \ 149 return PROF_MAGIC_NODE; 150 151 /* profile parser declarations */ 152 struct parse_state { 153 int state; 154 int group_level; 155 int line_num; 156 struct profile_node *root_section; 157 struct profile_node *current_section; 158 }; 159 160 static const char *default_filename = "<default>"; 161 162 static profile_syntax_err_cb_t syntax_err_cb; 163 164 static errcode_t parse_line(char *line, struct parse_state *state); 165 166 #ifdef DEBUG_PROGRAM 167 static errcode_t profile_write_tree_file 168 (struct profile_node *root, FILE *dstfile); 169 170 static errcode_t profile_write_tree_to_buffer 171 (struct profile_node *root, char **buf); 172 #endif 173 174 175 static void profile_free_node 176 (struct profile_node *relation); 177 178 static errcode_t profile_create_node 179 (const char *name, const char *value, 180 struct profile_node **ret_node); 181 182 #ifdef DEBUG_PROGRAM 183 static errcode_t profile_verify_node 184 (struct profile_node *node); 185 #endif 186 187 static errcode_t profile_add_node 188 (struct profile_node *section, 189 const char *name, const char *value, 190 struct profile_node **ret_node); 191 192 static errcode_t profile_find_node 193 (struct profile_node *section, 194 const char *name, const char *value, 195 int section_flag, void **state, 196 struct profile_node **node); 197 198 static errcode_t profile_node_iterator 199 (void **iter_p, struct profile_node **ret_node, 200 char **ret_name, char **ret_value); 201 202 static errcode_t profile_open_file 203 (const char * file, prf_file_t *ret_prof); 204 205 static errcode_t profile_update_file 206 (prf_file_t prf); 207 208 static void profile_free_file 209 (prf_file_t profile); 210 211 static errcode_t profile_get_value(profile_t profile, const char *name, 212 const char *subname, const char *subsubname, 213 const char **ret_value); 214 215 216 /* 217 * prof_init.c --- routines that manipulate the user-visible profile_t 218 * object. 219 */ 220 221 static int compstr(const void *m1, const void *m2) 222 { 223 const char *s1 = *((const char * const *) m1); 224 const char *s2 = *((const char * const *) m2); 225 226 return strcmp(s1, s2); 227 } 228 229 static void free_list(char **list) 230 { 231 char **cp; 232 233 if (list == 0) 234 return; 235 236 for (cp = list; *cp; cp++) 237 free(*cp); 238 free(list); 239 } 240 241 static errcode_t get_dirlist(const char *dirname, char***ret_array) 242 { 243 DIR *dir; 244 struct dirent *de; 245 struct stat st; 246 errcode_t retval; 247 char *fn, *cp; 248 char **array = 0, **new_array; 249 int max = 0, num = 0; 250 251 dir = opendir(dirname); 252 if (!dir) 253 return errno; 254 255 while ((de = readdir(dir)) != NULL) { 256 for (cp = de->d_name; *cp; cp++) { 257 if (!isalnum(*cp) && 258 (*cp != '-') && 259 (*cp != '_')) 260 break; 261 } 262 if (*cp) 263 continue; 264 fn = malloc(strlen(dirname) + strlen(de->d_name) + 2); 265 if (!fn) { 266 retval = ENOMEM; 267 goto errout; 268 } 269 sprintf(fn, "%s/%s", dirname, de->d_name); 270 if ((stat(fn, &st) < 0) || !S_ISREG(st.st_mode)) { 271 free(fn); 272 continue; 273 } 274 if (num >= max) { 275 max += 10; 276 new_array = realloc(array, sizeof(char *) * (max+1)); 277 if (!new_array) { 278 retval = ENOMEM; 279 free(fn); 280 goto errout; 281 } 282 array = new_array; 283 } 284 array[num++] = fn; 285 } 286 if (array) { 287 qsort(array, num, sizeof(char *), compstr); 288 array[num++] = 0; 289 } 290 *ret_array = array; 291 closedir(dir); 292 return 0; 293 errout: 294 if (array) 295 array[num] = 0; 296 closedir(dir); 297 free_list(array); 298 return retval; 299 } 300 301 errcode_t 302 profile_init(const char **files, profile_t *ret_profile) 303 { 304 const char **fs; 305 profile_t profile; 306 prf_file_t new_file, *last; 307 errcode_t retval = 0; 308 char **cpp, *cp, **array = 0; 309 310 profile = malloc(sizeof(struct _profile_t)); 311 if (!profile) 312 return ENOMEM; 313 memset(profile, 0, sizeof(struct _profile_t)); 314 profile->magic = PROF_MAGIC_PROFILE; 315 last = &profile->first_file; 316 317 /* if the filenames list is not specified return an empty profile */ 318 if ( files ) { 319 for (fs = files; !PROFILE_LAST_FILESPEC(*fs); fs++) { 320 if (array) 321 free_list(array); 322 retval = get_dirlist(*fs, &array); 323 if (retval == 0) { 324 if (!array) 325 continue; 326 for (cpp = array; (cp = *cpp); cpp++) { 327 retval = profile_open_file(cp, &new_file); 328 if (retval == EACCES) 329 continue; 330 if (retval) 331 goto errout; 332 *last = new_file; 333 last = &new_file->next; 334 } 335 } else if ((retval != ENOTDIR) && 336 strcmp(*fs, default_filename)) 337 goto errout; 338 339 retval = profile_open_file(*fs, &new_file); 340 /* if this file is missing, skip to the next */ 341 if (retval == ENOENT || retval == EACCES) { 342 continue; 343 } 344 if (retval) 345 goto errout; 346 *last = new_file; 347 last = &new_file->next; 348 } 349 /* 350 * If all the files were not found, return the appropriate error. 351 */ 352 if (!profile->first_file) { 353 retval = ENOENT; 354 goto errout; 355 } 356 } 357 358 free_list(array); 359 *ret_profile = profile; 360 return 0; 361 errout: 362 free_list(array); 363 profile_release(profile); 364 return retval; 365 } 366 367 void 368 profile_release(profile_t profile) 369 { 370 prf_file_t p, next; 371 372 if (!profile || profile->magic != PROF_MAGIC_PROFILE) 373 return; 374 375 for (p = profile->first_file; p; p = next) { 376 next = p->next; 377 profile_free_file(p); 378 } 379 profile->magic = 0; 380 free(profile); 381 } 382 383 /* 384 * This function sets the value of the pseudo file "<default>". If 385 * the file "<default>" had previously been passed to profile_init(), 386 * then def_string parameter will be parsed and used as the profile 387 * information for the "<default>" file. 388 */ 389 errcode_t profile_set_default(profile_t profile, const char *def_string) 390 { 391 struct parse_state state; 392 prf_file_t prf; 393 errcode_t retval; 394 const char *in; 395 char *line, *p, *end; 396 int line_size, len; 397 398 if (!def_string || !profile || profile->magic != PROF_MAGIC_PROFILE) 399 return PROF_MAGIC_PROFILE; 400 401 for (prf = profile->first_file; prf; prf = prf->next) { 402 if (strcmp(prf->filespec, default_filename) == 0) 403 break; 404 } 405 if (!prf) 406 return 0; 407 408 if (prf->root) { 409 profile_free_node(prf->root); 410 prf->root = 0; 411 } 412 413 memset(&state, 0, sizeof(struct parse_state)); 414 retval = profile_create_node("(root)", 0, &state.root_section); 415 if (retval) 416 return retval; 417 418 line = 0; 419 line_size = 0; 420 in = def_string; 421 while (*in) { 422 end = strchr(in, '\n'); 423 len = end ? (end - in) : (int) strlen(in); 424 if (len >= line_size) { 425 line_size = len+1; 426 p = realloc(line, line_size); 427 if (!p) { 428 retval = ENOMEM; 429 goto errout; 430 } 431 line = p; 432 } 433 memcpy(line, in, len); 434 line[len] = 0; 435 retval = parse_line(line, &state); 436 if (retval) { 437 errout: 438 if (syntax_err_cb) 439 (syntax_err_cb)(prf->filespec, retval, 440 state.line_num); 441 free(line); 442 if (prf->root) 443 profile_free_node(prf->root); 444 return retval; 445 } 446 if (!end) 447 break; 448 in = end+1; 449 } 450 prf->root = state.root_section; 451 free(line); 452 453 return 0; 454 } 455 456 /* 457 * prof_file.c ---- routines that manipulate an individual profile file. 458 */ 459 460 errcode_t profile_open_file(const char * filespec, 461 prf_file_t *ret_prof) 462 { 463 prf_file_t prf; 464 errcode_t retval; 465 char *home_env = 0; 466 unsigned int len; 467 char *expanded_filename; 468 469 prf = malloc(sizeof(struct _prf_file_t)); 470 if (!prf) 471 return ENOMEM; 472 memset(prf, 0, sizeof(struct _prf_file_t)); 473 prf->magic = PROF_MAGIC_FILE; 474 475 len = strlen(filespec)+1; 476 if (filespec[0] == '~' && filespec[1] == '/') { 477 home_env = getenv("HOME"); 478 #ifdef HAVE_PWD_H 479 if (home_env == NULL) { 480 #ifdef HAVE_GETWUID_R 481 struct passwd *pw, pwx; 482 uid_t uid; 483 char pwbuf[BUFSIZ]; 484 485 uid = getuid(); 486 if (!getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw) 487 && pw != NULL && pw->pw_dir[0] != 0) 488 home_env = pw->pw_dir; 489 #else 490 struct passwd *pw; 491 492 pw = getpwuid(getuid()); 493 home_env = pw->pw_dir; 494 #endif 495 } 496 #endif 497 if (home_env) 498 len += strlen(home_env); 499 } 500 expanded_filename = malloc(len); 501 if (expanded_filename == 0) { 502 profile_free_file(prf); 503 return errno; 504 } 505 if (home_env) { 506 strcpy(expanded_filename, home_env); 507 strcat(expanded_filename, filespec+1); 508 } else 509 memcpy(expanded_filename, filespec, len); 510 511 prf->filespec = expanded_filename; 512 513 if (strcmp(prf->filespec, default_filename) != 0) { 514 retval = profile_update_file(prf); 515 if (retval) { 516 profile_free_file(prf); 517 return retval; 518 } 519 } 520 521 *ret_prof = prf; 522 return 0; 523 } 524 525 errcode_t profile_update_file(prf_file_t prf) 526 { 527 errcode_t retval; 528 #ifdef HAVE_STAT 529 struct stat st; 530 #ifdef STAT_ONCE_PER_SECOND 531 time_t now; 532 #endif 533 #endif 534 FILE *f; 535 char buf[2048]; 536 struct parse_state state; 537 538 if (prf->flags & PROFILE_FILE_NO_RELOAD) 539 return 0; 540 541 #ifdef HAVE_STAT 542 #ifdef STAT_ONCE_PER_SECOND 543 now = time(0); 544 if (now == prf->last_stat && prf->root != NULL) { 545 return 0; 546 } 547 #endif 548 if (stat(prf->filespec, &st)) { 549 retval = errno; 550 return retval; 551 } 552 #ifdef STAT_ONCE_PER_SECOND 553 prf->last_stat = now; 554 #endif 555 if (st.st_mtime == prf->timestamp && prf->root != NULL) { 556 return 0; 557 } 558 if (prf->root) { 559 profile_free_node(prf->root); 560 prf->root = 0; 561 } 562 #else 563 /* 564 * If we don't have the stat() call, assume that our in-core 565 * memory image is correct. That is, we won't reread the 566 * profile file if it changes. 567 */ 568 if (prf->root) { 569 return 0; 570 } 571 #endif 572 memset(&state, 0, sizeof(struct parse_state)); 573 retval = profile_create_node("(root)", 0, &state.root_section); 574 if (retval) 575 return retval; 576 errno = 0; 577 f = fopen(prf->filespec, "r"); 578 if (f == NULL) { 579 retval = errno; 580 if (retval == 0) 581 retval = ENOENT; 582 return retval; 583 } 584 prf->upd_serial++; 585 while (!feof(f)) { 586 if (fgets(buf, sizeof(buf), f) == NULL) 587 break; 588 retval = parse_line(buf, &state); 589 if (retval) { 590 if (syntax_err_cb) 591 (syntax_err_cb)(prf->filespec, retval, 592 state.line_num); 593 fclose(f); 594 return retval; 595 } 596 } 597 prf->root = state.root_section; 598 599 fclose(f); 600 601 #ifdef HAVE_STAT 602 prf->timestamp = st.st_mtime; 603 #endif 604 return 0; 605 } 606 607 void profile_free_file(prf_file_t prf) 608 { 609 if (prf->root) 610 profile_free_node(prf->root); 611 free(prf->filespec); 612 free(prf); 613 } 614 615 /* Begin the profile parser */ 616 617 profile_syntax_err_cb_t profile_set_syntax_err_cb(profile_syntax_err_cb_t hook) 618 { 619 profile_syntax_err_cb_t old; 620 621 old = syntax_err_cb; 622 syntax_err_cb = hook; 623 return(old); 624 } 625 626 #define STATE_INIT_COMMENT 0 627 #define STATE_STD_LINE 1 628 #define STATE_GET_OBRACE 2 629 630 static char *skip_over_blanks(char *cp) 631 { 632 while (*cp && isspace((int) (*cp))) 633 cp++; 634 return cp; 635 } 636 637 static int end_or_comment(char ch) 638 { 639 return (ch == 0 || ch == '#' || ch == ';'); 640 } 641 642 static char *skip_over_nonblanks(char *cp) 643 { 644 while (!end_or_comment(*cp) && !isspace(*cp)) 645 cp++; 646 return cp; 647 } 648 649 static void strip_line(char *line) 650 { 651 char *p = line + strlen(line); 652 while (p > line && (p[-1] == '\n' || p[-1] == '\r')) 653 *p-- = 0; 654 } 655 656 static void parse_quoted_string(char *str) 657 { 658 char *to, *from; 659 660 to = from = str; 661 662 for (to = from = str; *from && *from != '"'; to++, from++) { 663 if (*from == '\\') { 664 from++; 665 switch (*from) { 666 case 'n': 667 *to = '\n'; 668 break; 669 case 't': 670 *to = '\t'; 671 break; 672 case 'b': 673 *to = '\b'; 674 break; 675 default: 676 *to = *from; 677 } 678 continue; 679 } 680 *to = *from; 681 } 682 *to = '\0'; 683 } 684 685 static errcode_t parse_line(char *line, struct parse_state *state) 686 { 687 char *cp, ch, *tag, *value; 688 char *p; 689 errcode_t retval; 690 struct profile_node *node; 691 int do_subsection = 0; 692 void *iter = 0; 693 694 state->line_num++; 695 if (state->state == STATE_GET_OBRACE) { 696 cp = skip_over_blanks(line); 697 if (*cp != '{') 698 return PROF_MISSING_OBRACE; 699 state->state = STATE_STD_LINE; 700 return 0; 701 } 702 if (state->state == STATE_INIT_COMMENT) { 703 if (line[0] != '[') 704 return 0; 705 state->state = STATE_STD_LINE; 706 } 707 708 if (*line == 0) 709 return 0; 710 strip_line(line); 711 cp = skip_over_blanks(line); 712 ch = *cp; 713 if (end_or_comment(ch)) 714 return 0; 715 if (ch == '[') { 716 if (state->group_level > 0) 717 return PROF_SECTION_NOTOP; 718 cp++; 719 cp = skip_over_blanks(cp); 720 p = strchr(cp, ']'); 721 if (p == NULL) 722 return PROF_SECTION_SYNTAX; 723 if (*cp == '"') { 724 cp++; 725 parse_quoted_string(cp); 726 } else { 727 *p-- = '\0'; 728 while (isspace(*p) && (p > cp)) 729 *p-- = '\0'; 730 if (*cp == 0) 731 return PROF_SECTION_SYNTAX; 732 } 733 retval = profile_find_node(state->root_section, cp, 0, 1, 734 &iter, &state->current_section); 735 if (retval == PROF_NO_SECTION) { 736 retval = profile_add_node(state->root_section, 737 cp, 0, 738 &state->current_section); 739 if (retval) 740 return retval; 741 } else if (retval) 742 return retval; 743 744 /* 745 * Finish off the rest of the line. 746 */ 747 cp = p+1; 748 if (*cp == '*') { 749 state->current_section->final = 1; 750 cp++; 751 } 752 /* 753 * Spaces or comments after ']' should not be fatal 754 */ 755 cp = skip_over_blanks(cp); 756 if (!end_or_comment(*cp)) 757 return PROF_SECTION_SYNTAX; 758 return 0; 759 } 760 if (ch == '}') { 761 if (state->group_level == 0) 762 return PROF_EXTRA_CBRACE; 763 if (*(cp+1) == '*') 764 state->current_section->final = 1; 765 state->current_section = state->current_section->parent; 766 state->group_level--; 767 return 0; 768 } 769 /* 770 * Parse the relations 771 */ 772 tag = cp; 773 cp = strchr(cp, '='); 774 if (!cp) 775 return PROF_RELATION_SYNTAX; 776 if (cp == tag) 777 return PROF_RELATION_SYNTAX; 778 *cp = '\0'; 779 if (*tag == '"') { 780 tag++; 781 parse_quoted_string(tag); 782 } else { 783 /* Look for whitespace on left-hand side. */ 784 p = skip_over_nonblanks(tag); 785 if (*p) 786 *p++ = 0; 787 p = skip_over_blanks(p); 788 /* If we have more non-whitespace, it's an error. */ 789 if (*p) 790 return PROF_RELATION_SYNTAX; 791 } 792 793 cp = skip_over_blanks(cp+1); 794 value = cp; 795 ch = value[0]; 796 if (ch == '"') { 797 value++; 798 parse_quoted_string(value); 799 } else if (end_or_comment(ch)) { 800 do_subsection++; 801 state->state = STATE_GET_OBRACE; 802 } else if (value[0] == '{') { 803 cp = skip_over_blanks(value+1); 804 ch = *cp; 805 if (end_or_comment(ch)) 806 do_subsection++; 807 else 808 return PROF_RELATION_SYNTAX; 809 } else { 810 cp = skip_over_nonblanks(value); 811 p = skip_over_blanks(cp); 812 ch = *p; 813 *cp = 0; 814 if (!end_or_comment(ch)) 815 return PROF_RELATION_SYNTAX; 816 } 817 if (do_subsection) { 818 p = strchr(tag, '*'); 819 if (p) 820 *p = '\0'; 821 retval = profile_add_node(state->current_section, 822 tag, 0, &state->current_section); 823 if (retval) 824 return retval; 825 if (p) 826 state->current_section->final = 1; 827 state->group_level++; 828 return 0; 829 } 830 p = strchr(tag, '*'); 831 if (p) 832 *p = '\0'; 833 profile_add_node(state->current_section, tag, value, &node); 834 if (p) 835 node->final = 1; 836 return 0; 837 } 838 839 #ifdef DEBUG_PROGRAM 840 /* 841 * Return TRUE if the string begins or ends with whitespace 842 */ 843 static int need_double_quotes(char *str) 844 { 845 if (!str || !*str) 846 return 0; 847 if (isspace((int) (*str)) ||isspace((int) (*(str + strlen(str) - 1)))) 848 return 1; 849 if (strchr(str, '\n') || strchr(str, '\t') || strchr(str, '\b') || 850 strchr(str, ' ') || strchr(str, '#') || strchr(str, ';')) 851 return 1; 852 return 0; 853 } 854 855 /* 856 * Output a string with double quotes, doing appropriate backquoting 857 * of characters as necessary. 858 */ 859 static void output_quoted_string(char *str, void (*cb)(const char *,void *), 860 void *data) 861 { 862 char ch; 863 char buf[2]; 864 865 cb("\"", data); 866 if (!str) { 867 cb("\"", data); 868 return; 869 } 870 buf[1] = 0; 871 while ((ch = *str++)) { 872 switch (ch) { 873 case '\\': 874 cb("\\\\", data); 875 break; 876 case '\n': 877 cb("\\n", data); 878 break; 879 case '\t': 880 cb("\\t", data); 881 break; 882 case '\b': 883 cb("\\b", data); 884 break; 885 default: 886 /* This would be a lot faster if we scanned 887 forward for the next "interesting" 888 character. */ 889 buf[0] = ch; 890 cb(buf, data); 891 break; 892 } 893 } 894 cb("\"", data); 895 } 896 897 #ifndef EOL 898 #define EOL "\n" 899 #endif 900 901 /* Errors should be returned, not ignored! */ 902 static void dump_profile(struct profile_node *root, int level, 903 void (*cb)(const char *, void *), void *data) 904 { 905 int i; 906 struct profile_node *p; 907 void *iter; 908 long retval; 909 910 iter = 0; 911 do { 912 retval = profile_find_node(root, 0, 0, 0, &iter, &p); 913 if (retval) 914 break; 915 for (i=0; i < level; i++) 916 cb("\t", data); 917 if (need_double_quotes(p->name)) 918 output_quoted_string(p->name, cb, data); 919 else 920 cb(p->name, data); 921 cb(" = ", data); 922 if (need_double_quotes(p->value)) 923 output_quoted_string(p->value, cb, data); 924 else 925 cb(p->value, data); 926 cb(EOL, data); 927 } while (iter != 0); 928 929 iter = 0; 930 do { 931 retval = profile_find_node(root, 0, 0, 1, &iter, &p); 932 if (retval) 933 break; 934 if (level == 0) { /* [xxx] */ 935 cb("[", data); 936 if (need_double_quotes(p->name)) 937 output_quoted_string(p->name, cb, data); 938 else 939 cb(p->name, data); 940 cb("]", data); 941 cb(p->final ? "*" : "", data); 942 cb(EOL, data); 943 dump_profile(p, level+1, cb, data); 944 cb(EOL, data); 945 } else { /* xxx = { ... } */ 946 for (i=0; i < level; i++) 947 cb("\t", data); 948 if (need_double_quotes(p->name)) 949 output_quoted_string(p->name, cb, data); 950 else 951 cb(p->name, data); 952 cb(" = {", data); 953 cb(EOL, data); 954 dump_profile(p, level+1, cb, data); 955 for (i=0; i < level; i++) 956 cb("\t", data); 957 cb("}", data); 958 cb(p->final ? "*" : "", data); 959 cb(EOL, data); 960 } 961 } while (iter != 0); 962 } 963 964 static void dump_profile_to_file_cb(const char *str, void *data) 965 { 966 fputs(str, data); 967 } 968 969 errcode_t profile_write_tree_file(struct profile_node *root, FILE *dstfile) 970 { 971 dump_profile(root, 0, dump_profile_to_file_cb, dstfile); 972 return 0; 973 } 974 975 struct prof_buf { 976 char *base; 977 size_t cur, max; 978 int err; 979 }; 980 981 static void add_data_to_buffer(struct prof_buf *b, const void *d, size_t len) 982 { 983 if (b->err) 984 return; 985 if (b->max - b->cur < len) { 986 size_t newsize; 987 char *newptr; 988 989 newsize = b->max + (b->max >> 1) + len + 1024; 990 newptr = realloc(b->base, newsize); 991 if (newptr == NULL) { 992 b->err = 1; 993 return; 994 } 995 b->base = newptr; 996 b->max = newsize; 997 } 998 memcpy(b->base + b->cur, d, len); 999 b->cur += len; /* ignore overflow */ 1000 } 1001 1002 static void dump_profile_to_buffer_cb(const char *str, void *data) 1003 { 1004 add_data_to_buffer((struct prof_buf *)data, str, strlen(str)); 1005 } 1006 1007 errcode_t profile_write_tree_to_buffer(struct profile_node *root, 1008 char **buf) 1009 { 1010 struct prof_buf prof_buf = { 0, 0, 0, 0 }; 1011 1012 dump_profile(root, 0, dump_profile_to_buffer_cb, &prof_buf); 1013 if (prof_buf.err) { 1014 *buf = NULL; 1015 return ENOMEM; 1016 } 1017 add_data_to_buffer(&prof_buf, "", 1); /* append nul */ 1018 if (prof_buf.max - prof_buf.cur > (prof_buf.max >> 3)) { 1019 char *newptr = realloc(prof_buf.base, prof_buf.cur); 1020 if (newptr) 1021 prof_buf.base = newptr; 1022 } 1023 *buf = prof_buf.base; 1024 return 0; 1025 } 1026 #endif 1027 1028 /* 1029 * prof_tree.c --- these routines maintain the parse tree of the 1030 * config file. 1031 * 1032 * All of the details of how the tree is stored is abstracted away in 1033 * this file; all of the other profile routines build, access, and 1034 * modify the tree via the accessor functions found in this file. 1035 * 1036 * Each node may represent either a relation or a section header. 1037 * 1038 * A section header must have its value field set to 0, and may a one 1039 * or more child nodes, pointed to by first_child. 1040 * 1041 * A relation has as its value a pointer to allocated memory 1042 * containing a string. Its first_child pointer must be null. 1043 * 1044 */ 1045 1046 /* 1047 * Free a node, and any children 1048 */ 1049 void profile_free_node(struct profile_node *node) 1050 { 1051 struct profile_node *child, *next; 1052 1053 if (node->magic != PROF_MAGIC_NODE) 1054 return; 1055 1056 free(node->name); 1057 free(node->value); 1058 1059 for (child=node->first_child; child; child = next) { 1060 next = child->next; 1061 profile_free_node(child); 1062 } 1063 node->magic = 0; 1064 1065 free(node); 1066 } 1067 1068 #ifndef HAVE_STRDUP 1069 #undef strdup 1070 #define strdup MYstrdup 1071 static char *MYstrdup (const char *s) 1072 { 1073 size_t sz = strlen(s) + 1; 1074 char *p = malloc(sz); 1075 if (p != 0) 1076 memcpy(p, s, sz); 1077 return p; 1078 } 1079 #endif 1080 1081 /* 1082 * Create a node 1083 */ 1084 errcode_t profile_create_node(const char *name, const char *value, 1085 struct profile_node **ret_node) 1086 { 1087 struct profile_node *new; 1088 1089 new = malloc(sizeof(struct profile_node)); 1090 if (!new) 1091 return ENOMEM; 1092 memset(new, 0, sizeof(struct profile_node)); 1093 new->name = strdup(name); 1094 if (new->name == 0) { 1095 profile_free_node(new); 1096 return ENOMEM; 1097 } 1098 if (value) { 1099 new->value = strdup(value); 1100 if (new->value == 0) { 1101 profile_free_node(new); 1102 return ENOMEM; 1103 } 1104 } 1105 new->magic = PROF_MAGIC_NODE; 1106 1107 *ret_node = new; 1108 return 0; 1109 } 1110 1111 /* 1112 * This function verifies that all of the representation invarients of 1113 * the profile are true. If not, we have a programming bug somewhere, 1114 * probably in this file. 1115 */ 1116 #ifdef DEBUG_PROGRAM 1117 errcode_t profile_verify_node(struct profile_node *node) 1118 { 1119 struct profile_node *p, *last; 1120 errcode_t retval; 1121 1122 CHECK_MAGIC(node); 1123 1124 if (node->value && node->first_child) 1125 return PROF_SECTION_WITH_VALUE; 1126 1127 last = 0; 1128 for (p = node->first_child; p; last = p, p = p->next) { 1129 if (p->prev != last) 1130 return PROF_BAD_LINK_LIST; 1131 if (last && (last->next != p)) 1132 return PROF_BAD_LINK_LIST; 1133 if (node->group_level+1 != p->group_level) 1134 return PROF_BAD_GROUP_LVL; 1135 if (p->parent != node) 1136 return PROF_BAD_PARENT_PTR; 1137 retval = profile_verify_node(p); 1138 if (retval) 1139 return retval; 1140 } 1141 return 0; 1142 } 1143 #endif 1144 1145 /* 1146 * Add a node to a particular section 1147 */ 1148 errcode_t profile_add_node(struct profile_node *section, const char *name, 1149 const char *value, struct profile_node **ret_node) 1150 { 1151 errcode_t retval; 1152 struct profile_node *p, *last, *new; 1153 1154 CHECK_MAGIC(section); 1155 1156 if (section->value) 1157 return PROF_ADD_NOT_SECTION; 1158 1159 /* 1160 * Find the place to insert the new node. We look for the 1161 * place *after* the last match of the node name, since 1162 * order matters. 1163 */ 1164 for (p=section->first_child, last = 0; p; last = p, p = p->next) { 1165 int cmp; 1166 cmp = strcmp(p->name, name); 1167 if (cmp > 0) 1168 break; 1169 } 1170 retval = profile_create_node(name, value, &new); 1171 if (retval) 1172 return retval; 1173 new->group_level = section->group_level+1; 1174 new->deleted = 0; 1175 new->parent = section; 1176 new->prev = last; 1177 new->next = p; 1178 if (p) 1179 p->prev = new; 1180 if (last) 1181 last->next = new; 1182 else 1183 section->first_child = new; 1184 if (ret_node) 1185 *ret_node = new; 1186 return 0; 1187 } 1188 1189 /* 1190 * Iterate through the section, returning the nodes which match 1191 * the given name. If name is NULL, then interate through all the 1192 * nodes in the section. If section_flag is non-zero, only return the 1193 * section which matches the name; don't return relations. If value 1194 * is non-NULL, then only return relations which match the requested 1195 * value. (The value argument is ignored if section_flag is non-zero.) 1196 * 1197 * The first time this routine is called, the state pointer must be 1198 * null. When this profile_find_node_relation() returns, if the state 1199 * pointer is non-NULL, then this routine should be called again. 1200 * (This won't happen if section_flag is non-zero, obviously.) 1201 * 1202 */ 1203 errcode_t profile_find_node(struct profile_node *section, const char *name, 1204 const char *value, int section_flag, void **state, 1205 struct profile_node **node) 1206 { 1207 struct profile_node *p; 1208 1209 CHECK_MAGIC(section); 1210 p = *state; 1211 if (p) { 1212 CHECK_MAGIC(p); 1213 } else 1214 p = section->first_child; 1215 1216 for (; p; p = p->next) { 1217 if (name && (strcmp(p->name, name))) 1218 continue; 1219 if (section_flag) { 1220 if (p->value) 1221 continue; 1222 } else { 1223 if (!p->value) 1224 continue; 1225 if (value && (strcmp(p->value, value))) 1226 continue; 1227 } 1228 if (p->deleted) 1229 continue; 1230 /* A match! */ 1231 if (node) 1232 *node = p; 1233 break; 1234 } 1235 if (p == 0) { 1236 *state = 0; 1237 return section_flag ? PROF_NO_SECTION : PROF_NO_RELATION; 1238 } 1239 /* 1240 * OK, we've found one match; now let's try to find another 1241 * one. This way, if we return a non-zero state pointer, 1242 * there's guaranteed to be another match that's returned. 1243 */ 1244 for (p = p->next; p; p = p->next) { 1245 if (name && (strcmp(p->name, name))) 1246 continue; 1247 if (section_flag) { 1248 if (p->value) 1249 continue; 1250 } else { 1251 if (!p->value) 1252 continue; 1253 if (value && (strcmp(p->value, value))) 1254 continue; 1255 } 1256 /* A match! */ 1257 break; 1258 } 1259 *state = p; 1260 return 0; 1261 } 1262 1263 /* 1264 * This is a general-purpose iterator for returning all nodes that 1265 * match the specified name array. 1266 */ 1267 struct profile_iterator { 1268 prf_magic_t magic; 1269 profile_t profile; 1270 int flags; 1271 const char *const *names; 1272 const char *name; 1273 prf_file_t file; 1274 int file_serial; 1275 int done_idx; 1276 struct profile_node *node; 1277 int num; 1278 }; 1279 1280 errcode_t 1281 profile_iterator_create(profile_t profile, const char *const *names, int flags, 1282 void **ret_iter) 1283 { 1284 struct profile_iterator *iter; 1285 int done_idx = 0; 1286 1287 if (profile == 0) 1288 return PROF_NO_PROFILE; 1289 if (profile->magic != PROF_MAGIC_PROFILE) 1290 return PROF_MAGIC_PROFILE; 1291 if (!names) 1292 return PROF_BAD_NAMESET; 1293 if (!(flags & PROFILE_ITER_LIST_SECTION)) { 1294 if (!names[0]) 1295 return PROF_BAD_NAMESET; 1296 done_idx = 1; 1297 } 1298 1299 if ((iter = malloc(sizeof(struct profile_iterator))) == NULL) 1300 return ENOMEM; 1301 1302 iter->magic = PROF_MAGIC_ITERATOR; 1303 iter->profile = profile; 1304 iter->names = names; 1305 iter->flags = flags; 1306 iter->file = profile->first_file; 1307 iter->done_idx = done_idx; 1308 iter->node = 0; 1309 iter->num = 0; 1310 *ret_iter = iter; 1311 return 0; 1312 } 1313 1314 void profile_iterator_free(void **iter_p) 1315 { 1316 struct profile_iterator *iter; 1317 1318 if (!iter_p) 1319 return; 1320 iter = *iter_p; 1321 if (!iter || iter->magic != PROF_MAGIC_ITERATOR) 1322 return; 1323 free(iter); 1324 *iter_p = 0; 1325 } 1326 1327 /* 1328 * Note: the returned character strings in ret_name and ret_value 1329 * points to the stored character string in the parse string. Before 1330 * this string value is returned to a calling application 1331 * (profile_node_iterator is not an exported interface), it should be 1332 * strdup()'ed. 1333 */ 1334 errcode_t profile_node_iterator(void **iter_p, struct profile_node **ret_node, 1335 char **ret_name, char **ret_value) 1336 { 1337 struct profile_iterator *iter = *iter_p; 1338 struct profile_node *section, *p; 1339 const char *const *cpp; 1340 errcode_t retval; 1341 int skip_num = 0; 1342 1343 if (!iter || iter->magic != PROF_MAGIC_ITERATOR) 1344 return PROF_MAGIC_ITERATOR; 1345 if (iter->file && iter->file->magic != PROF_MAGIC_FILE) 1346 return PROF_MAGIC_FILE; 1347 /* 1348 * If the file has changed, then the node pointer is invalid, 1349 * so we'll have search the file again looking for it. 1350 */ 1351 if (iter->node && (iter->file && 1352 iter->file->upd_serial != iter->file_serial)) { 1353 iter->flags &= ~PROFILE_ITER_FINAL_SEEN; 1354 skip_num = iter->num; 1355 iter->node = 0; 1356 } 1357 if (iter->node && iter->node->magic != PROF_MAGIC_NODE) { 1358 return PROF_MAGIC_NODE; 1359 } 1360 get_new_file: 1361 if (iter->node == 0) { 1362 if (iter->file == 0 || 1363 (iter->flags & PROFILE_ITER_FINAL_SEEN)) { 1364 profile_iterator_free(iter_p); 1365 if (ret_node) 1366 *ret_node = 0; 1367 if (ret_name) 1368 *ret_name = 0; 1369 if (ret_value) 1370 *ret_value =0; 1371 return 0; 1372 } 1373 if ((retval = profile_update_file(iter->file))) { 1374 if (retval == ENOENT || retval == EACCES) { 1375 /* XXX memory leak? */ 1376 iter->file = iter->file->next; 1377 skip_num = 0; 1378 retval = 0; 1379 goto get_new_file; 1380 } else { 1381 profile_iterator_free(iter_p); 1382 return retval; 1383 } 1384 } 1385 iter->file_serial = iter->file->upd_serial; 1386 /* 1387 * Find the section to list if we are a LIST_SECTION, 1388 * or find the containing section if not. 1389 */ 1390 section = iter->file->root; 1391 for (cpp = iter->names; cpp[iter->done_idx]; cpp++) { 1392 for (p=section->first_child; p; p = p->next) { 1393 if (!strcmp(p->name, *cpp) && !p->value) 1394 break; 1395 } 1396 if (!p) { 1397 section = 0; 1398 break; 1399 } 1400 section = p; 1401 if (p->final) 1402 iter->flags |= PROFILE_ITER_FINAL_SEEN; 1403 } 1404 if (!section) { 1405 iter->file = iter->file->next; 1406 skip_num = 0; 1407 goto get_new_file; 1408 } 1409 iter->name = *cpp; 1410 iter->node = section->first_child; 1411 } 1412 /* 1413 * OK, now we know iter->node is set up correctly. Let's do 1414 * the search. 1415 */ 1416 for (p = iter->node; p; p = p->next) { 1417 if (iter->name && strcmp(p->name, iter->name)) 1418 continue; 1419 if ((iter->flags & PROFILE_ITER_SECTIONS_ONLY) && 1420 p->value) 1421 continue; 1422 if ((iter->flags & PROFILE_ITER_RELATIONS_ONLY) && 1423 !p->value) 1424 continue; 1425 if (skip_num > 0) { 1426 skip_num--; 1427 continue; 1428 } 1429 if (p->deleted) 1430 continue; 1431 break; 1432 } 1433 iter->num++; 1434 if (!p) { 1435 iter->file = iter->file->next; 1436 iter->node = 0; 1437 skip_num = 0; 1438 goto get_new_file; 1439 } 1440 if ((iter->node = p->next) == NULL) 1441 iter->file = iter->file->next; 1442 if (ret_node) 1443 *ret_node = p; 1444 if (ret_name) 1445 *ret_name = p->name; 1446 if (ret_value) 1447 *ret_value = p->value; 1448 return 0; 1449 } 1450 1451 1452 /* 1453 * prof_get.c --- routines that expose the public interfaces for 1454 * querying items from the profile. 1455 * 1456 */ 1457 1458 /* 1459 * This function only gets the first value from the file; it is a 1460 * helper function for profile_get_string, profile_get_integer, etc. 1461 */ 1462 errcode_t profile_get_value(profile_t profile, const char *name, 1463 const char *subname, const char *subsubname, 1464 const char **ret_value) 1465 { 1466 errcode_t retval; 1467 void *state; 1468 char *value; 1469 const char *names[4]; 1470 1471 names[0] = name; 1472 names[1] = subname; 1473 names[2] = subsubname; 1474 names[3] = 0; 1475 1476 if ((retval = profile_iterator_create(profile, names, 1477 PROFILE_ITER_RELATIONS_ONLY, 1478 &state))) 1479 return retval; 1480 1481 if ((retval = profile_node_iterator(&state, 0, 0, &value))) 1482 goto cleanup; 1483 1484 if (value) 1485 *ret_value = value; 1486 else 1487 retval = PROF_NO_RELATION; 1488 1489 cleanup: 1490 profile_iterator_free(&state); 1491 return retval; 1492 } 1493 1494 errcode_t 1495 profile_get_string(profile_t profile, const char *name, const char *subname, 1496 const char *subsubname, const char *def_val, 1497 char **ret_string) 1498 { 1499 const char *value; 1500 errcode_t retval; 1501 1502 if (profile) { 1503 retval = profile_get_value(profile, name, subname, 1504 subsubname, &value); 1505 if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) 1506 value = def_val; 1507 else if (retval) 1508 return retval; 1509 } else 1510 value = def_val; 1511 1512 if (value) { 1513 *ret_string = malloc(strlen(value)+1); 1514 if (*ret_string == 0) 1515 return ENOMEM; 1516 strcpy(*ret_string, value); 1517 } else 1518 *ret_string = 0; 1519 return 0; 1520 } 1521 1522 errcode_t 1523 profile_get_integer(profile_t profile, const char *name, const char *subname, 1524 const char *subsubname, int def_val, int *ret_int) 1525 { 1526 const char *value; 1527 errcode_t retval; 1528 char *end_value; 1529 long ret_long; 1530 1531 *ret_int = def_val; 1532 if (profile == 0) 1533 return 0; 1534 1535 retval = profile_get_value(profile, name, subname, subsubname, &value); 1536 if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { 1537 *ret_int = def_val; 1538 return 0; 1539 } else if (retval) 1540 return retval; 1541 1542 if (value[0] == 0) 1543 /* Empty string is no good. */ 1544 return PROF_BAD_INTEGER; 1545 errno = 0; 1546 ret_long = strtol (value, &end_value, 10); 1547 1548 /* Overflow or underflow. */ 1549 if ((ret_long == LONG_MIN || ret_long == LONG_MAX) && errno != 0) 1550 return PROF_BAD_INTEGER; 1551 /* Value outside "int" range. */ 1552 if ((long) (int) ret_long != ret_long) 1553 return PROF_BAD_INTEGER; 1554 /* Garbage in string. */ 1555 if (end_value != value + strlen (value)) 1556 return PROF_BAD_INTEGER; 1557 1558 1559 *ret_int = ret_long; 1560 return 0; 1561 } 1562 1563 errcode_t 1564 profile_get_uint(profile_t profile, const char *name, const char *subname, 1565 const char *subsubname, unsigned int def_val, 1566 unsigned int *ret_int) 1567 { 1568 const char *value; 1569 errcode_t retval; 1570 char *end_value; 1571 unsigned long ret_long; 1572 1573 *ret_int = def_val; 1574 if (profile == 0) 1575 return 0; 1576 1577 retval = profile_get_value(profile, name, subname, subsubname, &value); 1578 if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { 1579 *ret_int = def_val; 1580 return 0; 1581 } else if (retval) 1582 return retval; 1583 1584 if (value[0] == 0) 1585 /* Empty string is no good. */ 1586 return PROF_BAD_INTEGER; 1587 errno = 0; 1588 ret_long = strtoul (value, &end_value, 10); 1589 1590 /* Overflow or underflow. */ 1591 if ((ret_long == ULONG_MAX) && errno != 0) 1592 return PROF_BAD_INTEGER; 1593 /* Value outside "int" range. */ 1594 if ((unsigned long) (unsigned int) ret_long != ret_long) 1595 return PROF_BAD_INTEGER; 1596 /* Garbage in string. */ 1597 if (end_value != value + strlen (value)) 1598 return PROF_BAD_INTEGER; 1599 1600 *ret_int = ret_long; 1601 return 0; 1602 } 1603 1604 errcode_t 1605 profile_get_double(profile_t profile, const char *name, const char *subname, 1606 const char *subsubname, double def_val, double *ret_double) 1607 { 1608 const char *value; 1609 errcode_t retval; 1610 char *end_value; 1611 double double_val; 1612 1613 *ret_double = def_val; 1614 if (profile == 0) 1615 return 0; 1616 1617 retval = profile_get_value(profile, name, subname, subsubname, &value); 1618 if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { 1619 *ret_double = def_val; 1620 return 0; 1621 } else if (retval) 1622 return retval; 1623 1624 if (value[0] == 0) 1625 /* Empty string is no good. */ 1626 return PROF_BAD_INTEGER; 1627 errno = 0; 1628 double_val = strtod(value, &end_value); 1629 1630 /* Overflow or underflow. */ 1631 if (errno != 0) 1632 return PROF_BAD_INTEGER; 1633 /* Garbage in string. */ 1634 if (end_value != value + strlen(value)) 1635 return PROF_BAD_INTEGER; 1636 1637 *ret_double = double_val; 1638 return 0; 1639 } 1640 1641 static const char *const conf_yes[] = { 1642 "y", "yes", "true", "t", "1", "on", 1643 0, 1644 }; 1645 1646 static const char *const conf_no[] = { 1647 "n", "no", "false", "nil", "0", "off", 1648 0, 1649 }; 1650 1651 static errcode_t 1652 profile_parse_boolean(const char *s, int *ret_boolean) 1653 { 1654 const char *const *p; 1655 1656 if (ret_boolean == NULL) 1657 return PROF_EINVAL; 1658 1659 for(p=conf_yes; *p; p++) { 1660 if (!strcasecmp(*p,s)) { 1661 *ret_boolean = 1; 1662 return 0; 1663 } 1664 } 1665 1666 for(p=conf_no; *p; p++) { 1667 if (!strcasecmp(*p,s)) { 1668 *ret_boolean = 0; 1669 return 0; 1670 } 1671 } 1672 1673 return PROF_BAD_BOOLEAN; 1674 } 1675 1676 errcode_t 1677 profile_get_boolean(profile_t profile, const char *name, const char *subname, 1678 const char *subsubname, int def_val, int *ret_boolean) 1679 { 1680 const char *value; 1681 errcode_t retval; 1682 1683 if (profile == 0) { 1684 *ret_boolean = def_val; 1685 return 0; 1686 } 1687 1688 retval = profile_get_value(profile, name, subname, subsubname, &value); 1689 if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { 1690 *ret_boolean = def_val; 1691 return 0; 1692 } else if (retval) 1693 return retval; 1694 1695 return profile_parse_boolean (value, ret_boolean); 1696 } 1697 1698 errcode_t 1699 profile_iterator(void **iter_p, char **ret_name, char **ret_value) 1700 { 1701 char *name, *value; 1702 errcode_t retval; 1703 1704 retval = profile_node_iterator(iter_p, 0, &name, &value); 1705 if (retval) 1706 return retval; 1707 1708 if (ret_name) { 1709 if (name) { 1710 *ret_name = malloc(strlen(name)+1); 1711 if (!*ret_name) 1712 return ENOMEM; 1713 strcpy(*ret_name, name); 1714 } else 1715 *ret_name = 0; 1716 } 1717 if (ret_value) { 1718 if (value) { 1719 *ret_value = malloc(strlen(value)+1); 1720 if (!*ret_value) { 1721 if (ret_name) { 1722 free(*ret_name); 1723 *ret_name = 0; 1724 } 1725 return ENOMEM; 1726 } 1727 strcpy(*ret_value, value); 1728 } else 1729 *ret_value = 0; 1730 } 1731 return 0; 1732 } 1733 1734 #ifdef DEBUG_PROGRAM 1735 1736 /* 1737 * test_profile.c --- testing program for the profile routine 1738 */ 1739 1740 #include "argv_parse.h" 1741 #include "profile_helpers.h" 1742 1743 const char *program_name = "test_profile"; 1744 1745 #define PRINT_VALUE 1 1746 #define PRINT_VALUES 2 1747 1748 static void do_cmd(profile_t profile, char **argv) 1749 { 1750 errcode_t retval; 1751 const char **names, *value; 1752 char **values, **cpp; 1753 char *cmd; 1754 int print_status; 1755 1756 cmd = *(argv); 1757 names = (const char **) argv + 1; 1758 print_status = 0; 1759 retval = 0; 1760 if (cmd == 0) 1761 return; 1762 if (!strcmp(cmd, "query")) { 1763 retval = profile_get_values(profile, names, &values); 1764 print_status = PRINT_VALUES; 1765 } else if (!strcmp(cmd, "query1")) { 1766 const char *name = 0; 1767 const char *subname = 0; 1768 const char *subsubname = 0; 1769 1770 name = names[0]; 1771 if (name) 1772 subname = names[1]; 1773 if (subname) 1774 subsubname = names[2]; 1775 if (subsubname && names[3]) { 1776 fprintf(stderr, 1777 "Only 3 levels are allowed with query1\n"); 1778 retval = EINVAL; 1779 } else 1780 retval = profile_get_value(profile, name, subname, 1781 subsubname, &value); 1782 print_status = PRINT_VALUE; 1783 } else if (!strcmp(cmd, "list_sections")) { 1784 retval = profile_get_subsection_names(profile, names, 1785 &values); 1786 print_status = PRINT_VALUES; 1787 } else if (!strcmp(cmd, "list_relations")) { 1788 retval = profile_get_relation_names(profile, names, 1789 &values); 1790 print_status = PRINT_VALUES; 1791 } else if (!strcmp(cmd, "dump")) { 1792 retval = profile_write_tree_file 1793 (profile->first_file->root, stdout); 1794 #if 0 1795 } else if (!strcmp(cmd, "clear")) { 1796 retval = profile_clear_relation(profile, names); 1797 } else if (!strcmp(cmd, "update")) { 1798 retval = profile_update_relation(profile, names+2, 1799 *names, *(names+1)); 1800 #endif 1801 } else if (!strcmp(cmd, "verify")) { 1802 retval = profile_verify_node 1803 (profile->first_file->root); 1804 #if 0 1805 } else if (!strcmp(cmd, "rename_section")) { 1806 retval = profile_rename_section(profile, names+1, *names); 1807 } else if (!strcmp(cmd, "add")) { 1808 value = *names; 1809 if (strcmp(value, "NULL") == 0) 1810 value = NULL; 1811 retval = profile_add_relation(profile, names+1, value); 1812 } else if (!strcmp(cmd, "flush")) { 1813 retval = profile_flush(profile); 1814 #endif 1815 } else { 1816 printf("Invalid command.\n"); 1817 } 1818 if (retval) { 1819 com_err(cmd, retval, ""); 1820 print_status = 0; 1821 } 1822 switch (print_status) { 1823 case PRINT_VALUE: 1824 printf("%s\n", value); 1825 break; 1826 case PRINT_VALUES: 1827 for (cpp = values; *cpp; cpp++) 1828 printf("%s\n", *cpp); 1829 profile_free_list(values); 1830 break; 1831 } 1832 } 1833 1834 static void do_batchmode(profile_t profile) 1835 { 1836 int argc, ret; 1837 char **argv; 1838 char buf[256]; 1839 1840 while (!feof(stdin)) { 1841 if (fgets(buf, sizeof(buf), stdin) == NULL) 1842 break; 1843 printf(">%s", buf); 1844 ret = argv_parse(buf, &argc, &argv); 1845 if (ret != 0) { 1846 printf("Argv_parse returned %d!\n", ret); 1847 continue; 1848 } 1849 do_cmd(profile, argv); 1850 printf("\n"); 1851 argv_free(argv); 1852 } 1853 profile_release(profile); 1854 exit(0); 1855 1856 } 1857 1858 void syntax_err_report(const char *filename, long err, int line_num) 1859 { 1860 fprintf(stderr, "Syntax error in %s, line number %d: %s\n", 1861 filename, line_num, error_message(err)); 1862 exit(1); 1863 } 1864 1865 const char *default_str = "[foo]\n\tbar=quux\n\tsub = {\n\t\twin = true\n}\n"; 1866 1867 int main(int argc, char **argv) 1868 { 1869 profile_t profile; 1870 long retval; 1871 char *cmd; 1872 1873 if (argc < 2) { 1874 fprintf(stderr, "Usage: %s filename [cmd argset]\n", program_name); 1875 exit(1); 1876 } 1877 1878 initialize_prof_error_table(); 1879 1880 profile_set_syntax_err_cb(syntax_err_report); 1881 1882 retval = profile_init_path(argv[1], &profile); 1883 if (retval) { 1884 com_err(program_name, retval, "while initializing profile"); 1885 exit(1); 1886 } 1887 retval = profile_set_default(profile, default_str); 1888 if (retval) { 1889 com_err(program_name, retval, "while setting default"); 1890 exit(1); 1891 } 1892 1893 cmd = *(argv+2); 1894 if (!cmd || !strcmp(cmd, "batch")) 1895 do_batchmode(profile); 1896 else 1897 do_cmd(profile, argv+2); 1898 profile_release(profile); 1899 1900 return 0; 1901 } 1902 1903 #endif 1904