service-process.c revision d4845c4245638fd6f02dc0cb92c3465fae763cbb
/* Copyright (c) 2005-2013 Dovecot authors, see the included COPYING file */
#include "common.h"
#include "array.h"
#include "aqueue.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "write-full.h"
#include "base64.h"
#include "hash.h"
#include "str.h"
#include "strescape.h"
#include "llist.h"
#include "hostpid.h"
#include "env-util.h"
#include "fd-close-on-exec.h"
#include "restrict-access.h"
#include "restrict-process-size.h"
#include "eacces-error.h"
#include "master-service.h"
#include "master-service-settings.h"
#include "dup2-array.h"
#include "service.h"
#include "service-anvil.h"
#include "service-log.h"
#include "service-process-notify.h"
#include "service-process.h"
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <syslog.h>
#include <signal.h>
static void
{
struct service_listener *const *listeners;
int fd = MASTER_LISTEN_FD_FIRST;
should have been opened with fd_close_on_exec() so we don't have to
worry about them.
because the destination fd might be another one's source fd we have
to be careful not to overwrite anything. dup() the fd when needed */
case SERVICE_TYPE_LOG:
break;
case SERVICE_TYPE_ANVIL:
/* nonblocking anvil fd must be the first one. anvil treats it
as the master's fd */
socket_listener_count += 2;
break;
default:
break;
}
for (i = MASTER_LISTEN_FD_FIRST; i < (unsigned int)fd; i++)
/* first add non-ssl listeners */
for (i = 0; i < count; i++) {
}
}
/* then ssl-listeners */
ssl_socket_count = 0;
for (i = 0; i < count; i++) {
}
}
}
case SERVICE_TYPE_LOG:
case SERVICE_TYPE_ANVIL:
case SERVICE_TYPE_CONFIG:
break;
case SERVICE_TYPE_UNKNOWN:
case SERVICE_TYPE_LOGIN:
case SERVICE_TYPE_STARTUP:
break;
}
} else {
}
/* keep stderr as-is. this is especially important when
situations for logging startup errors */
} else {
/* set log file to stderr. dup2() here immediately so that
we can set up logging to it without causing any log messages
to be lost. */
env_put("LOG_SERVICE=1");
i_fatal("dup2(log fd) failed: %m");
}
/* make sure we don't leak syslog fd. try to do it as late as possible,
but also before dup2()s in case syslog fd is one of them. */
closelog();
if (dup2_array(&dups) < 0)
}
static void
{
struct restrict_access_settings rset;
bool disallow_root;
unsigned int len;
/* drop trailing / if it exists */
}
}
}
{
case SERVICE_TYPE_CONFIG:
break;
case SERVICE_TYPE_LOG:
/* give the log's configuration directly, so it won't depend
on config process */
env_put("DOVECONF_ENV=1");
env_put("SSL=no");
break;
default:
break;
}
}
static void
{
service->client_limit));
service->process_limit));
}
/* manually given SSL password. give it only to services
that have inet listeners. */
}
env_put("ANVIL_RESTARTED=1");
}
{
"Initial status notification not received in %d "
"seconds, killing the process",
}
}
{
static unsigned int uid_counter = 0;
struct service_process *process;
unsigned int uid = ++uid_counter;
bool process_forked;
/* throttling service, don't create new processes */
return NULL;
}
/* these services are being destroyed, no point in creating
new processes now */
return NULL;
}
service_anvil_global->pid != 0) {
} else {
}
if (pid < 0) {
return NULL;
}
if (pid == 0) {
/* child */
}
if (process_forked) {
}
service->process_count++;
service->process_avail++;
return process;
}
{
if (process->available_count > 0)
service->process_avail--;
service->process_count--;
}
{
}
{
return;
}
static const char *
{
switch (status) {
case FATAL_LOGOPEN:
return "Can't open log file";
case FATAL_LOGWRITE:
return "Can't write to log file";
case FATAL_LOGERROR:
return "Internal logging error";
case FATAL_OUTOFMEM:
return "Out of memory";
return t_strdup_printf("Out of memory (service %s { vsz_limit=%u MB }, "
"you may need to increase it)",
case FATAL_EXEC:
return "exec() failed";
case FATAL_DEFAULT:
return "Fatal failure";
}
return NULL;
}
static void
{
#ifdef WCOREDUMP
return;
}
return;
/* let's try to figure out why we didn't get a core dump */
if (core_dumps_disabled) {
return;
}
#ifndef HAVE_PR_SET_DUMPABLE
"{ drop_priv_before_exec=yes })",
return;
}
"{ privileged_group } prevented it)",
return;
}
#else
return;
}
#endif
#endif
}
static void
int status, bool *default_fatal_r)
{
const char *msg;
*default_fatal_r = FALSE;
if (WIFSIGNALED(status)) {
return;
}
return;
}
if (status == 0) {
str_truncate(str, 0);
return;
}
if (status == FATAL_DEFAULT)
*default_fatal_r = TRUE;
}
bool default_fatal, const char *str)
{
const char *data;
return;
}
/* log it via the log process in charge of handling
this process's logging */
i_error("write(log process) failed: %m");
}
}
int status)
{
/* fast path */
return;
}
T_BEGIN {
bool default_fatal;
} T_END;
}