1
/* Copyright (c) 2011-2012 Dovecot authors, see the included COPYING file */
1
/* Copyright (c) 2011-2013 Dovecot authors, see the included COPYING file */
6
8
#include "write-full.h"
7
9
#include "time-util.h"
8
10
#include "istream.h"
9
11
#include "ostream.h"
12
#include "iostream-private.h"
13
#include "iostream-rawlog-private.h"
10
14
#include "istream-rawlog.h"
11
15
#include "ostream-rawlog.h"
12
#include "iostream-private.h"
13
#include "iostream-rawlog-private.h"
14
16
#include "iostream-rawlog.h"
16
18
#include <unistd.h>
21
#define RAWLOG_MAX_LINE_LEN 8192
20
24
rawlog_write(struct rawlog_iostream *rstream, const void *data, size_t size)
22
26
if (rstream->rawlog_fd == -1)
25
29
if (write_full(rstream->rawlog_fd, data, size) < 0) {
26
30
i_error("rawlog_istream.write(%s) failed: %m",
27
31
rstream->rawlog_path);
28
32
iostream_rawlog_close(rstream);
32
static void rawlog_write_timestamp(struct rawlog_iostream *rstream)
34
char buf[MAX_INT_STRLEN + 6 + 2];
36
i_snprintf(buf, sizeof(buf), "%lu.%06u ",
37
(unsigned long)ioloop_timeval.tv_sec,
38
(unsigned int)ioloop_timeval.tv_usec);
39
rawlog_write(rstream, buf, strlen(buf));
39
rawlog_write_timestamp(struct rawlog_iostream *rstream, bool line_ends)
41
unsigned char data[MAX_INT_STRLEN + 6 + 1 + 3];
44
buffer_create_from_data(&buf, data, sizeof(data));
45
str_printfa(&buf, "%lu.%06u ",
46
(unsigned long)ioloop_timeval.tv_sec,
47
(unsigned int)ioloop_timeval.tv_usec);
48
if ((rstream->flags & IOSTREAM_RAWLOG_FLAG_BUFFERED) != 0) {
49
str_append_c(&buf, rstream->input ? 'I' : 'O');
50
str_append_c(&buf, line_ends ? ':' : '>');
51
str_append_c(&buf, ' ');
53
return rawlog_write(rstream, buf.data, buf.used);
56
void iostream_rawlog_init(struct rawlog_iostream *rstream,
57
enum iostream_rawlog_flags flags, bool input)
59
rstream->flags = flags;
60
rstream->input = input;
61
if ((rstream->flags & IOSTREAM_RAWLOG_FLAG_BUFFERED) != 0)
62
rstream->buffer = buffer_create_dynamic(default_pool, 1024);
66
iostream_rawlog_write_unbuffered(struct rawlog_iostream *rstream,
67
const unsigned char *data, size_t size)
71
if (!rstream->line_continued) {
72
if (rawlog_write_timestamp(rstream, TRUE) < 0)
76
for (start = 0, i = 1; i < size; i++) {
77
if (data[i-1] == '\n') {
78
if (rawlog_write(rstream, data + start, i - start) < 0 ||
79
rawlog_write_timestamp(rstream, TRUE) < 0)
85
if (rawlog_write(rstream, data + start, size - start) < 0)
88
rstream->line_continued = data[size-1] != '\n';
42
91
void iostream_rawlog_write(struct rawlog_iostream *rstream,
43
92
const unsigned char *data, size_t size)
94
const unsigned char *p;
50
101
io_loop_time_refresh();
51
if (rstream->write_timestamp)
52
rawlog_write_timestamp(rstream);
54
for (start = 0, i = 1; i < size; i++) {
55
if (data[i-1] == '\n') {
56
rawlog_write(rstream, data + start, i - start);
57
rawlog_write_timestamp(rstream);
62
rawlog_write(rstream, data + start, size - start);
63
rstream->write_timestamp = data[size-1] == '\n';
102
if ((rstream->flags & IOSTREAM_RAWLOG_FLAG_BUFFERED) == 0) {
103
iostream_rawlog_write_unbuffered(rstream, data, size);
107
while (rstream->rawlog_fd != -1 && size > 0) {
108
p = memchr(data, '\n', size);
112
} else if (rstream->buffer->used + size < RAWLOG_MAX_LINE_LEN) {
113
buffer_append(rstream->buffer, data, size);
120
if (rawlog_write_timestamp(rstream, line_ends) < 0)
122
if (rstream->buffer->used > 0) {
123
if (rawlog_write(rstream, rstream->buffer->data,
124
rstream->buffer->used) < 0)
126
buffer_set_used_size(rstream->buffer, 0);
128
if (rawlog_write(rstream, data, pos) < 0)
66
136
void iostream_rawlog_close(struct rawlog_iostream *rstream)
68
if (rstream->autoclose_fd && rstream->rawlog_fd != -1) {
138
if ((rstream->flags & IOSTREAM_RAWLOG_FLAG_AUTOCLOSE) != 0 &&
139
rstream->rawlog_fd != -1) {
69
140
if (close(rstream->rawlog_fd) < 0) {
70
141
i_error("rawlog_istream.close(%s) failed: %m",
71
142
rstream->rawlog_path);
74
145
rstream->rawlog_fd = -1;
75
146
i_free_and_null(rstream->rawlog_path);
147
if (rstream->buffer != NULL)
148
buffer_free(&rstream->buffer);
78
151
int iostream_rawlog_create(const char *dir, struct istream **input,
79
152
struct ostream **output)
81
154
static unsigned int counter = 0;
82
const char *timestamp, *in_path, *out_path;
83
struct istream *old_input;
84
struct ostream *old_output;
155
const char *timestamp, *prefix;
87
157
timestamp = t_strflocaltime("%Y%m%d-%H%M%S", ioloop_time);
90
in_path = t_strdup_printf("%s/%s.%s.%u.in",
91
dir, timestamp, my_pid, counter);
92
out_path = t_strdup_printf("%s/%s.%s.%u.out",
93
dir, timestamp, my_pid, counter);
160
prefix = t_strdup_printf("%s/%s.%s.%u", dir, timestamp, my_pid, counter);
161
return iostream_rawlog_create_prefix(prefix, input, output);
164
int iostream_rawlog_create_prefix(const char *prefix, struct istream **input,
165
struct ostream **output)
167
const char *in_path, *out_path;
168
struct istream *old_input;
169
struct ostream *old_output;
172
in_path = t_strdup_printf("%s.in", prefix);
95
173
in_fd = open(in_path, O_CREAT | O_APPEND | O_WRONLY, 0600);
96
174
if (in_fd == -1) {
97
175
i_error("creat(%s) failed: %m", in_path);
179
out_path = t_strdup_printf("%s.out", prefix);
101
180
out_fd = open(out_path, O_CREAT | O_APPEND | O_WRONLY, 0600);
102
181
if (out_fd == -1) {
103
182
i_error("creat(%s) failed: %m", out_path);
105
184
(void)unlink(in_path);
109
188
old_input = *input;
110
189
old_output = *output;
111
*input = i_stream_create_rawlog(old_input, in_path, in_fd, TRUE);
112
*output = o_stream_create_rawlog(old_output, out_path, out_fd, TRUE);
190
*input = i_stream_create_rawlog(old_input, in_path, in_fd,
191
IOSTREAM_RAWLOG_FLAG_AUTOCLOSE);
192
*output = o_stream_create_rawlog(old_output, out_path, out_fd,
193
IOSTREAM_RAWLOG_FLAG_AUTOCLOSE);
194
i_stream_unref(&old_input);
195
o_stream_unref(&old_output);
199
int iostream_rawlog_create_path(const char *path, struct istream **input,
200
struct ostream **output)
202
struct istream *old_input;
203
struct ostream *old_output;
206
fd = open(path, O_CREAT | O_APPEND | O_WRONLY, 0600);
208
i_error("creat(%s) failed: %m", path);
213
old_output = *output;
214
*input = i_stream_create_rawlog(old_input, path, fd,
215
IOSTREAM_RAWLOG_FLAG_BUFFERED);
216
*output = o_stream_create_rawlog(old_output, path, fd,
217
IOSTREAM_RAWLOG_FLAG_AUTOCLOSE |
218
IOSTREAM_RAWLOG_FLAG_BUFFERED);
113
219
i_stream_unref(&old_input);
114
220
o_stream_unref(&old_output);