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 <[email protected]>
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