From 19c8cea8e525cb9886174630a0aa5b199a6ce153 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Mon, 3 Oct 2022 12:22:18 +0200 Subject: [PATCH] files: improve the error handling when executing an external command When something goes wrong while executing an external command or while piping text to it, report an error on the status bar and restore the state of the buffer to what it was before the execution. This fixes https://savannah.gnu.org/bugs/?63114. Bug existed since version 2.9.8, since filtering text was introduced, but basically existed since before version 2.0.0, since executing an external command was introduced. --- src/files.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/files.c b/src/files.c index 512f5826..64061452 100644 --- a/src/files.c +++ b/src/files.c @@ -1012,6 +1012,8 @@ void execute_command(const char *command) /* Original and temporary handlers for SIGINT. */ ssize_t was_lineno = (openfile->mark ? 0 : openfile->current->lineno); const bool should_pipe = (command[0] == '|'); + int command_status, sender_status; + pid_t pid_of_sender; FILE *stream; /* Create a pipe to read the command's output from, and, if needed, @@ -1095,11 +1097,14 @@ void execute_command(const char *command) } /* Create a separate process for piping the data to the command. */ - if (fork() == 0) { + if ((pid_of_sender = fork()) == 0) { send_data(whole_buffer ? openfile->filetop : cutbuffer, to_fd[1]); exit(0); } + if (pid_of_sender == -1) + statusline(ALERT, _("Could not fork: %s"), strerror(errno)); + close(to_fd[0]); close(to_fd[1]); @@ -1133,9 +1138,25 @@ void execute_command(const char *command) } /* Wait for the external command (and possibly data sender) to terminate. */ - wait(NULL); - if (should_pipe) - wait(NULL); + waitpid(pid_of_command, &command_status, 0); + if (should_pipe && pid_of_sender > 0) + waitpid(pid_of_sender, &sender_status, 0); + + /* If the command failed, show what the shell reported. */ + if (WIFEXITED(command_status) == 0 || WEXITSTATUS(command_status)) + statusline(ALERT, _("Error: %s"), !WIFSIGNALED(command_status) && + openfile->current->prev && + strstr(openfile->current->prev->data, ": ") ? + strstr(openfile->current->prev->data, ": ") + 2 : "---"); + else if (should_pipe && pid_of_sender > 0 && + (WIFEXITED(sender_status) == 0 || WEXITSTATUS(sender_status))) + statusline(ALERT, _("Piping failed")); + + /* If there was an error, undo and discard what the command did. */ + if (lastmessage == ALERT) { + do_undo(); + discard_until(openfile->current_undo); + } /* Restore the original handler for SIGINT. */ sigaction(SIGINT, &oldaction, NULL);