parse_format_string(): Explicitly set the result pointer to NULL on errors.
[adu.git] / adu.c
diff --git a/adu.c b/adu.c
index db7a56438b992d3e47e6b691b6496f0334bd6254..8ce7317cdd207719f924523a0d7aa5ca32fcf288 100644 (file)
--- a/adu.c
+++ b/adu.c
@@ -1,6 +1,8 @@
 #include "adu.h"
 #include <dirent.h> /* readdir() */
 #include <pwd.h>
+#include "format.h"
+#include "select.h"
 
 #include "gcc-compat.h"
 #include "cmdline.h"
@@ -18,6 +20,9 @@ static int signum;
 /** Command line and config file options. */
 struct gengetopt_args_info conf;
 
+/** Options passed to --select-options. */
+struct select_args_info select_conf;
+
 /** The number of different uids found so far. */
 uint32_t num_uids = 0;
 
@@ -48,12 +53,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
  *
@@ -142,6 +141,15 @@ static struct osl_table_description dir_table_desc = {
        .column_descriptions = dir_table_cols,
 };
 
+/*
+ * The columns of the per-user tables.
+ *
+ * Adu tracks disk usage on a per-user basis. For each user, a user table is
+ * being created. The rows of the user table have three columns: The directory
+ * number that may be resolved to the path using the directory table, the
+ * number of bytes and the number of files in that directory owned by the given
+ * user.
+ */
 static struct osl_column_description user_table_cols[] = {
        [UT_DIR_NUM] = {
                .storage_type = OSL_MAPPED_STORAGE,
@@ -166,61 +174,6 @@ static struct osl_column_description user_table_cols[] = {
        },
 };
 
-static int check_uid_arg(const char *arg, uint32_t *uid)
-{
-       const uint32_t max = ~0U;
-       /*
-        * we need an 64-bit int for string -> uid conversion because strtoll()
-        * returns a signed value.
-        */
-       int64_t val;
-       int ret = atoi64(arg, &val);
-
-       if (ret < 0)
-               return ret;
-       if (val < 0 || val > max)
-               return -ERRNO_TO_ERROR(EINVAL);
-       *uid = val;
-       return 1;
-}
-
-static int parse_uid_range(const char *orig_arg, struct uid_range *ur)
-{
-       int ret;
-       char *arg = adu_strdup(orig_arg), *p = strchr(arg, '-');
-
-       if (!p || p == arg) { /* -42 or 42 */
-               ret = check_uid_arg(p? p + 1 : arg, &ur->high);
-               if (ret < 0)
-                       goto out;
-               ur->low = p? 0 : ur->high;
-               ret = 1;
-               goto out;
-       }
-       /* 42- or 42-4711 */
-       *p = '\0';
-       p++;
-       ret = check_uid_arg(arg, &ur->low);
-       if (ret < 0)
-               goto out;
-       ur->high = ~0U;
-       if (*p) { /* 42-4711 */
-               ret = check_uid_arg(p, &ur->high);
-               if (ret < 0)
-                       goto out;
-       }
-       if (ur->low > ur->high)
-               ret = -ERRNO_TO_ERROR(EINVAL);
-out:
-       if (ret < 0)
-               ERROR_LOG("bad uid option: %s\n", orig_arg);
-       else
-               INFO_LOG("admissible uid range: %u - %u\n", ur->low,
-                       ur->high);
-       free(arg);
-       return ret;
-}
-
 /**
  * The log function.
  *
@@ -418,24 +371,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;
 
@@ -448,7 +402,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);
@@ -495,9 +449,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;
 
@@ -514,19 +465,35 @@ 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;
+}
+
+static int print_complete_help_and_die(void)
+{
+       const char **line;
+       select_cmdline_parser_init(&select_conf);
+
+       if (conf.help_given)
+               line = gengetopt_args_info_help;
+       else
+               line = gengetopt_args_info_detailed_help;
+
+       printf("adu command line options:\n");
+       printf("=========================\n");
+       for (; *line; line++)
+               printf("%s\n", *line);
+       if (conf.help_given)
+               line = select_args_info_help;
+       else
+               line  = select_args_info_detailed_help;
+       printf("select options:\n");
+       printf("===============\n");
+       for (; *line; line++)
+               printf("%s\n", *line);
+       printf("interactive commands:\n");
+       printf("=====================\n");
+       print_interactive_help();
+       exit(EXIT_FAILURE);
 }
 
 int main(int argc, char **argv)
@@ -535,12 +502,21 @@ int main(int argc, char **argv)
        struct cmdline_parser_params params = {
                .override = 0,
                .initialize = 1,
-               .check_required = 1,
-               .check_ambiguity = 1,
-               .print_errors = 1
+               .check_required = 0,
+               .check_ambiguity = 0,
+               .print_errors = 0
        };
+       /* ignore errors and print complete help if --help was given */
+       cmdline_parser_ext(argc, argv, &conf, &params);
+       if (conf.help_given || conf.detailed_help_given)
+               print_complete_help_and_die();
+       params.check_required = 1;
+       params.check_ambiguity = 1;
+       params.print_errors = 1;
+       ret = cmdline_parser_ext(argc, argv, &conf, &params);
+       if (ret)
+               exit(EXIT_FAILURE);
 
-       cmdline_parser_ext(argc, argv, &conf, &params); /* aborts on errors */
        ret = check_args();
        if (ret < 0)
                goto out;
@@ -550,12 +526,13 @@ int main(int argc, char **argv)
        ret = -E_SYNTAX;
        if (conf.select_given)
                ret = com_select();
-       else
+       else if (conf.create_given)
                ret = com_create();
+       else
+               ret = com_interactive();
        if (ret < 0)
                goto out;
 out:
-       free(admissible_uids);
        if (ret < 0) {
                ERROR_LOG("%s\n", adu_strerror(-ret));
                return -EXIT_FAILURE;