1
/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
7
#include "eacces-error.h"
9
#include "sieve-common.h"
10
#include "sieve-script.h"
11
#include "sieve-error-private.h"
13
#include <sys/types.h>
24
#define CRITICAL_MSG \
25
"internal error occurred: refer to server log for more information."
26
#define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]"
28
/* Logfile error handler will rotate log when it exceeds 10k bytes */
29
#define LOGFILE_MAX_SIZE (10 * 1024)
35
const char *sieve_error_script_location
36
(const struct sieve_script *script, unsigned int source_line)
40
sname = ( script == NULL ? NULL : sieve_script_name(script) );
42
if ( sname == NULL || *sname == '\0' )
43
return t_strdup_printf("line %d", source_line);
45
return t_strdup_printf("%s: line %d", sname, source_line);
49
* Main error functions
53
(struct sieve_error_handler *ehandler, const char *location,
54
const char *fmt, va_list args)
56
if ( ehandler == NULL ) return;
58
if ( ehandler->log_master ) {
61
VA_COPY(args_copy, args);
63
if ( location == NULL || *location == '\0' )
64
sieve_sys_error("%s", t_strdup_vprintf(fmt, args_copy));
66
sieve_sys_error("%s: %s", location, t_strdup_vprintf(fmt, args_copy));
69
if ( sieve_errors_more_allowed(ehandler) ) {
70
if ( ehandler->verror != NULL )
71
ehandler->verror(ehandler, location, fmt, args);
73
if ( ehandler->pool != NULL )
79
(struct sieve_error_handler *ehandler, const char *location,
80
const char *fmt, va_list args)
82
if ( ehandler == NULL ) return;
84
if ( ehandler->log_master ) {
87
VA_COPY(args_copy, args);
89
if ( location == NULL || *location == '\0' )
90
sieve_sys_warning("%s", t_strdup_vprintf(fmt, args_copy));
92
sieve_sys_warning("%s: %s", location, t_strdup_vprintf(fmt, args_copy));
95
if ( ehandler->vwarning != NULL )
96
ehandler->vwarning(ehandler, location, fmt, args);
98
if ( ehandler->pool != NULL )
103
(struct sieve_error_handler *ehandler, const char *location,
104
const char *fmt, va_list args)
106
if ( ehandler == NULL ) return;
108
if ( ehandler->log_master ) {
111
VA_COPY(args_copy, args);
114
if ( location == NULL || *location == '\0' )
115
sieve_sys_info("%s", t_strdup_vprintf(fmt, args_copy));
117
sieve_sys_info("%s: %s", location, t_strdup_vprintf(fmt, args_copy));
120
if ( ehandler->log_info && ehandler->vinfo != NULL )
121
ehandler->vinfo(ehandler, location, fmt, args);
125
(struct sieve_error_handler *ehandler, const char *location,
126
const char *fmt, va_list args)
131
tm = localtime(&ioloop_time);
133
if ( location == NULL || *location == '\0' )
134
sieve_sys_error("%s", t_strdup_vprintf(fmt, args));
136
sieve_sys_error("%s: %s", location, t_strdup_vprintf(fmt, args));
138
if ( ehandler == NULL ) return;
140
sieve_error(ehandler, location, "%s",
141
strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ?
142
str : CRITICAL_MSG );
149
unsigned int sieve_get_errors(struct sieve_error_handler *ehandler)
151
if ( ehandler == NULL || ehandler->pool == NULL ) return 0;
153
return ehandler->errors;
156
unsigned int sieve_get_warnings(struct sieve_error_handler *ehandler)
158
if ( ehandler == NULL || ehandler->pool == NULL ) return 0;
160
return ehandler->errors;
163
bool sieve_errors_more_allowed(struct sieve_error_handler *ehandler)
165
if ( ehandler == NULL || ehandler->pool == NULL )
168
return ehandler->max_errors == 0 || ehandler->errors < ehandler->max_errors;
172
* Error handler configuration
175
void sieve_error_handler_accept_infolog
176
(struct sieve_error_handler *ehandler, bool enable)
178
ehandler->log_info = enable;
181
void sieve_error_handler_copy_masterlog
182
(struct sieve_error_handler *ehandler, bool enable)
184
ehandler->log_master = enable;
191
void sieve_error_handler_init
192
(struct sieve_error_handler *ehandler, pool_t pool, unsigned int max_errors)
194
ehandler->pool = pool;
195
ehandler->refcount = 1;
196
ehandler->max_errors = max_errors;
198
ehandler->errors = 0;
199
ehandler->warnings = 0;
202
void sieve_error_handler_ref(struct sieve_error_handler *ehandler)
204
if ( ehandler == NULL || ehandler->pool == NULL ) return;
206
ehandler->refcount++;
209
void sieve_error_handler_unref(struct sieve_error_handler **ehandler)
211
if ( *ehandler == NULL || (*ehandler)->pool == NULL ) return;
213
i_assert((*ehandler)->refcount > 0);
215
if (--(*ehandler)->refcount != 0)
218
if ( (*ehandler)->free != NULL )
219
(*ehandler)->free(*ehandler);
221
pool_unref(&((*ehandler)->pool));
226
void sieve_error_handler_reset(struct sieve_error_handler *ehandler)
228
if ( ehandler == NULL || ehandler->pool == NULL ) return;
230
ehandler->errors = 0;
231
ehandler->warnings = 0;
235
* Master/System error handler
237
* - Output errors directly to Dovecot master log
240
static void sieve_master_verror
241
(struct sieve_error_handler *ehandler, const char *location,
242
const char *fmt, va_list args)
244
if ( ehandler->log_master ) return;
246
if ( location == NULL || *location == '\0' )
247
i_error("sieve: %s", t_strdup_vprintf(fmt, args));
249
i_error("sieve: %s: %s", location, t_strdup_vprintf(fmt, args));
252
static void sieve_master_vwarning
253
(struct sieve_error_handler *ehandler ATTR_UNUSED, const char *location,
254
const char *fmt, va_list args)
256
if ( ehandler->log_master ) return;
258
if ( location == NULL || *location == '\0' )
259
i_warning("sieve: %s", t_strdup_vprintf(fmt, args));
261
i_warning("sieve: %s: %s", location, t_strdup_vprintf(fmt, args));
264
static void sieve_master_vinfo
265
(struct sieve_error_handler *ehandler ATTR_UNUSED, const char *location,
266
const char *fmt, va_list args)
268
if ( ehandler->log_master ) return;
270
if ( location == NULL || *location == '\0' )
271
i_info("sieve: %s", t_strdup_vprintf(fmt, args));
273
i_info("sieve: %s: %s", location, t_strdup_vprintf(fmt, args));
276
struct sieve_error_handler *sieve_master_ehandler_create
277
(unsigned int max_errors)
280
struct sieve_error_handler *ehandler;
282
/* Pool is not strictly necessary, but other handler types will need a pool,
283
* so this one will have one too.
285
pool = pool_alloconly_create
286
("master_error_handler", sizeof(struct sieve_error_handler));
287
ehandler = p_new(pool, struct sieve_error_handler, 1);
288
sieve_error_handler_init(ehandler, pool, max_errors);
290
ehandler->verror = sieve_master_verror;
291
ehandler->vwarning = sieve_master_vwarning;
292
ehandler->vinfo = sieve_master_vinfo;
297
struct sieve_error_handler _sieve_system_ehandler_object = {
302
sieve_master_vwarning,
307
struct sieve_error_handler *_sieve_system_ehandler = &_sieve_system_ehandler_object;
309
void sieve_system_ehandler_set(struct sieve_error_handler *ehandler)
311
sieve_error_handler_unref(&_sieve_system_ehandler);
312
_sieve_system_ehandler = ehandler;
313
sieve_error_handler_ref(_sieve_system_ehandler);
316
void sieve_system_ehandler_reset(void)
318
sieve_error_handler_unref(&_sieve_system_ehandler);
319
_sieve_system_ehandler = &_sieve_system_ehandler_object;
323
* STDERR error handler
325
* - Output errors directly to stderror
328
static void sieve_stderr_verror
329
(struct sieve_error_handler *ehandler ATTR_UNUSED, const char *location,
330
const char *fmt, va_list args)
332
if ( location == NULL || *location == '\0' )
333
fprintf(stderr, "error: %s.\n", t_strdup_vprintf(fmt, args));
335
fprintf(stderr, "%s: error: %s.\n", location, t_strdup_vprintf(fmt, args));
338
static void sieve_stderr_vwarning
339
(struct sieve_error_handler *ehandler ATTR_UNUSED, const char *location,
340
const char *fmt, va_list args)
342
if ( location == NULL || *location == '\0' )
343
fprintf(stderr, "warning: %s.\n", t_strdup_vprintf(fmt, args));
345
fprintf(stderr, "%s: warning: %s.\n", location, t_strdup_vprintf(fmt, args));
348
static void sieve_stderr_vinfo
349
(struct sieve_error_handler *ehandler ATTR_UNUSED, const char *location,
350
const char *fmt, va_list args)
352
if ( location == NULL || *location == '\0' )
353
fprintf(stderr, "info: %s.\n", t_strdup_vprintf(fmt, args));
355
fprintf(stderr, "%s: info: %s.\n", location, t_strdup_vprintf(fmt, args));
358
struct sieve_error_handler *sieve_stderr_ehandler_create
359
(unsigned int max_errors)
362
struct sieve_error_handler *ehandler;
364
/* Pool is not strictly necessary, but other handler types will need a pool,
365
* so this one will have one too.
367
pool = pool_alloconly_create
368
("stderr_error_handler", sizeof(struct sieve_error_handler));
369
ehandler = p_new(pool, struct sieve_error_handler, 1);
370
sieve_error_handler_init(ehandler, pool, max_errors);
372
ehandler->verror = sieve_stderr_verror;
373
ehandler->vwarning = sieve_stderr_vwarning;
374
ehandler->vinfo = sieve_stderr_vinfo;
379
/* String buffer error handler
381
* - Output errors to a string buffer
384
struct sieve_strbuf_ehandler {
385
struct sieve_error_handler handler;
391
static void sieve_strbuf_verror
392
(struct sieve_error_handler *ehandler, const char *location,
393
const char *fmt, va_list args)
395
struct sieve_strbuf_ehandler *handler =
396
(struct sieve_strbuf_ehandler *) ehandler;
398
if ( location != NULL && *location != '\0' )
399
str_printfa(handler->errors, "%s: ", location);
400
str_append(handler->errors, "error: ");
401
str_vprintfa(handler->errors, fmt, args);
403
if ( !handler->crlf )
404
str_append(handler->errors, ".\n");
406
str_append(handler->errors, ".\r\n");
409
static void sieve_strbuf_vwarning
410
(struct sieve_error_handler *ehandler, const char *location,
411
const char *fmt, va_list args)
413
struct sieve_strbuf_ehandler *handler =
414
(struct sieve_strbuf_ehandler *) ehandler;
416
if ( location != NULL && *location != '\0' )
417
str_printfa(handler->errors, "%s: ", location);
418
str_printfa(handler->errors, "warning: ");
419
str_vprintfa(handler->errors, fmt, args);
421
if ( !handler->crlf )
422
str_append(handler->errors, ".\n");
424
str_append(handler->errors, ".\r\n");
427
static void sieve_strbuf_vinfo
428
(struct sieve_error_handler *ehandler, const char *location,
429
const char *fmt, va_list args)
431
struct sieve_strbuf_ehandler *handler =
432
(struct sieve_strbuf_ehandler *) ehandler;
434
if ( location != NULL && *location != '\0' )
435
str_printfa(handler->errors, "%s: ", location);
436
str_printfa(handler->errors, "info: ");
437
str_vprintfa(handler->errors, fmt, args);
439
if ( !handler->crlf )
440
str_append(handler->errors, ".\n");
442
str_append(handler->errors, ".\r\n");
445
struct sieve_error_handler *sieve_strbuf_ehandler_create
446
(string_t *strbuf, bool crlf, unsigned int max_errors)
449
struct sieve_strbuf_ehandler *ehandler;
451
pool = pool_alloconly_create("strbuf_error_handler", 256);
452
ehandler = p_new(pool, struct sieve_strbuf_ehandler, 1);
453
ehandler->errors = strbuf;
455
sieve_error_handler_init(&ehandler->handler, pool, max_errors);
457
ehandler->handler.verror = sieve_strbuf_verror;
458
ehandler->handler.vwarning = sieve_strbuf_vwarning;
459
ehandler->handler.vinfo = sieve_strbuf_vinfo;
461
ehandler->crlf = crlf;
463
return &(ehandler->handler);
467
* Logfile error handler
469
* - Output errors to a log file
472
struct sieve_logfile_ehandler {
473
struct sieve_error_handler handler;
478
struct ostream *stream;
481
static void sieve_logfile_vprintf
482
(struct sieve_logfile_ehandler *ehandler, const char *location,
483
const char *prefix, const char *fmt, va_list args)
486
ssize_t ret = 0, remain;
489
if ( ehandler->stream == NULL ) return;
492
outbuf = t_str_new(256);
493
if ( location != NULL && *location != '\0' )
494
str_printfa(outbuf, "%s: ", location);
495
str_printfa(outbuf, "%s: ", prefix);
496
str_vprintfa(outbuf, fmt, args);
497
str_append(outbuf, ".\n");
499
remain = str_len(outbuf);
500
data = (const char *) str_data(outbuf);
502
while ( remain > 0 ) {
503
if ( (ret=o_stream_send(ehandler->stream, data, remain)) < 0 )
513
"o_stream_send() failed on logfile %s: %m", ehandler->logfile);
517
inline static void sieve_logfile_printf
518
(struct sieve_logfile_ehandler *ehandler, const char *location, const char *prefix,
519
const char *fmt, ...)
524
sieve_logfile_vprintf(ehandler, location, prefix, fmt, args);
529
static void sieve_logfile_start(struct sieve_logfile_ehandler *ehandler)
532
struct ostream *ostream = NULL;
538
/* Open the logfile */
540
fd = open(ehandler->logfile, O_CREAT | O_APPEND | O_WRONLY, 0600);
542
if ( errno == EACCES ) {
543
sieve_sys_error("failed to open logfile (LOGGING TO STDERR): %s",
544
eacces_error_get_creating("open", ehandler->logfile));
546
sieve_sys_error("failed to open logfile (LOGGING TO STDERR): "
547
"open(%s) failed: %m", ehandler->logfile);
551
/* fd_close_on_exec(fd, TRUE); Necessary? */
553
/* Stat the log file to obtain size information */
554
if ( fstat(fd, &st) != 0 ) {
555
sieve_sys_error("failed to stat logfile (logging to STDERR): "
556
"fstat(fd=%s) failed: %m", ehandler->logfile);
558
if ( close(fd) < 0 ) {
559
sieve_sys_error("failed to close logfile after error: "
560
"close(fd=%s) failed: %m", ehandler->logfile);
566
/* Rotate log when it has grown too large */
567
if ( st.st_size >= LOGFILE_MAX_SIZE ) {
570
/* Close open file */
571
if ( close(fd) < 0 ) {
572
sieve_sys_error("failed to close logfile: close(fd=%s) failed: %m",
577
rotated = t_strconcat(ehandler->logfile, ".0", NULL);
578
if ( rename(ehandler->logfile, rotated) < 0 ) {
579
sieve_sys_error("failed to rotate logfile: rename(%s, %s) failed: %m",
580
ehandler->logfile, rotated);
583
/* Open clean logfile (overwrites existing if rename() failed earlier) */
584
fd = open(ehandler->logfile, O_CREAT | O_WRONLY | O_TRUNC, 0600);
586
if ( errno == EACCES ) {
587
sieve_sys_error("failed to open logfile (LOGGING TO STDERR): %s",
588
eacces_error_get_creating("open", ehandler->logfile));
590
sieve_sys_error("failed to open logfile (LOGGING TO STDERR): "
591
"open(%s) failed: %m", ehandler->logfile);
598
ostream = o_stream_create_fd(fd, 0, FALSE);
599
if ( ostream == NULL ) {
600
/* Can't we do anything else in this most awkward situation? */
601
sieve_sys_error("failed to open log stream on open file: "
602
"o_stream_create_fd(fd=%s) failed "
603
"(non-critical messages are not logged!)", ehandler->logfile);
607
ehandler->stream = ostream;
608
ehandler->started = TRUE;
610
if ( ostream != NULL ) {
612
tm = localtime(&now);
614
if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", tm) > 0) {
615
sieve_logfile_printf(ehandler, "sieve", "info",
616
"started log at %s", buf);
621
static void sieve_logfile_verror
622
(struct sieve_error_handler *ehandler, const char *location,
623
const char *fmt, va_list args)
625
struct sieve_logfile_ehandler *handler =
626
(struct sieve_logfile_ehandler *) ehandler;
628
if ( !handler->started ) sieve_logfile_start(handler);
630
sieve_logfile_vprintf(handler, location, "error", fmt, args);
633
static void sieve_logfile_vwarning
634
(struct sieve_error_handler *ehandler, const char *location,
635
const char *fmt, va_list args)
637
struct sieve_logfile_ehandler *handler =
638
(struct sieve_logfile_ehandler *) ehandler;
640
if ( !handler->started ) sieve_logfile_start(handler);
642
sieve_logfile_vprintf(handler, location, "warning", fmt, args);
645
static void sieve_logfile_vinfo
646
(struct sieve_error_handler *ehandler, const char *location,
647
const char *fmt, va_list args)
649
struct sieve_logfile_ehandler *handler =
650
(struct sieve_logfile_ehandler *) ehandler;
652
if ( !handler->started ) sieve_logfile_start(handler);
654
sieve_logfile_vprintf(handler, location, "info", fmt, args);
657
static void sieve_logfile_free
658
(struct sieve_error_handler *ehandler)
660
struct sieve_logfile_ehandler *handler =
661
(struct sieve_logfile_ehandler *) ehandler;
663
if ( handler->stream != NULL ) {
664
o_stream_destroy(&(handler->stream));
665
if ( handler->fd != STDERR_FILENO ){
666
if ( close(handler->fd) < 0 ) {
667
sieve_sys_error("failed to close logfile: "
668
"close(fd=%s) failed: %m", handler->logfile);
674
struct sieve_error_handler *sieve_logfile_ehandler_create
675
(const char *logfile, unsigned int max_errors)
678
struct sieve_logfile_ehandler *ehandler;
680
pool = pool_alloconly_create("logfile_error_handler", 256);
681
ehandler = p_new(pool, struct sieve_logfile_ehandler, 1);
682
sieve_error_handler_init(&ehandler->handler, pool, max_errors);
684
ehandler->handler.verror = sieve_logfile_verror;
685
ehandler->handler.vwarning = sieve_logfile_vwarning;
686
ehandler->handler.vinfo = sieve_logfile_vinfo;
687
ehandler->handler.free = sieve_logfile_free;
689
/* Don't open logfile until something is actually logged.
690
* Let's not pullute the sieve directory with useless logfiles.
692
ehandler->logfile = p_strdup(pool, logfile);
693
ehandler->started = FALSE;
694
ehandler->stream = NULL;
697
return &(ehandler->handler);