From: Andre Noll Date: Fri, 20 Jun 2008 13:27:02 +0000 (+0200) Subject: Make --uid take a comma-separated list of uids and move it to select.ggo. X-Git-Tag: v0.0.3~11 X-Git-Url: http://git.tuebingen.mpg.de/?p=adu.git;a=commitdiff_plain;h=15c765b696accdce0b20c339876e21e6e5967a52 Make --uid take a comma-separated list of uids and move it to select.ggo. This means --uid no needs to be a multiple option. Also, add descriptions to all interactive commands. --- diff --git a/adu.c b/adu.c index 07248e9..09619cf 100644 --- a/adu.c +++ b/adu.c @@ -48,12 +48,6 @@ static inline int ui_admissible(struct user_info *ui) */ struct osl_table *dir_table = NULL; -/** - * The array of all uid ranges that were given at the command line. - */ -struct uid_range *admissible_uids; - - /** * Compare the size of two directories * @@ -363,24 +357,25 @@ static uint32_t double_hash(uint32_t uid, uint32_t probe_num) % uid_hash_table_size; } -static int uid_is_admissible(uint32_t uid) +static int uid_is_admissible(uint32_t uid, struct uid_range *urs) { - int i; - - for (i = 0; i < conf.uid_given; i++) { - struct uid_range *ur = admissible_uids + i; + struct uid_range *ur; + int ret = 1; + if (!urs) /* empty array means all uids are allowed */ + return 1; + FOR_EACH_UID_RANGE(ur, urs) if (ur->low <= uid && ur->high >= uid) - break; - } - i = !conf.uid_given || i < conf.uid_given; + goto out; + ret = 0; +out: DEBUG_LOG("uid %u is %sadmissible\n", (unsigned)uid, - i? "" : "not "); - return i; + ret? "" : "not "); + return ret; } -int search_uid(uint32_t uid, enum search_uid_flags flags, - struct user_info **ui_ptr) +int search_uid(uint32_t uid, struct uid_range *urs, + enum search_uid_flags flags, struct user_info **ui_ptr) { uint32_t p; @@ -393,7 +388,7 @@ int search_uid(uint32_t uid, enum search_uid_flags flags, return -E_BAD_UID; ui->uid = uid; ui->flags |= UI_FL_SLOT_USED; - if (!uid_is_admissible(uid)) + if (!uid_is_admissible(uid, urs)) return 0; ui->flags |= UI_FL_ADMISSIBLE; ret = open_user_table(ui, flags & CREATE_USER_TABLE); @@ -440,9 +435,6 @@ int open_dir_table(int create) static int check_args(void) { - int i, ret; - - if (conf.create_given && !conf.base_dir_given) return -E_SYNTAX; @@ -459,19 +451,7 @@ static int check_args(void) conf.base_dir_arg[len] = '\0'; } } - if (!conf.uid_given) - return 0; - admissible_uids = adu_malloc(conf.uid_given * sizeof(*admissible_uids)); - for (i = 0; i < conf.uid_given; i++) { - ret = parse_uid_range(conf.uid_arg[i], admissible_uids + i); - if (ret < 0) - goto err; - } return 1; -err: - free(admissible_uids); - admissible_uids = NULL; - return ret; } int main(int argc, char **argv) @@ -502,7 +482,6 @@ int main(int argc, char **argv) if (ret < 0) goto out; out: - free(admissible_uids); if (ret < 0) { ERROR_LOG("%s\n", adu_strerror(-ret)); return -EXIT_FAILURE; diff --git a/adu.ggo b/adu.ggo index 38986af..1d0729d 100644 --- a/adu.ggo +++ b/adu.ggo @@ -49,25 +49,6 @@ details=" goes to stdout. Lower values mean more verbose logging. " -option "uid" u -#~~~~~~~~~~~~~ -"user id(s) to take into account" -string typestr="uid_spec" -optional -multiple -details=" - An uid specifier may be a single number, or a range of uids. - Example: - - --uid 42 # only consider uid 42 - --uid 42- # only consider uids greater or equal than 42 - --uid 23-42 # only consider uids between 23 and 42, inclusively. - - This option may be given multiple times. An uid is taken into - account if it satisfies at least one --uid option. -" - - option "paths" p #~~~~~~~~~~~~~~~ "files to take into account" @@ -169,10 +150,20 @@ details=" section "Options for --select" ############################## +option "select-options" s +#~~~~~~~~~~~~~~~~~~~~~~~~~ +"options for select mode" +string typestr="" +optional +dependon="select" +details=" + Try --select-options \"-h\" +" + option "limit" L #~~~~~~~~~~~~~~~ "Limit output" -int typestr="num" +int typestr="num" default="-1" optional dependon="select" diff --git a/adu.h b/adu.h index f8ef9c2..70dba77 100644 --- a/adu.h +++ b/adu.h @@ -173,6 +173,8 @@ enum search_uid_flags { CREATE_USER_TABLE = 2, }; +#define FOR_EACH_UID_RANGE(ur, urs) for (ur = urs; ur->low <= ur->high; ur++) + extern uint32_t num_uids; extern struct osl_table *dir_table; extern struct gengetopt_args_info conf; @@ -184,8 +186,8 @@ void check_signals(void); void close_all_tables(void); char *get_uid_list_name(void); void create_hash_table(unsigned bits); -int search_uid(uint32_t uid, enum search_uid_flags flags, - struct user_info **ui_ptr); +int search_uid(uint32_t uid, struct uid_range *urs, + enum search_uid_flags flags, struct user_info **ui_ptr); int for_each_admissible_user(int (*func)(struct user_info *, void *), void *data); void sort_hash_table(int (*comp)(const void *, const void *)); diff --git a/create.c b/create.c index 615349f..9b26f72 100644 --- a/create.c +++ b/create.c @@ -161,7 +161,7 @@ static int scan_dir(char *dirname, uint64_t *parent_dir_num) dir_size += size; dir_files++; uid = s.st_uid; - ret = search_uid(uid, CREATE_USER_TABLE | OPEN_USER_TABLE, &ui); + ret = search_uid(uid, NULL, CREATE_USER_TABLE | OPEN_USER_TABLE, &ui); if (ret < 0) goto out; ui->bytes += size; diff --git a/interactive.c b/interactive.c index 686a89f..8b27c0c 100644 --- a/interactive.c +++ b/interactive.c @@ -9,24 +9,28 @@ struct select_args_info select_conf; struct interactive_command { const char *name; int (*handler)(char *); + const char *desc; }; #define INTERACTIVE_COMMANDS \ - INTERACTIVE_COMMAND(dump) \ - INTERACTIVE_COMMAND(set) \ - INTERACTIVE_COMMAND(def) \ + INTERACTIVE_COMMAND(dump, "dump the current configuration") \ + INTERACTIVE_COMMAND(set, "change the current configuration") \ + INTERACTIVE_COMMAND(reset, "reset configuration to defaults") \ + INTERACTIVE_COMMAND(help, "show list of commands and one-line descriptions") \ -#define INTERACTIVE_COMMAND(name) \ + +#define INTERACTIVE_COMMAND(name, desc) \ static int icom_ ## name (char *line); INTERACTIVE_COMMANDS #undef INTERACTIVE_COMMAND -#define INTERACTIVE_COMMAND(_name) \ +#define INTERACTIVE_COMMAND(_name, _desc) \ { \ .name = #_name, \ - .handler = icom_ ## _name \ + .handler = icom_ ## _name, \ + .desc = _desc \ }, struct interactive_command icmds[] = { @@ -34,17 +38,30 @@ struct interactive_command icmds[] = { {.name = NULL} }; +#define FOR_EACH_COMMAND(c) for (c = icmds; c->name; c++) + static int read_input_line(char *line, size_t size) { return fgets(line, size, stdin)? 1 : -1; } -static int icom_def(__a_unused char *line) +static int icom_help(__a_unused char *line) +{ + struct interactive_command *c; + + FOR_EACH_COMMAND(c) + fprintf(stdout, "%s\t%s\n", c->name, c->desc); + return 1; +} + +static int icom_reset(__a_unused char *line) { select_cmdline_parser_init(&select_conf); return 1; } +static struct uid_range *admissible_uids; + static int icom_set(char *line) { struct select_cmdline_parser_params params = { @@ -54,9 +71,10 @@ static int icom_set(char *line) .check_ambiguity = 0, .print_errors = 1 }; - return select_cmdline_parser_string_ext(line, &select_conf, "select", - ¶ms)? - -E_SYNTAX : 1; + if (select_cmdline_parser_string_ext(line, &select_conf, "select", + ¶ms)) + return -E_SYNTAX; + return parse_uid_arg(select_conf.uid_arg, &admissible_uids); } static int icom_dump(__a_unused char *line) diff --git a/select.c b/select.c index 4c2f12c..ab95846 100644 --- a/select.c +++ b/select.c @@ -14,6 +14,7 @@ #include "string.h" #include "error.h" #include "portable_io.h" +#include "select.cmdline.h" /** Global dir count. */ static uint64_t num_dirs; @@ -76,6 +77,8 @@ static const uint64_t count_unit_divisors[] = { static const char size_unit_abbrevs[] = " BKMGT"; static const char count_unit_abbrevs[] = " kmgt"; +struct select_args_info select_conf; +static struct uid_range *admissible_uids; static enum enum_size_unit format_size_value(enum enum_size_unit unit, uint64_t value, int print_unit, char *result) @@ -575,7 +578,7 @@ static int read_uid_file(void) create_hash_table(bits); for (n = 0; n < num_uids; n++) { uint32_t uid = read_u32(map + n * sizeof(uid)); - ret = search_uid(uid, OPEN_USER_TABLE, NULL); + ret = search_uid(uid, admissible_uids, OPEN_USER_TABLE, NULL); if (ret < 0) goto out; } @@ -587,6 +590,22 @@ out: int com_select(void) { int ret; + struct select_cmdline_parser_params params = { + .override = 1, + .initialize = 1, + .check_required = 1, + .check_ambiguity = 1, + .print_errors = 1 + }; + + if (conf.select_options_given) { + if (select_cmdline_parser_string_ext(conf.select_options_arg, + &select_conf, "select", ¶ms)) + return -E_SYNTAX; + ret = parse_uid_arg(select_conf.uid_arg, &admissible_uids); + if (ret < 0) + return ret; + } if (conf.count_unit_arg != count_unit_arg_h) count_unit_buf[1] = count_unit_abbrevs[conf.count_unit_arg]; diff --git a/select.ggo b/select.ggo index 10c760e..33e75fe 100644 --- a/select.ggo +++ b/select.ggo @@ -4,7 +4,6 @@ option "uid" u "user id(s) to take into account" string typestr="uid_spec" optional -multiple details=" An uid specifier may be a single number, or a range of uids. Example: @@ -12,9 +11,7 @@ details=" --uid 42 # only consider uid 42 --uid 42- # only consider uids greater or equal than 42 --uid 23-42 # only consider uids between 23 and 42, inclusively. - - This option may be given multiple times. An uid is taken into - account if it satisfies at least one --uid option. + --uid 23-42,666-777,88 # consider uids 23-42, 666-777 and 88. " option "limit" L diff --git a/string.c b/string.c index 8b6ea5a..87f9c26 100644 --- a/string.c +++ b/string.c @@ -167,6 +167,56 @@ __must_check int atoi64(const char *str, int64_t *result) return 1; } +/** + * Split string and return pointers to its parts. + * + * \param args The string to be split. + * \param argv_ptr Pointer to the list of substrings. + * \param delim Delimiter. + * + * This function modifies \a args by replacing each occurance of \a delim by + * zero. A \p NULL-terminated array of pointers to char* is allocated dynamically + * and these pointers are initialized to point to the broken-up substrings + * within \a args. A pointer to this array is returned via \a argv_ptr. + * + * \return The number of substrings found in \a args. + */ +__must_check unsigned split_args(char *args, char *** const argv_ptr, const char *delim) +{ + char *p = args; + char **argv; + size_t n = 0, i, j; + + p = args + strspn(args, delim); + for (;;) { + i = strcspn(p, delim); + if (!i) + break; + p += i; + n++; + p += strspn(p, delim); + } + *argv_ptr = adu_malloc((n + 1) * sizeof(char *)); + argv = *argv_ptr; + i = 0; + p = args + strspn(args, delim); + while (p) { + argv[i] = p; + j = strcspn(p, delim); + if (!j) + break; + p += strcspn(p, delim); + if (*p) { + *p = '\0'; + p++; + p += strspn(p, delim); + } + i++; + } + argv[n] = NULL; + return n; +} + static int check_uid_arg(const char *arg, uint32_t *uid) { const uint32_t max = ~0U; @@ -222,3 +272,31 @@ out: return ret; } +int parse_uid_arg(const char *orig_arg, struct uid_range **ur) +{ + char *arg, **argv; + unsigned n; + int i, ret = 1; + + if (!orig_arg) + return 0; + arg = adu_strdup(orig_arg); + n = split_args(arg, &argv, ","); + if (!n) + return -E_SYNTAX; + *ur = adu_malloc((n + 1) * sizeof(struct uid_range)); + for (i = 0; i < n; i++) { + ret = parse_uid_range(argv[i], *ur + i); + if (ret < 0) + break; + } + free(arg); + if (ret < 0) { + free(*ur); + *ur = NULL; + } + /* an empty range indicates the end of the list */ + (*ur)[n].low = 1; + (*ur)[n].high = 0; + return n; +} diff --git a/string.h b/string.h index d975178..7229b7d 100644 --- a/string.h +++ b/string.h @@ -12,5 +12,4 @@ __must_check __malloc void *adu_calloc(size_t size); __must_check __malloc char *adu_strdup(const char *s); __must_check __malloc __printf_1_2 char *make_message(const char *fmt, ...); __must_check int atoi64(const char *str, int64_t *result); -int parse_uid_range(const char *orig_arg, struct uid_range *ur); - +int parse_uid_arg(const char *orig_arg, struct uid_range **ur);