[[[
svn --version --verbose: Support /etc/os-release, the systemd "what distro
am I running" API.

* subversion/libsvn_subr/sysinfo.c
  (linux_release_name): Try /etc/os-release if /usr/bin/lsb_release fails.
  (systemd_release): New helper for linux_release_name().
  (remove_shell_quoting): New helper function.
]]]

--- subversion/libsvn_subr/sysinfo.c
+++ subversion/libsvn_subr/sysinfo.c
@@ -410,6 +410,78 @@ lsb_release(apr_pool_t *pool)
   return NULL;
 }
 
+/* Attempt to strip double quotes from a string.
+ *
+ * The string considered is (STR->DATA + OFFSET).  If it starts
+ * and ends with double quotes, and has no escape sequences, return
+ * the string delimited by the double quotes.  Otherwise, return
+ * the original string verbatim.
+ */
+static const char *
+remove_shell_quoting(svn_stringbuf_t *buf,
+                     int offset,
+                     apr_pool_t *result_pool)
+{
+  const char *str = buf->data + offset;
+  const char *second_double_quote;
+
+  /* Are there exactly two double quotes, at the first and last positions? */
+  if (str[0] == '"' && (second_double_quote = strchr(str+1, '"'))
+      && second_double_quote[1] == '\0')
+    /* Are there any backslashes? */
+    if (!strchr(str, '\\'))
+      /* Return whatever is between the quotes. */
+      return apr_pstrndup(result_pool, str+1, second_double_quote - (str+1));
+
+  /* There are no double quotes, or there is a backslash and we punted.
+   * Either way, we'll return the string verbatim. */
+  return str;
+}
+
+/* Read /etc/os-release, as documented here:
+ * http://www.freedesktop.org/software/systemd/man/os-release.html
+ */
+static const char *
+systemd_release(apr_pool_t *pool)
+{
+  svn_error_t *err;
+  svn_stream_t *stream;
+
+  err = svn_stream_open_readonly(&stream, "/etc/os-release", pool, pool);
+  if (err && APR_STATUS_IS_ENOENT(err->apr_err))
+    {
+      svn_error_clear(err);
+      err = svn_stream_open_readonly(&stream, "/usr/lib/os-release", pool,
+                                     pool);
+    }
+  if (err)
+    {
+      svn_error_clear(err);
+      return NULL;
+    }
+
+  while (TRUE)
+    {
+      svn_stringbuf_t *line;
+      svn_boolean_t eof;
+
+      err = svn_stream_readline(stream, &line, "\n", &eof, pool);
+      if (err)
+        {
+          svn_error_clear(err);
+          return NULL;
+        }
+
+      if (!strncmp(line->data, "PRETTY_NAME=", 12))
+        return remove_shell_quoting(line, 12, pool);
+
+      if (eof)
+        break;
+    }
+
+  return NULL;
+}
+
 /* Read the whole contents of a file. */
 static svn_stringbuf_t *
 read_file_contents(const char *filename, apr_pool_t *pool)
@@ -527,6 +599,10 @@ linux_release_name(apr_pool_t *pool)
      Covers, for example, Debian, Ubuntu and SuSE.  */
   const char *release_name = lsb_release(pool);
 
+  /* Try the systemd way (covers Arch). */
+  if (!release_name)
+    release_name = systemd_release(pool);
+
   /* Try RHEL/Fedora/CentOS */
   if (!release_name)
     release_name = redhat_release(pool);

Reply via email to