From 01863ba4d230ef28c3ca5802fb9e78d2953e9450 Mon Sep 17 00:00:00 2001 From: Ludovico de Nittis <ludovico.denittis@collabora.com> Date: Wed, 7 Oct 2020 10:33:13 +0200 Subject: [PATCH] Include STEAMSCRIPT and STEAMSCRIPT_VERSION in the report These two environment variables can be useful for inferring how and which version of the Steam bootstrapper have been used. For example if the reported version is something like "1.0.0.63-1/Debian", we are quite sure that Steam has been installed using the package from Debian's non-free archive area. Signed-off-by: Ludovico de Nittis <ludovico.denittis@collabora.com> --- bin/meson.build | 2 +- bin/system-info.c | 11 +++ bin/system-info.md | 12 +++ steam-runtime-tools/steam-internal.h | 10 ++- steam-runtime-tools/steam.c | 107 +++++++++++++++++++++++- steam-runtime-tools/steam.h | 4 + steam-runtime-tools/system-info.c | 48 +++++++++++ steam-runtime-tools/system-info.h | 5 ++ tests/json-report/full-good-report.json | 2 + tests/json-report/partial-report-2.json | 4 +- tests/system-info-cli.c | 37 +++++++- tests/system-info.c | 53 ++++++++++++ 12 files changed, 288 insertions(+), 7 deletions(-) diff --git a/bin/meson.build b/bin/meson.build index d299b130a..01ff7eb7e 100644 --- a/bin/meson.build +++ b/bin/meson.build @@ -24,7 +24,7 @@ executable( 'steam-runtime-system-info', 'system-info.c', - dependencies : [glib, json_glib, libsteamrt_dep], + dependencies : [gio_unix, glib, json_glib, libglnx_dep, libsteamrt_dep], install : true, # Use the adjacent libsteam-runtime-tools and json-glib, ignoring # LD_LIBRARY_PATH even if set diff --git a/bin/system-info.c b/bin/system-info.c index 9034e28a1..66dab2c99 100644 --- a/bin/system-info.c +++ b/bin/system-info.c @@ -114,6 +114,8 @@ * A boolean: whether the character set is UTF-8 */ +#include <libglnx.h> + #include <steam-runtime-tools/steam-runtime-tools.h> #include <errno.h> @@ -787,6 +789,8 @@ main (int argc, JsonGenerator *generator; gboolean can_run = FALSE; const gchar *test_json_path = NULL; + g_autofree gchar *steamscript_path = NULL; + g_autofree gchar *steamscript_version = NULL; gchar *json_output; gchar *version = NULL; gchar *inst_path = NULL; @@ -894,6 +898,13 @@ main (int argc, json_builder_set_member_name (builder, "bin32_path"); bin32_path = srt_system_info_dup_steam_bin32_path (info); json_builder_add_string_value (builder, bin32_path); + json_builder_set_member_name (builder, "steamscript_path"); + steamscript_path = srt_system_info_dup_steamscript_path (info); + json_builder_add_string_value (builder, steamscript_path); + json_builder_set_member_name (builder, "steamscript_version"); + steamscript_version = srt_system_info_dup_steamscript_version (info); + json_builder_add_string_value (builder, steamscript_version); + json_builder_set_member_name (builder, "issues"); json_builder_begin_array (builder); steam_issues = srt_system_info_get_steam_issues (info); diff --git a/bin/system-info.md b/bin/system-info.md index b71411d93..25b896cc0 100644 --- a/bin/system-info.md +++ b/bin/system-info.md @@ -57,6 +57,18 @@ keys: This is usually a direct subdirectory of **path** but can differ under some circumstances. + **steamscript_path** + : A string: if **steam-runtime-system-info** was run by Steam, + the absolute path to the "bootstrapper" script used to launch + Steam, typically **/usr/bin/steam** or **/usr/games/steam**. + Otherwise, or if unavailable, it is **null**. + + **steamscript_version** + : A string: if **steam-runtime-system-info** was run by Steam, + the version of the "bootstrapper" script used to launch + Steam, for example **1.0.0.66** or **1.0.0.66-2/Debian**. + Otherwise, or if unavailable, it is **null**. + **issues** : An array of strings representing problems with the Steam installation. If empty, no problems were found. diff --git a/steam-runtime-tools/steam-internal.h b/steam-runtime-tools/steam-internal.h index 10ec22f19..6b91a63dd 100644 --- a/steam-runtime-tools/steam-internal.h +++ b/steam-runtime-tools/steam-internal.h @@ -40,20 +40,26 @@ static inline SrtSteam *_srt_steam_new (SrtSteamIssues issues, const char *install_path, const char *data_path, - const char *bin32_path); + const char *bin32_path, + const char *steamscript_path, + const char *steamscript_version); #ifndef __GTK_DOC_IGNORE__ static inline SrtSteam * _srt_steam_new (SrtSteamIssues issues, const char *install_path, const char *data_path, - const char *bin32_path) + const char *bin32_path, + const char *steamscript_path, + const char *steamscript_version) { return g_object_new (SRT_TYPE_STEAM, "issues", issues, "install-path", install_path, "data-path", data_path, "bin32-path", bin32_path, + "steamscript-path", steamscript_path, + "steamscript-version", steamscript_version, NULL); } #endif diff --git a/steam-runtime-tools/steam.c b/steam-runtime-tools/steam.c index 3cb2f583d..127742166 100644 --- a/steam-runtime-tools/steam.c +++ b/steam-runtime-tools/steam.c @@ -58,6 +58,8 @@ struct _SrtSteam gchar *install_path; gchar *data_path; gchar *bin32_path; + gchar *steamscript_path; + gchar *steamscript_version; }; struct _SrtSteamClass @@ -72,6 +74,8 @@ enum { PROP_INSTALL_PATH, PROP_DATA_PATH, PROP_BIN32_PATH, + PROP_STEAMSCRIPT_PATH, + PROP_STEAMSCRIPT_VERSION, N_PROPERTIES }; @@ -108,6 +112,14 @@ srt_steam_get_property (GObject *object, g_value_set_string (value, self->bin32_path); break; + case PROP_STEAMSCRIPT_PATH: + g_value_set_string (value, self->steamscript_path); + break; + + case PROP_STEAMSCRIPT_VERSION: + g_value_set_string (value, self->steamscript_version); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -147,6 +159,18 @@ srt_steam_set_property (GObject *object, self->bin32_path = g_value_dup_string (value); break; + case PROP_STEAMSCRIPT_PATH: + /* Construct only */ + g_return_if_fail (self->steamscript_path == NULL); + self->steamscript_path = g_value_dup_string (value); + break; + + case PROP_STEAMSCRIPT_VERSION: + /* Construct only */ + g_return_if_fail (self->steamscript_version == NULL); + self->steamscript_version = g_value_dup_string (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -160,6 +184,8 @@ srt_steam_finalize (GObject *object) g_free (self->install_path); g_free (self->data_path); g_free (self->bin32_path); + g_free (self->steamscript_path); + g_free (self->steamscript_version); G_OBJECT_CLASS (srt_steam_parent_class)->finalize (object); } @@ -204,6 +230,22 @@ srt_steam_class_init (SrtSteamClass *cls) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + properties[PROP_STEAMSCRIPT_PATH] = + g_param_spec_string ("steamscript-path", "Steamscript path", + "Absolute path to the bootstrapper script used to " + "launch Steam", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + properties[PROP_STEAMSCRIPT_VERSION] = + g_param_spec_string ("steamscript-version", "Steamscript version", + "Version of the bootstrapper script used to launch " + "Steam", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, N_PROPERTIES, properties); } @@ -268,6 +310,52 @@ srt_steam_get_bin32_path (SrtSteam *self) return self->bin32_path; } +/** + * srt_steam_get_steamscript_path: + * @self: The #SrtSteam object + * + * Return the absolute path to the script used to launch Steam, if known. + * If the application using this library was not run as a child process + * of the Steam client, then this will usually be %NULL. + * + * This will usually be `/usr/bin/steam` for the packaged Steam launcher + * released by Valve, `/app/bin/steam` for the Flatpak app, or either + * `/usr/bin/steam` or `/usr/games/steam` for third-party packaged versions + * of the Steam client. + * + * Returns: (type filename) (nullable): A filename valid as long as @self + * is not destroyed, or %NULL. + */ +const char * +srt_steam_get_steamscript_path (SrtSteam *self) +{ + g_return_val_if_fail (SRT_IS_STEAM (self), NULL); + return self->steamscript_path; +} + +/** + * srt_steam_get_steamscript_version: + * @self: The #SrtSteam object + * + * Return the version of the script used to launch Steam, if known. + * If the application using this library was not run as a child process + * of the Steam client, then this will usually be %NULL. + * + * Typical values look like `1.0.0.66` for the packaged Steam launcher + * released by Valve, `1.0.0.66-2/Debian` for recent Debian packages, or + * %NULL for older Debian/Ubuntu packages. Future Ubuntu packages might + * produce a string like `1.0.0.66-2ubuntu1/Ubuntu`. + * + * Returns: (type filename) (nullable): A filename valid as long as @self + * is not destroyed, or %NULL. + */ +const char * +srt_steam_get_steamscript_version (SrtSteam *self) +{ + g_return_val_if_fail (SRT_IS_STEAM (self), NULL); + return self->steamscript_version; +} + /** * _srt_steam_check: * @my_environ: (not nullable): The list of environment variables to use. @@ -298,6 +386,7 @@ _srt_steam_check (const GStrv my_environ, const char *home = NULL; const char *user_data = NULL; const char *steam_script = NULL; + const char *steam_script_version = NULL; const char *commandline = NULL; const char *executable = NULL; const char *app_id = NULL; @@ -603,11 +692,15 @@ _srt_steam_check (const GStrv my_environ, } } + steam_script_version = g_environ_getenv (env, "STEAMSCRIPT_VERSION"); + if (more_details_out != NULL) *more_details_out = _srt_steam_new (issues, install_path, data_path, - bin32); + bin32, + steam_script, + steam_script_version); free (install_path); free (data_path); @@ -640,6 +733,8 @@ _srt_steam_get_from_report (JsonObject *json_obj) const gchar *install_path = NULL; const gchar *data_path = NULL; const gchar *bin32_path = NULL; + const gchar *steamscript_path = NULL; + const gchar *steamscript_version = NULL; g_return_val_if_fail (json_obj != NULL, NULL); @@ -680,11 +775,19 @@ _srt_steam_get_from_report (JsonObject *json_obj) if (json_object_has_member (json_sub_obj, "bin32_path")) bin32_path = json_object_get_string_member (json_sub_obj, "bin32_path"); + + if (json_object_has_member (json_sub_obj, "steamscript_path")) + steamscript_path = json_object_get_string_member (json_sub_obj, "steamscript_path"); + + if (json_object_has_member (json_sub_obj, "steamscript_version")) + steamscript_version = json_object_get_string_member (json_sub_obj, "steamscript_version"); } out: return _srt_steam_new (issues, install_path, data_path, - bin32_path); + bin32_path, + steamscript_path, + steamscript_version); } diff --git a/steam-runtime-tools/steam.h b/steam-runtime-tools/steam.h index ba3a01b54..68fa5ad50 100644 --- a/steam-runtime-tools/steam.h +++ b/steam-runtime-tools/steam.h @@ -120,6 +120,10 @@ _SRT_PUBLIC const char *srt_steam_get_data_path (SrtSteam *self); _SRT_PUBLIC const char *srt_steam_get_bin32_path (SrtSteam *self); +_SRT_PUBLIC +const char *srt_steam_get_steamscript_path (SrtSteam *self); +_SRT_PUBLIC +const char *srt_steam_get_steamscript_version (SrtSteam *self); #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC G_DEFINE_AUTOPTR_CLEANUP_FUNC (SrtSteam, g_object_unref) diff --git a/steam-runtime-tools/system-info.c b/steam-runtime-tools/system-info.c index 423a188e6..914139595 100644 --- a/steam-runtime-tools/system-info.c +++ b/steam-runtime-tools/system-info.c @@ -3538,3 +3538,51 @@ srt_system_info_get_known_x86_features (SrtSystemInfo *self) return self->cpu_features.x86_known; } + +/** + * srt_system_info_dup_steamscript_path: + * @self: The #SrtSystemInfo object + * + * Return the absolute path to the script used to launch Steam, if known. + * If the application using this library was not run as a child process + * of the Steam client, then this will usually be %NULL. + * + * This will usually be `/usr/bin/steam` for the packaged Steam launcher + * released by Valve, `/app/bin/steam` for the Flatpak app, or either + * `/usr/bin/steam` or `/usr/games/steam` for third-party packaged versions + * of the Steam client. + * + * Returns: (transfer full) (type filename) (nullable): A filename, or %NULL. + */ +gchar * +srt_system_info_dup_steamscript_path (SrtSystemInfo *self) +{ + g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), NULL); + + ensure_steam_cached (self); + return g_strdup (srt_steam_get_steamscript_path (self->steam_data)); +} + +/** + * srt_system_info_dup_steamscript_version: + * @self: The #SrtSystemInfo object + * + * Return the version of the script used to launch Steam, if known. + * If the application using this library was not run as a child process + * of the Steam client, then this will usually be %NULL. + * + * Typical values look like `1.0.0.66` for the packaged Steam launcher + * released by Valve, `1.0.0.66-2/Debian` for recent Debian packages, or + * %NULL for older Debian/Ubuntu packages. Future Ubuntu packages might + * produce a string like `1.0.0.66-2ubuntu1/Ubuntu`. + * + * Returns: (transfer full) (type filename) (nullable): A filename, or %NULL. + */ +gchar * +srt_system_info_dup_steamscript_version (SrtSystemInfo *self) +{ + g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), NULL); + + ensure_steam_cached (self); + return g_strdup (srt_steam_get_steamscript_version (self->steam_data)); +} diff --git a/steam-runtime-tools/system-info.h b/steam-runtime-tools/system-info.h index d74395491..0c064004c 100644 --- a/steam-runtime-tools/system-info.h +++ b/steam-runtime-tools/system-info.h @@ -257,6 +257,11 @@ SrtX86FeatureFlags srt_system_info_get_x86_features (SrtSystemInfo *self); _SRT_PUBLIC SrtX86FeatureFlags srt_system_info_get_known_x86_features (SrtSystemInfo *self); +_SRT_PUBLIC +gchar *srt_system_info_dup_steamscript_path (SrtSystemInfo *self); +_SRT_PUBLIC +gchar *srt_system_info_dup_steamscript_version (SrtSystemInfo *self); + #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC G_DEFINE_AUTOPTR_CLEANUP_FUNC (SrtSystemInfo, g_object_unref) #endif diff --git a/tests/json-report/full-good-report.json b/tests/json-report/full-good-report.json index 20fd76cf2..9edf332b2 100644 --- a/tests/json-report/full-good-report.json +++ b/tests/json-report/full-good-report.json @@ -4,6 +4,8 @@ "path" : "/home/me/.local/share/Steam", "data_path" : "/home/me/.local/share/Steam", "bin32_path" : "/home/me/.local/share/Steam/ubuntu12_32", + "steamscript_path" : "/usr/bin/steam", + "steamscript_version" : "1.0.0.66", "issues" : [ "steamscript-not-in-environment" ] diff --git a/tests/json-report/partial-report-2.json b/tests/json-report/partial-report-2.json index 7297874d2..b882cd97c 100644 --- a/tests/json-report/partial-report-2.json +++ b/tests/json-report/partial-report-2.json @@ -1,6 +1,8 @@ { "steam-installation" : { - "path" : "/home/me/.local/share/Steam" + "path" : "/home/me/.local/share/Steam", + "steamscript_path" : null, + "steamscript_version" : null }, "runtime" : { "path" : "/home/me/.steam/root/ubuntu12_32/steam-runtime", diff --git a/tests/system-info-cli.c b/tests/system-info-cli.c index b3d6e71fc..10c21270b 100644 --- a/tests/system-info-cli.c +++ b/tests/system-info-cli.c @@ -487,6 +487,9 @@ steam_presence (Fixture *f, g_autoptr(GError) error = NULL; g_autofree gchar *output = NULL; const gchar *path = NULL; + const gchar *script_path = NULL; + const gchar *script_path_member = NULL; + const gchar *script_version = NULL; const gchar *version = NULL; const gchar *argv[] = { "steam-runtime-system-info", NULL }; FakeHome *fake_home; @@ -494,6 +497,13 @@ steam_presence (Fixture *f, fake_home = fake_home_new (NULL); fake_home_create_structure (fake_home); + /* We expect `fake_home_new` to already set 'STEAMSCRIPT' */ + script_path = g_environ_getenv (fake_home->env, "STEAMSCRIPT"); + g_assert_cmpstr (script_path, !=, NULL); + + fake_home->env = g_environ_setenv (fake_home->env, "STEAMSCRIPT_VERSION", + "1.0.0.66", TRUE); + result = g_spawn_sync (NULL, /* working directory */ (gchar **) argv, fake_home->env, /* envp */ @@ -528,6 +538,14 @@ steam_presence (Fixture *f, g_assert_cmpstr (path, !=, NULL); g_assert_true (path[0] == '/'); + g_assert_true (json_object_has_member (json_sub_object, "steamscript_path")); + script_path_member = json_object_get_string_member (json_sub_object, "steamscript_path"); + g_assert_cmpstr (script_path_member, ==, script_path); + + g_assert_true (json_object_has_member (json_sub_object, "steamscript_version")); + script_version = json_object_get_string_member (json_sub_object, "steamscript_version"); + g_assert_cmpstr (script_version, ==, "1.0.0.66"); + 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); @@ -576,6 +594,8 @@ steam_issues (Fixture *f, g_autoptr(GError) error = NULL; g_autofree gchar *output = NULL; const gchar *path = NULL; + const gchar *script_path = NULL; + const gchar *script_version = NULL; const gchar *version = NULL; const gchar *argv[] = { "steam-runtime-system-info", NULL }; FakeHome *fake_home; @@ -586,6 +606,8 @@ steam_issues (Fixture *f, fake_home->create_steamrt_files = FALSE; fake_home_create_structure (fake_home); + fake_home->env = g_environ_unsetenv (fake_home->env, "STEAMSCRIPT"); + result = g_spawn_sync (NULL, /* working directory */ (gchar **) argv, fake_home->env, /* envp */ @@ -621,13 +643,26 @@ steam_issues (Fixture *f, g_assert_cmpstr (path, !=, NULL); g_assert_true (path[0] == '/'); + g_assert_true (json_object_has_member (json_sub_object, "steamscript_path")); + script_path = json_object_get_string_member (json_sub_object, "steamscript_path"); + g_assert_cmpstr (script_path, ==, NULL); + + g_assert_true (json_object_has_member (json_sub_object, "steamscript_version")); + script_version = json_object_get_string_member (json_sub_object, "steamscript_version"); + g_assert_cmpstr (script_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_cmpint (json_array_get_length (array), ==, 4); g_assert_cmpstr (json_array_get_string_element (array, 0), ==, "dot-steam-steam-not-symlink"); g_assert_cmpstr (json_array_get_string_element (array, 1), ==, "dot-steam-steam-not-directory"); + g_assert_cmpstr (json_array_get_string_element (array, 2), ==, + "steamscript-not-in-environment"); + /* This is caused by the missing steamscript */ + g_assert_cmpstr (json_array_get_string_element (array, 3), ==, + "unexpected-steam-uri-handler"); g_assert_true (json_object_has_member (json, "runtime")); json_sub_object = json_object_get_object_member (json, "runtime"); diff --git a/tests/system-info.c b/tests/system-info.c index a5162237d..7b4e4fffe 100644 --- a/tests/system-info.c +++ b/tests/system-info.c @@ -2211,6 +2211,47 @@ driver_environment (Fixture *f, g_strfreev (envp); } +static void +steamscript_env (Fixture *f, + gconstpointer context) +{ + SrtSystemInfo *info; + gchar **envp; + g_autofree gchar *steamscript_path; + g_autofree gchar *steamscript_version; + + envp = g_get_environ (); + + envp = g_environ_setenv (envp, "STEAMSCRIPT", "/usr/bin/steam", TRUE); + envp = g_environ_setenv (envp, "STEAMSCRIPT_VERSION", "1.0.0.66", TRUE); + + info = srt_system_info_new (NULL); + srt_system_info_set_environ (info, envp); + + steamscript_path = srt_system_info_dup_steamscript_path (info); + steamscript_version = srt_system_info_dup_steamscript_version (info); + + g_assert_cmpstr (steamscript_path, ==, "/usr/bin/steam"); + g_assert_cmpstr (steamscript_version, ==, "1.0.0.66"); + + g_clear_pointer (&steamscript_path, g_free); + g_clear_pointer (&steamscript_version, g_free); + + envp = g_environ_unsetenv (envp, "STEAMSCRIPT"); + envp = g_environ_unsetenv (envp, "STEAMSCRIPT_VERSION"); + + srt_system_info_set_environ (info, envp); + + steamscript_path = srt_system_info_dup_steamscript_path (info); + steamscript_version = srt_system_info_dup_steamscript_version (info); + + g_assert_cmpstr (steamscript_path, ==, NULL); + g_assert_cmpstr (steamscript_version, ==, NULL); + + g_object_unref (info); + g_strfreev (envp); +} + typedef struct { const char *description; @@ -2314,6 +2355,8 @@ typedef struct { const gchar *path; const gchar *data_path; + const gchar *steamscript_path; + const gchar *steamscript_version; SrtSteamIssues issues; } SteamInstallationTest; @@ -2436,6 +2479,8 @@ static const JsonTest json_test[] = { .path = "/home/me/.local/share/Steam", .data_path = "/home/me/.local/share/Steam", + .steamscript_path = "/usr/bin/steam", + .steamscript_version = "1.0.0.66", .issues = SRT_STEAM_ISSUES_STEAMSCRIPT_NOT_IN_ENVIRONMENT, }, @@ -2930,6 +2975,8 @@ json_parsing (Fixture *f, gchar *name; gchar *pretty_name; gchar *host_directory; + g_autofree gchar *steamscript_path = NULL; + g_autofree gchar *steamscript_version = NULL; gchar **pinned_32 = NULL; gchar **messages_32 = NULL; gchar **pinned_64 = NULL; @@ -2949,8 +2996,12 @@ json_parsing (Fixture *f, steam_path = srt_system_info_dup_steam_installation_path (info); steam_data_path = srt_system_info_dup_steam_data_path (info); + steamscript_path = srt_system_info_dup_steamscript_path (info); + steamscript_version = srt_system_info_dup_steamscript_version (info); g_assert_cmpstr (t->steam_installation.path, ==, steam_path); g_assert_cmpstr (t->steam_installation.data_path, ==, steam_data_path); + g_assert_cmpstr (t->steam_installation.steamscript_path, ==, steamscript_path); + g_assert_cmpstr (t->steam_installation.steamscript_version, ==, steamscript_version); g_assert_cmpint (t->steam_installation.issues, ==, srt_system_info_get_steam_issues (info)); runtime_path = srt_system_info_dup_runtime_path (info); @@ -3265,6 +3316,8 @@ main (int argc, g_test_add ("/system-info/driver_environment", Fixture, NULL, setup, driver_environment, teardown); + g_test_add ("/system-info/steamscript_env", Fixture, NULL, + setup, steamscript_env, teardown); g_test_add ("/system-info/containers", Fixture, NULL, setup, test_containers, teardown); -- GitLab