service-process.c revision 114162093a3eb36c23a4ce4d4f2a43541dc18cc2
/* Copyright (c) 2005-2010 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 "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 <grp.h>
#include <pwd.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <syslog.h>
#include <signal.h>
static void
{
struct service_listener *const *listeners;
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:
i_assert(n == 0);
n += socket_listener_count;
break;
case SERVICE_TYPE_ANVIL:
/* nonblocking anvil fd must be the first one. anvil treats it
as the master's fd */
MASTER_LISTEN_FD_FIRST + n++);
MASTER_LISTEN_FD_FIRST + n++);
socket_listener_count += 2;
break;
default:
break;
}
/* first add non-ssl listeners */
for (i = 0; i < count; i++) {
MASTER_LISTEN_FD_FIRST + n);
n++; socket_listener_count++;
}
}
/* then ssl-listeners */
ssl_socket_count = 0;
for (i = 0; i < count; i++) {
MASTER_LISTEN_FD_FIRST + n);
n++; socket_listener_count++;
}
}
}
case SERVICE_TYPE_LOG:
case SERVICE_TYPE_ANVIL:
case SERVICE_TYPE_CONFIG:
break;
case SERVICE_TYPE_UNKNOWN:
case SERVICE_TYPE_LOGIN:
break;
}
/* 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");
} else {
}
/* 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 */
}
} else {
}
}
static void
{
const char *const *p;
/* remove all environment, and put back what we need */
env_clean();
env_put(*p);
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");
break;
default:
break;
}
service->client_limit));
}
/* manually given SSL password. give it only to services
that have inet listeners. */
}
}
{
"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;
}
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 TRUE;
return FALSE;
}
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 (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
return;
}
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;
}