From ed9c1baeb8840aa1d78a3025e143aa813e03b3dc Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Sun, 11 Jul 2010 17:06:31 +0200 Subject: [PATCH] Sieve tools: added support for extended trace debugging and updated man pages. --- doc/man/sieve-filter.1 | 4 +- doc/man/sieve-test.1 | 52 ++++++++++++++++--- doc/man/sievec.1 | 4 +- doc/man/sieved.1 | 4 +- .../plugins/include/ext-include-common.c | 8 +-- src/lib-sieve/sieve-interpreter.c | 4 +- src/lib-sieve/sieve-runtime-trace.h | 21 +++++--- src/lib-sieve/sieve-runtime.h | 2 +- src/lib-sieve/sieve-types.h | 22 +++++--- src/sieve-tools/sieve-test.c | 51 +++++++++++++++--- src/testsuite/cmd-test.c | 4 +- src/testsuite/testsuite-script.c | 2 +- src/testsuite/testsuite.c | 2 +- 13 files changed, 132 insertions(+), 48 deletions(-) diff --git a/doc/man/sieve-filter.1 b/doc/man/sieve-filter.1 index a69710a32..2cac97c46 100644 --- a/doc/man/sieve-filter.1 +++ b/doc/man/sieve-filter.1 @@ -6,7 +6,7 @@ sieve\-filter \- Sieve mailbox filter tool for the Dovecot secure IMAP server features! The behavior described in this manual page represents the design and not necessarily what the tool currently implements. .SH SYNOPSIS -sieve\-filter [\fB\-c\fR \fIconfig-file\fR] [\fIoptions\fR] \fIscript\-file\fR \fIsource\-location\fR \fIsource\-mailbox\fR [\fIinbox\-namespace\fR [\fInamespace\fR ...]] +sieve\-filter [\fB\-c\fR \fIconfig\-file\fR] [\fIoptions\fR] \fIscript\-file\fR \fIsource\-location\fR \fIsource\-mailbox\fR [\fIinbox\-namespace\fR [\fInamespace\fR ...]] .TP \fInamepace\fR = [prefix=]location[;option=value,option=value,...] .TP @@ -66,7 +66,7 @@ Sieve script decides to do so. .SH OPTIONS .TP -\fB\-c\fP \fIconfig-file\fP +\fB\-c\fP \fIconfig\-file\fP Alternative Dovecot configuration file path. .TP \fB\-D\fP \fIsource\-action\fP diff --git a/doc/man/sieve-test.1 b/doc/man/sieve-test.1 index 222abaa60..4da259539 100644 --- a/doc/man/sieve-test.1 +++ b/doc/man/sieve-test.1 @@ -3,7 +3,7 @@ sieve\-test \- Sieve script tester for the Dovecot secure IMAP server .SH SYNOPSIS sieve\-test -[\fB\-c\fR \fIconfig-file\fR] +[\fB\-c\fR \fIconfig\-file\fR] [\fB\-C\fR] [\fB\-D\fR] [\fB\-d\fR \fIdump\-file\fR] @@ -13,7 +13,7 @@ sieve\-test [\fB\-m\fR \fIdefault\-mailbox\fR] [\fB\-r\fR \fIrecipient\-address\fR] [\fB\-s\fR \fIscript\-file\fR] -[\fB\-t\fR] +[\fB\-t\fR \fItrace\-option\fR] [\fB\-x\fR "\fIextension extension ...\fR"] \fIscript\-file\fR \fImail\-file\fR .SH DESCRIPTION @@ -45,7 +45,7 @@ with basename and path identical to the specified script. Use the \fB\-C\fP opti behavior by forcing the script to be compiled into a new binary. .SH OPTIONS .TP -\fB\-c\fP \fIconfig-file\fP +\fB\-c\fP \fIconfig\-file\fP Alternative Dovecot configuration file path. .TP \fB\-C\fP @@ -91,9 +91,9 @@ Specify additional scripts to be executed before the main script. Multiple \fB\- allowed and the specified scripts are executed sequentially in the order specified at the command line. .TP -\fB\-t\fP -Enable simple trace debugging; prints all encountered byte code instructions to \fBstdout\fP. This is -currently only intelligible for developers. +\fB\-t\fP \fItrace\-option\fP +Configure runtime trace debugging. Trace debugging provides detailed insight in the operations performed +by the Sieve script. Refer to the trace debugging section below. .TP \fB\-x\fP "\fIextension extension ...\fP" Set the available extensions. The parameter is a space\-separated list of the active extensions. By @@ -105,7 +105,45 @@ or those that are still under development. For example \fB\-x\fP "+imapflags \-enotify" will enable the deprecated imapflags extension along with all extensions that are available by default, except for the enotify extension. -.SH DEBUG SUPPORT + +.SH RUNTIME TRACE DEBUGGING +.PP +Using the \fB-t\fP option, the \fBsieve\-test\fP tool can be configured to print detailed information on +the Sieve script execution. For example, the encountered commands, the performed tests and the matched +values can be printed. +.PP +The \fB\-t\fP option can be specified multiple times. It can be used as follows: + +.TP 2 +\fB\-tlevel=...\fP +Set the verbosity level of the trace debugging. One of the following values can be supplied: +.RS 2 +.TP 3 +\fInone\fP (default) +No trace debugging. +.TP +\fIactions\fP +Only print executed action commands, like keep, fileinto, reject and redirect. +.TP +\fIcommands\fP +Print any command, excluding tests. +.TP +\fItests\fP +Print all commands and performed tests. +.TP +\fImatching\fP +Print all commands, performed tests and the values matched for those tests. +.RE +.TP 2 +\fB\-tdebug\fP +Print debug messages as well. This is usually only useful for developers and produces messy output. +.TP +\fB\-taddresses\fP +Print byte code addresses for the current trace output. Normally, only the current Sieve source code +position is printed. The byte code addresses are equal to those listed in a binary dump produced +using the \fB\-d\fP option or by the \fBsieved(1)\fP command. + +.SH DEBUG SIEVE EXTENSION .PP To improve script debugging, the Sieve command line tools such as \fBsieve\-test\fP support a custom Sieve language extension called 'vnd.dovecot.debug'. It adds the \fBdebug_print\fP command that allows diff --git a/doc/man/sievec.1 b/doc/man/sievec.1 index c89be696a..bce1dc245 100644 --- a/doc/man/sievec.1 +++ b/doc/man/sievec.1 @@ -2,7 +2,7 @@ .SH NAME sievec \- Sieve script compiler for the Dovecot secure IMAP server .SH SYNOPSIS -sievec [\fB\-c\fR \fIconfig-file\fR] [\fB\-d\fR] [\fB\-x\fR "\fIextension extension ...\fR"] \fIscript\-file\fR [\fIout\-file\fR] +sievec [\fB\-c\fR \fIconfig\-file\fR] [\fB\-d\fR] [\fB\-x\fR "\fIextension extension ...\fR"] \fIscript\-file\fR [\fIout\-file\fR] .SH DESCRIPTION .PP The \fBsievec\fP command is part of the Pigeonhole Sieve implementation for the Dovecot secure @@ -43,7 +43,7 @@ for a stored binary file. This output is mainly useful to find bugs in the compi binaries. .SH OPTIONS .TP -\fB\-c\fP \fIconfig-file\fP +\fB\-c\fP \fIconfig\-file\fP Alternative Dovecot configuration file path. .TP \fB\-d\fP diff --git a/doc/man/sieved.1 b/doc/man/sieved.1 index 8bc6143f3..724eea85d 100644 --- a/doc/man/sieved.1 +++ b/doc/man/sieved.1 @@ -2,7 +2,7 @@ .SH NAME sieved \- Sieve script binary dump tool for the Dovecot secure IMAP server .SH SYNOPSIS -sieved [\fB\-c\fR \fIconfig-file\fR] [\fB\-x\fR "\fIextension extension ...\fR"] \fIsieve\-binary\fR [\fIout\-file\fR] +sieved [\fB\-c\fR \fIconfig\-file\fR] [\fB\-x\fR "\fIextension extension ...\fR"] \fIsieve\-binary\fR [\fIout\-file\fR] .br .SH DESCRIPTION .PP @@ -34,7 +34,7 @@ new operations and use additional blocks. Therefore, the output of \fBsieved\fP on the language extensions used when compiling the binary. .SH OPTIONS .TP -\fB\-c\fP \fIconfig-file\fP +\fB\-c\fP \fIconfig\-file\fP Alternative Dovecot configuration file path. .TP \fB\-x\fP "\fIextension extension ...\fP" diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c index 9491a270c..336685a2c 100644 --- a/src/lib-sieve/plugins/include/ext-include-common.c +++ b/src/lib-sieve/plugins/include/ext-include-common.c @@ -566,12 +566,12 @@ int ext_include_execute_include /* If :once modifier is specified, check for duplicate include */ if ( ext_include_runtime_include_mark(ctx, included, once) ) { - sieve_runtime_trace(renv, SIEVE_TRLVL_MINIMUM, + sieve_runtime_trace(renv, SIEVE_TRLVL_NONE, "include: start script '%s' [inc id: %d, block: %d]", sieve_script_name(included->script), include_id, block_id); } else { /* skip */ - sieve_runtime_trace(renv, SIEVE_TRLVL_MINIMUM, + sieve_runtime_trace(renv, SIEVE_TRLVL_NONE, "include: skipped include for script '%s' [inc id: %d, block: %d]; " "already run once", sieve_script_name(included->script), include_id, block_id); @@ -636,7 +636,7 @@ int ext_include_execute_include curctx = curctx->parent; sieve_interpreter_free(&subinterp); - sieve_runtime_trace(renv, SIEVE_TRLVL_MINIMUM, + sieve_runtime_trace(renv, SIEVE_TRLVL_NONE, "include: script '%s' ended [inc id: %d, block: %d]", sieve_script_name(ended_script->script), ended_script->id, sieve_binary_block_get_id(ended_script->block)); @@ -697,7 +697,7 @@ int ext_include_execute_include /* This kills curctx too */ sieve_interpreter_free(&killed_interp); - sieve_runtime_trace(renv, SIEVE_TRLVL_MINIMUM, + sieve_runtime_trace(renv, SIEVE_TRLVL_NONE, "include: script '%s' ended [id: %d, block: %d]", sieve_script_name(ended_script->script), ended_script->id, sieve_binary_block_get_id(ended_script->block)); diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c index d301c266f..68260ea5b 100644 --- a/src/lib-sieve/sieve-interpreter.c +++ b/src/lib-sieve/sieve-interpreter.c @@ -100,7 +100,7 @@ static struct sieve_interpreter *_sieve_interpreter_create interp->runenv.msgdata = msgdata; interp->runenv.scriptenv = senv; interp->runenv.trace_stream = senv->trace_stream; - interp->runenv.trace_level = senv->trace_level; + interp->runenv.trace_config = senv->trace_config; if ( senv->exec_status == NULL ) interp->runenv.exec_status = p_new(interp->pool, struct sieve_exec_status, 1); @@ -509,7 +509,7 @@ int sieve_interpreter_continue ret = sieve_interpreter_operation_execute(interp); if ( ret != SIEVE_EXEC_OK ) { - sieve_runtime_trace(&interp->runenv, SIEVE_TRLVL_MINIMUM, + sieve_runtime_trace(&interp->runenv, SIEVE_TRLVL_NONE, "[[EXECUTION ABORTED]]"); } } diff --git a/src/lib-sieve/sieve-runtime-trace.h b/src/lib-sieve/sieve-runtime-trace.h index e3d427d97..8aa895327 100644 --- a/src/lib-sieve/sieve-runtime-trace.h +++ b/src/lib-sieve/sieve-runtime-trace.h @@ -13,7 +13,8 @@ static inline bool sieve_runtime_trace_active (const struct sieve_runtime_env *renv, sieve_trace_level_t trace_level) { - return ( renv->trace_stream != NULL && trace_level <= renv->trace_level ); + return ( renv->trace_stream != NULL && + trace_level <= renv->trace_config.level ); } /* Trace errors */ @@ -39,7 +40,8 @@ static inline void sieve_runtime_trace_error va_list args; va_start(args, fmt); - if ( renv->trace_stream != NULL ) + if ( renv->trace_stream != NULL && + renv->trace_config.level > SIEVE_TRLVL_NONE ) _sieve_runtime_trace_error(renv, fmt, args); va_end(args); } @@ -51,7 +53,8 @@ static inline void sieve_runtime_trace_operand_error va_list args; va_start(args, fmt); - if ( renv->trace_stream != NULL ) + if ( renv->trace_stream != NULL && + renv->trace_config.level > SIEVE_TRLVL_NONE ) _sieve_runtime_trace_operand_error(renv, oprnd, field_name, fmt, args); va_end(args); } @@ -73,7 +76,7 @@ static inline void sieve_runtime_trace va_start(args, fmt); - if ( renv->trace_stream != NULL && trace_level <= renv->trace_level ) { + if ( renv->trace_stream != NULL && trace_level <= renv->trace_config.level ) { _sieve_runtime_trace(renv, fmt, args); } @@ -96,7 +99,7 @@ static inline void sieve_runtime_trace_address va_start(args, fmt); - if ( renv->trace_stream != NULL && trace_level <= renv->trace_level ) { + if ( renv->trace_stream != NULL && trace_level <= renv->trace_config.level ) { _sieve_runtime_trace_address(renv, address, fmt, args); } @@ -111,7 +114,7 @@ static inline void sieve_runtime_trace_here va_start(args, fmt); - if ( renv->trace_stream != NULL && trace_level <= renv->trace_level ) { + if ( renv->trace_stream != NULL && trace_level <= renv->trace_config.level ) { _sieve_runtime_trace_address(renv, renv->pc, fmt, args); } @@ -126,14 +129,16 @@ void _sieve_runtime_trace_end(const struct sieve_runtime_env *renv); static inline void sieve_runtime_trace_begin (const struct sieve_runtime_env *renv) { - if ( renv->trace_stream != NULL ) + if ( renv->trace_stream != NULL && + renv->trace_config.level > SIEVE_TRLVL_NONE ) _sieve_runtime_trace_begin(renv); } static inline void sieve_runtime_trace_end (const struct sieve_runtime_env *renv) { - if ( renv->trace_stream != NULL ) + if ( renv->trace_stream != NULL && + renv->trace_config.level > SIEVE_TRLVL_NONE ) _sieve_runtime_trace_end(renv); } diff --git a/src/lib-sieve/sieve-runtime.h b/src/lib-sieve/sieve-runtime.h index ab304dd7b..26659674c 100644 --- a/src/lib-sieve/sieve-runtime.h +++ b/src/lib-sieve/sieve-runtime.h @@ -37,7 +37,7 @@ struct sieve_runtime_env { /* Runtime tracing */ struct ostream *trace_stream; - sieve_trace_level_t trace_level; + struct sieve_trace_config trace_config; }; #endif /* __SIEVE_RUNTIME_H */ diff --git a/src/lib-sieve/sieve-types.h b/src/lib-sieve/sieve-types.h index 1d026c879..205a0e0e6 100644 --- a/src/lib-sieve/sieve-types.h +++ b/src/lib-sieve/sieve-types.h @@ -8,9 +8,6 @@ #include <stdio.h> -/* Enable runtime trace functionality */ -#define SIEVE_RUNTIME_TRACE - /* * Forward declarations */ @@ -49,18 +46,27 @@ struct sieve_message_data { }; /* - * Runtime trace level + * Runtime trace settings */ typedef enum { - SIEVE_TRLVL_MINIMUM, + SIEVE_TRLVL_NONE, SIEVE_TRLVL_ACTIONS, SIEVE_TRLVL_COMMANDS, SIEVE_TRLVL_TESTS, - SIEVE_TRLVL_MATCH, - SIEVE_TRLVL_DEBUG + SIEVE_TRLVL_MATCHING } sieve_trace_level_t; +enum { + SIEVE_TRFLG_DEBUG = (1 << 0), + SIEVE_TRFLG_ADDRESSES = (1 << 1) +}; + +struct sieve_trace_config { + sieve_trace_level_t level; + unsigned int flags; +}; + /* * Script environment * @@ -106,7 +112,7 @@ struct sieve_script_env { /* Runtime trace*/ struct ostream *trace_stream; - sieve_trace_level_t trace_level; + struct sieve_trace_config trace_config; }; #define SIEVE_SCRIPT_DEFAULT_MAILBOX(senv) \ diff --git a/src/sieve-tools/sieve-test.c b/src/sieve-tools/sieve-test.c index 166f6ee46..fe5aa36e4 100644 --- a/src/sieve-tools/sieve-test.c +++ b/src/sieve-tools/sieve-test.c @@ -44,10 +44,10 @@ static void print_help(void) { printf( -"Usage: sieve-test [-c] [-d <dump-filename>] [-e] [-f <envelope-sender>]\n" +"Usage: sieve-test [-C] [-d <dump-filename>] [-e] [-f <envelope-sender>]\n" " [-l <mail-location>] [-m <default-mailbox>]\n" " [-r <recipient-address>] [-s <script-file>]\n" -" [-t] [-P <plugin>] [-x <extensions>]\n" +" [-t <trace-option>] [-P <plugin>] [-x <extensions>]\n" " <script-file> <mail-file>\n" ); } @@ -96,6 +96,38 @@ static void duplicate_mark i_info("marked duplicate for user %s.\n", user); } +/* + * Trace option handling + */ + +static void parse_trace_option +(struct sieve_trace_config *tr_config, const char *tr_option) +{ + if ( strncmp(tr_option, "level=", 6) == 0 ) { + const char *lvl = &tr_option[6]; + + if ( strcmp(lvl, "none") == 0 ) { + tr_config->level = SIEVE_TRLVL_NONE; + } else if ( strcmp(lvl, "actions") == 0 ) { + tr_config->level = SIEVE_TRLVL_ACTIONS; + } else if ( strcmp(lvl, "commands") == 0 ) { + tr_config->level = SIEVE_TRLVL_COMMANDS; + } else if ( strcmp(lvl, "tests") == 0 ) { + tr_config->level = SIEVE_TRLVL_TESTS; + } else if ( strcmp(lvl, "matching") == 0 ) { + tr_config->level = SIEVE_TRLVL_MATCHING; + } else { + i_fatal_status(EX_USAGE, "Unknown -tlevel= trace level: %s", lvl); + } + } else if ( strcmp(tr_option, "debug") == 0 ) { + tr_config->flags = SIEVE_TRFLG_DEBUG; + } else if ( strcmp(tr_option, "addresses") == 0 ) { + tr_config->flags = SIEVE_TRFLG_ADDRESSES; + } else { + i_fatal_status(EX_USAGE, "Unknown -t trace option value: %s", tr_option); + } +} + /* * Tool implementation */ @@ -106,6 +138,7 @@ int main(int argc, char **argv) ARRAY_TYPE (const_string) scriptfiles; const char *scriptfile, *recipient, *sender, *mailbox, *dumpfile, *mailfile, *mailloc; + struct sieve_trace_config tr_config; struct mail *mail; struct sieve_binary *main_sbin, *sbin = NULL; struct sieve_message_data msgdata; @@ -119,12 +152,13 @@ int main(int argc, char **argv) int ret, c; sieve_tool = sieve_tool_init - ("sieve-test", &argc, &argv, "r:f:m:d:l:s:eCtDP:x:u:", FALSE); + ("sieve-test", &argc, &argv, "r:f:m:d:l:s:eCt:DP:x:u:", FALSE); t_array_init(&scriptfiles, 16); /* Parse arguments */ scriptfile = recipient = sender = mailbox = dumpfile = mailfile = mailloc = NULL; + memset(&tr_config, 0, sizeof(tr_config)); while ((c = sieve_tool_getopt(sieve_tool)) > 0) { switch (c) { case 'r': @@ -147,6 +181,9 @@ int main(int argc, char **argv) /* mail location */ mailloc = optarg; break; + case 't': + parse_trace_option(&tr_config, optarg); + break; case 's': /* scriptfile executed before main script */ { @@ -162,9 +199,6 @@ int main(int argc, char **argv) case 'C': force_compile = TRUE; break; - case 't': - trace = TRUE; - break; default: print_help(); i_fatal_status(EX_USAGE, "Unknown argument: %c", c); @@ -253,8 +287,9 @@ int main(int argc, char **argv) scriptenv.smtp_close = sieve_smtp_close; scriptenv.duplicate_mark = duplicate_mark; scriptenv.duplicate_check = duplicate_check; - scriptenv.trace_stream = ( trace ? teststream : NULL ); - scriptenv.trace_level = SIEVE_TRLVL_TESTS; + scriptenv.trace_stream = + ( tr_config.level > SIEVE_TRLVL_NONE ? teststream : NULL ); + scriptenv.trace_config = tr_config; scriptenv.exec_status = &estatus; /* Run the test */ diff --git a/src/testsuite/cmd-test.c b/src/testsuite/cmd-test.c index b60758979..00947e75f 100644 --- a/src/testsuite/cmd-test.c +++ b/src/testsuite/cmd-test.c @@ -155,7 +155,7 @@ static int cmd_test_operation_execute if ( !sieve_opr_string_read(renv, address, "test name", &test_name) ) return SIEVE_EXEC_BIN_CORRUPT; - sieve_runtime_trace(renv, SIEVE_TRLVL_MINIMUM, + sieve_runtime_trace(renv, SIEVE_TRLVL_NONE, "** Test start: \"%s\"", str_c(test_name)); testsuite_test_start(test_name); @@ -166,7 +166,7 @@ static int cmd_test_finish_operation_execute (const struct sieve_runtime_env *renv ATTR_UNUSED, sieve_size_t *address ATTR_UNUSED) { - sieve_runtime_trace(renv, SIEVE_TRLVL_MINIMUM, "** Test end"); + sieve_runtime_trace(renv, SIEVE_TRLVL_NONE, "** Test end"); testsuite_test_succeed(NULL); return SIEVE_EXEC_OK; diff --git a/src/testsuite/testsuite-script.c b/src/testsuite/testsuite-script.c index 302734ae1..c82031e40 100644 --- a/src/testsuite/testsuite-script.c +++ b/src/testsuite/testsuite-script.c @@ -106,7 +106,7 @@ bool testsuite_script_run(const struct sieve_runtime_env *renv) scriptenv.duplicate_check = NULL; scriptenv.user = renv->scriptenv->user; scriptenv.trace_stream = renv->scriptenv->trace_stream; - scriptenv.trace_level = renv->scriptenv->trace_level; + scriptenv.trace_config = renv->scriptenv->trace_config; result = testsuite_result_get(); diff --git a/src/testsuite/testsuite.c b/src/testsuite/testsuite.c index a1b23f04b..f4d3eeca9 100644 --- a/src/testsuite/testsuite.c +++ b/src/testsuite/testsuite.c @@ -170,7 +170,7 @@ int main(int argc, char **argv) scriptenv.smtp_open = testsuite_smtp_open; scriptenv.smtp_close = testsuite_smtp_close; scriptenv.trace_stream = ( trace ? o_stream_create_fd(1, 0, FALSE) : NULL ); - scriptenv.trace_level = SIEVE_TRLVL_TESTS; + scriptenv.trace_config.level = SIEVE_TRLVL_TESTS; testsuite_scriptenv = &scriptenv; -- GitLab