+1998-11-03 Theodore Ts'o <tytso@rsts-11.mit.edu>
+
+ * Makefile.in: Added prof_get.c to the list of files to be compiled.
+
+ * profile.hin: Added declarations for profile_free_list(),
+ profile_get_relation_names(), and
+ profile_get_subsection_names(). (These are new public
+ interfaces to the profile library.)
+
+ * prof_int.h: Removed the profile_section_t structure, which was
+ used only by the now-defunct prof_section.c file. Added
+ the internal interfaces for the new public interfaces.
+ Removed unused declarations which were never
+ implemented(profile_get, profile_update).
+
+ * prof_init.c: Moved all of the profile querying functions
+ (profile_get_values(), profile_get_value(), etc.) to
+ prof_get.c. In the process, removed the really
+ bletcherous (and badly implemented)
+ profile_get_first_values(), which did nothing like what
+ the named implied. Also added to prof_get.c new functions
+ profile_get_subsection_names() and
+ profile_get_relation_names().
+ (profile_ser_internalize): Rewrote error handling to be
+ clearer, and removed a bug where memory was not freed
+ correctly in an error case.
+ (profile_init): If a list of pathnames is passed in,
+ profile_init will now try to open all of them, now that
+ we've defined query fallback semantics in prof_get.c
+
+ * prof_parse.c: Fix lint warning.
+
+ * prof_tree.c (profile_find_node_relation,
+ profile_find_node_subsection): Allow the returned value or
+ subsection field to be NULL (in case the caller isn't
+ interested in getting the returned value or subsection,
+ and only cares about getting the name).
+ (profile_delete_node_relation,
+ profile_delete_interior_node_relation): Removed these
+ functions and replaced it with profile_remove_node(),
+ which takes a boolean argument section_flag.
+ (profile_find_node_name): Removed this function. (This
+ was a Cygnus/Fusion special used by the now removed
+ profile_find_first_values() function.)
+
+ * test_profile.c: Added commands to test the new
+ profile_get_subsection_names() and
+ profile_get_relation_names() interfaces.
+
1998-08-06 Theodore Ts'o <tytso@rsts-11.mit.edu>
* prof_tree.c (profile_delete_node_relation): Fix bug where
prof_tree.o \
prof_file.o \
prof_parse.o \
+ prof_get.o \
prof_err.o \
prof_init.o
OBJS = prof_tree.$(OBJEXT) \
prof_file.$(OBJEXT) \
prof_parse.$(OBJEXT) \
+ prof_get.$(OBJEXT) \
prof_err.$(OBJEXT) \
prof_init.$(OBJEXT)
SRCS = $(srcdir)/prof_tree.c \
$(srcdir)/prof_file.c \
$(srcdir)/prof_parse.c \
+ $(srcdir)/prof_get.c \
prof_err.c \
$(srcdir)/prof_init.c
error_code PROF_BAD_NAMESET, "Bad nameset passed to query routine"
error_code PROF_NO_PROFILE, "No profile file open"
+#
+# generated by prof_file.c
+#
+error_code PROF_MAGIC_FILE, "Bad magic value in profile_file_t"
+
end
return ENOMEM;
}
strcpy(prf->filename, filename);
+ prf->magic = PROF_MAGIC_FILE;
retval = profile_update_file(prf);
if (retval) {
return errno;
if (st.st_mtime == prf->timestamp)
return 0;
- if (prf->root)
+ if (prf->root) {
profile_free_node(prf->root);
+ prf->root = 0;
+ }
+ if (prf->comment) {
+ free(prf->comment);
+ prf->comment = 0;
+ }
#else
/*
* If we don't have the stat() call, assume that our in-core
free(prf->filename);
if (prf->root)
profile_free_node(prf->root);
+ if (prf->comment)
+ free(prf->comment);
+ prf->magic = 0;
free(prf);
return 0;
--- /dev/null
+/*
+ * 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>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <errno.h>
+
+#include "prof_int.h"
+
+/*
+ * These functions --- init_list(), end_list(), and add_to_list() are
+ * internal functions used to build up a null-terminated char ** list
+ * of strings to be returned by functions like profile_get_values.
+ *
+ * The profile_string_list structure is used for internal booking
+ * purposes to build up the list, which is returned in *ret_list by
+ * the end_list() function.
+ *
+ * The publicly exported interface for freeing char** list is
+ * profile_free_list().
+ */
+
+struct profile_string_list {
+ char **list;
+ int num;
+ int max;
+};
+
+/*
+ * Initialize the string list abstraction.
+ */
+static errcode_t init_list(list)
+ struct profile_string_list *list;
+{
+ list->num = 0;
+ list->max = 10;
+ list->list = malloc(list->max * sizeof(char *));
+ if (list->list == 0)
+ return ENOMEM;
+ list->list[0] = 0;
+ return 0;
+}
+
+/*
+ * Free any memory left over in the string abstraction, returning the
+ * built up list in *ret_list if it is non-null.
+ */
+static void end_list(list, ret_list)
+ struct profile_string_list *list;
+ char ***ret_list;
+{
+ char **cp;
+
+ if (list == 0)
+ return;
+
+ if (ret_list) {
+ *ret_list = list->list;
+ return;
+ } else {
+ for (cp = list->list; *cp; cp++)
+ free(*cp);
+ free(list->list);
+ }
+ list->num = list->max = 0;
+ list->list = 0;
+}
+
+/*
+ * Add a string to the list.
+ */
+static errcode_t add_to_list(list, str)
+ struct profile_string_list *list;
+ const char *str;
+{
+ char *newstr, **newlist;
+ int newmax;
+
+ if (list->num+1 >= list->max) {
+ newmax = list->max + 10;
+ newlist = realloc(list->list, newmax * sizeof(char *));
+ if (newlist == 0)
+ return ENOMEM;
+ list->max = newmax;
+ list->list = newlist;
+ }
+ newstr = malloc(strlen(str)+1);
+ if (newstr == 0)
+ return ENOMEM;
+ strcpy(newstr, str);
+
+ list->list[list->num++] = newstr;
+ list->list[list->num] = 0;
+ return 0;
+}
+
+/*
+ * Return TRUE if the string is already a member of the list.
+ */
+static int is_list_member(list, str)
+ struct profile_string_list *list;
+ const char *str;
+{
+ char **cpp;
+
+ if (!list->list)
+ return 0;
+
+ for (cpp = list->list; *cpp; cpp++) {
+ if (!strcmp(*cpp, str))
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * This function frees a null-terminated list as returned by
+ * profile_get_values.
+ */
+KRB5_DLLIMP void KRB5_CALLCONV profile_free_list(list)
+ char **list;
+{
+ char **cp;
+
+ if (list == 0)
+ return;
+
+ for (cp = list; *cp; cp++)
+ free(*cp);
+ 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;
+ const char **names;
+ 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)
+ return retval;
+
+ init_list(&values);
+
+ state = 0;
+ do {
+ if ((retval = profile_find_node_relation(section, name,
+ &state, 0, &value)))
+ goto cleanup;
+ add_to_list(&values, value);
+ } while (state);
+
+ end_list(&values, ret_values);
+ return 0;
+
+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)
+ profile_t profile;
+ const char **names;
+ 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)
+ return retval;
+
+ state = 0;
+ if ((retval = profile_find_node_relation(section, name,
+ &state, 0, &value)))
+ return retval;
+
+ *ret_value = value;
+ return 0;
+}
+
+errcode_t profile_get_string(profile, name, subname, subsubname,
+ def_val, ret_string)
+ profile_t profile;
+ const char *name, *subname, *subsubname;
+ const char *def_val;
+ char **ret_string;
+{
+ const char *value;
+ errcode_t retval;
+ const char *names[4];
+
+ if (profile) {
+ names[0] = name;
+ names[1] = subname;
+ names[2] = subsubname;
+ names[3] = 0;
+ retval = profile_get_value(profile, names, &value);
+ if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION)
+ value = def_val;
+ else if (retval)
+ return retval;
+ } else
+ value = def_val;
+
+ if (value) {
+ *ret_string = malloc(strlen(value)+1);
+ if (*ret_string == 0)
+ return ENOMEM;
+ strcpy(*ret_string, value);
+ } else
+ *ret_string = 0;
+ return 0;
+}
+
+errcode_t profile_get_integer(profile, name, subname, subsubname,
+ def_val, ret_int)
+ profile_t profile;
+ const char *name, *subname, *subsubname;
+ int def_val;
+ int *ret_int;
+{
+ char *value;
+ errcode_t retval;
+ const char *names[4];
+
+ if (profile == 0) {
+ *ret_int = def_val;
+ return 0;
+ }
+
+ names[0] = name;
+ names[1] = subname;
+ names[2] = subsubname;
+ names[3] = 0;
+ retval = profile_get_value(profile, names, &value);
+ if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {
+ *ret_int = def_val;
+ return 0;
+ } else if (retval)
+ return retval;
+
+ *ret_int = atoi(value);
+ return 0;
+}
+
+/*
+ * This function will return the list of the names of subections in the
+ * under the specified section name.
+ */
+errcode_t profile_get_subsection_names(profile, names, ret_names)
+ profile_t profile;
+ const char **names;
+ char ***ret_names;
+{
+ prf_file_t file;
+ errcode_t retval;
+ char *name;
+ const char **cpp;
+ void *state;
+ struct profile_node *section;
+ struct profile_string_list values;
+
+ if (profile == 0)
+ return PROF_NO_PROFILE;
+
+ if (names == 0)
+ return PROF_BAD_NAMESET;
+
+ 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;
+}
+
+/*
+ * This function will return the list of the names of relations in the
+ * under the specified section name.
+ */
+errcode_t profile_get_relation_names(profile, names, ret_names)
+ profile_t profile;
+ const char **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)
+ return retval;
+
+ init_list(&values);
+
+ state = 0;
+ do {
+ retval = profile_find_node_relation(section, 0,
+ &state, &name, 0);
+ if (retval == PROF_NO_RELATION)
+ 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;
+}
+
+
+
const char **fn;
profile_t profile;
prf_file_t new_file, last = 0;
- errcode_t retval;
+ errcode_t retval = 0;
initialize_prof_error_table();
else
profile->first_file = new_file;
last = new_file;
- /* since we actually got something, don't loop again */
- /* (at least until we understand what multiple files mean) */
- break;
}
/* if the last file was missing, they all were, so report such */
if (retval == ENOENT) {
free(profile);
}
-struct string_list {
- char **list;
- int num;
- int max;
-};
-
-static errcode_t init_list(list)
- struct string_list *list;
-{
- list->num = 0;
- list->max = 10;
- list->list = malloc(list->max * sizeof(char *));
- if (list->list == 0)
- return ENOMEM;
- list->list[0] = 0;
- return 0;
-}
-
-static void free_list(list)
- struct string_list *list;
-{
- char **cp;
-
- for (cp = list->list; *cp; cp++)
- free(*cp);
- free(list->list);
- list->num = list->max = 0;
- list->list = 0;
-}
-
-static errcode_t add_to_list(list, str)
- struct string_list *list;
- const char *str;
-{
- char *newstr;
-
- if (list->num+1 >= list->max) {
- list->max += 5;
- list->list = realloc(list->list, list->max * sizeof(char *));
- if (list->list == 0)
- return ENOMEM;
- }
- newstr = malloc(strlen(str)+1);
- if (newstr == 0)
- return ENOMEM;
- strcpy(newstr, str);
-
- list->list[list->num++] = newstr;
- list->list[list->num] = 0;
- return 0;
-}
-
/*
- * XXX this version only works to get values from the first file.
- * To do more than that means we have to implement some "interesting"
- * code to do the section searching.
+ * Here begins the profile serialization functions.
*/
-KRB5_DLLIMP errcode_t KRB5_CALLCONV
-profile_get_values(profile, names, ret_values)
- profile_t profile;
- const char **names;
- char ***ret_values;
-{
- prf_file_t file;
- errcode_t retval;
- struct profile_node *section;
- void *state;
- char *value;
- struct string_list values;
- const char **cpp;
-
- if (profile == 0)
- return PROF_NO_PROFILE;
-
- if (names == 0 || names[0] == 0 || names[1] == 0)
- return PROF_BAD_NAMESET;
-
- init_list(&values);
-
- file = profile->first_file;
- retval = profile_update_file(file);
- if (retval)
- goto cleanup;
-
- section = file->root;
-
- for (cpp = names; cpp[1]; cpp++) {
- state = 0;
- retval = profile_find_node_subsection(section, *cpp,
- &state, 0, §ion);
- if (retval)
- goto cleanup;
- }
-
- state = 0;
- do {
- retval = profile_find_node_relation(section, *cpp, &state, 0, &value);
- if (retval)
- goto cleanup;
- add_to_list(&values, value);
- } while (state);
-
- *ret_values = values.list;
- return 0;
-cleanup:
- free_list(&values);
- return retval;
-}
-
-/*
- * XXX this version only works to get values from the first file.
- * To do more than that means we have to implement some "interesting"
- * code to do the section searching.
- */
-errcode_t profile_get_first_values(profile, names, ret_values)
- profile_t profile;
- const char **names;
- char ***ret_values;
-{
- prf_file_t file;
- errcode_t retval;
- struct profile_node *section;
- void *state;
- char *value;
- struct string_list values;
- char *secname;
-
- if (profile == 0)
- return PROF_NO_PROFILE;
-
- if (names == 0 || names[0] == 0)
- return PROF_BAD_NAMESET;
-
- init_list(&values);
-
- file = profile->first_file;
- retval = profile_update_file(file);
- if (retval)
- goto cleanup;
-
- section = file->root;
-
- state = 0;
- retval = profile_find_node_subsection(section, *names, &state, &secname, §ion);
-
- do {
- retval = profile_find_node_name(section, &state, &value);
- if (retval)
- goto cleanup;
- add_to_list(&values, value);
- } while (state);
-
- *ret_values = values.list;
- return 0;
-cleanup:
- free_list(&values);
- return retval;
-}
-
-/*
- * XXX this version only works to get values from the first file.
- */
-static errcode_t profile_get_value(profile, names, ret_value)
- profile_t profile;
- const char **names;
- char **ret_value;
-{
- prf_file_t file;
- errcode_t retval;
- struct profile_node *section;
- void *state;
- char *value;
- const char **cpp;
-
- if (names == 0 || names[0] == 0 || names[1] == 0)
- return PROF_BAD_NAMESET;
-
- file = profile->first_file;
- retval = profile_update_file(file);
- if (retval)
- goto cleanup;
-
- section = file->root;
-
- for (cpp = names; cpp[1]; cpp++) {
- state = 0;
- retval = profile_find_node_subsection(section, *cpp,
- &state, 0, §ion);
- if (retval)
- goto cleanup;
- }
-
- state = 0;
- retval = profile_find_node_relation(section, *cpp, &state, 0, &value);
- if (retval)
- goto cleanup;
-
- *ret_value = value;
- return 0;
-cleanup:
- return retval;
-}
-
-errcode_t profile_get_string(profile, name, subname, subsubname,
- def_val, ret_string)
- profile_t profile;
- const char *name, *subname, *subsubname;
- const char *def_val;
- char **ret_string;
-{
- const char *value;
- errcode_t retval;
- const char *names[4];
-
- if (profile) {
- names[0] = name;
- names[1] = subname;
- names[2] = subsubname;
- names[3] = 0;
- retval = profile_get_value(profile, names, &value);
- if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION)
- value = def_val;
- else if (retval)
- return retval;
- } else
- value = def_val;
-
- if (value) {
- *ret_string = malloc(strlen(value)+1);
- if (*ret_string == 0)
- return ENOMEM;
- strcpy(*ret_string, value);
- } else
- *ret_string = 0;
- return 0;
-}
-
-errcode_t profile_get_integer(profile, name, subname, subsubname,
- def_val, ret_int)
- profile_t profile;
- const char *name, *subname, *subsubname;
- int def_val;
- int *ret_int;
-{
- char *value;
- errcode_t retval;
- const char *names[4];
-
- if (profile == 0) {
- *ret_int = def_val;
- return 0;
- }
-
- names[0] = name;
- names[1] = subname;
- names[2] = subsubname;
- names[3] = 0;
- retval = profile_get_value(profile, names, &value);
- if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {
- *ret_int = def_val;
- return 0;
- } else if (retval)
- return retval;
-
- *ret_int = atoi(value);
- return 0;
-}
-
errcode_t profile_ser_size(unused, profile, sizep)
const char *unused;
profile_t profile;
size_t required;
prf_file_t pfp;
- /*
- * ARGH - We want to avoid having to include k5-int.h. We ASSuME that
- * krb5_int32 is 4 bytes in length.
- *
- * krb5_int32 for header
- * krb5_int32 for number of files.
- * krb5_int32 for trailer
- */
required = 3*sizeof(prof_int32);
for (pfp = profile->first_file; pfp; pfp = pfp->next) {
required += sizeof(prof_int32);
}
errcode_t profile_ser_internalize(unused, profilep, bufpp, remainp)
- const char *unused;
- profile_t *profilep;
- unsigned char **bufpp;
- size_t *remainp;
+ const char *unused;
+ profile_t *profilep;
+ unsigned char **bufpp;
+ size_t *remainp;
{
- errcode_t retval;
- unsigned char *bp;
- size_t remain;
- int i;
- prof_int32 fcount, tmp;
- char **flist;
-
- bp = *bufpp;
- remain = *remainp;
- retval = EINVAL;
-
- if (remain >= 12)
- (void) unpack_int32(&tmp, &bp, &remain);
- else
- tmp = 0;
- if (tmp == PROF_MAGIC_PROFILE) {
+ errcode_t retval;
+ unsigned char *bp;
+ size_t remain;
+ int i;
+ prof_int32 fcount, tmp;
+ char **flist = 0;
+
+ bp = *bufpp;
+ remain = *remainp;
+
+ if (remain >= 12)
+ (void) unpack_int32(&tmp, &bp, &remain);
+ else
+ tmp = 0;
+
+ if (tmp != PROF_MAGIC_PROFILE) {
+ retval = EINVAL;
+ goto cleanup;
+ }
+
(void) unpack_int32(&fcount, &bp, &remain);
retval = ENOMEM;
- if (!fcount ||
- (flist = (char **) malloc(sizeof(char *) * (fcount + 1)))) {
- memset(flist, 0, sizeof(char *) * (fcount+1));
- for (i=0; i<fcount; i++) {
+
+ flist = (char **) malloc(sizeof(char *) * (fcount + 1));
+ if (!flist)
+ goto cleanup;
+
+ memset(flist, 0, sizeof(char *) * (fcount+1));
+ for (i=0; i<fcount; i++) {
if (!unpack_int32(&tmp, &bp, &remain)) {
- if ((flist[i] = (char *) malloc((size_t) (tmp+1)))) {
+ flist[i] = (char *) malloc((size_t) (tmp+1));
+ if (!flist[i])
+ goto cleanup;
memcpy(flist[i], bp, (size_t) tmp);
flist[i][tmp] = '\0';
bp += tmp;
remain -= (size_t) tmp;
- }
- else
- break;
}
- else
- break;
- }
- if ((i == fcount) &&
- !unpack_int32(&tmp, &bp, &remain) &&
- (tmp == PROF_MAGIC_PROFILE))
- retval = profile_init((const char **)flist, profilep);
+ }
- if (!retval) {
- *bufpp = bp;
- *remainp = remain;
- }
+ if (unpack_int32(&tmp, &bp, &remain) ||
+ (tmp != PROF_MAGIC_PROFILE)) {
+ retval = EINVAL;
+ goto cleanup;
+ }
- for (i=0; i<fcount; i++) {
- if (flist[i])
- free(flist[i]);
- }
- free(flist);
+ if ((retval = profile_init((const char **)flist, profilep)))
+ goto cleanup;
+
+ *bufpp = bp;
+ *remainp = remain;
+
+cleanup:
+ if (flist) {
+ for (i=0; i<fcount; i++) {
+ if (flist[i])
+ free(flist[i]);
+ }
+ free(flist);
}
- }
- return(retval);
+ return(retval);
}
-
typedef struct _profile_t *profile_t;
-/*
- * This structure defines the profile_section_t object, which is
- * returned to the user when a section is searched.
- */
-struct _profile_section_t {
- prf_magic_t magic;
- int top_lvl:1, top_lvl_search:1;
- char *name;
- void *state;
- struct profile_node *parent, *sect;
- profile_t profile;
- prf_file_t file_ptr;
-};
-
-typedef struct _profile_section_t *profile_section_t;
-
-errcode_t profile_get
- PROTOTYPE((const char *filename, prf_file_t *ret_prof));
-
-errcode_t profile_update
- PROTOTYPE((prf_file_t profile));
+/* profile_parse.c */
errcode_t profile_parse_file
PROTOTYPE((FILE *f, struct profile_node **root));
void profile_release
PROTOTYPE ((profile_t profile));
+/* prof_get.c */
+
+KRB5_DLLIMP void KRB5_CALLCONV profile_free_list
+ PROTOTYPE ((char **list));
KRB5_DLLIMP errcode_t KRB5_CALLCONV profile_get_values
- PROTOTYPE ((profile_t profile, const char **names, char ***ret_values));
+ PROTOTYPE ((profile_t profile, const char **names,
+ char ***ret_values));
+
errcode_t profile_get_string
PROTOTYPE((profile_t profile, const char *name, const char *subname,
const char *subsubname, const char *def_val,
PROTOTYPE((profile_t profile, const char *name, const char *subname,
const char *subsubname, int def_val,
int *ret_default));
+
+errcode_t profile_get_relation_names
+ PROTOTYPE((profile_t profile, const char **names, char ***ret_names));
+
+errcode_t profile_get_subsection_names
+ PROTOTYPE((profile_t profile, const char **names, char ***ret_names));
+
fputc('"', f);
return;
}
- while (ch = *str++) {
+ while ((ch = *str++)) {
switch (ch) {
case '\\':
fputs("\\\\", f);
+++ /dev/null
-/*
- * prof_section.c --- routines that manipulate the profile_section_t
- * object
- *
- * XXX this file is still under construction.
- */
-
-#include <stdio.h>
-#include <string.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#include <errno.h>
-
-#include "prof_int.h"
-
-/*
- * This routine frees a profile_section
- */
-void profile_free_section(sect)
- profile_section_t sect;
-{
- if (sect->name)
- free(sect->name);
- sect->magic = 0;
- free(sect);
-}
-
-/*
- * This routine creates a profile_section from its parent. If the
- * parent is NULL, then a top-level profile section is created.
- *
- * Top-level profile sections are different from normal
- * profile_sections in that top-level sections are agregated across
- * multiple files, where as subsections are not.
- */
-errcode_t profile_get_subsection(profile, parent, name, ret_name,
- ret_section)
- profile_t profile;
- profile_section_t parent;
- const char * name;
- char ** ret_name;
- profile_section_t *ret_section;
-{
- profile_section_t section;
- prf_file_t file;
- errcode_t retval;
-
- section = malloc(sizeof(struct _profile_section_t));
- if (section == 0)
- return ENOMEM;
- memset(section, 0, sizeof(struct _profile_section_t));
- section->magic = PROF_MAGIC_SECTION;
- section->name = malloc(strlen(name)+1);
- if (section->name == 0) {
- free(section);
- return ENOMEM;
- }
- strcpy(section->name, name);
- section->file_ptr = file = profile->first_file;
- section->profile = profile;
-
- if (parent == 0) {
- /*
- * If parent is NULL, then we are creating a
- * top-level section which hangs off the root.
- *
- * We make sure that the section exists in least one
- * file.
- */
- section->top_lvl = 1;
- if (name == 0)
- return PROF_TOPSECTION_ITER_NOSUPP;
- while (file) {
- retval = profile_find_node_subsection(file->root,
- name, §ion->state,
- ret_name, §ion->sect);
- file = file->next;
- if (retval == 0)
- break;
- if (retval == PROF_NO_SECTION)
- continue;
- profile_free_section(section);
- return retval;
- }
- if (section->sect == 0 && file == 0) {
- profile_free_section(section);
- return PROF_NO_SECTION;
- }
- *ret_section = section;
- return 0;
- }
-
-
- section->top_lvl = 0;
- if (parent->top_lvl) {
- section->top_lvl_search = 1;
-
- } else {
- section->top_lvl_search = 0;
- if (parent->sect == 0) {
- profile_free_section(section);
- return PROF_INVALID_SECTION;
- }
- section->parent = parent->sect;
- retval = profile_find_node_subsection(parent->sect,
- name, §ion->state, ret_name, §ion->sect);
- if (retval) {
- profile_free_section(section);
- return retval;
- }
- }
- *ret_section = section;
- return 0;
-}
-
-errcode_t profile_next_section(section, ret_name)
- profile_section_t section;
- char **ret_name;
-{
- prf_file_t file;
- errcode_t retval;
-
- if (section->top_lvl)
- return PROF_END_OF_SECTIONS;
- else {
- if (section->sect == 0)
- return PROF_INVALID_SECTION;
- retval = profile_find_node_subsection(section->parent,
- section->name, §ion->state, ret_name, §ion->sect);
- if (retval == PROF_NO_SECTION)
- retval = PROF_END_OF_SECTIONS;
- return retval;
- }
-}
-
-errcode_t profile_get_relation(section, name, ret_values)
- profile_section_t section;
- const char *name;
- char ***ret_values;
-{
- prf_file_t file;
- char **values;
- int num_values;
- int max_values;
- char *value;
- errcode_t retval;
-
-
- max_values = 10;
- values = malloc(sizeof(char *) * max_values);
-
- if (section->top_lvl) {
- for (file = section->profile->first_file; file;
- file = file->next) {
- retval = profile_find_node_relation(file->root,
- section->name, §ion->state, 0, &value);
- if (retval)
- continue;
-
- }
- } else {
- if (section->sect == 0)
- return PROF_INVALID_SECTION;
- }
- return 0;
-}
-
-
-
free(node->name);
if (node->value)
free(node->value);
+
for (child=node->first_child; child; child = next) {
next = child->next;
profile_free_node(child);
while (p) {
if (((name == 0) || (strcmp(p->name, name) == 0)) &&
p->value) {
- *value = p->value;
+ if (value)
+ *value = p->value;
if (ret_name)
*ret_name = p->name;
break;
while (p) {
if (((name == 0) || (strcmp(p->name, name) == 0)) &&
(p->value == 0)) {
- *subsection = p;
+ if (subsection)
+ *subsection = p;
if (ret_name)
*ret_name = p->name;
break;
}
/*
- * This function deletes a relation from a section. Subsections are
- * not deleted; if those need to be deleted, they must be done so manually.
+ * This function deletes a subsection or relation from a section,
+ * depending whether on the section flag is non-zero or not.
*/
-errcode_t profile_delete_node_relation(section, name)
+errcode_t profile_remove_node(section, name, section_flag)
struct profile_node *section;
const char *name;
+ int section_flag;
{
struct profile_node *p, *next;
if (p == 0)
return PROF_NO_RELATION;
/*
- * Now we start deleting the relations... if we find a
- * subsection with the same name, delete it and keep going.
+ * Now we start deleting the relations or subsection.
*/
while (p && (strcmp(p->name, name) == 0)) {
- if (p->value == 0) {
+ /*
+ * Skip if it is not the correct type.
+ */
+ if ((section_flag && p->value) ||
+ (!section_flag && !p->value)) {
p = p->next;
continue;
}
return 0;
}
-/*
- * This function deletes a relation from a section. Subsections are
- * not deleted; if those need to be deleted, they must be done so manually.
- * And sections need not have a value to be delete, this is to enable
- * deleting sections which are valueless headers for subsections.
- */
-errcode_t profile_delete_interior_node_relation(section, name)
- struct profile_node *section;
- const char *name;
-{
- struct profile_node *p, *next;
-
- for (p = section->first_child; p; p = p->next) {
- if ((strcmp(p->name, name) == 0))
- break;
- }
- if (p == 0)
- return PROF_NO_RELATION;
- /*
- * Now we start deleting the relations... if we find a
- * subsection with the same name, delete it and keep going.
- */
- while (p && (strcmp(p->name, name) == 0)) {
- if (p->prev)
- p->prev->next = p->next;
- else
- section->first_child = p->next;
- next = p->next;
- if (p->next)
- p->next->prev = p;
- profile_free_node(p);
- p = next;
- }
- return 0;
-}
-
/*
* This function returns the parent of a particular node.
*/
*parent = section->parent;
return 0;
}
-
-
-/*
- * Taking the state from another find function, give the name of the
- * section and move to the next section. In this case, state can't be null
- */
-errcode_t profile_find_node_name(section, state, ret_name)
- struct profile_node *section;
- void **state;
- char **ret_name;
-{
- struct profile_node *p;
-
- CHECK_MAGIC(section);
- p = *state;
- if (p) {
- CHECK_MAGIC(p);
- } else
- p = section->first_child;
-
- if (p == 0) {
- *state = 0;
- return PROF_NO_SECTION;
- }
-/* give the name back */
- *ret_name = p->name;
- p = p->next;
-
- *state = p;
- return 0;
-}
KRB5_DLLIMP long KRB5_CALLCONV profile_get_values
PROTOTYPE ((profile_t profile, const char **names, char ***ret_values));
+
+KRB5_DLLIMP void KRB5_CALLCONV profile_free_list
+ PROTOTYPE ((char **list));
+
long profile_get_string
PROTOTYPE((profile_t profile, const char *name, const char *subname,
const char *subsubname, const char *def_val,
const char *subsubname, int def_val,
int *ret_default));
+long profile_get_relation_names
+ PROTOTYPE((profile_t profile, const char **names, char ***ret_names));
+
+long profile_get_subsection_names
+ PROTOTYPE((profile_t profile, const char **names, char ***ret_names));
+
#endif /* _KRB5_PROFILE_H */
}
#endif
+const char *program_name = "test_profile";
+
int main(argc, argv)
int argc;
char **argv;
{
profile_t profile;
long retval;
- const char *filenames[2];
char **values, **cpp;
const char **names;
+ char *cmd;
- filenames[0] = argv[1];
- filenames[1] = 0;
-
- if (argc < 2) {
- fprintf(stderr, "Usage: %s filename argset\n", argv[0]);
+ if (argc < 3) {
+ fprintf(stderr, "Usage: %s filename cmd argset\n", program_name);
exit(1);
}
initialize_prof_error_table();
- retval = profile_init(filenames, &profile);
+ retval = profile_init_path(argv[1], &profile);
if (retval) {
- com_err(argv[0], retval, "while initializing profile");
+ com_err(program_name, retval, "while initializing profile");
exit(1);
}
- names = (const char **) argv+2;
- retval = profile_get_values(profile, names, &values);
+ cmd = *(argv+2);
+ names = (const char **) argv+3;
+ if (!strcmp(cmd, "query")) {
+ retval = profile_get_values(profile, names, &values);
+ } else if (!strcmp(cmd, "list_sections")) {
+ retval = profile_get_subsection_names(profile, names, &values);
+ } else if (!strcmp(cmd, "list_relations")) {
+ retval = profile_get_relation_names(profile, names, &values);
+ } else {
+ fprintf(stderr, "Invalid command.\n");
+ exit(1);
+ }
if (retval) {
- com_err(argv[0], retval, "while getting values");
- exit(1);
+ com_err(argv[0], retval, "while getting values");
+ exit(1);
}
for (cpp = values; *cpp; cpp++) {
printf("%s\n", *cpp);
free(values);
profile_release(profile);
- return 0;
-
+ return 0;
}