Make --uid take a comma-separated list of uids and move it to select.ggo.
authorAndre Noll <maan@systemlinux.org>
Fri, 20 Jun 2008 13:27:02 +0000 (15:27 +0200)
committerAndre Noll <maan@systemlinux.org>
Fri, 20 Jun 2008 13:27:02 +0000 (15:27 +0200)
This means --uid no needs to be a multiple option.
Also, add descriptions to all interactive commands.

adu.c
adu.ggo
adu.h
create.c
interactive.c
select.c
select.ggo
string.c
string.h

diff --git a/adu.c b/adu.c
index 07248e9..09619cf 100644 (file)
--- 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 (file)
--- 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="<options>"
+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 (file)
--- 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 *));
index 615349f..9b26f72 100644 (file)
--- 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;
index 686a89f..8b27c0c 100644 (file)
@@ -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",
-               &params)?
-               -E_SYNTAX : 1;
+       if (select_cmdline_parser_string_ext(line, &select_conf, "select",
+               &params))
+               return -E_SYNTAX;
+       return parse_uid_arg(select_conf.uid_arg, &admissible_uids);
 }
 
 static int icom_dump(__a_unused char *line)
index 4c2f12c..ab95846 100644 (file)
--- 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", &params))
+                       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];
index 10c760e..33e75fe 100644 (file)
@@ -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
index 8b6ea5a..87f9c26 100644 (file)
--- 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;
+}
index d975178..7229b7d 100644 (file)
--- 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);