service-process.c revision 41ee23907b084da5baed459e35bccd5a33430419
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen/* Copyright (c) 2005-2016 Dovecot authors, see the included COPYING file */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void service_reopen_inet_listeners(struct service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i, count;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen listeners = array_get(&service->listeners, &count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < count; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!listeners[i]->reuse_port || listeners[i]->fd == -1)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service_listener_listen(listeners[i]) < 0)
230ef558135f16a66b86cbe3762524eaa9ae9d81Timo Sirainen /* stdin/stdout is already redirected to /dev/null. Other master fds
230ef558135f16a66b86cbe3762524eaa9ae9d81Timo Sirainen should have been opened with fd_close_on_exec() so we don't have to
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen worry about them.
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen because the destination fd might be another one's source fd we have
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen to be careful not to overwrite anything. dup() the fd when needed */
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen listeners = array_get(&service->listeners, &count);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen dup2_append(&dups, service_anvil_global->log_fdpass_fd[0],
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen /* nonblocking anvil fd must be the first one. anvil treats it
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen as the master's fd */
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen dup2_append(&dups, service_anvil_global->nonblocking_fd[0], fd++);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen dup2_append(&dups, service_anvil_global->blocking_fd[0], fd++);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen /* add listeners */
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen for (i = 0; i < count; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append_tabescaped(listener_settings, listeners[i]->name);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (listeners[i]->type == SERVICE_LISTENER_INET) {
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen env_put(t_strdup_printf("SOCKET%d_SETTINGS=%s",
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen socket_listener_count, str_c(listener_settings)));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, dev_null_fd, MASTER_ANVIL_FD);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, service_anvil_global->blocking_fd[1],
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, service->status_fd[1], MASTER_STATUS_FD);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, service->master_dead_pipe_fd[1],
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, global_master_dead_pipe_fd[1],
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen /* keep stderr as-is. this is especially important when
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen log_path=/dev/stderr, but might be helpful even in other
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen situations for logging startup errors */
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen /* set log file to stderr. dup2() here immediately so that
e1f866daa1bd1a5cd7516f3b19c6f197bcf6cc8aTimo Sirainen we can set up logging to it without causing any log messages
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen to be lost. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (dup2(service->log_fd[1], STDERR_FILENO) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* make sure we don't leak syslog fd. try to do it as late as possible,
e1f866daa1bd1a5cd7516f3b19c6f197bcf6cc8aTimo Sirainen but also before dup2()s in case syslog fd is one of them. */
e1f866daa1bd1a5cd7516f3b19c6f197bcf6cc8aTimo Sirainen i_fatal("service(%s): dup2s failed", service->set->name);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(fd == MASTER_LISTEN_FD_FIRST + (int)socket_listener_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf("SOCKET_COUNT=%d", socket_listener_count));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int len;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.privileged_gid = service->privileged_gid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.chroot_dir = *service->set->chroot == '\0' ? NULL :
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* drop trailing / if it exists */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.chroot_dir = t_strndup(rset.chroot_dir, len-1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen disallow_root = service->type == SERVICE_TYPE_LOGIN;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void service_process_setup_config_environment(struct service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct master_service_settings *set = service->list->service_set;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat(MASTER_CONFIG_FILE_ENV"=",
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen /* give the log's configuration directly, so it won't depend
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen on config process */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat("LOG_PATH=", set->log_path, NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat("INFO_LOG_PATH=", set->info_log_path, NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat("DEBUG_LOG_PATH=", set->debug_log_path, NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat("LOG_TIMESTAMP=", set->log_timestamp, NULL));
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen env_put(t_strconcat("SYSLOG_FACILITY=", set->syslog_facility, NULL));
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen env_put(t_strconcat(MASTER_CONFIG_FILE_ENV"=",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen services_get_config_socket_path(service->list), NULL));
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainenservice_process_setup_environment(struct service *service, unsigned int uid,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_setup_config_environment(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf(MASTER_CLIENT_LIMIT_ENV"=%u",
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen env_put(t_strdup_printf(MASTER_PROCESS_LIMIT_ENV"=%u",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf(MASTER_PROCESS_MIN_AVAIL_ENV"=%u",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf(MASTER_SERVICE_IDLE_KILL_ENV"=%u",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf(MASTER_SERVICE_COUNT_ENV"=%u",
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen env_put(t_strdup_printf(MASTER_UID_ENV"=%u", uid));
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen env_put(t_strdup_printf(MY_HOSTNAME_ENV"=%s", my_hostname));
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen env_put(t_strdup_printf(MY_HOSTDOMAIN_ENV"=%s", hostdomain));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!service->set->master_set->version_ignore)
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen env_put(MASTER_DOVECOT_VERSION_ENV"="PACKAGE_VERSION);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen if (ssl_manual_key_password != NULL && service->have_inet_listeners) {
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen /* manually given SSL password. give it only to services
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen that have inet listeners. */
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen env_put(t_strconcat(MASTER_SSL_KEY_PASSWORD_ENV"=",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void service_process_status_timeout(struct service_process *process)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Initial status notification not received in %d "
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen "seconds, killing the process",
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (kill(process->pid, SIGKILL) < 0 && errno != ESRCH) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_error(process->service, "kill(%s, SIGKILL) failed: %m",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstruct service_process *service_process_create(struct service *service)
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen static unsigned int uid_counter = 0;
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen /* throttling service, don't create new processes */
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen /* these services are being destroyed, no point in creating
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen new processes now */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* look this up before fork()ing so that it gets cached for all the
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen future lookups. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_setup_environment(service, uid, hostdomain);
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen i_assert(hash_table_lookup(service_pids, POINTER_CAST(pid)) == NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen timeout_add(SERVICE_FIRST_STATUS_TIMEOUT_SECS * 1000,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->available_count = service->client_limit;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hash_table_insert(service_pids, POINTER_CAST(process->pid), process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->type == SERVICE_TYPE_ANVIL && process_forked)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid service_process_destroy(struct service_process *process)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service_list *service_list = service->list;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hash_table_remove(service_pids, POINTER_CAST(process->pid));
61618d4c58080570f689614fec204ae14e90cef2Timo Sirainen i_assert(service->process_avail <= service->process_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_notify_add(service->list->log_byes, process);
129db31de1780783a175633eba5811e44c361a81Timo Sirainen if (service->process_count < service->process_limit &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid service_process_ref(struct service_process *process)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid service_process_unref(struct service_process *process)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic const char *
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenget_exit_status_message(struct service *service, enum fatal_exit_status status)
63849db64682675a2fd3e1aea05c10ecbc6d473aTimo Sirainen return "Can't open log file";
63849db64682675a2fd3e1aea05c10ecbc6d473aTimo Sirainen return "Can't write to log file";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return "Internal logging error";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, " (service %s { vsz_limit=%u MB }, "
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "you may need to increase it)",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (unsigned int)(service->vsz_limit/1024/1024));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append(str, " - set CORE_OUTOFMEM=1 environment to get core dump");
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen return "exec() failed";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return "Fatal failure";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenlog_coredump(struct service *service, string_t *str, int status)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (signum != SIGABRT && signum != SIGSEGV && signum != SIGBUS)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* let's try to figure out why we didn't get a core dump */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!service->set->drop_priv_before_exec && service->uid != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, " (core not dumped - set service %s "
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen "{ drop_priv_before_exec=yes })",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (*service->set->privileged_group != '\0' && service->uid != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, " (core not dumped - service %s "
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "{ privileged_group } prevented it)",
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen str_printfa(str, " (core not dumped - add -D parameter to "
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "service %s { executable }", service->set->name);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, " (core not dumped - try to clear "
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "service %s { chroot = } )", service->set->name);
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainenservice_process_get_status_error(string_t *str, struct service_process *process,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *msg;
if (status == 0) {
const char *data;
int status)
T_BEGIN {
bool default_fatal;
} T_END;