dict-process.c revision 97d4906cf332727cdea5b49cbcbc7638ff600d55
bf40639e42957133fef54f2f0a322061ac37fe90nd/* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd#include "common.h"
bf40639e42957133fef54f2f0a322061ac37fe90nd#include "array.h"
bf40639e42957133fef54f2f0a322061ac37fe90nd#include "ioloop.h"
bf40639e42957133fef54f2f0a322061ac37fe90nd#include "network.h"
bf40639e42957133fef54f2f0a322061ac37fe90nd#include "fd-close-on-exec.h"
bf40639e42957133fef54f2f0a322061ac37fe90nd#include "env-util.h"
bf40639e42957133fef54f2f0a322061ac37fe90nd#include "log.h"
bf40639e42957133fef54f2f0a322061ac37fe90nd#include "child-process.h"
0662ed52e814f8f08ef0e09956413a792584eddffuankg#include "dict-process.h"
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd#include <syslog.h>
bf40639e42957133fef54f2f0a322061ac37fe90nd#include <unistd.h>
bf40639e42957133fef54f2f0a322061ac37fe90nd#include <sys/stat.h>
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd#define DICT_SERVER_SOCKET_NAME "dict-server"
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90ndstruct dict_listener {
bf40639e42957133fef54f2f0a322061ac37fe90nd char *path;
16b55a35cff91315d261d1baa776138af465c4e4fuankg int fd;
16b55a35cff91315d261d1baa776138af465c4e4fuankg struct io *io;
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd struct dict_process *processes;
bf40639e42957133fef54f2f0a322061ac37fe90nd};
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90ndstruct dict_process {
bf40639e42957133fef54f2f0a322061ac37fe90nd struct child_process process;
bf40639e42957133fef54f2f0a322061ac37fe90nd struct dict_process *next;
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd struct dict_listener *listener;
bf40639e42957133fef54f2f0a322061ac37fe90nd struct log_io *log;
bf40639e42957133fef54f2f0a322061ac37fe90nd};
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90ndstatic struct dict_listener *dict_listener;
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90ndstatic int dict_process_create(struct dict_listener *listener)
bf40639e42957133fef54f2f0a322061ac37fe90nd{
bf40639e42957133fef54f2f0a322061ac37fe90nd struct dict_process *process;
bf40639e42957133fef54f2f0a322061ac37fe90nd struct log_io *log;
bf40639e42957133fef54f2f0a322061ac37fe90nd const char *executable, *const *dicts;
bf40639e42957133fef54f2f0a322061ac37fe90nd unsigned int i, count;
bf40639e42957133fef54f2f0a322061ac37fe90nd int log_fd;
bf40639e42957133fef54f2f0a322061ac37fe90nd pid_t pid;
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd process = i_new(struct dict_process, 1);
bf40639e42957133fef54f2f0a322061ac37fe90nd process->process.type = PROCESS_TYPE_DICT;
bf40639e42957133fef54f2f0a322061ac37fe90nd process->listener = listener;
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd log_fd = log_create_pipe(&log, 0);
bf40639e42957133fef54f2f0a322061ac37fe90nd if (log_fd < 0)
bf40639e42957133fef54f2f0a322061ac37fe90nd pid = -1;
bf40639e42957133fef54f2f0a322061ac37fe90nd else {
bf40639e42957133fef54f2f0a322061ac37fe90nd pid = fork();
bf40639e42957133fef54f2f0a322061ac37fe90nd if (pid < 0)
bf40639e42957133fef54f2f0a322061ac37fe90nd i_error("fork() failed: %m");
bf40639e42957133fef54f2f0a322061ac37fe90nd }
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg
bf40639e42957133fef54f2f0a322061ac37fe90nd if (pid < 0) {
bf40639e42957133fef54f2f0a322061ac37fe90nd (void)close(log_fd);
bf40639e42957133fef54f2f0a322061ac37fe90nd i_free(process);
bf40639e42957133fef54f2f0a322061ac37fe90nd return -1;
bf40639e42957133fef54f2f0a322061ac37fe90nd }
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd if (pid != 0) {
bf40639e42957133fef54f2f0a322061ac37fe90nd /* master */
bf40639e42957133fef54f2f0a322061ac37fe90nd process->next = process->listener->processes;
bf40639e42957133fef54f2f0a322061ac37fe90nd process->listener->processes = process;
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd child_process_add(pid, &process->process);
bf40639e42957133fef54f2f0a322061ac37fe90nd log_set_prefix(log, "dict: ");
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg log_set_pid(log, pid);
bf40639e42957133fef54f2f0a322061ac37fe90nd (void)close(log_fd);
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd process->log = log;
bf40639e42957133fef54f2f0a322061ac37fe90nd log_ref(process->log);
bf40639e42957133fef54f2f0a322061ac37fe90nd return 0;
bf40639e42957133fef54f2f0a322061ac37fe90nd }
bf40639e42957133fef54f2f0a322061ac37fe90nd log_set_prefix(log, "master-dict: ");
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd /* set stdin and stdout to /dev/null, so anything written into it
bf40639e42957133fef54f2f0a322061ac37fe90nd gets ignored. */
bf40639e42957133fef54f2f0a322061ac37fe90nd if (dup2(null_fd, 0) < 0)
bf40639e42957133fef54f2f0a322061ac37fe90nd i_fatal("dup2(stdin) failed: %m");
bf40639e42957133fef54f2f0a322061ac37fe90nd if (dup2(null_fd, 1) < 0)
bf40639e42957133fef54f2f0a322061ac37fe90nd i_fatal("dup2(stdout) failed: %m");
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd /* stderr = log, 3 = listener */
bf40639e42957133fef54f2f0a322061ac37fe90nd if (dup2(log_fd, 2) < 0)
bf40639e42957133fef54f2f0a322061ac37fe90nd i_fatal("dup2(stderr) failed: %m");
bf40639e42957133fef54f2f0a322061ac37fe90nd if (dup2(process->listener->fd, 3) < 0)
bf40639e42957133fef54f2f0a322061ac37fe90nd i_fatal("dup2(3) failed: %m");
bf40639e42957133fef54f2f0a322061ac37fe90nd
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg for (i = 0; i <= 3; i++)
bf40639e42957133fef54f2f0a322061ac37fe90nd fd_close_on_exec(i, FALSE);
bf40639e42957133fef54f2f0a322061ac37fe90nd
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg child_process_init_env();
bf40639e42957133fef54f2f0a322061ac37fe90nd env_put(t_strconcat("DICT_LISTEN_FROM_FD=",
bf40639e42957133fef54f2f0a322061ac37fe90nd process->listener->path, NULL));
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd if (settings_root->defaults->dict_db_config != NULL) {
bf40639e42957133fef54f2f0a322061ac37fe90nd env_put(t_strconcat("DB_CONFIG=",
bf40639e42957133fef54f2f0a322061ac37fe90nd settings_root->defaults->dict_db_config,
bf40639e42957133fef54f2f0a322061ac37fe90nd NULL));
bf40639e42957133fef54f2f0a322061ac37fe90nd }
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd dicts = array_get(&settings_root->dicts, &count);
bf40639e42957133fef54f2f0a322061ac37fe90nd i_assert((count % 2) == 0);
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg for (i = 0; i < count; i += 2)
0662ed52e814f8f08ef0e09956413a792584eddffuankg env_put(t_strdup_printf("DICT_%s=%s", dicts[i], dicts[i+1]));
bf40639e42957133fef54f2f0a322061ac37fe90nd
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg /* make sure we don't leak syslog fd, but do it last so that
bf40639e42957133fef54f2f0a322061ac37fe90nd any errors above will be logged */
bf40639e42957133fef54f2f0a322061ac37fe90nd closelog();
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd executable = PKG_LIBEXECDIR"/dict";
bf40639e42957133fef54f2f0a322061ac37fe90nd client_process_exec(executable, "");
bf40639e42957133fef54f2f0a322061ac37fe90nd i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", executable);
bf40639e42957133fef54f2f0a322061ac37fe90nd return -1;
bf40639e42957133fef54f2f0a322061ac37fe90nd}
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90ndstatic void dict_process_deinit(struct dict_process *process)
0662ed52e814f8f08ef0e09956413a792584eddffuankg{
bf40639e42957133fef54f2f0a322061ac37fe90nd struct dict_process **p;
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd for (p = &process->listener->processes; *p != NULL; p++) {
bf40639e42957133fef54f2f0a322061ac37fe90nd if (*p == process) {
0662ed52e814f8f08ef0e09956413a792584eddffuankg *p = process->next;
bf40639e42957133fef54f2f0a322061ac37fe90nd break;
bf40639e42957133fef54f2f0a322061ac37fe90nd }
bf40639e42957133fef54f2f0a322061ac37fe90nd }
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd if (process->log != NULL)
bf40639e42957133fef54f2f0a322061ac37fe90nd log_unref(process->log);
bf40639e42957133fef54f2f0a322061ac37fe90nd i_free(process);
bf40639e42957133fef54f2f0a322061ac37fe90nd}
bf40639e42957133fef54f2f0a322061ac37fe90nd
0662ed52e814f8f08ef0e09956413a792584eddffuankgstatic void dict_listener_input(struct dict_listener *listener)
bf40639e42957133fef54f2f0a322061ac37fe90nd{
bf40639e42957133fef54f2f0a322061ac37fe90nd unsigned int i;
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg int fd;
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd i_assert(listener->processes == NULL);
bf40639e42957133fef54f2f0a322061ac37fe90nd
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg for (i = 0; i < settings_root->defaults->dict_process_count; i++) {
bf40639e42957133fef54f2f0a322061ac37fe90nd if (dict_process_create(listener) < 0)
bf40639e42957133fef54f2f0a322061ac37fe90nd break;
bf40639e42957133fef54f2f0a322061ac37fe90nd }
bf40639e42957133fef54f2f0a322061ac37fe90nd if (i > 0)
bf40639e42957133fef54f2f0a322061ac37fe90nd io_remove(&listener->io);
bf40639e42957133fef54f2f0a322061ac37fe90nd else {
bf40639e42957133fef54f2f0a322061ac37fe90nd /* failed to create dict process, so just reject this
bf40639e42957133fef54f2f0a322061ac37fe90nd connection and try again later */
bf40639e42957133fef54f2f0a322061ac37fe90nd fd = net_accept(listener->fd, NULL, NULL);
bf40639e42957133fef54f2f0a322061ac37fe90nd if (fd >= 0)
bf40639e42957133fef54f2f0a322061ac37fe90nd (void)close(fd);
bf40639e42957133fef54f2f0a322061ac37fe90nd }
bf40639e42957133fef54f2f0a322061ac37fe90nd}
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90ndstatic struct dict_listener *dict_listener_init(const char *path)
bf40639e42957133fef54f2f0a322061ac37fe90nd{
bf40639e42957133fef54f2f0a322061ac37fe90nd struct dict_listener *listener;
bf40639e42957133fef54f2f0a322061ac37fe90nd mode_t old_umask;
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd listener = i_new(struct dict_listener, 1);
bf40639e42957133fef54f2f0a322061ac37fe90nd listener->path = i_strdup(path);
bf40639e42957133fef54f2f0a322061ac37fe90nd old_umask = umask(0);
bf40639e42957133fef54f2f0a322061ac37fe90nd listener->fd = net_listen_unix_unlink_stale(path, 128);
bf40639e42957133fef54f2f0a322061ac37fe90nd umask(old_umask);
bf40639e42957133fef54f2f0a322061ac37fe90nd if (listener->fd == -1) {
bf40639e42957133fef54f2f0a322061ac37fe90nd if (errno == EADDRINUSE)
bf40639e42957133fef54f2f0a322061ac37fe90nd i_fatal("Socket already exists: %s", path);
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg else
bf40639e42957133fef54f2f0a322061ac37fe90nd i_fatal("net_listen_unix(%s) failed: %m", path);
bf40639e42957133fef54f2f0a322061ac37fe90nd }
bf40639e42957133fef54f2f0a322061ac37fe90nd fd_close_on_exec(listener->fd, TRUE);
bf40639e42957133fef54f2f0a322061ac37fe90nd listener->io = io_add(listener->fd, IO_READ,
bf40639e42957133fef54f2f0a322061ac37fe90nd dict_listener_input, listener);
bf40639e42957133fef54f2f0a322061ac37fe90nd return listener;
bf40639e42957133fef54f2f0a322061ac37fe90nd}
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90ndstatic void dict_listener_deinit(struct dict_listener *listener)
bf40639e42957133fef54f2f0a322061ac37fe90nd{
bf40639e42957133fef54f2f0a322061ac37fe90nd if (listener->io != NULL)
bf40639e42957133fef54f2f0a322061ac37fe90nd io_remove(&listener->io);
bf40639e42957133fef54f2f0a322061ac37fe90nd if (close(listener->fd) < 0)
bf40639e42957133fef54f2f0a322061ac37fe90nd i_error("close(dict listener) failed: %m");
bf40639e42957133fef54f2f0a322061ac37fe90nd
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg while (listener->processes != NULL)
bf40639e42957133fef54f2f0a322061ac37fe90nd dict_process_deinit(listener->processes);
bf40639e42957133fef54f2f0a322061ac37fe90nd}
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90ndstatic void
bf40639e42957133fef54f2f0a322061ac37fe90nddict_process_destroyed(struct child_process *_process,
bf40639e42957133fef54f2f0a322061ac37fe90nd pid_t pid ATTR_UNUSED, bool abnormal_exit ATTR_UNUSED)
bf40639e42957133fef54f2f0a322061ac37fe90nd{
bf40639e42957133fef54f2f0a322061ac37fe90nd struct dict_process *process = (struct dict_process *)_process;
bf40639e42957133fef54f2f0a322061ac37fe90nd struct dict_listener *listener = process->listener;
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd dict_process_deinit(process);
bf40639e42957133fef54f2f0a322061ac37fe90nd if (listener->processes == NULL) {
bf40639e42957133fef54f2f0a322061ac37fe90nd /* last listener died, create new ones */
bf40639e42957133fef54f2f0a322061ac37fe90nd listener->io = io_add(listener->fd, IO_READ,
8ffac2c334103c0336602aaede650cb578611151fuankg dict_listener_input, listener);
8ffac2c334103c0336602aaede650cb578611151fuankg }
bf40639e42957133fef54f2f0a322061ac37fe90nd}
bf40639e42957133fef54f2f0a322061ac37fe90nd
ac7985784d08a3655291f24f711812b4d8b1cbcffuankgvoid dict_processes_init(void)
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg{
bf40639e42957133fef54f2f0a322061ac37fe90nd const char *path;
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd path = t_strconcat(settings_root->defaults->base_dir,
bf40639e42957133fef54f2f0a322061ac37fe90nd "/"DICT_SERVER_SOCKET_NAME, NULL);
bf40639e42957133fef54f2f0a322061ac37fe90nd dict_listener = dict_listener_init(path);
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg child_process_set_destroy_callback(PROCESS_TYPE_DICT,
bf40639e42957133fef54f2f0a322061ac37fe90nd dict_process_destroyed);
bf40639e42957133fef54f2f0a322061ac37fe90nd}
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90ndvoid dict_processes_deinit(void)
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg{
bf40639e42957133fef54f2f0a322061ac37fe90nd dict_listener_deinit(dict_listener);
bf40639e42957133fef54f2f0a322061ac37fe90nd}
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90ndvoid dict_processes_kill(void)
bf40639e42957133fef54f2f0a322061ac37fe90nd{
bf40639e42957133fef54f2f0a322061ac37fe90nd struct dict_process *process;
bf40639e42957133fef54f2f0a322061ac37fe90nd
bf40639e42957133fef54f2f0a322061ac37fe90nd process = dict_listener->processes;
bf40639e42957133fef54f2f0a322061ac37fe90nd for (; process != NULL; process = process->next) {
bf40639e42957133fef54f2f0a322061ac37fe90nd if (process->log != NULL) {
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg log_unref(process->log);
0662ed52e814f8f08ef0e09956413a792584eddffuankg process->log = NULL;
bf40639e42957133fef54f2f0a322061ac37fe90nd }
bf40639e42957133fef54f2f0a322061ac37fe90nd }
bf40639e42957133fef54f2f0a322061ac37fe90nd}
bf40639e42957133fef54f2f0a322061ac37fe90nd