]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
quota: Avoid calling i_fatal() on initialization errors, plus some other fixes.
authorTimo Sirainen <tss@iki.fi>
Tue, 21 Sep 2010 17:05:13 +0000 (18:05 +0100)
committerTimo Sirainen <tss@iki.fi>
Tue, 21 Sep 2010 17:05:13 +0000 (18:05 +0100)
src/plugins/quota/quota-storage.c
src/plugins/quota/quota.c
src/plugins/quota/quota.h

index 65e39c0dd41ae473b0b6642e851b8bb31271d1b5..714f59562825ced1f763f8e7da1b3d40ca0f802e 100644 (file)
@@ -454,14 +454,28 @@ void quota_mail_user_created(struct mail_user *user)
        struct mail_user_vfuncs *v = user->vlast;
        struct quota_user *quser;
        struct quota_settings *set;
+       struct quota *quota;
+       const char *error;
+       int ret;
 
-       set = quota_user_read_settings(user);
-       if (set != NULL) {
+       if ((ret = quota_user_read_settings(user, &set, &error)) > 0) {
+               if (quota_init(set, user, &quota, &error) < 0) {
+                       quota_settings_deinit(&set);
+                       ret = -1;
+               }
+       }
+
+       if (ret < 0) {
+               user->error = p_strdup_printf(user->pool,
+                       "Failed to initialize quota: %s", error);
+               return;
+       }
+       if (ret > 0) {
                quser = p_new(user->pool, struct quota_user, 1);
                quser->module_ctx.super = *v;
                user->vlast = &quser->module_ctx.super;
                v->deinit = quota_user_deinit;
-               quser->quota = quota_init(set, user);
+               quser->quota = quota;
 
                MODULE_CONTEXT_SET(user, quota_user_module, quser);
        } else if (user->mail_debug) {
index a14f324bad104a55c026ae3555283b9e8916c03f..92c59cedb28603121021c32a2aaad28b590d5b89 100644 (file)
@@ -45,8 +45,21 @@ static const struct quota_backend *quota_backends[] = {
 static int quota_default_test_alloc(struct quota_transaction_context *ctx,
                                    uoff_t size, bool *too_large_r);
 
-static void quota_root_add_rules(struct mail_user *user, const char *root_name, 
-                                struct quota_root_settings *root_set)
+static const struct quota_backend *quota_backend_find(const char *name)
+{
+       unsigned int i;
+
+       for (i = 0; i < N_ELEMENTS(quota_backends); i++) {
+               if (strcmp(quota_backends[i]->name, name) == 0)
+                       return quota_backends[i];
+       }
+
+       return NULL;
+}
+
+static int quota_root_add_rules(struct mail_user *user, const char *root_name,
+                               struct quota_root_settings *root_set,
+                               const char **error_r)
 {
        const char *rule_name, *rule, *error;
        unsigned int i;
@@ -58,16 +71,19 @@ static void quota_root_add_rules(struct mail_user *user, const char *root_name,
                        break;
 
                if (quota_root_add_rule(root_set, rule, &error) < 0) {
-                       i_fatal("Quota root %s: Invalid rule %s: %s",
-                               root_name, rule, error);
+                       *error_r = t_strdup_printf("Invalid rule %s: %s",
+                                                  rule, error);
+                       return -1;
                }
                rule_name = t_strdup_printf("%s_rule%d", root_name, i);
        }
+       return 0;
 }
 
-static void
+static int
 quota_root_add_warning_rules(struct mail_user *user, const char *root_name,
-                            struct quota_root_settings *root_set)
+                            struct quota_root_settings *root_set,
+                            const char **error_r)
 {
        const char *rule_name, *rule, *error;
        unsigned int i;
@@ -79,76 +95,19 @@ quota_root_add_warning_rules(struct mail_user *user, const char *root_name,
                        break;
 
                if (quota_root_add_warning_rule(root_set, rule, &error) < 0) {
-                       i_fatal("Quota root %s: Invalid warning rule: %s",
-                               root_name, rule);
+                       *error_r = t_strdup_printf("Invalid warning rule: %s",
+                                                  rule);
+                       return -1;
                }
                rule_name = t_strdup_printf("%s_warning%d", root_name, i);
        }
+       return 0;
 }
 
-struct quota_settings *quota_user_read_settings(struct mail_user *user)
-{
-       struct quota_settings *quota_set;
-       struct quota_root_settings *root_set;
-       char root_name[6 + MAX_INT_STRLEN];
-       const char *env;
-       unsigned int i;
-       pool_t pool;
-
-       pool = pool_alloconly_create("quota settings", 2048);
-       quota_set = p_new(pool, struct quota_settings, 1);
-       quota_set->pool = pool;
-       quota_set->test_alloc = quota_default_test_alloc;
-       quota_set->debug = user->mail_debug;
-       quota_set->quota_exceeded_msg =
-               mail_user_plugin_getenv(user, "quota_exceeded_message");
-       if (quota_set->quota_exceeded_msg == NULL)
-               quota_set->quota_exceeded_msg = DEFAULT_QUOTA_EXCEEDED_MSG;
-
-       p_array_init(&quota_set->root_sets, pool, 4);
-       i_strocpy(root_name, "quota", sizeof(root_name));
-       for (i = 2;; i++) {
-               env = mail_user_plugin_getenv(user, root_name);
-               if (env == NULL)
-                       break;
-
-               root_set = quota_root_settings_init(quota_set, env);
-               if (root_set == NULL) {
-                       i_fatal("Couldn't create quota root %s: %s",
-                               root_name, env);
-               }
-               quota_root_add_rules(user, root_name, root_set);
-               quota_root_add_warning_rules(user, root_name, root_set);
-
-               i_snprintf(root_name, sizeof(root_name), "quota%d", i);
-       }
-
-       return quota_set;
-}
-
-void quota_settings_deinit(struct quota_settings **_quota_set)
-{
-       struct quota_settings *quota_set = *_quota_set;
-
-       *_quota_set = NULL;
-
-       pool_unref(&quota_set->pool);
-}
-
-static const struct quota_backend *quota_backend_find(const char *name)
-{
-       unsigned int i;
-
-       for (i = 0; i < N_ELEMENTS(quota_backends); i++) {
-               if (strcmp(quota_backends[i]->name, name) == 0)
-                       return quota_backends[i];
-       }
-
-       return NULL;
-}
-
-struct quota_root_settings *
-quota_root_settings_init(struct quota_settings *quota_set, const char *root_def)
+static int
+quota_root_settings_init(struct quota_settings *quota_set, const char *root_def,
+                        struct quota_root_settings **set_r,
+                        const char **error_r)
 {
        struct quota_root_settings *root_set;
        const struct quota_backend *backend;
@@ -166,8 +125,9 @@ quota_root_settings_init(struct quota_settings *quota_set, const char *root_def)
 
        backend = quota_backend_find(backend_name);
        if (backend == NULL) {
-               i_error("Unknown quota backend: %s", backend_name);
-               return NULL;
+               *error_r = t_strdup_printf("Unknown quota backend: %s",
+                                          backend_name);
+               return -1;
        }
        
        root_set = p_new(quota_set->pool, struct quota_root_settings, 1);
@@ -198,11 +158,89 @@ quota_root_settings_init(struct quota_settings *quota_set, const char *root_def)
        p_array_init(&root_set->rules, quota_set->pool, 4);
        p_array_init(&root_set->warning_rules, quota_set->pool, 4);
        array_append(&quota_set->root_sets, &root_set, 1);
-       return root_set;
+       *set_r = root_set;
+       return 0;
 }
 
-static struct quota_root *
-quota_root_init(struct quota_root_settings *root_set, struct quota *quota)
+static int
+quota_root_add(struct quota_settings *quota_set, struct mail_user *user,
+              const char *env, const char *root_name, const char **error_r)
+{
+       struct quota_root_settings *root_set;
+
+       if (quota_root_settings_init(quota_set, env, &root_set, error_r) < 0)
+               return -1;
+       if (quota_root_add_rules(user, root_name, root_set, error_r) < 0)
+               return -1;
+       if (quota_root_add_warning_rules(user, root_name, root_set, error_r) < 0)
+               return -1;
+       return 0;
+}
+
+int quota_user_read_settings(struct mail_user *user,
+                            struct quota_settings **set_r,
+                            const char **error_r)
+{
+       struct quota_settings *quota_set;
+       char root_name[6 + MAX_INT_STRLEN];
+       const char *env, *error;
+       unsigned int i;
+       pool_t pool;
+
+       pool = pool_alloconly_create("quota settings", 2048);
+       quota_set = p_new(pool, struct quota_settings, 1);
+       quota_set->pool = pool;
+       quota_set->test_alloc = quota_default_test_alloc;
+       quota_set->debug = user->mail_debug;
+       quota_set->quota_exceeded_msg =
+               mail_user_plugin_getenv(user, "quota_exceeded_message");
+       if (quota_set->quota_exceeded_msg == NULL)
+               quota_set->quota_exceeded_msg = DEFAULT_QUOTA_EXCEEDED_MSG;
+
+       p_array_init(&quota_set->root_sets, pool, 4);
+       i_strocpy(root_name, "quota", sizeof(root_name));
+       for (i = 2;; i++) {
+               env = mail_user_plugin_getenv(user, root_name);
+               if (env == NULL)
+                       break;
+
+               if (quota_root_add(quota_set, user, env, root_name,
+                                  &error) < 0) {
+                       *error_r = t_strdup_printf("Invalid quota root %s: %s",
+                                                  root_name, error);
+                       pool_unref(&pool);
+                       return -1;
+               }
+               i_snprintf(root_name, sizeof(root_name), "quota%d", i);
+       }
+       if (array_count(&quota_set->root_sets) == 0) {
+               pool_unref(&pool);
+               return 0;
+       }
+       *set_r = quota_set;
+       return 1;
+}
+
+void quota_settings_deinit(struct quota_settings **_quota_set)
+{
+       struct quota_settings *quota_set = *_quota_set;
+
+       *_quota_set = NULL;
+
+       pool_unref(&quota_set->pool);
+}
+
+static void quota_root_deinit(struct quota_root *root)
+{
+       pool_t pool = root->pool;
+
+       root->backend.v.deinit(root);
+       pool_unref(&pool);
+}
+
+static int
+quota_root_init(struct quota_root_settings *root_set, struct quota *quota,
+               struct quota_root **root_r, const char **error_r)
 {
        struct quota_root *root;
        const char *const *tmp;
@@ -220,8 +258,10 @@ quota_root_init(struct quota_root_settings *root_set, struct quota *quota)
                     sizeof(void *), 10);
 
        if (root->backend.v.init != NULL) {
-               if (root->backend.v.init(root, root_set->args) < 0)
-                       i_fatal("Quota root %s init() failed", root_set->name);
+               if (root->backend.v.init(root, root_set->args) < 0) {
+                       *error_r = "init() failed";
+                       return -1;
+               }
        } else if (root_set->args != NULL) {
                tmp = t_strsplit_spaces(root_set->args, " ");
                for (; *tmp != NULL; tmp++) {
@@ -233,33 +273,31 @@ quota_root_init(struct quota_root_settings *root_set, struct quota *quota)
                                break;
                }
                if (*tmp != NULL) {
-                       i_fatal("Quota root %s backend %s: "
-                               "Unknown parameter: %s",
-                               root_set->name, root->backend.name, *tmp);
+                       *error_r = t_strdup_printf(
+                               "Unknown parameter for backend %s: %s",
+                               root->backend.name, *tmp);
+                       return -1;
                }
        }
        if (root_set->default_rule.bytes_limit == 0 &&
            root_set->default_rule.count_limit == 0 &&
-           root->disable_unlimited_tracking)
-               return NULL;
-       return root;
-}
-
-static void quota_root_deinit(struct quota_root *root)
-{
-       pool_t pool = root->pool;
-
-       root->backend.v.deinit(root);
-       pool_unref(&pool);
+           root->disable_unlimited_tracking) {
+               quota_root_deinit(root);
+               return 0;
+       }
+       *root_r = root;
+       return 1;
 }
 
-struct quota *quota_init(struct quota_settings *quota_set,
-                        struct mail_user *user)
+int quota_init(struct quota_settings *quota_set, struct mail_user *user,
+              struct quota **quota_r, const char **error_r)
 {
        struct quota *quota;
        struct quota_root *root;
        struct quota_root_settings *const *root_sets;
        unsigned int i, count;
+       const char *error;
+       int ret;
 
        quota = i_new(struct quota, 1);
        quota->user = user;
@@ -269,11 +307,18 @@ struct quota *quota_init(struct quota_settings *quota_set,
        root_sets = array_get(&quota_set->root_sets, &count);
        i_array_init(&quota->namespaces, count);
        for (i = 0; i < count; i++) {
-               root = quota_root_init(root_sets[i], quota);
-               if (root != NULL)
+               ret = quota_root_init(root_sets[i], quota, &root, &error);
+               if (ret < 0) {
+                       *error_r = t_strdup_printf("Quota root %s: %s",
+                                                  root_sets[i]->name, error);
+                       quota_deinit(&quota);
+                       return -1;
+               }
+               if (ret > 0)
                        array_append(&quota->roots, &root, 1);
        }
-       return quota;
+       *quota_r = quota;
+       return 0;
 }
 
 void quota_deinit(struct quota **_quota)
@@ -496,8 +541,11 @@ int quota_root_add_rule(struct quota_root_settings *root_set,
        }
 
        if (strncmp(p, "backend=", 8) == 0) {
-               if (!root_set->backend->v.parse_rule(root_set, rule,
-                                                    p + 8, error_r))
+               if (root_set->backend->v.parse_rule == NULL) {
+                       *error_r = "backend rule not supported";
+                       ret = -1;
+               } else if (!root_set->backend->v.parse_rule(root_set, rule,
+                                                           p + 8, error_r))
                        ret = -1;
        } else {
                bool relative_rule = rule != &root_set->default_rule;
index ec198970d53ddd85a755581a81ae211ca1b4fc85..93e570c0dbf35ed43da6303d107664492aaa6815 100644 (file)
@@ -13,19 +13,17 @@ struct mail_user;
 #define QUOTA_NAME_MESSAGES "MESSAGE"
 
 struct quota;
+struct quota_settings;
+struct quota_root_settings;
 struct quota_root;
 struct quota_root_iter;
 struct quota_transaction_context;
 
-struct quota_settings *quota_user_read_settings(struct mail_user *user);
+int quota_user_read_settings(struct mail_user *user,
+                            struct quota_settings **set_r,
+                            const char **error_r);
 void quota_settings_deinit(struct quota_settings **quota_set);
 
-/* Set up a new quota root. */
-struct quota_root_settings *
-quota_root_settings_init(struct quota_settings *quota_set,
-                        const char *root_def);
-void quota_root_settings_deinit(struct quota_root_settings **root_set);
-
 /* Add a new rule too the quota root. Returns 0 if ok, -1 if rule is invalid. */
 int quota_root_add_rule(struct quota_root_settings *root_set,
                        const char *rule_def, const char **error_r);
@@ -35,8 +33,8 @@ int quota_root_add_warning_rule(struct quota_root_settings *root_set,
                                const char *rule_def, const char **error_r);
 
 /* Initialize quota for the given user. */
-struct quota *quota_init(struct quota_settings *quota_set,
-                        struct mail_user *user);
+int quota_init(struct quota_settings *quota_set, struct mail_user *user,
+              struct quota **quota_r, const char **error_r);
 void quota_deinit(struct quota **quota);
 
 /* List all quota roots. Returned quota roots are freed by quota_deinit(). */