main.c revision 55cdf2ed53584247aab18d2689ba24264211ccf6
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2005-2016 Dovecot authors, see the included COPYING file */
f81a4d2002da0db33d11ca694d3a91b3ee2a0fdbTimo Sirainen#define DOVECOT_CONFIG_BIN_PATH BINDIR"/doveconf"
f81a4d2002da0db33d11ca694d3a91b3ee2a0fdbTimo Sirainen#define SERVICE_TIME_MOVED_BACKWARDS_MAX_THROTTLE_SECS (60*3)
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainenstatic failure_callback_t *orig_fatal_callback;
945631faab2bf1aed8d95a1fd0c317a9ce153725Timo Sirainenstatic failure_callback_t *orig_error_callback;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic const struct setting_parser_info *set_roots[] = {
9315dd69233d554452df0c12bc57002d2042a8f4Timo Sirainen /* hide the path, it's ugly */
538c58fc95200fcc5e91abdda8b912b574a2f968Timo Sirainen /* prefix with dovecot/ */
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen argv[0] = t_strdup_printf("%s/%s", services->set->instance_name,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (strncmp(argv[0], PACKAGE, strlen(PACKAGE)) != 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen argv[0] = t_strconcat(PACKAGE"-", argv[0], NULL);
bf91bed88d4e294b4577ba2a3b14d87cf35ae135Timo Sirainenint get_uidgid(const char *user, uid_t *uid_r, gid_t *gid_r,
bf91bed88d4e294b4577ba2a3b14d87cf35ae135Timo Sirainen const char **error_r)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen *error_r = t_strdup_printf("getpwnam(%s) failed: %m", user);
7de1c472fd23ddac6b4dc5cbeee6fa6a8418b071Timo Sirainen *error_r = t_strdup_printf("User doesn't exist: %s", user);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint get_gid(const char *group, gid_t *gid_r, const char **error_r)
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen *error_r = t_strdup_printf("getgrnam(%s) failed: %m", group);
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen *error_r = t_strdup_printf("Group doesn't exist: %s", group);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmaster_fatal_callback(const struct failure_context *ctx,
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen /* if we already forked a child process, this isn't fatal for the
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen main process and there's no need to write the fatal file. */
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen /* write the error message to a file (we're chdired to
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen abort(); /* just to silence the noreturn attribute warnings */
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainenstartup_fatal_handler(const struct failure_context *ctx,
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen fprintf(stderr, "%s%s\n", failure_log_type_prefixes[ctx->type],
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstartup_error_handler(const struct failure_context *ctx,
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen fprintf(stderr, "%s%s\n", failure_log_type_prefixes[ctx->type],
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainenstatic void fatal_log_check(const struct master_settings *set)
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen path = t_strconcat(set->base_dir, "/"FATAL_FILENAME, NULL);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen fprintf(stderr, "Last died with error (see error log for more "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool pid_file_read(const char *path, pid_t *pid_r)
31050c3df6cbe403e8ced8ef11b5c4e12124d354Timo Sirainen i_error("Empty PID file in %s, overriding", path);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen i_error("PID file contains invalid PID value");
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainenstatic void pid_file_check_running(const char *path)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen i_fatal("Dovecot is already running with PID %s "
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen const char *pid;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen pid = t_strconcat(dec2str(getpid()), "\n", NULL);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644);
bddd52cb7f3e5a894c080f60750aa76b5aeaf103Timo Sirainenstatic void create_config_symlink(const struct master_settings *set)
bddd52cb7f3e5a894c080f60750aa76b5aeaf103Timo Sirainen base_config_path = t_strconcat(set->base_dir, "/"PACKAGE".conf", NULL);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen if (symlink(services->config->config_file_path, base_config_path) < 0) {
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen services->config->config_file_path, base_config_path);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainenstatic void instance_update_now(struct master_instance_list *list)
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen ret = master_instance_list_set_name(list, services->set->base_dir,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen /* duplicate instance names. allow without warning.. */
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen (void)master_instance_list_update(list, services->set->base_dir);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen to_instance = timeout_add((3600*12 + rand()%(60*30)) * 1000,
bddd52cb7f3e5a894c080f60750aa76b5aeaf103Timo Sirainenstatic void instance_update(const struct master_settings *set)
bddd52cb7f3e5a894c080f60750aa76b5aeaf103Timo Sirainen path = t_strconcat(set->state_dir, "/"MASTER_INSTANCE_FNAME, NULL);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainensig_settings_reload(const siginfo_t *si ATTR_UNUSED,
bddd52cb7f3e5a894c080f60750aa76b5aeaf103Timo Sirainen i_warning("SIGHUP received - reloading configuration");
bddd52cb7f3e5a894c080f60750aa76b5aeaf103Timo Sirainen /* see if hostname changed */
bddd52cb7f3e5a894c080f60750aa76b5aeaf103Timo Sirainen /* we can't reload config if there's no config process. */
bddd52cb7f3e5a894c080f60750aa76b5aeaf103Timo Sirainen if (service_process_create(services->config) == NULL) {
bddd52cb7f3e5a894c080f60750aa76b5aeaf103Timo Sirainen "we couldn't create a config process");
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen input.config_path = services_get_config_socket_path(services);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen if (master_service_settings_read(master_service, &input,
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen i_error("Error reading configuration: %s", error);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen sets = master_service_settings_get_others(master_service);
4b89231f4ec9cc69f4aea715e1d34f405c7e317dTimo Sirainen if (services_create(set, &new_services, &error) < 0) {
4b89231f4ec9cc69f4aea715e1d34f405c7e317dTimo Sirainen /* new configuration is invalid, keep the old */
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen /* switch to new configuration. */
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen if (services_listen_using(new_services, services) < 0) {
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen /* anvil never dies. it just gets moved to the new services list */
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen service = service_lookup_type(services, SERVICE_TYPE_ANVIL);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainensig_log_reopen(const siginfo_t *si ATTR_UNUSED, void *context ATTR_UNUSED)
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen master_service_init_log(master_service, "master: ");
cd5ee8630497fdbd853ef588a858b4ef619a5e03Timo Sirainensig_reap_children(const siginfo_t *si ATTR_UNUSED, void *context ATTR_UNUSED)
3342badd8c69adff34db589fb0a221ace5996212Timo Sirainenstatic void sig_die(const siginfo_t *si, void *context ATTR_UNUSED)
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen /* make sure new processes won't be created by the currently
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen running ioloop. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic struct master_settings *master_settings_read(void)
1032e5427bf10566098f3b3bb9110e2bc1227e85Timo Sirainen if (master_service_settings_read(master_service, &input, &output,
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen i_fatal("Error reading configuration: %s", error);
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen return master_service_settings_get_others(master_service)[0];
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainenstatic void master_set_import_environment(const struct master_settings *set)
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen envs = t_strsplit_spaces(set->import_environment, " ");
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen value = t_strarray_join(array_idx(&keys, 0), " ");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen env_put(t_strconcat(DOVECOT_PRESERVE_ENVS_ENV"=", value, NULL));
7394389230750c45b105cdefb5850c81cae8cdc0Timo Sirainen#define STARTUP_STRING PACKAGE_NAME" v"DOVECOT_VERSION_FULL" starting up"
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen t_strarray_join((const char **)protocols, ", "));
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen core_dumps_disabled = restrict_get_core_limit(&core_limit) == 0 &&
51920d00fa50edf7b2e9b1019288d64b7abee7f3Timo Sirainen unsigned int process_limit = 0;
21ec6628c567eeff025af35d8027be01044b0b1aTimo Sirainen /* we'll just count all the processes that can exist and set the
21ec6628c567eeff025af35d8027be01044b0b1aTimo Sirainen process limit so that we won't reach it. it's usually higher than
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen needed, since we'd only need to set it high enough for each
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen separate UID not to reach the limit, but this is difficult to
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen guess: mail processes should probably be counted together for a
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen common vmail user (unless system users are being used), but
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen we can't really guess what the mail processes are. */
3342badd8c69adff34db589fb0a221ace5996212Timo Sirainen if (restrict_get_process_limit(&nproc) == 0 &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void main_init(const struct master_settings *set)
cd5ee8630497fdbd853ef588a858b4ef619a5e03Timo Sirainen /* deny file access from everyone else except owner */
d647e72663b52cb2301df5eaf93e67ee873a41f8Timo Sirainen lib_signals_set_handler(SIGHUP, LIBSIG_FLAGS_SAFE,
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen lib_signals_set_handler(SIGUSR1, LIBSIG_FLAGS_SAFE,
9887c39c5ba429169389153ca99de49e084a73f0Timo Sirainen lib_signals_set_handler(SIGCHLD, LIBSIG_FLAGS_SAFE,
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen lib_signals_set_handler(SIGINT, LIBSIG_FLAGS_SAFE, sig_die, NULL);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen lib_signals_set_handler(SIGTERM, LIBSIG_FLAGS_SAFE, sig_die, NULL);
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen i_error("close(global dead pipe) failed: %m");
d647e72663b52cb2301df5eaf93e67ee873a41f8Timo Sirainen i_error("close(global dead pipe) failed: %m");
d647e72663b52cb2301df5eaf93e67ee873a41f8Timo Sirainenstatic void main_deinit(void)
d647e72663b52cb2301df5eaf93e67ee873a41f8Timo Sirainen /* kill services and wait for them to die before unlinking pid file */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenstatic const char *get_full_config_path(struct service_list *list)
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen path = master_service_get_config_path(master_service);
d143077bd518de129b8d446fb58e003903e50867Timo Sirainenstatic void master_time_moved(time_t old_time, time_t new_time)
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen unsigned long secs;
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen /* time moved backwards. disable launching new service processes
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (secs > SERVICE_TIME_MOVED_BACKWARDS_MAX_THROTTLE_SECS)
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen secs = SERVICE_TIME_MOVED_BACKWARDS_MAX_THROTTLE_SECS;
e063aca6bc2f08bec516d4b631052ea9191f011dTimo Sirainen services_throttle_time_sensitives(services, secs);
e063aca6bc2f08bec516d4b631052ea9191f011dTimo Sirainen i_warning("Time moved backwards by %lu seconds, "
e063aca6bc2f08bec516d4b631052ea9191f011dTimo Sirainen "waiting for %lu secs until new services are launched again.",
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainenstatic void daemonize(void)
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen /* update my_pid */
d143077bd518de129b8d446fb58e003903e50867Timo Sirainenstatic void print_help(void)
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen"Usage: dovecot [-F] [-c <config file>] [-p] [-n] [-a] [--help] [--version]\n"
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen" [--build-options] [--hostdomain] [reload] [stop]\n");
d143077bd518de129b8d446fb58e003903e50867Timo Sirainenstatic void print_build_options(void)
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen " ioloop=epoll"
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen " ioloop=kqueue"
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen " ioloop=poll"
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen " ioloop=select"
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen " notify=inotify"
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen " notify=kqueue"
2c677e9d339bc91d5b54376ba2986f71476c06abTimo Sirainen " io_block_size=%u"
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen "SQL driver plugins:"
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen "SQL drivers:"
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen " postgresql"
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen " checkpassword"
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen " passwd-file"
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen " checkpassword"
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen " passwd-file"
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen failure_callback_t *orig_info_callback, *orig_debug_callback;
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen bool foreground = FALSE, ask_key_pass = FALSE;
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen /* drop -- prefix from all --args. ugly, but the only way that it
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen works with standard getopt() in all OSes.. */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen master_service = master_service_init(MASTER_SERVICE_NAME,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen io_loop_set_time_moved_callback(current_ioloop, master_time_moved);
2d79e603e20a32bdae4c2b516ead5c5c9169545aTimo Sirainen while ((c = master_getopt(master_service)) > 0) {
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen /* Ask SSL private key password */
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen if (!master_service_parse_option(master_service,
c5794838af9995f50bfecb06a3cd4f9a0ac77858Timo Sirainen const char **args;
c5794838af9995f50bfecb06a3cd4f9a0ac77858Timo Sirainen args[3] = master_service_get_config_path(master_service);
c5794838af9995f50bfecb06a3cd4f9a0ac77858Timo Sirainen /* starting Dovecot */
c5794838af9995f50bfecb06a3cd4f9a0ac77858Timo Sirainen /* dovecot xx -> doveadm xx */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen i_fatal("execv("BINDIR"/doveadm) failed: %m");
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen } else if (strcmp(argv[optind], "version") == 0) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen } else if (strcmp(argv[optind], "hostdomain") == 0) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen } else if (strcmp(argv[optind], "build-options") == 0) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen } else if (strcmp(argv[optind], "log-error") == 0) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen fprintf(stderr, "Writing to error logs and killing myself..\n");
bddd52cb7f3e5a894c080f60750aa76b5aeaf103Timo Sirainen i_fatal("execv("BINDIR"/doveadm) failed: %m");
bddd52cb7f3e5a894c080f60750aa76b5aeaf103Timo Sirainen } else if (strcmp(argv[optind], "help") == 0) {
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen i_fatal("Unknown argument: --%s", argv[optind]);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen fd_close_on_exec(global_master_dead_pipe_fd[0], TRUE);
651fc0f1e43fef3e02e0e7b5f498973b05f641d7Timo Sirainen fd_close_on_exec(global_master_dead_pipe_fd[1], TRUE);
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen t_askpass("Give the password for SSL keys: ");
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen if (!foreground && dup2(dev_null_fd, STDOUT_FILENO) < 0)
20261d71760e4199cb8d906ab9704a4561d954d7Timo Sirainen i_strconcat(set->base_dir, "/"MASTER_PID_FILE_NAME, NULL);
20261d71760e4199cb8d906ab9704a4561d954d7Timo Sirainen master_service_init_log(master_service, "master: ");
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen i_get_failure_handlers(&orig_fatal_callback, &orig_error_callback,
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen /* create service structures from settings. if there are any errors in
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen service configuration we'll catch it here. */
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen if (services_create(set, &services, &error) < 0)
91d4c7b37580b031ed7b0154ae10c643521803f3Timo Sirainen services->config->config_file_path = get_full_config_path(services);
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen /* if any listening fails, fail completely */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_fatal("chdir(%s) failed: %m", set->base_dir);