From: Karel Zak Date: Thu, 17 Oct 2019 08:36:27 +0000 (+0200) Subject: lib/fileutils: add close_all_fds() X-Git-Tag: v2.35-rc1~97 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=488f65fcb819e20d2e6c611597bde40b911a8212;p=thirdparty%2Futil-linux.git lib/fileutils: add close_all_fds() The classic way which is based on file-descriptors table size is pretty expensive (due to table size) and forces code to do many unnecessary close() calls. It seems better to use /proc/self/fds and close used descriptors only. Addresses: https://github.com/karelzak/util-linux/issues/883 Signed-off-by: Karel Zak --- diff --git a/include/fileutils.h b/include/fileutils.h index 043f2ca44b..479ad15cfe 100644 --- a/include/fileutils.h +++ b/include/fileutils.h @@ -72,4 +72,6 @@ static inline struct dirent *xreaddir(DIR *dp) return d; } +extern void close_all_fds(const int exclude[], size_t exsz); + #endif /* UTIL_LINUX_FILEUTILS */ diff --git a/lib/fileutils.c b/lib/fileutils.c index 822ca9676b..3ca43c1fb5 100644 --- a/lib/fileutils.c +++ b/lib/fileutils.c @@ -124,16 +124,76 @@ int get_fd_tabsize(void) return m; } +static inline int in_set(int x, const int set[], size_t setsz) +{ + size_t i; + + for (i = 0; i < setsz; i++) { + if (set[i] == x) + return 1; + } + return 0; +} + +void close_all_fds(const int exclude[], size_t exsz) +{ + struct dirent *d; + DIR *dir; + + dir = opendir(_PATH_PROC_FDDIR); + if (dir) { + while ((d = xreaddir(dir))) { + char *end; + int fd; + + errno = 0; + fd = strtol(d->d_name, &end, 10); + + if (errno || end == d->d_name || !end || *end) + continue; + if (dirfd(dir) == fd) + continue; + if (in_set(fd, exclude, exsz)) + continue; + close(fd); + } + closedir(dir); + } else { + int fd, tbsz = get_fd_tabsize(); + + for (fd = 0; fd < tbsz; fd++) { + if (!in_set(fd, exclude, exsz)) + close(fd); + } + } +} + #ifdef TEST_PROGRAM_FILEUTILS -int main(void) +int main(int argc, char *argv[]) { - FILE *f; - char *tmpname; - f = xfmkstemp(&tmpname, NULL, "test"); - unlink(tmpname); - free(tmpname); - fclose(f); - return EXIT_FAILURE; + if (argc < 2) + errx(EXIT_FAILURE, "Usage %s --{mkstemp,close-fds}", argv[0]); + + if (strcmp(argv[1], "--mkstemp") == 0) { + FILE *f; + char *tmpname; + f = xfmkstemp(&tmpname, NULL, "test"); + unlink(tmpname); + free(tmpname); + fclose(f); + + } else if (strcmp(argv[1], "--close-fds") == 0) { + static const int wanted_fds[] = { + STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO + }; + + ignore_result( dup(STDIN_FILENO) ); + ignore_result( dup(STDIN_FILENO) ); + ignore_result( dup(STDIN_FILENO) ); + + close_all_fds(wanted_fds, ARRAY_SIZE(wanted_fds)); + } + return EXIT_SUCCESS; } #endif