service.c revision 2d06f521ae13ba145fe4e60bfbf7afaf1cdebaed
/* Copyright (c) 2005-2012 Dovecot authors, see the included COPYING file */
#include "common.h"
#include "ioloop.h"
#include "array.h"
#include "aqueue.h"
#include "hash.h"
#include "str.h"
#include "master-service.h"
#include "master-service-settings.h"
#include "service.h"
#include "service-anvil.h"
#include "service-process.h"
#include "service-monitor.h"
#include <unistd.h>
#include <signal.h>
#define SERVICE_LOGIN_NOTIFY_MIN_INTERVAL_SECS 2
{
}
static struct service_listener *
enum service_listener_type type,
const struct file_listener_settings *set,
const char **error_r)
{
struct service_listener *l;
const char *set_name;
l->fd = -1;
l->name++;
else
set_name = "user";
set_name = "group";
else
return l;
"%s (See service %s { %s_listener %s { %s } } setting)",
return NULL;
}
static int
unsigned int *ips_count_r, const char **error_r)
{
unsigned int ips_count;
int ret;
/* IPv4 any */
*ips_count_r = 1;
return 0;
}
/* IPv6 any */
*ips_count_r = 1;
return 0;
}
/* Return the first IP if there happens to be multiple. */
if (ret != 0) {
return -1;
}
if (ips_count < 1) {
return -1;
}
*ips_count_r = ips_count;
return 0;
}
static struct service_listener *
const struct inet_listener_settings *set,
const char **error_r)
{
struct service_listener *l;
l->type = SERVICE_LISTENER_INET;
l->fd = -1;
return NULL;
}
return l;
}
static int
const struct inet_listener_settings *set,
const char **error_r)
{
static struct service_listener *l;
unsigned int i, ips_count;
/* disabled */
return 0;
}
else {
/* use the default listen address */
}
continue;
return -1;
for (i = 0; i < ips_count; i++) {
error_r);
if (l == NULL)
return -1;
}
}
return 0;
}
{
const char *const *tmp;
return -1;
}
return 0;
}
static struct service *
{
struct file_listener_settings *const *unix_listeners;
struct file_listener_settings *const *fifo_listeners;
struct inet_listener_settings *const *inet_listeners;
struct service_listener *l;
if (set->service_count > 0 &&
if (set->process_limit == 0) {
/* use default */
} else {
}
/* default gid to user's primary group */
switch (set->user_default) {
"%s (See service %s { user } setting)",
break;
" (See default_internal_user setting)", NULL);
break;
" (See default_login_user setting)", NULL);
break;
}
return NULL;
}
"%s (See service %s { group } setting)",
return NULL;
}
}
error_r) < 0) {
"%s (See service %s { privileged_group } setting)",
return NULL;
}
"%s (See service %s { extra_groups } setting)",
return NULL;
}
}
/* set these later, so if something fails we don't have to worry about
closing them */
}
else {
unix_count = 0;
}
else {
fifo_count = 0;
}
else {
inet_count = 0;
}
*error_r = "Service must have unix listeners";
return NULL;
}
for (i = 0; i < unix_count; i++) {
if (unix_listeners[i]->mode == 0) {
/* disabled */
continue;
}
unix_listeners[i], error_r);
if (l == NULL)
return NULL;
}
for (i = 0; i < fifo_count; i++) {
if (fifo_listeners[i]->mode == 0) {
/* disabled */
continue;
}
fifo_listeners[i], error_r);
if (l == NULL)
return NULL;
}
for (i = 0; i < inet_count; i++) {
error_r) < 0)
return NULL;
}
return NULL;
}
return service;
}
struct service *
{
return service;
}
return NULL;
}
struct service *
{
return service;
}
return NULL;
}
{
char *const *proto;
/* silently allow service {} blocks for disabled extensions
(e.g. service managesieve {} block without pigeonhole
installed) */
return FALSE;
}
return TRUE;
return TRUE;
}
return FALSE;
}
static int
{
struct service_list *service_list;
struct service_settings *const *service_settings;
const char *error;
unsigned int i, count;
for (i = 0; i < count; i++) {
if (!service_want(service_settings[i]))
continue;
service_list, &error);
return -1;
}
case SERVICE_TYPE_LOG:
*error_r = "Multiple log services specified";
return -1;
}
break;
case SERVICE_TYPE_CONFIG:
*error_r = "Multiple config services specified";
return -1;
}
break;
case SERVICE_TYPE_ANVIL:
*error_r = "Multiple anvil services specified";
return -1;
}
break;
default:
break;
}
}
*error_r = "log service not specified";
return -1;
}
*error_r = "config process not specified";
return -1;
}
return 0;
}
{
pool_unref(&pool);
return -1;
}
return 0;
}
{
if (!SERVICE_PROCESS_IS_INITIALIZED(process) &&
/* too early to signal it */
continue;
}
}
}
}
{
}
{
}
{
enum master_login_state state;
int diff;
return;
/* change the state always immediately. it's cheap. */
/* but don't send signal to processes too often */
return;
service);
} else {
}
}
{
bool sigterm_log;
int sig;
else
i_warning("Processes aren't dying after reload, sending %s.",
log_service = NULL;
else
}
/* kill log service later so it could still have a chance of logging
something */
}
}
{
/* make sure we log if child processes died unexpectedly */
}
}
{
service_list->refcount++;
}
{
if (--service_list->refcount > 0)
return;
}
{
struct service_listener *const *listeners;
unsigned int count;
}
{
}
{
struct service_listener *const *listenerp;
int fd;
case SERVICE_LISTENER_UNIX:
case SERVICE_LISTENER_INET:
/* already stopped listening */
break;
}
i_close_fd(&fd);
break;
case SERVICE_LISTENER_FIFO:
break;
}
}
}
{
return;
}
unsigned int secs)
{
}
}
void service_pids_init(void)
{
}
void service_pids_deinit(void)
{
struct hash_iterate_context *iter;
void *key;
struct service_process *process;
/* free all child process information */
}