From f95bab5c40f35da6a2edf54ce467414f1f5866bd Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Wed, 6 Apr 2016 00:28:29 +0200 Subject: [PATCH] lib-sieve: Implemented support for writing runtime trace output to a directory if it exists, much like Dovecot rawlog. --- src/lib-sieve/sieve-common.h | 8 +++ src/lib-sieve/sieve-interpreter.c | 4 +- src/lib-sieve/sieve-runtime-trace.c | 6 +- src/lib-sieve/sieve-runtime-trace.h | 2 +- src/lib-sieve/sieve-types.h | 3 +- src/lib-sieve/sieve.c | 92 +++++++++++++++++++++++++++++ src/lib-sieve/sieve.h | 16 +++++ src/sieve-tools/sieve-test.c | 23 +++++--- src/testsuite/testsuite-script.c | 4 +- src/testsuite/testsuite.c | 25 ++++---- 10 files changed, 153 insertions(+), 30 deletions(-) diff --git a/src/lib-sieve/sieve-common.h b/src/lib-sieve/sieve-common.h index c832dc865..508958c23 100644 --- a/src/lib-sieve/sieve-common.h +++ b/src/lib-sieve/sieve-common.h @@ -216,4 +216,12 @@ struct sieve_instance { struct sieve_mail_sender redirect_from; }; +/* + * Script trace log + */ + +void sieve_trace_log_write_line + (struct sieve_trace_log *trace_log, const string_t *line) + ATTR_NULL(2); + #endif /* __SIEVE_COMMON_H */ diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c index a9bb38be2..08063a3d6 100644 --- a/src/lib-sieve/sieve-interpreter.c +++ b/src/lib-sieve/sieve-interpreter.c @@ -130,8 +130,8 @@ static struct sieve_interpreter *_sieve_interpreter_create interp->runenv.msgdata = msgdata; interp->runenv.scriptenv = senv; - if ( senv->trace_stream != NULL ) { - interp->trace.stream = senv->trace_stream; + if ( senv->trace_log != NULL ) { + interp->trace.log = senv->trace_log; interp->trace.config = senv->trace_config; interp->trace.indent = 0; interp->runenv.trace = &interp->trace; diff --git a/src/lib-sieve/sieve-runtime-trace.c b/src/lib-sieve/sieve-runtime-trace.c index c14375ef9..e4798bdc5 100644 --- a/src/lib-sieve/sieve-runtime-trace.c +++ b/src/lib-sieve/sieve-runtime-trace.c @@ -36,15 +36,13 @@ static inline string_t *_trace_line_new static inline void _trace_line_print (string_t *trline, const struct sieve_runtime_env *renv) { - str_append_c(trline, '\n'); - - o_stream_send(renv->trace->stream, str_data(trline), str_len(trline)); + sieve_trace_log_write_line(renv->trace->log, trline); } static inline void _trace_line_print_empty (const struct sieve_runtime_env *renv) { - o_stream_send_str(renv->trace->stream, "\n"); + sieve_trace_log_write_line(renv->trace->log, NULL); } /* diff --git a/src/lib-sieve/sieve-runtime-trace.h b/src/lib-sieve/sieve-runtime-trace.h index b479cb6a4..2b19c27b0 100644 --- a/src/lib-sieve/sieve-runtime-trace.h +++ b/src/lib-sieve/sieve-runtime-trace.h @@ -13,7 +13,7 @@ struct sieve_runtime_trace { struct sieve_trace_config config; - struct ostream *stream; + struct sieve_trace_log *log; unsigned int indent; }; diff --git a/src/lib-sieve/sieve-types.h b/src/lib-sieve/sieve-types.h index fcc4b8719..1c3e84674 100644 --- a/src/lib-sieve/sieve-types.h +++ b/src/lib-sieve/sieve-types.h @@ -21,6 +21,7 @@ struct sieve_binary; struct sieve_message_data; struct sieve_script_env; struct sieve_exec_status; +struct sieve_trace_log; /* * System environment @@ -225,7 +226,7 @@ struct sieve_script_env { struct sieve_exec_status *exec_status; /* Runtime trace*/ - struct ostream *trace_stream; + struct sieve_trace_log *trace_log; struct sieve_trace_config trace_config; }; diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c index b29f5c547..c6fe99485 100644 --- a/src/lib-sieve/sieve.c +++ b/src/lib-sieve/sieve.c @@ -4,9 +4,12 @@ #include "lib.h" #include "str.h" #include "istream.h" +#include "ostream.h" #include "buffer.h" +#include "time-util.h" #include "eacces-error.h" #include "home-expand.h" +#include "hostpid.h" #include "sieve-settings.h" #include "sieve-extensions.h" @@ -796,5 +799,94 @@ size_t sieve_max_script_size(struct sieve_instance *svinst) return svinst->max_script_size; } +/* + * Script trace log + */ + +struct sieve_trace_log { + struct ostream *output; +}; + +int sieve_trace_log_create +(struct sieve_instance *svinst, const char *path, + struct sieve_trace_log **trace_log_r) +{ + struct sieve_trace_log *trace_log; + struct ostream *output; + int fd; + + *trace_log_r = NULL; + + if ( path == NULL ) { + output = o_stream_create_fd(1, 0, FALSE); + } else { + fd = open(path, O_CREAT | O_APPEND | O_WRONLY, 0600); + if ( fd == -1 ) { + sieve_sys_error(svinst, "trace: " + "creat(%s) failed: %m", path); + return -1; + } + output = o_stream_create_fd_autoclose(&fd, 0); + } + + trace_log = i_new(struct sieve_trace_log, 1); + trace_log->output = output; + + *trace_log_r = trace_log; + return 0; +} + +int sieve_trace_log_create_dir +(struct sieve_instance *svinst, const char *dir, + struct sieve_trace_log **trace_log_r) +{ + static unsigned int counter = 0; + const char *timestamp, *prefix; + struct stat st; + + *trace_log_r = NULL; + if (stat(dir, &st) < 0) { + if (errno != ENOENT && errno != EACCES) { + sieve_sys_error(svinst, "trace: " + "stat(%s) failed: %m", dir); + } + return -1; + } + + timestamp = t_strflocaltime("%Y%m%d-%H%M%S", ioloop_time); + + counter++; + prefix = t_strdup_printf("%s/%s.%s.%u.trace", + dir, timestamp, my_pid, counter); + return sieve_trace_log_create(svinst, prefix, trace_log_r); +} + +void sieve_trace_log_write_line +(struct sieve_trace_log *trace_log, const string_t *line) +{ + struct const_iovec iov[2]; + + if (line == NULL) { + o_stream_send_str(trace_log->output, "\n"); + return; + } + + memset(iov, 0, sizeof(iov)); + iov[0].iov_base = str_data(line); + iov[0].iov_len = str_len(line); + iov[1].iov_base = "\n"; + iov[1].iov_len = 1; + o_stream_sendv(trace_log->output, iov, 2); +} + +void sieve_trace_log_free(struct sieve_trace_log **_trace_log) +{ + struct sieve_trace_log *trace_log = *_trace_log; + + *_trace_log = NULL; + + o_stream_destroy(&trace_log->output); + i_free(trace_log); +} diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h index 9ed3d61a0..3e108e02a 100644 --- a/src/lib-sieve/sieve.h +++ b/src/lib-sieve/sieve.h @@ -213,4 +213,20 @@ unsigned int sieve_max_redirects(struct sieve_instance *svinst); unsigned int sieve_max_actions(struct sieve_instance *svinst); size_t sieve_max_script_size(struct sieve_instance *svinst); +/* + * Script trace log + */ + +struct sieve_trace_log; + +int sieve_trace_log_create + (struct sieve_instance *svinst, const char *path, + struct sieve_trace_log **trace_log_r) + ATTR_NULL(2); +int sieve_trace_log_create_dir + (struct sieve_instance *svinst, const char *dir, + struct sieve_trace_log **trace_log_r); + +void sieve_trace_log_free(struct sieve_trace_log **_trace_log); + #endif diff --git a/src/sieve-tools/sieve-test.c b/src/sieve-tools/sieve-test.c index 316bfab5d..3d884544e 100644 --- a/src/sieve-tools/sieve-test.c +++ b/src/sieve-tools/sieve-test.c @@ -124,7 +124,7 @@ int main(int argc, char **argv) ARRAY_TYPE (const_string) scriptfiles; const char *scriptfile, *recipient, *final_recipient, *sender, *mailbox, *dumpfile, *tracefile, *mailfile, *mailloc; - struct sieve_trace_config tr_config; + struct sieve_trace_config trace_config; struct mail *mail; struct sieve_binary *main_sbin, *sbin = NULL; struct sieve_message_data msgdata; @@ -132,7 +132,7 @@ int main(int argc, char **argv) struct sieve_exec_status estatus; struct sieve_error_handler *ehandler, *action_ehandler; struct ostream *teststream = NULL; - struct ostream *tracestream = NULL; + struct sieve_trace_log *trace_log = NULL; bool force_compile = FALSE, execute = FALSE; int exit_status = EXIT_SUCCESS; int ret, c; @@ -146,8 +146,8 @@ int main(int argc, char **argv) /* Parse arguments */ recipient = final_recipient = sender = mailbox = dumpfile = tracefile = mailloc = NULL; - memset(&tr_config, 0, sizeof(tr_config)); - tr_config.level = SIEVE_TRLVL_ACTIONS; + memset(&trace_config, 0, sizeof(trace_config)); + trace_config.level = SIEVE_TRLVL_ACTIONS; while ((c = sieve_tool_getopt(sieve_tool)) > 0) { switch (c) { case 'r': @@ -176,7 +176,7 @@ int main(int argc, char **argv) break; /* trace options */ case 'T': - sieve_tool_parse_trace_option(&tr_config, optarg); + sieve_tool_parse_trace_option(&trace_config, optarg); break; case 'd': /* dump file */ @@ -287,8 +287,11 @@ int main(int argc, char **argv) ( msgdata.id == NULL ? "unspecified" : msgdata.id ))); } - if ( tracefile != NULL ) - tracestream = sieve_tool_open_output_stream(tracefile); + if ( tracefile != NULL ) { + (void)sieve_trace_log_create(svinst, + (strcmp(tracefile, "-") == 0 ? NULL : tracefile), + &trace_log); + } /* Compose script environment */ memset(&scriptenv, 0, sizeof(scriptenv)); @@ -301,8 +304,8 @@ int main(int argc, char **argv) scriptenv.smtp_finish = sieve_smtp_finish; scriptenv.duplicate_mark = duplicate_mark; scriptenv.duplicate_check = duplicate_check; - scriptenv.trace_stream = tracestream; - scriptenv.trace_config = tr_config; + scriptenv.trace_log = trace_log; + scriptenv.trace_config = trace_config; scriptenv.exec_status = &estatus; /* Run the test */ @@ -412,6 +415,8 @@ int main(int argc, char **argv) if ( teststream != NULL ) o_stream_destroy(&teststream); + if ( trace_log != NULL ) + sieve_trace_log_free(&trace_log); /* Cleanup remaining binaries */ if ( sbin != NULL ) diff --git a/src/testsuite/testsuite-script.c b/src/testsuite/testsuite-script.c index e99e4e788..e85c9ab78 100644 --- a/src/testsuite/testsuite-script.c +++ b/src/testsuite/testsuite-script.c @@ -116,7 +116,7 @@ bool testsuite_script_run(const struct sieve_runtime_env *renv) scriptenv.duplicate_mark = NULL; scriptenv.duplicate_check = NULL; scriptenv.user = renv->scriptenv->user; - scriptenv.trace_stream = renv->scriptenv->trace_stream; + scriptenv.trace_log = renv->scriptenv->trace_log; scriptenv.trace_config = renv->scriptenv->trace_config; result = testsuite_result_get(); @@ -189,7 +189,7 @@ bool testsuite_script_multiscript scriptenv.duplicate_mark = NULL; scriptenv.duplicate_check = NULL; scriptenv.user = renv->scriptenv->user; - scriptenv.trace_stream = renv->scriptenv->trace_stream; + scriptenv.trace_log = renv->scriptenv->trace_log; scriptenv.trace_config = renv->scriptenv->trace_config; /* Start execution */ diff --git a/src/testsuite/testsuite.c b/src/testsuite/testsuite.c index 2d8f5e1a0..38bcf84e8 100644 --- a/src/testsuite/testsuite.c +++ b/src/testsuite/testsuite.c @@ -84,7 +84,7 @@ int main(int argc, char **argv) { struct sieve_instance *svinst; const char *scriptfile, *dumpfile, *tracefile; - struct sieve_trace_config tr_config; + struct sieve_trace_config trace_config; struct sieve_binary *sbin; const char *sieve_dir; bool log_stdout = FALSE; @@ -95,8 +95,8 @@ int main(int argc, char **argv) /* Parse arguments */ dumpfile = tracefile = NULL; - memset(&tr_config, 0, sizeof(tr_config)); - tr_config.level = SIEVE_TRLVL_ACTIONS; + memset(&trace_config, 0, sizeof(trace_config)); + trace_config.level = SIEVE_TRLVL_ACTIONS; while ((c = sieve_tool_getopt(sieve_tool)) > 0) { switch (c) { case 'd': @@ -108,7 +108,7 @@ int main(int argc, char **argv) tracefile = optarg; break; case 'T': - sieve_tool_parse_trace_option(&tr_config, optarg); + sieve_tool_parse_trace_option(&trace_config, optarg); break; case 'E': log_stdout = TRUE; @@ -162,14 +162,17 @@ int main(int argc, char **argv) if ( (sbin = sieve_compile (svinst, scriptfile, NULL, testsuite_log_main_ehandler, 0, NULL)) != NULL ) { - struct ostream *tracestream = NULL; + struct sieve_trace_log *trace_log = NULL; struct sieve_script_env scriptenv; /* Dump script */ sieve_tool_dump_binary_to(sbin, dumpfile, FALSE); - if ( tracefile != NULL ) - tracestream = sieve_tool_open_output_stream(tracefile); + if ( tracefile != NULL ) { + (void)sieve_trace_log_create(svinst, + (strcmp(tracefile, "-") == 0 ? NULL : tracefile), + &trace_log); + } testsuite_mailstore_init(); testsuite_message_init(); @@ -182,8 +185,8 @@ int main(int argc, char **argv) scriptenv.smtp_add_rcpt = testsuite_smtp_add_rcpt; scriptenv.smtp_send = testsuite_smtp_send; scriptenv.smtp_finish = testsuite_smtp_finish; - scriptenv.trace_stream = tracestream; - scriptenv.trace_config = tr_config; + scriptenv.trace_log = trace_log; + scriptenv.trace_config = trace_config; testsuite_scriptenv = &scriptenv; @@ -213,8 +216,8 @@ int main(int argc, char **argv) testsuite_mailstore_deinit(); testsuite_result_deinit(); - if ( tracestream != NULL ) - o_stream_unref(&tracestream); + if ( trace_log != NULL ) + sieve_trace_log_free(&trace_log); testsuite_scriptenv = NULL; } else { -- GitLab