main.c revision b849b2f39b86dd1e23bd13b597dffe33ebd94185
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2005-2011 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define DOVECOT_CONFIG_BIN_PATH BINDIR"/doveconf"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen#define SERVICE_TIME_MOVED_BACKWARDS_MAX_THROTTLE_SECS (60*3)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic failure_callback_t *orig_fatal_callback;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic failure_callback_t *orig_error_callback;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic const struct setting_parser_info *set_roots[] = {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid process_exec(const char *cmd, const char *extra_args[])
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* @UNSAFE */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen new_argv = t_new(const char *, count1 + count2 + 1);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen memcpy(new_argv, argv, sizeof(const char *) * count1);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen sizeof(const char *) * count2);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* hide the path, it's ugly */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* prefix with dovecot/ */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen argv[0] = t_strdup_printf("%s/%s", services->set->instance_name,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (strncmp(argv[0], PACKAGE, strlen(PACKAGE)) != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen argv[0] = t_strconcat(PACKAGE"-", argv[0], NULL);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenint get_uidgid(const char *user, uid_t *uid_r, gid_t *gid_r,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const char **error_r)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen *error_r = t_strdup_printf("getpwnam(%s) failed: %m", user);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen *error_r = t_strdup_printf("User doesn't exist: %s", user);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenint get_gid(const char *group, gid_t *gid_r, const char **error_r)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen *error_r = t_strdup_printf("getgrnam(%s) failed: %m", group);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen *error_r = t_strdup_printf("Group doesn't exist: %s", group);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmaster_fatal_callback(const struct failure_context *ctx,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* if we already forked a child process, this isn't fatal for the
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen main process and there's no need to write the fatal file. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* write the error message to a file (we're chdired to
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen abort(); /* just to silence the noreturn attribute warnings */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstartup_fatal_handler(const struct failure_context *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fprintf(stderr, "%s%s\n", failure_log_type_prefixes[ctx->type],
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstartup_error_handler(const struct failure_context *ctx,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen fprintf(stderr, "%s%s\n", failure_log_type_prefixes[ctx->type],
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void fatal_log_check(const struct master_settings *set)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen path = t_strconcat(set->base_dir, "/"FATAL_FILENAME, NULL);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen fprintf(stderr, "Last died with error (see error log for more "
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic bool pid_file_read(const char *path, pid_t *pid_r)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_error("Empty PID file in %s, overriding", path);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void pid_file_check_running(const char *path)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_fatal("Dovecot is already running with PID %s "
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const char *pid;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen pid = t_strconcat(dec2str(getpid()), "\n", NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void create_config_symlink(const struct master_settings *set)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen base_config_path = t_strconcat(set->base_dir, "/"PACKAGE".conf", NULL);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (unlink(base_config_path) < 0 && errno != ENOENT)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_error("unlink(%s) failed: %m", base_config_path);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (symlink(services->config->config_file_path, base_config_path) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen services->config->config_file_path, base_config_path);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void mountpoints_warn_missing(struct mountpoint_list *mountpoints)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* warn about mountpoints that no longer exist */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen iter = mountpoint_list_iter_init(mountpoints);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen while ((rec = mountpoint_list_iter_next(iter)) != NULL) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen "If this is intentional, "
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen "remove it with doveadm mount",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void mountpoints_update(const struct master_settings *set)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen perm_path = t_strconcat(PKG_STATEDIR"/"MOUNTPOINT_LIST_FNAME, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen state_path = t_strconcat(set->base_dir, "/"MOUNTPOINT_LIST_FNAME, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mountpoints = mountpoint_list_init(perm_path, state_path);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mountpoint_list_add_missing(mountpoints, MOUNTPOINT_STATE_DEFAULT,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void instance_update_now(struct master_instance_list *list)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ret = master_instance_list_set_name(list, services->set->base_dir,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* duplicate instance names. allow without warning.. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen master_instance_list_update(list, services->set->base_dir);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen to_instance = timeout_add((3600*12 + rand()%(60*30)) * 1000,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void instance_update(void)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen instances = master_instance_list_init(MASTER_INSTANCE_PATH);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainensig_settings_reload(const siginfo_t *si ATTR_UNUSED,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_warning("SIGHUP received - reloading configuration");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* see if hostname changed */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* we can't reload config if there's no config process. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (service_process_create(services->config) == NULL) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen "we couldn't create a config process");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen input.config_path = services_get_config_socket_path(services);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (master_service_settings_read(master_service, &input,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_error("Error reading configuration: %s", error);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen sets = master_service_settings_get_others(master_service);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (services_create(set, &new_services, &error) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* new configuration is invalid, keep the old */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* switch to new configuration. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (services_listen_using(new_services, services) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* anvil never dies. it just gets moved to the new services list */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen service = service_lookup_type(services, SERVICE_TYPE_ANVIL);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainensig_log_reopen(const siginfo_t *si ATTR_UNUSED, void *context ATTR_UNUSED)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen master_service_init_log(master_service, "master: ");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainensig_reap_children(const siginfo_t *si ATTR_UNUSED, void *context ATTR_UNUSED)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void sig_die(const siginfo_t *si, void *context ATTR_UNUSED)
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic struct master_settings *master_settings_read(void)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (master_service_settings_read(master_service, &input, &output,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_fatal("Error reading configuration: %s", error);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return master_service_settings_get_others(master_service)[0];
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void master_set_import_environment(const struct master_settings *set)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen envs = t_strsplit_spaces(set->import_environment, " ");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen value = t_strarray_join(array_idx(&keys, 0), " ");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen env_put(t_strconcat(DOVECOT_PRESERVE_ENVS_ENV"=", value, NULL));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void main_log_startup(void)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen#define STARTUP_STRING PACKAGE_NAME" v"DOVECOT_VERSION_FULL" starting up"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen core_dumps_disabled = restrict_get_core_limit(&core_limit) == 0 &&
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_info(STARTUP_STRING" (core dumps disabled)");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int process_limit = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we'll just count all the processes that can exist and set the
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen process limit so that we won't reach it. it's usually higher than
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen needed, since we'd only need to set it high enough for each
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen separate UID not to reach the limit, but this is difficult to
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen guess: mail processes should probably be counted together for a
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen common vmail user (unless system users are being used), but
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen we can't really guess what the mail processes are. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (restrict_get_process_limit(&nproc) == 0 &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void main_init(const struct master_settings *set)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* deny file access from everyone else except owner */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen lib_signals_set_handler(SIGHUP, LIBSIG_FLAGS_SAFE,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen lib_signals_set_handler(SIGUSR1, LIBSIG_FLAGS_SAFE,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen lib_signals_set_handler(SIGCHLD, LIBSIG_FLAGS_SAFE,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen lib_signals_set_handler(SIGINT, LIBSIG_FLAGS_SAFE, sig_die, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen lib_signals_set_handler(SIGTERM, LIBSIG_FLAGS_SAFE, sig_die, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("close(global dead pipe) failed: %m");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("close(global dead pipe) failed: %m");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void main_deinit(void)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* kill services and wait for them to die before unlinking pid file */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_error("unlink(%s) failed: %m", pidfile_path);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic const char *get_full_config_path(struct service_list *list)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen path = master_service_get_config_path(master_service);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void master_time_moved(time_t old_time, time_t new_time)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned long secs;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* time moved backwards. disable launching new service processes
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (secs > SERVICE_TIME_MOVED_BACKWARDS_MAX_THROTTLE_SECS)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen secs = SERVICE_TIME_MOVED_BACKWARDS_MAX_THROTTLE_SECS;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen services_throttle_time_sensitives(services, secs);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_warning("Time moved backwards by %lu seconds, "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "waiting for %lu secs until new services are launched again.",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void daemonize(void)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* update my_pid */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void print_help(void)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen"Usage: dovecot [-F] [-c <config file>] [-p] [-n] [-a] [--help] [--version]\n"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen" [--build-options] [reload] [stop]\n");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void print_build_options(void)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen " ioloop=epoll"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen " ioloop=kqueue"
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen " ioloop=poll"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen " ioloop=select"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen " notify=dnotify"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen " notify=inotify"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen " notify=kqueue"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen " io_block_size=%u"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen "SQL driver plugins:"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen "SQL drivers:"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen " postgresql"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen " checkpassword"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen " passwd-file"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen " checkpassword"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen " passwd-file"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen failure_callback_t *orig_info_callback, *orig_debug_callback;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen bool foreground = FALSE, ask_key_pass = FALSE;
#ifdef DEBUG
c, optarg)) {
print_help();
const char **args;
print_help();
print_help();
if (ask_key_pass) {
T_BEGIN {
} T_END;
if (!foreground)
daemonize();
T_BEGIN {
} T_END;
main_deinit();