service-process.c revision 2047bbce87d1a1adc281a875814390bdc9532946
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březinastatic void service_reopen_inet_listeners(struct service *service)
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina unsigned int i, count;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina listeners = array_get(&service->listeners, &count);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina for (i = 0; i < count; i++) {
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (!listeners[i]->reuse_port || listeners[i]->fd == -1)
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (service_listener_listen(listeners[i]) < 0)
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina /* stdin/stdout is already redirected to /dev/null. Other master fds
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina should have been opened with fd_close_on_exec() so we don't have to
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina worry about them.
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina because the destination fd might be another one's source fd we have
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina to be careful not to overwrite anything. dup() the fd when needed */
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina listeners = array_get(&service->listeners, &count);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina dup2_append(&dups, service_anvil_global->log_fdpass_fd[0],
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina /* nonblocking anvil fd must be the first one. anvil treats it
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina as the master's fd */
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina dup2_append(&dups, service_anvil_global->nonblocking_fd[0], fd++);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina dup2_append(&dups, service_anvil_global->blocking_fd[0], fd++);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina /* add listeners */
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina for (i = 0; i < count; i++) {
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina str_append_tabescaped(listener_settings, listeners[i]->name);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (listeners[i]->type == SERVICE_LISTENER_INET) {
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina env_put(t_strdup_printf("SOCKET%d_SETTINGS=%s",
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina socket_listener_count, str_c(listener_settings)));
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina dup2_append(&dups, dev_null_fd, MASTER_ANVIL_FD);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina dup2_append(&dups, service_anvil_global->blocking_fd[1],
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina dup2_append(&dups, service->status_fd[1], MASTER_STATUS_FD);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina dup2_append(&dups, service->master_dead_pipe_fd[1],
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina dup2_append(&dups, global_master_dead_pipe_fd[1],
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina /* keep stderr as-is. this is especially important when
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina log_path=/dev/stderr, but might be helpful even in other
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina situations for logging startup errors */
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina /* set log file to stderr. dup2() here immediately so that
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina we can set up logging to it without causing any log messages
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina to be lost. */
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina if (dup2(service->log_fd[1], STDERR_FILENO) < 0)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina /* make sure we don't leak syslog fd. try to do it as late as possible,
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina but also before dup2()s in case syslog fd is one of them. */
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina i_fatal("service(%s): dup2s failed", service->set->name);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina i_assert(fd == MASTER_LISTEN_FD_FIRST + (int)socket_listener_count);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina env_put(t_strdup_printf("SOCKET_COUNT=%d", socket_listener_count));
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina rset.privileged_gid = service->privileged_gid;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina rset.chroot_dir = *service->set->chroot == '\0' ? NULL :
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina /* drop trailing / if it exists */
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina rset.chroot_dir = t_strndup(rset.chroot_dir, len-1);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina allow_root = service->type != SERVICE_TYPE_LOGIN;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina allow_root ? RESTRICT_ACCESS_FLAG_ALLOW_ROOT : 0,
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březinastatic void service_process_setup_config_environment(struct service *service)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina const struct master_service_settings *set = service->list->service_set;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina env_put(t_strconcat(MASTER_CONFIG_FILE_ENV"=",
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina /* give the log's configuration directly, so it won't depend
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina on config process */
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina env_put(t_strconcat("LOG_PATH=", set->log_path, NULL));
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina env_put(t_strconcat("INFO_LOG_PATH=", set->info_log_path, NULL));
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina env_put(t_strconcat("DEBUG_LOG_PATH=", set->debug_log_path, NULL));
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina env_put(t_strconcat("LOG_TIMESTAMP=", set->log_timestamp, NULL));
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina env_put(t_strconcat("SYSLOG_FACILITY=", set->syslog_facility, NULL));
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina env_put(t_strconcat(MASTER_CONFIG_FILE_ENV"=",
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina services_get_config_socket_path(service->list), NULL));
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březinaservice_process_setup_environment(struct service *service, unsigned int uid,
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service_process_setup_config_environment(service);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina env_put(t_strdup_printf(MASTER_CLIENT_LIMIT_ENV"=%u",
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina env_put(t_strdup_printf(MASTER_PROCESS_LIMIT_ENV"=%u",
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina env_put(t_strdup_printf(MASTER_PROCESS_MIN_AVAIL_ENV"=%u",
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina env_put(t_strdup_printf(MASTER_SERVICE_IDLE_KILL_ENV"=%u",
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina env_put(t_strdup_printf(MASTER_SERVICE_COUNT_ENV"=%u",
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina env_put(t_strdup_printf(MASTER_UID_ENV"=%u", uid));
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina env_put(t_strdup_printf(MY_HOSTNAME_ENV"=%s", my_hostname));
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina env_put(t_strdup_printf(MY_HOSTDOMAIN_ENV"=%s", hostdomain));
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina if (!service->set->master_set->version_ignore)
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina env_put(MASTER_DOVECOT_VERSION_ENV"="PACKAGE_VERSION);
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina if (ssl_manual_key_password != NULL && service->have_inet_listeners) {
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina /* manually given SSL password. give it only to services
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina that have inet listeners. */
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina env_put(t_strconcat(MASTER_SSL_KEY_PASSWORD_ENV"=",
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service->list->service_set->log_debug, NULL));
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březinastatic void service_process_status_timeout(struct service_process *process)
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina "Initial status notification not received in %d "
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina "seconds, killing the process",
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek if (kill(process->pid, SIGKILL) < 0 && errno != ESRCH) {
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek service_error(process->service, "kill(%s, SIGKILL) failed: %m",
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březinastruct service_process *service_process_create(struct service *service)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina static unsigned int uid_counter = 0;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina /* throttling service, don't create new processes */
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina /* these services are being destroyed, no point in creating
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina new processes now */
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina /* look this up before fork()ing so that it gets cached for all the
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina future lookups. */
if (pid < 0) {
(unsigned long long)limit);
return NULL;
if (pid == 0) {
if (process_forked) {
return process;
switch (status) {
case FATAL_LOGOPEN:
case FATAL_LOGWRITE:
case FATAL_LOGERROR:
case FATAL_OUTOFMEM:
case FATAL_EXEC:
case FATAL_DEFAULT:
return NULL;
#ifdef WCOREDUMP
if (core_dumps_disabled) {
#ifndef HAVE_PR_SET_DUMPABLE
const char *msg;
if (status == 0) {
const char *data;
int status)
T_BEGIN {
bool default_fatal;
} T_END;