From: Willy Tarreau Date: Fri, 6 Dec 2019 16:18:28 +0000 (+0100) Subject: MINOR: debug: replace popen() with pipe+fork() in "debug dev exec" X-Git-Tag: v2.2-dev1~208 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=368bff40cea6cee1fef46d3201ef07cd007dbc25;p=thirdparty%2Fhaproxy.git MINOR: debug: replace popen() with pipe+fork() in "debug dev exec" popen() is annoying because it doesn't catch stderr. The command was implemented using it just by pure laziness, let's just redo it a bit cleaner using normal syscalls. Note that this command is only enabled when built with -DDEBUG_DEV. --- diff --git a/src/debug.c b/src/debug.c index fe2fe310c9..41fa7ae4a1 100644 --- a/src/debug.c +++ b/src/debug.c @@ -10,10 +10,13 @@ * */ +#include #include #include #include #include +#include +#include #include #include @@ -310,8 +313,9 @@ static int debug_parse_cli_panic(char **args, char *payload, struct appctx *appc #if defined(DEBUG_DEV) static int debug_parse_cli_exec(char **args, char *payload, struct appctx *appctx, void *private) { - FILE *f; + int pipefd[2]; int arg; + int pid; if (!cli_has_level(appctx, ACCESS_LVL_ADMIN)) return 1; @@ -324,14 +328,41 @@ static int debug_parse_cli_exec(char **args, char *payload, struct appctx *appct chunk_strcat(&trash, args[arg]); } - f = popen(trash.area, "re"); - if (!f) - return cli_err(appctx, "Failed to execute command.\n"); + thread_isolate(); + if (pipe(pipefd) < 0) + goto fail_pipe; + if (fcntl(pipefd[0], F_SETFD, fcntl(pipefd[0], F_GETFD, FD_CLOEXEC) | FD_CLOEXEC) == -1) + goto fail_fcntl; + + if (fcntl(pipefd[1], F_SETFD, fcntl(pipefd[1], F_GETFD, FD_CLOEXEC) | FD_CLOEXEC) == -1) + goto fail_fcntl; + + pid = fork(); + + if (pid < 0) + goto fail_fork; + else if (pid == 0) { + /* child */ + char *cmd[4] = { "/bin/sh", "-c", 0, 0 }; + + close(0); + dup2(pipefd[1], 1); + dup2(pipefd[1], 2); + + cmd[2] = trash.area; + execvp(cmd[0], cmd); + printf("execvp() failed\n"); + exit(1); + } + + /* parent */ + thread_release(); + close(pipefd[1]); chunk_reset(&trash); while (1) { - size_t ret = fread(trash.area + trash.data, 1, trash.size - 20 - trash.data, f); - if (!ret) + size_t ret = read(pipefd[0], trash.area + trash.data, trash.size - 20 - trash.data); + if (ret <= 0) break; trash.data += ret; if (trash.data + 20 == trash.size) { @@ -339,10 +370,18 @@ static int debug_parse_cli_exec(char **args, char *payload, struct appctx *appct break; } } - - fclose(f); + close(pipefd[0]); + waitpid(pid, NULL, WNOHANG); trash.area[trash.data] = 0; return cli_msg(appctx, LOG_INFO, trash.area); + + fail_fork: + fail_fcntl: + close(pipefd[0]); + close(pipefd[1]); + fail_pipe: + thread_release(); + return cli_err(appctx, "Failed to execute command.\n"); } #endif