dovecot-2.2-pigeonhole: Moved script-client from extprograms plu...
pigeonhole at rename-it.nl
pigeonhole at rename-it.nl
Sat Dec 21 22:32:25 EET 2013
details: http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/f7967d104216
changeset: 1825:f7967d104216
user: Stephan Bosch <stephan at rename-it.nl>
date: Sat Dec 21 21:32:13 2013 +0100
description:
Moved script-client from extprograms plugin to lib-sieve/util and renamed it to program-client for generic use.
diffstat:
src/lib-sieve/util/Makefile.am | 9 +-
src/lib-sieve/util/program-client-local.c | 304 +++++++++++++
src/lib-sieve/util/program-client-private.h | 59 ++
src/lib-sieve/util/program-client-remote.c | 319 ++++++++++++++
src/lib-sieve/util/program-client.c | 337 +++++++++++++++
src/lib-sieve/util/program-client.h | 35 +
src/plugins/sieve-extprograms/Makefile.am | 6 +-
src/plugins/sieve-extprograms/script-client-local.c | 304 -------------
src/plugins/sieve-extprograms/script-client-private.h | 59 --
src/plugins/sieve-extprograms/script-client-remote.c | 319 --------------
src/plugins/sieve-extprograms/script-client.c | 337 ---------------
src/plugins/sieve-extprograms/script-client.h | 35 -
src/plugins/sieve-extprograms/sieve-extprograms-common.c | 53 +-
13 files changed, 1089 insertions(+), 1087 deletions(-)
diffs (truncated from 2329 to 300 lines):
diff -r 559621e9e633 -r f7967d104216 src/lib-sieve/util/Makefile.am
--- a/src/lib-sieve/util/Makefile.am Sat Dec 21 21:10:13 2013 +0100
+++ b/src/lib-sieve/util/Makefile.am Sat Dec 21 21:32:13 2013 +0100
@@ -8,12 +8,17 @@
libsieve_util_la_DEPENDENCIES = $(LIBDOVECOT_STORAGE_DEPS) $(LIBDOVECOT_DEPS)
libsieve_util_la_SOURCES = \
+ edit-mail.c \
rfc2822.c \
- edit-mail.c
+ program-client-local.c \
+ program-client-remote.c \
+ program-client.c
headers = \
+ edit-mail.h \
rfc2822.h \
- edit-mail.h
+ program-client-private.h \
+ program-client.h
pkginc_libdir=$(dovecot_pkgincludedir)/sieve
pkginc_lib_HEADERS = $(headers)
diff -r 559621e9e633 -r f7967d104216 src/lib-sieve/util/program-client-local.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-sieve/util/program-client-local.c Sat Dec 21 21:32:13 2013 +0100
@@ -0,0 +1,304 @@
+/* Copyright (c) 2002-2013 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "lib-signals.h"
+#include "env-util.h"
+#include "execv-const.h"
+#include "array.h"
+#include "net.h"
+#include "istream.h"
+#include "ostream.h"
+
+#include "program-client-private.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+
+struct program_client_local {
+ struct program_client client;
+
+ pid_t pid;
+};
+
+static void exec_child
+(const char *bin_path, const char *const *args, const char *const *envs,
+ int in_fd, int out_fd)
+{
+ ARRAY_TYPE(const_string) exec_args;
+
+ if ( in_fd < 0 ) {
+ in_fd = open("/dev/null", O_RDONLY);
+
+ if ( in_fd == -1 )
+ i_fatal("open(/dev/null) failed: %m");
+ }
+
+ if ( out_fd < 0 ) {
+ out_fd = open("/dev/null", O_WRONLY);
+
+ if ( out_fd == -1 )
+ i_fatal("open(/dev/null) failed: %m");
+ }
+
+ if ( dup2(in_fd, STDIN_FILENO) < 0 )
+ i_fatal("dup2(stdin) failed: %m");
+ if ( dup2(out_fd, STDOUT_FILENO) < 0 )
+ i_fatal("dup2(stdout) failed: %m");
+
+ /* Close all fds */
+ if ( close(in_fd) < 0 )
+ i_error("close(in_fd) failed: %m");
+ if ( (out_fd != in_fd) && close(out_fd) < 0 )
+ i_error("close(out_fd) failed: %m");
+
+ t_array_init(&exec_args, 16);
+ array_append(&exec_args, &bin_path, 1);
+ if ( args != NULL ) {
+ for (; *args != NULL; args++)
+ array_append(&exec_args, args, 1);
+ }
+ (void)array_append_space(&exec_args);
+
+ env_clean();
+ if ( envs != NULL ) {
+ for (; *envs != NULL; envs++)
+ env_put(*envs);
+ }
+
+ args = array_idx(&exec_args, 0);
+ execvp_const(args[0], args);
+}
+
+static int program_client_local_connect
+(struct program_client *pclient)
+{
+ struct program_client_local *slclient =
+ (struct program_client_local *) pclient;
+ int fd[2] = { -1, -1 };
+
+ if ( pclient->input != NULL || pclient->output != NULL ) {
+ if ( socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0 ) {
+ i_error("socketpair() failed: %m");
+ return -1;
+ }
+ }
+
+ if ( (slclient->pid = fork()) == (pid_t)-1 ) {
+ i_error("fork() failed: %m");
+ if ( fd[0] >= 0 && close(fd[0]) < 0 ) {
+ i_error("close(pipe_fd[0]) failed: %m");
+ }
+ if ( fd[1] >= 0 && close(fd[1]) < 0 ) {
+ i_error("close(pipe_fd[1]) failed: %m");
+ }
+ return -1;
+ }
+
+ if ( slclient->pid == 0 ) {
+ unsigned int count;
+ const char *const *envs = NULL;
+
+ /* child */
+ if ( fd[1] >= 0 && close(fd[1]) < 0 ) {
+ i_error("close(pipe_fd[1]) failed: %m");
+ }
+
+ if ( array_is_created(&pclient->envs) )
+ envs = array_get(&pclient->envs, &count);
+
+ exec_child(pclient->path, pclient->args, envs,
+ ( pclient->input != NULL ? fd[0] : -1 ),
+ ( pclient->output != NULL ? fd[0] : -1 ));
+ i_unreached();
+ }
+
+ /* parent */
+ if ( fd[0] >= 0 && close(fd[0]) < 0 ) {
+ i_error("close(pipe_fd[0]) failed: %m");
+ }
+
+ if ( fd[1] >= 0 ) {
+ net_set_nonblock(fd[1], TRUE);
+ pclient->fd_in = ( pclient->output != NULL ? fd[1] : -1 );
+ pclient->fd_out = ( pclient->input != NULL ? fd[1] : -1 );
+ }
+ program_client_init_streams(pclient);
+ return program_client_connected(pclient);
+}
+
+static int program_client_local_close_output(struct program_client *pclient)
+{
+ /* Shutdown output; program stdin will get EOF */
+ if ( pclient->fd_out >= 0 && shutdown(pclient->fd_out, SHUT_WR) < 0 ) {
+ i_error("shutdown(%s, SHUT_WR) failed: %m", pclient->path);
+ return -1;
+ }
+ return 1;
+}
+
+static int program_client_local_disconnect
+(struct program_client *pclient, bool force)
+{
+ struct program_client_local *slclient =
+ (struct program_client_local *) pclient;
+ pid_t pid = slclient->pid, ret;
+ time_t runtime, timeout = 0;
+ int status;
+
+ i_assert( pid >= 0 );
+ slclient->pid = -1;
+
+ /* Calculate timeout */
+ runtime = ioloop_time - pclient->start_time;
+ if ( !force && pclient->set->input_idle_timeout_secs > 0 &&
+ runtime < (time_t)pclient->set->input_idle_timeout_secs )
+ timeout = pclient->set->input_idle_timeout_secs - runtime;
+
+ if ( pclient->debug ) {
+ i_debug("waiting for program `%s' to finish after %llu seconds",
+ pclient->path, (unsigned long long int)runtime);
+ }
+
+ /* Wait for child to exit */
+ force = force ||
+ (timeout == 0 && pclient->set->input_idle_timeout_secs > 0);
+ if ( !force ) {
+ alarm(timeout);
+ ret = waitpid(pid, &status, 0);
+ alarm(0);
+ }
+ if ( force || ret < 0 ) {
+ if ( !force && errno != EINTR ) {
+ i_error("waitpid(%s) failed: %m", pclient->path);
+ (void)kill(pid, SIGKILL);
+ return -1;
+ }
+
+ /* Timed out */
+ force = TRUE;
+ if ( pclient->error == PROGRAM_CLIENT_ERROR_NONE )
+ pclient->error = PROGRAM_CLIENT_ERROR_RUN_TIMEOUT;
+ if ( pclient->debug ) {
+ i_debug("program `%s' execution timed out after %llu seconds: "
+ "sending TERM signal", pclient->path,
+ (unsigned long long int)pclient->set->input_idle_timeout_secs);
+ }
+
+ /* Kill child gently first */
+ if ( kill(pid, SIGTERM) < 0 ) {
+ i_error("failed to send SIGTERM signal to program `%s'", pclient->path);
+ (void)kill(pid, SIGKILL);
+ return -1;
+ }
+
+ /* Wait for it to die (give it some more time) */
+ alarm(5);
+ ret = waitpid(pid, &status, 0);
+ alarm(0);
+ if ( ret < 0 ) {
+ if ( errno != EINTR ) {
+ i_error("waitpid(%s) failed: %m", pclient->path);
+ (void)kill(pid, SIGKILL);
+ return -1;
+ }
+
+ /* Timed out again */
+ if ( pclient->debug ) {
+ i_debug("program `%s' execution timed out: sending KILL signal",
+ pclient->path);
+ }
+
+ /* Kill it brutally now */
+ if ( kill(pid, SIGKILL) < 0 ) {
+ i_error("failed to send SIGKILL signal to program `%s'",
+ pclient->path);
+ return -1;
+ }
+
+ /* Now it will die immediately */
+ if ( waitpid(pid, &status, 0) < 0 ) {
+ i_error("waitpid(%s) failed: %m", pclient->path);
+ return -1;
+ }
+ }
+ }
+
+ /* Evaluate child exit status */
+ pclient->exit_code = -1;
+ if ( WIFEXITED(status) ) {
+ /* Exited */
+ int exit_code = WEXITSTATUS(status);
+
+ if ( exit_code != 0 ) {
+ i_info("program `%s' terminated with non-zero exit code %d",
+ pclient->path, exit_code);
+ pclient->exit_code = 0;
+ return 0;
+ }
+
+ pclient->exit_code = 1;
+ return 1;
+
+ } else if ( WIFSIGNALED(status) ) {
+ /* Killed with a signal */
+
+ if ( force ) {
+ i_error("program `%s' was forcibly terminated with signal %d",
+ pclient->path, WTERMSIG(status));
+ } else {
+ i_error("program `%s' terminated abnormally, signal %d",
+ pclient->path, WTERMSIG(status));
+ }
+ return -1;
+
+ } else if ( WIFSTOPPED(status) ) {
+ /* Stopped */
+ i_error("program `%s' stopped, signal %d",
+ pclient->path, WSTOPSIG(status));
+ return -1;
+ }
+
+ /* Something else */
+ i_error("program `%s' terminated abnormally, return status %d",
+ pclient->path, status);
+ return -1;
+}
+
+static void program_client_local_failure
More information about the dovecot-cvs
mailing list