/** The number of different uids found so far. */
uint32_t num_uids = 0;
+/** This is always a power of two. It is set in create_hash_table(). */
+static uint32_t uid_hash_table_size;
+
/**
* Contains info for each user that owns at least one regular file.
*
* option occupy a slot in this hash table. This allows to find out
* quicky whether a uid is admissible. And yes, this has to be fast.
*/
-struct user_info *uid_hash_table = NULL;
+static struct user_info *uid_hash_table;
/**
* The table containing the directory names and statistics.
return ret;
}
+int for_each_admissible_user(int (*func)(struct user_info *, void *),
+ void *data)
+{
+ struct user_info *ui = uid_hash_table;
+
+ if (!ui)
+ return -ERRNO_TO_ERROR(EFAULT);
+
+ for (; ui < uid_hash_table + uid_hash_table_size; ui++) {
+ int ret;
+
+ if (!ui_used(ui) || !ui_admissible(ui))
+ continue;
+ ret = func(ui, data);
+ if (ret < 0)
+ return ret;
+ }
+ return 1;
+}
+
#define PRIME1 0x811c9dc5
#define PRIME2 0x01000193
-uint32_t uid_hash_table_size;
void create_hash_table(unsigned bits)
{
uid_hash_table_size = 1 << bits;
dir_table = NULL;
}
-static void close_user_table(struct user_info *ui)
+static int close_user_table(struct user_info *ui, __a_unused void *data)
{
int ret;
- if (!ui || !ui_used(ui) || !ui_admissible(ui))
- return;
ret = osl(osl_close_table(ui->table, OSL_MARK_CLEAN));
if (ret < 0)
ERROR_LOG("failed to close user table %u: %s\n",
ui->desc = NULL;
ui->table = NULL;
ui->flags = 0;
+ return 1;
}
static void close_user_tables(void)
{
- struct user_info *ui;
-
- FOR_EACH_USER(ui)
- close_user_table(ui);
+ for_each_admissible_user(close_user_table, NULL);
}
void close_all_tables(void)
}
-static void print_id_stats(void)
+static int print_user_summary_line(struct user_info *ui, __a_unused void *data)
{
- struct user_info *ui;
+ char formated_dir_count[FORMATED_VALUE_SIZE],
+ formated_file_count[FORMATED_VALUE_SIZE],
+ formated_bytes[FORMATED_VALUE_SIZE ];
+
+ format_count_value(conf.count_unit_arg, ui->dirs,
+ conf.count_unit_arg == count_unit_arg_h,
+ formated_dir_count);
+ format_count_value(conf.count_unit_arg, ui->files,
+ conf.count_unit_arg == count_unit_arg_h,
+ formated_file_count);
+ format_size_value(conf.size_unit_arg, ui->bytes,
+ conf.size_unit_arg == size_unit_arg_h,
+ formated_bytes);
+ printf("\t%s\t%u\t%s\t%s\t%s\n",
+ ui->pw_name? ui->pw_name : "?",
+ (unsigned)ui->uid,
+ formated_dir_count,
+ formated_file_count,
+ formated_bytes
+ );
+ return 1;
+}
+static void print_user_summary(void)
+{
printf("User summary "
"(pw_name/uid/dirs%s/files%s/size%s):\n",
count_unit_buf, count_unit_buf, size_unit_buf);
- FOR_EACH_USER(ui) {
- char formated_dir_count[FORMATED_VALUE_SIZE],
- formated_file_count[FORMATED_VALUE_SIZE],
- formated_bytes[FORMATED_VALUE_SIZE ];
- if (!ui_used(ui) || !ui_admissible(ui))
- continue;
- format_count_value(conf.count_unit_arg, ui->dirs,
- conf.count_unit_arg == count_unit_arg_h,
- formated_dir_count);
- format_count_value(conf.count_unit_arg, ui->files,
- conf.count_unit_arg == count_unit_arg_h,
- formated_file_count);
- format_size_value(conf.size_unit_arg, ui->bytes,
- conf.size_unit_arg == size_unit_arg_h,
- formated_bytes);
- printf("\t%s\t%u\t%s\t%s\t%s\n",
- ui->pw_name? ui->pw_name : "?",
- (unsigned)ui->uid,
- formated_dir_count,
- formated_file_count,
- formated_bytes
- );
- }
+ for_each_admissible_user(print_user_summary_line, NULL);
}
-static int print_user_stats(void)
+static int print_user_stat(struct user_info *ui, __a_unused void *data)
{
- struct user_info *ui;
int ret;
+ struct user_stats_info usi = {
+ .count = conf.limit_arg,
+ .ui = ui
+ };
- FOR_EACH_USER(ui) {
- struct user_stats_info usi = {
- .count = conf.limit_arg,
- .ui = ui
- };
- if (!ui_used(ui) || !ui_admissible(ui))
- continue;
- usi.flags = USF_PRINT_DIRNAME | USF_PRINT_BYTES | USF_COMPUTE_SUMMARY;
- printf("%s (uid %u), by size%s:\n",
- ui->pw_name? ui->pw_name : "?", (unsigned)ui->uid,
- size_unit_buf);
- ret = adu_loop_reverse(ui->table, UT_BYTES, &usi, user_stats_loop_function,
- &usi.ret, &usi.osl_errno);
- if (ret < 0)
- return ret;
- printf("\n%s (uid %u), by file count%s:\n",
- ui->pw_name? ui->pw_name : "?", (unsigned)ui->uid,
- count_unit_buf);
- usi.count = conf.limit_arg,
- usi.flags = USF_PRINT_DIRNAME | USF_PRINT_FILES;
- ret = adu_loop_reverse(ui->table, UT_FILES, &usi, user_stats_loop_function,
- &usi.ret, &usi.osl_errno);
- if (ret < 0)
- return ret;
- printf("\n");
- }
+ usi.flags = USF_PRINT_DIRNAME | USF_PRINT_BYTES | USF_COMPUTE_SUMMARY;
+ printf("%s (uid %u), by size%s:\n",
+ ui->pw_name? ui->pw_name : "?", (unsigned)ui->uid,
+ size_unit_buf);
+ ret = adu_loop_reverse(ui->table, UT_BYTES, &usi, user_stats_loop_function,
+ &usi.ret, &usi.osl_errno);
+ if (ret < 0)
+ return ret;
+ printf("\n%s (uid %u), by file count%s:\n",
+ ui->pw_name? ui->pw_name : "?", (unsigned)ui->uid,
+ count_unit_buf);
+ usi.count = conf.limit_arg,
+ usi.flags = USF_PRINT_DIRNAME | USF_PRINT_FILES;
+ ret = adu_loop_reverse(ui->table, UT_FILES, &usi, user_stats_loop_function,
+ &usi.ret, &usi.osl_errno);
+ if (ret < 0)
+ return ret;
+ printf("\n");
return 1;
}
+static int print_user_stats(void)
+{
+ return for_each_admissible_user(print_user_stat, NULL);
+}
+
static int print_statistics(void)
{
int ret;
printf("\n");
print_global_summary();
print_user_stats();
- print_id_stats();
+ print_user_summary();
return 1;
}
uint32_t n;
char *filename = get_uid_list_name(), *map;
int ret = mmap_full_file(filename, O_RDONLY, (void **)&map, &size, NULL);
+ unsigned bits;
if (ret < 0) {
INFO_LOG("failed to map %s\n", filename);
num_uids = size / 4;
INFO_LOG("found %u uids in %s\n", (unsigned)num_uids, filename);
free(filename);
- /* hash table size should be a power of two and larger than the number of uids */
- uid_hash_table_size = 4;
- while (uid_hash_table_size < num_uids)
- uid_hash_table_size *= 2;
- create_hash_table();
+ /*
+ * Compute number of hash table bits. The hash table size must be a
+ * power of two and larger than the number of uids.
+ */
+ bits = 2;
+ while (1 << bits < num_uids)
+ bits++;
+ 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);