diff --git a/bin/meson.build b/bin/meson.build index d299b130a91b832b42837cf8eb4d17df410eb9ef..01ff7eb7ee4619e765496b988b0858f2fdad300d 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 9034e28a1136624757f2b37400f94409fbd27af8..66dab2c992cf84f72fa3a7bf77459e2d6c92a892 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 b71411d93b9ca55ead3cbe8225d69b754b5b70fb..25b896cc0d97d3a070ce20801344553c0e835886 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 10ec22f19dbec680ae54264849f17cd44c0687f7..6b91a63dd55188b87ebf6ebc160cc44ecf656f36 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 3cb2f583d6d489419b4fc70253d0e2832c600e07..127742166507cd4a64b006b91f337ddd03f91c1e 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 ba3a01b543521f0f7f7657d64a8fe08c120879fa..68fa5ad509e7cba8aa1b6d82c45e246cba409108 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 423a188e6aa7faa0e7c685dc44ea7230a7de188b..91413959570fd20d6d1db1614477fd59718d7434 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 d74395491139b5533d8671ef682f132dea77eb44..0c064004c3eab15f1855b3d0b26f3bd456080b0d 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 20fd76cf2e89b6ac52a0774f1eeeb3fd8c65300a..9edf332b24bbea8291d145520a645acb4ecfac97 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 7297874d29a4c2c2ec7e8cedf5032b244cca1a0c..b882cd97c2088f6dbba002e746690ca8e72da185 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 b3d6e71fcddcc299c0474c557033fa0469076b85..10c21270b11f5a143b0f8c271a3184c97a1aa673 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 a5162237d2fc4bf7fc5a8263f38efe9ee5cef415..7b4e4fffedc82e9aa5a9eee28bc08e137b3b2fc7 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);