--- /dev/null
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LVM_DAEMON_STRAY_H
+#define _LVM_DAEMON_STRAY_H
+
+/*
+ * needs dm -> #include "device_mapper/all.h"
+ * needs logging -> #include "libdm/misc/dmlib.h"
+ */
+#include "lib/misc/lvm-file.h"
+
+/*
+ * When compiling with valgrind pool support, skip closing descriptors
+ * as there is couple more of them being held by valgrind itself.
+ */
+#ifndef VALGRIND_POOL
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <limits.h>
+
+#ifdef HAVE_VALGRIND
+#include <valgrind.h>
+#endif
+
+static void _daemon_get_cmdline(pid_t pid, char *cmdline, size_t size)
+{
+ char buf[sizeof(DEFAULT_PROC_DIR) + 32];
+ int fd, n = 0;
+
+ snprintf(buf, sizeof(buf), DEFAULT_PROC_DIR "/%u/cmdline", pid);
+ /* FIXME Use generic read code. */
+ if ((fd = open(buf, O_RDONLY)) >= 0) {
+ if ((n = read(fd, cmdline, size - 1)) < 0) {
+ //perror("read", buf);
+ n = 0;
+ }
+ (void) close(fd);
+ }
+ cmdline[n] = '\0';
+}
+
+static void _daemon_get_filename(int fd, char *filename, size_t size)
+{
+ char buf[sizeof(DEFAULT_PROC_DIR) + 32];
+ ssize_t lsize;
+
+ snprintf(buf, sizeof(buf), DEFAULT_PROC_DIR "/self/fd/%u", fd);
+
+ if ((lsize = readlink(buf, filename, sizeof(filename) - 1)) == -1)
+ filename[0] = '\0';
+ else
+ filename[lsize] = '\0';
+}
+
+static void _daemon_close_descriptor(int fd, unsigned suppress_warnings,
+ const char *command, pid_t ppid,
+ const char *parent_cmdline)
+{
+ char filename[PATH_MAX];
+ int r;
+
+ /* Ignore bad file descriptors */
+ if (!is_valid_fd(fd))
+ return;
+
+ if (!suppress_warnings)
+ _daemon_get_filename(fd, filename, sizeof(filename));
+
+ r = close(fd);
+ if ((fd <= STDERR_FILENO) || suppress_warnings)
+ return;
+
+ if (!r)
+ fprintf(stderr, "File descriptor %d (%s) leaked on "
+ "%s invocation.", fd, filename, command);
+ else if (errno == EBADF)
+ return;
+ else
+ fprintf(stderr, "Close failed on stray file descriptor "
+ "%d (%s): %s", fd, filename, strerror(errno));
+
+ fprintf(stderr, " Parent PID %d: %s\n", (int)ppid, parent_cmdline);
+}
+
+#endif /* VALGRIND_POOL */
+
+/* Close all stray descriptor except custom fds.
+ * Note: when 'from_fd' is set to -1, unused 'custom_fds' must use same value!
+ *
+ * command: print command name with warning message
+ * suppress_warning: whether to print warning messages
+ * above_fd: close all descriptors above this descriptor
+ * custom_fds: preserve descriptors from this set of descriptors
+ */
+static int daemon_close_stray_fds(const char *command, int suppress_warning,
+ int from_fd, const struct custom_fds *custom_fds)
+{
+#ifndef VALGRIND_POOL
+ struct rlimit rlim;
+ int fd;
+ unsigned suppress_warnings = 0;
+ pid_t ppid = getppid();
+ char parent_cmdline[64];
+ static const char _fd_dir[] = DEFAULT_PROC_DIR "/self/fd";
+ struct dirent *dirent;
+ DIR *d;
+
+#ifdef HAVE_VALGRIND
+ if (RUNNING_ON_VALGRIND)
+ /* Skipping close of descriptors within valgrind execution. */
+ return 1;
+#endif /* HAVE_VALGRIND */
+ _daemon_get_cmdline(ppid, parent_cmdline, sizeof(parent_cmdline));
+
+ if ((d = opendir(_fd_dir))) {
+ /* Discover openned descriptors from /proc/self/fd listing */
+ while ((dirent = readdir(d))) {
+ fd = atoi(dirent->d_name);
+ if ((fd > from_fd) &&
+ (fd != dirfd(d)) &&
+ (fd != custom_fds->out) &&
+ (fd != custom_fds->err) &&
+ (fd != custom_fds->report))
+ _daemon_close_descriptor(fd, suppress_warnings,
+ command, ppid, parent_cmdline);
+ }
+
+ (void) closedir(d);
+ } else if (errno == ENOENT) {
+ /* Path does not exist, use the old way */
+ if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
+ fd = 256; /* just have to guess */
+ else if ((fd = (int)rlim.rlim_cur) > 65536)
+ fd = 65536; /* do not bother with more then 64K fds */
+
+ while (--fd > from_fd) {
+ if ((fd != custom_fds->out) &&
+ (fd != custom_fds->err) &&
+ (fd != custom_fds->report))
+ _daemon_close_descriptor(fd, suppress_warnings, command,
+ ppid, parent_cmdline);
+ }
+ } else
+ return 0; /* broken system */
+#endif /* VALGRIND_POOL */
+ return 1;
+}
+
+#endif
#include "lvm-version.h"
#include "lib/locking/lvmlockd.h"
#include "lib/datastruct/str_list.h"
+#include "libdaemon/server/daemon-stray.h"
/* coverity[unnecessary_header] */
#include "stub.h"
#include <locale.h>
#include <langinfo.h>
-#ifdef HAVE_VALGRIND
-#include <valgrind.h>
-#endif
-
#ifdef HAVE_GETOPTLONG
# include <getopt.h>
# define GETOPTLONG_FN(a, b, c, d, e) getopt_long((a), (b), (c), (d), (e))
_do_get_custom_fd(LVM_REPORT_FD_ENV_VAR_NAME, &custom_fds->report);
}
-static const char *_get_cmdline(pid_t pid)
-{
- static char _proc_cmdline[32];
- char buf[256];
- int fd, n = 0;
-
- snprintf(buf, sizeof(buf), DEFAULT_PROC_DIR "/%u/cmdline", pid);
- /* FIXME Use generic read code. */
- if ((fd = open(buf, O_RDONLY)) >= 0) {
- if ((n = read(fd, _proc_cmdline, sizeof(_proc_cmdline) - 1)) < 0) {
- log_sys_error("read", buf);
- n = 0;
- }
- if (close(fd))
- log_sys_error("close", buf);
- }
- _proc_cmdline[n] = '\0';
-
- return _proc_cmdline;
-}
-
-static const char *_get_filename(int fd)
-{
- static char filename[PATH_MAX];
- char buf[32]; /* Assumes short DEFAULT_PROC_DIR */
- int size;
-
- snprintf(buf, sizeof(buf), DEFAULT_PROC_DIR "/self/fd/%u", fd);
-
- if ((size = readlink(buf, filename, sizeof(filename) - 1)) == -1)
- filename[0] = '\0';
- else
- filename[size] = '\0';
-
- return filename;
-}
-
-static void _close_descriptor(int fd, unsigned suppress_warnings,
- const char *command, pid_t ppid,
- const char *parent_cmdline)
-{
- int r;
- const char *filename;
-
- /* Ignore bad file descriptors */
- if (!is_valid_fd(fd))
- return;
-
- if (!suppress_warnings)
- filename = _get_filename(fd);
-
- r = close(fd);
- if (suppress_warnings)
- return;
-
- if (!r)
- fprintf(stderr, "File descriptor %d (%s) leaked on "
- "%s invocation.", fd, filename, command);
- else if (errno == EBADF)
- return;
- else
- fprintf(stderr, "Close failed on stray file descriptor "
- "%d (%s): %s", fd, filename, strerror(errno));
-
- fprintf(stderr, " Parent PID %" PRIpid_t ": %s\n", ppid, parent_cmdline);
-}
-
-static int _close_stray_fds(const char *command, struct custom_fds *custom_fds)
-{
-#ifndef VALGRIND_POOL
- struct rlimit rlim;
- int fd;
- unsigned suppress_warnings = 0;
- pid_t ppid = getppid();
- const char *parent_cmdline = _get_cmdline(ppid);
- static const char _fd_dir[] = DEFAULT_PROC_DIR "/self/fd";
- struct dirent *dirent;
- DIR *d;
-
-#ifdef HAVE_VALGRIND
- if (RUNNING_ON_VALGRIND) {
- log_debug("Skipping close of descriptors within valgrind execution.");
- return 1;
- }
-#endif
-
- if (getenv("LVM_SUPPRESS_FD_WARNINGS"))
- suppress_warnings = 1;
-
- if (!(d = opendir(_fd_dir))) {
- if (errno != ENOENT) {
- log_sys_error("opendir", _fd_dir);
- return 0; /* broken system */
- }
-
- /* Path does not exist, use the old way */
- if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
- log_sys_error("getrlimit", "RLIMIT_NOFILE");
- return 1;
- }
-
- for (fd = 3; fd < (int)rlim.rlim_cur; fd++) {
- if ((fd != custom_fds->out) &&
- (fd != custom_fds->err) &&
- (fd != custom_fds->report)) {
- _close_descriptor(fd, suppress_warnings, command, ppid,
- parent_cmdline);
- }
- }
- return 1;
- }
-
- while ((dirent = readdir(d))) {
- fd = atoi(dirent->d_name);
- if ((fd > 2) &&
- (fd != dirfd(d)) &&
- (fd != custom_fds->out) &&
- (fd != custom_fds->err) &&
- (fd != custom_fds->report)) {
- _close_descriptor(fd, suppress_warnings,
- command, ppid, parent_cmdline);
- }
- }
-
- if (closedir(d))
- log_sys_debug("closedir", _fd_dir);
-#endif
-
- return 1;
-}
-
struct cmd_context *init_lvm(unsigned set_connections,
unsigned set_filters,
unsigned threaded)
if (!_get_custom_fds(&custom_fds))
return EINIT_FAILED;
- if (!_close_stray_fds(base, &custom_fds))
+ if (!daemon_close_stray_fds(base, getenv("LVM_SUPPRESS_FD_WARNINGS") ? 1 : 0,
+ STDERR_FILENO, &custom_fds))
return EINIT_FAILED;
if (!init_custom_log_streams(&custom_fds))