From: Olliver Schinagl Date: Fri, 16 Jun 2023 13:25:36 +0000 (+0200) Subject: spawn: Do not close every possible file descriptor X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=85360356660a11e5c7a65274d58e5f4945f83f5f;p=thirdparty%2Ftvheadend.git spawn: Do not close every possible file descriptor When close is called with a non-existant file descriptor, it will happily do so. Since we do not even check for the error code, trying to close a non existant/not-open file descriptor does not even cause an error. This in itself is not a problem at all, however, we try to close every open file descriptor beyond stderr, upto whatever _SC_OPEN_MAX returns. Some systems may have a very large ulimit set for `_SC_OPEN_MAX` and thus `maxfd` may return something in the millions. This means that the simple `for() close();` loop now has to iterate a million file descriptors which may not even be open/exist. Instead, we can use the power of `/proc/self/fd` to list our open file descriptors, and only close open ones. Signed-off-by: Olliver Schinagl --- diff --git a/src/spawn.c b/src/spawn.c index 516168f6a..a491c0690 100644 --- a/src/spawn.c +++ b/src/spawn.c @@ -459,7 +459,7 @@ spawn_and_give_stdout(const char *prog, char *argv[], char *envp[], int *rd, pid_t *pid, int redir_stderr) { pid_t p; - int fd[2], f, i, maxfd; + int fd[2], f, i; char bin[256]; const char *local_argv[2] = { NULL, NULL }; char **e, **e0, **e2, **e3, *p1, *p2; @@ -507,8 +507,6 @@ spawn_and_give_stdout(const char *prog, char *argv[], char *envp[], *e0 = NULL; } - maxfd = sysconf(_SC_OPEN_MAX); - tvh_mutex_lock(&fork_lock); if(pipe(fd) == -1) { @@ -528,6 +526,9 @@ spawn_and_give_stdout(const char *prog, char *argv[], char *envp[], } if(p == 0) { + struct dirent *selfd_ent; + DIR *selfd; + f = open("/dev/null", O_RDWR); if(f == -1) { spawn_error("pid %d cannot open /dev/null for redirect %s -- %s", @@ -549,8 +550,25 @@ spawn_and_give_stdout(const char *prog, char *argv[], char *envp[], spawn_info("Executing \"%s\"\n", prog); - for (f = 3; f < maxfd; f++) - close(f); + if ((selfd = opendir("/dev/fd")) != NULL) { + while ((selfd_ent = readdir(selfd)) != NULL) { + int open_fd = atoi(selfd_ent->d_name); + + if (open_fd >= 3) { + if (close(open_fd) == -1) + spawn_error("failed to close fd '%d': %s", open_fd, strerror(errno)); + } + } + closedir(selfd); + } else { + int maxfd = sysconf(_SC_OPEN_MAX);; + + spawn_error("unable to open '/dev/fd', falling back to closing all %d" + "This may take a long time!", maxfd); + + for (f = 3; f < maxfd; f++) + close(f); + } execve(prog, argv, e); spawn_error("pid %d cannot execute %s -- %s\n",