From 8f760cf88e060300ae04cc23715a442171c31795 Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Thu, 22 Oct 2020 15:52:57 +0100
Subject: [PATCH] utils: Add the ability to find our prefix when statically
 linked

Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 steam-runtime-tools/utils.c | 30 +++++++++++++++++--
 tests/find-myself.c         | 59 +++++++++++++++++++++++++++++++++++++
 tests/meson.build           | 25 ++++++++++++++++
 3 files changed, 112 insertions(+), 2 deletions(-)
 create mode 100644 tests/find-myself.c

diff --git a/steam-runtime-tools/utils.c b/steam-runtime-tools/utils.c
index 656d36e14..a52f07947 100644
--- a/steam-runtime-tools/utils.c
+++ b/steam-runtime-tools/utils.c
@@ -154,6 +154,8 @@ _srt_check_not_setuid (void)
   "/lib/" _SRT_MULTIARCH
 #define RELOCATABLE_PKGLIBDIR \
   MULTIARCH_LIBDIR "/steam-runtime-tools-" _SRT_API_MAJOR
+#define PKGLIBEXECDIR \
+  "/libexec/steam-runtime-tools-" _SRT_API_MAJOR
 
 /**
  * _srt_process_timeout_wait_status:
@@ -234,17 +236,41 @@ _srt_find_myself (const char **helpers_path_out,
       goto out;
     }
 
-  g_debug ("Found _srt_find_myself() in %s", map->l_name);
-  dir = g_path_get_dirname (map->l_name);
+  if (map->l_name == NULL || map->l_name[0] == '\0')
+    {
+      char *exe = realpath ("/proc/self/exe", NULL);
+
+      if (exe == NULL)
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "Unable to locate main executable");
+          goto out;
+        }
+
+      g_debug ("Found _srt_find_myself() in main executable %s", exe);
+      dir = g_path_get_dirname (exe);
+      free (exe);
+    }
+  else
+    {
+      g_debug ("Found _srt_find_myself() in %s", map->l_name);
+      dir = g_path_get_dirname (map->l_name);
+    }
 
   if (g_str_has_suffix (dir, RELOCATABLE_PKGLIBDIR))
     dir[strlen (dir) - strlen (RELOCATABLE_PKGLIBDIR)] = '\0';
   else if (g_str_has_suffix (dir, MULTIARCH_LIBDIR))
     dir[strlen (dir) - strlen (MULTIARCH_LIBDIR)] = '\0';
+  else if (g_str_has_suffix (dir, PKGLIBEXECDIR))
+    dir[strlen (dir) - strlen (PKGLIBEXECDIR)] = '\0';
+  else if (g_str_has_suffix (dir, "/libexec"))
+    dir[strlen (dir) - strlen ("/libexec")] = '\0';
   else if (g_str_has_suffix (dir, "/lib64"))
     dir[strlen (dir) - strlen ("/lib64")] = '\0';
   else if (g_str_has_suffix (dir, "/lib"))
     dir[strlen (dir) - strlen ("/lib")] = '\0';
+  else if (g_str_has_suffix (dir, "/bin"))
+    dir[strlen (dir) - strlen ("/bin")] = '\0';
 
   /* If the library was found in /lib/MULTIARCH, /lib64 or /lib on a
    * merged-/usr system, assume --prefix=/usr (/libexec doesn't
diff --git a/tests/find-myself.c b/tests/find-myself.c
new file mode 100644
index 000000000..bcab0fda2
--- /dev/null
+++ b/tests/find-myself.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright © 2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <steam-runtime-tools/steam-runtime-tools.h>
+
+#include <glib.h>
+
+#include "steam-runtime-tools/glib-backports-internal.h"
+#include "steam-runtime-tools/utils-internal.h"
+
+/*
+ * Usage: copy the compiled executable into some random prefix and
+ * run it.
+ *
+ * If you put it in /prefix/bin, /prefix/libexec or
+ * /prefix/libexec/steam-runtime-tools-0, it should say that its prefix
+ * is /prefix.
+ */
+
+int
+main (int argc,
+      char **argv)
+{
+  g_autoptr(GError) error = NULL;
+  const char *helpers = NULL;
+  const char *prefix = _srt_find_myself (&helpers, &error);
+
+  if (prefix == NULL)
+    {
+      g_warning ("Unable to find myself: %s", error->message);
+      return 1;
+    }
+
+  g_print ("Prefix: %s\n", prefix);
+  g_print ("Looking for helpers in: %s\n", helpers);
+  return 0;
+}
diff --git a/tests/meson.build b/tests/meson.build
index 3bf5760d1..bc04ff996 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -187,6 +187,31 @@ foreach test_info : tests
   endif
 endforeach
 
+# Helpers and manual tests statically linked to libsteam-r-t
+foreach helper : [
+  'find-myself',
+]
+  executable(
+    helper,
+    files(helper + '.c'),
+    c_args : [
+      '-D_SRT_MULTIARCH="' + multiarch + '"',
+    ],
+    dependencies : [
+      glib,
+      gobject,
+      gio_unix,
+      json_glib,
+      libglnx_dep,
+      libsteamrt_static_dep,
+      test_utils_static_libsteamrt_dep,
+    ],
+    include_directories : project_include_dirs,
+    install : get_option('installed_tests'),
+    install_dir : tests_dir,
+  )
+endforeach
+
 # A mock implementation of check-locale that offers lots of locales
 executable(
   'mock-check-locale',
-- 
GitLab