]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
master: Fixes to handling logging.
authorTimo Sirainen <tss@iki.fi>
Tue, 5 May 2009 00:24:57 +0000 (20:24 -0400)
committerTimo Sirainen <tss@iki.fi>
Tue, 5 May 2009 00:24:57 +0000 (20:24 -0400)
Master now has a non-blocking write pipe to log process, so it no longer
blocks if log process is hanging. Also it's cleaner to send log commands via
a pipe specifically meant for them.

--HG--
branch : HEAD

src/lib-master/master-interface.h
src/lib-master/master-service.c
src/log/log-connection.c
src/log/log-connection.h
src/log/main.c
src/master/service-log.c
src/master/service-log.h
src/master/service-process.c
src/master/service-process.h
src/master/service.c
src/master/service.h

index 600173bbbdbbb67c832da54d50f8fce0986e113b..9334a34afd9c97553f010cdb0de7232ab9635ed7 100644 (file)
@@ -28,6 +28,7 @@ struct log_service_handshake {
        unsigned int max_lines_per_sec;
 
        /* Add this previs to each logged line */
+#define MASTER_LOG_PREFIX_NAME "MASTER"
        unsigned int prefix_len;
        /* unsigned char prefix[]; */
 };
index 871c504398d57b3b4f8f4e976149e3663fb15b95..9670027768e9d0746716413118d903a74f7937e2 100644 (file)
@@ -64,9 +64,20 @@ master_service_init(const char *name, enum master_service_flags flags,
                    int argc, char *argv[])
 {
        struct master_service *service;
+       const char *str;
 
        i_assert(name != NULL);
 
+#ifdef DEBUG
+       if (getenv("GDB") == NULL) {
+               int count;
+
+               str = getenv("SOCKET_COUNT");
+               count = str == NULL ? 0 : atoi(str);
+               fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
+       }
+#endif
+
        /* NOTE: we start rooted, so keep the code minimal until
           restrict_access_by_env() is called */
        lib_init();
@@ -95,6 +106,9 @@ master_service_init(const char *name, enum master_service_flags flags,
        } else {
                service->version_string = PACKAGE_VERSION;
        }
+       str = getenv("SOCKET_COUNT");
+       if (str != NULL)
+               service->socket_count = atoi(str);
 
        /* set up some kind of logging until we know exactly how and where
           we want to log */
index fb9beb9570d5822fed23d984ec927da4139cbdaf..535aa286c0be35b3ca02bf15fb24c7e8b74783f8 100644 (file)
@@ -1,6 +1,7 @@
 /* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
 
 #include "common.h"
+#include "array.h"
 #include "ioloop.h"
 #include "llist.h"
 #include "hash.h"
@@ -8,6 +9,8 @@
 #include "master-service.h"
 #include "log-connection.h"
 
+#include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
 
 #define FATAL_QUEUE_TIMEOUT_MSECS 500
@@ -26,10 +29,12 @@ struct log_connection {
        char *prefix;
        struct hash_table *clients;
 
+       unsigned int master:1;
        unsigned int handshaked:1;
 };
 
 static struct log_connection *log_connections = NULL;
+static ARRAY_DEFINE(logs_by_fd, struct log_connection *);
 
 static struct log_client *log_client_get(struct log_connection *log, pid_t pid)
 {
@@ -52,47 +57,60 @@ static void log_parse_ip(struct log_connection *log,
        (void)net_addr2ip(failure->text + 3, &client->ip);
 }
 
-static void log_remove_pid(struct log_connection *log, pid_t pid)
-{
-       struct log_client *client;
-
-       client = hash_table_lookup(log->clients, POINTER_CAST(pid));
-       if (client != NULL) {
-               hash_table_remove(log->clients, POINTER_CAST(pid));
-               i_free(client);
-       }
-}
-
 static void log_parse_option(struct log_connection *log,
                             const struct failure_line *failure)
 {
        if (strncmp(failure->text, "ip=", 3) == 0)
                log_parse_ip(log, failure);
-       else if (strcmp(failure->text, "bye") == 0)
-               log_remove_pid(log, failure->pid);
 }
 
-static bool
-log_handle_seen_fatal(struct log_connection *log, const char **_text)
+static void log_parse_master_line(const char *line)
 {
-       const char *text = *_text;
+       struct log_connection *const *logs, *log;
        struct log_client *client;
-       pid_t pid = 0;
-
-       while (*text >= '0' && *text <= '9') {
-               pid = pid*10 + (*text - '0');
-               text++;
+       const char *p, *p2;
+       unsigned int count;
+       int service_fd;
+       long pid;
+
+       p = strchr(line, ' ');
+       if (p == NULL || (p2 = strchr(++p, ' ')) == NULL) {
+               i_error("Received invalid input from master: %s", line);
+               return;
        }
-       if (*text != ' ' || pid == 0)
-               return FALSE;
-       *_text = text;
+       service_fd = atoi(t_strcut(line, ' '));
+       pid = strtol(t_strcut(p, ' '), NULL, 10);
 
+       logs = array_get(&logs_by_fd, &count);
+       if (service_fd >= (int)count || logs[service_fd] == NULL) {
+               i_error("Received master input for invalid service_fd %d: %s",
+                       service_fd, line);
+               return;
+       }
+       log = logs[service_fd];
        client = hash_table_lookup(log->clients, POINTER_CAST(pid));
-       if (client != NULL && client->fatal_logged) {
-               log_remove_pid(log, pid);
-               return TRUE;
+       line = p2 + 1;
+
+       if (strcmp(line, "BYE") == 0) {
+               if (client == NULL) {
+                       /* we haven't seen anything important from this client.
+                          it's not an error. */
+                       return;
+               }
+               hash_table_remove(log->clients, POINTER_CAST(pid));
+               i_free(client);
+       } else if (strncmp(line, "DEFAULT-FATAL ", 14) == 0) {
+               /* If the client has logged a fatal/panic, don't log this
+                  message. */
+               if (client == NULL || !client->fatal_logged)
+                       i_error("%s", line + 14);
+               else {
+                       hash_table_remove(log->clients, POINTER_CAST(pid));
+                       i_free(client);
+               }
+       } else {
+               i_error("Received unknown command from master: %s", line);
        }
-       return FALSE;
 }
 
 static void log_it(struct log_connection *log, const char *line)
@@ -100,6 +118,11 @@ static void log_it(struct log_connection *log, const char *line)
        struct failure_line failure;
        struct log_client *client;
 
+       if (log->master) {
+               log_parse_master_line(line);
+               return;
+       }
+
        i_failure_parse_line(line, &failure);
        switch (failure.log_type) {
        case LOG_TYPE_FATAL:
@@ -107,20 +130,6 @@ static void log_it(struct log_connection *log, const char *line)
                client = log_client_get(log, failure.pid);
                client->fatal_logged = TRUE;
                break;
-       case LOG_TYPE_ERROR_IGNORE_IF_SEEN_FATAL:
-               /* Special case for master connection. If the following PID
-                  has logged a fatal/panic, don't log this message. */
-               failure.log_type = LOG_TYPE_ERROR;
-               if (failure.pid != master_pid) {
-                       i_error("Non-master process %s "
-                               "sent LOG_TYPE_ERROR_IGNORE_IF_SEEN_FATAL",
-                               dec2str(failure.pid));
-                       break;
-               }
-
-               if (log_handle_seen_fatal(log, &failure.text))
-                       return;
-               break;
        case LOG_TYPE_OPTION:
                log_parse_option(log, &failure);
                return;
@@ -151,6 +160,14 @@ static bool log_connection_handshake(struct log_connection *log,
                                        handshake.prefix_len);
                *data += sizeof(handshake) + handshake.prefix_len;
        }
+       if (strcmp(log->prefix, MASTER_LOG_PREFIX_NAME) == 0) {
+               if (log->fd != MASTER_LISTEN_FD_FIRST) {
+                       i_error("Received master prefix in handshake "
+                               "from non-master fd %d", log->fd);
+                       return FALSE;
+               }
+               log->master = TRUE;
+       }
        log->handshaked = TRUE;
        return TRUE;
 }
@@ -171,7 +188,7 @@ static void log_connection_input(struct log_connection *log)
 
        line = data;
        if (!log->handshaked)
-               log_connection_handshake(log, &line, ret);
+               (void)log_connection_handshake(log, &line, ret);
 
        p = line;
        while ((p = strchr(line, '\n')) != NULL) {
@@ -194,6 +211,7 @@ struct log_connection *log_connection_create(int fd)
        log->io = io_add(fd, IO_READ, log_connection_input, log);
        log->clients = hash_table_create(default_pool, default_pool, 0,
                                         NULL, NULL);
+       array_idx_set(&logs_by_fd, fd, &log);
 
        DLLIST_PREPEND(&log_connections, log);
        log_connection_input(log);
@@ -205,6 +223,8 @@ void log_connection_destroy(struct log_connection *log)
        struct hash_iterate_context *iter;
        void *key, *value;
 
+       array_idx_clear(&logs_by_fd, log->fd);
+
        DLLIST_REMOVE(&log_connections, log);
 
        iter = hash_table_iterate_init(log->clients);
@@ -215,16 +235,24 @@ void log_connection_destroy(struct log_connection *log)
 
        if (log->io != NULL)
                io_remove(&log->io);
+       if (close(log->fd) < 0)
+               i_error("close(log connection fd) failed: %m");
        i_free(log->prefix);
        i_free(log);
 
         master_service_client_connection_destroyed(service);
 }
 
+void log_connections_init(void)
+{
+       i_array_init(&logs_by_fd, 64);
+}
+
 void log_connections_deinit(void)
 {
        /* normally we don't exit until all log connections are gone,
           but we could get here when we're being killed by a signal */
        while (log_connections != NULL)
                log_connection_destroy(log_connections);
+       array_free(&logs_by_fd);
 }
index 819bb2012a2705180f967a5527ac1e9a1b9af55f..c2abbe2d820230eb46a9a3419397e2b2011a30c2 100644 (file)
@@ -4,6 +4,7 @@
 struct log_connection *log_connection_create(int fd);
 void log_connection_destroy(struct log_connection *log);
 
+void log_connections_init(void);
 void log_connections_deinit(void);
 
 #endif
index 7434382c0f2cd4b2052270ce9e9e150b55207f63..d8496ee964444124a270c06255226addfb173aaf 100644 (file)
@@ -31,6 +31,7 @@ static void main_init(void)
        lib_signals_set_handler(SIGUSR1, TRUE, sig_reopen_logs, NULL);
 
        master_pid = getppid();
+       log_connections_init();
 }
 
 static void main_deinit(void)
index c1dc3fbfe42efeaa4e7af2ecd3ecb3a51c72e78e..c8f4421f1b4efa8e2df871df1407385d4d24b7cf 100644 (file)
@@ -2,61 +2,86 @@
 
 #include "common.h"
 #include "array.h"
+#include "aqueue.h"
 #include "hash.h"
 #include "ioloop.h"
 #include "fd-close-on-exec.h"
+#include "fd-set-nonblock.h"
 #include "service.h"
 #include "service-process.h"
 #include "service-log.h"
 
 #include <unistd.h>
 
-int services_log_init(struct service_list *service_list)
+static int service_log_fds_init(const char *log_prefix, int log_fd[2],
+                               buffer_t *handshake_buf)
 {
        struct log_service_handshake handshake;
-       struct service *const *services;
-       unsigned int i, count;
-       buffer_t *handshake_buf;
-       ssize_t ret = 0;
+       ssize_t ret;
+
+       i_assert(log_fd[0] == -1);
+
+       if (pipe(log_fd) < 0) {
+               i_error("pipe() failed: %m");
+               return -1;
+       }
+       fd_close_on_exec(log_fd[0], TRUE);
+       fd_close_on_exec(log_fd[1], TRUE);
 
        memset(&handshake, 0, sizeof(handshake));
        handshake.log_magic = MASTER_LOG_MAGIC;
+       handshake.prefix_len = strlen(log_prefix);
+
+       buffer_set_used_size(handshake_buf, 0);
+       buffer_append(handshake_buf, &handshake, sizeof(handshake));
+       buffer_append(handshake_buf, log_prefix, strlen(log_prefix));
+
+       ret = write(log_fd[1], handshake_buf->data, handshake_buf->used);
+       if (ret < 0) {
+               i_error("write(log handshake) failed: %m");
+               return -1;
+       }
+       if ((size_t)ret != handshake_buf->used) {
+               i_error("write(log handshake) didn't write everything");
+               return -1;
+       }
+       return 0;
+}
+
+int services_log_init(struct service_list *service_list)
+{
+       struct service *const *services;
+       unsigned int i, count, n;
+       const char *log_prefix;
+       buffer_t *handshake_buf;
+       ssize_t ret = 0;
 
        handshake_buf = buffer_create_dynamic(default_pool, 256);
        services = array_get(&service_list->services, &count);
+
+       if (service_log_fds_init(MASTER_LOG_PREFIX_NAME,
+                                service_list->master_log_fd,
+                                handshake_buf) < 0)
+               ret = -1;
+       else
+               fd_set_nonblock(service_list->master_log_fd[1], TRUE);
+
+       n = 1;
        for (i = 0; i < count; i++) {
                if (services[i]->type == SERVICE_TYPE_LOG)
                        continue;
 
-               i_assert(services[i]->log_fd[0] == -1);
-               if (pipe(services[i]->log_fd) < 0) {
-                       i_error("pipe() failed: %m");
-                       ret = -1;
-                       break;
-               }
-               fd_close_on_exec(services[i]->log_fd[0], TRUE);
-               fd_close_on_exec(services[i]->log_fd[1], TRUE);
-
-               handshake.prefix_len = strlen(services[i]->set->name) + 2;
-
-               buffer_set_used_size(handshake_buf, 0);
-               buffer_append(handshake_buf, &handshake, sizeof(handshake));
-               buffer_append(handshake_buf, services[i]->set->name,
-                             strlen(services[i]->set->name));
-               buffer_append(handshake_buf, ": ", 2);
-
-               ret = write(services[i]->log_fd[1],
-                           handshake_buf->data, handshake_buf->used);
-               if (ret < 0) {
-                       i_error("write(log handshake) failed: %m");
-                       break;
-               }
-               if ((size_t)ret != handshake_buf->used) {
-                       i_error("write(log handshake) didn't write everything");
+               log_prefix = t_strconcat(services[i]->set->name, ": ", NULL);
+               if (service_log_fds_init(log_prefix,
+                                        services[i]->log_fd,
+                                        handshake_buf) < 0) {
                        ret = -1;
                        break;
                }
+               services[i]->log_process_internal_fd =
+                       MASTER_LISTEN_FD_FIRST + n++;
        }
+
        buffer_free(&handshake_buf);
        if (ret < 0) {
                services_log_deinit(service_list);
@@ -65,19 +90,24 @@ int services_log_init(struct service_list *service_list)
        return 0;
 }
 
-static void service_remove_log_io_writes(struct service *service)
+void services_log_clear_byes(struct service_list *service_list)
 {
-       struct hash_iterate_context *iter;
-       void *key, *value;
+       struct service_process *const *processes, *process;
+       unsigned int i, count;
 
-       iter = hash_table_iterate_init(service->list->pids);
-       while (hash_table_iterate(iter, &key, &value)) {
-               struct service_process *process = value;
+       if (service_list->io_log_write == NULL)
+               return;
 
-               if (process->io_log_write != NULL)
-                       io_remove(&process->io_log_write);
+       processes = array_idx_modifiable(&service_list->bye_arr, 0);
+       count = aqueue_count(service_list->bye_queue);
+       for (i = 0; i < count; i++) {
+               process = processes[aqueue_idx(service_list->bye_queue, i)];
+               service_process_unref(process);
        }
-       hash_table_iterate_deinit(&iter);
+       aqueue_clear(service_list->bye_queue);
+       array_clear(&service_list->bye_arr);
+
+       io_remove(&service_list->io_log_write);
 }
 
 void services_log_deinit(struct service_list *service_list)
@@ -98,9 +128,18 @@ void services_log_deinit(struct service_list *service_list)
                        }
                        services[i]->log_fd[0] = -1;
                        services[i]->log_fd[1] = -1;
-                       service_remove_log_io_writes(services[i]);
+                       services[i]->log_process_internal_fd = -1;
                }
        }
+       services_log_clear_byes(service_list);
+       if (service_list->master_log_fd[0] != -1) {
+               if (close(service_list->master_log_fd[0]) < 0)
+                       i_error("close(master log fd) failed: %m");
+               if (close(service_list->master_log_fd[1]) < 0)
+                       i_error("close(master log fd) failed: %m");
+               service_list->master_log_fd[0] = -1;
+               service_list->master_log_fd[1] = -1;
+       }
 }
 
 void services_log_dup2(ARRAY_TYPE(dup2) *dups,
@@ -108,13 +147,19 @@ void services_log_dup2(ARRAY_TYPE(dup2) *dups,
                       unsigned int first_fd, unsigned int *fd_count)
 {
        struct service *const *services;
-       unsigned int i, n, count;
+       unsigned int i, n = 0, count;
+
+       /* master log fd is always the first one */
+       dup2_append(dups, service_list->master_log_fd[0], first_fd);
+       n++; *fd_count += 1;
 
        services = array_get(&service_list->services, &count);
-       for (i = n = 0; i < count; i++) {
-               if (services[i]->log_fd[1] != -1) {
-                       dup2_append(dups, services[i]->log_fd[0], first_fd + n);
-                       n++; *fd_count += 1;
-               }
+       for (i = 0; i < count; i++) {
+               if (services[i]->log_fd[1] == -1)
+                       continue;
+
+               i_assert((int)(first_fd + n) == services[i]->log_process_internal_fd);
+               dup2_append(dups, services[i]->log_fd[0], first_fd + n);
+               n++; *fd_count += 1;
        }
 }
index 475c91dd1484b01e76bde6b749781ad43a79cdee..e6dca287eba33e0e1480a540cb7f40a7f232e3a7 100644 (file)
@@ -6,6 +6,7 @@
 int services_log_init(struct service_list *service_list);
 void services_log_deinit(struct service_list *service_list);
 
+void services_log_clear_byes(struct service_list *service_list);
 void services_log_dup2(ARRAY_TYPE(dup2) *dups,
                       struct service_list *service_list,
                       unsigned int first_fd, unsigned int *fd_count);
index eb78edbba245750c085808c8ec4e39946b01d7b2..ae56a9aa28143afbb232d6fcb473c6daecd9316c 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "common.h"
 #include "array.h"
+#include "aqueue.h"
 #include "ioloop.h"
 #include "istream.h"
 #include "ostream.h"
 #include <signal.h>
 #include <sys/wait.h>
 
-static const char **
+static void
 service_dup_fds(struct service *service, int auth_fd, int std_fd)
 {
        struct service_listener *const *listeners;
        ARRAY_TYPE(dup2) dups;
-       unsigned int i, count, n, socket_listener_count;
+       unsigned int i, count, n = 0, socket_listener_count;
 
        /* stdin/stdout is already redirected to /dev/null. Other master fds
           should have been opened with fd_close_on_exec() so we don't have to
@@ -43,8 +44,16 @@ service_dup_fds(struct service *service, int auth_fd, int std_fd)
 
         socket_listener_count = 0;
        listeners = array_get(&service->listeners, &count);
-       t_array_init(&dups, count + 4);
-       for (i = n = 0; i < count; i++) {
+       t_array_init(&dups, count + 10);
+
+       if (service->type == SERVICE_TYPE_LOG) {
+               i_assert(n == 0);
+               services_log_dup2(&dups, service->list, MASTER_LISTEN_FD_FIRST,
+                                 &socket_listener_count);
+               n += socket_listener_count;
+       }
+
+       for (i = 0; i < count; i++) {
                if (listeners[i]->fd == -1)
                        continue;
 
@@ -63,11 +72,6 @@ service_dup_fds(struct service *service, int auth_fd, int std_fd)
                dup2_append(&dups, auth_fd, MASTER_AUTH_FD);
                env_put(t_strdup_printf("MASTER_AUTH_FD=%d", MASTER_AUTH_FD));
                break;
-       case SERVICE_TYPE_LOG:
-               services_log_dup2(&dups, service->list,
-                                 MASTER_LISTEN_FD_FIRST + n,
-                                 &socket_listener_count);
-               /* fall through */
        default:
                i_assert(auth_fd == -1);
                dup2_append(&dups, null_fd, MASTER_AUTH_FD);
@@ -101,18 +105,7 @@ service_dup_fds(struct service *service, int auth_fd, int std_fd)
        if (dup2_array(&dups) < 0)
                service_error(service, "dup2s failed");
 
-#ifdef DEBUG
        env_put(t_strdup_printf("SOCKET_COUNT=%d", socket_listener_count));
-#endif
-
-       if (socket_listener_count == 1)
-               return NULL;
-       else {
-               const char **args = t_new(const char *, 3);
-               args[0] = "-s";
-               args[1] = dec2str(socket_listener_count);
-               return args;
-       }
 }
 
 static int validate_uid_gid(struct master_settings *set, uid_t uid, gid_t gid,
@@ -338,8 +331,6 @@ service_process_create(struct service *service, const char *const *auth_args,
        }
        if (pid == 0) {
                /* child */
-               const char **args;
-
                if (fd[0] != -1)
                        (void)close(fd[0]);
                service_process_setup_environment(service, uid);
@@ -349,9 +340,9 @@ service_process_create(struct service *service, const char *const *auth_args,
                        base64_encode(data, data_size, str);
                        env_put(str_c(str));
                }
-               args = service_dup_fds(service, fd[1], std_fd);
+               service_dup_fds(service, fd[1], std_fd);
                drop_privileges(service, auth_args);
-               process_exec(service->executable, args);
+               process_exec(service->executable, NULL);
        }
 
        switch (service->type) {
@@ -395,31 +386,62 @@ service_process_create(struct service *service, const char *const *auth_args,
        return process;
 }
 
-static void service_process_log_bye(struct service_process *process)
+static int service_process_write_bye(struct service_process *process)
 {
        const char *data;
 
+       data = t_strdup_printf("%d %s BYE\n",
+                              process->service->log_process_internal_fd,
+                              dec2str(process->pid));
+       if (write(process->service->list->master_log_fd[1],
+                 data, strlen(data)) < 0) {
+               if (errno != EAGAIN)
+                       i_error("write(log process) failed: %m");
+               return -1;
+       }
+       return 0;
+}
+
+static void service_list_log_flush_byes(struct service_list *service_list)
+{
+       struct service_process *const *processes, *process;
+
+       while (aqueue_count(service_list->bye_queue) > 0) {
+               processes = array_idx_modifiable(&service_list->bye_arr, 0);
+               process = processes[aqueue_idx(service_list->bye_queue, 0)];
+
+               if (service_process_write_bye(process) < 0) {
+                       if (errno != EAGAIN)
+                               services_log_clear_byes(service_list);
+                       return;
+               }
+               service_process_unref(process);
+               aqueue_delete_tail(service_list->bye_queue);
+       }
+       io_remove(&service_list->io_log_write);
+}
+
+static void service_process_log_bye(struct service_process *process)
+{
+       struct service_list *service_list = process->service->list;
+
        if (process->service->log_fd[1] == -1) {
                /* stopping all services */
                return;
        }
 
-       data = t_strdup_printf("\001%c%s bye\n",
-                              LOG_TYPE_OPTION+1, dec2str(process->pid));
-       if (write(process->service->log_fd[1], data, strlen(data)) < 0) {
+       if (service_process_write_bye(process) < 0) {
                if (errno != EAGAIN)
-                       i_error("write(log process) failed: %m");
-               else {
-                       process->io_log_write =
-                               io_add(process->service->log_fd[1], IO_WRITE,
-                                      service_process_log_bye, process);
-                       service_process_ref(process);
-               }
-       } else {
-               if (process->io_log_write != NULL) {
-                       io_remove(&process->io_log_write);
-                       service_process_unref(process);
+                       return;
+
+               if (service_list->io_log_write == NULL) {
+                       service_list->io_log_write =
+                               io_add(service_list->master_log_fd[1], IO_WRITE,
+                                      service_list_log_flush_byes,
+                                      service_list);
                }
+               aqueue_append(service_list->bye_queue, &process);
+               service_process_ref(process);
        }
 }
 
@@ -468,7 +490,6 @@ int service_process_unref(struct service_process *process)
        if (--process->refcount > 0)
                return TRUE;
 
-       i_assert(process->io_log_write == NULL);
        i_assert(process->destroyed);
 
        i_free(process);
@@ -583,11 +604,13 @@ static void service_process_log(struct service_process *process,
 
        /* log it via the log process in charge of handling
           this process's logging */
-       data = t_strdup_printf("\001%c%s %s %s\n",
-                              type+1, my_pid, dec2str(process->pid), str);
-       if (write(process->service->log_fd[1], data, strlen(data)) < 0) {
+       data = t_strdup_printf("%d %s DEFAULT-FATAL %s\n",
+                              process->service->log_process_internal_fd,
+                              dec2str(process->pid), str);
+       if (write(process->service->list->master_log_fd[1],
+                 data, strlen(data)) < 0) {
                i_error("write(log process) failed: %m");
-               i_log_type(type, "%s", str);
+               i_error("%s", str);
        }
 }
 
index 61b011ea7ca72bafabc486d8ea4e881657f8bbd9..aca151efcee36c5d0802cf58954c8b2479b71b86 100644 (file)
@@ -19,8 +19,6 @@ struct service_process {
 
        /* kill the process if it doesn't send initial status notification */
        struct timeout *to_status;
-       /* we're waiting to be able to send "bye" to log process */
-       struct io *io_log_write;
 
        unsigned int destroyed:1;
 };
index b46f9792cf6d943f1930c23368e9583b81083254..270b3ffa6f11ec10c16945b057c920043a588ad1 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "common.h"
 #include "array.h"
+#include "aqueue.h"
 #include "hash.h"
 #include "str.h"
 #include "service.h"
@@ -238,6 +239,7 @@ service_create(pool_t pool, const struct service_settings *set,
        service->log_fd[1] = -1;
        service->status_fd[0] = -1;
        service->status_fd[1] = -1;
+       service->log_process_internal_fd = -1;
 
        if (array_is_created(&set->unix_listeners))
                unix_listeners = array_get(&set->unix_listeners, &unix_count);
@@ -336,6 +338,8 @@ services_create(const struct master_settings *set,
        service_list = p_new(pool, struct service_list, 1);
        service_list->pool = pool;
        service_list->child_process_env = child_process_env;
+       service_list->master_log_fd[0] = -1;
+       service_list->master_log_fd[1] = -1;
 
        service_settings = array_get(&set->services, &count);
        p_array_init(&service_list->services, pool, count);
@@ -400,6 +404,8 @@ services_create(const struct master_settings *set,
 
        service_list->pids = hash_table_create(default_pool, pool, 0,
                                               pid_hash, pid_hash_cmp);
+       p_array_init(&service_list->bye_arr, pool, 64);
+       service_list->bye_queue = aqueue_init(&service_list->bye_arr.arr);
        return service_list;
 }
 
@@ -440,5 +446,6 @@ void services_destroy(struct service_list *service_list)
        hash_table_iterate_deinit(&iter);
 
        hash_table_destroy(&service_list->pids);
+       aqueue_deinit(&service_list->bye_queue);
        pool_unref(&service_list->pool);
 }
index bf4bd5794feb5a13348feccd22c848522d7f3896..3bde297203b598c5272181dedfe102b66121324d 100644 (file)
@@ -65,8 +65,11 @@ struct service {
        /* max number of processes allowed */
        unsigned int process_limit;
 
-       /* log process pipe file descriptors */
+       /* log process pipe file descriptors. */
        int log_fd[2];
+       /* fd that log process sees log_fd[0] as. can be used to identify
+          service name when sending commands via master_log_fd. */
+       int log_process_internal_fd;
 
        /* status report pipe file descriptors */
        int status_fd[2];
@@ -92,6 +95,14 @@ struct service_list {
        struct hash_table *pids;
        const char *const *child_process_env;
 
+       /* nonblocking log fds usd by master */
+       int master_log_fd[2];
+       /* we're waiting to be able to send "bye" to log process */
+       struct io *io_log_write;
+       /* List of processes who are waiting for the "bye" */
+       struct aqueue *bye_queue;
+       ARRAY_DEFINE(bye_arr, struct service_process *);
+
        ARRAY_DEFINE(services, struct service *);
 };