Mercurial > dovecot > original-hg > dovecot-1.2
view src/master/dict-process.c @ 7109:e6823d781317 HEAD
Reverted "environment array" changes. It broke overriding imap/pop3 settings
from userdb and the performance improvements weren't all that great anyway.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 05 Jan 2008 01:28:46 +0200 |
parents | 59ac3628b8d8 |
children | 768231eb84cf |
line wrap: on
line source
/* Copyright (c) 2006-2008 Dovecot authors, see the included COPYING file */ #include "common.h" #include "array.h" #include "ioloop.h" #include "network.h" #include "fd-close-on-exec.h" #include "env-util.h" #include "log.h" #include "child-process.h" #include "dict-process.h" #include <syslog.h> #include <unistd.h> #include <sys/stat.h> #define DICT_SERVER_SOCKET_NAME "dict-server" struct dict_process { struct child_process process; char *path; int fd; struct log_io *log; struct io *io; }; static struct dict_process *process; static void dict_process_unlisten(struct dict_process *process); static int dict_process_start(struct dict_process *process) { struct log_io *log; const char *executable, *const *dicts; unsigned int i, count; int log_fd; pid_t pid; log_fd = log_create_pipe(&log, 0); if (log_fd < 0) pid = -1; else { pid = fork(); if (pid < 0) i_error("fork() failed: %m"); } if (pid < 0) { (void)close(log_fd); return -1; } if (pid != 0) { /* master */ child_process_add(pid, &process->process); log_set_prefix(log, "dict: "); log_set_pid(log, pid); (void)close(log_fd); process->log = log; log_ref(process->log); dict_process_unlisten(process); return 0; } log_set_prefix(log, "master-dict: "); /* set stdin and stdout to /dev/null, so anything written into it gets ignored. */ if (dup2(null_fd, 0) < 0) i_fatal("dup2(stdin) failed: %m"); if (dup2(null_fd, 1) < 0) i_fatal("dup2(stdout) failed: %m"); /* stderr = log, 3 = listener */ if (dup2(log_fd, 2) < 0) i_fatal("dup2(stderr) failed: %m"); if (dup2(process->fd, 3) < 0) i_fatal("dup2(3) failed: %m"); for (i = 0; i <= 3; i++) fd_close_on_exec(i, FALSE); child_process_init_env(); env_put(t_strconcat("DICT_LISTEN_FROM_FD=", process->path, NULL)); dicts = array_get(&settings_root->dicts, &count); i_assert((count % 2) == 0); for (i = 0; i < count; i += 2) env_put(t_strdup_printf("DICT_%s=%s", dicts[i], dicts[i+1])); /* make sure we don't leak syslog fd, but do it last so that any errors above will be logged */ closelog(); executable = PKG_LIBEXECDIR"/dict"; client_process_exec(executable, ""); i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", executable); return -1; } static void dict_process_listen_input(struct dict_process *process) { i_assert(process->log == NULL); dict_process_start(process); } static int dict_process_listen(struct dict_process *process) { mode_t old_umask; int fd, i = 0; for (;;) { old_umask = umask(0); process->fd = net_listen_unix(process->path, 64); umask(old_umask); if (process->fd != -1) break; if (errno != EADDRINUSE || ++i == 2) { i_error("net_listen_unix(%s) failed: %m", process->path); return -1; } /* see if it really exists */ fd = net_connect_unix(process->path); if (fd != -1 || errno != ECONNREFUSED) { if (fd != -1) (void)close(fd); i_error("Socket already exists: %s", process->path); return -1; } /* delete and try again */ if (unlink(process->path) < 0 && errno != ENOENT) { i_error("unlink(%s) failed: %m", process->path); return -1; } } fd_close_on_exec(process->fd, TRUE); process->io = io_add(process->fd, IO_READ, dict_process_listen_input, process); return process->fd != -1 ? 0 : -1; } static void dict_process_unlisten(struct dict_process *process) { if (process->fd == -1) return; io_remove(&process->io); if (close(process->fd) < 0) i_error("close(dict) failed: %m"); process->fd = -1; } static void dict_process_destroyed(struct child_process *process, pid_t pid ATTR_UNUSED, bool abnormal_exit ATTR_UNUSED) { struct dict_process *p = (struct dict_process *)process; if (p->log != NULL) { /* not killed by ourself */ log_unref(p->log); p->log = NULL; } (void)dict_process_listen(p); } void dict_process_init(void) { process = i_new(struct dict_process, 1); process->process.type = PROCESS_TYPE_DICT; process->fd = -1; process->path = i_strconcat(settings_root->defaults->base_dir, "/"DICT_SERVER_SOCKET_NAME, NULL); (void)dict_process_listen(process); child_process_set_destroy_callback(PROCESS_TYPE_DICT, dict_process_destroyed); } void dict_process_deinit(void) { dict_process_unlisten(process); if (process->log != NULL) log_unref(process->log); i_free(process->path); i_free(process); } void dict_process_kill(void) { if (process->log != NULL) { log_unref(process->log); process->log = NULL; } }