From d0bef44ffe5b6f985f4ba6a718e08afb50f096c6 Mon Sep 17 00:00:00 2001 From: Sebastian Stark Date: Wed, 4 Feb 2009 11:16:01 +0100 Subject: [PATCH] new option database-root 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 | 26 ++++++++++++++++++++------ adu.ggo | 53 ++++++++++++++++++++++++++++++++++++++++------------- adu.h | 3 +++ error.h | 3 ++- fd.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ fd.h | 1 + user.c | 4 ++-- 7 files changed, 121 insertions(+), 22 deletions(-) diff --git a/adu.c b/adu.c index 82c876a..9fb70be 100644 --- 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 --- 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 --- 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 --- 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 --- a/fd.c +++ b/fd.c @@ -9,9 +9,11 @@ #include #include #include +#include #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 --- 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 --- 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. -- 2.39.2