From: Andre Noll Date: Tue, 10 Feb 2009 22:08:20 +0000 (+0100) Subject: Merge commit 'fml/master' X-Git-Tag: v0.1.0~16 X-Git-Url: http://git.tuebingen.mpg.de/?p=adu.git;a=commitdiff_plain;h=d0f564069d8445e5ffe03c57ff63721f4c47877e;hp=c7d5ddb6906ab8a18181fee29ac78d604db5fdb9 Merge commit 'fml/master' Conflicts: adu.ggo user.c --- diff --git a/Makefile b/Makefile index a4293c7..880ba86 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,8 @@ CPPFLAGS += -I/usr/local/include LDFLAGS += -L/usr/local/lib +PREFIX ?= /usr/local + ifeq (,$(findstring BSD,$(uname_S))) CPPFLAGS += -D_LARGEFILE64_SOURCE @@ -82,3 +84,7 @@ index.html: adu.1.html index.html.in INSTALL README sed -e '1,/@INSTALL@/d' -e '/@MAN_PAGE@/,$$d' index.html.in >> $@ sed -e '1,/Return to Main Contents/d' -e '/Index/,$$d' adu.1.html >> $@ sed -e '1,/@MAN_PAGE@/d' index.html.in >> $@ + +install: adu adu.1 + install -s adu $(PREFIX)/bin + install -m 0644 adu.1 $(PREFIX)/man/man1 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 5da5908..2ddc34e 100644 --- a/adu.ggo +++ b/adu.ggo @@ -14,17 +14,18 @@ usage patterns of subdirectories and/or files owned by a given user id. section "General options" ######################### -option "database-dir" d -#~~~~~~~~~~~~~~~~~~~~~~ -"directory containing the osl tables" -string typestr="path" -required +option "config-file" c +#~~~~~~~~~~~~~~~~~~~~~ +"(default='~/.adurc')" +string typestr="filename" +optional 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. - + Options may be given at the command line or in the + configuration file. As usual, if an option is given both at + the command line and in the configuration file, the command + line option takes precedence. " + option "loglevel" l #~~~~~~~~~~~~~~~~~~ "Set loglevel (0-6)" @@ -36,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" ############### @@ -46,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 @@ -93,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/create.c b/create.c index 2925d57..87b0b9a 100644 --- a/create.c +++ b/create.c @@ -131,7 +131,7 @@ static int scan_dir(char *dirname, uint64_t *parent_dir_num) dir_size += size; dir_files++; uid = s.st_uid; - ret = create_user_table(conf.database_dir_arg, uid, &ui); + ret = create_user_table(uid, &ui); if (ret < 0) goto out; ret = update_user_row(ui->table, this_dir_num, &size); @@ -173,7 +173,7 @@ int com_create(void) ret = scan_dir(conf.base_dir_arg, &zero); if (ret < 0) goto out; - ret = write_uid_file(conf.database_dir_arg); + ret = write_uid_file(); out: return ret; } 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/interactive.c b/interactive.c index 08f700f..1c75622 100644 --- a/interactive.c +++ b/interactive.c @@ -214,13 +214,14 @@ int com_interactive(void) ret = parse_select_options(NULL, NULL, &admissible_uids, &fi); if (ret< 0) return ret; - ret = read_uid_file(conf.database_dir_arg); + ret = read_uid_file(); if (ret < 0) return ret; while (read_input_line(line, sizeof(line)) >= 0) { ret = exec_interactive_command(line); if (ret < 0) printf("%s\n", adu_strerror(-ret)); + fflush(NULL); } return ret; } diff --git a/select.c b/select.c index 4ebfbbf..e30697e 100644 --- a/select.c +++ b/select.c @@ -912,8 +912,7 @@ int run_select_query(struct uid_range *admissible_uids, struct format_info *fi) if (ret < 0) goto out; check_signals(); - ret = open_admissible_user_tables(conf.database_dir_arg, - admissible_uids); + ret = open_admissible_user_tables(admissible_uids); if (ret < 0) goto out; check_signals(); @@ -1063,7 +1062,7 @@ int com_select(void) ret = parse_select_options(conf.select_options_arg, ¶ms, &admissible_uids, &fi); if (ret > 0) { - ret = read_uid_file(conf.database_dir_arg); + ret = read_uid_file(); if (ret < 0) goto out; ret = run_select_query(admissible_uids, fi); diff --git a/string.c b/string.c index 77c90cb..946faab 100644 --- a/string.c +++ b/string.c @@ -138,7 +138,7 @@ __must_check __printf_1_2 __malloc char *make_message(const char *fmt, ...) * Append \p b to \p a. * * \return If \a a is \p NULL, return a pointer to a copy of \a b, i.e. - * para_strcat(NULL, b) is equivalent to para_strdup(b). If \a b is \p NULL, + * adu_strcat(NULL, b) is equivalent to adu_strdup(b). If \a b is \p NULL, * return \a a without making a copy of \a a. Otherwise, construct the * concatenation \a c, free \a a (but not \a b) and return \a c. * diff --git a/user.c b/user.c index dfa1c10..0ae4a6c 100644 --- a/user.c +++ b/user.c @@ -257,7 +257,7 @@ static inline int ui_admissible(struct user_info *ui) return ui->flags & UI_FL_ADMISSIBLE; } -static int open_user_table(const char *dirname, struct user_info *ui, int create) +static int open_user_table(struct user_info *ui, int create) { int ret; struct passwd *pw; @@ -266,7 +266,7 @@ static int open_user_table(const char *dirname, 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(dirname); + 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) @@ -435,8 +435,7 @@ static struct user_info *lookup_uid(uint32_t uid) * * \return Standard. */ -int create_user_table(const char *dirname, uint32_t uid, - struct user_info **ui_ptr) +int create_user_table(uint32_t uid, struct user_info **ui_ptr) { struct user_info *ui = lookup_uid(uid); @@ -447,12 +446,12 @@ int create_user_table(const char *dirname, uint32_t uid, return 1; ui->uid = uid; ui->flags |= UI_FL_SLOT_USED; - return open_user_table(dirname, ui, 1); + return open_user_table(ui, 1); } -static char *get_uid_list_name(const char *dirname) +static char *get_uid_list_name(void) { - return make_message("%s/uid_list", dirname); + return make_message("%s/uid_list", database_dir); } /** * Open the osl tables for all admissible uids. @@ -469,8 +468,7 @@ static char *get_uid_list_name(const char *dirname) * * \return Stamdard. */ -int open_admissible_user_tables(const char *dirname, - struct uid_range *admissible_uids) +int open_admissible_user_tables(struct uid_range *admissible_uids) { struct user_info *ui; @@ -489,7 +487,7 @@ int open_admissible_user_tables(const char *dirname, ui->flags |= UI_FL_ADMISSIBLE; if (ui->table) continue; - ret = open_user_table(dirname, ui, 0); + ret = open_user_table(ui, 0); if (ret < 0) return ret; } @@ -508,11 +506,11 @@ int open_admissible_user_tables(const char *dirname, * * \return Standard. */ -int read_uid_file(const char *dirname) +int read_uid_file(void) { size_t size; uint32_t n; - char *filename = get_uid_list_name(dirname), *map; + char *filename = get_uid_list_name(), *map; int ret = mmap_full_file(filename, O_RDONLY, (void **)&map, &size, NULL); unsigned bits; @@ -562,7 +560,7 @@ out: * * \return Standard. */ -int write_uid_file(const char *dirname) +int write_uid_file(void) { char *buf, *p, *filename; size_t size = num_uids * sizeof(uint32_t); @@ -578,7 +576,7 @@ int write_uid_file(const char *dirname) write_u32(p, ui->uid); p += sizeof(uint32_t); } - filename = get_uid_list_name(dirname); + filename = get_uid_list_name(); ret = adu_write_file(filename, buf, size); free(filename); free(buf); diff --git a/user.h b/user.h index c64983e..a6fbbf6 100644 --- a/user.h +++ b/user.h @@ -35,10 +35,9 @@ struct user_info { /** An opaque struct that contains info about which users are admissible. */ struct uid_range; -int create_user_table(const char *dirname, uint32_t uid, - struct user_info **ui_ptr); -int read_uid_file(const char *dirname); -int write_uid_file(const char *dirname); +int create_user_table(uint32_t uid, struct user_info **ui_ptr); +int read_uid_file(void); +int write_uid_file(void); void create_hash_table(unsigned bits); int for_each_admissible_user(int (*func)(struct user_info *, void *), @@ -47,5 +46,4 @@ int parse_uid_arg(const char *orig_arg, struct uid_range **ur); int append_users(char **users, int num_users, struct uid_range **admissible_uids, int num_uid_ranges); void close_user_tables(void); -int open_admissible_user_tables(const char *dirname, - struct uid_range *admissible_uids); +int open_admissible_user_tables(struct uid_range *admissible_uids);