better config file handling
authorFelix Fietkau <nbd@openwrt.org>
Sun, 20 Jan 2008 15:10:32 +0000 (16:10 +0100)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 20 Jan 2008 15:10:32 +0000 (16:10 +0100)
Makefile
libuci.c
libuci.h [deleted file]
parse.c
test.c
uci.h [new file with mode: 0644]

index bf194d1..b33f6fa 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -5,8 +5,8 @@ all: parsetest
 parsetest: libuci.o test.o
        $(CC) $(CFLAGS) -o $@ $^
 
-libuci.o: libuci.c parse.c libuci.h list.c err.h
-test.o: test.c libuci.h
+libuci.o: libuci.c parse.c uci.h list.c err.h
+test.o: test.c uci.h
 
 clean:
        rm -f parsetest *.o
index 4dfffff..262ca69 100644 (file)
--- a/libuci.c
+++ b/libuci.c
@@ -21,7 +21,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
-#include "libuci.h"
+#include "uci.h"
 
 #define DEBUG
 #include "err.h"
@@ -31,6 +31,7 @@ static const char *uci_errstr[] = {
        [UCI_ERR_MEM] =      "Out of memory",
        [UCI_ERR_INVAL] =    "Invalid argument",
        [UCI_ERR_NOTFOUND] = "Entry not found",
+       [UCI_ERR_IO] =       "I/O error",
        [UCI_ERR_PARSE] =    "Parse error",
        [UCI_ERR_UNKNOWN] =  "Unknown error",
 };
diff --git a/libuci.h b/libuci.h
deleted file mode 100644 (file)
index de96f45..0000000
--- a/libuci.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * libuci - Library for the Unified Configuration Interface
- * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
- *
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu lesser general public license version 2.1
- * as published by the free software foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __LIBUCI_H
-#define __LIBUCI_H
-
-#include <setjmp.h>
-#include <stdio.h>
-
-enum
-{
-       UCI_OK = 0,
-       UCI_ERR_MEM,
-       UCI_ERR_INVAL,
-       UCI_ERR_NOTFOUND,
-       UCI_ERR_PARSE,
-       UCI_ERR_UNKNOWN,
-       UCI_ERR_LAST
-};
-
-struct uci_list
-{
-       void *next;
-       void *prev;
-};
-
-struct uci_config;
-struct uci_section;
-struct uci_option;
-struct uci_parse_context;
-
-
-/**
- * uci_alloc: Allocate a new uci context
- */
-extern struct uci_context *uci_alloc(void);
-
-/**
- * uci_perror: Print the last uci error that occured
- * @ctx: uci context
- * @str: string to print before the error message
- */
-extern void uci_perror(struct uci_context *ctx, const char *str);
-
-/**
- * uci_parse: Parse an uci config file and store it in the uci context
- *
- * @ctx: uci context
- * @name: name of the config file (relative to the config directory)
- */
-int uci_parse(struct uci_context *ctx, const char *name);
-
-/**
- * uci_cleanup: Clean up after an error
- *
- * @ctx: uci context
- */
-int uci_cleanup(struct uci_context *ctx);
-
-
-/* UCI data structures */
-
-struct uci_context
-{
-       struct uci_list root;
-
-       /* for error handling only */
-       struct uci_parse_context *pctx;
-
-       /* private: */
-       int errno;
-       jmp_buf trap;
-       jmp_buf trap_saved;
-       int saved;
-};
-
-struct uci_parse_context
-{
-       int line;
-       int byte;
-
-       /* private: */
-       struct uci_config *cfg;
-       FILE *file;
-       char *buf;
-       int bufsz;
-};
-
-struct uci_config
-{
-       struct uci_list list;
-       struct uci_list sections;
-       struct uci_context *ctx;
-       char *name;
-};
-
-struct uci_section
-{
-       struct uci_list list;
-       struct uci_list options;
-       struct uci_config *config;
-       char *type;
-       char *name;
-};
-
-struct uci_option
-{
-       struct uci_list list;
-       struct uci_section *section;
-       char *name;
-       char *value;
-};
-
-/* linked list handling */
-#ifndef offsetof
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-#endif
-
-#define uci_list_empty(list) (list->next == ptr)
-#define uci_list_entry(_type, _ptr) \
-       ((struct uci_ ## _type *) ((char *)(_ptr) - offsetof(struct uci_ ## _type,list)))
-
-#define uci_foreach_entry(_type, _list, _ptr)          \
-       for(_ptr = uci_list_entry(_type, (_list)->next);        \
-               &_ptr->list != (_list);                 \
-               _ptr = uci_list_entry(_type, _ptr->list.next))
-
-#endif
diff --git a/parse.c b/parse.c
index 9dd7126..5fc4661 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -16,6 +16,7 @@
  * This file contains the code for parsing uci config files
  */
 
+#include <sys/stat.h>
 #include <ctype.h>
 
 #define LINEBUF        128
@@ -267,9 +268,11 @@ static void uci_parse_line(struct uci_context *ctx)
        }
 }
 
-int uci_parse(struct uci_context *ctx, const char *name)
+int uci_load(struct uci_context *ctx, const char *name)
 {
        struct uci_parse_context *pctx;
+       struct stat statbuf;
+       char *filename;
 
        UCI_HANDLE_ERR(ctx);
        UCI_ASSERT(ctx, name != NULL);
@@ -280,11 +283,26 @@ int uci_parse(struct uci_context *ctx, const char *name)
        pctx = (struct uci_parse_context *) uci_malloc(ctx, sizeof(struct uci_parse_context));
        ctx->pctx = pctx;
 
-       /* TODO: use /etc/config/ */
-       pctx->file = fopen(name, "r");
-       if (!pctx->file)
+       switch (name[0]) {
+       case '.':
+       case '/':
+               /* absolute/relative path outside of /etc/config */
+               filename = (char *) name;
+               break;
+       default:
+               filename = uci_malloc(ctx, strlen(name) + sizeof(UCI_CONFDIR) + 2);
+               sprintf(filename, UCI_CONFDIR "/%s", name);
+               break;
+       }
+
+       if ((stat(filename, &statbuf) < 0) ||
+               ((statbuf.st_mode &  S_IFMT) != S_IFREG))
                UCI_THROW(ctx, UCI_ERR_NOTFOUND);
 
+       pctx->file = fopen(filename, "r");
+       if (!pctx->file)
+               UCI_THROW(ctx, UCI_ERR_IO);
+
        pctx->cfg = uci_alloc_file(ctx, name);
 
        while (!feof(pctx->file)) {
diff --git a/test.c b/test.c
index 53b2a6a..caf773b 100644 (file)
--- a/test.c
+++ b/test.c
@@ -10,7 +10,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-#include "libuci.h"
+#include "uci.h"
 
 int main(int argc, char **argv)
 {
@@ -21,7 +21,7 @@ int main(int argc, char **argv)
                return 1;
        }
 
-       if (uci_parse(ctx, argv[1])) {
+       if (uci_load(ctx, argv[1])) {
                uci_perror(ctx, "uci_parse");
                return 1;
        }
diff --git a/uci.h b/uci.h
new file mode 100644 (file)
index 0000000..4706255
--- /dev/null
+++ b/uci.h
@@ -0,0 +1,142 @@
+/*
+ * libuci - Library for the Unified Configuration Interface
+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
+ *
+ * this program is free software; you can redistribute it and/or modify
+ * it under the terms of the gnu lesser general public license version 2.1
+ * as published by the free software foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LIBUCI_H
+#define __LIBUCI_H
+
+#include <setjmp.h>
+#include <stdio.h>
+
+#define UCI_CONFDIR "/etc/config"
+
+enum
+{
+       UCI_OK = 0,
+       UCI_ERR_MEM,
+       UCI_ERR_INVAL,
+       UCI_ERR_NOTFOUND,
+       UCI_ERR_IO,
+       UCI_ERR_PARSE,
+       UCI_ERR_UNKNOWN,
+       UCI_ERR_LAST
+};
+
+struct uci_list
+{
+       void *next;
+       void *prev;
+};
+
+struct uci_config;
+struct uci_section;
+struct uci_option;
+struct uci_parse_context;
+
+
+/**
+ * uci_alloc: Allocate a new uci context
+ */
+extern struct uci_context *uci_alloc(void);
+
+/**
+ * uci_perror: Print the last uci error that occured
+ * @ctx: uci context
+ * @str: string to print before the error message
+ */
+extern void uci_perror(struct uci_context *ctx, const char *str);
+
+/**
+ * uci_load: Parse an uci config file and store it in the uci context
+ *
+ * @ctx: uci context
+ * @name: name of the config file (relative to the config directory)
+ */
+int uci_load(struct uci_context *ctx, const char *name);
+
+/**
+ * uci_cleanup: Clean up after an error
+ *
+ * @ctx: uci context
+ */
+int uci_cleanup(struct uci_context *ctx);
+
+
+/* UCI data structures */
+
+struct uci_context
+{
+       struct uci_list root;
+
+       /* for error handling only */
+       struct uci_parse_context *pctx;
+
+       /* private: */
+       int errno;
+       jmp_buf trap;
+       jmp_buf trap_saved;
+       int saved;
+};
+
+struct uci_parse_context
+{
+       int line;
+       int byte;
+
+       /* private: */
+       struct uci_config *cfg;
+       FILE *file;
+       char *buf;
+       int bufsz;
+};
+
+struct uci_config
+{
+       struct uci_list list;
+       struct uci_list sections;
+       struct uci_context *ctx;
+       char *name;
+};
+
+struct uci_section
+{
+       struct uci_list list;
+       struct uci_list options;
+       struct uci_config *config;
+       char *type;
+       char *name;
+};
+
+struct uci_option
+{
+       struct uci_list list;
+       struct uci_section *section;
+       char *name;
+       char *value;
+};
+
+/* linked list handling */
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#define uci_list_empty(list) (list->next == ptr)
+#define uci_list_entry(_type, _ptr) \
+       ((struct uci_ ## _type *) ((char *)(_ptr) - offsetof(struct uci_ ## _type,list)))
+
+#define uci_foreach_entry(_type, _list, _ptr)          \
+       for(_ptr = uci_list_entry(_type, (_list)->next);        \
+               &_ptr->list != (_list);                 \
+               _ptr = uci_list_entry(_type, _ptr->list.next))
+
+#endif