You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2018/10/13 19:12:32 UTC

svn commit: r1843774 - /subversion/trunk/subversion/libsvn_subr/sysinfo.c

Author: brane
Date: Sat Oct 13 19:12:32 2018
New Revision: 1843774

URL: http://svn.apache.org/viewvc?rev=1843774&view=rev
Log:
Make 'svn --version --verbose' list the loaded shared libraries on Linux.

* subversion/libsvn_subr/sysinfo.c: Include sys/types.h and unistd.h.
  (linux_shared_libs): New; reads and parses /proc/[pid]/maps.
  (stringbuf_first_whitespace, stringbuf_skip_whitespace_field): New.

Modified:
    subversion/trunk/subversion/libsvn_subr/sysinfo.c

Modified: subversion/trunk/subversion/libsvn_subr/sysinfo.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/sysinfo.c?rev=1843774&r1=1843773&r2=1843774&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/sysinfo.c (original)
+++ subversion/trunk/subversion/libsvn_subr/sysinfo.c Sat Oct 13 19:12:32 2018
@@ -51,6 +51,14 @@
 #include "sysinfo.h"
 #include "svn_private_config.h"
 
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
 #if HAVE_SYS_UTSNAME_H
 #include <sys/utsname.h>
 #endif
@@ -92,6 +100,7 @@ static const apr_array_header_t *macos_s
 
 #if __linux__
 static const char *linux_release_name(apr_pool_t *pool);
+static const apr_array_header_t *linux_shared_libs(apr_pool_t *pool);
 #endif
 
 const char *
@@ -187,6 +196,8 @@ svn_sysinfo__loaded_libs(apr_pool_t *poo
   return win32_shared_libs(pool);
 #elif defined(SVN_HAVE_MACHO_ITERATE)
   return macos_shared_libs(pool);
+#elif __linux__
+  return linux_shared_libs(pool);
 #else
   return NULL;
 #endif
@@ -300,6 +311,31 @@ release_name_from_uname(apr_pool_t *pool
 
 
 #if __linux__
+/* Find the first whitespace character in a stringbuf.
+   Analogous to svn_stringbuf_first_non_whitespace. */
+static apr_size_t
+stringbuf_first_whitespace(const svn_stringbuf_t *str)
+{
+  apr_size_t i;
+  for (i = 0; i < str->len; ++i)
+    {
+      if (svn_ctype_isspace(str->data[i]))
+        return i;
+    }
+  return str->len;
+}
+
+/* Skip a whitespace-delimited field in a stringbuf. */
+static void
+stringbuf_skip_whitespace_field(svn_stringbuf_t *str)
+{
+  apr_size_t i;
+  i = stringbuf_first_whitespace(str);
+  svn_stringbuf_leftchop(str, i);
+  i = svn_stringbuf_first_non_whitespace(str);
+  svn_stringbuf_leftchop(str, i);
+}
+
 /* Split a stringbuf into a key/value pair.
    Return the key, leaving the stripped value in the stringbuf. */
 static const char *
@@ -635,6 +671,78 @@ linux_release_name(apr_pool_t *pool)
 
   return apr_psprintf(pool, "%s [%s]", release_name, uname_release);
 }
+
+static const apr_array_header_t *
+linux_shared_libs(apr_pool_t *pool)
+{
+  /* Read the list of loaded modules from /proc/[pid]/maps
+    The format is described here:
+        http://man7.org/linux/man-pages/man5/proc.5.html
+  */
+
+  const char *maps = apr_psprintf(pool, "/proc/%ld/maps", (long)getpid());
+  apr_array_header_t *result = NULL;
+  svn_boolean_t eof = FALSE;
+  svn_stream_t *stream;
+  svn_error_t *err;
+
+  err = svn_stream_open_readonly(&stream, maps, pool, pool);
+  if (err)
+    {
+      svn_error_clear(err);
+      return NULL;
+    }
+
+  /* Each line in /proc/<pid>/maps consists of whitespace-delimited fields. */
+  while (!eof)
+    {
+      svn_version_ext_loaded_lib_t *lib;
+      svn_stringbuf_t *line;
+      svn_node_kind_t kind;
+
+      err = svn_stream_readline(stream, &line, "\n", &eof, pool);
+      if (err)
+        {
+          svn_error_clear(err);
+          return NULL;
+        }
+
+      /* Find the permissions of the mapped region. */
+      stringbuf_skip_whitespace_field(line); /* skip address */
+
+      /* Permissions: The memory region must be executable. */
+      if (line->len < 4 || line->data[2] != 'x')
+        continue;
+
+      stringbuf_skip_whitespace_field(line); /* skip perms */
+      stringbuf_skip_whitespace_field(line); /* skip offset */
+      stringbuf_skip_whitespace_field(line); /* skip device */
+
+      /* I-Node: If it is 0, there is no file associated with the region. */
+      if (line->len < 2
+          || (line->data[0] == '0' && svn_ctype_isspace(line->data[1])))
+        continue;
+
+      stringbuf_skip_whitespace_field(line); /* skip inode */
+
+      /* Check that the file exists. */
+      err = svn_io_check_path(line->data, &kind, pool);
+      svn_error_clear(err);
+      if (!err && kind == svn_node_file)
+        {
+          if (!result)
+            {
+              result = apr_array_make(pool, 32, sizeof(*lib));
+            }
+          lib = &APR_ARRAY_PUSH(result, svn_version_ext_loaded_lib_t);
+          lib->name = line->data;
+          lib->version = NULL;
+        }
+    }
+
+  svn_error_clear(svn_stream_close(stream));
+  return result;
+}
 #endif /* __linux__ */