new option database-root
authorSebastian Stark <seb@biskalar.de>
Wed, 4 Feb 2009 10:16:01 +0000 (11:16 +0100)
committerSebastian Stark <seb@biskalar.de>
Wed, 4 Feb 2009 12:36:44 +0000 (13:36 +0100)
If database-root is given, the database dir is computed by
appending the base dir to it. Obviously this works only if
base dir is given, even for select mode.
The needed directory structure is created below database-root
by the new function mkpath(), which recursively creates any
directory needed to copy the structure of base dir. This
has the side-effect that the database dir is always created
for the user (if permissions allow) which wasn't the case
before.

database_dir is now a global variable just like conf and should
be used whenever conf.database_dir_arg was used before.

adu.c
adu.ggo
adu.h
error.h
fd.c
fd.h
user.c

diff --git a/adu.c b/adu.c
index 82c876a96eb550956f60db458207c2777e67cb86..9fb70bed1446f41d4a6049db036e28c5bf6d971e 100644 (file)
--- a/adu.c
+++ b/adu.c
@@ -46,6 +46,8 @@ struct gengetopt_args_info conf;
 /** Options passed to --select-options. */
 struct select_args_info select_conf;
 
+/** Computed database dir */
+char *database_dir;
 
 /**
  * The table containing the directory names and statistics.
@@ -183,21 +185,27 @@ static int init_signals(void)
  */
 int open_dir_table(int create)
 {
+       int ret;
 
        if (dir_table)
                return 1;
-       dir_table_desc.dir = adu_strdup(conf.database_dir_arg);
 
+       dir_table_desc.dir = adu_strdup(database_dir);
        if (create) {
+               INFO_LOG("creating database directory structure\n");
+               ret = mkpath(dir_table_desc.dir, 0777);
+               if (ret < 0)
+                       goto out;
                NOTICE_LOG("creating dir table\n");
-               int ret = osl(osl_create_table(&dir_table_desc));
-               if (ret < 0) {
-                       free((char *)dir_table_desc.dir);
-                       return ret;
-               }
+               ret = osl(osl_create_table(&dir_table_desc));
+               if (ret < 0)
+                       goto out;
        }
        INFO_LOG("opening dir table\n");
        return osl(osl_open_table(&dir_table_desc, &dir_table));
+out:
+       free((char *)dir_table_desc.dir);
+       return ret;
 }
 
 static int check_args(void)
@@ -293,6 +301,11 @@ int main(int argc, char **argv)
        if (ret < 0)
                goto out;
        ret = -E_SYNTAX;
+       if (conf.database_dir_given)
+               database_dir = adu_strdup(conf.database_dir_arg);
+       else
+               database_dir = make_message("%s%s",
+                       conf.database_root_arg, conf.base_dir_arg);
        if (conf.select_given)
                ret = com_select();
        else if (conf.create_given)
@@ -307,6 +320,7 @@ out:
                ERROR_LOG("%s\n", adu_strerror(-ret));
                return -EXIT_FAILURE;
        }
+       free(database_dir);
        cmdline_parser_free(&conf);
        select_cmdline_parser_free(&select_conf);
        return EXIT_SUCCESS;
diff --git a/adu.ggo b/adu.ggo
index 2ecdea4b6b3116b6e6e2f32742ae8966778910e3..2ddc34e234acd87538fcfbc49abe9f53a83c1fbf 100644 (file)
--- a/adu.ggo
+++ b/adu.ggo
@@ -26,17 +26,6 @@ details="
        line option takes precedence.
 "
 
-option "database-dir" d
-#~~~~~~~~~~~~~~~~~~~~~~
-"directory containing the osl tables"
-string typestr="path"
-required
-details="
-       Full path to the directory containing the osl tables. This
-       directory must exist. It must be writable for the user running
-       adu in --create mode and readable in --select mode.
-
-"
 option "loglevel" l
 #~~~~~~~~~~~~~~~~~~
 "Set loglevel (0-6)"
@@ -48,6 +37,46 @@ details="
        goes to stdout. Lower values mean more verbose logging.
 "
 
+defgroup "database"
+#==================
+groupdesc="
+       There are two ways to specify a database directory. You can either
+       specify a full path using the database-dir option or a root path
+       using the database-root option. In the latter case, a directory
+       structure matching that of the base-dir argument is created
+       below the given full path.
+
+       The advantage of using database-root is that the base-dir is
+       used to find the relevant database both in create and select mode
+       and you do not have to care for setting the database-dir explicitly.
+"
+
+groupoption "database-dir" d
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~
+"directory containing the osl tables"
+group="database"
+string typestr="path"
+details="
+       Full path to the directory containing the osl tables. This
+       directory is created if it does not exist. It must be writable for the
+       user running adu in --create mode and readable in --select mode.
+"
+
+groupoption "database-root" r
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+"directory containing directories containing the osl tables"
+group="database"
+string typestr="path"
+default="/var/lib/adu"
+dependon="base-dir"
+optional
+details="
+       Base path to the directory containing the osl tables. The real
+       database-dir is generated by appending base-dir. This
+       directory is created if it does not exist. When used in select
+       mode you have to specify the base-dir as well.
+"
+
 ###############
 section "Modes"
 ###############
@@ -58,7 +87,6 @@ groupdesc="
        adu may be started in one of three possible modes, each of
        which corresponds to a different command line option. Exactly
        one of these options must be given.
-
 "
 required
 
@@ -105,7 +133,6 @@ option "base-dir" b
 #~~~~~~~~~~~~~~~~~~
 "directory to traverse"
 string typestr="path"
-dependon="create"
 optional
 details="
        The base directory to be traversed recursively. A warning
diff --git a/adu.h b/adu.h
index 5e99709c3679571b70ccaf5db5bc70c62957eb83..42b9471ee251e0ccf28ffd185628bfdd3d315634 100644 (file)
--- a/adu.h
+++ b/adu.h
@@ -139,6 +139,9 @@ extern struct osl_table *dir_table;
 /** The adu command line options. */
 extern struct gengetopt_args_info conf;
 
+/** Computed database dir. */
+extern char *database_dir;
+
 /**
  * The select command line options.
  *
diff --git a/error.h b/error.h
index 00bdede471394e7a051a81674bdda18aa4d1c4cd..5a5aefb987dad5f4946844e3153f2c8f12d0f282 100644 (file)
--- a/error.h
+++ b/error.h
@@ -42,7 +42,8 @@
        _ERROR(BAD_UNIT, "invalid unit specifier") \
        _ERROR(BAD_ATOM, "invalid atom") \
        _ERROR(BAD_OUTPUT_ARG, "invalid name for output") \
-       _ERROR(REGEX, "regular expression error")
+       _ERROR(REGEX, "regular expression error") \
+       _ERROR(MKDIR, "could not create directory")
 
 
 /**
diff --git a/fd.c b/fd.c
index e1d243e1e8f34006326bdfab72f24455ad801eff..e661e71fa32d2c20d92f558f9f40f62f576b9ba1 100644 (file)
--- a/fd.c
+++ b/fd.c
@@ -9,9 +9,11 @@
 #include <sys/types.h>
 #include <dirent.h>
 #include <sys/mman.h>
+#include <string.h>
 
 #include "adu.h"
 #include "error.h"
+#include "string.h"
 
 /**
  * Wrapper for the write system call.
@@ -273,3 +275,54 @@ int adu_munmap(void *start, size_t length)
                strerror(err));
        return -ERRNO_TO_ERROR(err);
 }
+
+__must_check __malloc static char *adu_dirname(const char *name)
+{
+       char *p, *ret;
+
+       if (!name || !*name)
+               return NULL;
+       ret = adu_strdup(name);
+       p = strrchr(ret, '/');
+       if (!p)
+               *ret = '\0';
+       else
+               *p = '\0';
+       return ret;
+}
+
+/**
+ * Recursive mkdir
+ *
+ * \param p Full path that should be created.
+ *
+ * \param mode Use this mode when creating directories.
+ *
+ * \return 0 if successful, -E_MKDIR on errors.
+ */
+int mkpath(const char *p, mode_t mode)
+{
+       char *parent, *path;
+       int ret = -E_MKDIR;
+
+       DEBUG_LOG("%s\n", p);
+       if (strcmp(p, ".") == 0 || strcmp(p, "/") == 0 || strcmp(p, "") == 0) {
+               DEBUG_LOG("reached beginning of path\n");
+               return 0;
+       }
+       path = adu_strdup(p);
+       parent = adu_dirname(p);
+       if (!parent)
+               goto out;
+       ret = mkpath(parent, mode);
+       if (ret < 0)
+               goto out;
+       INFO_LOG("making dir %s\n", path);
+       ret = 0;
+       if ((mkdir(path, mode) == -1) && (errno != EEXIST))
+               ret = -E_MKDIR;
+out:
+       free(parent);
+       free(path);
+       return ret;
+}
diff --git a/fd.h b/fd.h
index 6ebd9c90cb67f5917b50c923491d8f5a8fe9d1a1..32a3ad3df108e297dbe3c22c1fae520c6a835ba9 100644 (file)
--- a/fd.h
+++ b/fd.h
@@ -12,3 +12,4 @@ int mmap_full_file(const char *filename, int open_mode, void **map,
        size_t *size, int *fd_ptr);
 int adu_munmap(void *start, size_t length);
 int adu_write_file(const char *filename, const void *buf, size_t size);
+int mkpath(const char *p, mode_t mode);
diff --git a/user.c b/user.c
index 026d65be741fdc3a100c24f6cce379f8eaa124e0..2ed3d471bf9227424993383ac4e314aeedbf5b48 100644 (file)
--- a/user.c
+++ b/user.c
@@ -267,7 +267,7 @@ static int open_user_table(struct user_info *ui, int create)
        ui->desc->num_columns = NUM_UT_COLUMNS;
        ui->desc->flags = 0;
        ui->desc->column_descriptions = user_table_cols;
-       ui->desc->dir = adu_strdup(conf.database_dir_arg);
+       ui->desc->dir = adu_strdup(database_dir);
        ui->desc->name = make_message("%u", (unsigned)ui->uid);
        pw = getpwuid(ui->uid);
        if (pw && pw->pw_name)
@@ -452,7 +452,7 @@ int create_user_table(uint32_t uid, struct user_info **ui_ptr)
 
 static char *get_uid_list_name(void)
 {
-       return make_message("%s/uid_list", conf.database_dir_arg);
+       return make_message("%s/uid_list", database_dir);
 }
 /**
  * Open the osl tables for all admissible uids.