If a child process sets stdin to non-blocking and does not set it back to blocking before exiting, other processes may fail to read from stdin.
Reproducer steps : $ cat set_nonblock.c #include <stdio.h> #include <unistd.h> #include <fcntl.h> int main() { char buff[256]; int flags = fcntl (0, F_GETFL); if (fcntl(0, F_SETFL, flags | O_NONBLOCK)) { perror("fcntl failed"); } if (read(0, buff, 256) == -1) { perror("read failed"); } } $ cc -o set_nonblock set_nonblock.c $ cat test.sh #!/bin/bash ./set_nonblock cat $ ./test.sh read failed: Resource temporarily unavailable cat: -: Resource temporarily unavailable Attached patch sets standard file descriptors to blocking before child process starts. -- -- Siteshwar Vashisht
From f4fd3c17cb15f87fc8733b44bd477e32ff2d002a Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht <svashi...@redhat.com> Date: Sun, 22 Jan 2017 08:25:23 +0100 Subject: [PATCH] Make stdin blocking when command starts --- execute_cmd.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/execute_cmd.c b/execute_cmd.c index 00389df..d63f6e5 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -531,6 +531,22 @@ async_redirect_stdin () internal_error (_("cannot redirect standard input from /dev/null: %s"), strerror (errno)); } +/* Make stdin,stdout and stderr blocking */ +static void +set_standard_fds_blocking() { + int flags = fcntl (0, F_GETFL); + if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK)) + sys_error (_("Failed to make stdin blocking")); + + flags = fcntl (1, F_GETFL); + if (fcntl(1, F_SETFL, flags & ~O_NONBLOCK)) + sys_error (_("Failed to make stdout blocking")); + + flags = fcntl (2, F_GETFL); + if (fcntl(2, F_SETFL, flags & ~O_NONBLOCK)) + sys_error (_("Failed to make stderr blocking")); +} + #define DESCRIBE_PID(pid) do { if (interactive) describe_pid (pid); } while (0) extern int rpm_requires; @@ -594,6 +610,8 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, exec_result = EXECUTION_SUCCESS; + set_standard_fds_blocking(); + /* If a command was being explicitly run in a subshell, or if it is a shell control-structure, and it has a pipe, then we do the command in a subshell. */ -- 2.9.3