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 82c876a..9fb70be 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 2ecdea4..2ddc34e 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 5e99709..42b9471 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 00bdede..5a5aefb 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 e1d243e..e661e71 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 6ebd9c9..32a3ad3 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 026d65b..2ed3d47 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.