From: Markus Valentin Date: Wed, 19 Jun 2019 07:37:39 +0000 (+0200) Subject: script: extract message parsing to separate function X-Git-Tag: 2.3.8~213 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=978dc7e2af2c7d691a529ec1aee66b179b520de9;p=thirdparty%2Fdovecot%2Fcore.git script: extract message parsing to separate function --- diff --git a/src/util/script.c b/src/util/script.c index b8bfd6f6fc..fc06cf3d90 100644 --- a/src/util/script.c +++ b/src/util/script.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */ +/* Copyright (c) 2010-2019 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "array.h" @@ -70,19 +70,15 @@ exec_child(struct master_service_connection *conn, execvp_const(args[0], args); } -static bool client_exec_script(struct master_service_connection *conn) +static bool +parse_input(ARRAY_TYPE(const_string)* envs, const char *const **args_r, + struct master_service_connection* conn, ssize_t *output_r) { - ARRAY_TYPE(const_string) envs; - const char *const *args; string_t *input; void *buf; size_t prev_size, scanpos; bool header_complete = FALSE, noreply = FALSE; - ssize_t ret; - int status; - pid_t pid; - net_set_nonblock(conn->fd, FALSE); input = t_buffer_create(IO_BLOCK_SIZE); /* Input contains: @@ -110,13 +106,13 @@ static bool client_exec_script(struct master_service_connection *conn) buf = buffer_append_space_unsafe(input, IO_BLOCK_SIZE); /* peek in socket input buffer */ - ret = recv(conn->fd, buf, IO_BLOCK_SIZE, MSG_PEEK); - if (ret <= 0) { + *output_r = recv(conn->fd, buf, IO_BLOCK_SIZE, MSG_PEEK); + if (*output_r <= 0) { buffer_set_used_size(input, prev_size); if (strchr(str_c(input), '\n') != NULL) script_verify_version(t_strcut(str_c(input), '\n')); - if (ret < 0) + if (*output_r < 0) i_fatal("recv(MSG_PEEK) failed: %m"); i_fatal("recv(MSG_PEEK) failed: disconnected"); @@ -124,7 +120,7 @@ static bool client_exec_script(struct master_service_connection *conn) /* scan for final \n\n */ pos = CONST_PTR_OFFSET(input->data, scanpos); - end = CONST_PTR_OFFSET(input->data, prev_size + ret); + end = CONST_PTR_OFFSET(input->data, prev_size + *output_r); for (; pos < end; pos++) { if (pos[-1] == '\n' && pos[0] == '\n') { header_complete = TRUE; @@ -135,11 +131,11 @@ static bool client_exec_script(struct master_service_connection *conn) scanpos = pos - (const unsigned char *)input->data; /* read data for real (up to and including \n\n) */ - ret = recv(conn->fd, buf, scanpos-prev_size, 0); - if (prev_size+ret != scanpos) { - if (ret < 0) + *output_r = recv(conn->fd, buf, scanpos-prev_size, 0); + if (prev_size+(*output_r) != scanpos) { + if (*output_r < 0) i_fatal("recv() failed: %m"); - if (ret == 0) + if (*output_r == 0) i_fatal("recv() failed: disconnected"); i_fatal("recv() failed: size of definitive recv() differs from peek"); } @@ -150,43 +146,59 @@ static bool client_exec_script(struct master_service_connection *conn) /* drop the last two LFs */ buffer_set_used_size(input, scanpos-2); - args = t_strsplit(str_c(input), "\n"); - script_verify_version(*args); args++; - t_array_init(&envs, 16); - if (*args != NULL) { + *args_r = t_strsplit(str_c(input), "\n"); + script_verify_version(**args_r); (*args_r)++; + if (**args_r != NULL) { const char *p; - if (str_begins(*args, "alarm=")) { + if (str_begins(**args_r, "alarm=")) { unsigned int seconds; - if (str_to_uint(*args + 6, &seconds) < 0) + if (str_to_uint((**args_r) + 6, &seconds) < 0) i_fatal("invalid alarm option"); alarm(seconds); - args++; + (*args_r)++; } - while (str_begins(*args, "env_")) { + while (str_begins(**args_r, "env_")) { const char *envname, *env; - env = t_str_tabunescape(*args+4); + env = t_str_tabunescape((**args_r)+4); p = strchr(env, '='); if (p == NULL) i_fatal("invalid environment variable"); - envname = t_strdup_until(*args+4, p); + envname = t_strdup_until((**args_r)+4, p); if (str_array_find(accepted_envs, envname)) - array_push_back(&envs, &env); - args++; + array_push_back(envs, &env); + (*args_r)++; } - if (strcmp(*args, "noreply") == 0) { + if (strcmp(**args_r, "noreply") == 0) { noreply = TRUE; } - if (**args == '\0') + if (***args_r == '\0') i_fatal("empty options"); - args++; + (*args_r)++; } - array_append_zero(&envs); + array_append_zero(envs); + + return noreply; +} + +static bool client_exec_script(struct master_service_connection *conn) +{ + ARRAY_TYPE(const_string) envs; + const char *const *args = NULL; + ssize_t ret; + int status; + pid_t pid; + + t_array_init(&envs, 16); + + net_set_nonblock(conn->fd, FALSE); - if (noreply) { - /* no need to fork and check exit status */ + if (parse_input(&envs, &args, conn, &ret)) { + /* parse_input returns TRUE if noreply is set in the input. + * In that case there is no need to fork and check exit + * status */ exec_child(conn, args, array_front(&envs)); i_unreached(); }