]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
script: extract message parsing to separate function
authorMarkus Valentin <markus.valentin@open-xchange.com>
Wed, 19 Jun 2019 07:37:39 +0000 (09:37 +0200)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Tue, 10 Sep 2019 07:01:44 +0000 (10:01 +0300)
src/util/script.c

index b8bfd6f6fc686f84289e7e224ef4aadd33491ee8..fc06cf3d909fecf839c4ca003ad2c6d29e9a0cfc 100644 (file)
@@ -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();
        }