This set of patches improve the platform specific code in progreloc.c.
Most BSD systems and Solaris nowadays have a way to retrieve the name
of the current executable, in a way similar to /proc/self/exe on Linux.


2019-02-19  Bruno Haible  <[email protected]>

        progreloc: Simplify code for Android.
        * lib/progreloc.c (executable_fd): Don't define on Android.
        (maybe_executable, find_executable): Don't use executable_fd on Android.

2019-02-19  Bruno Haible  <[email protected]>

        progreloc: Speed up executable lookup on various platforms.
        * lib/progreloc.c: Include <errno.h>.
        (safe_read, full_read): New functions.
        (find_executable): On GNU/kFreeBSD, FreeBSD, DragonFly, NetBSD, Solaris,
        prefer the information from the /proc file system to a PATH search.

>From cd46bf0ca5083162f3ac564ebbdeb6371085df45 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 19 Feb 2019 21:38:53 +0100
Subject: [PATCH 1/2] progreloc: Simplify code for Android.

* lib/progreloc.c (executable_fd): Don't define on Android.
(maybe_executable, find_executable): Don't use executable_fd on Android.
---
 ChangeLog       |  6 ++++++
 lib/progreloc.c | 15 ++++++++++++---
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 64e9acf..9cb7ac8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2019-02-19  Bruno Haible  <[email protected]>
+
+	progreloc: Simplify code for Android.
+	* lib/progreloc.c (executable_fd): Don't define on Android.
+	(maybe_executable, find_executable): Don't use executable_fd on Android.
+
 2019-02-15  Bruno Haible  <[email protected]>
 
 	gnulib-tool: Support --import with just a few tests, not --with-tests.
diff --git a/lib/progreloc.c b/lib/progreloc.c
index 1c4db0c..0cd335e 100644
--- a/lib/progreloc.c
+++ b/lib/progreloc.c
@@ -102,7 +102,7 @@ extern char * canonicalize_file_name (const char *name);
 
 #if ENABLE_RELOCATABLE
 
-#if defined __linux__ || defined __ANDROID__ || defined __CYGWIN__
+#if defined __linux__ || defined __CYGWIN__
 /* File descriptor of the executable.
    (Only used to verify that we find the correct executable.)  */
 static int executable_fd = -1;
@@ -118,7 +118,7 @@ maybe_executable (const char *filename)
     return false;
 #endif
 
-#if defined __linux__ || defined __ANDROID__ || defined __CYGWIN__
+#if defined __linux__ || defined __CYGWIN__
   if (executable_fd >= 0)
     {
       /* If we already have an executable_fd, check that filename points to
@@ -180,7 +180,7 @@ find_executable (const char *argv0)
 
   return xstrdup (location);
 #else /* Unix */
-# if defined __linux__ || defined __ANDROID__
+# if defined __linux__
   /* The executable is accessible as /proc/<pid>/exe.  In newer Linux
      versions, also as /proc/self/exe.  Linux >= 2.1 provides a symlink
      to the true pathname; older Linux versions give only device and ino,
@@ -205,6 +205,15 @@ find_executable (const char *argv0)
     }
   }
 # endif
+# if defined __ANDROID__
+  {
+    char *link;
+
+    link = xreadlink ("/proc/self/exe");
+    if (link != NULL)
+      return link;
+  }
+# endif
 # ifdef __CYGWIN__
   /* The executable is accessible as /proc/<pid>/exe, at least in
      Cygwin >= 1.5.  */
-- 
2.7.4

>From 18f4d4133eae7d8ac228ed2986748c52825f3d0e Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 19 Feb 2019 21:42:54 +0100
Subject: [PATCH 2/2] progreloc: Speed up executable lookup on various
 platforms.

* lib/progreloc.c: Include <errno.h>.
(safe_read, full_read): New functions.
(find_executable): On GNU/kFreeBSD, FreeBSD, DragonFly, NetBSD, Solaris,
prefer the information from the /proc file system to a PATH search.
---
 ChangeLog       |  8 +++++
 lib/progreloc.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 100 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 9cb7ac8..949dbae 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2019-02-19  Bruno Haible  <[email protected]>
 
+	progreloc: Speed up executable lookup on various platforms.
+	* lib/progreloc.c: Include <errno.h>.
+	(safe_read, full_read): New functions.
+	(find_executable): On GNU/kFreeBSD, FreeBSD, DragonFly, NetBSD, Solaris,
+	prefer the information from the /proc file system to a PATH search.
+
+2019-02-19  Bruno Haible  <[email protected]>
+
 	progreloc: Simplify code for Android.
 	* lib/progreloc.c (executable_fd): Don't define on Android.
 	(maybe_executable, find_executable): Don't use executable_fd on Android.
diff --git a/lib/progreloc.c b/lib/progreloc.c
index 0cd335e..b3eb503 100644
--- a/lib/progreloc.c
+++ b/lib/progreloc.c
@@ -22,6 +22,7 @@
 /* Specification.  */
 #include "progname.h"
 
+#include <errno.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -102,6 +103,48 @@ extern char * canonicalize_file_name (const char *name);
 
 #if ENABLE_RELOCATABLE
 
+#ifdef __sun
+
+/* Helper function, from gnulib module 'safe-read'.  */
+static size_t
+safe_read (int fd, void *buf, size_t count)
+{
+  for (;;)
+    {
+      ssize_t result = read (fd, buf, count);
+
+      if (0 <= result || errno != EINTR)
+        return result;
+    }
+}
+
+/* Helper function, from gnulib module 'full-read'.  */
+static size_t
+full_read (int fd, void *buf, size_t count)
+{
+  size_t total = 0;
+  const char *ptr = (const char *) buf;
+
+  while (count > 0)
+    {
+      size_t n = safe_read (fd, ptr, count);
+      if (n == (size_t) -1)
+        break;
+      if (n == 0)
+        {
+          errno = 0;
+          break;
+        }
+      total += n;
+      ptr += n;
+      count -= n;
+    }
+
+  return total;
+}
+
+#endif
+
 #if defined __linux__ || defined __CYGWIN__
 /* File descriptor of the executable.
    (Only used to verify that we find the correct executable.)  */
@@ -205,7 +248,9 @@ find_executable (const char *argv0)
     }
   }
 # endif
-# if defined __ANDROID__
+# if defined __ANDROID__ || defined __FreeBSD_kernel__
+  /* On Android and GNU/kFreeBSD, the executable is accessible as
+     /proc/<pid>/exe and /proc/self/exe.  */
   {
     char *link;
 
@@ -214,7 +259,52 @@ find_executable (const char *argv0)
       return link;
   }
 # endif
-# ifdef __CYGWIN__
+# if defined __FreeBSD__ || defined __DragonFly__
+  /* In FreeBSD >= 5.0, the executable is accessible as /proc/<pid>/file and
+     /proc/curproc/file.  */
+  {
+    char *link;
+
+    link = xreadlink ("/proc/curproc/file");
+    if (link != NULL)
+      {
+        if (strcmp (link, "unknown") != 0)
+          return link;
+        free (link);
+      }
+  }
+# endif
+# if defined __NetBSD__
+  /* In NetBSD >= 4.0, the executable is accessible as /proc/<pid>/exe and
+     /proc/curproc/exe.  */
+  {
+    char *link;
+
+    link = xreadlink ("/proc/curproc/exe");
+    if (link != NULL)
+      return link;
+  }
+# endif
+# if defined __sun
+  /* On Solaris >= 11.4, /proc/<pid>/execname and /proc/self/execname contains
+     the name of the executable, either as an absolute file name or relative to
+     the current directory.  */
+  {
+    char namebuf[4096];
+    int fd = open ("/proc/self/execname", O_RDONLY, 0);
+    if (fd >= 0)
+      {
+        size_t len = full_read (fd, namebuf, sizeof (namebuf));
+        close (fd);
+        if (len > 0 && len < sizeof (namebuf))
+          {
+            namebuf[len] = '\0';
+            return canonicalize_file_name (namebuf);
+          }
+      }
+  }
+# endif
+# if defined __CYGWIN__
   /* The executable is accessible as /proc/<pid>/exe, at least in
      Cygwin >= 1.5.  */
   {
-- 
2.7.4

Reply via email to