dovecot-2.0: Added "script" service that can be used to easily e...
dovecot at dovecot.org
dovecot at dovecot.org
Wed Jun 2 20:52:15 EEST 2010
details: http://hg.dovecot.org/dovecot-2.0/rev/19c661891964
changeset: 11461:19c661891964
user: Timo Sirainen <tss at iki.fi>
date: Wed Jun 02 18:46:26 2010 +0100
description:
Added "script" service that can be used to easily execute programs via UNIX socket.
diffstat:
.hgignore | 1 +
src/util/Makefile.am | 6 ++
src/util/script.c | 125 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 132 insertions(+), 0 deletions(-)
diffs (163 lines):
diff -r 3ac8c5dd9c30 -r 19c661891964 .hgignore
--- a/.hgignore Wed Jun 02 18:45:02 2010 +0100
+++ b/.hgignore Wed Jun 02 18:46:26 2010 +0100
@@ -86,6 +86,7 @@
src/util/listview
src/util/maildirlock
src/util/rawlog
+src/util/script
src/util/script-login
src/util/tcpwrap
src/plugins/quota/rquota_xdr.c
diff -r 3ac8c5dd9c30 -r 19c661891964 src/util/Makefile.am
--- a/src/util/Makefile.am Wed Jun 02 18:45:02 2010 +0100
+++ b/src/util/Makefile.am Wed Jun 02 18:46:26 2010 +0100
@@ -2,6 +2,7 @@
pkglibexec_PROGRAMS = \
rawlog \
+ script \
script-login \
$(TCPWRAP_BIN) \
gdbhelper \
@@ -32,6 +33,11 @@
script_login_SOURCES = \
script-login.c
+script_LDADD = $(LIBDOVECOT) $(MODULE_LIBS)
+script_DEPENDENCIES = $(LIBDOVECOT_DEPS)
+script_SOURCES = \
+ script.c
+
if TCPWRAPPERS
TCPWRAP_BIN = tcpwrap
tcpwrap_LDADD = $(LIBDOVECOT) $(MODULE_LIBS) $(LIBWRAP_LIBS)
diff -r 3ac8c5dd9c30 -r 19c661891964 src/util/script.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/util/script.c Wed Jun 02 18:46:26 2010 +0100
@@ -0,0 +1,125 @@
+/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "execv-const.h"
+#include "master-interface.h"
+#include "master-service.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#define SCRIPT_MAJOR_VERSION 1
+#define SCRIPT_READ_TIMEOUT_SECS 10
+
+static ARRAY_TYPE(const_string) exec_args;
+
+static void script_verify_version(const char *line)
+{
+ if (line == NULL ||
+ !version_string_verify(line, "script", SCRIPT_MAJOR_VERSION)) {
+ i_fatal("Client not compatible with this binary "
+ "(connecting to wrong socket?)");
+ }
+}
+
+static void client_connected(struct master_service_connection *conn)
+{
+ const unsigned char *end;
+ const char *const *args;
+ buffer_t *input;
+ void *buf;
+ unsigned int i, socket_count;
+ size_t prev_size;
+ ssize_t ret;
+
+ net_set_nonblock(conn->fd, FALSE);
+ input = buffer_create_dynamic(pool_datastack_create(), IO_BLOCK_SIZE);
+
+ /* Input contains:
+
+ VERSION .. <lf>
+ arg 1 <lf>
+ arg 2 <lf>
+ ...
+ <lf> */
+ alarm(SCRIPT_READ_TIMEOUT_SECS);
+ do {
+ prev_size = input->used;
+ buf = buffer_append_space_unsafe(input, IO_BLOCK_SIZE);
+ ret = read(conn->fd, buf, IO_BLOCK_SIZE);
+ if (ret <= 0) {
+ buffer_set_used_size(input, prev_size);
+ if (strchr(str_c(input), '\n') != NULL)
+ script_verify_version(t_strcut(str_c(input), '\t'));
+
+ if (ret < 0)
+ i_fatal("read() failed: %m");
+ else
+ i_fatal("read() failed: disconnected");
+ }
+ buffer_set_used_size(input, prev_size + ret);
+ end = CONST_PTR_OFFSET(input->data, input->used);
+ } while (!(end[-1] == '\n' && (input->used == 1 || end[-2] == '\n')));
+
+ /* drop the last LF */
+ buffer_set_used_size(input, input->used - 1);
+
+ args = t_strsplit(str_c(input), "\n");
+ script_verify_version(*args);
+
+ for (args++; *args != NULL; args++)
+ array_append(&exec_args, args, 1);
+ (void)array_append_space(&exec_args);
+
+ /* close all fds */
+ socket_count = master_service_get_socket_count(master_service);
+ for (i = 0; i < socket_count; i++) {
+ if (close(MASTER_LISTEN_FD_FIRST + i) < 0)
+ i_error("close(listener) failed: %m");
+ }
+ if (close(MASTER_STATUS_FD) < 0)
+ i_error("close(status) failed: %m");
+ if (close(conn->fd) < 0)
+ i_error("close() failed: %m");
+
+ args = array_idx(&exec_args, 0);
+ execvp_const(args[0], args);
+}
+
+int main(int argc, char *argv[])
+{
+ const char *binary;
+ int i;
+
+ master_service = master_service_init("script", 0, &argc, &argv, NULL);
+ if (master_getopt(master_service) > 0)
+ return FATAL_DEFAULT;
+ argc -= optind;
+ argv += optind;
+
+ master_service_init_log(master_service, "script: ");
+ master_service_init_finish(master_service);
+ master_service_set_service_count(master_service, 1);
+
+ if (argv[0] == NULL)
+ i_fatal("Missing script path");
+
+ if (argv[0][0] == '/')
+ binary = argv[0];
+ else
+ binary = t_strconcat(PKG_LIBEXECDIR"/", argv[0], NULL);
+
+ i_array_init(&exec_args, argc + 16);
+ array_append(&exec_args, &binary, 1);
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+
+ array_append(&exec_args, &arg, 1);
+ }
+
+ master_service_run(master_service, client_connected);
+ master_service_deinit(&master_service);
+ return 0;
+}
More information about the dovecot-cvs
mailing list