rawlog.c revision fcae6bd5f2fa9da7ef1302279488b6ed97cf8e3c
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina#define TIMESTAMP_FORMAT "* OK [RAWLOG TIMESTAMP] %Y-%m-%d %H:%M:%S\n"
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina struct ostream *client_output, *server_output;
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březinastatic void rawlog_proxy_destroy(struct rawlog_proxy *proxy)
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březinastatic void proxy_write_in(struct rawlog_proxy *proxy,
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina if ((proxy->flags & RAWLOG_FLAG_LOG_BOUNDARIES) != 0)
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina if (write_full(proxy->fd_in, data, size) < 0) {
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina /* failed, disable logging */
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina } else if ((proxy->flags & RAWLOG_FLAG_LOG_BOUNDARIES) != 0) {
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březinastatic void proxy_write_out(struct rawlog_proxy *proxy,
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina (proxy->flags & RAWLOG_FLAG_LOG_TIMESTAMPS) != 0 &&
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina ioloop_time - proxy->last_write >= TIMESTAMP_WAIT_TIME) {
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina if (strftime(buf, sizeof(buf), TIMESTAMP_FORMAT, tm) <= 0)
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina if (write_full(proxy->fd_out, buf, strlen(buf)) < 0)
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina if ((proxy->flags & RAWLOG_FLAG_LOG_BOUNDARIES) != 0)
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina if (write_full(proxy->fd_out, data, size) < 0) {
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina /* failed, disable logging */
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina } else if ((proxy->flags & RAWLOG_FLAG_LOG_BOUNDARIES) != 0) {
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina proxy->last_out_lf = ((const unsigned char *)buf)[size-1] == '\n' ||
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina (proxy->flags & RAWLOG_FLAG_LOG_BOUNDARIES) != 0;
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březinastatic void server_input(struct rawlog_proxy *proxy)
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina if (o_stream_get_buffer_used_size(proxy->client_output) >
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina /* client's output buffer is already quite full.
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina don't send more until we're below threshold. */
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina ret = net_receive(proxy->server_fd, buf, sizeof(buf));
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina (void)o_stream_send(proxy->client_output, buf, ret);
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina } else if (ret <= 0)
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březinastatic void client_input(struct rawlog_proxy *proxy)
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina if (o_stream_get_buffer_used_size(proxy->server_output) >
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina /* proxy's output buffer is already quite full.
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina don't send more until we're below threshold. */
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina ret = net_receive(proxy->client_in_fd, buf, sizeof(buf));
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina (void)o_stream_send(proxy->server_output, buf, ret);
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina } else if (ret < 0)
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březinastatic int server_output(struct rawlog_proxy *proxy)
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina if (o_stream_flush(proxy->server_output) < 0) {
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina o_stream_get_buffer_used_size(proxy->server_output) <
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina /* there's again space in proxy's output buffer, so we can
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina read more from client. */
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina proxy->client_io = io_add(proxy->client_in_fd, IO_READ,
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březinastatic int client_output(struct rawlog_proxy *proxy)
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina if (o_stream_flush(proxy->client_output) < 0) {
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina o_stream_get_buffer_used_size(proxy->client_output) <
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina /* there's again space in client's output buffer, so we can
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina read more from proxy. */
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina io_add(proxy->server_fd, IO_READ, server_input, proxy);
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březinastatic void proxy_open_logs(struct rawlog_proxy *proxy, const char *path)
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina if (strftime(timestamp, sizeof(timestamp), "%Y%m%d-%H%M%S", tm) <= 0)
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina if ((proxy->flags & RAWLOG_FLAG_LOG_INPUT) != 0) {
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina fname = t_strdup_printf("%s/%s-%s.in", path, timestamp,
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina proxy->fd_in = open(fname, O_CREAT|O_EXCL|O_WRONLY, 0600);
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina i_error("rawlog_open: open() failed for %s: %m", fname);
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina if ((proxy->flags & RAWLOG_FLAG_LOG_OUTPUT) != 0) {
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina fname = t_strdup_printf("%s/%s-%s.out", path, timestamp,
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina proxy->fd_out = open(fname, O_CREAT|O_EXCL|O_WRONLY, 0600);
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina i_error("rawlog_open: open() failed for %s: %m", fname);
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březinarawlog_proxy_create(int client_in_fd, int client_out_fd, int server_fd,
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina i_stream_create_fd(server_fd, MAX_PROXY_INPUT_SIZE, FALSE);
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina proxy->server_output = o_stream_create_fd(server_fd, (size_t)-1, FALSE);
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina proxy->server_io = io_add(server_fd, IO_READ, server_input, proxy);
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina o_stream_set_flush_callback(proxy->server_output, server_output, proxy);
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina o_stream_create_fd(client_out_fd, (size_t)-1, FALSE);
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina proxy->client_io = io_add(proxy->client_in_fd, IO_READ,
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina o_stream_set_flush_callback(proxy->client_output, client_output, proxy);
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březinastatic void rawlog_open(enum rawlog_flags flags)
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina /* see if we want rawlog */
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina path = t_strconcat(home, "/dovecot.rawlog", NULL);
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina i_info("rawlog: %s is not a directory", path);
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina /* we'll chroot soon. skip over the chroot in the path. */
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) < 0)
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina process_title_set(t_strdup_printf("[%s:%s rawlog]", getenv("USER"),
a2057618f30a3c64bdffb35a2ef3c2ba148c8a03Pavel Březina rawlog_proxy_create(0, 1, sfd[0], path, flags);
a2057618f30a3c64bdffb35a2ef3c2ba148c8a03Pavel Březina flags = RAWLOG_FLAG_LOG_INPUT | RAWLOG_FLAG_LOG_OUTPUT;
argc = 0;
argc--;
argv++;
return FATAL_EXEC;