https://www.redhat.com/archives/libguestfs/2019-August/thread.html#00347
Thanks: Eric Blake and Daniel P. Berrangé
---
common/utils/utils.h | 1 +
server/connections.c | 4 ++--
server/crypto.c | 5 +++--
server/main.c | 23 +++++++++++++++++++++++
common/utils/utils.c | 29 +++++++++++++++++++++++++++++
5 files changed, 58 insertions(+), 4 deletions(-)
diff --git a/common/utils/utils.h b/common/utils/utils.h
index ebd5f66..a77d2cd 100644
--- a/common/utils/utils.h
+++ b/common/utils/utils.h
@@ -38,5 +38,6 @@ extern void uri_quote (const char *str, FILE *fp);
extern int exit_status_to_nbd_error (int status, const char *cmd);
extern int set_cloexec (int fd);
extern int set_nonblock (int fd);
+extern void close_or_nullify_fd (int fd);
#endif /* NBDKIT_UTILS_H */
diff --git a/server/connections.c b/server/connections.c
index c173df8..f57ab3e 100644
--- a/server/connections.c
+++ b/server/connections.c
@@ -489,7 +489,7 @@ static void
raw_close (struct connection *conn)
{
if (conn->sockin >= 0)
- close (conn->sockin);
+ close_or_nullify_fd (conn->sockin);
if (conn->sockout >= 0 && conn->sockin != conn->sockout)
- close (conn->sockout);
+ close_or_nullify_fd (conn->sockout);
}
diff --git a/server/crypto.c b/server/crypto.c
index 9cd1bb0..6f97f2c 100644
--- a/server/crypto.c
+++ b/server/crypto.c
@@ -47,6 +47,7 @@
#include <assert.h>
#include "internal.h"
+#include "utils.h"
#ifdef HAVE_GNUTLS
@@ -404,9 +405,9 @@ crypto_close (struct connection *conn)
gnutls_bye (session, GNUTLS_SHUT_RDWR);
if (sockin >= 0)
- close (sockin);
+ close_or_nullify_fd (sockin);
if (sockout >= 0 && sockin != sockout)
- close (sockout);
+ close_or_nullify_fd (sockout);
gnutls_deinit (session);
conn->crypto_session = NULL;
diff --git a/server/main.c b/server/main.c
index 65025a6..65bef30 100644
--- a/server/main.c
+++ b/server/main.c
@@ -60,6 +60,7 @@ static struct backend *open_filter_so (struct backend *next, size_t i,
const cha
static void start_serving (void);
static void write_pidfile (void);
static bool is_config_key (const char *key, size_t len);
+static void open_std_file_descriptors (void);
struct debug_flag *debug_flags; /* -D */
bool exit_with_parent; /* --exit-with-parent */
@@ -149,6 +150,13 @@ main (int argc, char *argv[])
size_t i;
const char *magic_config_key;
+ /* Ensures that fds 0, 1 and 2 are open (on /dev/null if nothing
+ * else). This is so that nbdkit and plugins can assume these file
+ * descriptors are always open, which makes certain code easier to
+ * write.
+ */
+ open_std_file_descriptors ();
+
threadlocal_init ();
/* The default setting for TLS depends on whether we were
@@ -930,3 +938,18 @@ is_config_key (const char *key, size_t len)
return true;
}
+
+static void
+open_std_file_descriptors (void)
+{
+ int fds[] = { STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO };
+ int i, fd, fl;
+
+ for (i = 0; i < sizeof fds / sizeof fds[0]; ++i) {
+ fd = fds[i];
+ fl = fcntl (fd, F_GETFL, NULL);
+ if (fl == -1 && errno == EBADF)
+ /* This is best effort - don't fail. */
+ open ("/dev/null", fd == STDIN_FILENO ? O_RDONLY : O_WRONLY);
+ }
+}
diff --git a/common/utils/utils.c b/common/utils/utils.c
index 32bc96a..c818d4c 100644
--- a/common/utils/utils.c
+++ b/common/utils/utils.c
@@ -190,3 +190,32 @@ set_nonblock (int fd) {
}
return fd;
}
+
+/* Calls close (fd). As a special case if fd is stdin/stdout/stderr
+ * then it reopens the file descriptor on /dev/null. This allows us
+ * to maintain certain invariants for nbdkit and plugins. In all
+ * cases this ignores errors.
+ */
+void
+close_or_nullify_fd (int fd)
+{
+ int flags;
+ int nfd;
+
+ close (fd);
+
+ if (fd == STDIN_FILENO)
+ flags = O_RDONLY;
+ else if (fd == STDOUT_FILENO || fd == STDERR_FILENO)
+ flags = O_WRONLY;
+ else
+ return;
+
+ nfd = open ("/dev/null", flags);
+ if (nfd == -1)
+ return;
+ if (nfd != fd) {
+ dup2 (nfd, fd);
+ close (nfd);
+ }
+}
--
2.22.0