/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
#include "lib.h"
+#include "abspath.h"
#include "array.h"
#include "istream.h"
#include "ostream.h"
const char *path;
ARRAY_DEFINE(instances, struct master_instance);
+
+ unsigned int locked:1;
+ unsigned int config_paths_changed:1;
};
struct master_instance_list_iter {
pool_unref(&list->pool);
}
+static void
+master_instance_update_config_path(struct master_instance_list *list,
+ struct master_instance *inst)
+{
+ const char *path, *config_path;
+
+ /* update instance's config path if it has changed */
+ path = t_strconcat(inst->base_dir, "/"PACKAGE".conf", NULL);
+ if (t_readlink(path, &config_path) == 0) {
+ if (null_strcmp(inst->config_path, config_path) != 0) {
+ inst->config_path = p_strdup(list->pool, config_path);
+ list->config_paths_changed = TRUE;
+ }
+ }
+}
+
static int
master_instance_list_add_line(struct master_instance_list *list,
const char *line)
const char *const *args;
time_t last_used;
- /* <last used> <name> <base dir> */
+ /* <last used> <name> <base dir> [<config path>] */
args = t_strsplit_tabescaped(line);
- if (str_array_length(args) != 3)
+ if (str_array_length(args) < 3)
return -1;
if (str_to_time(args[0], &last_used) < 0)
return -1;
inst->last_used = last_used;
inst->name = p_strdup(list->pool, args[1]);
inst->base_dir = p_strdup(list->pool, args[2]);
+ inst->config_path = p_strdup_empty(list->pool, args[3]);
+ master_instance_update_config_path(list, inst);
return 0;
}
str_tabescape_write(str, inst->name);
str_append_c(str, '\t');
str_tabescape_write(str, inst->base_dir);
+ str_append_c(str, '\t');
+ if (inst->config_path != NULL)
+ str_tabescape_write(str, inst->config_path);
str_append_c(str, '\n');
(void)o_stream_send(output, str_data(str), str_len(str));
}
{
int fd;
+ i_assert(!list->locked);
+
*dotlock_r = NULL;
fd = file_dotlock_open_mode(&dotlock_set, list->path, 0, 0644,
(void)file_dotlock_delete(dotlock_r);
return -1;
}
+ list->locked = TRUE;
return fd;
}
const char *lock_path = file_dotlock_get_lock_path(*dotlock);
int ret;
+ i_assert(list->locked);
+
T_BEGIN {
ret = master_instance_list_write(list, fd, lock_path);
} T_END;
+
+ list->locked = FALSE;
if (ret < 0) {
(void)file_dotlock_delete(dotlock);
return -1;
(void)file_dotlock_delete(dotlock);
return -1;
}
+ list->config_paths_changed = FALSE;
return file_dotlock_replace(dotlock, 0);
}
inst->base_dir = p_strdup(list->pool, base_dir);
}
inst->last_used = time(NULL);
+ master_instance_update_config_path(list, inst);
return master_instance_write_finish(list, fd, &dotlock);
}
return master_instance_write_finish(list, fd, &dotlock) < 0 ? -1 : 1;
}
+static int
+master_instance_list_refresh_and_update(struct master_instance_list *list)
+{
+ struct dotlock *dotlock;
+ int fd;
+
+ if (master_instance_list_refresh(list) < 0)
+ return -1;
+ if (list->config_paths_changed && !list->locked) {
+ /* write new config paths */
+ if ((fd = master_instance_write_init(list, &dotlock)) == -1)
+ return -1;
+ if (master_instance_write_finish(list, fd, &dotlock) < 0)
+ return -1;
+ }
+ return 0;
+}
+
const struct master_instance *
master_instance_list_find_by_name(struct master_instance_list *list,
const char *name)
i_assert(*name != '\0');
if (array_count(&list->instances) == 0)
- (void)master_instance_list_refresh(list);
+ (void)master_instance_list_refresh_and_update(list);
array_foreach(&list->instances, inst) {
if (strcmp(inst->name, name) == 0)
iter = i_new(struct master_instance_list_iter, 1);
iter->list = list;
- (void)master_instance_list_refresh(list);
+ (void)master_instance_list_refresh_and_update(list);
return iter;
}