This means --uid no needs to be a multiple option.
Also, add descriptions to all interactive commands.
*/
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
*
% 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;
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);
static int check_args(void)
{
- int i, ret;
-
-
if (conf.create_given && !conf.base_dir_given)
return -E_SYNTAX;
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)
if (ret < 0)
goto out;
out:
- free(admissible_uids);
if (ret < 0) {
ERROR_LOG("%s\n", adu_strerror(-ret));
return -EXIT_FAILURE;
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"
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"
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;
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 *));
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;
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[] = {
{.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 = {
.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)
#include "string.h"
#include "error.h"
#include "portable_io.h"
+#include "select.cmdline.h"
/** Global dir count. */
static uint64_t num_dirs;
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)
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;
}
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];
"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.
+ --uid 23-42,666-777,88 # consider uids 23-42, 666-777 and 88.
"
option "limit" L
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;
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;
+}
__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);