diff dep/animone/src/fd/bsd.cc @ 270:0718f538c5f9

dep/animone: filter open files by access mode
author Paper <paper@paper.us.eu.org>
date Fri, 12 Apr 2024 19:13:50 -0400
parents 1a6a5d3a94cd
children 65df2813d0de
line wrap: on
line diff
--- a/dep/animone/src/fd/bsd.cc	Fri Apr 12 05:23:45 2024 -0400
+++ b/dep/animone/src/fd/bsd.cc	Fri Apr 12 19:13:50 2024 -0400
@@ -13,6 +13,7 @@
 
 #ifdef HAVE_KVM_GETFILES
 #	include <kvm.h>
+#	include <fts.h>
 #elif defined(LIBUTIL)
 #	include <libutil.h>
 #endif
@@ -110,10 +111,8 @@
 		return false;
 
 	/* actually get our results */
-	if (sysctl((const int*)mib, (sizeof(mib) / sizeof(*mib)) - 1, result.get(), &length, NULL, 0) == ENOMEM) {
-		result.reset();
-		throw std::bad_alloc();
-	}
+	if (sysctl((const int*)mib, (sizeof(mib) / sizeof(*mib)) - 1, result.get(), &length, NULL, 0) == ENOMEM)
+		return false;
 
 	if (length < sizeof(struct kinfo_proc))
 		return false;
@@ -126,10 +125,47 @@
 #endif
 }
 
+#ifdef HAVE_KVM_GETFILES
+static bool GetOpenFileName(const struct kinfo_file& file, std::string& name) {
+	/* OpenBSD doesn't provide a native API for this, so we have
+	 * to do it ourselves */
+	static constexpr std::string_view root = "/";
+
+	FTS* file_system = fts_open(root.data(), FTS_COMFOLLOW | FTS_NOCHDIR, nullptr);
+	if (!file_system)
+		return false;
+
+	/* Search through the filesystem for a file that matches our
+	 * kinfo_file structure */
+	FTSENT* parent = nullptr;
+	while ((parent = fts_read(file_system))) {
+		FTSENT* child = fts_children(file_system, 0);
+		while (child && child->fts_link) {
+			child = child->fts_link;
+			if (!S_ISREG(child->fts_statp->st_mode) || !S_ISLNK(child->fts_statp->st_mode))
+				continue;
+
+			if (child->fts_statp->st_dev != file->va_fsid)
+				continue;
+
+			if (child->fts_statp->st_ino != file->va_fileid)
+				continue;
+
+			name = std::string(child->fts_path) + child->fts_name;
+			fts_close(file_system);
+			return true;
+		}
+	}
+
+	fts_close(filesystem);
+	return false;
+}
+#endif /* HAVE_KVM_GETFILES */
+
 bool EnumerateOpenFiles(const std::set<pid_t>& pids, open_file_proc_t open_file_proc) {
 #ifdef HAVE_KVM_GETFILES
 	char errbuf[_POSIX2_LINE_MAX];
-	kvm_t* kernel = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
+	kvm_t* kernel = kvm_openfiles(nullptr, nullptr, nullptr, O_RDONLY, errbuf);
 	if (!kernel)
 		return false;
 
@@ -142,7 +178,15 @@
 		}
 
 		for (int i = 0; i < cnt; i++) {
-			if (!open_file_proc({pid, kfile[i].kf_path})) {
+			uint32_t oflags = kfile[i].kf_flags & O_ACCMODE;
+			if (oflags == O_WRONLY || oflags == O_RDWR)
+				continue;
+
+			std::string name;
+			if (!GetOpenFileName(kfile[i], name))
+				continue;
+
+			if (!open_file_proc({pid, name})) {
 				kvm_close(kernel);
 				return false;
 			}
@@ -150,10 +194,8 @@
 	}
 
 	kvm_close(kernel);
-
 	return true;
 #elif defined(LIBUTIL)
-	/* does this code even work? */
 	for (const auto& pid : pids) {
 		int cnt;
 		std::unique_ptr<struct kinfo_file[]> files(kinfo_getfile(pid, &cnt));
@@ -162,7 +204,11 @@
 
 		for (int i = 0; i < cnt; i++) {
 			const struct kinfo_file& current = files[i];
-			if (current.kf_vnode_type != KF_VTYPE_VREG)
+			if (current.kf_vnode_type != KF_VTYPE_VREG || current.kf_vnode_type != KF_VTYPE_VLNK)
+				continue;
+
+			const int oflags = current.kf_flags & O_ACCMODE;
+			if (oflags == O_WRONLY || oflags == O_RDWR)
 				continue;
 
 			if (!open_file_proc({pid, current.kf_path}))
@@ -172,29 +218,8 @@
 
 	return true;
 #else
-	for (const auto& pid : pids) {
-		int mib[6] = {CTL_KERN, KERN_FILE2, KERN_FILE_BYPID, pid, sizeof(struct kinfo_file), 0};
-
-		size_t len = 0;
-		if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &len, NULL, 0) == -1)
-			return false;
-
-		mib[5] = len / sizeof(struct kinfo_file);
-
-		std::unique_ptr<struct kinfo_file[]> buf(new struct kinfo_file[mib[5]]);
-		if (!buf)
-			return false;
-
-		if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf.get(), &len, NULL, 0) == -1)
-			return false;
-
-		/* TODO: check kfile[i].ki_ofileflags */
-		for (size_t i = 0; i < mib[5]; i++)
-			if (!open_file_proc({pid, kfile[i].kf_path}))
-				return false;
-	}
-
-	return true;
+	/* NetBSD doesn't even provide a real API for this */
+	return false;
 #endif
 }