883N/A/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
883N/A
883N/A#include "common.h"
883N/A#include "array.h"
883N/A#include "aqueue.h"
883N/A#include "hash.h"
883N/A#include "ioloop.h"
883N/A#include "service.h"
883N/A#include "service-process.h"
883N/A#include "service-process-notify.h"
883N/A#include "service-anvil.h"
883N/A#include "service-log.h"
883N/A
883N/A#include <unistd.h>
883N/A
883N/Astatic int service_log_fds_init(const char *log_prefix, int log_fd[2],
883N/A buffer_t *handshake_buf)
883N/A{
883N/A struct log_service_handshake handshake;
883N/A ssize_t ret;
883N/A
883N/A i_assert(log_fd[0] == -1);
3996N/A
883N/A if (pipe(log_fd) < 0) {
883N/A i_error("pipe() failed: %m");
883N/A return -1;
883N/A }
883N/A fd_close_on_exec(log_fd[0], TRUE);
883N/A fd_close_on_exec(log_fd[1], TRUE);
883N/A
883N/A i_zero(&handshake);
883N/A handshake.log_magic = MASTER_LOG_MAGIC;
1273N/A handshake.prefix_len = strlen(log_prefix);
883N/A
4561N/A buffer_set_used_size(handshake_buf, 0);
4561N/A buffer_append(handshake_buf, &handshake, sizeof(handshake));
4561N/A buffer_append(handshake_buf, log_prefix, strlen(log_prefix));
4561N/A
4561N/A ret = write(log_fd[1], handshake_buf->data, handshake_buf->used);
4561N/A if (ret < 0) {
4561N/A i_error("write(log handshake) failed: %m");
883N/A return -1;
883N/A }
883N/A if ((size_t)ret != handshake_buf->used) {
883N/A i_error("write(log handshake) didn't write everything");
883N/A return -1;
883N/A }
883N/A return 0;
1653N/A}
883N/A
956N/Astatic int
883N/Aservice_process_write_log_bye(int fd, struct service_process *process)
883N/A{
883N/A const char *data;
883N/A
883N/A if (process->service->log_process_internal_fd == -1) {
883N/A /* another log process was just destroyed */
883N/A return 0;
883N/A }
1574N/A
1574N/A data = t_strdup_printf("%d %s BYE\n",
1574N/A process->service->log_process_internal_fd,
883N/A dec2str(process->pid));
883N/A if (write(fd, data, strlen(data)) < 0) {
883N/A if (errno != EAGAIN)
883N/A i_error("write(log process) failed: %m");
883N/A return -1;
883N/A }
883N/A return 0;
883N/A}
883N/A
883N/Aint services_log_init(struct service_list *service_list)
887N/A{
887N/A struct service *const *services;
887N/A const char *log_prefix;
913N/A buffer_t *handshake_buf;
913N/A ssize_t ret = 0;
913N/A int fd;
913N/A
883N/A handshake_buf = buffer_create_dynamic(default_pool, 256);
3996N/A if (service_log_fds_init(MASTER_LOG_PREFIX_NAME,
3996N/A service_list->master_log_fd,
handshake_buf) < 0)
ret = -1;
else
fd_set_nonblock(service_list->master_log_fd[1], TRUE);
i_assert(service_list->log_byes == NULL);
service_list->log_byes =
service_process_notify_init(service_list->master_log_fd[1],
service_process_write_log_bye);
fd = MASTER_LISTEN_FD_FIRST + 1;
array_foreach(&service_list->services, services) {
struct service *service = *services;
if (service->type == SERVICE_TYPE_LOG)
continue;
log_prefix = t_strconcat(service->set->name, ": ", NULL);
if (service_log_fds_init(log_prefix, service->log_fd,
handshake_buf) < 0) {
ret = -1;
break;
}
service->log_process_internal_fd = fd++;
}
buffer_free(&handshake_buf);
if (ret < 0) {
services_log_deinit(service_list);
return -1;
}
service_anvil_send_log_fd();
return 0;
}
void services_log_deinit(struct service_list *service_list)
{
struct service *const *services;
unsigned int i, count;
services = array_get(&service_list->services, &count);
for (i = 0; i < count; i++) {
if (services[i]->log_fd[0] != -1) {
if (close(services[i]->log_fd[0]) < 0) {
service_error(services[i],
"close(log_fd) failed: %m");
}
if (close(services[i]->log_fd[1]) < 0) {
service_error(services[i],
"close(log_fd) failed: %m");
}
services[i]->log_fd[0] = -1;
services[i]->log_fd[1] = -1;
services[i]->log_process_internal_fd = -1;
}
}
if (service_list->log_byes != NULL)
service_process_notify_deinit(&service_list->log_byes);
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,
struct service_list *service_list,
unsigned int first_fd, unsigned int *fd_count)
{
struct service *const *services;
unsigned int n = 0;
/* master log fd is always the first one */
dup2_append(dups, service_list->master_log_fd[0], first_fd);
n++; *fd_count += 1;
array_foreach(&service_list->services, services) {
struct service *service = *services;
if (service->log_fd[1] == -1)
continue;
i_assert((int)(first_fd + n) == service->log_process_internal_fd);
dup2_append(dups, service->log_fd[0], first_fd + n);
n++; *fd_count += 1;
}
}