diff dep/animia/src/util/osx.cc @ 163:44c5e6dd9488

dep/animia/osx: move GetProcessName to util/osx so we can use it in quartz
author Paper <mrpapersonic@gmail.com>
date Sat, 18 Nov 2023 00:47:40 -0500
parents 61b76c7b656a
children 8937fb7f2d66
line wrap: on
line diff
--- a/dep/animia/src/util/osx.cc	Fri Nov 17 16:49:57 2023 -0500
+++ b/dep/animia/src/util/osx.cc	Sat Nov 18 00:47:40 2023 -0500
@@ -1,55 +1,59 @@
-/* A wrapper around multiple LaunchServices things */
-
 #include "animia/util/osx.h"
 
+#ifdef HAVE_COREFOUNDATION
 #include <CoreFoundation/CoreFoundation.h>
-
-#include <iostream>
+#endif
 
 namespace animia::internal::osx::util {
 
-#define RDSymbolNameStr(symbol) (CFSTR("_"#symbol))
+#ifdef HAVE_COREFOUNDATION
+/* All of these LaunchServices things use *internal functions* that are subject
+** to change. Granted, it's not very likely that these will change very much
+** because I'm fairly sure Apple uses them lots in their own internal code.
+*/
 
-static constexpr int kLaunchServicesMagicConstant = -2; // or -1, dunno the difference
-
+/* from RDProcess */
 typedef CFTypeRef (*LSASNCreateWithPidSpec)(CFAllocatorRef, pid_t);
 typedef CFDictionaryRef (*LSCopyApplicationInformationSpec)(int, CFTypeRef, CFArrayRef);
 
 static LSCopyApplicationInformationSpec LSCopyApplicationInformation = nullptr;
 static LSASNCreateWithPidSpec LSASNCreateWithPid = nullptr;
 
-static CFStringRef (kLSDisplayNameKey) = nullptr;
-static CFStringRef (kLSPIDKey) = nullptr;
+/* retrieved from LaunchServicesSPI.h in WebKit */
+static constexpr int kLSDefaultSessionID = -2;
+static const CFStringRef kLaunchServicesBundleID = CFSTR("com.apple.LaunchServices");
 
-static CFStringRef (kLaunchServicesBundleID) = CFSTR("com.apple.LaunchServices");
+/* retrieved dynamically */
+static CFStringRef kLSDisplayNameKey = nullptr;
+static CFStringRef kLSPIDKey = nullptr;
 
-static bool FindLaunchServicesPrivateSymbols() {
+static bool GetLaunchServicesPrivateSymbols() {
 	CFBundleRef launch_services_bundle = CFBundleGetBundleWithIdentifier(kLaunchServicesBundleID);
 	if (!launch_services_bundle)
 		return false;
 
-	LSCopyApplicationInformation = (LSCopyApplicationInformationSpec)CFBundleGetFunctionPointerForName(launch_services_bundle, RDSymbolNameStr(LSCopyApplicationInformation));
+	LSCopyApplicationInformation = (LSCopyApplicationInformationSpec)CFBundleGetFunctionPointerForName(launch_services_bundle, CFSTR("_LSCopyApplicationInformation"));
 	if (!LSCopyApplicationInformation)
 		return false;
 
-	LSASNCreateWithPid = (LSASNCreateWithPidSpec)CFBundleGetFunctionPointerForName(launch_services_bundle, RDSymbolNameStr(LSASNCreateWithPid));
+	LSASNCreateWithPid = (LSASNCreateWithPidSpec)CFBundleGetFunctionPointerForName(launch_services_bundle, CFSTR("_LSASNCreateWithPid"));
 	if (!LSASNCreateWithPid)
 		return false;
 
-	kLSDisplayNameKey = *(CFStringRef*)CFBundleGetDataPointerForName(launch_services_bundle, RDSymbolNameStr(kLSDisplayNameKey));
+	kLSDisplayNameKey = *(CFStringRef*)CFBundleGetDataPointerForName(launch_services_bundle, CFSTR("_kLSDisplayNameKey"));
 	if (!kLSDisplayNameKey)
 		return false;
 
-	kLSPIDKey = *(CFStringRef*)CFBundleGetDataPointerForName(launch_services_bundle, RDSymbolNameStr(kLSPIDKey));
+	kLSPIDKey = *(CFStringRef*)CFBundleGetDataPointerForName(launch_services_bundle, CFSTR("_kLSPIDKey"));
 	if (!kLSPIDKey)
 		return false;
 
 	return true;
 }
 
-bool LaunchServicesGetProcessName(pid_t pid, std::string& result) {
+static bool LaunchServicesGetProcessName(pid_t pid, std::string& result) {
 	if (!LSCopyApplicationInformation || !LSASNCreateWithPid)
-		if (!FindLaunchServicesPrivateSymbols())
+		if (!GetLaunchServicesPrivateSymbols())
 			return false;
 
 	CFTypeRef asn = LSASNCreateWithPid(kCFAllocatorDefault, pid);
@@ -82,5 +86,92 @@
 
 	return true;
 }
+#endif // HAVE_COREFOUNDATION
+
+static bool GetProcessArgs(pid_t pid, std::string& args) {
+	/* sysctl shouldn't touch these, so we define them as const */
+	const int mib[3] = {CTL_KERN, KERN_PROCARGS2, static_cast<int>(pid)};
+	const size_t mib_size = sizeof(mib)/sizeof(*mib);
+
+	/* Get the initial size of the array */
+	size_t size;
+	{
+		int ret = sysctl((int*)mib, mib_size, nullptr, &size, nullptr, 0);
+		if (ret)
+			return false;
+	}
+
+	/* Reserve the space for it in args */
+	args.resize(size);
+
+	/* Get the contents of argc and argv */
+	{
+		int ret = sysctl((int*)mib, mib_size, &args.front(), &size, NULL, 0);
+		if (ret)
+			return false;
+	}
+
+	/* Is the size big enough to hold at least argc? */
+	if (size < sizeof(int))
+		return false;
+
+	args.resize(size);
+}
+
+static bool GetProcessNameFromArgs(pid_t pid, std::string& result) {
+	if (!GetProcessArgs(pid, result))
+		return false;
+
+	/* Get argc using memcpy */
+	int argc;
+	memcpy(&argc, &args.front(), sizeof(argc));
+
+	/* Do we even have argv[0]? */
+	if (argc < 1)
+		return false;
+
+	/* Find the first null character */
+	size_t null_pos = args.find('\0', sizeof(argc));
+	if (null_pos == std::string::npos)
+		return false;
+
+	/* Find the last slash */
+	size_t last_slash = args.rfind('/', null_pos);
+	if (last_slash == std::string::npos)
+		return false;
+
+	/* Return our result */
+	result = args.substr(last_slash + 1, null_pos - last_slash - 1);
+	return true;
+}
+
+static bool GetProcessNameFromKernel(pid_t pid, std::string& result) {
+	result.reserve(2*MAXCOMLEN);
+	if (!proc_name(pid, &result.front(), result.length()))
+		return false;
+
+	result.shrink_to_fit();
+	return true;
+}
+
+static bool GetProcessName(pid_t pid, std::string& result) {
+#ifdef HAVE_COREFOUNDATION
+	if (LaunchServicesGetProcessName(pid, result))
+		return true;
+#endif // HAVE_COREFOUNDATION
+
+	/* Try parsing the arguments, this prevents the process name being
+	   cut off to 2*MAXCOMLEN (32 chars) */
+	if (GetProcessNameFromArgs(pid, result))
+		return true;
+
+	/* Then attempt getting it from the kernel, which results in the
+	   process name being cut to 32 chars (worse, 16 chars if p_name is
+	   unavailable) */
+	if (GetProcessNameFromKernel(pid, result))
+		return true;
+
+	return false;
+}
 
 }