]> git.tuebingen.mpg.de Git - adu.git/blobdiff - adu.c
Implement --one-file-system (-x).
[adu.git] / adu.c
diff --git a/adu.c b/adu.c
index 3a676c4dd29dc6c33c09001d12a9aedfdbc712ba..dad9d8c17f83db81d62ef4116f181fd394320825 100644 (file)
--- a/adu.c
+++ b/adu.c
@@ -34,6 +34,9 @@ struct user_info {
 /** The decimal representation of an uint64_t never exceeds that size. */
 #define FORMATED_VALUE_SIZE 25
 
+#define FOR_EACH_USER(ui) for (ui = uid_hash_table; ui && ui < uid_hash_table \
+               + uid_hash_table_size; ui++)
+
 
 /**
  * Contains info for each user that owns at least one regular file.
@@ -72,7 +75,7 @@ static inline int check_uid_arg(const char *arg, uint32_t *uid)
         * returns a signed value.
         */
        int64_t val;
-       int ret = para_atoi64(arg, &val);
+       int ret = atoi64(arg, &val);
 
        if (ret < 0)
                return ret;
@@ -85,7 +88,7 @@ static inline int check_uid_arg(const char *arg, uint32_t *uid)
 static int parse_uid_range(const char *orig_arg, struct uid_range *ur)
 {
        int ret;
-       char *arg = para_strdup(orig_arg), *p = strchr(arg, '-');
+       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);
@@ -119,7 +122,6 @@ out:
        return ret;
 }
 
-
 /** evaluates to 1 if x < y, to -1 if x > y and to 0 if x == y */
 #define NUM_COMPARE(x, y) ((int)((x) < (y)) - (int)((x) > (y)))
 
@@ -318,11 +320,11 @@ static int open_user_table(struct user_info *ui, int create)
 {
        int ret;
 
-       ui->desc = para_malloc(sizeof(*ui->desc));
+       ui->desc = adu_malloc(sizeof(*ui->desc));
        ui->desc->num_columns = NUM_UT_COLUMNS;
        ui->desc->flags = 0;
        ui->desc->column_descriptions = user_table_cols;
-       ui->desc->dir = para_strdup(conf.database_dir_arg);
+       ui->desc->dir = adu_strdup(conf.database_dir_arg);
        ui->desc->name = make_message("%u", (unsigned)ui->uid);
        INFO_LOG(".............................uid #%u: %u\n",
                (unsigned)num_uids, (unsigned)ui->uid);
@@ -355,7 +357,7 @@ static uint32_t uid_hash_table_size = 1 << uid_hash_bits;
 
 static void create_hash_table(void)
 {
-       uid_hash_table = para_calloc(uid_hash_table_size
+       uid_hash_table = adu_calloc(uid_hash_table_size
                * sizeof(struct user_info));
 }
 
@@ -369,7 +371,7 @@ static int create_tables(void)
 {
        int ret;
 
-       dir_table_desc.dir = para_strdup(conf.database_dir_arg);
+       dir_table_desc.dir = adu_strdup(conf.database_dir_arg);
        ret = osl(osl_create_table(&dir_table_desc));
        if (ret < 0)
                return ret;
@@ -377,6 +379,79 @@ static int create_tables(void)
        return 1;
 }
 
+static void close_dir_table(void)
+{
+       int ret;
+
+       if (!dir_table)
+               return;
+       ret = osl(osl_close_table(dir_table, OSL_MARK_CLEAN));
+       if (ret < 0)
+               ERROR_LOG("failed to close dir table: %s\n", adu_strerror(-ret));
+       free((char *)dir_table_desc.dir);
+       dir_table = NULL;
+}
+
+static void close_user_table(struct user_info *ui)
+{
+       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",
+                       (unsigned) ui->uid, adu_strerror(-ret));
+       free((char *)ui->desc->name);
+       ui->desc->name = NULL;
+       free((char *)ui->desc->dir);
+       ui->desc->dir = NULL;
+       free(ui->desc);
+       ui->desc = NULL;
+       ui->table = NULL;
+       ui->flags = 0;
+}
+
+static void close_user_tables(void)
+{
+       struct user_info *ui;
+
+       FOR_EACH_USER(ui)
+               close_user_table(ui);
+}
+
+static void close_all_tables(void)
+{
+       close_dir_table();
+       close_user_tables();
+       free_hash_table();
+}
+
+static int signum;
+
+static void signal_handler(int s)
+{
+       signum = s;
+}
+
+static void check_signals(void)
+{
+       if (likely(!signum))
+               return;
+       EMERG_LOG("caught signal %d\n", signum);
+       close_all_tables();
+       exit(EXIT_FAILURE);
+}
+
+static int init_signals(void)
+{
+       if (signal(SIGINT, &signal_handler) == SIG_ERR)
+               return -E_SIGNAL_SIG_ERR;
+       if (signal(SIGTERM, &signal_handler) == SIG_ERR)
+               return -E_SIGNAL_SIG_ERR;
+       return 1;
+}
+
 /*
  * We use a hash table of size s=2^uid_hash_bits to map the uids into the
  * interval [0..s]. Hash collisions are treated by open addressing, i.e.
@@ -399,9 +474,6 @@ static uint32_t double_hash(uint32_t uid, uint32_t probe_num)
                % uid_hash_table_size;
 }
 
-#define FOR_EACH_USER(ui) for (ui = uid_hash_table; ui && ui < uid_hash_table \
-               + uid_hash_table_size; ui++)
-
 enum search_uid_flags {
        OPEN_USER_TABLE = 1,
        CREATE_USER_TABLE = 2,
@@ -504,7 +576,10 @@ static uint64_t num_dirs;
 static uint64_t num_files;
 static uint64_t num_bytes;
 
-int scan_dir(char *dirname, uint64_t *parent_dir_num)
+/* id of the device containing the base dir. */
+static dev_t device_id;
+
+static int scan_dir(char *dirname, uint64_t *parent_dir_num)
 {
        DIR *dir;
        struct dirent *entry;
@@ -512,8 +587,9 @@ int scan_dir(char *dirname, uint64_t *parent_dir_num)
        uint64_t dir_size = 0, dir_files = 0;
        uint64_t this_dir_num = ++num_dirs;
 
+       check_signals();
        DEBUG_LOG("----------------- %llu: %s\n", (long long unsigned)num_dirs, dirname);
-       ret = para_opendir(dirname, &dir, &cwd_fd);
+       ret = adu_opendir(dirname, &dir, &cwd_fd);
        if (ret < 0) {
                if (ret != -ERRNO_TO_ERROR(EACCES))
                        return ret;
@@ -540,6 +616,8 @@ int scan_dir(char *dirname, uint64_t *parent_dir_num)
                if (!S_ISREG(m) && !S_ISDIR(m))
                        continue;
                if (S_ISDIR(m)) {
+                       if (conf.one_file_system_given && s.st_dev != device_id)
+                               continue;
                        ret = scan_dir(entry->d_name, &this_dir_num);
                        if (ret < 0)
                                goto out;
@@ -565,7 +643,7 @@ int scan_dir(char *dirname, uint64_t *parent_dir_num)
                        &dir_size, &dir_files);
 out:
        closedir(dir);
-       ret2 = para_fchdir(cwd_fd);
+       ret2 = adu_fchdir(cwd_fd);
        if (ret2 < 0 && ret >= 0)
                ret = ret2;
        close(cwd_fd);
@@ -592,7 +670,7 @@ again:
                free(result);
                result = tmp;
        } else
-               result = para_strdup((char *)obj.data);
+               result = adu_strdup((char *)obj.data);
        ret = osl(osl_get_object(dir_table, row, DT_PARENT_NUM, &obj));
        if (ret < 0)
                goto out;
@@ -618,7 +696,7 @@ static int get_dir_name_of_row(struct osl_row *dir_table_row, char **name)
        ret = osl(osl_get_object(dir_table, dir_table_row, DT_NAME, &obj));
        if (ret < 0)
                return ret;
-       this_dir = para_strdup((char *)obj.data);
+       this_dir = adu_strdup((char *)obj.data);
        ret = osl(osl_get_object(dir_table, dir_table_row, DT_PARENT_NUM, &obj));
        if (ret < 0)
                goto out;
@@ -712,6 +790,7 @@ static int global_stats_loop_function(struct osl_row *row, void *data)
        char *dirname, formated_value[FORMATED_VALUE_SIZE];
        int ret, summary = gsi->flags & GSF_COMPUTE_SUMMARY;
 
+       check_signals();
        if (!gsi->count && !summary) {
                ret = -E_LOOP_COMPLETE;
                goto err;
@@ -824,6 +903,7 @@ static int user_stats_loop_function(struct osl_row *row, void *data)
        int ret, summary = usi->flags & GSF_COMPUTE_SUMMARY;
        char formated_value[FORMATED_VALUE_SIZE];
 
+       check_signals();
        if (!usi->count && !summary) {
                ret = -E_LOOP_COMPLETE;
                goto err;
@@ -1015,7 +1095,7 @@ static int write_uid_list(void)
 
        if (!num_uids)
                return 0;
-       buf = para_malloc(size);
+       buf = adu_malloc(size);
        FOR_EACH_USER(ui) {
                if (!ui_used(ui) || !ui_admissible(ui))
                        continue;
@@ -1023,7 +1103,7 @@ static int write_uid_list(void)
                write_u32(buf + count++ * sizeof(uint32_t), ui->uid);
        }
        filename = get_uid_list_name();
-       ret = para_write_file(filename, buf, size);
+       ret = adu_write_file(filename, buf, size);
        free(filename);
        free(buf);
        return ret;
@@ -1032,68 +1112,28 @@ static int write_uid_list(void)
 static int open_dir_table(void)
 {
        if (!dir_table_desc.dir) /* we did not create the table */
-               dir_table_desc.dir = para_strdup(conf.database_dir_arg);
+               dir_table_desc.dir = adu_strdup(conf.database_dir_arg);
        return osl(osl_open_table(&dir_table_desc, &dir_table));
 }
-
-static void close_dir_table(void)
-{
-       int ret;
-
-       if (!dir_table)
-               return;
-       ret = osl(osl_close_table(dir_table, OSL_MARK_CLEAN));
-       if (ret < 0)
-               ERROR_LOG("failed to close dir table: %s\n", adu_strerror(-ret));
-       free((char *)dir_table_desc.dir);
-       dir_table = NULL;
-}
-
-static void close_user_table(struct user_info *ui)
-{
-       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",
-                       (unsigned) ui->uid, adu_strerror(-ret));
-       free((char *)ui->desc->name);
-       ui->desc->name = NULL;
-       free((char *)ui->desc->dir);
-       ui->desc->dir = NULL;
-       free(ui->desc);
-       ui->desc = NULL;
-       ui->table = NULL;
-       ui->flags = 0;
-}
-
-static void close_user_tables(void)
-{
-       struct user_info *ui;
-
-       FOR_EACH_USER(ui)
-               close_user_table(ui);
-}
-
-static void close_all_tables(void)
-{
-       close_dir_table();
-       close_user_tables();
-       free_hash_table();
-}
-
 static int com_create()
 {
        uint64_t zero = 0ULL;
-       int ret = create_tables();
-
+       int ret;
+       struct stat statbuf;
+
+       if (lstat(conf.base_dir_arg, &statbuf) == -1)
+               return -ERRNO_TO_ERROR(errno);
+       if (!S_ISDIR(statbuf.st_mode))
+               return -ERRNO_TO_ERROR(ENOTDIR);
+       device_id = statbuf.st_dev;
+       ret = create_tables();
        if (ret < 0)
                return ret;
+       check_signals();
        ret = open_dir_table();
        if (ret < 0)
                return ret;
+       check_signals();
        ret = scan_dir(conf.base_dir_arg, &zero);
        if (ret < 0)
                goto out;
@@ -1130,7 +1170,7 @@ static int read_uid_file(void)
                        goto out;
        }
 out:
-       para_munmap(map, size);
+       adu_munmap(map, size);
        return ret;
 }
 
@@ -1150,9 +1190,11 @@ static int com_select(void)
        ret = open_dir_table();
        if (ret < 0)
                return ret;
+       check_signals();
        ret = read_uid_file();
        if (ret < 0)
                return ret;
+       check_signals();
        ret = print_statistics();
        close_all_tables();
        return ret;
@@ -1177,7 +1219,7 @@ static int check_args(void)
        }
        if (!conf.uid_given)
                return 0;
-       admissible_uids = para_malloc(conf.uid_given * sizeof(*admissible_uids));
+       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)
@@ -1202,6 +1244,9 @@ int main(int argc, char **argv)
        };
 
        cmdline_parser_ext(argc, argv, &conf, &params); /* aborts on errors */
+       ret = init_signals();
+       if (ret < 0)
+               goto out;
        ret = check_args();
        if (ret < 0)
                goto out;