view dep/animia/src/bsd.cpp @ 118:39521c47c7a3

*: another huge megacommit, SORRY The torrents page works a lot better now Added the edit option to the anime list right click menu Vectorized currently playing files Available player and extensions are now loaded at runtime from files in (dotpath)/players.json and (dotpath)/extensions.json These paths are not permanent and will likely be moved to (dotpath)/recognition ... ... ...
author Paper <mrpapersonic@gmail.com>
date Tue, 07 Nov 2023 23:40:54 -0500
parents f5940a575d83
children
line wrap: on
line source

/**
 * bsd.cpp
 *  - provides support for most* versions of BSD
 *  - this also works for OS X :)
 * more technical details: this is essentially a wrapper
 * around the very C-like BSD system functions that are...
 * kind of unnatural to use in modern C++.
 **/
#include "bsd.h"
#include "os.h"
#include <assert.h>
#include <fcntl.h>
#include <iostream>
#include <string>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/user.h>
#include <unordered_map>
#include <vector>
#ifdef __FreeBSD__
#	include <libutil.h>
#elif defined(__APPLE__)
#	include <libproc.h>
#endif

namespace Animia { namespace Unix {

/* this is a cleaned up version of a function from... Apple?
   ...anyway, what it essentially does is gets the size and stuff from
   sysctl() and reserves the space in a vector to store the PIDs */
std::vector<int> get_all_pids() {
	std::vector<int> ret;
	struct kinfo_proc* result = NULL;
	size_t length = 0;
	static const int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};

	/* get appropriate length from sysctl()
	   note: the reason this isn't checked is actually because this will
	   *always* return an error on OS X (or... maybe I'm doing it wrong :) ) */
	sysctl((int*)name, (sizeof(name) / sizeof(*name)) - 1, NULL, &length, NULL, 0);

	result = (struct kinfo_proc*)malloc(length);
	if (result == NULL)
		return std::vector<int>();

	/* actually get our results */
	if (sysctl((int*)name, (sizeof(name) / sizeof(*name)) - 1, result, &length, NULL, 0) == ENOMEM) {
		assert(result != NULL);
		free(result);
		throw std::bad_alloc();
	}

	/* add pids to our vector */
	ret.reserve(length / sizeof(*result));
	for (int i = 0; i < length / sizeof(*result); i++)
		ret.push_back(result[i].kp_proc.p_pid);

	return ret;
}

std::string get_process_name(const int pid) {
	std::string ret;
#ifdef __FreeBSD__
	struct kinfo_proc* proc = kinfo_getproc(pid);
	if (!proc)
		return "";
	ret = proc->ki_comm;
	free(proc);
#elif defined(__APPLE__)
	struct proc_bsdinfo proc;

	int st = proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &proc, PROC_PIDTBSDINFO_SIZE);
	if (st != PROC_PIDTBSDINFO_SIZE)
		return "";
	ret = proc.pbi_comm;
#endif
	return ret;
}

std::vector<std::string> get_open_files(const int pid) {
	/* note: this is OS X only right now. eventually, I'll find a way
	   to do this in FreeBSD, OpenBSD and the like */
	std::vector<std::string> ret;

	if (pid == 0)
		return ret;

	int bufsz = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
	if (bufsz == -1)
		return ret;

	struct proc_fdinfo* info = (struct proc_fdinfo*)malloc(bufsz);
	if (!info)
		return ret;

	proc_pidinfo(pid, PROC_PIDLISTFDS, 0, info, bufsz);

	// iterate over stuff
	ret.reserve(bufsz / sizeof(info[0]));
	for (int i = 0; i < bufsz / sizeof(info[0]); i++) {
		if (info[i].proc_fdtype == PROX_FDTYPE_VNODE) {
			struct vnode_fdinfowithpath vnodeInfo;

			int sz = proc_pidfdinfo(pid, info[i].proc_fd, PROC_PIDFDVNODEPATHINFO, &vnodeInfo, PROC_PIDFDVNODEPATHINFO_SIZE);
			if (sz != PROC_PIDFDVNODEPATHINFO_SIZE)
				continue;

			/* I'm 99.9% sure this is incorrect. We can't pick up QuickTime files with this :(

			   Actually, we can't pick up QuickTime files regardless. WTF? */
			if ((vnodeInfo.pfi.fi_status & O_ACCMODE) == O_WRONLY)
				continue;

			ret.push_back(vnodeInfo.pvip.vip_path);
		}
	}
	return ret;
}

std::vector<std::string> filter_system_files(const std::vector<std::string>& in) {
#ifdef ON_OSX
	std::vector<std::string> ret;
	for (const auto& str : in)
		/* these are some places nobody would ever want to store media files. */
		if (str.find("/Library") && str.find("/System") && str.find("/Applications") &&
			str.find("/dev") && str.find("/private"))
			ret.push_back(str);
	return ret;
#else
	return in;
#endif
}


std::unordered_map<int, std::vector<std::string>> get_all_open_files() {
	std::unordered_map<int, std::vector<std::string>> map;
	std::vector<int> pids = get_all_pids();
	for (int i : pids) {
		map[i] = get_open_files(i);
	}
	return map;
}

} // namespace Unix
} // namespace Animia