bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
5d4eaaf7babd0ada6fad82887b9cd9480dbc25b0Timo Sirainen#include "lib.h"
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen#include "array.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "ioloop.h"
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen#include "istream.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "llist.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "hash.h"
f45d9079400cca2810f6c182b972924b42b55f33Timo Sirainen#include "time-util.h"
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen#include "process-title.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "master-interface.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "master-service.h"
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen#include "log-error-buffer.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "log-connection.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen#include <stdio.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <unistd.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#define FATAL_QUEUE_TIMEOUT_MSECS 500
f45d9079400cca2810f6c182b972924b42b55f33Timo Sirainen#define MAX_MSECS_PER_CONNECTION 100
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
aed2118ef7de81b1f7c4437991029cc043b23fa7Timo Sirainen/* Log a warning after 1 secs when we've been all the time busy writing the
aed2118ef7de81b1f7c4437991029cc043b23fa7Timo Sirainen log connection. */
aed2118ef7de81b1f7c4437991029cc043b23fa7Timo Sirainen#define LOG_WARN_PENDING_COUNT (1000 / MAX_MSECS_PER_CONNECTION)
211c638d81d382517d196ad47565e0d85012c927klemens/* If we keep being busy, log a warning every 60 seconds. */
aed2118ef7de81b1f7c4437991029cc043b23fa7Timo Sirainen#define LOG_WARN_PENDING_INTERVAL (60 * LOG_WARN_PENDING_COUNT)
aed2118ef7de81b1f7c4437991029cc043b23fa7Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstruct log_client {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct ip_addr ip;
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen char *prefix;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool fatal_logged:1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen};
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstruct log_connection {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct log_connection *prev, *next;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen struct log_error_buffer *errorbuf;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int fd;
3e8558a3a8e12b012e43976ead883bb5cc00ada4Timo Sirainen int listen_fd;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct io *io;
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen struct istream *input;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen char *default_prefix;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen HASH_TABLE(void *, struct log_client *) clients;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
aed2118ef7de81b1f7c4437991029cc043b23fa7Timo Sirainen unsigned int pending_count;
aed2118ef7de81b1f7c4437991029cc043b23fa7Timo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool master:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool handshaked:1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen};
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic struct log_connection *log_connections = NULL;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainenstatic ARRAY(struct log_connection *) logs_by_fd;
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainenstatic unsigned int global_pending_count;
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainenstatic struct log_connection *last_pending_log;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
f37939033c80f14b66868cc677179f9e54d729bdTimo Sirainenstatic void
f37939033c80f14b66868cc677179f9e54d729bdTimo Sirainenlog_connection_destroy(struct log_connection *log, bool shutting_down);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainenstatic void log_refresh_proctitle(void)
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen{
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen if (!verbose_proctitle)
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen return;
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen if (global_pending_count == 0)
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen process_title_set("");
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen else if (last_pending_log == NULL) {
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen process_title_set(t_strdup_printf(
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen "[%u services too fast]", global_pending_count));
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen } else if (global_pending_count > 1) {
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen process_title_set(t_strdup_printf(
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen "[%u services too fast, last: %d/%d/%s]",
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen global_pending_count,
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen last_pending_log->fd,
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen last_pending_log->listen_fd,
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen last_pending_log->default_prefix));
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen } else {
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen process_title_set(t_strdup_printf(
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen "[service too fast: %d/%d/%s]",
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen last_pending_log->fd,
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen last_pending_log->listen_fd,
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen last_pending_log->default_prefix));
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen }
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen}
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic struct log_client *log_client_get(struct log_connection *log, pid_t pid)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct log_client *client;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen client = hash_table_lookup(log->clients, POINTER_CAST(pid));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (client == NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client = i_new(struct log_client, 1);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen hash_table_insert(log->clients, POINTER_CAST(pid), client);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return client;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainenstatic void log_client_free(struct log_connection *log,
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen struct log_client *client, pid_t pid)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen hash_table_remove(log->clients, POINTER_CAST(pid));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen i_free(client->prefix);
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen i_free(client);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void log_parse_option(struct log_connection *log,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct failure_line *failure)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen struct log_client *client;
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen client = log_client_get(log, failure->pid);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (strncmp(failure->text, "ip=", 3) == 0)
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen (void)net_addr2ip(failure->text + 3, &client->ip);
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen else if (strncmp(failure->text, "prefix=", 7) == 0) {
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen i_free(client->prefix);
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen client->prefix = i_strdup(failure->text + 7);
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainenstatic void
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainenclient_log_ctx(struct log_connection *log,
d4f004105cd7159aa9ade6b019eaecce9e94f382Timo Sirainen const struct failure_context *ctx,
d4f004105cd7159aa9ade6b019eaecce9e94f382Timo Sirainen const struct timeval *log_time,
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen const char *prefix, const char *text)
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen{
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen struct log_error err;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen switch (ctx->type) {
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen case LOG_TYPE_DEBUG:
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen case LOG_TYPE_INFO:
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen case LOG_TYPE_OPTION:
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen break;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen case LOG_TYPE_WARNING:
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen case LOG_TYPE_ERROR:
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen case LOG_TYPE_FATAL:
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen case LOG_TYPE_PANIC:
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&err);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen err.type = ctx->type;
d4f004105cd7159aa9ade6b019eaecce9e94f382Timo Sirainen err.timestamp = log_time->tv_sec;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen err.prefix = prefix;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen err.text = text;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen log_error_buffer_add(log->errorbuf, &err);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen break;
a4ec27bfd5ba15d5914063b674873a12f3eb8f9eAki Tuomi case LOG_TYPE_COUNT:
a4ec27bfd5ba15d5914063b674873a12f3eb8f9eAki Tuomi i_unreached();
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen }
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen i_set_failure_prefix("%s", prefix);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen i_log_type(ctx, "%s", text);
9a795eb60306eede5efc7e8ec5d584457a49e32eTimo Sirainen i_set_failure_prefix("%s", global_log_prefix);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen}
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainenstatic void
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainenclient_log_fatal(struct log_connection *log, struct log_client *client,
d4f004105cd7159aa9ade6b019eaecce9e94f382Timo Sirainen const char *line, const struct timeval *log_time,
d4f004105cd7159aa9ade6b019eaecce9e94f382Timo Sirainen const struct tm *tm)
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen{
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen struct failure_context failure_ctx;
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen const char *prefix = log->default_prefix;
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&failure_ctx);
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen failure_ctx.type = LOG_TYPE_FATAL;
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen failure_ctx.timestamp = tm;
d4f004105cd7159aa9ade6b019eaecce9e94f382Timo Sirainen failure_ctx.timestamp_usecs = log_time->tv_usec;
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen if (client != NULL) {
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen if (client->prefix != NULL)
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen prefix = client->prefix;
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen else if (client->ip.family != 0) {
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen line = t_strdup_printf("%s [last ip=%s]",
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen line, net_ip2addr(&client->ip));
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen }
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen }
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen client_log_ctx(log, &failure_ctx, log_time, prefix,
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen t_strconcat("master: ", line, NULL));
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen}
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainenstatic void
d4f004105cd7159aa9ade6b019eaecce9e94f382Timo Sirainenlog_parse_master_line(const char *line, const struct timeval *log_time,
d4f004105cd7159aa9ade6b019eaecce9e94f382Timo Sirainen const struct tm *tm)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen struct log_connection *const *logs, *log;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct log_client *client;
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch const char *p, *p2, *cmd, *pidstr;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen unsigned int count;
d695286ee8796c701f1911fefeb9bcb878dd2b32Timo Sirainen unsigned int service_fd;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen pid_t pid;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen p = strchr(line, ' ');
d695286ee8796c701f1911fefeb9bcb878dd2b32Timo Sirainen if (p == NULL || (p2 = strchr(++p, ' ')) == NULL ||
d695286ee8796c701f1911fefeb9bcb878dd2b32Timo Sirainen str_to_uint(t_strcut(line, ' '), &service_fd) < 0) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen i_error("Received invalid input from master: %s", line);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch pidstr = t_strcut(p, ' ');
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch if (str_to_pid(pidstr, &pid) < 0) {
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch i_error("Received invalid pid from master: %s", pidstr);
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch return;
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch }
b636982bb629d23efba1e49c361e19237c435f19Timo Sirainen cmd = p2 + 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen logs = array_get(&logs_by_fd, &count);
d695286ee8796c701f1911fefeb9bcb878dd2b32Timo Sirainen if (service_fd >= count || logs[service_fd] == NULL) {
d695286ee8796c701f1911fefeb9bcb878dd2b32Timo Sirainen if (strcmp(cmd, "BYE") == 0 && service_fd < count) {
b636982bb629d23efba1e49c361e19237c435f19Timo Sirainen /* master is probably shutting down and we already
b636982bb629d23efba1e49c361e19237c435f19Timo Sirainen noticed the log fd closing */
b636982bb629d23efba1e49c361e19237c435f19Timo Sirainen return;
b636982bb629d23efba1e49c361e19237c435f19Timo Sirainen }
d695286ee8796c701f1911fefeb9bcb878dd2b32Timo Sirainen i_error("Received master input for invalid service_fd %u: %s",
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen service_fd, line);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen return;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen }
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen log = logs[service_fd];
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen client = hash_table_lookup(log->clients, POINTER_CAST(pid));
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
b636982bb629d23efba1e49c361e19237c435f19Timo Sirainen if (strcmp(cmd, "BYE") == 0) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen if (client == NULL) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen /* we haven't seen anything important from this client.
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen it's not an error. */
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen return;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen }
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen log_client_free(log, client, pid);
b636982bb629d23efba1e49c361e19237c435f19Timo Sirainen } else if (strncmp(cmd, "FATAL ", 6) == 0) {
b636982bb629d23efba1e49c361e19237c435f19Timo Sirainen client_log_fatal(log, client, cmd + 6, log_time, tm);
b636982bb629d23efba1e49c361e19237c435f19Timo Sirainen } else if (strncmp(cmd, "DEFAULT-FATAL ", 14) == 0) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen /* If the client has logged a fatal/panic, don't log this
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen message. */
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen if (client == NULL || !client->fatal_logged)
b636982bb629d23efba1e49c361e19237c435f19Timo Sirainen client_log_fatal(log, client, cmd + 14, log_time, tm);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen } else {
b636982bb629d23efba1e49c361e19237c435f19Timo Sirainen i_error("Received unknown command from master: %s", cmd);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
19c587fe07581d654721efb724ccc7fa8513abd6Timo Sirainenstatic void
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainenlog_it(struct log_connection *log, const char *line,
d4f004105cd7159aa9ade6b019eaecce9e94f382Timo Sirainen const struct timeval *log_time, const struct tm *tm)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct failure_line failure;
2303ad68175883aaebd1f3b18e69593c2422c7bbTimo Sirainen struct failure_context failure_ctx;
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen struct log_client *client = NULL;
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen const char *prefix;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen if (log->master) {
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen T_BEGIN {
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen log_parse_master_line(line, log_time, tm);
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen } T_END;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen return;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen }
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_failure_parse_line(line, &failure);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen switch (failure.log_type) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case LOG_TYPE_FATAL:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case LOG_TYPE_PANIC:
ea26d341b160373e5fa99bb6931d38429c91745aTimo Sirainen if (failure.pid != 0) {
ea26d341b160373e5fa99bb6931d38429c91745aTimo Sirainen client = log_client_get(log, failure.pid);
ea26d341b160373e5fa99bb6931d38429c91745aTimo Sirainen client->fatal_logged = TRUE;
ea26d341b160373e5fa99bb6931d38429c91745aTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case LOG_TYPE_OPTION:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen log_parse_option(log, &failure);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen default:
ea26d341b160373e5fa99bb6931d38429c91745aTimo Sirainen client = failure.pid == 0 ? NULL :
ea26d341b160373e5fa99bb6931d38429c91745aTimo Sirainen hash_table_lookup(log->clients,
ea26d341b160373e5fa99bb6931d38429c91745aTimo Sirainen POINTER_CAST(failure.pid));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(failure.log_type < LOG_TYPE_COUNT);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&failure_ctx);
2303ad68175883aaebd1f3b18e69593c2422c7bbTimo Sirainen failure_ctx.type = failure.log_type;
19c587fe07581d654721efb724ccc7fa8513abd6Timo Sirainen failure_ctx.timestamp = tm;
d4f004105cd7159aa9ade6b019eaecce9e94f382Timo Sirainen failure_ctx.timestamp_usecs = log_time->tv_usec;
2f366ea2725490208d4a163533a2c90757608849Timo Sirainen if (failure.disable_log_prefix)
2f366ea2725490208d4a163533a2c90757608849Timo Sirainen failure_ctx.log_prefix = "";
2303ad68175883aaebd1f3b18e69593c2422c7bbTimo Sirainen
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen prefix = client != NULL && client->prefix != NULL ?
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen client->prefix : log->default_prefix;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen client_log_ctx(log, &failure_ctx, log_time, prefix, failure.text);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainenstatic int log_connection_handshake(struct log_connection *log)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct log_service_handshake handshake;
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen const unsigned char *data;
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen size_t size;
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen ssize_t ret;
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen
0f27d0c9330143a8b08f6660d1dbe1cc921c209eTimo Sirainen /* we're reading from a FIFO, so we're assuming that we're getting a
0f27d0c9330143a8b08f6660d1dbe1cc921c209eTimo Sirainen full handshake packet immediately. if not, treat it as an error
0f27d0c9330143a8b08f6660d1dbe1cc921c209eTimo Sirainen message that we want to log. */
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen ret = i_stream_read(log->input);
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen if (ret < 0) {
0f27d0c9330143a8b08f6660d1dbe1cc921c209eTimo Sirainen i_error("read(log %s) failed: %s", log->default_prefix,
0f27d0c9330143a8b08f6660d1dbe1cc921c209eTimo Sirainen i_stream_get_error(log->input));
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen return -1;
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen }
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen if ((size_t)ret < sizeof(handshake)) {
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen /* this isn't a handshake */
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen return 0;
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen data = i_stream_get_data(log->input, &size);
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen i_assert(size >= sizeof(handshake));
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen memcpy(&handshake, data, sizeof(handshake));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen if (handshake.log_magic != MASTER_LOG_MAGIC) {
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen /* this isn't a handshake */
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen return 0;
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen if (handshake.prefix_len > size - sizeof(handshake)) {
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen i_error("Missing prefix data in handshake");
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
f6849394b03f483abe2172bfc553be5c2439ea17Timo Sirainen i_free(log->default_prefix);
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen log->default_prefix = i_strndup(data + sizeof(handshake),
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen handshake.prefix_len);
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen i_stream_skip(log->input, sizeof(handshake) + handshake.prefix_len);
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen if (strcmp(log->default_prefix, MASTER_LOG_PREFIX_NAME) == 0) {
3e8558a3a8e12b012e43976ead883bb5cc00ada4Timo Sirainen if (log->listen_fd != MASTER_LISTEN_FD_FIRST) {
3e8558a3a8e12b012e43976ead883bb5cc00ada4Timo Sirainen i_error("Received master prefix in handshake "
3e8558a3a8e12b012e43976ead883bb5cc00ada4Timo Sirainen "from non-master fd %d", log->fd);
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen return -1;
3e8558a3a8e12b012e43976ead883bb5cc00ada4Timo Sirainen }
3e8558a3a8e12b012e43976ead883bb5cc00ada4Timo Sirainen log->master = TRUE;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen log->handshaked = TRUE;
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void log_connection_input(struct log_connection *log)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen const char *line;
19c587fe07581d654721efb724ccc7fa8513abd6Timo Sirainen ssize_t ret;
f45d9079400cca2810f6c182b972924b42b55f33Timo Sirainen struct timeval now, start_timeval;
19c587fe07581d654721efb724ccc7fa8513abd6Timo Sirainen struct tm tm;
ffafd76c96f018523f23601bc57200ec013c84a4Timo Sirainen bool too_much = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen if (!log->handshaked) {
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen if (log_connection_handshake(log) < 0) {
f37939033c80f14b66868cc677179f9e54d729bdTimo Sirainen log_connection_destroy(log, FALSE);
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen return;
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen }
0f27d0c9330143a8b08f6660d1dbe1cc921c209eTimo Sirainen /* come back here even if we read something else besides a
0f27d0c9330143a8b08f6660d1dbe1cc921c209eTimo Sirainen handshake. the first few lines could be coming from e.g.
0f27d0c9330143a8b08f6660d1dbe1cc921c209eTimo Sirainen libc before the proper handshake line is sent. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
f45d9079400cca2810f6c182b972924b42b55f33Timo Sirainen io_loop_time_refresh();
f45d9079400cca2810f6c182b972924b42b55f33Timo Sirainen start_timeval = ioloop_timeval;
19c587fe07581d654721efb724ccc7fa8513abd6Timo Sirainen while ((ret = i_stream_read(log->input)) > 0 || ret == -2) {
19c587fe07581d654721efb724ccc7fa8513abd6Timo Sirainen /* get new timestamps for every read() */
452455bb3b7008907a6150ce56a4a1413dd07d75Timo Sirainen now = ioloop_timeval;
d4f004105cd7159aa9ade6b019eaecce9e94f382Timo Sirainen tm = *localtime(&now.tv_sec);
19c587fe07581d654721efb724ccc7fa8513abd6Timo Sirainen
19c587fe07581d654721efb724ccc7fa8513abd6Timo Sirainen while ((line = i_stream_next_line(log->input)) != NULL)
d4f004105cd7159aa9ade6b019eaecce9e94f382Timo Sirainen log_it(log, line, &now, &tm);
f45d9079400cca2810f6c182b972924b42b55f33Timo Sirainen io_loop_time_refresh();
ffafd76c96f018523f23601bc57200ec013c84a4Timo Sirainen if (timeval_diff_msecs(&ioloop_timeval, &start_timeval) > MAX_MSECS_PER_CONNECTION) {
ffafd76c96f018523f23601bc57200ec013c84a4Timo Sirainen too_much = TRUE;
f45d9079400cca2810f6c182b972924b42b55f33Timo Sirainen break;
ffafd76c96f018523f23601bc57200ec013c84a4Timo Sirainen }
19c587fe07581d654721efb724ccc7fa8513abd6Timo Sirainen }
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen
da3aebb67683adc7399de1fea5ca4218f9c746d3Timo Sirainen if (log->input->eof) {
da3aebb67683adc7399de1fea5ca4218f9c746d3Timo Sirainen if (log->input->stream_errno != 0)
da3aebb67683adc7399de1fea5ca4218f9c746d3Timo Sirainen i_error("read(log %s) failed: %m", log->default_prefix);
f37939033c80f14b66868cc677179f9e54d729bdTimo Sirainen log_connection_destroy(log, FALSE);
7feff164fa1a09aefcd6e41b8dcdf6d921440d26Timo Sirainen } else {
7feff164fa1a09aefcd6e41b8dcdf6d921440d26Timo Sirainen i_assert(!log->input->closed);
ffafd76c96f018523f23601bc57200ec013c84a4Timo Sirainen if (!too_much) {
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen if (log->pending_count > 0) {
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen log->pending_count = 0;
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen i_assert(global_pending_count > 0);
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen global_pending_count--;
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen if (log == last_pending_log)
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen last_pending_log = NULL;
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen log_refresh_proctitle();
aed2118ef7de81b1f7c4437991029cc043b23fa7Timo Sirainen }
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen return;
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen }
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen last_pending_log = log;
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen if (log->pending_count++ == 0) {
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen global_pending_count++;
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen log_refresh_proctitle();
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen }
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen if (log->pending_count == LOG_WARN_PENDING_COUNT ||
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen (log->pending_count % LOG_WARN_PENDING_INTERVAL) == 0) {
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen i_warning("Log connection fd %d listen_fd %d prefix '%s' is sending input faster than we can write",
f2880c3c3de56ec757ffc393363bb863efd7bcbeTimo Sirainen log->fd, log->listen_fd, log->default_prefix);
aed2118ef7de81b1f7c4437991029cc043b23fa7Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainenvoid log_connection_create(struct log_error_buffer *errorbuf,
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen int fd, int listen_fd)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct log_connection *log;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen log = i_new(struct log_connection, 1);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen log->errorbuf = errorbuf;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen log->fd = fd;
3e8558a3a8e12b012e43976ead883bb5cc00ada4Timo Sirainen log->listen_fd = listen_fd;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen log->io = io_add(fd, IO_READ, log_connection_input, log);
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi log->input = i_stream_create_fd(fd, PIPE_BUF);
f6849394b03f483abe2172bfc553be5c2439ea17Timo Sirainen log->default_prefix = i_strdup_printf("listen_fd %d", listen_fd);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create_direct(&log->clients, default_pool, 0);
3e8558a3a8e12b012e43976ead883bb5cc00ada4Timo Sirainen array_idx_set(&logs_by_fd, listen_fd, &log);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen DLLIST_PREPEND(&log_connections, log);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen log_connection_input(log);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
f37939033c80f14b66868cc677179f9e54d729bdTimo Sirainenstatic void
f37939033c80f14b66868cc677179f9e54d729bdTimo Sirainenlog_connection_destroy(struct log_connection *log, bool shutting_down)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct hash_iterate_context *iter;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen void *key;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen struct log_client *client;
f37939033c80f14b66868cc677179f9e54d729bdTimo Sirainen unsigned int client_count = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
3e8558a3a8e12b012e43976ead883bb5cc00ada4Timo Sirainen array_idx_clear(&logs_by_fd, log->listen_fd);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen DLLIST_REMOVE(&log_connections, log);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen iter = hash_table_iterate_init(log->clients);
f37939033c80f14b66868cc677179f9e54d729bdTimo Sirainen while (hash_table_iterate(iter, log->clients, &key, &client)) {
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen i_free(client);
f37939033c80f14b66868cc677179f9e54d729bdTimo Sirainen client_count++;
f37939033c80f14b66868cc677179f9e54d729bdTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hash_table_iterate_deinit(&iter);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hash_table_destroy(&log->clients);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
f37939033c80f14b66868cc677179f9e54d729bdTimo Sirainen if (client_count > 0 && shutting_down) {
f37939033c80f14b66868cc677179f9e54d729bdTimo Sirainen i_warning("Shutting down logging for '%s' with %u clients",
f37939033c80f14b66868cc677179f9e54d729bdTimo Sirainen log->default_prefix, client_count);
f37939033c80f14b66868cc677179f9e54d729bdTimo Sirainen }
f37939033c80f14b66868cc677179f9e54d729bdTimo Sirainen
0694891cdf35a905ba67b027d28c1657ede2b9c1Timo Sirainen i_stream_unref(&log->input);
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&log->io);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen if (close(log->fd) < 0)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen i_error("close(log connection fd) failed: %m");
b5f3c378bcb0df052f8d46ace0945e8cc1d2140eTimo Sirainen i_free(log->default_prefix);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_free(log);
9da1a079c12108658d58876cd8d157418b3b518cTimo Sirainen
9da1a079c12108658d58876cd8d157418b3b518cTimo Sirainen master_service_client_connection_destroyed(master_service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenvoid log_connections_init(void)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen{
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen i_array_init(&logs_by_fd, 64);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen}
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid log_connections_deinit(void)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* normally we don't exit until all log connections are gone,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen but we could get here when we're being killed by a signal */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen while (log_connections != NULL)
f37939033c80f14b66868cc677179f9e54d729bdTimo Sirainen log_connection_destroy(log_connections, TRUE);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen array_free(&logs_by_fd);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}