From 4ff6839a8b32e800dd56c624c296a61e367ab867 Mon Sep 17 00:00:00 2001
From: Michael Chiu <m_chiu@apple.com>
Date: Fri, 10 Jan 2025 00:28:05 -0800
Subject: [PATCH] freebsd: lookup binary exec path via sysctl

---
 Sources/CoreFoundation/CFPlatform.c | 30 +++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/Sources/CoreFoundation/CFPlatform.c b/Sources/CoreFoundation/CFPlatform.c
index 186a6e8970..776dc4c8eb 100644
--- a/Sources/CoreFoundation/CFPlatform.c
+++ b/Sources/CoreFoundation/CFPlatform.c
@@ -136,6 +136,10 @@ static inline void _CFSetProgramNameFromPath(const char *path) {
 #include <sys/exec.h>
 #endif
 
+#if TARGET_OS_BSD && defined(__FreeBSD__)
+#include <sys/sysctl.h>
+#endif
+
 const char *_CFProcessPath(void) {
     if (__CFProcessPath) return __CFProcessPath;
 
@@ -230,6 +234,29 @@ const char *_CFProcessPath(void) {
         char *res = realpath(ps->ps_argvstr[0], NULL);
         argv0 = res? res: strdup(ps->ps_argvstr[0]);
     }
+#elif defined(__FreeBSD__)
+    // see sysctl(3), pid == -1 means current process
+    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
+    int sysctl_ret = 0;
+    size_t len = PATH_MAX + 1;
+    argv0 = calloc(len, 1);
+
+    sysctl_ret = sysctl(mib, 4, argv0, &len, NULL, 0);
+
+    // in case for whatever reason the path is > PATH_MAX
+    if (sysctl_ret == -1 && errno == ENOMEM) {
+        // get size needed
+        sysctl_ret = sysctl(mib, 4, NULL, &len, NULL, 0);
+        if (sysctl_ret != -1) {
+            argv0 = realloc(argv0, len);
+            sysctl_ret = sysctl(mib, 4, argv0, &len, NULL, 0);
+        }
+    }
+
+    if (sysctl_ret == -1) {
+        free(argv0);
+        argv0 = NULL;
+    }
 #endif
 
     if (!__CFProcessIsRestricted() && argv0 && argv0[0] == '/') {
@@ -908,6 +935,9 @@ static void __CFTSDFinalize(void *arg) {
 
     if (!arg || arg == CF_TSD_BAD_PTR) {
         // We've already been destroyed. The call above set the bad pointer again. Now we just return.
+#if defined(__FreeBSD__)
+        __CFTSDSetSpecific(NULL);
+#endif
         return;
     }