dovecot-2.0-pigeonhole: Improved and simplified file error handling
pigeonhole at rename-it.nl
pigeonhole at rename-it.nl
Wed Aug 11 19:22:58 EEST 2010
details: http://hg.rename-it.nl/dovecot-2.0-pigeonhole/rev/5b078d671e51
changeset: 1366:5b078d671e51
user: Stephan Bosch <stephan at rename-it.nl>
date: Wed Aug 11 18:20:41 2010 +0200
description:
Improved and simplified file error handling
- Administrators now get properly notified about uncompiled global scripts and the inability of the sieve plugin to store global binaries.
- Improved binary load/save error handling and fixed a few smal bugs.
- Simplified ManageSieve error handling.
diffstat:
TODO | 10 +-
src/lib-sieve-tool/sieve-tool.c | 5 +-
src/lib-sieve/plugins/include/cmd-include.c | 6 +-
src/lib-sieve/plugins/include/ext-include-common.c | 4 +-
src/lib-sieve/sieve-binary-file.c | 281 +++++++++++++++----------
src/lib-sieve/sieve-binary-private.h | 3 +-
src/lib-sieve/sieve-binary.c | 31 +-
src/lib-sieve/sieve-binary.h | 18 +-
src/lib-sieve/sieve-common.h | 6 +-
src/lib-sieve/sieve-lexer.c | 7 +-
src/lib-sieve/sieve-lexer.h | 3 +-
src/lib-sieve/sieve-parser.c | 5 +-
src/lib-sieve/sieve-parser.h | 3 +-
src/lib-sieve/sieve-script-private.h | 2 +-
src/lib-sieve/sieve-script.c | 129 +++++------
src/lib-sieve/sieve-script.h | 7 +-
src/lib-sieve/sieve-types.h | 29 ++
src/lib-sieve/sieve.c | 158 +++++++++-----
src/lib-sieve/sieve.h | 69 +++--
src/lib-sievestorage/Makefile.am | 1 -
src/lib-sievestorage/sieve-storage-error.h | 32 --
src/lib-sievestorage/sieve-storage-list.c | 20 +-
src/lib-sievestorage/sieve-storage-private.h | 6 +-
src/lib-sievestorage/sieve-storage-quota.c | 6 +-
src/lib-sievestorage/sieve-storage-save.c | 34 +-
src/lib-sievestorage/sieve-storage-script.c | 147 ++++++-------
src/lib-sievestorage/sieve-storage-script.h | 10 +-
src/lib-sievestorage/sieve-storage.c | 31 +-
src/lib-sievestorage/sieve-storage.h | 5 +-
src/managesieve/cmd-deletescript.c | 10 +-
src/managesieve/cmd-getscript.c | 51 ++--
src/managesieve/cmd-putscript.c | 2 +-
src/managesieve/cmd-renamescript.c | 10 +-
src/managesieve/cmd-setactive.c | 12 +-
src/managesieve/managesieve-client.c | 20 +-
src/plugins/lda-sieve/lda-sieve-plugin.c | 178 +++++++++------
src/sieve-tools/sieve-test.c | 4 +-
src/sieve-tools/sievec.c | 4 +-
src/sieve-tools/sieved.c | 2 +-
src/testsuite/testsuite-binary.c | 6 +-
src/testsuite/testsuite-script.c | 4 +-
src/testsuite/testsuite.c | 2 +-
42 files changed, 753 insertions(+), 620 deletions(-)
diffs (truncated from 3186 to 300 lines):
diff -r 0bdde11004f5 -r 5b078d671e51 TODO
--- a/TODO Wed Aug 11 18:10:46 2010 +0200
+++ b/TODO Wed Aug 11 18:20:41 2010 +0200
@@ -1,5 +1,8 @@
Current activities:
+* Improve error handling and logging
+ - Avoid reporting user-caused errors to the master log.
+ - Review logging and error handling; add more warning/info/debug messages where useful.
* Cleanup the test suite
- Make uniform command implementations
- Cleanup test scripts
@@ -7,13 +10,6 @@
Next (in order of descending priority/precedence):
* Update man pages to match style of Dovecot man pages.
-* Improve error handling and logging
- - Detect permission errors when writing global script binaries and advise the
- administrator on using sievec to precompile the scripts.
- - Avoid reporting user-caused errors to the master log.
- - Review logging and error handling; add more warning/info/debug messages where useful.
- - Improve logging of script execution (particularly what is currently executed;
- a promptly compiled script or the stored binary).
* Update include extension to latest draft:
- Implement required ManageSieve behavior
* Unfinished new extensions:
diff -r 0bdde11004f5 -r 5b078d671e51 src/lib-sieve-tool/sieve-tool.c
--- a/src/lib-sieve-tool/sieve-tool.c Wed Aug 11 18:10:46 2010 +0200
+++ b/src/lib-sieve-tool/sieve-tool.c Wed Aug 11 18:20:41 2010 +0200
@@ -516,11 +516,11 @@
ehandler = sieve_stderr_ehandler_create(0);
sieve_error_handler_accept_infolog(ehandler, TRUE);
- if ( (sbin = sieve_compile(svinst, filename, name, ehandler)) == NULL )
+ if ( (sbin = sieve_compile(svinst, filename, name, ehandler, NULL)) == NULL )
i_error("failed to compile sieve script '%s'", filename);
sieve_error_handler_unref(&ehandler);
-
+
return sbin;
}
@@ -540,6 +540,7 @@
sieve_error_handler_unref(&ehandler);
+ sieve_save(sbin, NULL, FALSE, NULL);
return sbin;
}
diff -r 0bdde11004f5 -r 5b078d671e51 src/lib-sieve/plugins/include/cmd-include.c
--- a/src/lib-sieve/plugins/include/cmd-include.c Wed Aug 11 18:10:46 2010 +0200
+++ b/src/lib-sieve/plugins/include/cmd-include.c Wed Aug 11 18:20:41 2010 +0200
@@ -202,7 +202,7 @@
(struct cmd_include_context_data *) cmd->data;
struct sieve_script *script;
const char *script_path, *script_name;
- bool exists = TRUE;
+ enum sieve_error error = TRUE;
/* Check argument */
if ( !sieve_validate_positional_argument
@@ -247,10 +247,10 @@
/* Create script object */
script = sieve_script_create_in_directory
(this_ext->svinst, script_path, script_name,
- sieve_validator_error_handler(valdtr), &exists);
+ sieve_validator_error_handler(valdtr), &error);
if ( script == NULL ) {
- if ( !exists ) {
+ if ( error == SIEVE_ERROR_NOT_FOUND ) {
sieve_argument_validate_error(valdtr, arg,
"included %s script '%s' does not exist",
ext_include_script_location_name(ctx_data->location),
diff -r 0bdde11004f5 -r 5b078d671e51 src/lib-sieve/plugins/include/ext-include-common.c
--- a/src/lib-sieve/plugins/include/ext-include-common.c Wed Aug 11 18:10:46 2010 +0200
+++ b/src/lib-sieve/plugins/include/ext-include-common.c Wed Aug 11 18:20:41 2010 +0200
@@ -456,7 +456,7 @@
(binctx, script, location, inc_block);
/* Parse */
- if ( (ast = sieve_parse(script, ehandler)) == NULL ) {
+ if ( (ast = sieve_parse(script, ehandler, NULL)) == NULL ) {
sieve_command_generate_error(gentr, cmd,
"failed to parse included script '%s'", str_sanitize(script_name, 80));
return FALSE;
@@ -466,7 +466,7 @@
(void)ext_include_create_ast_context(this_ext, ast, cmd->ast_node->ast);
/* Validate */
- if ( !sieve_validate(ast, ehandler) ) {
+ if ( !sieve_validate(ast, ehandler, NULL) ) {
sieve_command_generate_error(gentr, cmd,
"failed to validate included script '%s'",
str_sanitize(script_name, 80));
diff -r 0bdde11004f5 -r 5b078d671e51 src/lib-sieve/sieve-binary-file.c
--- a/src/lib-sieve/sieve-binary-file.c Wed Aug 11 18:10:46 2010 +0200
+++ b/src/lib-sieve/sieve-binary-file.c Wed Aug 11 18:20:41 2010 +0200
@@ -66,9 +66,13 @@
static inline bool _save_skip(struct ostream *stream, size_t size)
{
- if ( (o_stream_seek(stream, stream->offset + size)) <= 0 )
+ if ( (o_stream_seek(stream, stream->offset + size)) <= 0 ) {
+ sieve_sys_error("binary save: failed to skip output stream "
+ "to position %"PRIuUOFF_T": %s", stream->offset + size,
+ strerror(stream->stream_errno));
return FALSE;
-
+ }
+
return TRUE;
}
@@ -77,8 +81,12 @@
{
uoff_t aligned_offset = SIEVE_BINARY_ALIGN(stream->offset);
- if ( (o_stream_seek(stream, aligned_offset + size)) <= 0 )
+ if ( (o_stream_seek(stream, aligned_offset + size)) <= 0 ) {
+ sieve_sys_error("binary save: failed to skip output stream "
+ "to position %"PRIuUOFF_T": %s", aligned_offset + size,
+ strerror(stream->stream_errno));
return FALSE;
+ }
if ( offset != NULL )
*offset = aligned_offset;
@@ -95,8 +103,11 @@
while ( bytes_left > 0 ) {
ssize_t ret;
- if ( (ret=o_stream_send(stream, pdata, bytes_left)) <= 0 )
+ if ( (ret=o_stream_send(stream, pdata, bytes_left)) <= 0 ) {
+ sieve_sys_error("binary save: failed to write %"PRIuSIZE_T" bytes "
+ "to output stream: %s", bytes_left, strerror(stream->stream_errno));
return FALSE;
+ }
pdata = PTR_OFFSET(pdata, ret);
bytes_left -= ret;
@@ -169,8 +180,7 @@
header.offset = block->offset;
if ( !_save_full(stream, &header, sizeof(header)) ) {
- sieve_sys_error("failed to save block index header %d: %m", id);
-
+ sieve_sys_error("binary save: failed to save block index header %d", id);
return FALSE;
}
@@ -206,7 +216,7 @@
header.blocks = blk_count;
if ( !_save_aligned(stream, &header, sizeof(header), NULL) ) {
- sieve_sys_error("failed to save binary header: %m");
+ sieve_sys_error("binary save: failed to save header");
return FALSE;
}
@@ -251,69 +261,100 @@
return TRUE;
}
-bool sieve_binary_save
-(struct sieve_binary *sbin, const char *path)
+int sieve_binary_save
+(struct sieve_binary *sbin, const char *path, bool update,
+ enum sieve_error *error_r)
{
- bool result = TRUE;
+ int result, fd;
string_t *temp_path;
struct ostream *stream;
- int fd;
mode_t save_mode =
sbin->script == NULL ? 0600 : sieve_script_permissions(sbin->script);
+
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_NONE;
/* Use default path if none is specified */
if ( path == NULL ) {
if ( sbin->script == NULL ) {
- sieve_sys_error("cannot determine default binary save path "
+ sieve_sys_error("binary save: cannot determine default path "
"with missing script object");
- return FALSE;
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_NOT_POSSIBLE;
+ return -1;
}
path = sieve_script_binpath(sbin->script);
}
+ /* Check whether saving is necessary */
+ if ( !update && sbin->path != NULL && strcmp(sbin->path, path) == 0 ) {
+ if ( sbin->svinst->debug ) {
+ sieve_sys_debug("binary save: not saving binary %s, "
+ "because it is already stored", path);
+ }
+ return 0;
+ }
+
/* Open it as temp file first, as not to overwrite an existing just yet */
temp_path = t_str_new(256);
str_append(temp_path, path);
+ str_append_c(temp_path, '.');
fd = safe_mkstemp_hostpid(temp_path, save_mode, (uid_t)-1, (gid_t)-1);
if ( fd < 0 ) {
if ( errno == EACCES ) {
- sieve_sys_error("failed to save binary temporary file: %s",
+ sieve_sys_error("binary save: failed to create temporary file: %s",
eacces_error_get_creating("open", str_c(temp_path)));
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_NO_PERM;
} else {
- sieve_sys_error("failed to save binary temporary file: "
+ sieve_sys_error("binary save: failed to create temporary file: "
"open(%s) failed: %m", str_c(temp_path));
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_TEMP_FAIL;
}
- return FALSE;
+ return -1;
}
/* Save binary */
+ result = 1;
stream = o_stream_create_fd(fd, 0, FALSE);
- result = _sieve_binary_save(sbin, stream);
+ if ( !_sieve_binary_save(sbin, stream) ) {
+ result = -1;
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_TEMP_FAIL;
+ }
o_stream_destroy(&stream);
/* Close saved binary */
if ( close(fd) < 0 ) {
- sieve_sys_error("failed to close saved binary temporary file: "
+ sieve_sys_error("binary save: failed to close temporary file: "
"close(fd=%s) failed: %m", str_c(temp_path));
}
/* Replace any original binary atomically */
if ( result && (rename(str_c(temp_path), path) < 0) ) {
if ( errno == EACCES ) {
- sieve_sys_error("failed to replace existing binary: %s",
- eacces_error_get_creating("rename", path));
+ sieve_sys_error("binary save: failed to save binary: %s",
+ eacces_error_get_creating("rename", path));
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_NO_PERM;
} else {
- sieve_sys_error("failed to replace existing binary: "
+ sieve_sys_error("binary save: failed to save binary: "
"rename(%s, %s) failed: %m", str_c(temp_path), path);
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_TEMP_FAIL;
}
- result = FALSE;
+ result = -1;
}
- if ( !result ) {
+ if ( result < 0 ) {
/* Get rid of temp output (if any) */
- (void) unlink(str_c(temp_path));
+ if ( unlink(str_c(temp_path)) < 0 && errno != ENOENT ) {
+ sieve_sys_error("binary save: failed to clean up after error: "
+ "unlink(%s) failed: %m", str_c(temp_path));
+ }
} else {
- if ( sbin->path == NULL || strcmp(sbin->path, path) != 0 ) {
+ if ( sbin->path == NULL ) {
sbin->path = p_strdup(sbin->pool, path);
}
}
@@ -326,37 +367,57 @@
*/
bool sieve_binary_file_open
- (struct sieve_binary_file *file, const char *path)
+(struct sieve_binary_file *file, const char *path, enum sieve_error *error_r)
{
int fd;
+ bool result = TRUE;
struct stat st;
+
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_NONE;
if ( (fd=open(path, O_RDONLY)) < 0 ) {
- if ( errno != ENOENT ) {
- if ( errno == EACCES ) {
- sieve_sys_error("failed to open binary: %s",
- eacces_error_get("open", path));
More information about the dovecot-cvs
mailing list