dict-process.c revision e17fd08d865094c644aa3298ad29320b60c60247
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "common.h"
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen#include "array.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "ioloop.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "network.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "fd-close-on-exec.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "env-util.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "log.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "child-process.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "dict-process.h"
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include <syslog.h>
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include <unistd.h>
1d738cce754bc64bbc66d3355ebdaf3f6eac55f1Timo Sirainen#include <sys/stat.h>
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen#define DICT_SERVER_SOCKET_NAME "dict-server"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainenstruct dict_process {
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen struct child_process process;
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen char *path;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen int fd;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen struct log_io *log;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen struct io *io;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen};
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainenstatic struct dict_process *dict_process;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainenstatic void dict_process_unlisten(struct dict_process *process);
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainenstatic int dict_process_start(struct dict_process *process)
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen{
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen struct log_io *log;
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen const char *executable, *const *dicts;
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen unsigned int i, count;
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen int log_fd;
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen pid_t pid;
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen log_fd = log_create_pipe(&log, 0);
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen if (log_fd < 0)
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen pid = -1;
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen else {
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen pid = fork();
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen if (pid < 0)
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen i_error("fork() failed: %m");
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen }
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen if (pid < 0) {
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen (void)close(log_fd);
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen return -1;
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen }
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen if (pid != 0) {
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen /* master */
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen child_process_add(pid, &process->process);
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen log_set_prefix(log, "dict: ");
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen log_set_pid(log, pid);
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen (void)close(log_fd);
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen process->log = log;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen log_ref(process->log);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen dict_process_unlisten(process);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen log_set_prefix(log, "master-dict: ");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen /* set stdin and stdout to /dev/null, so anything written into it
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen gets ignored. */
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen if (dup2(null_fd, 0) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_fatal("dup2(stdin) failed: %m");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (dup2(null_fd, 1) < 0)
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen i_fatal("dup2(stdout) failed: %m");
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen /* stderr = log, 3 = listener */
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen if (dup2(log_fd, 2) < 0)
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen i_fatal("dup2(stderr) failed: %m");
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen if (dup2(process->fd, 3) < 0)
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen i_fatal("dup2(3) failed: %m");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen for (i = 0; i <= 3; i++)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen fd_close_on_exec(i, FALSE);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen child_process_init_env();
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen env_put(t_strconcat("DICT_LISTEN_FROM_FD=", process->path, NULL));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (settings_root->defaults->dict_db_config != NULL) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen env_put(t_strconcat("DB_CONFIG=",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen settings_root->defaults->dict_db_config,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen NULL));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen dicts = array_get(&settings_root->dicts, &count);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert((count % 2) == 0);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen for (i = 0; i < count; i += 2)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen env_put(t_strdup_printf("DICT_%s=%s", dicts[i], dicts[i+1]));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* make sure we don't leak syslog fd, but do it last so that
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen any errors above will be logged */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen closelog();
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen executable = PKG_LIBEXECDIR"/dict";
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen client_process_exec(executable, "");
da4376093d4e1b26b14ea1e945689fb7056fe0a0Timo Sirainen i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", executable);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic void dict_process_listen_input(struct dict_process *process)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert(process->log == NULL);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen dict_process_start(process);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int dict_process_listen(struct dict_process *process)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mode_t old_umask;
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen old_umask = umask(0);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen process->fd = net_listen_unix_unlink_stale(process->path, 128);
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen umask(old_umask);
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen if (process->fd == -1) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (errno == EADDRINUSE)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_error("Socket already exists: %s", process->path);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen else
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen i_error("net_listen_unix(%s) failed: %m", process->path);
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen fd_close_on_exec(process->fd, TRUE);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen process->io = io_add(process->fd, IO_READ,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen dict_process_listen_input, process);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return process->fd != -1 ? 0 : -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic void dict_process_unlisten(struct dict_process *process)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (process->fd == -1)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen io_remove(&process->io);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (close(process->fd) < 0)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen i_error("close(dict) failed: %m");
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen process->fd = -1;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen}
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenstatic void
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainendict_process_destroyed(struct child_process *process,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen pid_t pid ATTR_UNUSED,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen bool abnormal_exit ATTR_UNUSED)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen{
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen struct dict_process *p = (struct dict_process *)process;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (p->log != NULL) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen /* not killed by ourself */
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen log_unref(p->log);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen p->log = NULL;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen (void)dict_process_listen(p);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen}
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenvoid dict_process_init(void)
0bf3eac1110a902e7ec7e695c64e8e46c114e623Timo Sirainen{
0bf3eac1110a902e7ec7e695c64e8e46c114e623Timo Sirainen struct dict_process *process;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen process = dict_process = i_new(struct dict_process, 1);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen process->process.type = PROCESS_TYPE_DICT;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen process->fd = -1;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen process->path = i_strconcat(settings_root->defaults->base_dir,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen "/"DICT_SERVER_SOCKET_NAME, NULL);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen (void)dict_process_listen(process);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen child_process_set_destroy_callback(PROCESS_TYPE_DICT,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen dict_process_destroyed);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen}
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenvoid dict_process_deinit(void)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen struct dict_process *process = dict_process;
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen dict_process_unlisten(process);
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen if (process->log != NULL)
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen log_unref(process->log);
dffa503fd4ce31334346e539496084c80a2d8d37Timo Sirainen i_free(process->path);
dffa503fd4ce31334346e539496084c80a2d8d37Timo Sirainen i_free(process);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen}
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenvoid dict_process_kill(void)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen{
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen struct dict_process *process = dict_process;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (process->log != NULL) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen log_unref(process->log);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen process->log = NULL;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen