diff dep/animia/src/fd/kvm.cc @ 169:e44b7c428d7c

dep/animia: add libkvm method (UNTESTED)
author Paper <mrpapersonic@gmail.com>
date Sun, 19 Nov 2023 17:30:38 -0500
parents
children 8f6f8dd2eb23
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/animia/src/fd/kvm.cc	Sun Nov 19 17:30:38 2023 -0500
@@ -0,0 +1,134 @@
+/* kvm.cc: provides support for libkvm in multiple BSDs
+**
+** this is really the only way to get a thing that works on
+** OpenBSD AND NetBSD.
+**
+** Much of this file is taken from the fstat source code in
+** NetBSD.
+*/
+
+#include <kvm.h>
+
+namespace animia::internal::kvm {
+
+static bool GetFilename(kvm_t* kvm, struct vnode *vp, std::string& name) {
+	struct vnode vn;
+	if (!kvm_read(kvm, vp, &vn, sizeof(*vn)))
+		return 0;
+
+	struct filestat fst;
+	const char* type = vfilestat(vn, &fst);
+	if (type == dead)
+		return false;
+
+	for (DEVS* d = devs; d != NULL; d = d->next) {
+		if (d->fsid == fst->fsid && d->ino == fst->fileid) {
+			name = d->name;
+			break;
+		}
+	}
+
+	return true;
+}
+
+static bool GetFilePath(kvm_t* kvm, fdfile_t* fp, std::string& path) {
+	struct file file;
+	fdfile_t fdfile;
+
+	if (!kvm_read(kvm, fp, &fdfile, sizeof(fdfile)))
+		return false;
+
+	if (!fdfile.ff_file)
+		return false;
+
+	if (!kvm_read(fdfile.ff_file, &file, sizeof(file)))
+		return false;
+
+	if (file.f_type != DTYPE_VNODE)
+		return false;
+
+	return GetFilename(kvm, file.f_data, path);
+}
+
+static bool OpenFiles(kvm_t* kvm, struct kinfo_proc* p, open_file_proc_t open_file_proc) {
+	if (p->proc->p_fd == 0 || p->proc->p_cwdi == 0)
+		return false;
+
+	struct filedesc filed;
+	if (!kvm_read(kvm, p->proc->p_fd, &filed, sizeof(filed)))
+		return false;
+
+	if (filed.fd_lastfile == -1)
+		return false;
+
+	struct cwdinfo cwdi;
+	if (!kvm_read(kvm, p->proc->p_cwdi, &cwdi, sizeof(cwdi)))
+		return false;
+
+	struct fdtab dt;
+	if (!kvm_read(kvm, filed.fd_dt, &dt, sizeof(dt)))
+		return false;
+
+	/* check for corrupted files? */
+	if ((unsigned)filed.fd_lastfile >= dt.dt_nfiles || filed.fd_freefile > filed.fd_lastfile + 1)
+		return false;
+
+	/* open files */
+	std::unique_ptr<fdfile_t*[]> ofiles = nullptr;
+	{
+		ofiles.reset(malloc((filed.fd_lastfile + 1) * sizeof(fdfile_t*)));
+		if (!ofiles.get())
+			return false;
+	}
+
+	if (!kvm_read(kvm, &filed.fd_dt->dt_ff, ofiles.get(), filed.fd_lastfile + 1 * (sizeof(fdfile_t*))))
+		return false;
+
+	for (int i = 0; i <= filed.fd_lastfile; i++) {
+		if (!ofiles[i])
+			continue;
+		std::string name;
+		GetFilePath(kvm, ofiles[i], name);
+		if (!open_file_proc(p->proc->p_pid, name))
+			return false;
+	}
+
+	return true;
+}
+
+bool EnumerateOpenProcesses(process_proc_t process_proc) {
+	char errbuf[_POSIX2_LINE_MAX];
+	kvm_t* kernel = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
+	if (!kernel)
+		return false;
+
+	int entries = 0;
+	struct kinfo_proc* kinfo = kvm_getprocs(kernel, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &nentries);
+	if (!kinfo)
+		return false;
+
+	for (int i = 0; i < entries; i++)
+		if (!process_proc({kinfo[i].p_pid, kinfo[i].p_comm}))
+			return false;
+
+	return true;
+}
+
+bool EnumerateOpenFiles(std::set<pid_t>& pids, open_file_proc_t open_file_proc) {
+	kvm_t* kernel = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
+	if (!kernel)
+		return false;
+
+	for (const auto& pid : pids) {
+		int cnt;
+		struct kinfo_proc* kinfo = kvm_getprocs(kernel, KERN_PROC_PID, pid, &cnt);
+		if (!kinfo)
+			return false;
+
+		for (int i = 0; i < cnt; i++) {
+			OpenFiles(kernel, kinfo, open_file_proc);
+		}
+	}
+}
+
+}