From: Andrej Shadura <andrew.shadura@collabora.co.uk>
Date: Thu, 7 May 2020 17:23:32 +0200
Subject: [PATCH 3/3] Implement GNU/Hurd and BSD support inspired by the LLVM
 implementation

Signed-off-by: Andrej Shadura <andrew.shadura@collabora.co.uk>
---
 src/fileutil.cc | 35 +++++++++++++++++++++++++++++++----
 1 file changed, 31 insertions(+), 4 deletions(-)

diff --git a/src/fileutil.cc b/src/fileutil.cc
index 14ee68a..c36acff 100644
--- a/src/fileutil.cc
+++ b/src/fileutil.cc
@@ -29,6 +29,9 @@
 #if defined(__APPLE__)
 #include <mach-o/dyld.h>
 #endif
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 1300057)
+#include <sys/auxv.h>
+#endif
 
 #include <unordered_map>
 
@@ -179,14 +182,38 @@ int RunCommand(const string& shell,
 }
 
 std::string GetExecutablePath() {
-#if defined(__linux__)
+#if defined(__linux__) || defined(__GNU__) || defined(__FreeBSD_kernel__) || \
+    defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||   \
+    defined(__minix) || defined(__DragonFly__) || defined(_AIX)
   char mypath[PATH_MAX + 1];
-  ssize_t l = readlink("/proc/self/exe", mypath, PATH_MAX);
+
+// On FreeBSD if the exec path specified in ELF auxiliary vectors is
+// preferred, if available.  /proc/curproc/file and the KERN_PROC_PATHNAME
+// sysctl may not return the desired path if there are multiple hardlinks
+// to the file.
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 1300057)
+  if (elf_aux_info(AT_EXECPATH, mypath, sizeof(mypath)) == 0) {
+    return {mypath};
+  }
+#endif
+
+#if defined(__linux__) || defined(__GNU__)
+#define PROC_CUR_EXE "/proc/self/exe"
+#else
+#define PROC_CUR_EXE "/proc/curproc/file"
+#endif
+  ssize_t l = readlink(PROC_CUR_EXE, mypath, PATH_MAX);
   if (l < 0) {
-    PERROR("readlink for /proc/self/exe");
+    PERROR("readlink for " PROC_CUR_EXE);
   }
   mypath[l] = '\0';
-  return {mypath};
+
+  char real_path[PATH_MAX + 1];
+  char *ret = realpath(mypath, real_path);
+  if (ret == NULL) {
+    PERROR("realpath failed");
+  }
+  return {real_path};
 #elif defined(__APPLE__)
   char mypath[PATH_MAX + 1];
   uint32_t size = PATH_MAX;
