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);