main.c revision 16e1bc9ee262481ec8bf6a1afbb539d1c2723912
/* Copyright (c) 2005-2013 Dovecot authors, see the included COPYING file */
#include "common.h"
#include "ioloop.h"
#include "lib-signals.h"
#include "fd-close-on-exec.h"
#include "array.h"
#include "write-full.h"
#include "env-util.h"
#include "hostpid.h"
#include "abspath.h"
#include "ipwd.h"
#include "execv-const.h"
#include "mountpoint-list.h"
#include "restrict-process-size.h"
#include "master-instance.h"
#include "master-service.h"
#include "master-service-settings.h"
#include "askpass.h"
#include "capabilities.h"
#include "service.h"
#include "service-anvil.h"
#include "service-listen.h"
#include "service-monitor.h"
#include "service-process.h"
#include "service-log.h"
#include "dovecot-version.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#define MASTER_SERVICE_NAME "master"
#define FATAL_FILENAME "master-fatal.lastlog"
#define MASTER_PID_FILE_NAME "master.pid"
bool core_dumps_disabled;
const char *ssl_manual_key_password;
struct service_list *services;
static char *pidfile_path;
static struct master_instance_list *instances;
static struct timeout *to_instance;
static failure_callback_t *orig_fatal_callback;
static failure_callback_t *orig_error_callback;
static const struct setting_parser_info *set_roots[] = {
};
{
const char *executable, *p, **argv;
executable = argv[0];
if (extra_args != NULL) {
const char **new_argv;
/* @UNSAFE */
sizeof(const char *) * count2);
}
/* hide the path, it's ugly */
/* prefix with dovecot/ */
argv[0]);
}
const char **error_r)
{
if (*user == '\0') {
return 0;
}
case -1:
return -1;
case 0:
return -1;
default:
return 0;
}
}
{
if (*group == '\0') {
return 0;
}
case -1:
return -1;
case 0:
return -1;
default:
return 0;
}
}
{
int fd;
/* if we already forked a child process, this isn't fatal for the
main process and there's no need to write the fatal file. */
/* write the error message to a file (we're chdired to
base dir) */
if (fd != -1) {
i_close_fd(&fd);
}
}
abort(); /* just to silence the noreturn attribute warnings */
}
{
abort();
}
static void ATTR_FORMAT(2, 0)
{
}
{
const char *path;
char buf[1024];
int fd;
if (fd == -1)
return;
if (ret < 0)
else {
"information): %s\n", buf);
}
}
{
char buf[32];
int fd;
bool found;
if (fd == -1) {
return FALSE;
}
if (ret <= 0) {
if (ret == 0)
else
} else {
ret--;
}
i_close_fd(&fd);
return found;
}
static void pid_file_check_running(const char *path)
{
return;
i_fatal("Dovecot is already running with PID %s "
}
static void create_pid_file(const char *path)
{
const char *pid;
int fd;
if (fd == -1)
i_close_fd(&fd);
}
{
const char *base_config_path;
i_error("symlink(%s, %s) failed: %m",
}
}
{
struct mountpoint_list_iter *iter;
struct mountpoint_list_rec *rec;
/* warn about mountpoints that no longer exist */
if (MOUNTPOINT_WRONGLY_NOT_MOUNTED(rec)) {
i_warning("%s is no longer mounted. "
rec->mount_path);
}
}
}
{
struct mountpoint_list *mountpoints;
const char *perm_path, *state_path;
(void)mountpoint_list_save(mountpoints);
}
{
int ret;
if (ret == 0) {
/* duplicate instance names. allow without warning.. */
}
if (to_instance != NULL)
}
{
const char *path;
}
static void
void *context ATTR_UNUSED)
{
struct master_service_settings_input input;
struct master_service_settings_output output;
const struct master_settings *set;
void **sets;
struct service_list *new_services;
const char *error;
i_warning("SIGHUP received - reloading configuration");
/* see if hostname changed */
hostpid_init();
/* we can't reload config if there's no config process. */
i_error("Can't reload configuration because "
"we couldn't create a config process");
return;
}
}
return;
}
/* new configuration is invalid, keep the old */
return;
}
/* switch to new configuration. */
return;
}
/* anvil never dies. it just gets moved to the new services list */
}
}
static void
{
}
static void
{
}
{
i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
}
static struct master_settings *master_settings_read(void)
{
struct master_service_settings_input input;
struct master_service_settings_output output;
const char *error;
&error) < 0)
return master_service_settings_get_others(master_service)[0];
}
{
return;
else {
}
}
}
static void main_log_startup(void)
{
core_limit == 0;
if (core_dumps_disabled)
else
}
static void master_set_process_limit(void)
{
unsigned int process_limit = 0;
/* we'll just count all the processes that can exist and set the
process limit so that we won't reach it. it's usually higher than
needed, since we'd only need to set it high enough for each
separate UID not to reach the limit, but this is difficult to
guess: mail processes should probably be counted together for a
common vmail user (unless system users are being used), but
we can't really guess what the mail processes are. */
if (restrict_get_process_limit(&nproc) == 0 &&
}
{
/* deny file access from everyone else except owner */
(void)umask(0077);
}
static void global_dead_pipe_close(void)
{
if (close(global_master_dead_pipe_fd[0]) < 0)
i_error("close(global dead pipe) failed: %m");
i_error("close(global dead pipe) failed: %m");
global_master_dead_pipe_fd[0] = -1;
}
static void main_deinit(void)
{
/* kill services and wait for them to die before unlinking pid file */
if (unlink(pidfile_path) < 0)
}
{
const char *path;
if (*path == '/')
return path;
}
{
unsigned long secs;
return;
/* time moved backwards. disable launching new service processes
until */
i_warning("Time moved backwards by %lu seconds, "
"waiting for %lu secs until new services are launched again.",
}
static void daemonize(void)
{
if (pid < 0)
i_fatal("fork() failed: %m");
if (pid != 0)
_exit(0);
if (setsid() < 0)
i_fatal("setsid() failed: %m");
/* update my_pid */
hostpid_init();
}
static void print_help(void)
{
"Usage: dovecot [-F] [-c <config file>] [-p] [-n] [-a] [--help] [--version]\n"
" [--build-options] [reload] [stop]\n");
}
static void print_build_options(void)
{
printf("Build options:"
#ifdef IOLOOP_EPOLL
" ioloop=epoll"
#endif
#ifdef IOLOOP_KQUEUE
" ioloop=kqueue"
#endif
#ifdef IOLOOP_POLL
" ioloop=poll"
#endif
#ifdef IOLOOP_SELECT
" ioloop=select"
#endif
#ifdef IOLOOP_NOTIFY_DNOTIFY
" notify=dnotify"
#endif
#ifdef IOLOOP_NOTIFY_INOTIFY
" notify=inotify"
#endif
#ifdef IOLOOP_NOTIFY_KQUEUE
" notify=kqueue"
#endif
#ifdef HAVE_IPV6
" ipv6"
#endif
#ifdef HAVE_GNUTLS
" gnutls"
#endif
#ifdef HAVE_OPENSSL
" openssl"
#endif
" io_block_size=%u"
#ifdef SQL_DRIVER_PLUGINS
"SQL driver plugins:"
#else
"SQL drivers:"
#endif
#ifdef BUILD_MYSQL
" mysql"
#endif
#ifdef BUILD_PGSQL
" postgresql"
#endif
#ifdef BUILD_SQLITE
" sqlite"
#endif
"\nPassdb:"
#ifdef PASSDB_BSDAUTH
" bsdauth"
#endif
#ifdef PASSDB_CHECKPASSWORD
" checkpassword"
#endif
#ifdef PASSDB_LDAP
" ldap"
#endif
#ifdef PASSDB_PAM
" pam"
#endif
#ifdef PASSDB_PASSWD
" passwd"
#endif
#ifdef PASSDB_PASSWD_FILE
" passwd-file"
#endif
#ifdef PASSDB_SHADOW
" shadow"
#endif
#ifdef PASSDB_SQL
" sql"
#endif
#ifdef PASSDB_VPOPMAIL
" vpopmail"
#endif
"\nUserdb:"
#ifdef USERDB_CHECKPASSWORD
" checkpassword"
#endif
#ifdef USERDB_LDAP
" ldap"
#ifndef BUILTIN_LDAP
"(plugin)"
#endif
#endif
#ifdef USERDB_NSS
" nss"
#endif
#ifdef USERDB_PASSWD
" passwd"
#endif
#ifdef USERDB_PREFETCH
" prefetch"
#endif
#ifdef USERDB_PASSWD_FILE
" passwd-file"
#endif
#ifdef USERDB_SQL
" sql"
#endif
#ifdef USERDB_STATIC
" static"
#endif
#ifdef USERDB_VPOPMAIL
" vpopmail"
#endif
"\n", IO_BLOCK_SIZE);
}
{
struct master_settings *set;
bool doubleopts[argc];
int i, c;
#ifdef DEBUG
#endif
/* drop -- prefix from all --args. ugly, but the only way that it
works with standard getopt() in all OSes.. */
for (i = 1; i < argc; i++) {
break;
argv[i] += 2;
doubleopts[i] = TRUE;
} else {
doubleopts[i] = FALSE;
}
}
master_uid = geteuid();
master_gid = getegid();
while ((c = master_getopt(master_service)) > 0) {
switch (c) {
case 'F':
foreground = TRUE;
break;
case 'a':
doveconf_arg = "-a";
break;
case 'n':
doveconf_arg = "-n";
break;
case 'p':
/* Ask SSL private key password */
ask_key_pass = TRUE;
break;
default:
c, optarg)) {
print_help();
}
break;
}
}
if (doveconf_arg != NULL) {
const char **args;
args[0] = DOVECOT_CONFIG_BIN_PATH;
}
/* starting Dovecot */
} else if (!doubleopts[optind]) {
/* dovecot xx -> doveadm xx */
return 0;
return 0;
print_help();
return 0;
} else {
print_help();
}
do {
if (null_fd == -1)
} while (null_fd <= STDERR_FILENO);
if (pipe(global_master_dead_pipe_fd) < 0)
i_fatal("pipe() failed: %m");
set = master_settings_read();
if (ask_key_pass) {
t_askpass("Give the password for SSL keys: ");
}
i_fatal("dup2(null_fd) failed: %m");
T_BEGIN {
} T_END;
/* create service structures from settings. if there are any errors in
service configuration we'll catch it here. */
/* if any listening fails, fail completely */
if (services_listen(services) <= 0)
i_fatal("Failed to start listeners");
if (!foreground)
daemonize();
T_BEGIN {
} T_END;
main_deinit();
return 0;
}