From: Theodore Tso Date: Sat, 14 Nov 1998 03:45:05 +0000 (+0000) Subject: Makefile.in: Set the myfulldir and mydir variables (which are relative X-Git-Tag: krb5-1.1-beta1~479 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=5b62e1f2ff162cc7bef392fbc85266648eb100d5;p=krb5.git Makefile.in: Set the myfulldir and mydir variables (which are relative to buildtop and thisconfigdir, respectively.) configure.in: Build the test script prtest for doing regression test suites of the profile library. prof_err.et (PROF_MAGIC_ITERATOR): Add a new error code for the magic number for the iterator structure. prof_file.c (profile_update_file): Increment the update serial number when the profile file is re-read. prof_tree.c (profile_make_node_final, profile_is_node_final): Add a new attribute for a node, which is whether or not the node is "final". This controls whether or not the next profile file should be searched when looking up a key which matches the section named by the node. (profile_node_iterator_create, profile_node_iterator_free, profile_node_iterator): New functions which take a profile_t and returns all of the names or values for a particular search key. This iterator follows the rules of doing multiple profile file lookups using the "final node" marker to stop searching subsequent profile files. prof_parse.c (parse_std_line): Add support for marking top level sections, subsections, and individual nodes as final, using the '*' character. (dump_profile_to_file): Print finalized sections with the '*' character. prof_get.c: Update routines to use the iterators provided by prof_tree.c. prof_int.c: Add upd_serial member to the prf_file_t structure. Define the symbolic flags used by the profile node iterator. Add function declarations for profile_make_node_final, profile_is_node_final, profile_node_iterator_create, profile_node_iterator_free, profile_node_iterator, and profile_get_value. test_profile.c: Add the query1 command which tests profile_get_value. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@11038 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/util/profile/ChangeLog b/src/util/profile/ChangeLog index e3345397c..21dd99016 100644 --- a/src/util/profile/ChangeLog +++ b/src/util/profile/ChangeLog @@ -1,3 +1,48 @@ +1998-11-13 Theodore Ts'o + + * Makefile.in: Set the myfulldir and mydir variables (which are + relative to buildtop and thisconfigdir, respectively.) + + * configure.in: Build the test script prtest for doing regression + test suites of the profile library. + + * prof_err.et (PROF_MAGIC_ITERATOR): Add a new error code for the + magic number for the iterator structure. + + * prof_file.c (profile_update_file): Increment the update serial + number when the profile file is re-read. + + * prof_tree.c (profile_make_node_final, profile_is_node_final): + Add a new attribute for a node, which is whether or not + the node is "final". This controls whether or not the + next profile file should be searched when looking up a key + which matches the section named by the node. + (profile_node_iterator_create, profile_node_iterator_free, + profile_node_iterator): New functions which take a + profile_t and returns all of the names or values for a + particular search key. This iterator follows the rules of + doing multiple profile file lookups using the "final node" + marker to stop searching subsequent profile files. + + * prof_parse.c (parse_std_line): Add support for marking top level + sections, subsections, and individual nodes as final, + using the '*' character. + (dump_profile_to_file): Print finalized sections with the '*' + character. + + * prof_get.c: Update routines to use the iterators provided by + prof_tree.c. + + * prof_int.c: Add upd_serial member to the prf_file_t structure. + Define the symbolic flags used by the profile node + iterator. Add function declarations for + profile_make_node_final, profile_is_node_final, + profile_node_iterator_create, profile_node_iterator_free, + profile_node_iterator, and profile_get_value. + + * test_profile.c: Add the query1 command which tests + profile_get_value. + 1998-11-05 Geoffrey King * prof_init.c (profile_init): Fix a problem whereby if the last diff --git a/src/util/profile/Makefile.in b/src/util/profile/Makefile.in index 0889e343c..b17ef17e6 100644 --- a/src/util/profile/Makefile.in +++ b/src/util/profile/Makefile.in @@ -1,4 +1,6 @@ thisconfigdir=. +myfulldir=util/profile +mydir=. BUILDTOP=$(REL)$(U)$(S)$(U) PROG_LIBPATH=-L$(TOPLIBD) PROG_RPATH=$(KRB5_LIBDIR) diff --git a/src/util/profile/configure.in b/src/util/profile/configure.in index 0594dbaa9..850f3befb 100644 --- a/src/util/profile/configure.in +++ b/src/util/profile/configure.in @@ -10,5 +10,8 @@ AC_PROG_AWK KRB5_BUILD_LIBOBJS KRB5_BUILD_PROGRAM KRB5_BUILD_LIBRARY_WITH_DEPS -V5_AC_OUTPUT_MAKEFILE +K5_GEN_MAKEFILE(., lib libobj) +K5_GEN_FILE(prtest) +K5_AC_OUTPUT + diff --git a/src/util/profile/prof_err.et b/src/util/profile/prof_err.et index 6e1dac68f..e424042cb 100644 --- a/src/util/profile/prof_err.et +++ b/src/util/profile/prof_err.et @@ -16,6 +16,7 @@ error_code PROF_BAD_LINK_LIST, "Bad linked list in profile structures" error_code PROF_BAD_GROUP_LVL, "Bad group level in profile strctures" error_code PROF_BAD_PARENT_PTR, "Bad parent pointer in profile strctures" +error_code PROF_MAGIC_ITERATOR, "Bad magic value in profile iterator" # # generated by prof_parse.c diff --git a/src/util/profile/prof_file.c b/src/util/profile/prof_file.c index d2b427e55..070cbeffc 100644 --- a/src/util/profile/prof_file.c +++ b/src/util/profile/prof_file.c @@ -86,6 +86,7 @@ errcode_t profile_update_file(prf) f = fopen(prf->filename, "r"); if (f == NULL) return errno; + prf->upd_serial++; retval = profile_parse_file(f, &prf->root); fclose(f); if (retval) diff --git a/src/util/profile/prof_get.c b/src/util/profile/prof_get.c index adb175afa..2613127b7 100644 --- a/src/util/profile/prof_get.c +++ b/src/util/profile/prof_get.c @@ -2,85 +2,6 @@ * prof_get.c --- routines that expose the public interfaces for * querying items from the profile. * - * A profile object can contain multiple profile files; each profile - * is composed of hierarchical sections. Sections can contain - * sections, or relations, both of which are named. (Sections roughly - * correspond to directories, and relations to files.) - * - * Relations may contain multiple values; profile_get_values() will - * return all of the values for a particular relation, - * profile_get_value() will return the first such value for a - * relation. - * - * When there are multiple profile files open for a particular - * profile object, the searching algorithms will find the first - * profile file which contains the full section-path, and only look in - * that profile file for the named relation. - * - * An example here may be useful. Consider a profile which is - * initialied to search to profile files, ~/.samplerc and - * /etc/sample.conf, in that order. Let us suppose that the - * system-wide /etc/sample.conf contains the following information: - * - * [realms] - * ATHENA.MIT.EDU = { - * kdc = kerberos.mit.edu:88 - * kdc = kerberos-1.mit.edu:88 - * kdc = kerberos-2.mit.edu:88 - * admin_server = kerberos.mit.edu:88 - * default_domain = mit.edu - * } - * - * [DNS] - * MIT.EDU = { - * strawb = { - * version = 4.8.3 - * location = E40 - * } - * bitsy = { - * version = 4.8.3 - * location = E40 - * } - * } - * - * ... and the user's ~/.samplerc contains the following: - * - * [realms] - * ATHENA.MIT.EDU = { - * kdc = kerberos-test.mit.edu - * admin_server = kerberos-test.mit.edu - * } - * - * [DNS] - * MIT.EDU = { - * w20-ns = { - * version = 4.8.3 - * location = W20 - * } - * bitsy = { - * version = 4.9.4 - * } - * } - * - * In this example, the values for realms/ATHENA.MIT.EDU/kdc and - * realms/ATHENA.MIT.EDU/admin_server will be taken from ~/.samplrc - * exclusively, since the section realms/ATHENA.MIT.EDU was found - * first in ~/.samplerc. - * - * However, in the case of the [DNS] section, queries for - * DNS/MIT.EDU/w20-ns/<*> will be taken from ~/.samplrc, and - * DNS/MIT.EDU/strawb/<*> will be taken from /etc/sample.rc. - * - * DNS/MIT.EDU/BITSY/version will return 4.9.4, since the entry - * in ~/.samplerc will override the one in /etc/sample.conf. Less - * intuitively, a query for DNS/bitsy/location will return no value, - * since the DNS/bitsy section exists in ~/.samplerc. - * - * This can all be summed up using the following rule: a section found - * in an earlier profile file completely shadows a section in a later - * profile file for the purposes of looking up relations, but not when - * looking up subsections contained in the section. - * */ #include @@ -215,75 +136,6 @@ KRB5_DLLIMP void KRB5_CALLCONV profile_free_list(list) free(list); } -/* - * This function searches the profile for a named section, looking in - * each file in the profile. If ret_name is NULL, then this - * function looks at the entire names array; if ret_name is non-NULL, - * then the last entry in the names array is assumed to be the name of - * the relation desired by profile_get_values(), and is returned in - * ret_name. The section looked up in that case will not include the - * last entry in the names array. - */ -static errcode_t lookup_section(profile, names, ret_name, ret_section) - profile_t profile; - const char **names; - const char **ret_name; - struct profile_node **ret_section; -{ - prf_file_t file; - errcode_t retval; - int done_idx = 0; - const char **cpp; - void *state; - struct profile_node *section; - - if (profile == 0) - return PROF_NO_PROFILE; - - if (names == 0 || names[0] == 0 || (ret_name && names[1] == 0)) - return PROF_BAD_NAMESET; - - if (ret_name) - done_idx = 1; - - file = profile->first_file; - if ((retval = profile_update_file(file))) - return retval; - - section = file->root; - cpp = names; - - while (cpp[done_idx]) { - state = 0; - retval = profile_find_node_subsection(section, *cpp, - &state, 0, §ion); - if (retval == PROF_NO_SECTION) { - /* - * OK, we didn't find the section in this - * file; let's try the next file. - */ - file = file->next; - if (!file) - return retval; - if ((retval = profile_update_file(file))) - return retval; - section = file->root; - cpp = names; - continue; - } else if (retval) - return retval; - cpp++; - } - *ret_section = section; - if (ret_name) - *ret_name = *cpp; - return 0; -} - -/* - * This function finds a relation from the profile, and returns all of - * the values from that relation. - */ KRB5_DLLIMP errcode_t KRB5_CALLCONV profile_get_values(profile, names, ret_values) profile_t profile; @@ -291,24 +143,23 @@ profile_get_values(profile, names, ret_values) char ***ret_values; { errcode_t retval; - struct profile_node *section; void *state; - const char *name; char *value; struct profile_string_list values; - retval = lookup_section(profile, names, &name, §ion); - if (retval) + if ((retval = profile_node_iterator_create(profile, names, + PROFILE_ITER_RELATIONS_ONLY, + &state))) return retval; - init_list(&values); + if ((retval = init_list(&values))) + return retval; - state = 0; do { - if ((retval = profile_find_node_relation(section, name, - &state, 0, &value))) + if ((retval = profile_node_iterator(&state, 0, 0, &value))) goto cleanup; - add_to_list(&values, value); + if (value) + add_to_list(&values, value); } while (state); end_list(&values, ret_values); @@ -317,34 +168,37 @@ profile_get_values(profile, names, ret_values) cleanup: end_list(&values, 0); return retval; -} +} /* * This function only gets the first value from the file; it is a * helper function for profile_get_string, profile_get_integer, etc. */ -static errcode_t profile_get_value(profile, names, ret_value) +errcode_t profile_get_value(profile, names, ret_value) profile_t profile; const char **names; - char **ret_value; + const char **ret_value; { errcode_t retval; - struct profile_node *section; void *state; - const char *name; char *value; - retval = lookup_section(profile, names, &name, §ion); - if (retval) + if ((retval = profile_node_iterator_create(profile, names, + PROFILE_ITER_RELATIONS_ONLY, + &state))) return retval; - state = 0; - if ((retval = profile_find_node_relation(section, name, - &state, 0, &value))) - return retval; + if ((retval = profile_node_iterator(&state, 0, 0, &value))) + goto cleanup; + + if (value) + *ret_value = value; + else + retval = PROF_NO_RELATION; - *ret_value = value; - return 0; +cleanup: + profile_node_iterator_free(&state); + return retval; } errcode_t profile_get_string(profile, name, subname, subsubname, @@ -388,7 +242,7 @@ errcode_t profile_get_integer(profile, name, subname, subsubname, int def_val; int *ret_int; { - char *value; + const char *value; errcode_t retval; const char *names[4]; @@ -421,59 +275,29 @@ errcode_t profile_get_subsection_names(profile, names, ret_names) const char **names; char ***ret_names; { - prf_file_t file; - errcode_t retval; - char *name; - const char **cpp; - void *state; - struct profile_node *section; + errcode_t retval; + void *state; + char *name; struct profile_string_list values; - if (profile == 0) - return PROF_NO_PROFILE; + if ((retval = profile_node_iterator_create(profile, names, + PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY, + &state))) + return retval; - if (names == 0) - return PROF_BAD_NAMESET; + if ((retval = init_list(&values))) + return retval; + + do { + if ((retval = profile_node_iterator(&state, 0, &name, 0))) + goto cleanup; + if (name) + add_to_list(&values, name); + } while (state); - init_list(&values); - for (file = profile->first_file; file; file = file->next) { - if ((retval = profile_update_file(file))) - return retval; - section = file->root; - cpp = names; - /* - * Find the correct section in this file, if it - * exists. - */ - while (*cpp) { - state = 0; - retval = profile_find_node_subsection(section, *cpp, - &state, 0, §ion); - if (retval == PROF_NO_SECTION) - continue; - else if (retval) - goto cleanup; - cpp++; - } - /* - * Now find all of the subsections and append them to - * the list. - */ - state = 0; - do { - retval = profile_find_node_subsection(section, 0, - &state, &name, 0); - if (retval == PROF_NO_SECTION) - break; - else if (retval) - goto cleanup; - if (!is_list_member(&values, name)) - add_to_list(&values, name); - } while (state); - } - end_list(&values, ret_names); return 0; + cleanup: end_list(&values, 0); return retval; @@ -489,35 +313,29 @@ errcode_t profile_get_relation_names(profile, names, ret_names) char ***ret_names; { errcode_t retval; - struct profile_node *section; void *state; char *name; struct profile_string_list values; - retval = lookup_section(profile, names, 0, §ion); - if (retval) + if ((retval = profile_node_iterator_create(profile, names, + PROFILE_ITER_LIST_SECTION | PROFILE_ITER_RELATIONS_ONLY, + &state))) return retval; - init_list(&values); + if ((retval = init_list(&values))) + return retval; - state = 0; do { - retval = profile_find_node_relation(section, 0, - &state, &name, 0); - if (retval == PROF_NO_RELATION) - break; - else if (retval) + if ((retval = profile_node_iterator(&state, 0, &name, 0))) goto cleanup; - if (!is_list_member(&values, name)) + if (name && !is_list_member(&values, name)) add_to_list(&values, name); } while (state); end_list(&values, ret_names); return 0; + cleanup: end_list(&values, 0); return retval; } - - - diff --git a/src/util/profile/prof_int.h b/src/util/profile/prof_int.h index 8a45ec423..99d7fc1ae 100644 --- a/src/util/profile/prof_int.h +++ b/src/util/profile/prof_int.h @@ -43,6 +43,7 @@ struct _prf_file_t { struct profile_node *root; time_t timestamp; int flags; + int upd_serial; struct _prf_file_t *next; }; @@ -60,6 +61,16 @@ struct _profile_t { typedef struct _profile_t *profile_t; +/* + * Used by the profile node iterator in prof_tre.c + */ +#define PROFILE_ITER_LIST_SECTION 0x0001 +#define PROFILE_ITER_SECTIONS_ONLY 0x0002 +#define PROFILE_ITER_RELATIONS_ONLY 0x0004 + +#define PROFILE_ITER_FINAL_SEEN 0x0100 + + /* profile_parse.c */ errcode_t profile_parse_file @@ -82,6 +93,12 @@ errcode_t profile_add_node const char *name, const char *value, struct profile_node **ret_node)); +errcode_t profile_make_node_final + PROTOTYPE((struct profile_node *node)); + +int profile_is_node_final + PROTOTYPE((struct profile_node *node)); + errcode_t profile_find_node_relation PROTOTYPE ((struct profile_node *section, const char *name, void **state, @@ -103,6 +120,17 @@ errcode_t profile_find_node_name PROTOTYPE ((struct profile_node *section, void **state, char **ret_name)); +errcode_t profile_node_iterator_create + PROTOTYPE((profile_t profile, const char **names, + int flags, void **ret_iter)); + +void profile_node_iterator_free + PROTOTYPE((void **iter_p)); + +errcode_t profile_node_iterator + PROTOTYPE((void **iter_p, struct profile_node **ret_node, + char **ret_name, char **ret_value)); + /* prof_file.c */ errcode_t profile_open_file @@ -134,6 +162,10 @@ KRB5_DLLIMP errcode_t KRB5_CALLCONV profile_get_values PROTOTYPE ((profile_t profile, const char **names, char ***ret_values)); +errcode_t profile_get_value + PROTOTYPE ((profile_t profile, const char **names, + const char **ret_value)); + errcode_t profile_get_string PROTOTYPE((profile_t profile, const char *name, const char *subname, const char *subsubname, const char *def_val, diff --git a/src/util/profile/prof_parse.c b/src/util/profile/prof_parse.c index cc7e36b8f..833f80d35 100644 --- a/src/util/profile/prof_parse.c +++ b/src/util/profile/prof_parse.c @@ -89,6 +89,7 @@ static errcode_t parse_std_line(line, state) char *cp, ch, *tag, *value; char *p; errcode_t retval; + struct profile_node *node; int do_subsection = 0; void *iter = 0; @@ -125,6 +126,10 @@ static errcode_t parse_std_line(line, state) * Finish off the rest of the line. */ cp = p+1; + if (*cp == '*') { + profile_make_node_final(state->current_section); + cp++; + } if (*cp) return PROF_SECTION_SYNTAX; return 0; @@ -132,6 +137,8 @@ static errcode_t parse_std_line(line, state) if (ch == '}') { if (state->group_level == 0) return PROF_EXTRA_CBRACE; + if (*(cp+1) == '*') + profile_make_node_final(state->current_section); retval = profile_get_node_parent(state->current_section, &state->current_section); if (retval) @@ -170,15 +177,24 @@ static errcode_t parse_std_line(line, state) *cp-- = 0; } if (do_subsection) { + p = strchr(tag, '*'); + if (p) + *p = '\0'; retval = profile_add_node(state->current_section, tag, 0, &state->current_section); if (retval) return retval; - + if (p) + profile_make_node_final(state->current_section); state->group_level++; return 0; } - profile_add_node(state->current_section, tag, value, 0); + p = strchr(tag, '*'); + if (p) + *p = '\0'; + profile_add_node(state->current_section, tag, value, &node); + if (p) + profile_make_node_final(node); return 0; } @@ -384,7 +400,8 @@ void dump_profile_to_file(root, level, dstfile) if (level == 0) { /* [xxx] */ for (i=0; i < level; i++) fprintf(dstfile, "\t"); - fprintf(dstfile, "[%s]%s", name, EOL); + fprintf(dstfile, "[%s]%s%s", name, + profile_is_node_final(p) ? "*" : "", EOL); dump_profile_to_file(p, level+1, dstfile); fprintf(dstfile, EOL); } else { /* xxx = { ... } */ @@ -394,7 +411,8 @@ void dump_profile_to_file(root, level, dstfile) dump_profile_to_file(p, level+1, dstfile); for (i=0; i < level; i++) fprintf(dstfile, "\t"); - fprintf(dstfile, "}%s", EOL); + fprintf(dstfile, "}%s%s", + profile_is_node_final(p) ? "*" : "", EOL); } } while (iter != 0); } diff --git a/src/util/profile/prof_tree.c b/src/util/profile/prof_tree.c index 80d633ded..3bb05d29f 100644 --- a/src/util/profile/prof_tree.c +++ b/src/util/profile/prof_tree.c @@ -32,6 +32,7 @@ struct profile_node { char *name; char *value; int group_level; + int final:1; /* Indicate don't search next file */ struct profile_node *first_child; struct profile_node *parent; struct profile_node *next, *prev; @@ -174,6 +175,27 @@ errcode_t profile_add_node(section, name, value, ret_node) return 0; } +/* + * Set the final flag on a particular node. + */ +errcode_t profile_make_node_final(node) + struct profile_node *node; +{ + CHECK_MAGIC(node); + + node->final = 1; + return 0; +} + +/* + * Check the final flag on a node + */ +int profile_is_node_final(node) + struct profile_node *node; +{ + return (node->final != 0); +} + /* * Iterate through the section, returning the relations which match * the given name. If name is NULL, then interate through all the @@ -340,3 +362,174 @@ errcode_t profile_get_node_parent(section, parent) *parent = section->parent; return 0; } + +/* + * This is a general-purpose iterator for returning all nodes that + * match the specified name array. + */ +struct profile_iterator { + prf_magic_t magic; + profile_t profile; + int flags; + const char **names; + const char *name; + prf_file_t file; + int file_serial; + int done_idx; + struct profile_node *node; + int num; +}; + +errcode_t profile_node_iterator_create(profile, names, flags, ret_iter) + profile_t profile; + const char **names; + int flags; + void **ret_iter; +{ + struct profile_iterator *iter; + int done_idx = 0; + + if (profile == 0) + return PROF_NO_PROFILE; + if (profile->magic != PROF_MAGIC_PROFILE) + return PROF_MAGIC_PROFILE; + if (!names) + return PROF_BAD_NAMESET; + if (!(flags & PROFILE_ITER_LIST_SECTION)) { + if (!names[0]) + return PROF_BAD_NAMESET; + done_idx = 1; + } + + if ((iter = malloc(sizeof(struct profile_iterator))) == NULL) + return ENOMEM; + + iter->magic = PROF_MAGIC_ITERATOR; + iter->profile = profile; + iter->names = names; + iter->flags = flags; + iter->file = profile->first_file; + iter->done_idx = done_idx; + iter->node = 0; + iter->num = 0; + *ret_iter = iter; + return 0; +} + +void profile_node_iterator_free(iter_p) + void **iter_p; +{ + struct profile_iterator *iter; + + if (!iter_p) + return; + iter = *iter_p; + if (!iter || iter->magic != PROF_MAGIC_ITERATOR) + return; + free(iter); + *iter_p = 0; +} + +errcode_t profile_node_iterator(iter_p, ret_node, ret_name, ret_value) + void **iter_p; + struct profile_node **ret_node; + char **ret_name, **ret_value; +{ + struct profile_iterator *iter = *iter_p; + struct profile_node *section, *p; + const char **cpp; + errcode_t retval; + int skip_num = 0; + + if (iter->magic != PROF_MAGIC_ITERATOR) + return PROF_MAGIC_ITERATOR; + /* + * If the file has changed, then the node pointer is invalid, + * so we'll have search the file again looking for it. + */ + if (iter->node && (iter->file->upd_serial != iter->file_serial)) { + iter->flags &= ~PROFILE_ITER_FINAL_SEEN; + skip_num = iter->num; + iter->node = 0; + } +get_new_file: + while (iter->node == 0) { + if (iter->file == 0 || + (iter->flags & PROFILE_ITER_FINAL_SEEN)) { + profile_node_iterator_free(iter_p); + if (ret_node) + *ret_node = 0; + if (ret_name) + *ret_name = 0; + if (ret_value) + *ret_value =0; + return 0; + } + if ((retval = profile_update_file(iter->file))) { + profile_node_iterator_free(iter_p); + return retval; + } + iter->file_serial = iter->file->upd_serial; + /* + * Find the section to list if we are a LIST_SECTION, + * or find the containing section if not. + */ + section = iter->file->root; + for (cpp = iter->names; cpp[iter->done_idx]; cpp++) { + for (p=section->first_child; p; p = p->next) + if (!strcmp(p->name, *cpp) && !p->value) + break; + if (!p) { + section = 0; + break; + } + section = p; + if (p->final) + iter->flags |= PROFILE_ITER_FINAL_SEEN; + } + if (!section) { + iter->file = iter->file->next; + skip_num = 0; + continue; + } + iter->name = *cpp; + iter->node = section->first_child; + } + /* + * OK, now we know iter->node is set up correctly. Let's do + * the search. + */ + for (p = iter->node; p; p = p->next) { + if (iter->name && strcmp(p->name, iter->name)) + continue; + if ((iter->flags & PROFILE_ITER_SECTIONS_ONLY) && + p->value) + continue; + if ((iter->flags & PROFILE_ITER_RELATIONS_ONLY) && + !p->value) + continue; + if (skip_num > 0) { + skip_num--; + continue; + } + break; + } + iter->num++; + if (!p) { + iter->file = iter->file->next; + iter->node = 0; + skip_num = 0; + goto get_new_file; + } + if ((iter->node = p->next) == NULL) + iter->file = iter->file->next; + if (ret_node) + *ret_node = p; + if (ret_name) + *ret_name = p->name; + if (ret_value) + *ret_value = p->value; + return 0; +}; + + diff --git a/src/util/profile/profile.5 b/src/util/profile/profile.5 new file mode 100644 index 000000000..7f3b36ab5 --- /dev/null +++ b/src/util/profile/profile.5 @@ -0,0 +1,71 @@ + +A profile file is a generic way of storing program configuration +information for applications. An application may choose to consult +multiple configuration files; for example, a Kerberos application +might look first in ~/.krb5rc, and then in /etc/krb5.conf. So +/etc/krb5.conf would contain the side-wide default configuration for +Kerberos, and ~/.krb5rc would contain the user's specific +configuration overrides. + +Configuration information is stored in relations, which have a name +and a value. There may be multiple relations with the same name. +Relations are always contained inside named sections. Sections can +contain relations and other named child sections. + +Top-level sections are defined by enclosing the section name in square +braces. Child sections are defined by enclosing the contents of the +child section in curly braces. Relations are defined by using the +format "name = value". + +An example profile file might look like this: + +[libdefaults] + default_realm = ATHENA.MIT.EDU + +[realms] + ATHENA.MIT.EDU = { + kdc = kerberos.mit.edu:88 + kdc = kerberos-1.mit.edu:88 + kdc = kerberos-2.mit.edu:88 + admin_server = kerberos.mit.edu:88 + default_domain = mit.edu + } + CYGNUS.COM = { + kdc = KERBEROS-1.CYGNUS.COM + kdc = KERBEROS.CYGNUS.COM + admin_server = KERBEROS.MIT.EDU + } + +In this example, the profile file has two top-level sections, +"libdefaults" and "realms". The libdefaults section has a single +relation which is named "default_realm" and has the value +"ATHENA.MIT.EDU". The realms section has two child sections, +"ATHENA.MIT.EDU" and "CYGNUS.MIT.EDU". Each of these child has a +number of relations, "kdc", "admin_server", and (in the case of +"ATHENA.MIT.EDU"), "default_domain". Note that there are multiple +relations with the name "kdc" in both sections; if a +profile_get_values() is called querying the "kdc" relation, both +values will be returned. + +Sections may be marked as "final". If they are marked as final, then +the contents of that section override all subsequent profile files (if +the application is searching multiple profile files for its +configuration information). Normally, all of the profiles are +searched for a matching relation, and all of the values found in all +of the various profile files will be returned. + +Top-level sections are marked as final by adding an '*' character +following the closing square brace. Child sections are marked as +final by adding a '*' character after the closing curly brace. So for +example, in this example both the "libdefaults" and "ATHENA.MIT.EDU" +sections have been marked as final: + +[libdefaults]* + default_realm = ATHENA.MIT.EDU + +[realms] + ATHENA.MIT.EDU = { + kdc = kerberos.mit.edu:88 + admin_server = kerberos.mit.edu:88 + }* + diff --git a/src/util/profile/prtest.in b/src/util/profile/prtest.in new file mode 100644 index 000000000..ef3efb308 --- /dev/null +++ b/src/util/profile/prtest.in @@ -0,0 +1,36 @@ +#!/bin/sh +SRCDIR=@srcdir@ +SCRIPT=$SRCDIR/prtest.script +REPORT=prtest.report +TESTPROG=./test_profile + +rm -f $REPORT + +if test -f $SCRIPT ; then + : +else + echo "$SCRIPT not found!" + exit 1 +fi + +grep -v ^\# < $SCRIPT | while read filespec cmd args +do + case $filespec in + krb5) + file=$SRCDIR/krb5.conf + ;; + test) + file=$SRCDIR/test.ini + ;; + *) + echo "Unknown file specifer $file!" + exit 1 + ;; + esac + if test $cmd = parse ; then + echo \# test_parse $filespec >> $REPORT 2>&1 + $TESTPARSE $file >> $REPORT >> $REPORT 2>&1 + fi + echo \# $filespec $cmd $args >> $REPORT 2>&1 + $TESTPROG $file $cmd $args >> $REPORT 2>&1 +done diff --git a/src/util/profile/prtest.script b/src/util/profile/prtest.script new file mode 100644 index 000000000..5d5a14422 --- /dev/null +++ b/src/util/profile/prtest.script @@ -0,0 +1,11 @@ +krb5 query realms ATHENA.MIT.EDU kdc +krb5 query1 realms ATHENA.MIT.EDU kdc +krb5 query libdefaults ticket_lifetime +krb5 query1 libdefaults ticket_lifetime +krb5 query libdefaults not_present +krb5 query1 libdefaults not_present +krb5 list_sections libdefaults +krb5 list_sections realms +krb5 list_relations libdefaults +krb5 list_relations realms +krb5 list_relations realms ATHENA.MIT.EDU diff --git a/src/util/profile/test_profile.c b/src/util/profile/test_profile.c index 19edbaf3f..4b2df6d36 100644 --- a/src/util/profile/test_profile.c +++ b/src/util/profile/test_profile.c @@ -7,7 +7,7 @@ #include #endif -#include "profile.h" +#include "prof_int.h" #ifndef _MSDOS #include "com_err.h" #else @@ -29,8 +29,10 @@ int main(argc, argv) profile_t profile; long retval; char **values, **cpp; + const char *value; const char **names; char *cmd; + int print_value = 0; if (argc < 3) { fprintf(stderr, "Usage: %s filename cmd argset\n", program_name); @@ -48,6 +50,9 @@ int main(argc, argv) names = (const char **) argv+3; if (!strcmp(cmd, "query")) { retval = profile_get_values(profile, names, &values); + } else if (!strcmp(cmd, "query1")) { + retval = profile_get_value(profile, names, &value); + print_value++; } else if (!strcmp(cmd, "list_sections")) { retval = profile_get_subsection_names(profile, names, &values); } else if (!strcmp(cmd, "list_relations")) { @@ -60,11 +65,13 @@ int main(argc, argv) com_err(argv[0], retval, "while getting values"); exit(1); } - for (cpp = values; *cpp; cpp++) { - printf("%s\n", *cpp); - free(*cpp); + if (print_value) { + printf("%s\n", value); + } else { + for (cpp = values; *cpp; cpp++) + printf("%s\n", *cpp); + profile_free_list(values); } - free(values); profile_release(profile); return 0;