script.c revision db776508d6e959ae6e66050e22e2763521e6d272
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#include "lib.h"
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#include "array.h"
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#include "str.h"
7f945ad00fd50dbbbe09dc2e79e0d8d24f917052Timo Sirainen#include "env-util.h"
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#include "execv-const.h"
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#include "master-interface.h"
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#include "master-service.h"
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#include <stdlib.h>
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#include <unistd.h>
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#define SCRIPT_MAJOR_VERSION 1
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#define SCRIPT_READ_TIMEOUT_SECS 10
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainenstatic ARRAY_TYPE(const_string) exec_args;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainenstatic void script_verify_version(const char *line)
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen{
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen if (line == NULL ||
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen !version_string_verify(line, "script", SCRIPT_MAJOR_VERSION)) {
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen i_fatal("Client not compatible with this binary "
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen "(connecting to wrong socket?)");
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen }
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen}
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainenstatic void client_connected(struct master_service_connection *conn)
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen{
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen const unsigned char *end;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen const char *const *args;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen buffer_t *input;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen void *buf;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen unsigned int i, socket_count;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen size_t prev_size;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen ssize_t ret;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen net_set_nonblock(conn->fd, FALSE);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen input = buffer_create_dynamic(pool_datastack_create(), IO_BLOCK_SIZE);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen /* Input contains:
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen VERSION .. <lf>
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen arg 1 <lf>
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen arg 2 <lf>
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen ...
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen <lf> */
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen alarm(SCRIPT_READ_TIMEOUT_SECS);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen do {
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen prev_size = input->used;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen buf = buffer_append_space_unsafe(input, IO_BLOCK_SIZE);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen ret = read(conn->fd, buf, IO_BLOCK_SIZE);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen if (ret <= 0) {
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen buffer_set_used_size(input, prev_size);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen if (strchr(str_c(input), '\n') != NULL)
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen script_verify_version(t_strcut(str_c(input), '\t'));
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen if (ret < 0)
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen i_fatal("read() failed: %m");
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen else
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen i_fatal("read() failed: disconnected");
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen }
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen buffer_set_used_size(input, prev_size + ret);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen end = CONST_PTR_OFFSET(input->data, input->used);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen } while (!(end[-1] == '\n' && (input->used == 1 || end[-2] == '\n')));
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen /* drop the last LF */
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen buffer_set_used_size(input, input->used - 1);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen args = t_strsplit(str_c(input), "\n");
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen script_verify_version(*args);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen for (args++; *args != NULL; args++)
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen array_append(&exec_args, args, 1);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen (void)array_append_space(&exec_args);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen /* close all fds */
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen socket_count = master_service_get_socket_count(master_service);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen for (i = 0; i < socket_count; i++) {
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen if (close(MASTER_LISTEN_FD_FIRST + i) < 0)
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen i_error("close(listener) failed: %m");
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen }
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen if (close(MASTER_STATUS_FD) < 0)
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen i_error("close(status) failed: %m");
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen if (close(conn->fd) < 0)
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen i_error("close() failed: %m");
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
7f945ad00fd50dbbbe09dc2e79e0d8d24f917052Timo Sirainen env_clean();
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen args = array_idx(&exec_args, 0);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen execvp_const(args[0], args);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen}
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainenint main(int argc, char *argv[])
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen{
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen const char *binary;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen int i;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
db776508d6e959ae6e66050e22e2763521e6d272Timo Sirainen master_service = master_service_init("script", 0, &argc, &argv, "+");
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen if (master_getopt(master_service) > 0)
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen return FATAL_DEFAULT;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen argc -= optind;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen argv += optind;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen master_service_init_log(master_service, "script: ");
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen master_service_init_finish(master_service);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen master_service_set_service_count(master_service, 1);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen if (argv[0] == NULL)
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen i_fatal("Missing script path");
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen if (argv[0][0] == '/')
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen binary = argv[0];
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen else
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen binary = t_strconcat(PKG_LIBEXECDIR"/", argv[0], NULL);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen i_array_init(&exec_args, argc + 16);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen array_append(&exec_args, &binary, 1);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen for (i = 1; i < argc; i++) {
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen const char *arg = argv[i];
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen array_append(&exec_args, &arg, 1);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen }
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen master_service_run(master_service, client_connected);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen master_service_deinit(&master_service);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen return 0;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen}