diff --git a/bin/system-info.c b/bin/system-info.c
index b220516be40399169e4a752388ca39889eafff9a..642cc84da9fe5319c45dab9d9b36948a0e79c8f4 100644
--- a/bin/system-info.c
+++ b/bin/system-info.c
@@ -190,6 +190,55 @@ jsonify_library_issues (JsonBuilder *builder,
     json_builder_add_string_value (builder, "unknown-expectations");
 }
 
+static void
+jsonify_steam_issues (JsonBuilder *builder,
+                      SrtSteamIssues issues)
+{
+  if ((issues & SRT_STEAM_ISSUES_INTERNAL_ERROR) != 0)
+    json_builder_add_string_value (builder, "internal-error");
+
+  if ((issues & SRT_STEAM_ISSUES_CANNOT_FIND) != 0)
+    json_builder_add_string_value (builder, "cannot-find");
+
+  if ((issues & SRT_STEAM_ISSUES_DOT_STEAM_STEAM_NOT_SYMLINK) != 0)
+    json_builder_add_string_value (builder, "dot-steam-steam-not-symlink");
+}
+
+static void
+jsonify_runtime_issues (JsonBuilder *builder,
+                        SrtRuntimeIssues issues)
+{
+  if ((issues & SRT_RUNTIME_ISSUES_INTERNAL_ERROR) != 0)
+    json_builder_add_string_value (builder, "internal-error");
+
+  if ((issues & SRT_RUNTIME_ISSUES_DISABLED) != 0)
+    json_builder_add_string_value (builder, "disabled");
+
+  if ((issues & SRT_RUNTIME_ISSUES_NOT_RUNTIME) != 0)
+    json_builder_add_string_value (builder, "not-runtime");
+
+  if ((issues & SRT_RUNTIME_ISSUES_UNOFFICIAL) != 0)
+    json_builder_add_string_value (builder, "unofficial");
+
+  if ((issues & SRT_RUNTIME_ISSUES_UNEXPECTED_LOCATION) != 0)
+    json_builder_add_string_value (builder, "unexpected-location");
+
+  if ((issues & SRT_RUNTIME_ISSUES_UNEXPECTED_VERSION) != 0)
+    json_builder_add_string_value (builder, "unexpected-version");
+
+  if ((issues & SRT_RUNTIME_ISSUES_NOT_IN_LD_PATH) != 0)
+    json_builder_add_string_value (builder, "not-in-ld-path");
+
+  if ((issues & SRT_RUNTIME_ISSUES_NOT_IN_PATH) != 0)
+    json_builder_add_string_value (builder, "not-in-path");
+
+  if ((issues & SRT_RUNTIME_ISSUES_NOT_IN_ENVIRONMENT) != 0)
+    json_builder_add_string_value (builder, "not-in-environment");
+
+  if ((issues & SRT_RUNTIME_ISSUES_NOT_USING_NEWER_HOST_LIBRARIES) != 0)
+    json_builder_add_string_value (builder, "not-using-newer-host-libraries");
+}
+
 static void
 print_libraries_details (JsonBuilder *builder,
                          GList *libraries,
@@ -251,13 +300,18 @@ main (int argc,
   FILE *original_stdout = NULL;
   GError *error = NULL;
   SrtSystemInfo *info;
-  SrtLibraryIssues issues = SRT_LIBRARY_ISSUES_NONE;
+  SrtLibraryIssues library_issues = SRT_LIBRARY_ISSUES_NONE;
+  SrtSteamIssues steam_issues = SRT_STEAM_ISSUES_NONE;
+  SrtRuntimeIssues runtime_issues = SRT_RUNTIME_ISSUES_NONE;
   char *expectations = NULL;
   gboolean verbose = FALSE;
   JsonBuilder *builder;
   JsonGenerator *generator;
   gboolean can_run = FALSE;
   gchar *json_output;
+  gchar *version = NULL;
+  gchar *inst_path = NULL;
+  gchar *rt_path = NULL;
   int opt;
   static const char * const multiarch_tuples[] = { SRT_ABI_I386, SRT_ABI_X86_64 };
 
@@ -306,6 +360,33 @@ main (int argc,
   json_builder_set_member_name (builder, "can-write-uinput");
   json_builder_add_boolean_value (builder, srt_system_info_can_write_to_uinput (info));
 
+  json_builder_set_member_name (builder, "steam-installation");
+  json_builder_begin_object (builder);
+  json_builder_set_member_name (builder, "path");
+  inst_path = srt_system_info_dup_steam_installation_path (info);
+  json_builder_add_string_value (builder, inst_path);
+  json_builder_set_member_name (builder, "issues");
+  json_builder_begin_array (builder);
+  steam_issues = srt_system_info_get_steam_issues (info);
+  jsonify_steam_issues (builder, steam_issues);
+  json_builder_end_array (builder);
+  json_builder_end_object (builder);
+
+  json_builder_set_member_name (builder, "runtime");
+  json_builder_begin_object (builder);
+  json_builder_set_member_name (builder, "path");
+  rt_path = srt_system_info_dup_runtime_path (info);
+  json_builder_add_string_value (builder, rt_path);
+  json_builder_set_member_name (builder, "version");
+  version = srt_system_info_dup_runtime_version (info);
+  json_builder_add_string_value (builder, version);
+  json_builder_set_member_name (builder, "issues");
+  json_builder_begin_array (builder);
+  runtime_issues = srt_system_info_get_runtime_issues (info);
+  jsonify_runtime_issues (builder, runtime_issues);
+  json_builder_end_array (builder);
+  json_builder_end_object (builder);
+
   json_builder_set_member_name (builder, "architectures");
   json_builder_begin_object (builder);
 
@@ -323,14 +404,14 @@ main (int argc,
         {
           json_builder_set_member_name (builder, "library-issues-summary");
           json_builder_begin_array (builder);
-          issues = srt_system_info_check_libraries (info,
-                                                    multiarch_tuples[i],
-                                                    &libraries);
-          jsonify_library_issues (builder, issues);
+          library_issues = srt_system_info_check_libraries (info,
+                                                            multiarch_tuples[i],
+                                                            &libraries);
+          jsonify_library_issues (builder, library_issues);
           json_builder_end_array (builder);
         }
 
-      if (libraries != NULL && (issues != SRT_LIBRARY_ISSUES_NONE || verbose))
+      if (libraries != NULL && (library_issues != SRT_LIBRARY_ISSUES_NONE || verbose))
           print_libraries_details (builder, libraries, verbose);
 
       json_builder_end_object (builder);
@@ -360,6 +441,9 @@ main (int argc,
   json_node_free (root);
   g_object_unref (builder);
   g_object_unref (info);
+  g_free (rt_path);
+  g_free (inst_path);
+  g_free (version);
 
   return 0;
 }
diff --git a/docs/reference/steam-runtime-tools.xml b/docs/reference/steam-runtime-tools.xml
index 1eebb3f58343ae5973202ffd549c5248e2ff644b..c9038ed68fd40d39492ccd40f8668c1831ccf9ef 100644
--- a/docs/reference/steam-runtime-tools.xml
+++ b/docs/reference/steam-runtime-tools.xml
@@ -20,6 +20,8 @@
     <title>Specific system information</title>
     <xi:include href="xml/architecture.xml"/>
     <xi:include href="xml/library.xml"/>
+    <xi:include href="xml/runtime.xml"/>
+    <xi:include href="xml/steam.xml"/>
   </chapter>
 
   <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
diff --git a/steam-runtime-tools/meson.build b/steam-runtime-tools/meson.build
index 5d3d0a0dccc5873c31f09f7652067e18b79537e6..852b880db65d1999b002e0c03d6ccc58675eb1c0 100644
--- a/steam-runtime-tools/meson.build
+++ b/steam-runtime-tools/meson.build
@@ -26,6 +26,10 @@ libsteamrt_sources = [
     'architecture.c',
     'library-internal.h',
     'library.c',
+    'runtime-internal.h',
+    'runtime.c',
+    'steam-internal.h',
+    'steam.c',
     'system-info.c',
     'utils-internal.h',
     'utils.c',
@@ -34,7 +38,9 @@ libsteamrt_sources = [
 libsteamrt_public_headers = [
     'architecture.h',
     'library.h',
+    'runtime.h',
     'steam-runtime-tools.h',
+    'steam.h',
     'system-info.h',
 ]
 
diff --git a/steam-runtime-tools/runtime-internal.h b/steam-runtime-tools/runtime-internal.h
new file mode 100644
index 0000000000000000000000000000000000000000..d7980641986ef1b1b166c981d30d423e9d4f4760
--- /dev/null
+++ b/steam-runtime-tools/runtime-internal.h
@@ -0,0 +1,39 @@
+/*<private_header>*/
+/*
+ * Copyright © 2019 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.
+ */
+
+#pragma once
+
+#include "steam-runtime-tools/runtime.h"
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_GNUC_INTERNAL
+SrtRuntimeIssues _srt_runtime_check (const char *bin32,
+                                     const char *expected_version,
+                                     const GStrv custom_environ,
+                                     gchar **version_out,
+                                     gchar **path_out);
diff --git a/steam-runtime-tools/runtime.c b/steam-runtime-tools/runtime.c
new file mode 100644
index 0000000000000000000000000000000000000000..314b870c35848e68437dc20aee3eb47a61f386e5
--- /dev/null
+++ b/steam-runtime-tools/runtime.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright © 2019 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/runtime.h"
+#include "steam-runtime-tools/runtime-internal.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <glib/gstdio.h>
+
+#include "steam-runtime-tools/glib-compat.h"
+
+/**
+* SECTION:runtime
+* @title: LD_LIBRARY_PATH-based Steam Runtime
+* @short_description: Information about the Steam Runtime
+* @include: steam-runtime-tools/steam-runtime-tools.h
+*
+* #SrtRuntimeIssues represents problems encountered with the Steam
+* Runtime.
+*/
+
+static void
+should_be_executable (SrtRuntimeIssues *issues,
+                      const char *path,
+                      const char *filename)
+{
+  gchar *full = g_build_filename (path, filename, NULL);
+
+  if (!g_file_test (full, G_FILE_TEST_IS_EXECUTABLE))
+    {
+      g_debug ("%s is not executable", full);
+      *issues |= SRT_RUNTIME_ISSUES_NOT_RUNTIME;
+    }
+
+  g_free (full);
+}
+
+static void
+should_be_dir (SrtRuntimeIssues *issues,
+               const char *path,
+               const char *filename)
+{
+  gchar *full = g_build_filename (path, filename, NULL);
+
+  if (!g_file_test (full, G_FILE_TEST_IS_DIR))
+    {
+      g_debug ("%s is not a regular file", full);
+      *issues |= SRT_RUNTIME_ISSUES_NOT_RUNTIME;
+    }
+
+  g_free (full);
+}
+
+static void
+should_be_stattable (SrtRuntimeIssues *issues,
+                     const char *path,
+                     const char *filename,
+                     GStatBuf *buf)
+{
+  gchar *full = g_build_filename (path, filename, NULL);
+
+  if (g_stat (full, buf) != 0)
+    {
+      g_debug ("stat %s: %s", full, g_strerror (errno));
+      *issues |= SRT_RUNTIME_ISSUES_NOT_RUNTIME;
+    }
+
+  g_free (full);
+}
+
+static void
+might_be_stattable (const char *path,
+                    const char *filename,
+                    GStatBuf *buf)
+{
+  GStatBuf zeroed_stat = {};
+  gchar *full = g_build_filename (path, filename, NULL);
+
+  if (g_stat (full, buf) != 0)
+    {
+      g_debug ("stat %s: %s", full, g_strerror (errno));
+      *buf = zeroed_stat;
+    }
+
+  g_free (full);
+}
+
+static gboolean
+same_stat (GStatBuf *left,
+           GStatBuf *right)
+{
+  return left->st_dev == right->st_dev && left->st_ino == right->st_ino;
+}
+
+/*
+ * _srt_runtime_check:
+ * @bin32: (nullable): The absolute path to `ubuntu12_32`
+ * @expected_version: (nullable): The expected version number of the
+ *  Steam Runtime
+ * @custom_environ: (nullable): The list of environment variables to use. If NULL
+ *  g_get_environ will be used instead.
+ * @version_out: (optional) (type utf8) (out): The actual version number
+ * @path_out: (optional) (type filename) (out): The absolute path of the
+ *  Steam Runtime
+ */
+SrtRuntimeIssues
+_srt_runtime_check (const char *bin32,
+                    const char *expected_version,
+                    const GStrv custom_environ,
+                    gchar **version_out,
+                    gchar **path_out)
+{
+  SrtRuntimeIssues issues = SRT_RUNTIME_ISSUES_NONE;
+  GStatBuf zeroed_stat = {};
+  GStatBuf expected_stat, actual_stat;
+  GStatBuf pinned_libs_32;
+  GStatBuf pinned_libs_64;
+  GStatBuf lib_i386_linux_gnu;
+  GStatBuf lib_x86_64_linux_gnu;
+  GStatBuf usr_lib_i386_linux_gnu;
+  GStatBuf usr_lib_x86_64_linux_gnu;
+  GStatBuf amd64_bin;
+  GStatBuf i386_bin;
+  const gchar *env = NULL;
+  gchar *contents = NULL;
+  gchar *expected_path = NULL;
+  gchar *path = NULL;
+  gchar *version = NULL;
+  gchar *version_txt = NULL;
+  gsize len = 0;
+  GError *error = NULL;
+  GStrv environ = NULL;
+
+  environ = (custom_environ == NULL) ? g_get_environ () : g_strdupv (custom_environ);
+
+  env = g_environ_getenv (environ, "STEAM_RUNTIME");
+
+  if (bin32 != NULL)
+    expected_path = g_build_filename (bin32, "steam-runtime", NULL);
+
+  if (g_strcmp0 (env, "0") == 0)
+    {
+      issues |= SRT_RUNTIME_ISSUES_DISABLED;
+      goto out;
+    }
+
+  if (env == NULL || env[0] != '/')
+    {
+      issues |= SRT_RUNTIME_ISSUES_NOT_IN_ENVIRONMENT;
+    }
+  else if (g_stat (env, &actual_stat) != 0)
+    {
+      g_debug ("stat %s: %s", env, g_strerror (errno));
+      issues |= SRT_RUNTIME_ISSUES_NOT_IN_ENVIRONMENT;
+      actual_stat = zeroed_stat;
+    }
+
+  if (issues & SRT_RUNTIME_ISSUES_NOT_IN_ENVIRONMENT)
+    {
+      /* Try to recover by using the expected path */
+      if (expected_path != NULL)
+        {
+          path = g_strdup (expected_path);
+
+          if (g_stat (path, &actual_stat) != 0)
+            actual_stat = zeroed_stat;
+        }
+    }
+  else
+    {
+      g_assert (env != NULL);
+      g_assert (env[0] == '/');
+      path = g_strdup (env);
+    }
+
+  /* If we haven't found it yet, there is nothing else we can check */
+  if (path == NULL)
+    goto out;
+
+  if (expected_path != NULL && strcmp (path, expected_path) != 0)
+    {
+      if (g_stat (expected_path, &expected_stat) == 0)
+        {
+          if (!same_stat (&expected_stat, &actual_stat))
+            {
+              g_debug ("%s and %s are different inodes", path, expected_path);
+              issues |= SRT_RUNTIME_ISSUES_UNEXPECTED_LOCATION;
+            }
+        }
+      else
+        {
+          g_debug ("stat %s: %s", expected_path, g_strerror (errno));
+          /* If the expected location doesn't exist then logically
+           * the actual Steam Runtime in use can't be in the expected
+           * location... */
+          issues |= SRT_RUNTIME_ISSUES_UNEXPECTED_LOCATION;
+        }
+    }
+
+  version_txt = g_build_filename (path, "version.txt", NULL);
+
+  if (g_file_get_contents (version_txt, &contents, &len, &error))
+    {
+      const char *underscore = strrchr (contents, '_');
+
+      /* Remove trailing \n if any */
+      if (contents[len - 1] == '\n')
+        contents[--len] = '\0';
+
+      if (len != strlen (contents) ||
+          strchr (contents, '\n') != NULL ||
+          underscore == NULL)
+        {
+          g_debug ("Corrupt runtime: contents of %s should be in the "
+                   "format NAME_VERSION",
+                   version_txt);
+          issues |= SRT_RUNTIME_ISSUES_NOT_RUNTIME;
+        }
+      else if (!g_str_has_prefix (contents, "steam-runtime_"))
+        {
+          g_debug ("Unofficial Steam Runtime build %s", contents);
+          issues |= SRT_RUNTIME_ISSUES_UNOFFICIAL;
+        }
+
+      if (underscore != NULL)
+        {
+          version = g_strdup (underscore + 1);
+
+          if (version[0] == '\0')
+            {
+              g_debug ("Corrupt runtime: contents of %s is missing the expected "
+                       "runtime version number",
+                       version_txt);
+              issues |= SRT_RUNTIME_ISSUES_NOT_RUNTIME;
+            }
+
+          if (expected_version != NULL &&
+              strcmp (expected_version, version) != 0)
+            {
+              g_debug ("Expected Steam Runtime v%s, got v%s",
+                       expected_version, version);
+              issues |= SRT_RUNTIME_ISSUES_UNEXPECTED_VERSION;
+            }
+        }
+
+      g_clear_pointer (&contents, g_free);
+    }
+  else
+    {
+      issues |= SRT_RUNTIME_ISSUES_NOT_RUNTIME;
+      g_debug ("Unable to read %s: %s", version_txt, error->message);
+      g_clear_error (&error);
+    }
+
+  should_be_dir (&issues, path, "scripts");
+  should_be_executable (&issues, path, "run.sh");
+  should_be_executable (&issues, path, "setup.sh");
+  should_be_stattable (&issues, path, "amd64/lib/x86_64-linux-gnu",
+                       &lib_x86_64_linux_gnu);
+  should_be_stattable (&issues, path, "amd64/usr/lib/x86_64-linux-gnu",
+                       &usr_lib_x86_64_linux_gnu);
+  should_be_stattable (&issues, path, "i386/lib/i386-linux-gnu",
+                       &lib_i386_linux_gnu);
+  should_be_stattable (&issues, path, "i386/usr/lib/i386-linux-gnu",
+                       &usr_lib_i386_linux_gnu);
+  might_be_stattable (path, "pinned_libs_32", &pinned_libs_32);
+  might_be_stattable (path, "pinned_libs_64", &pinned_libs_64);
+  might_be_stattable (path, "amd64/usr/bin", &amd64_bin);
+  might_be_stattable (path, "i386/usr/bin", &i386_bin);
+
+  env = g_environ_getenv (environ, "STEAM_RUNTIME_PREFER_HOST_LIBRARIES");
+
+  if (g_strcmp0 (env, "0") == 0)
+    issues |= SRT_RUNTIME_ISSUES_NOT_USING_NEWER_HOST_LIBRARIES;
+
+  env = g_environ_getenv (environ, "LD_LIBRARY_PATH");
+
+  if (env == NULL)
+    {
+      issues |= SRT_RUNTIME_ISSUES_NOT_IN_LD_PATH;
+    }
+  else
+    {
+      gchar **entries = g_strsplit (env, ":", 0);
+      gchar **entry;
+      gboolean saw_lib_i386_linux_gnu = FALSE;
+      gboolean saw_lib_x86_64_linux_gnu = FALSE;
+      gboolean saw_usr_lib_i386_linux_gnu = FALSE;
+      gboolean saw_usr_lib_x86_64_linux_gnu = FALSE;
+      gboolean saw_pinned_libs_32 = FALSE;
+      gboolean saw_pinned_libs_64 = FALSE;
+
+      for (entry = entries; entry != NULL && *entry != NULL; entry++)
+        {
+          /* Scripts that manipulate LD_LIBRARY_PATH have a habit of
+           * adding empty entries */
+          if (*entry[0] == '\0')
+            continue;
+
+          /* We compare by stat(), because the entries in the
+           * LD_LIBRARY_PATH might not have been canonicalized by
+           * chasing symlinks, replacing "/.." or "//", etc. */
+          if (g_stat (*entry, &actual_stat) == 0)
+            {
+              if (same_stat (&actual_stat, &lib_i386_linux_gnu))
+                saw_lib_i386_linux_gnu = TRUE;
+
+              /* Don't use "else if": it would be legitimate for
+               * usr/lib/i386-linux-gnu and lib/i386-linux-gnu
+               * to be symlinks to the same place, in which case
+               * seeing one counts as seeing both. */
+              if (same_stat (&actual_stat, &usr_lib_i386_linux_gnu))
+                saw_usr_lib_i386_linux_gnu = TRUE;
+
+              if (same_stat (&actual_stat, &lib_x86_64_linux_gnu))
+                saw_lib_x86_64_linux_gnu = TRUE;
+
+              if (same_stat (&actual_stat, &usr_lib_x86_64_linux_gnu))
+                saw_usr_lib_x86_64_linux_gnu = TRUE;
+
+              /* The pinned libraries only count if they are before the
+               * corresponding Steam Runtime directories */
+              if (!saw_lib_i386_linux_gnu &&
+                  !saw_usr_lib_i386_linux_gnu &&
+                  pinned_libs_32.st_mode != 0 &&
+                  same_stat (&actual_stat, &pinned_libs_32))
+                saw_pinned_libs_32 = TRUE;
+
+              if (!saw_lib_x86_64_linux_gnu &&
+                  !saw_usr_lib_x86_64_linux_gnu &&
+                  pinned_libs_64.st_mode != 0 &&
+                  same_stat (&actual_stat, &pinned_libs_64))
+                saw_pinned_libs_64 = TRUE;
+            }
+          else
+            {
+              g_debug ("stat LD_LIBRARY_PATH entry %s: %s",
+                       *entry, g_strerror (errno));
+            }
+        }
+
+      if (!saw_lib_x86_64_linux_gnu || !saw_usr_lib_x86_64_linux_gnu)
+        {
+          g_debug ("STEAM_RUNTIME/amd64/[usr/]lib/x86_64-linux-gnu missing "
+                   "from LD_LIBRARY_PATH");
+          issues |= SRT_RUNTIME_ISSUES_NOT_IN_LD_PATH;
+        }
+
+      if (!saw_lib_i386_linux_gnu || !saw_usr_lib_i386_linux_gnu)
+        {
+          g_debug ("STEAM_RUNTIME/i386/[usr/]lib/i386-linux-gnu missing "
+                   "from LD_LIBRARY_PATH");
+          issues |= SRT_RUNTIME_ISSUES_NOT_IN_LD_PATH;
+        }
+
+      if (!saw_pinned_libs_64 || !saw_pinned_libs_32)
+        {
+          g_debug ("Pinned libraries missing from LD_LIBRARY_PATH");
+          issues |= SRT_RUNTIME_ISSUES_NOT_USING_NEWER_HOST_LIBRARIES;
+        }
+
+      g_strfreev (entries);
+    }
+
+  env = g_environ_getenv (environ, "PATH");
+
+  if (env == NULL)
+    {
+      issues |= SRT_RUNTIME_ISSUES_NOT_IN_PATH;
+    }
+  else
+    {
+      gchar **entries = g_strsplit (env, ":", 0);
+      gchar **entry;
+      gboolean saw_amd64_bin = FALSE;
+      gboolean saw_i386_bin = FALSE;
+
+      for (entry = entries; entry != NULL && *entry != NULL; entry++)
+        {
+          /* Scripts that manipulate PATH have a habit of adding empty
+           * entries */
+          if (*entry[0] == '\0')
+            continue;
+
+          /* We compare by stat(), because the entries in the
+           * PATH might not have been canonicalized by
+           * chasing symlinks, replacing "/.." or "//", etc. */
+          if (g_stat (*entry, &actual_stat) == 0)
+            {
+              if (amd64_bin.st_mode != 0 &&
+                  same_stat (&actual_stat, &amd64_bin))
+                saw_amd64_bin = TRUE;
+
+              if (i386_bin.st_mode != 0 &&
+                  same_stat (&actual_stat, &i386_bin))
+                saw_i386_bin = TRUE;
+
+            }
+          else
+            {
+              g_debug ("stat PATH entry %s: %s",
+                       *entry, g_strerror (errno));
+            }
+        }
+
+      if (!saw_amd64_bin && !saw_i386_bin)
+        {
+          g_debug ("Neither STEAM_RUNTIME/amd64/usr/bin nor STEAM_RUNTIME/i386/usr/bin "
+                   "are available in PATH");
+          issues |= SRT_RUNTIME_ISSUES_NOT_IN_PATH;
+        }
+
+      g_strfreev (entries);
+    }
+
+out:
+  if (path_out != NULL)
+    *path_out = g_steal_pointer (&path);
+
+  if (version_out != NULL)
+    *version_out = g_steal_pointer (&version);
+
+  g_free (contents);
+  g_free (expected_path);
+  g_free (path);
+  g_free (version);
+  g_free (version_txt);
+  g_strfreev (environ);
+  g_clear_error (&error);
+  return issues;
+}
diff --git a/steam-runtime-tools/runtime.h b/steam-runtime-tools/runtime.h
new file mode 100644
index 0000000000000000000000000000000000000000..96662d331f61f0df5f11f50d08ff43dbef234f1b
--- /dev/null
+++ b/steam-runtime-tools/runtime.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright © 2019 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.
+ */
+
+#pragma once
+
+#if !defined(_SRT_IN_SINGLE_HEADER) && !defined(_SRT_COMPILATION)
+#error "Do not include directly, use <steam-runtime-tools/steam-runtime-tools.h>"
+#endif
+
+/**
+ * SrtRuntimeIssues:
+ * @SRT_RUNTIME_ISSUES_NONE: There are no problems
+ * @SRT_RUNTIME_ISSUES_INTERNAL_ERROR: Unable to detect the status of the
+ *  `LD_LIBRARY_PATH`-based Steam Runtime
+ * @SRT_RUNTIME_ISSUES_DISABLED: The Steam Runtime has been disabled
+ * @SRT_RUNTIME_ISSUES_NOT_RUNTIME: The Steam Runtime does not appear to
+ *  have the correct structure
+ * @SRT_RUNTIME_ISSUES_UNOFFICIAL: The Steam Runtime is an unofficial build
+ * @SRT_RUNTIME_ISSUES_UNEXPECTED_LOCATION: The Steam Runtime is not in
+ *  the location that was expected
+ * @SRT_RUNTIME_ISSUES_UNEXPECTED_VERSION: The Steam Runtime is not the
+ *  version that was expected
+ * @SRT_RUNTIME_ISSUES_NOT_IN_LD_PATH: The Steam Runtime is not in the
+ *  expected position in the `LD_LIBRARY_PATH`
+ * @SRT_RUNTIME_ISSUES_NOT_IN_PATH: The Steam Runtime is not in the
+ *  expected position in the `PATH`
+ * @SRT_RUNTIME_ISSUES_NOT_IN_ENVIRONMENT: The environment variable
+ *  `STEAM_RUNTIME` is not set to the absolute path to the Steam Runtime
+ * @SRT_RUNTIME_ISSUES_NOT_USING_NEWER_HOST_LIBRARIES: The Steam Runtime has
+ *  been configured to not use host libraries even if they are newer than
+ *  the libraries in the Steam Runtime. This is likely to work
+ *  acceptably with NVIDIA non-free graphics drivers, but is likely to
+ *  break Mesa.
+ *
+ * A bitfield with flags representing problems with the Steam Runtime, or
+ * %SRT_RUNTIME_ISSUES_NONE (which is numerically zero) if no problems
+ * were detected.
+ *
+ * In general, more bits set means more problems.
+ */
+typedef enum
+{
+  SRT_RUNTIME_ISSUES_INTERNAL_ERROR = (1 << 0),
+  SRT_RUNTIME_ISSUES_DISABLED = (1 << 1),
+  SRT_RUNTIME_ISSUES_NOT_RUNTIME = (1 << 2),
+  SRT_RUNTIME_ISSUES_UNOFFICIAL = (1 << 3),
+  SRT_RUNTIME_ISSUES_UNEXPECTED_LOCATION = (1 << 4),
+  SRT_RUNTIME_ISSUES_UNEXPECTED_VERSION = (1 << 5),
+  SRT_RUNTIME_ISSUES_NOT_IN_LD_PATH = (1 << 6),
+  SRT_RUNTIME_ISSUES_NOT_IN_PATH = (1 << 7),
+  SRT_RUNTIME_ISSUES_NOT_IN_ENVIRONMENT = (1 << 8),
+  SRT_RUNTIME_ISSUES_NOT_USING_NEWER_HOST_LIBRARIES = (1 << 9),
+  SRT_RUNTIME_ISSUES_NONE = 0
+} SrtRuntimeIssues;
diff --git a/steam-runtime-tools/steam-internal.h b/steam-runtime-tools/steam-internal.h
new file mode 100644
index 0000000000000000000000000000000000000000..73863cd7adb6395bd8e426a01c198706d51d5768
--- /dev/null
+++ b/steam-runtime-tools/steam-internal.h
@@ -0,0 +1,37 @@
+/*<private_header>*/
+/*
+ * Copyright © 2019 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.
+ */
+
+#pragma once
+
+#include "steam-runtime-tools/steam.h"
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_GNUC_INTERNAL
+SrtSteamIssues _srt_steam_check (const GStrv env,
+                                 gchar **path_out,
+                                 gchar **bin32_out);
diff --git a/steam-runtime-tools/steam-runtime-tools.h b/steam-runtime-tools/steam-runtime-tools.h
index e7313d07bcf9f72676c70466ed54bb8367b2e334..bc51b02fb1a10e63acf1915f73aaed3d1eff8b5c 100644
--- a/steam-runtime-tools/steam-runtime-tools.h
+++ b/steam-runtime-tools/steam-runtime-tools.h
@@ -30,6 +30,8 @@
 #include <steam-runtime-tools/architecture.h>
 #include <steam-runtime-tools/enums.h>
 #include <steam-runtime-tools/library.h>
+#include <steam-runtime-tools/runtime.h>
+#include <steam-runtime-tools/steam.h>
 #include <steam-runtime-tools/system-info.h>
 
 #undef _SRT_IN_SINGLE_HEADER
diff --git a/steam-runtime-tools/steam.c b/steam-runtime-tools/steam.c
new file mode 100644
index 0000000000000000000000000000000000000000..c01e39d05b080cdc7c7f31246c72095d3f5a854d
--- /dev/null
+++ b/steam-runtime-tools/steam.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright © 2019 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.h"
+#include "steam-runtime-tools/steam-internal.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "steam-runtime-tools/glib-compat.h"
+
+/**
+ * SECTION:steam
+ * @title: Steam installation
+ * @short_description: Information about the Steam installation
+ * @include: steam-runtime-tools/steam-runtime-tools.h
+ *
+ * #SrtSteamIssues represents problems encountered with the Steam
+ * installation.
+ */
+
+/*
+ * _srt_steam_check:
+ * @environ: (nullable): The list of environment variables to use.
+ * @path_out: (out) (optional) (nullable) (type filename):
+ *  Used to return the absolute path to the Steam installation
+ * @bin32_out: (out) (optional) (nullable) (type filename):
+ *  Used to return the absolute path to `ubuntu12_32`
+ */
+SrtSteamIssues
+_srt_steam_check (const GStrv environ,
+                  gchar **path_out,
+                  gchar **bin32_out)
+{
+  SrtSteamIssues issues = SRT_STEAM_ISSUES_NONE;
+  gchar *dot_steam_bin32 = NULL;
+  gchar *dot_steam_steam = NULL;
+  gchar *dot_steam_root = NULL;
+  gchar *default_steam_path = NULL;
+  char *path = NULL;
+  char *bin32 = NULL;
+  const char *home = NULL;
+  const char *user_data = NULL;
+  GStrv env = NULL;
+
+  env = (environ == NULL) ? g_get_environ () : g_strdupv (environ);
+
+  home = g_environ_getenv (env, "HOME");
+  user_data = g_environ_getenv (env, "XDG_DATA_HOME");
+
+  if (home == NULL)
+    home = g_get_home_dir ();
+
+  if (user_data == NULL)
+    user_data = g_get_user_data_dir ();
+
+  default_steam_path = g_build_filename (user_data,
+                                         "Steam", NULL);
+
+  dot_steam_bin32 = g_build_filename (home, ".steam", "bin32", NULL);
+  dot_steam_steam = g_build_filename (home, ".steam", "steam", NULL);
+  dot_steam_root = g_build_filename (home, ".steam", "root", NULL);
+
+  g_return_val_if_fail (path_out == NULL || *path_out == NULL,
+                        SRT_STEAM_ISSUES_INTERNAL_ERROR);
+  g_return_val_if_fail (bin32_out == NULL || *bin32_out == NULL,
+                        SRT_STEAM_ISSUES_INTERNAL_ERROR);
+
+  /* Canonically, ~/.steam/steam is a symlink to the Steam installation.
+   * (This is ignoring the Valve-internal "beta universe", which uses
+   * ~/.steam/steambeta instead.) */
+  if (g_file_test (dot_steam_steam, G_FILE_TEST_IS_SYMLINK))
+    {
+      path = realpath (dot_steam_steam, NULL);
+
+      if (path == NULL)
+        g_debug ("realpath(%s): %s", dot_steam_steam, g_strerror (errno));
+    }
+  else
+    {
+      /* e.g. https://bugs.debian.org/916303 */
+      issues |= SRT_STEAM_ISSUES_DOT_STEAM_STEAM_NOT_SYMLINK;
+    }
+
+  /* If that doesn't work, try ~/.steam/root, which points to whichever
+   * one of the public or beta universe was run most recently. */
+  if (path == NULL &&
+      g_file_test (dot_steam_root, G_FILE_TEST_IS_SYMLINK))
+    {
+      path = realpath (dot_steam_root, NULL);
+
+      if (path == NULL)
+        g_debug ("realpath(%s): %s", dot_steam_root, g_strerror (errno));
+    }
+
+  /* If *that* doesn't work, try going up one level from ubuntu12_32,
+   * to which ~/.steam/bin32 is a symlink */
+  if (path == NULL &&
+      g_file_test (dot_steam_bin32, G_FILE_TEST_IS_SYMLINK))
+    {
+      bin32 = realpath (dot_steam_bin32, NULL);
+
+      if (bin32 == NULL)
+        {
+          g_debug ("realpath(%s): %s", dot_steam_bin32, g_strerror (errno));
+        }
+      else if (!g_str_has_suffix (bin32, "/ubuntu12_32"))
+        {
+          g_debug ("Unexpected bin32 path: %s -> %s", dot_steam_bin32,
+                   bin32);
+        }
+      else
+        {
+          path = strndup (bin32, strlen (bin32) - strlen ("/ubuntu12_32"));
+
+          /* We don't try to survive out-of-memory */
+          if (path == NULL)
+            g_error ("strndup: %s", g_strerror (errno));
+        }
+    }
+
+  /* If *that* doesn't work, try the default installation location. */
+  if (path == NULL)
+    {
+      path = realpath (default_steam_path, NULL);
+
+      if (path == NULL)
+        g_debug ("realpath(%s): %s", default_steam_path, g_strerror (errno));
+    }
+
+  if (path == NULL)
+    {
+      g_debug ("Unable to find Steam installation");
+      issues |= SRT_STEAM_ISSUES_CANNOT_FIND;
+      goto out;
+    }
+
+  g_debug ("Found Steam installation at %s", path);
+
+  /* If we haven't found ubuntu12_32 yet, it's a subdirectory of the
+   * Steam installation */
+  if (bin32 == NULL)
+    {
+      /* We don't try to survive out-of-memory */
+      if (asprintf (&bin32, "%s/ubuntu12_32", path) < 0)
+        g_error ("asprintf: %s", g_strerror (errno));
+    }
+
+  if (bin32 != NULL)
+    {
+      g_debug ("Found ubuntu12_32 directory at %s", bin32);
+    }
+  else
+    {
+      g_debug ("Unable to find ubuntu12_32 directory");
+    }
+
+  /* We can't just transfer ownership here, because in the older GLib
+   * that we're targeting, g_free() and free() are not guaranteed to be
+   * associated with the same memory pool. */
+  if (path_out != NULL)
+    *path_out = g_strdup (path);
+
+  if (bin32_out != NULL)
+    *bin32_out = g_strdup (bin32);
+
+out:
+  free (path);
+  free (bin32);
+  g_free (dot_steam_bin32);
+  g_free (dot_steam_steam);
+  g_free (dot_steam_root);
+  g_free (default_steam_path);
+  g_strfreev (env);
+  return issues;
+}
diff --git a/steam-runtime-tools/steam.h b/steam-runtime-tools/steam.h
new file mode 100644
index 0000000000000000000000000000000000000000..68e64c200e66daff8fa58b19ec150efc491e111f
--- /dev/null
+++ b/steam-runtime-tools/steam.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2019 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.
+ */
+
+#pragma once
+
+#if !defined(_SRT_IN_SINGLE_HEADER) && !defined(_SRT_COMPILATION)
+#error "Do not include directly, use <steam-runtime-tools/steam-runtime-tools.h>"
+#endif
+
+/**
+ * SrtSteamIssues:
+ * @SRT_STEAM_ISSUES_NONE: There are no problems
+ * @SRT_STEAM_ISSUES_INTERNAL_ERROR: Unable to detect the status of the
+ *  Steam installation
+ * @SRT_STEAM_ISSUES_CANNOT_FIND: Unable to find the Steam installation
+ * @SRT_STEAM_ISSUES_DOT_STEAM_STEAM_NOT_SYMLINK: `~/.steam/steam` is not
+ *  a symbolic link to a Steam installation, which for example can happen
+ *  if Steam was installed on a system with https://bugs.debian.org/916303
+ *
+ * A bitfield with flags representing problems with the Steam
+ * installation, or %SRT_STEAM_ISSUES_NONE (which is numerically zero)
+ * if no problems were detected.
+ *
+ * In general, more bits set means more problems.
+ */
+typedef enum
+{
+  SRT_STEAM_ISSUES_INTERNAL_ERROR = (1 << 0),
+  SRT_STEAM_ISSUES_CANNOT_FIND = (1 << 1),
+  SRT_STEAM_ISSUES_DOT_STEAM_STEAM_NOT_SYMLINK = (1 << 2),
+  SRT_STEAM_ISSUES_NONE = 0
+} SrtSteamIssues;
diff --git a/steam-runtime-tools/system-info.c b/steam-runtime-tools/system-info.c
index 0b6179d1cee47b8d71c0c5e01977c7956611312c..76d33e93ca5fdff8eff1603eea3877f52cb6f0e0 100644
--- a/steam-runtime-tools/system-info.c
+++ b/steam-runtime-tools/system-info.c
@@ -28,6 +28,8 @@
 #include "steam-runtime-tools/architecture.h"
 #include "steam-runtime-tools/architecture-internal.h"
 #include "steam-runtime-tools/glib-compat.h"
+#include "steam-runtime-tools/runtime-internal.h"
+#include "steam-runtime-tools/steam-internal.h"
 #include "steam-runtime-tools/utils-internal.h"
 
 #include <errno.h>
@@ -79,6 +81,23 @@ struct _SrtSystemInfo
   gchar *expectations;
   /* Fake environment variables, or %NULL to use the real environment */
   gchar **env;
+  struct
+  {
+    /* path != NULL or issues != NONE indicates we have already checked
+     * the Steam installation */
+    gchar *path;
+    gchar *bin32;
+    SrtSteamIssues issues;
+  } steam;
+  struct
+  {
+    /* path != NULL or issues != NONE indicates we have already checked
+     * the Steam Runtime */
+    gchar *path;
+    gchar *expected_version;
+    gchar *version;
+    SrtRuntimeIssues issues;
+  } runtime;
   Tristate can_write_uinput;
   /* (element-type Abi) */
   GPtrArray *abis;
@@ -195,11 +214,38 @@ srt_system_info_set_property (GObject *object,
     }
 }
 
+/*
+ * Forget any cached information about the Steam Runtime.
+ */
+static void
+forget_runtime (SrtSystemInfo *self)
+{
+  g_clear_pointer (&self->runtime.path, g_free);
+  g_clear_pointer (&self->runtime.version, g_free);
+  g_clear_pointer (&self->runtime.expected_version, g_free);
+  self->runtime.issues = SRT_RUNTIME_ISSUES_NONE;
+}
+
+/*
+ * Forget any cached information about the Steam installation.
+ */
+static void
+forget_steam (SrtSystemInfo *self)
+{
+  forget_runtime (self);
+  self->steam.issues = SRT_STEAM_ISSUES_NONE;
+  g_clear_pointer (&self->steam.path, g_free);
+  g_clear_pointer (&self->steam.bin32, g_free);
+}
+
 static void
 srt_system_info_finalize (GObject *object)
 {
   SrtSystemInfo *self = SRT_SYSTEM_INFO (object);
 
+  forget_runtime (self);
+  forget_steam (self);
+
   g_clear_pointer (&self->abis, g_ptr_array_unref);
   g_free (self->expectations);
   g_strfreev (self->env);
@@ -708,4 +754,187 @@ srt_system_info_set_environ (SrtSystemInfo *self,
   forget_libraries (self);
   g_strfreev (self->env);
   self->env = g_strdupv ((gchar **) env);
+
+  /* Forget what we know about Steam because it is bounded to the environment. */
+  forget_steam (self);
+}
+
+static void
+ensure_steam_cached (SrtSystemInfo *self)
+{
+  if (self->steam.issues == SRT_STEAM_ISSUES_NONE &&
+      self->steam.path == NULL)
+    self->steam.issues = _srt_steam_check (self->env,
+                                           &self->steam.path,
+                                           &self->steam.bin32);
+}
+
+/**
+ * srt_system_info_get_steam_issues:
+ * @self: The #SrtSystemInfo object
+ *
+ * Detect and return any problems encountered with the Steam installation.
+ *
+ * Returns: Any problems detected with the Steam installation,
+ *  or %SRT_RUNTIME_ISSUES_NONE if no problems were detected
+ */
+SrtSteamIssues
+srt_system_info_get_steam_issues (SrtSystemInfo *self)
+{
+  g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self),
+                        SRT_STEAM_ISSUES_INTERNAL_ERROR);
+
+  ensure_steam_cached (self);
+  return self->steam.issues;
+}
+
+/**
+ * srt_system_info_dup_steam_installation_path:
+ * @self: The #SrtSystemInfo object
+ *
+ * Return the absolute path to the Steam installation in use (the
+ * directory containing `steam.sh` and `ubuntu12_32/` among other
+ * files and directories, analogous to `C:\Program Files\Steam` in a
+ * typical Windows installation of Steam). This is typically of the form
+ * `/home/me/.local/share/Steam`.
+ *
+ * If the Steam installation could not be found, at least one flag will
+ * be set in the result of srt_system_info_get_steam_issues() to indicate
+ * why.
+ *
+ * Returns: (transfer full) (type filename) (nullable): The absolute path
+ *  to the Steam installation, or %NULL if it could not be determined.
+ *  Free with g_free().
+ */
+gchar *
+srt_system_info_dup_steam_installation_path (SrtSystemInfo *self)
+{
+  g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), NULL);
+
+  ensure_steam_cached (self);
+  return g_strdup (self->steam.path);
+}
+
+/**
+ * srt_system_info_set_expected_runtime_version:
+ * @self: The #SrtSystemInfo object
+ * @version (nullable): The expected version number, such as `0.20190711.3`,
+ *  or %NULL if there is no particular expectation
+ *
+ * Set the expected version number of the Steam Runtime. Invalidate any
+ * cached information about the Steam Runtime if it differs from the
+ * previous expectation.
+ */
+void
+srt_system_info_set_expected_runtime_version (SrtSystemInfo *self,
+                                              const char *version)
+{
+  g_return_if_fail (SRT_IS_SYSTEM_INFO (self));
+
+  if (g_strcmp0 (version, self->runtime.expected_version) != 0)
+    {
+      forget_runtime (self);
+      g_clear_pointer (&self->runtime.expected_version, g_free);
+      self->runtime.expected_version = g_strdup (version);
+    }
+}
+
+/**
+ * srt_system_info_dup_expected_runtime_version:
+ * @self: The #SrtSystemInfo object
+ *
+ * Returns: (transfer full) (type utf8): The expected version number of
+ *  the Steam Runtime, or %NULL if no particular version is expected.
+ *  Free with g_free().
+ */
+gchar *
+srt_system_info_dup_expected_runtime_version (SrtSystemInfo *self)
+{
+  g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), NULL);
+
+  return g_strdup (self->runtime.expected_version);
+}
+
+static void
+ensure_runtime_cached (SrtSystemInfo *self)
+{
+  ensure_steam_cached (self);
+
+  if (self->runtime.issues == SRT_RUNTIME_ISSUES_NONE &&
+      self->runtime.path == NULL)
+    self->runtime.issues = _srt_runtime_check (self->steam.bin32,
+                                               self->runtime.expected_version,
+                                               self->env,
+                                               &self->runtime.version,
+                                               &self->runtime.path);
+}
+
+/**
+ * srt_system_info_get_runtime_issues:
+ * @self: The #SrtSystemInfo object
+ *
+ * Detect and return any problems encountered with the
+ * `LD_LIBRARY_PATH`-based Steam Runtime.
+ *
+ * Returns: Any problems detected with the Steam Runtime,
+ *  or %SRT_RUNTIME_ISSUES_NONE if no problems were detected
+ */
+SrtRuntimeIssues
+srt_system_info_get_runtime_issues (SrtSystemInfo *self)
+{
+  g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self),
+                        SRT_RUNTIME_ISSUES_INTERNAL_ERROR);
+
+  ensure_runtime_cached (self);
+  return self->runtime.issues;
+}
+
+/**
+ * srt_system_info_dup_runtime_path:
+ * @self: The #SrtSystemInfo object
+ *
+ * Return the absolute path to the `LD_LIBRARY_PATH`-based Steam Runtime
+ * in use (the directory containing `run.sh`, `version.txt` and
+ * similar files).
+ *
+ * If the Steam Runtime has been disabled or could not be found, at
+ * least one flag will be set in the result of
+ * srt_system_info_get_runtime_issues() to indicate why.
+ *
+ * Returns: (transfer full) (type filename) (nullable): The absolute path
+ *  to the Steam Runtime, or %NULL if it could not be determined.
+ *  Free with g_free().
+ */
+gchar *
+srt_system_info_dup_runtime_path (SrtSystemInfo *self)
+{
+  g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), NULL);
+
+  ensure_runtime_cached (self);
+  return g_strdup (self->runtime.path);
+}
+
+/**
+ * srt_system_info_dup_runtime_version:
+ * @self: The #SrtSystemInfo object
+ *
+ * Return the version number of the `LD_LIBRARY_PATH`-based Steam Runtime
+ * in use, for example `0.20190711.3`, or %NULL if it could not be
+ * determined.
+ *
+ * If the Steam Runtime has been disabled or could not be found, or its
+ * version number could not be read, then at least one flag will be set
+ * in the result of srt_system_info_get_runtime_issues() to indicate why.
+ *
+ * Returns: (transfer full) (type utf8) (nullable): The version number of
+ *  the Steam Runtime, or %NULL if it could not be determined.
+ *  Free with g_free().
+ */
+gchar *
+srt_system_info_dup_runtime_version (SrtSystemInfo *self)
+{
+  g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), NULL);
+
+  ensure_runtime_cached (self);
+  return g_strdup (self->runtime.version);
 }
diff --git a/steam-runtime-tools/system-info.h b/steam-runtime-tools/system-info.h
index 33b6132b3b25235e320bfd201b54b85dafd5bcdd..632e5df379ab39ae6d06ce5c3fd8ffd01539a78b 100644
--- a/steam-runtime-tools/system-info.h
+++ b/steam-runtime-tools/system-info.h
@@ -33,6 +33,8 @@
 #include <glib-object.h>
 
 #include <steam-runtime-tools/library.h>
+#include <steam-runtime-tools/runtime.h>
+#include <steam-runtime-tools/steam.h>
 
 typedef struct _SrtSystemInfo SrtSystemInfo;
 typedef struct _SrtSystemInfoClass SrtSystemInfoClass;
@@ -61,3 +63,12 @@ SrtLibraryIssues srt_system_info_check_library (SrtSystemInfo *self,
 
 void srt_system_info_set_environ (SrtSystemInfo *self,
                                   gchar * const *env);
+void srt_system_info_set_expected_runtime_version (SrtSystemInfo *self,
+                                                   const char *version);
+gchar *srt_system_info_dup_expected_runtime_version (SrtSystemInfo *self);
+SrtRuntimeIssues srt_system_info_get_runtime_issues (SrtSystemInfo *self);
+gchar *srt_system_info_dup_runtime_path (SrtSystemInfo *self);
+gchar *srt_system_info_dup_runtime_version (SrtSystemInfo *self);
+
+SrtSteamIssues srt_system_info_get_steam_issues (SrtSystemInfo *self);
+gchar *srt_system_info_dup_steam_installation_path (SrtSystemInfo *self);
diff --git a/tests/fake-home.c b/tests/fake-home.c
new file mode 100644
index 0000000000000000000000000000000000000000..c60da94021c8acdb0e7e448af7eedd013bf785f8
--- /dev/null
+++ b/tests/fake-home.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright © 2019 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 "fake-home.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <ftw.h>
+#include <gio/gio.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include "test-utils.h"
+
+/**
+ * fake_home_new:
+ *
+ * Create a new #FakeHome object and a temporary folder in the file system
+ *
+ * Returns: the newely created #FakeHome object
+ */
+FakeHome *
+fake_home_new (void)
+{
+  GError *error = NULL;
+  FakeHome *fake_home = g_slice_new (FakeHome);
+  fake_home->home = g_dir_make_tmp ("fake-home-XXXXXX", &error);
+  g_assert_no_error (error);
+  
+  fake_home->create_pinning_libs = TRUE;
+  fake_home->create_i386_folders = TRUE;
+  fake_home->create_amd64_folders = TRUE;
+  fake_home->create_steam_symlink = TRUE;
+  fake_home->create_steamrt_files = TRUE;
+  fake_home->add_environments = TRUE;
+  fake_home->has_debian_bug_916303 = FALSE;
+  
+  return fake_home;
+}
+
+/**
+ * fake_home_create_structure:
+ * @f: a #FakeHome object used to create the folder structure
+ *
+ * Create folders and files like a canonical Steam Installation.
+ * As the home directory, the temporary folder stored in `home` is used.
+ * A custom environ is also created and stored under `env`.
+ *
+ * Returns: %TRUE if the creation was successful
+ */
+gboolean
+fake_home_create_structure (FakeHome *f)
+{
+  gboolean ret = FALSE;
+  GFile *symlink = NULL;
+  gchar *dot_steam = NULL;
+  gchar *scripts = NULL;
+  gchar *run = NULL;
+  gchar *setup = NULL;
+  gchar *version = NULL;
+  gchar *dot_steam_bin32 = NULL;
+  gchar *dot_steam_steam = NULL;
+  gchar *local_share = NULL;
+  gchar *ld_path = NULL;
+  gchar *prepended_path = NULL;
+  gchar *ubuntu12_32 = NULL;
+  GError *error = NULL;
+  int saved_errno;
+
+  g_return_val_if_fail (f != NULL, FALSE);
+
+  dot_steam = g_build_filename (f->home, ".steam", NULL);
+
+  if (f->has_debian_bug_916303)
+    f->steam_base_folder = g_strdup (dot_steam);
+  else
+    f->steam_base_folder = g_build_filename (f->home, ".local", "share",
+                                             "Steam", NULL);
+
+  f->runtime = g_build_filename (f->steam_base_folder, "ubuntu12_32",
+                                 "steam-runtime", NULL);
+
+  scripts = g_build_filename (f->runtime, "scripts", NULL);
+
+  if (g_mkdir_with_parents (dot_steam, 0755) != 0)
+    goto out;
+  if (g_mkdir_with_parents (f->steam_base_folder, 0755) != 0)
+    goto out;
+  if (g_mkdir_with_parents (scripts, 0755) != 0)
+    goto out;
+
+  f->pinned_32 = g_build_filename (f->runtime, "pinned_libs_32", NULL);
+  f->pinned_64 = g_build_filename (f->runtime, "pinned_libs_64", NULL);
+  f->i386_lib_i386 = g_build_filename (f->runtime, "i386", "lib", "i386-linux-gnu", NULL);
+  f->i386_lib = g_build_filename (f->runtime, "i386", "lib", NULL);
+  f->i386_usr_lib_i386 = g_build_filename (f->runtime, "i386", "usr", "lib", "i386-linux-gnu", NULL);
+  f->i386_usr_lib = g_build_filename (f->runtime, "i386", "usr", "lib", NULL);
+  f->i386_usr_bin = g_build_filename (f->runtime, "i386", "usr", "bin", NULL);
+  f->amd64_lib_64 = g_build_filename (f->runtime, "amd64", "lib", "x86_64-linux-gnu", NULL);
+  f->amd64_lib = g_build_filename (f->runtime, "amd64", "lib", NULL);
+  f->amd64_usr_lib_64 = g_build_filename (f->runtime, "amd64", "usr", "lib", "x86_64-linux-gnu", NULL);
+  f->amd64_usr_lib = g_build_filename (f->runtime, "amd64", "usr", "lib", NULL);
+  f->amd64_bin = g_build_filename (f->runtime, "amd64", "bin", NULL);
+  f->amd64_usr_bin = g_build_filename (f->runtime, "amd64", "usr", "bin", NULL);
+
+  if (f->create_pinning_libs)
+    {
+      if (g_mkdir_with_parents (f->pinned_32, 0755) != 0)
+        goto out;
+      if (g_mkdir_with_parents (f->pinned_64, 0755) != 0)
+        goto out;
+    }
+
+  if (f->create_i386_folders)
+    {
+      if (g_mkdir_with_parents (f->i386_lib_i386, 0755) != 0)
+        goto out;
+      if (g_mkdir_with_parents (f->i386_usr_lib_i386, 0755) != 0)
+        goto out;
+      if (g_mkdir_with_parents (f->i386_usr_bin, 0755) != 0)
+        goto out;
+    }
+
+  if (f->create_amd64_folders)
+    {
+      if (g_mkdir_with_parents (f->amd64_lib_64, 0755) != 0)
+        goto out;
+      if (g_mkdir_with_parents (f->amd64_usr_lib_64, 0755) != 0)
+        goto out;
+      if (g_mkdir_with_parents (f->amd64_usr_bin, 0755) != 0)
+        goto out;
+    }
+
+  if (f->create_steamrt_files)
+    {
+      run = g_build_filename (f->runtime, "run.sh", NULL);
+      setup = g_build_filename (f->runtime, "setup.sh", NULL);
+      version = g_build_filename (f->runtime, "version.txt", NULL);
+
+      if (g_creat (run, 0755) < 0)
+        goto out;
+      if (g_creat (setup, 0755) < 0)
+        goto out;
+      if (g_creat (version, 0755) < 0)
+        goto out;
+      
+      g_file_set_contents (version, "steam-runtime_0.20190711.3", -1, &error);
+      g_assert_no_error (error);
+    }
+
+  if (f->has_debian_bug_916303)
+    {
+      dot_steam_steam = g_build_filename (dot_steam, "steam", NULL);
+      if (g_mkdir_with_parents (dot_steam_steam, 0755) != 0)
+        goto out;
+    }
+
+  if (f->create_steam_symlink)
+    {
+      dot_steam_steam = g_build_filename (dot_steam, "steam", NULL);
+      symlink = g_file_new_for_path (dot_steam_steam);
+
+      g_file_make_symbolic_link (symlink, f->steam_base_folder, NULL, &error);
+      g_object_unref (symlink);
+      if (f->has_debian_bug_916303)
+        {
+          g_error_free (error);
+          error = NULL;
+        }
+      else
+        {
+          g_assert_no_error (error);
+        }
+
+      dot_steam_bin32 = g_build_filename (dot_steam, "bin32", NULL);
+      symlink = g_file_new_for_path (dot_steam_bin32);
+
+      ubuntu12_32 = g_build_filename (f->steam_base_folder, "ubuntu12_32", NULL);
+      g_file_make_symbolic_link (symlink, ubuntu12_32, NULL, &error);
+      g_object_unref (symlink);
+      g_assert_no_error (error);
+    }
+
+  local_share = g_build_filename (f->home, ".local", "share", NULL);
+  f->env = g_get_environ ();
+  f->env = g_environ_setenv (f->env, "HOME", f->home, TRUE);
+  f->env = g_environ_setenv (f->env, "XDG_DATA_HOME", local_share, TRUE);
+
+  if (f->add_environments)
+    {
+      const gchar *path;
+
+      f->env = g_environ_setenv (f->env, "STEAM_RUNTIME", f->runtime, TRUE);
+
+      ld_path = g_strjoin (":",
+                           f->pinned_32,
+                           f->pinned_64,
+                           f->i386_lib_i386,
+                           f->i386_lib,
+                           f->i386_usr_lib_i386,
+                           f->i386_usr_lib,
+                           f->amd64_lib_64,
+                           f->amd64_lib,
+                           f->amd64_usr_lib_64,
+                           f->amd64_usr_lib,
+                           NULL);
+      f->env = g_environ_setenv (f->env, "LD_LIBRARY_PATH", ld_path, TRUE);
+
+      path = g_environ_getenv (f->env, "PATH");
+
+      prepended_path = g_strjoin (":",
+                                  f->amd64_bin,
+                                  f->amd64_usr_bin,
+                                  path,
+                                  NULL);
+
+      f->env = g_environ_setenv (f->env, "PATH", prepended_path, TRUE);
+    }
+
+  ret = TRUE;
+
+  out:
+    saved_errno = errno;
+    g_free (dot_steam);
+    g_free (scripts);
+    g_free (run);
+    g_free (setup);
+    g_free (version);
+    g_free (dot_steam_steam);
+    g_free (local_share);
+    g_free (ld_path);
+    g_free (prepended_path);
+
+    if (!ret)
+      g_warning ("Unable to create directories: %s", g_strerror (saved_errno));
+    
+    return ret;
+
+}
+
+/**
+ * fake_home_clean_up:
+ * @f: the #FakeHome object to clean up and finalize
+ *
+ * Clean up a #FakeHome object recursively removing the created
+ * home directory and freeing @f.
+ */
+void
+fake_home_clean_up (FakeHome *f)
+{
+  if (!rm_rf (f->home))
+    g_debug ("Unable to remove the fake home directory: %s", f->home);
+
+  g_free (f->home);
+  g_free (f->steam_base_folder);
+  g_free (f->runtime);
+  g_free (f->pinned_32);
+  g_free (f->pinned_64);
+  g_free (f->i386_lib_i386);
+  g_free (f->i386_lib);
+  g_free (f->i386_usr_lib_i386);
+  g_free (f->i386_usr_lib);
+  g_free (f->i386_usr_bin);
+  g_free (f->amd64_lib_64);
+  g_free (f->amd64_lib);
+  g_free (f->amd64_usr_lib_64);
+  g_free (f->amd64_usr_lib);
+  g_free (f->amd64_bin);
+  g_free (f->amd64_usr_bin);
+  g_strfreev (f->env);
+
+  g_slice_free (FakeHome, f);
+}
diff --git a/tests/fake-home.h b/tests/fake-home.h
new file mode 100644
index 0000000000000000000000000000000000000000..60a9846c0ace729554c7f7263eff9d0a3014d833
--- /dev/null
+++ b/tests/fake-home.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright © 2019 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.
+ */
+
+#pragma once
+
+#include <glib.h>
+#include <glib-object.h>
+
+typedef struct
+{
+  gboolean create_pinning_libs;
+  gboolean create_i386_folders;
+  gboolean create_amd64_folders;
+  gboolean create_steam_symlink;
+  gboolean create_steamrt_files;
+  gboolean add_environments;
+  gboolean has_debian_bug_916303;
+
+  gchar *home;
+  gchar *steam_base_folder;
+  gchar *runtime;
+  gchar *pinned_32;
+  gchar *pinned_64;
+  gchar *i386_lib_i386;
+  gchar *i386_lib;
+  gchar *i386_usr_lib_i386;
+  gchar *i386_usr_lib;
+  gchar *i386_usr_bin;
+  gchar *amd64_lib_64;
+  gchar *amd64_lib;
+  gchar *amd64_usr_lib_64;
+  gchar *amd64_usr_lib;
+  gchar *amd64_bin;
+  gchar *amd64_usr_bin;
+  GStrv env;
+} FakeHome;
+
+FakeHome * fake_home_new (void);
+gboolean fake_home_create_structure (FakeHome *fake_home);
+void fake_home_clean_up (FakeHome *f);
diff --git a/tests/meson.build b/tests/meson.build
index 53a323a8aaf07477412fdbcad6ae68cad1947451..12f2363e29678d044babd1916af99b14abe0f400 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -34,6 +34,11 @@ tests = [
   'system-info-cli',
 ]
 
+tests_utils = [
+  'fake-home.c',
+  'test-utils.c',
+]
+
 tests_dir = join_paths(
   get_option('libexecdir'),
   'installed-tests',
@@ -52,7 +57,7 @@ install_subdir('fake-steam-runtime', install_dir : tests_dir)
 foreach test_name : tests
   exe = executable(
     'test-' + test_name,
-    files(test_name + '.c'),
+    files(test_name + '.c') + tests_utils,
     c_args : [
       '-D_SRT_MULTIARCH="' + multiarch + '"',
     ],
diff --git a/tests/system-info-cli.c b/tests/system-info-cli.c
index f80e912f9f91daa7a0b87269f8a7504743ccfb22..93615bb96f8336ee7d0edafffd9a9d4860551b0d 100644
--- a/tests/system-info-cli.c
+++ b/tests/system-info-cli.c
@@ -39,6 +39,7 @@
 #include <json-glib/json-glib.h>
 
 #include "test-utils.h"
+#include "fake-home.h"
 
 static const char *argv0;
 static const char * const multiarch_tuples[] = { SRT_ABI_I386, SRT_ABI_X86_64 };
@@ -346,6 +347,10 @@ libraries_presence_verbose (Fixture *f,
 
   g_assert_true (json_object_has_member (json, "can-write-uinput"));
   
+  g_assert_true (json_object_has_member (json, "steam-installation"));
+
+  g_assert_true (json_object_has_member (json, "runtime"));
+
   g_assert_true (json_object_has_member (json, "architectures"));
   json = json_object_get_object_member (json, "architectures");
 
@@ -384,7 +389,6 @@ no_arguments (Fixture *f,
   GError *error = NULL;
   gchar *output = NULL;
   SrtSystemInfo *info = srt_system_info_new (NULL);
-  gchar *expectations_in = g_build_filename (f->srcdir, "expectations", NULL);
   const gchar *argv[] = { "steam-runtime-system-info", NULL };
 
   g_assert_true (g_spawn_sync (NULL,    /* working directory */
@@ -424,7 +428,186 @@ no_arguments (Fixture *f,
   
   g_object_unref (parser);
   g_object_unref (info);
-  g_free (expectations_in);
+  g_free (output);
+  g_clear_error (&error);
+}
+
+/*
+ * Test a system with a good Steam installation.
+ */
+static void
+steam_presence (Fixture *f,
+                gconstpointer context)
+{
+  int exit_status = -1;
+  JsonParser *parser = NULL;
+  JsonNode *node = NULL;
+  JsonObject *json;
+  JsonObject *json_sub_object;
+  JsonArray *array;
+  GError *error = NULL;
+  gchar *output = NULL;
+  const gchar *path = NULL;
+  const gchar *version = NULL;
+  SrtSystemInfo *info = srt_system_info_new (NULL);
+  const gchar *argv[] = { "steam-runtime-system-info", NULL };
+  FakeHome *fake_home;
+
+  fake_home = fake_home_new ();
+  fake_home_create_structure (fake_home);
+
+  g_assert_true (g_spawn_sync (NULL,    /* working directory */
+                               (gchar **) argv,
+                               fake_home->env, /* envp */
+                               G_SPAWN_SEARCH_PATH,
+                               NULL,    /* child setup */
+                               NULL,    /* user data */
+                               &output, /* stdout */
+                               NULL,    /* stderr */
+                               &exit_status,
+                               &error));
+  g_assert_cmpint (exit_status, ==, 0);
+  g_assert_null (error);
+  g_assert_nonnull (output);
+
+  /* We can't use `json_from_string()` directly because we are targeting an
+   * older json-glib version */
+  parser = json_parser_new ();
+  g_assert_true (json_parser_load_from_data (parser, output, -1, NULL));
+  node = json_parser_get_root (parser);
+  json = json_node_get_object (node);
+
+  g_assert_true (json_object_has_member (json, "can-write-uinput"));
+  
+  g_assert_true (json_object_has_member (json, "steam-installation"));
+  json_sub_object = json_object_get_object_member (json, "steam-installation");
+
+  g_assert_true (json_object_has_member (json_sub_object, "path"));
+  path = json_object_get_string_member (json_sub_object, "path");
+  g_assert_cmpstr (path, !=, NULL);
+  g_assert_true (path[0] == '/');
+
+  g_assert_true (json_object_has_member (json_sub_object, "issues"));
+  array = json_object_get_array_member (json_sub_object, "issues");
+  g_assert_cmpint (json_array_get_length (array), ==, 0);
+
+  g_assert_true (json_object_has_member (json, "runtime"));
+  json_sub_object = json_object_get_object_member (json, "runtime");
+
+  g_assert_true (json_object_has_member (json_sub_object, "path"));
+  path = json_object_get_string_member (json_sub_object, "path");
+  g_assert_cmpstr (path, !=, NULL);
+  g_assert_true (path[0] == '/');
+
+  g_assert_true (json_object_has_member (json_sub_object, "version"));
+  version = json_object_get_string_member (json_sub_object, "version");
+  g_assert_cmpstr (version, !=, NULL);
+
+  g_assert_true (json_object_has_member (json_sub_object, "issues"));
+  array = json_object_get_array_member (json_sub_object, "issues");
+  g_assert_cmpint (json_array_get_length (array), ==, 0);
+
+  g_assert_true (json_object_has_member (json, "architectures"));
+  
+  fake_home_clean_up (fake_home);
+  g_object_unref (parser);
+  g_object_unref (info);
+  g_free (output);
+  g_clear_error (&error);
+}
+
+/*
+ * Test a system with a Steam installation with issues.
+ */
+static void
+steam_issues (Fixture *f,
+                gconstpointer context)
+{
+  int exit_status = -1;
+  JsonParser *parser = NULL;
+  JsonNode *node = NULL;
+  JsonObject *json;
+  JsonObject *json_sub_object;
+  JsonArray *array;
+  GError *error = NULL;
+  gchar *output = NULL;
+  const gchar *path = NULL;
+  const gchar *version = NULL;
+  SrtSystemInfo *info = srt_system_info_new (NULL);
+  const gchar *argv[] = { "steam-runtime-system-info", NULL };
+  FakeHome *fake_home;
+
+  g_assert_true (TRUE);
+
+  fake_home = fake_home_new ();
+  fake_home->create_pinning_libs = FALSE;
+  fake_home->create_steam_symlink = FALSE;
+  fake_home->create_steamrt_files = FALSE;
+  fake_home_create_structure (fake_home);
+
+  g_assert_true (g_spawn_sync (NULL,    /* working directory */
+                               (gchar **) argv,
+                               fake_home->env, /* envp */
+                               G_SPAWN_SEARCH_PATH,
+                               NULL,    /* child setup */
+                               NULL,    /* user data */
+                               &output, /* stdout */
+                               NULL,    /* stderr */
+                               &exit_status,
+                               &error));
+  g_assert_cmpint (exit_status, ==, 0);
+  g_assert_null (error);
+  g_assert_nonnull (output);
+
+  /* We can't use `json_from_string()` directly because we are targeting an
+   * older json-glib version */
+  parser = json_parser_new ();
+  g_assert_true (json_parser_load_from_data (parser, output, -1, NULL));
+  node = json_parser_get_root (parser);
+  json = json_node_get_object (node);
+
+  g_assert_true (json_object_has_member (json, "can-write-uinput"));
+  
+
+  g_assert_true (json_object_has_member (json, "steam-installation"));
+  json_sub_object = json_object_get_object_member (json, "steam-installation");
+
+  g_assert_true (json_object_has_member (json_sub_object, "path"));
+  path = json_object_get_string_member (json_sub_object, "path");
+  g_assert_cmpstr (path, !=, NULL);
+  g_assert_true (path[0] == '/');
+
+  g_assert_true (json_object_has_member (json_sub_object, "issues"));
+  array = json_object_get_array_member (json_sub_object, "issues");
+  g_assert_cmpint (json_array_get_length (array), ==, 1);
+  g_assert_cmpstr (json_array_get_string_element (array, 0), ==,
+                   "dot-steam-steam-not-symlink");
+
+  g_assert_true (json_object_has_member (json, "runtime"));
+  json_sub_object = json_object_get_object_member (json, "runtime");
+
+  g_assert_true (json_object_has_member (json_sub_object, "path"));
+  path = json_object_get_string_member (json_sub_object, "path");
+  g_assert_cmpstr (path, !=, NULL);
+  g_assert_true (path[0] == '/');
+
+  g_assert_true (json_object_has_member (json_sub_object, "version"));
+  version = json_object_get_string_member (json_sub_object, "version");
+  g_assert_cmpstr (version, ==, NULL);
+
+  g_assert_true (json_object_has_member (json_sub_object, "issues"));
+  array = json_object_get_array_member (json_sub_object, "issues");
+  g_assert_cmpint (json_array_get_length (array), ==, 2);
+  g_assert_cmpstr (json_array_get_string_element (array, 0), ==,
+                   "not-runtime");
+  g_assert_cmpstr (json_array_get_string_element (array, 1), ==,
+                   "not-using-newer-host-libraries");
+
+  g_assert_true (json_object_has_member (json, "architectures"));
+  
+  fake_home_clean_up (fake_home);
+  g_object_unref (parser);
+  g_object_unref (info);
   g_free (output);
   g_clear_error (&error);
 }
@@ -436,14 +619,18 @@ main (int argc,
   argv0 = argv[0];
 
   g_test_init (&argc, &argv, NULL);
-  g_test_add ("/system-info/libraries_presence", Fixture, NULL,
+  g_test_add ("/system-info-cli/libraries_presence", Fixture, NULL,
               setup, libraries_presence, teardown);
-  g_test_add ("/system-info/libraries_missing", Fixture, NULL,
+  g_test_add ("/system-info-cli/libraries_missing", Fixture, NULL,
               setup, libraries_missing, teardown);
-  g_test_add ("/system-info/libraries_presence_verbose", Fixture, NULL,
+  g_test_add ("/system-info-cli/libraries_presence_verbose", Fixture, NULL,
               setup, libraries_presence_verbose, teardown);
-  g_test_add ("/system-info/no_arguments", Fixture, NULL,
+  g_test_add ("/system-info-cli/no_arguments", Fixture, NULL,
               setup, no_arguments, teardown);
+  g_test_add ("/system-info-cli/steam_presence", Fixture, NULL,
+              setup, steam_presence, teardown);
+  g_test_add ("/system-info-cli/steam_issues", Fixture, NULL,
+              setup, steam_issues, teardown);
 
   return g_test_run ();
 }
diff --git a/tests/system-info.c b/tests/system-info.c
index afe4d58b1c1a9da6bc8c40b04630d6eb941dcda9..b7d73821e6c75483bd62cbc13609d329c32ed7bc 100644
--- a/tests/system-info.c
+++ b/tests/system-info.c
@@ -29,14 +29,17 @@
 
 #include <glib.h>
 #include <glib/gstdio.h>
+#include <gio/gio.h>
 
 #include <fcntl.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <ftw.h>
 
 #include "test-utils.h"
+#include "fake-home.h"
 
 static const char *argv0;
 
@@ -679,6 +682,497 @@ wrong_expectations (Fixture *f,
   g_object_unref (info);
 }
 
+static void
+steam_runtime (Fixture *f,
+               gconstpointer context)
+{
+  SrtSystemInfo *info;
+  SrtRuntimeIssues runtime_issues;
+  SrtSteamIssues steam_issues;
+  gchar *runtime_path = NULL;
+  gchar *installation_path = NULL;
+  FakeHome *fake_home;
+
+  fake_home = fake_home_new ();
+  fake_home_create_structure (fake_home);
+
+  info = srt_system_info_new (NULL);
+  srt_system_info_set_environ (info, fake_home->env);
+
+  /* Check for runtime issues */
+  runtime_issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (runtime_issues, ==, SRT_RUNTIME_ISSUES_NONE);
+  runtime_path = srt_system_info_dup_runtime_path (info);
+  g_assert_cmpstr (runtime_path, ==, fake_home->runtime);
+  installation_path = srt_system_info_dup_steam_installation_path (info);
+  g_assert_cmpstr (installation_path, ==, fake_home->steam_base_folder);
+  g_free (runtime_path);
+  g_free (installation_path);
+
+  /* Do the check again, this time using the cache */
+  runtime_issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (runtime_issues, ==, SRT_RUNTIME_ISSUES_NONE);
+  runtime_path = srt_system_info_dup_runtime_path (info);
+  g_assert_cmpstr (runtime_path, ==, fake_home->runtime);
+  installation_path = srt_system_info_dup_steam_installation_path (info);
+  g_assert_cmpstr (installation_path, ==, fake_home->steam_base_folder);
+
+  /* Check for Steam issues */
+  steam_issues = srt_system_info_get_steam_issues (info);
+  g_assert_cmpint (steam_issues, ==, SRT_RUNTIME_ISSUES_NONE);
+
+  /* Do the check again, this time using the cache */
+  steam_issues = srt_system_info_get_steam_issues (info);
+  g_assert_cmpint (steam_issues, ==, SRT_RUNTIME_ISSUES_NONE);
+
+  fake_home_clean_up (fake_home);
+  g_object_unref (info);
+  g_free (runtime_path);
+  g_free (installation_path);
+}
+
+static void
+steam_runtime_missing (Fixture *f,
+                       gconstpointer context)
+{
+  SrtSystemInfo *info;
+  SrtRuntimeIssues runtime_issues;
+  SrtSteamIssues steam_issues;
+  gchar *full_ld_path = NULL;
+  FakeHome *fake_home;
+
+  fake_home = fake_home_new ();
+  fake_home_create_structure (fake_home);
+
+  full_ld_path = g_strdup (g_environ_getenv (fake_home->env, "LD_LIBRARY_PATH"));
+
+  info = srt_system_info_new (NULL);
+
+  /* Unset LD_LIBRARY_PATH */
+  fake_home->env = g_environ_unsetenv (fake_home->env, "LD_LIBRARY_PATH");
+  srt_system_info_set_environ (info, fake_home->env);
+  runtime_issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (runtime_issues, ==, SRT_RUNTIME_ISSUES_NOT_IN_LD_PATH);
+
+  /* Re set LD_LIBRARY_PATH and remove a required folder from the runtime */
+  fake_home->env = g_environ_setenv (fake_home->env, "LD_LIBRARY_PATH", full_ld_path, TRUE);
+  srt_system_info_set_environ (info, fake_home->env);
+  g_assert_cmpint (g_rmdir (fake_home->amd64_usr_lib_64), ==, 0);
+  runtime_issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (runtime_issues & SRT_RUNTIME_ISSUES_NOT_RUNTIME, !=, 0);
+  g_assert_cmpint (runtime_issues & SRT_RUNTIME_ISSUES_NOT_IN_LD_PATH, !=, 0);
+  steam_issues = srt_system_info_get_steam_issues (info);
+  g_assert_cmpint (steam_issues, ==, SRT_STEAM_ISSUES_NONE);
+
+  /* Do the check again, this time using the cache */
+  runtime_issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (runtime_issues & SRT_RUNTIME_ISSUES_NOT_RUNTIME, !=, 0);
+  g_assert_cmpint (runtime_issues & SRT_RUNTIME_ISSUES_NOT_IN_LD_PATH, !=, 0);
+  steam_issues = srt_system_info_get_steam_issues (info);
+  g_assert_cmpint (steam_issues, ==, SRT_STEAM_ISSUES_NONE);
+
+  fake_home_clean_up (fake_home);
+  g_object_unref (info);
+  g_free (full_ld_path);
+}
+
+static void
+steam_runtime_pinned (Fixture *f,
+                      gconstpointer context)
+{
+  SrtSystemInfo *info;
+  SrtRuntimeIssues issues;
+  gchar *full_ld_path = NULL;
+  gchar *ld_path = NULL;
+  FakeHome *fake_home;
+
+  fake_home = fake_home_new ();
+  fake_home_create_structure (fake_home);
+
+  full_ld_path = g_strdup (g_environ_getenv (fake_home->env, "LD_LIBRARY_PATH"));
+
+  info = srt_system_info_new (NULL);
+
+  /* Move the pinned libraries at the end of LD_LIBRARY_PATH */
+  ld_path = g_strjoin (":",
+                       fake_home->i386_lib_i386,
+                       fake_home->i386_lib,
+                       fake_home->i386_usr_lib_i386,
+                       fake_home->i386_usr_lib,
+                       fake_home->amd64_lib_64,
+                       fake_home->amd64_lib,
+                       fake_home->amd64_usr_lib_64,
+                       fake_home->amd64_usr_lib,
+                       fake_home->pinned_32,
+                       fake_home->pinned_64,
+                       NULL);
+  fake_home->env = g_environ_setenv (fake_home->env, "LD_LIBRARY_PATH", ld_path, TRUE);
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (SRT_RUNTIME_ISSUES_NOT_USING_NEWER_HOST_LIBRARIES, ==, issues);
+  g_free (ld_path);
+
+  /* Remove the pinned library folder */
+  g_assert_cmpint (g_rmdir (fake_home->pinned_32), ==, 0);
+  g_assert_cmpint (g_rmdir (fake_home->pinned_64), ==, 0);
+  fake_home->env = g_environ_setenv (fake_home->env, "LD_LIBRARY_PATH", full_ld_path, TRUE);
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (SRT_RUNTIME_ISSUES_NOT_USING_NEWER_HOST_LIBRARIES, ==, issues);
+
+  /* Remove pinned libraries from LD_LIBRARY_PATH */
+  ld_path = g_strjoin (":",
+                       fake_home->i386_lib_i386,
+                       fake_home->i386_lib,
+                       fake_home->i386_usr_lib_i386,
+                       fake_home->i386_usr_lib,
+                       fake_home->amd64_lib_64,
+                       fake_home->amd64_lib,
+                       fake_home->amd64_usr_lib_64,
+                       fake_home->amd64_usr_lib,
+                       NULL);
+  fake_home->env = g_environ_setenv (fake_home->env, "LD_LIBRARY_PATH", ld_path, TRUE);
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (SRT_RUNTIME_ISSUES_NOT_USING_NEWER_HOST_LIBRARIES, ==, issues);
+
+  fake_home_clean_up (fake_home);
+  g_object_unref (info);
+  g_free (full_ld_path);
+  g_free (ld_path);
+}
+
+static void
+runtime_disabled_or_missing (Fixture *f,
+                             gconstpointer context)
+{
+  SrtSystemInfo *info;
+  SrtRuntimeIssues issues;
+  gchar *runtime_path = NULL;
+  FakeHome *fake_home;
+
+  fake_home = fake_home_new ();
+  fake_home->create_steamrt_files = FALSE;
+  fake_home_create_structure (fake_home);
+
+  info = srt_system_info_new (NULL);
+
+  /* Completely disable the runtime */
+  fake_home->env = g_environ_setenv (fake_home->env, "STEAM_RUNTIME", "0", TRUE);
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (issues, ==, SRT_RUNTIME_ISSUES_DISABLED);
+  runtime_path = srt_system_info_dup_runtime_path (info);
+  g_assert_cmpstr (runtime_path, ==, NULL);
+
+  /* Set the runtime to a relative position.
+   * Test if we can revover using the expected path.
+   * We didn't create SteamRT files so expect to receive a "not_runtime"
+   * issue. */
+  fake_home->env = g_environ_setenv (fake_home->env, "STEAM_RUNTIME", "my/not/absolute/runtime/path", TRUE);
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (SRT_RUNTIME_ISSUES_NOT_IN_ENVIRONMENT |
+                   SRT_RUNTIME_ISSUES_NOT_RUNTIME, ==, issues);
+
+  /* Remove the STEAM_RUNTIME environment. */
+  fake_home->env = g_environ_unsetenv (fake_home->env, "STEAM_RUNTIME");
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (SRT_RUNTIME_ISSUES_NOT_IN_ENVIRONMENT |
+                   SRT_RUNTIME_ISSUES_NOT_RUNTIME, ==, issues);
+
+  /* Disable prefer host libraries */
+  fake_home->env = g_environ_setenv (fake_home->env, "STEAM_RUNTIME_PREFER_HOST_LIBRARIES", "0", TRUE);
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (SRT_RUNTIME_ISSUES_NOT_USING_NEWER_HOST_LIBRARIES |
+                   SRT_RUNTIME_ISSUES_NOT_IN_ENVIRONMENT |
+                   SRT_RUNTIME_ISSUES_NOT_RUNTIME, ==, issues);
+
+  fake_home_clean_up (fake_home);
+  g_object_unref (info);
+}
+
+static void
+runtime_version (Fixture *f,
+                 gconstpointer context)
+{
+  SrtSystemInfo *info;
+  SrtRuntimeIssues issues;
+  gchar *version = NULL;
+  gchar *dup_version = NULL;
+  GError *error = NULL;
+  FakeHome *fake_home;
+
+  fake_home = fake_home_new ();
+  fake_home_create_structure (fake_home);
+
+  version = g_build_filename (fake_home->runtime, "version.txt", NULL);
+  info = srt_system_info_new (NULL);
+
+  /* Check version with a trailing new line */
+  g_file_set_contents (version, "steam-runtime_0.20190711.3\n", -1, &error);
+  g_assert_no_error (error);
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (issues, ==, SRT_RUNTIME_ISSUES_NONE);
+
+  /* Check version with an empty number */
+  g_file_set_contents (version, "steam-runtime_", -1, &error);
+  g_assert_no_error (error);
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (issues, ==, SRT_RUNTIME_ISSUES_NOT_RUNTIME);
+
+  /* Check version without underscore */
+  g_file_set_contents (version, "steam-runtime", -1, &error);
+  g_assert_no_error (error);
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (issues, ==, SRT_RUNTIME_ISSUES_NOT_RUNTIME);
+  dup_version = srt_system_info_dup_runtime_version (info);
+  g_assert_cmpstr (dup_version, ==, NULL);
+
+  /* Check version with a custom prefix */
+  g_file_set_contents (version, "custom-steam-runtime_0.20190711.3", -1, &error);
+  g_assert_no_error (error);
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (issues, ==, SRT_RUNTIME_ISSUES_UNOFFICIAL);
+
+  /* Check version with a custom prefix and multiple underscores */
+  g_file_set_contents (version, "custom_steam_runtime_0.20190711.3", -1, &error);
+  g_assert_no_error (error);
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (issues, ==, SRT_RUNTIME_ISSUES_UNOFFICIAL);
+  dup_version = srt_system_info_dup_runtime_version (info);
+  g_assert_cmpstr (dup_version, ==, "0.20190711.3");
+  g_free (dup_version);
+
+  /* Check an empty version file */
+  g_file_set_contents (version, "", -1, &error);
+  g_assert_no_error (error);
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (issues, ==, SRT_RUNTIME_ISSUES_NOT_RUNTIME);
+  dup_version = srt_system_info_dup_runtime_version (info);
+  g_assert_cmpstr (dup_version, ==, NULL);
+
+  /* Check expected version */
+  g_file_set_contents (version, "steam-runtime_0.20190711.3", -1, &error);
+  g_assert_no_error (error);
+  srt_system_info_set_expected_runtime_version (info, "0.20190711.3");
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (issues, ==, SRT_RUNTIME_ISSUES_NONE);
+
+  /* Check expected version with trailing new line */
+  g_file_set_contents (version, "steam-runtime_0.20190711.3\n", -1, &error);
+  g_assert_no_error (error);
+  srt_system_info_set_expected_runtime_version (info, "0.20190711.3");
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (issues, ==, SRT_RUNTIME_ISSUES_NONE);
+
+  /* Check wrong expected version */
+  g_file_set_contents (version, "steam-runtime_0.20190711.3", -1, &error);
+  g_assert_no_error (error);
+  srt_system_info_set_expected_runtime_version (info, "0.20210813.4");
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (issues, ==, SRT_RUNTIME_ISSUES_UNEXPECTED_VERSION);
+
+  /* Check wrong expected version */
+  g_file_set_contents (version, "steam-runtime_", -1, &error);
+  g_assert_no_error (error);
+  srt_system_info_set_expected_runtime_version (info, "0.20180101.2");
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (SRT_RUNTIME_ISSUES_NOT_RUNTIME |
+                   SRT_RUNTIME_ISSUES_UNEXPECTED_VERSION, ==, issues);
+  dup_version = srt_system_info_dup_runtime_version (info);
+  g_assert_cmpstr (dup_version, ==, "");
+
+  /* Check expected version with custom prefix */
+  g_file_set_contents (version, "my-custom_steam_runtime_0.20190711.3", -1, &error);
+  g_assert_no_error (error);
+  srt_system_info_set_expected_runtime_version (info, "0.20190711.3");
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (issues, ==, SRT_RUNTIME_ISSUES_UNOFFICIAL);
+
+  fake_home_clean_up (fake_home);
+  g_object_unref (info);
+  g_free (version);
+  g_free (dup_version);
+}
+
+static void
+runtime_unexpected_location (Fixture *f,
+                             gconstpointer context)
+{
+  SrtSystemInfo *info;
+  SrtRuntimeIssues issues;
+  gchar *dot_steam_steam = NULL;
+  gchar *my_runtime = NULL;
+  gchar *ld_path = NULL;
+  gchar *env_path = NULL;
+  gchar **parts = NULL;
+  GFile *symlink = NULL;
+  GError *error = NULL;
+  FakeHome *fake_home;
+
+  fake_home = fake_home_new ();
+  fake_home->create_steam_symlink = FALSE;
+  fake_home_create_structure (fake_home);
+
+  info = srt_system_info_new (NULL);
+  dot_steam_steam = g_build_filename (fake_home->home, ".steam", "steam", NULL);
+
+  my_runtime = g_build_filename (fake_home->steam_base_folder, "ubuntu12_32",
+                                 "my-runtime", NULL);
+
+
+  /* Create a new homedir/.steam/steam symlink that doesn't point to
+   * the expected steam runtime path. */
+  symlink = g_file_new_for_path (dot_steam_steam);
+  g_file_make_symbolic_link (symlink, fake_home->pinned_64, NULL, &error);
+  g_assert_no_error (error);
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (issues, ==, SRT_RUNTIME_ISSUES_UNEXPECTED_LOCATION);
+  g_object_unref (symlink);
+
+  /* Move the steam-runtime to another location called "my-runtime" and
+   * adjust all the environment variables accordingly. */
+  ld_path = g_strdup (g_environ_getenv (fake_home->env, "LD_LIBRARY_PATH"));
+  parts = g_strsplit (ld_path, "steam-runtime", -1);
+  g_free (ld_path);
+  ld_path = g_strjoinv ("my-runtime", parts);
+  g_strfreev (parts);
+
+  env_path = g_strdup (g_environ_getenv (fake_home->env, "PATH"));
+  parts = g_strsplit (env_path, "steam-runtime", -1);
+  g_free (env_path);
+  env_path = g_strjoinv ("my-runtime", parts);
+
+  g_rename (fake_home->runtime, my_runtime);
+  g_remove (dot_steam_steam);
+  symlink = g_file_new_for_path (dot_steam_steam);
+  g_file_make_symbolic_link (symlink, my_runtime, NULL, &error);
+  g_assert_no_error (error);
+  fake_home->env = g_environ_setenv (fake_home->env, "LD_LIBRARY_PATH", ld_path, TRUE);
+  fake_home->env = g_environ_setenv (fake_home->env, "STEAM_RUNTIME", my_runtime, TRUE);
+  fake_home->env = g_environ_setenv (fake_home->env, "PATH", env_path, TRUE);
+
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_runtime_issues (info);
+  g_assert_cmpint (issues, ==, SRT_RUNTIME_ISSUES_UNEXPECTED_LOCATION);
+
+  fake_home_clean_up (fake_home);
+  g_object_unref (symlink);
+  g_object_unref (info);
+  g_free (dot_steam_steam);
+  g_free (my_runtime);
+  g_free (ld_path);
+  g_free (env_path);
+  g_strfreev (parts);
+}
+
+static void
+steam_symlink (Fixture *f,
+               gconstpointer context)
+{
+  SrtSystemInfo *info;
+  SrtSteamIssues issues;
+  gchar *data_home = NULL;
+  gchar *dot_steam_steam = NULL;
+  gchar *dot_steam_root = NULL;
+  gchar *dot_steam_bin32 = NULL;
+  gchar *installation_path = NULL;
+  gchar *ubuntu12_32 = NULL;
+  GFile *symlink = NULL;
+  GError *error = NULL;
+  FakeHome *fake_home;
+
+  fake_home = fake_home_new ();
+  fake_home->create_steam_symlink = FALSE;
+  fake_home_create_structure (fake_home);
+
+  info = srt_system_info_new (NULL);
+  dot_steam_steam = g_build_filename (fake_home->home, ".steam", "steam", NULL);
+  dot_steam_root = g_build_filename (fake_home->home, ".steam", "root", NULL);
+  dot_steam_bin32 = g_build_filename (fake_home->home, ".steam", "bin32", NULL);
+  ubuntu12_32 = g_build_filename (fake_home->steam_base_folder, "ubuntu12_32", NULL);
+
+  /* We don't have a homedir/.steam/steam symlink. */
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_steam_issues (info);
+  g_assert_cmpint (SRT_STEAM_ISSUES_DOT_STEAM_STEAM_NOT_SYMLINK, ==, issues);
+
+  /* Create the homedir/.steam/root symlink. */
+  symlink = g_file_new_for_path (dot_steam_root);
+  g_file_make_symbolic_link (symlink, fake_home->steam_base_folder, NULL, &error);
+  g_assert_no_error (error);
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_steam_issues (info);
+  g_assert_cmpint (SRT_STEAM_ISSUES_DOT_STEAM_STEAM_NOT_SYMLINK, ==, issues);
+  g_object_unref (symlink);
+
+  /* Remove homedir/.steam/root symlink and create homedir/.steam/bin32 symlink. */
+  g_remove (dot_steam_root);
+  symlink = g_file_new_for_path (dot_steam_bin32);
+  g_file_make_symbolic_link (symlink, ubuntu12_32, NULL, &error);
+  g_assert_no_error (error);
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_steam_issues (info);
+  g_assert_cmpint (SRT_STEAM_ISSUES_DOT_STEAM_STEAM_NOT_SYMLINK, ==, issues);
+
+  /* Remove the homedir/.steam/bin32 symlink and set XDG_DATA_HOME env to a
+   * folder that is not the expected homedir/.local/share */
+  g_remove (dot_steam_bin32);
+  data_home = g_build_filename (fake_home->home, "DataHome", NULL);
+  fake_home->env = g_environ_setenv (fake_home->env, "XDG_DATA_HOME", data_home, TRUE);
+  srt_system_info_set_environ (info, fake_home->env);
+  issues = srt_system_info_get_steam_issues (info);
+  g_assert_cmpint (SRT_STEAM_ISSUES_CANNOT_FIND |
+                   SRT_STEAM_ISSUES_DOT_STEAM_STEAM_NOT_SYMLINK, ==, issues);
+  installation_path = srt_system_info_dup_steam_installation_path (info);
+  g_assert_cmpstr (installation_path, ==, NULL);
+
+  fake_home_clean_up (fake_home);
+  g_object_unref (symlink);
+  g_object_unref (info);
+  g_free (data_home);
+  g_free (dot_steam_steam);
+  g_free (dot_steam_root);
+  g_free (dot_steam_bin32);
+  g_free (ubuntu12_32);
+}
+
+/* Recreate the conditions that triggered the Debian bug 916303.
+ * Steam was installed into "~/.steam", which meant that the "steam/"
+ * directory inside the Steam installation collided with the "~/.steam/steam"
+ * symlink, preventing the symlink from being created. */
+static void
+debian_bug_916303 (Fixture *f,
+                   gconstpointer context)
+{
+  SrtSystemInfo *info;
+  SrtSteamIssues issues;
+  FakeHome *fake_home;
+
+  fake_home = fake_home_new ();
+  fake_home->has_debian_bug_916303 = TRUE;
+  fake_home_create_structure (fake_home);
+
+  info = srt_system_info_new (NULL);
+  srt_system_info_set_environ (info, fake_home->env);
+
+  issues = srt_system_info_get_steam_issues (info);
+  g_assert_cmpint (issues, ==, SRT_STEAM_ISSUES_DOT_STEAM_STEAM_NOT_SYMLINK);
+
+  fake_home_clean_up (fake_home);
+  g_object_unref (info);
+}
+
 int
 main (int argc,
       char **argv)
@@ -701,5 +1195,22 @@ main (int argc,
   g_test_add ("/system-info/wrong_expectations", Fixture, NULL,
               setup, wrong_expectations, teardown);
 
+  g_test_add ("/system-info/steam_runtime", Fixture, NULL,
+              setup, steam_runtime, teardown);
+  g_test_add ("/system-info/steam_runtime_missing", Fixture, NULL,
+              setup, steam_runtime_missing, teardown);
+  g_test_add ("/system-info/steam_runtime_pinned", Fixture, NULL,
+              setup, steam_runtime_pinned, teardown);
+  g_test_add ("/system-info/runtime_disabled_or_missing", Fixture, NULL,
+              setup, runtime_disabled_or_missing, teardown);
+  g_test_add ("/system-info/runtime_version", Fixture, NULL,
+              setup, runtime_version, teardown);
+  g_test_add ("/system-info/runtime_unexpected_location", Fixture, NULL,
+              setup, runtime_unexpected_location, teardown);
+  g_test_add ("/system-info/steam_symlink", Fixture, NULL,
+              setup, steam_symlink, teardown);
+  g_test_add ("/system-info/debian_bug_916303", Fixture, NULL,
+              setup, debian_bug_916303, teardown);
+
   return g_test_run ();
 }
diff --git a/tests/test-utils.c b/tests/test-utils.c
new file mode 100644
index 0000000000000000000000000000000000000000..969c790a8198b673764b0a9cec5f00be5a8ee28c
--- /dev/null
+++ b/tests/test-utils.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2019 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 "test-utils.h"
+
+#include <ftw.h>
+#include <glib.h>
+#include <stdio.h>
+
+static gint
+ftw_remove (const gchar *path,
+            const struct stat *sb,
+            gint typeflags,
+            struct FTW *ftwbuf)
+{
+  if (remove (path) < 0)
+    return -1;
+
+  return 0;
+}
+
+/**
+ * rm_rf:
+ * @directory: (type filename): The folder to remove.
+ *
+ * Recursively delete @directory within the same file system and
+ * without following symbolic links.
+ *
+ * Returns: %TRUE if the removal was successful
+ */
+gboolean rm_rf (char *directory)
+{
+  g_return_val_if_fail (directory != NULL, FALSE);
+
+  if (nftw (directory, ftw_remove, 10, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) < 0)
+    return FALSE;
+
+  return TRUE;
+}
\ No newline at end of file
diff --git a/tests/test-utils.h b/tests/test-utils.h
index e963a25495cc255fcff308d79ac4162e1ff079f8..8bb481e427984417e999b1d7dbf8836e10c45a44 100644
--- a/tests/test-utils.h
+++ b/tests/test-utils.h
@@ -64,3 +64,5 @@
 #if !GLIB_CHECK_VERSION(2, 38, 0)
 #define g_test_skip(msg) g_test_message ("SKIP: %s", msg)
 #endif
+
+gboolean rm_rf (char *directory);