Tue Mar 2 18:55:50 1999 Theodore Y. Ts'o <tytso@mit.edu>
+ * test_profile.c: Added ability to test profile set functions, and
+ in a batch mode.
+
+ * prof_init.c (profile_flush): Add new public function for
+ flushing changes made to the profile.
+
+ * prof_parse.c (profile_write_tree_file): Add official internal
+ function for flushing out a profile tree to a FILE *.
+
+ * configure.in, prof_file.c (rw_access): Add new function which
+ checks to see whether we have read/write access, and
+ emulate this for losing non-POSIX OS's.
+
+ * prof_file.c (profile_flush_file): Add support for writing
+ modified profile file's. Call profile_flush_file from
+ profile_close_file().
+
* prof_tree.c: Add new functions profile_get_node_name,
profile_get_node_value, profile_find_node,
profile_remove_node, profile_set_relation_value,
test_parse: test_parse.$(OBJEXT) $(OBJS) $(DEPLIBS)
$(CC_LINK) -o test_parse test_parse.$(OBJEXT) $(OBJS) $(MLIBS)
-test_profile: test_profile.$(OBJEXT) $(OBJS) $(DEPLIBS)
- $(CC_LINK) -o test_profile test_profile.$(OBJEXT) $(OBJS) $(MLIBS)
+test_profile: test_profile.$(OBJEXT) argv_parse.$(OBJEXT) $(OBJS) $(DEPLIBS)
+ $(CC_LINK) -o test_profile test_profile.$(OBJEXT) \
+ argv_parse.$(OBJEXT) $(OBJS) $(MLIBS)
test_parse.exe:
$(CC) $(CFLAGS2) -o test_parse.exe test_parse.c \
--- /dev/null
+/*
+ * argv_parse.c --- utility function for parsing a string into a
+ * argc, argv array.
+ *
+ * This file defines a function argv_parse() which parsing a
+ * passed-in string, handling double quotes and backslashes, and
+ * creates an allocated argv vector which can be freed using the
+ * argv_free() function.
+ *
+ * See argv_parse.h for the formal definition of the functions.
+ *
+ * Copyright 1999 by Theodore Ts'o.
+ *
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose with or without fee is hereby granted, provided that
+ * the above copyright notice and this permission notice appear in all
+ * copies. THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE
+ * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (Isn't
+ * it sick that the U.S. culture of lawsuit-happy lawyers requires
+ * this kind of disclaimer?)
+ *
+ * Version 1.1, modified 2/27/1999
+ */
+
+#include <stdlib.h>
+#include <ctype.h>
+#include "argv_parse.h"
+
+#define STATE_WHITESPACE 1
+#define STATE_TOKEN 2
+#define STATE_QUOTED 3
+
+/*
+ * Returns 0 on success, -1 on failure.
+ */
+int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv)
+{
+ int argc = 0, max_argc = 0;
+ char **argv, **new_argv, *buf, ch;
+ char *cp = 0, *outcp = 0;
+ int state = STATE_WHITESPACE;
+
+ buf = malloc(strlen(in_buf)+1);
+ if (!buf)
+ return -1;
+
+ max_argc = 0; argc = 0; argv = 0;
+ outcp = buf;
+ for (cp = in_buf; (ch = *cp); cp++) {
+ if (state == STATE_WHITESPACE) {
+ if (isspace(ch))
+ continue;
+ /* Not whitespace, so start a new token */
+ state = STATE_TOKEN;
+ if (argc >= max_argc) {
+ max_argc += 3;
+ new_argv = realloc(argv,
+ (max_argc+1)*sizeof(char *));
+ if (!new_argv) {
+ if (argv) free(argv);
+ free(buf);
+ return -1;
+ }
+ argv = new_argv;
+ }
+ argv[argc++] = outcp;
+ }
+ if (state == STATE_QUOTED) {
+ if (ch == '"')
+ state = STATE_TOKEN;
+ else
+ *outcp++ = ch;
+ continue;
+ }
+ /* Must be processing characters in a word */
+ if (isspace(ch)) {
+ /*
+ * Terminate the current word and start
+ * looking for the beginning of the next word.
+ */
+ *outcp++ = 0;
+ state = STATE_WHITESPACE;
+ continue;
+ }
+ if (ch == '"') {
+ state = STATE_QUOTED;
+ continue;
+ }
+ if (ch == '\\') {
+ ch = *++cp;
+ switch (ch) {
+ case '\0':
+ ch = '\\'; cp--; break;
+ case 'n':
+ ch = '\n'; break;
+ case 't':
+ ch = '\t'; break;
+ case 'b':
+ ch = '\b'; break;
+ }
+ }
+ *outcp++ = ch;
+ }
+ if (state != STATE_WHITESPACE)
+ *outcp++ = '\0';
+ if (argv == 0) {
+ argv = malloc(sizeof(char *));
+ free(buf);
+ }
+ argv[argc] = 0;
+ if (ret_argc)
+ *ret_argc = argc;
+ if (ret_argv)
+ *ret_argv = argv;
+ return 0;
+}
+
+void argv_free(char **argv)
+{
+ if (*argv)
+ free(*argv);
+ free(argv);
+}
+
+#ifdef DEBUG
+/*
+ * For debugging
+ */
+
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ int ac, ret;
+ char **av, **cpp;
+ char buf[256];
+
+ while (!feof(stdin)) {
+ if (fgets(buf, sizeof(buf), stdin) == NULL)
+ break;
+ ret = argv_parse(buf, &ac, &av);
+ if (ret != 0) {
+ printf("Argv_parse returned %d!\n", ret);
+ continue;
+ }
+ printf("Argv_parse returned %d arguments...\n", ac);
+ for (cpp = av; *cpp; cpp++) {
+ if (cpp != av)
+ printf(", ");
+ printf("'%s'", *cpp);
+ }
+ printf("\n");
+ argv_free(av);
+ }
+ exit(0);
+}
+#endif /* DEBUG */
--- /dev/null
+/*
+ * argv_parse.h --- header file for the argv parser.
+ *
+ * This file defines the interface for the functions argv_parse() and
+ * argv_free().
+ *
+ ***********************************************************************
+ * int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv)
+ *
+ * This function takes as its first argument a string which it will
+ * parse into an argv argument vector, with each white-space separated
+ * word placed into its own slot in the argv. This function handles
+ * double quotes and backslashes so that the parsed words can contain
+ * special characters. The count of the number words found in the
+ * parsed string, as well as the argument vector, are returned into
+ * ret_argc and ret_argv, respectively.
+ ***********************************************************************
+ * extern void argv_free(char **argv);
+ *
+ * This function frees the argument vector created by argv_parse().
+ ***********************************************************************
+ *
+ * Copyright 1999 by Theodore Ts'o.
+ *
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose with or without fee is hereby granted, provided that
+ * the above copyright notice and this permission notice appear in all
+ * copies. THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE
+ * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (Isn't
+ * it sick that the U.S. culture of lawsuit-happy lawyers requires
+ * this kind of disclaimer?)
+ *
+ * Version 1.1, modified 2/27/1999
+ */
+
+extern int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv);
+extern void argv_free(char **argv);
AC_CHECK_SIZEOF(int)
AC_CHECK_SIZEOF(long)
AC_CHECK_HEADERS(unistd.h stdlib.h)
-AC_HAVE_FUNCS(stat)
+AC_HAVE_FUNCS(stat access)
AC_PROG_AWK
KRB5_BUILD_LIBOBJS
KRB5_BUILD_PROGRAM
+[libdefaults]
+ default_realm = ATHENA.MIT.EDU
+ default_tgs_enctypes = des-cbc-crc
+ default_tkt_enctypes = des-cbc-crc
+ krb4_config = /etc/athena/krb.conf
+ krb4_realms = /etc/athena/krb.realms
+ default_keytab_name = FILE:/etc/krb5.keytab
+ kdc_timesync = 1
+ ccache_type = 4
+
[realms]
ATHENA.MIT.EDU = {
- kdc = KERBEROS.MIT.EDU:88
- kdc = KERBEROS-1.MIT.EDU:88
- admin_server = KERBEROS.MIT.EDU
+# kdc = kerberos-2000.mit.edu
+ kdc = kerberos.mit.edu:88
+ kdc = kerberos-1.mit.edu:88
+ kdc = kerberos-2.mit.edu:88
+ kdc = kerberos-3.mit.edu:88
+ admin_server = kerberos.mit.edu
+ default_domain = mit.edu
+ }
+ MEDIA-LAB.MIT.EDU = {
+ kdc = kerberos.media.mit.edu
+ admin_server = kerberos.media.mit.edu
+ }
+ ZONE.MIT.EDU = {
+ kdc = casio.mit.edu
+ kdc = seiko.mit.edu
+ admin_server = casio.mit.edu
+ }
+ MOOF.MIT.EDU = {
+ kdc = three-headed-dogcow.mit.edu:88
+ kdc = three-headed-dogcow-1.mit.edu:88
+ admin_server = three-headed-dogcow.mit.edu
+ }
+ CYGNUS.COM = {
+ kdc = KERBEROS-1.CYGNUS.COM
+ kdc = KERBEROS.CYGNUS.COM
+ admin_server = KERBEROS.CYGNUS.COM
+ }
+ GREY17.ORG = {
+ kdc = kerberos.grey17.org
+ admin_server = kerberos.grey17.org
+ }
+ IHTFP.ORG = {
+ kdc = kerberos.ihtfp.org
+ admin_server = kerberos.ihtfp.org
}
-[kdc]
- port = 88
+[domain_realm]
+ .mit.edu = ATHENA.MIT.EDU
+ mit.edu = ATHENA.MIT.EDU
+ .media.mit.edu = MEDIA-LAB.MIT.EDU
+ media.mit.edu = MEDIA-LAB.MIT.EDU
-[libdefaults]
- ticket_lifetime = 10 hours
+[login]
+ krb4_convert = true
+ krb4_get_tickets = true
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
#include <string.h>
#include "prof_int.h"
#if defined(_MSDOS) || defined(_WIN32)
+#include <io.h>
+#define HAVE_STAT
#define stat _stat
#endif
+static int rw_access(filename)
+ const char *filename;
+{
+#ifdef HAVE_ACCESS
+ if (access(filename, W_OK) == 0)
+ return 1;
+ else
+ return 0;
+#else
+ /*
+ * We're on a substandard OS that doesn't support access. So
+ * we kludge a test using stdio routines, and hope fopen
+ * checks the r/w permissions.
+ */
+ FILE *f;
+
+ f = fopen(filename, "r+");
+ if (f) {
+ fclose(f);
+ return 1;
+ }
+ return 0;
+#endif
+}
+
errcode_t profile_open_file(filename, ret_prof)
const char *filename;
prf_file_t *ret_prof;
if (f == NULL)
return errno;
prf->upd_serial++;
+ prf->flags = 0;
+ if (rw_access(prf->filename))
+ prf->flags |= PROFILE_FILE_RW;
retval = profile_parse_file(f, &prf->root);
fclose(f);
if (retval)
return 0;
}
+errcode_t profile_flush_file(prf)
+ prf_file_t prf;
+{
+ FILE *f;
+ char *new_name = 0, *old_name = 0;
+ errcode_t retval = 0;
+
+ if (!prf || prf->magic != PROF_MAGIC_FILE)
+ return PROF_MAGIC_FILE;
+
+ if ((prf->flags & PROFILE_FILE_DIRTY) == 0)
+ return 0;
+
+ retval = ENOMEM;
+ new_name = malloc(strlen(prf->filename) + 5);
+ if (!new_name)
+ goto errout;
+ old_name = malloc(strlen(prf->filename) + 5);
+ if (!old_name)
+ goto errout;
+
+ sprintf(new_name, "%s.$$$", prf->filename);
+ sprintf(old_name, "%s.bak", prf->filename);
+
+ f = fopen(new_name, "w");
+ if (!f) {
+ retval = errno;
+ goto errout;
+ }
+
+ profile_write_tree_file(prf->root, f);
+ if (fclose(f) != 0) {
+ retval = errno;
+ goto errout;
+ }
+
+ unlink(old_name);
+ if (rename(prf->filename, old_name)) {
+ retval = errno;
+ goto errout;
+ }
+ if (rename(new_name, prf->filename)) {
+ retval = errno;
+ rename(old_name, prf->filename); /* back out... */
+ goto errout;
+ }
+
+ prf->flags = 0;
+ if (rw_access(prf->filename))
+ prf->flags |= PROFILE_FILE_RW;
+ retval = 0;
+
+errout:
+ if (new_name)
+ free(new_name);
+ if (old_name)
+ free(old_name);
+ return retval;
+}
+
+
errcode_t profile_close_file(prf)
prf_file_t prf;
{
+ errcode_t retval;
+
+ retval = profile_flush_file(prf);
+ if (retval)
+ return retval;
if (prf->filename)
free(prf->filename);
if (prf->root)
return retval;
}
+KRB5_DLLIMP errcode_t KRB5_CALLCONV
+profile_flush(profile)
+ profile_t profile;
+{
+ if (!profile || profile->magic != PROF_MAGIC_PROFILE)
+ return PROF_MAGIC_PROFILE;
+
+ if (profile->first_file)
+ return profile_flush_file(profile->first_file);
+
+ return 0;
+}
+
KRB5_DLLIMP void KRB5_CALLCONV
profile_release(profile)
errcode_t profile_parse_file
PROTOTYPE((FILE *f, struct profile_node **root));
+errcode_t profile_write_tree_file
+ PROTOTYPE((struct profile_node *root, FILE *dstfile));
+
+
/* prof_tree.c */
void profile_free_node
errcode_t profile_update_file
PROTOTYPE ((prf_file_t profile));
+errcode_t profile_flush_file
+ PROTOTYPE ((prf_file_t profile));
+
errcode_t profile_close_file
PROTOTYPE ((prf_file_t profile));
#define EOL "\n"
#endif
-#if !defined(_MSDOS) && !defined(_WIN32)
-
-void dump_profile(root, level)
- struct profile_node *root;
- int level;
-{
- int i;
- struct profile_node *p;
- void *iter;
- long retval;
- char *name, *value;
-
- iter = 0;
- do {
- retval = profile_find_node_relation(root, 0, &iter,
- &name, &value);
- if (retval)
- break;
- for (i=0; i < level; i++)
- printf(" ");
- if (need_double_quotes(value)) {
- fputs(name, stdout);
- fputs(" = ", stdout);
- output_quoted_string(value, stdout);
- fputs(EOL, stdout);
- } else
- printf("%s = '%s'%s", name, value, EOL);
- } while (iter != 0);
-
- iter = 0;
- do {
- retval = profile_find_node_subsection(root, 0, &iter,
- &name, &p);
- if (retval)
- break;
- for (i=0; i < level; i++)
- printf(" ");
- printf("[%s]%s", name, EOL);
- dump_profile(p, level+1);
- } while (iter != 0);
-}
-#endif /* !_MSDOS && !_WIN32 */
-
-
-void dump_profile_to_file(root, level, dstfile)
+static void dump_profile_to_file(root, level, dstfile)
struct profile_node *root;
int level;
FILE *dstfile;
}
} while (iter != 0);
}
+
+errcode_t profile_write_tree_file(root, dstfile)
+ struct profile_node *root;
+ FILE *dstfile;
+{
+ dump_profile_to_file(root, 0, dstfile);
+ return 0;
+}
CHECK_MAGIC(node);
- if (node->value)
+ if (!node->value)
return PROF_SET_SECTION_VALUE;
cp = malloc(strlen(new_value)+1);
}
/*
- * OK, let's detach the node
+ * If we need to move the node, do it now.
*/
- if (node->prev)
- node->prev->next = node->next;
- else
- node->parent->first_child = node->next;
-
- if (node->next)
- node->next->prev = node->prev;
+ if ((p != node) && (last != node)) {
+ /*
+ * OK, let's detach the node
+ */
+ if (node->prev)
+ node->prev->next = node->next;
+ else
+ node->parent->first_child = node->next;
+ if (node->next)
+ node->next->prev = node->prev;
- /*
- * Now let's reattach it in the right place.
- */
- if (p)
- p->prev = node;
- if (last)
- last->next = node;
- else
- node->parent->first_child = node;
+ /*
+ * Now let's reattach it in the right place.
+ */
+ if (p)
+ p->prev = node;
+ if (last)
+ last->next = node;
+ else
+ node->parent->first_child = node;
+ node->next = p;
+ node->prev = last;
+ }
free(node->name);
node->name = new_string;
KRB5_DLLIMP long KRB5_CALLCONV profile_init_path
PROTOTYPE ((const char *filepath, profile_t *ret_profile));
+KRB5_DLLIMP errcode_t KRB5_CALLCONV profile_flush
+ PROTOTYPE ((profile_t profile));
+
KRB5_DLLIMP void KRB5_CALLCONV profile_release
PROTOTYPE ((profile_t profile));
fclose(f);
printf("\n\nDebugging dump.\n");
-#if 0
- dump_profile(root, 0);
-#else
- dump_profile_to_file(root, 0, stdout);
-#endif
-
+ profile_write_tree_file(root, stdout);
+
retval = profile_verify_node(root);
if (retval) {
printf("profile_verify_node reported an error: %s\n",
#endif
#include "prof_int.h"
+#include "argv_parse.h"
#ifndef _MSDOS
#include "com_err.h"
#else
const char *program_name = "test_profile";
+#define PRINT_VALUE 1
+#define PRINT_VALUES 2
+
+static void do_batchmode(profile)
+ profile_t profile;
+{
+ errcode_t retval;
+ int argc, ret;
+ char **argv, **values, **cpp;
+ char buf[256];
+ const char **names, *value;
+ char *cmd;
+ int print_status;
+
+ while (!feof(stdin)) {
+ if (fgets(buf, sizeof(buf), stdin) == NULL)
+ break;
+ printf(">%s", buf);
+ ret = argv_parse(buf, &argc, &argv);
+ if (ret != 0) {
+ printf("Argv_parse returned %d!\n", ret);
+ continue;
+ }
+ cmd = *(argv);
+ names = (const char **) argv + 1;
+ print_status = 0;
+ retval = 0;
+ if (cmd == 0) {
+ argv_free(argv);
+ continue;
+ }
+ if (!strcmp(cmd, "query")) {
+ retval = profile_get_values(profile, names, &values);
+ print_status = PRINT_VALUES;
+ } else if (!strcmp(cmd, "query1")) {
+ retval = profile_get_value(profile, names, &value);
+ print_status = PRINT_VALUE;
+ } else if (!strcmp(cmd, "list_sections")) {
+ retval = profile_get_subsection_names(profile, names,
+ &values);
+ print_status = PRINT_VALUES;
+ } else if (!strcmp(cmd, "list_relations")) {
+ retval = profile_get_relation_names(profile, names,
+ &values);
+ print_status = PRINT_VALUES;
+ } else if (!strcmp(cmd, "dump")) {
+ retval = profile_write_tree_file
+ (profile->first_file->root, stdout);
+ } else if (!strcmp(cmd, "clear")) {
+ retval = profile_clear_relation(profile, names);
+ } else if (!strcmp(cmd, "update")) {
+ retval = profile_update_relation(profile, names+2,
+ *names, *(names+1));
+ } else if (!strcmp(cmd, "verify")) {
+ retval = profile_verify_node
+ (profile->first_file->root);
+ } else if (!strcmp(cmd, "rename_section")) {
+ retval = profile_rename_section(profile, names+1,
+ *names);
+ } else if (!strcmp(cmd, "add")) {
+ retval = profile_add_relation(profile, names+1,
+ *names);
+ } else if (!strcmp(cmd, "flush")) {
+ retval = profile_flush(profile);
+ } else {
+ printf("Invalid command.\n");
+ }
+ if (retval) {
+ com_err(cmd, retval, "");
+ print_status = 0;
+ }
+ switch (print_status) {
+ case PRINT_VALUE:
+ printf("%s\n", value);
+ break;
+ case PRINT_VALUES:
+ for (cpp = values; *cpp; cpp++)
+ printf("%s\n", *cpp);
+ profile_free_list(values);
+ break;
+ }
+ printf("\n");
+ argv_free(argv);
+ }
+ profile_release(profile);
+ exit(0);
+
+}
+
+
int main(argc, argv)
int argc;
char **argv;
char *cmd;
int print_value = 0;
- if (argc < 3) {
- fprintf(stderr, "Usage: %s filename cmd argset\n", program_name);
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s filename [cmd argset]\n", program_name);
exit(1);
}
}
cmd = *(argv+2);
names = (const char **) argv+3;
+ if (!cmd || !strcmp(cmd, "batch"))
+ do_batchmode(profile);
if (!strcmp(cmd, "query")) {
retval = profile_get_values(profile, names, &values);
} else if (!strcmp(cmd, "query1")) {