aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheodore Tso <tytso@mit.edu>1998-11-14 03:45:05 +0000
committerTheodore Tso <tytso@mit.edu>1998-11-14 03:45:05 +0000
commit5b62e1f2ff162cc7bef392fbc85266648eb100d5 (patch)
tree8b8d3e6b29e9834a2dc0ea246b4326f4babc7896
parent9c3cd8f8f10efe5c9428ad0a1ada71bae826007a (diff)
downloadkrb5-5b62e1f2ff162cc7bef392fbc85266648eb100d5.zip
krb5-5b62e1f2ff162cc7bef392fbc85266648eb100d5.tar.gz
krb5-5b62e1f2ff162cc7bef392fbc85266648eb100d5.tar.bz2
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
-rw-r--r--src/util/profile/ChangeLog45
-rw-r--r--src/util/profile/Makefile.in2
-rw-r--r--src/util/profile/configure.in5
-rw-r--r--src/util/profile/prof_err.et1
-rw-r--r--src/util/profile/prof_file.c1
-rw-r--r--src/util/profile/prof_get.c282
-rw-r--r--src/util/profile/prof_int.h32
-rw-r--r--src/util/profile/prof_parse.c26
-rw-r--r--src/util/profile/prof_tree.c193
-rw-r--r--src/util/profile/profile.571
-rw-r--r--src/util/profile/prtest.in36
-rw-r--r--src/util/profile/prtest.script11
-rw-r--r--src/util/profile/test_profile.c17
13 files changed, 480 insertions, 242 deletions
diff --git a/src/util/profile/ChangeLog b/src/util/profile/ChangeLog
index e334539..21dd990 100644
--- a/src/util/profile/ChangeLog
+++ b/src/util/profile/ChangeLog
@@ -1,3 +1,48 @@
+1998-11-13 Theodore Ts'o <tytso@rsts-11.mit.edu>
+
+ * 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 <gjking@mit.edu>
* 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 0889e34..b17ef17 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 0594dba..850f3be 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 6e1dac6..e424042 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 d2b427e..070cbef 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 adb175a..2613127 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 <stdio.h>
@@ -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, &section);
- 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, &section);
- 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, &section);
- 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, &section);
- 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, &section);
- 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 8a45ec4..99d7fc1 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 cc7e36b..833f80d 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 80d633d..3bb05d2 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;
@@ -175,6 +176,27 @@ errcode_t profile_add_node(section, name, value, ret_node)
}
/*
+ * 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
* relations in the section. The first time this routine is called,
@@ -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 0000000..7f3b36a
--- /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 0000000..ef3efb3
--- /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 0000000..5d5a144
--- /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 19edbaf..4b2df6d 100644
--- a/src/util/profile/test_profile.c
+++ b/src/util/profile/test_profile.c
@@ -7,7 +7,7 @@
#include <stdlib.h>
#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;