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