diff --git a/.gitignore b/.gitignore index f177cb4b903b312165439cb30f46c9c3b325d2fd..5a9de428f2129b954e3a775c66a961f3b5887cac 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /_build/ /build/ /builddir/ +/helpers/_generated_*/ /libcapsule/ /libcapsule_*.dsc /libcapsule_*.tar.[gx]z diff --git a/bin/system-info.c b/bin/system-info.c index 88e76992859dbcd031c87453d1a26f621d71ec6e..c9403bd635b65ed1188fc444e53adab069040b3c 100644 --- a/bin/system-info.c +++ b/bin/system-info.c @@ -1046,6 +1046,10 @@ main (int argc, GList *va_api_list = NULL; GList *vdpau_list = NULL; GList *glx_list = NULL; + g_autofree gchar *libdl_lib = NULL; + g_autofree gchar *libdl_platform = NULL; + g_autoptr(GError) libdl_lib_error = NULL; + g_autoptr(GError) libdl_platform_error = NULL; const char *ld_so; json_builder_set_member_name (builder, multiarch_tuples[i]); @@ -1054,6 +1058,35 @@ main (int argc, can_run = srt_system_info_can_run (info, multiarch_tuples[i]); json_builder_add_boolean_value (builder, can_run); + json_builder_set_member_name (builder, "libdl-LIB"); + libdl_lib = srt_system_info_dup_libdl_lib (info, multiarch_tuples[i], + &libdl_lib_error); + if (libdl_lib != NULL) + { + json_builder_add_string_value (builder, libdl_lib); + } + else + { + json_builder_begin_object (builder); + _srt_json_builder_add_error_members (builder, libdl_lib_error); + json_builder_end_object (builder); + } + + json_builder_set_member_name (builder, "libdl-PLATFORM"); + libdl_platform = srt_system_info_dup_libdl_platform (info, + multiarch_tuples[i], + &libdl_platform_error); + if (libdl_platform != NULL) + { + json_builder_add_string_value (builder, libdl_platform); + } + else + { + json_builder_begin_object (builder); + _srt_json_builder_add_error_members (builder, libdl_platform_error); + json_builder_end_object (builder); + } + ld_so = srt_architecture_get_expected_runtime_linker (multiarch_tuples[i]); if (ld_so != NULL) diff --git a/bin/system-info.md b/bin/system-info.md index 9b9e705173bb62fcd66a1837e311e80d22431a90..233885754584f865e9cadf30b238bfec7121b4b4 100644 --- a/bin/system-info.md +++ b/bin/system-info.md @@ -354,6 +354,27 @@ keys: : A boolean value indicating whether a simple executable for this architecture was run successfully. + **libdl-LIB** + : A string containing the dynamic linker expansion of the literal token + `$LIB`/`${LIB}`. See `ld.so(8)` section "Dynamic string tokens" for + more details. However if an error occurred while trying to determine + the expansion value, **libdl-LIB** will instead contain an object with + the following details of the error: + + **error-domain** + : A machine-readable string indicating a category of errors. + + **error-code** + : A small integer indicating a specific error. Its meaning depends + on the **error-domain**. + + **error** + : A human-readable error message. + + **libdl-PLATFORM** + : The same as the **libdl-LIB** described above, but describing the + literal token `$PLATFORM`/`${PLATFORM}`. + **runtime-linker** : If the multiarch tuple is a known one, an object with the following keys and values describing the runtime linker **ld.so**(8): diff --git a/helpers/create-meson-in-subdir.py b/helpers/create-meson-in-subdir.py new file mode 100644 index 0000000000000000000000000000000000000000..2e029e4faf52683081b31cebf0ec850b710dd265 --- /dev/null +++ b/helpers/create-meson-in-subdir.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +# +# Copyright © 2021 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. + +import sys +from pathlib import Path + +dir_path = Path(sys.argv[1]) +dir_path.mkdir(exist_ok=True) + +meson_path = dir_path / "meson.build" + +with meson_path.open('w') as text: + text.write(sys.argv[2]) diff --git a/helpers/detect.c b/helpers/detect.c new file mode 100644 index 0000000000000000000000000000000000000000..1734537ff1ed16ce7f4a76be08514067c72ad047 --- /dev/null +++ b/helpers/detect.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2021 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 <dlfcn.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int +main (int argc, + char **argv) +{ + void *handle = NULL; + const char *err; + +#if defined(_SRT_LIB_PATH) && defined(_SRT_FUNCTION) + handle = dlopen (_SRT_LIB_PATH, RTLD_NOW); + if (handle == NULL) + { + fprintf (stderr, "Unable to find the library: %s\n", dlerror ()); + return 1; + } + + char *(*fn)(void) = dlsym (handle, _SRT_FUNCTION); + err = dlerror (); + if (err != NULL) + { + fprintf (stderr, "Unable to load the library function: %s\n", + dlerror ()); + dlclose (handle); + return 1; + } + + printf ("%s\n", fn()); + + dlclose (handle); + return 0; +#else + return 1; +#endif +} diff --git a/helpers/identify-lib.c b/helpers/identify-lib.c new file mode 100644 index 0000000000000000000000000000000000000000..80cf3eefc97849ae452e3a6e7029ff4703380bad --- /dev/null +++ b/helpers/identify-lib.c @@ -0,0 +1,37 @@ +/* + * Copyright © 2021 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 "identify-lib.h" + + +const +char *_srt_identify_lib (void) +{ + #if defined(_SRT_LIB_VALUE) + return _SRT_LIB_VALUE; + #else + return NULL; + #endif +} diff --git a/helpers/identify-lib.h b/helpers/identify-lib.h new file mode 100644 index 0000000000000000000000000000000000000000..66a10a71fc27be776de1b270444e73284794548b --- /dev/null +++ b/helpers/identify-lib.h @@ -0,0 +1,27 @@ +/* + * Copyright © 2021 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. + */ + +__attribute__((visibility("default"))) +const char *_srt_identify_lib (void); diff --git a/helpers/identify-platform.c b/helpers/identify-platform.c new file mode 100644 index 0000000000000000000000000000000000000000..3364c59b8a91700723fe1253fdca73bdc966b947 --- /dev/null +++ b/helpers/identify-platform.c @@ -0,0 +1,37 @@ +/* + * Copyright © 2021 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 "identify-platform.h" + + +const +char *_srt_identify_platform (void) +{ + #if defined(_SRT_PLATFORM_VALUE) + return _SRT_PLATFORM_VALUE; + #else + return NULL; + #endif +} diff --git a/helpers/identify-platform.h b/helpers/identify-platform.h new file mode 100644 index 0000000000000000000000000000000000000000..6d78777bdaf8d726e49c290f933466cde4fdea75 --- /dev/null +++ b/helpers/identify-platform.h @@ -0,0 +1,27 @@ +/* + * Copyright © 2021 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. + */ + +__attribute__((visibility("default"))) +const char *_srt_identify_platform (void); diff --git a/helpers/meson.build b/helpers/meson.build index 0034412f4816194bba6042eec2128f545687f889..7da618da416bc3720ba32ee1146544dd9b3d4409 100644 --- a/helpers/meson.build +++ b/helpers/meson.build @@ -1,4 +1,4 @@ -# Copyright © 2019 Collabora Ltd. +# Copyright © 2019-2021 Collabora Ltd. # # SPDX-License-Identifier: MIT # @@ -136,4 +136,112 @@ executable( install_rpath : pkglibexec_rpath, ) +executable( + multiarch + '-detect-lib', + 'detect.c', + c_args : [ + '-D_SRT_LIB_PATH="${ORIGIN}/' + multiarch + '/${LIB}/libidentify-lib.so"', + '-D_SRT_FUNCTION="_srt_identify_lib"', + ], + dependencies : [libdl], + include_directories : project_include_dirs, + install : true, + install_dir : pkglibexecdir, +) + +executable( + multiarch + '-detect-platform', + 'detect.c', + c_args : [ + '-D_SRT_LIB_PATH="${ORIGIN}/' + multiarch + '/${PLATFORM}/libidentify-platform.so"', + '-D_SRT_FUNCTION="_srt_identify_platform"', + ], + dependencies : [libdl], + include_directories : project_include_dirs, + install : true, + install_dir : pkglibexecdir, +) + +# Due to some Meson's limitations it is not possible to build multiple times +# the same library, with the same name, and place it in a different directory. +# For this reason we generate the required meson.build files in subdirectories +# to avoid conflicts. +# https://github.com/mesonbuild/meson/issues/2320 +# https://github.com/mesonbuild/meson/issues/4019 + +meson_library_template = ''' +shared_module( + 'identify-lib', + '@0@', + c_args : ['-D_SRT_LIB_VALUE="@1@"',], + install : true, + install_dir : join_paths( + pkglibexecdir, + multiarch, + '@1@', + ) +) +''' + +# This was supposed to be a dictionary but meson < 0.53.0 doesn't support +# the usage of variables containing a string value as keys. +components = [['lib', '../identify-lib.c']] + +if multiarch != '' + components += [ + ['lib' / multiarch, '../../identify-lib.c'], + # This is to support Ubuntu 12.04 where $LIB wrongly expanded to just + # the multiarch + [multiarch, '../identify-lib.c'], + ] +endif + +if multiarch == 'i386-linux-gnu' + components += [['lib32', '../identify-lib.c']] + platform_dirs = ['i386', 'i486', 'i586', 'i686'] +elif multiarch == 'x86_64-linux-gnu' + components += [['lib64', '../identify-lib.c']] + platform_dirs = ['x86_64', 'haswell', 'xeon_phi'] +endif + +foreach component : components + subdir = '_generated_' + component[0] + meson_library = meson_library_template.format(component[1], component[0]) + run_command( + python, + 'create-meson-in-subdir.py', + meson.current_source_dir() / subdir, + meson_library, + check : true, + ) + subdir(subdir) +endforeach + +meson_platform_template = ''' +shared_module( + 'identify-platform', + '../identify-platform.c', + c_args : ['-D_SRT_PLATFORM_VALUE="@0@"',], + install : true, + install_dir : join_paths( + pkglibexecdir, + multiarch, + '@0@', + ) +) +''' + +foreach platform_dir : platform_dirs + generated_dir = '_generated_' + platform_dir + meson_platform = meson_platform_template.format(platform_dir) + run_command( + python, + 'create-meson-in-subdir.py', + meson.current_source_dir() / generated_dir, + meson_platform, + check : true, + ) + subdir(generated_dir) +endforeach + # vim:set sw=2 sts=2 et: diff --git a/steam-runtime-tools/libdl-internal.h b/steam-runtime-tools/libdl-internal.h new file mode 100644 index 0000000000000000000000000000000000000000..dc3b70179a36918ee4521ebb22d480d507501119 --- /dev/null +++ b/steam-runtime-tools/libdl-internal.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2021 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 <glib.h> +#include <glib-object.h> + +G_GNUC_INTERNAL gchar *_srt_libdl_detect_platform (gchar **envp, + const char *helpers_path, + const char *multiarch_tuple, + GError **error); + +G_GNUC_INTERNAL gchar *_srt_libdl_detect_lib (gchar **envp, + const char *helpers_path, + const char *multiarch_tuple, + GError **error); diff --git a/steam-runtime-tools/libdl.c b/steam-runtime-tools/libdl.c new file mode 100644 index 0000000000000000000000000000000000000000..7223f4366ca559578025d635459abbb8f1b756ab --- /dev/null +++ b/steam-runtime-tools/libdl.c @@ -0,0 +1,128 @@ +/* + * Copyright © 2021 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/libdl-internal.h" + +#include "steam-runtime-tools/glib-backports-internal.h" +#include "steam-runtime-tools/utils.h" +#include "steam-runtime-tools/utils-internal.h" + +static gchar * +_srt_libdl_run_helper (gchar **envp, + const char *helpers_path, + const char *multiarch_tuple, + const char *helper_name, + GError **error) +{ + g_autoptr(GPtrArray) argv = NULL; + g_auto(GStrv) my_environ = NULL; + g_autofree gchar *child_stdout = NULL; + g_autofree gchar *child_stderr = NULL; + gint wait_status; + int exit_status; + gsize len; + + g_return_val_if_fail (envp != NULL, NULL); + g_return_val_if_fail (helper_name != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_val_if_fail (_srt_check_not_setuid (), NULL); + + if (multiarch_tuple == NULL) + multiarch_tuple = _SRT_MULTIARCH; + + argv = _srt_get_helper (helpers_path, multiarch_tuple, helper_name, + SRT_HELPER_FLAGS_NONE, error); + + if (argv == NULL) + return NULL; + + my_environ = _srt_filter_gameoverlayrenderer_from_envp (envp); + + g_ptr_array_add (argv, NULL); + + g_debug ("Running %s", (const char *) g_ptr_array_index (argv, 0)); + + if (!g_spawn_sync (NULL, /* working directory */ + (gchar **) argv->pdata, + my_environ, + G_SPAWN_DEFAULT, + _srt_child_setup_unblock_signals, + NULL, /* user data */ + &child_stdout, + &child_stderr, + &wait_status, + error)) + return NULL; + + if (!WIFEXITED (wait_status)) + { + g_debug ("-> wait status: %d", wait_status); + return glnx_null_throw (error, "Unhandled wait status %d (killed by signal?)", + wait_status); + } + + exit_status = WEXITSTATUS (wait_status); + g_debug ("-> exit status: %d", exit_status); + g_debug ("-> stderr: %s", child_stderr); + + if (exit_status != 0) + return glnx_null_throw (error, "%s", child_stderr); + + len = strlen (child_stdout); + + /* Emulate shell $() */ + if (len > 0 && child_stdout[len - 1] == '\n') + child_stdout[len - 1] = '\0'; + + g_debug ("-> %s", child_stdout); + + return g_steal_pointer(&child_stdout); +} + +gchar * +_srt_libdl_detect_platform (gchar **envp, + const char *helpers_path, + const char *multiarch_tuple, + GError **error) +{ + return _srt_libdl_run_helper (envp, + helpers_path, + multiarch_tuple, + "detect-platform", + error); +} + +gchar * +_srt_libdl_detect_lib (gchar **envp, + const char *helpers_path, + const char *multiarch_tuple, + GError **error) +{ + return _srt_libdl_run_helper (envp, + helpers_path, + multiarch_tuple, + "detect-lib", + error); +} diff --git a/steam-runtime-tools/meson.build b/steam-runtime-tools/meson.build index 7f345e2915407017dedac78a76ab8b82519cd0f0..1f5ea949bd7d893c3723cd4640f5e5c03263d8ae 100644 --- a/steam-runtime-tools/meson.build +++ b/steam-runtime-tools/meson.build @@ -40,6 +40,8 @@ libsteamrt_sources = [ 'json-glib-backports-internal.h', 'json-utils.c', 'json-utils-internal.h', + 'libdl-internal.h', + 'libdl.c', 'library-internal.h', 'library.c', 'locale-internal.h', diff --git a/steam-runtime-tools/system-info.c b/steam-runtime-tools/system-info.c index 4819412376824da22add142a6e5d4ebb33da59b1..4c38f40284a1565447c8b4cf491c39278e3807e4 100644 --- a/steam-runtime-tools/system-info.c +++ b/steam-runtime-tools/system-info.c @@ -37,6 +37,7 @@ #include "steam-runtime-tools/graphics.h" #include "steam-runtime-tools/graphics-internal.h" #include "steam-runtime-tools/json-utils-internal.h" +#include "steam-runtime-tools/libdl-internal.h" #include "steam-runtime-tools/library-internal.h" #include "steam-runtime-tools/locale-internal.h" #include "steam-runtime-tools/os-internal.h" @@ -261,6 +262,11 @@ typedef struct SrtLibraryIssues cached_combined_issues; gboolean libraries_cache_available; + gchar *libdl_lib; + GError *libdl_lib_error; + gchar *libdl_platform; + GError *libdl_platform_error; + GHashTable *cached_graphics_results; SrtGraphicsIssues cached_combined_graphics_issues; gboolean graphics_cache_available; @@ -339,6 +345,10 @@ abi_free (gpointer self) g_free (abi->runtime_linker_resolved); g_clear_error (&abi->runtime_linker_error); + g_free (abi->libdl_lib); + g_clear_error (&abi->libdl_lib_error); + g_free (abi->libdl_platform); + g_clear_error (&abi->libdl_platform_error); g_slice_free (Abi, self); } @@ -698,6 +708,72 @@ get_runtime_linker_from_report (SrtSystemInfo *self, } } +static void +get_libdl_from_report (SrtSystemInfo *self, + Abi *abi, + JsonObject *json_arch_obj) +{ + gsize i; + + /* Struct to avoid code duplication between all the similar libdl entries */ + typedef struct + { + const gchar *member_name; + gchar **abi_member; + GError **abi_member_error; + } LibdlStruct; + + LibdlStruct libdl_elements[] = + { + { "libdl-LIB", &abi->libdl_lib, &abi->libdl_lib_error }, + { "libdl-PLATFORM", &abi->libdl_platform, &abi->libdl_platform_error }, + }; + + g_return_if_fail (abi->libdl_lib == NULL); + g_return_if_fail (abi->libdl_lib_error == NULL); + g_return_if_fail (abi->libdl_platform == NULL); + g_return_if_fail (abi->libdl_platform_error == NULL); + + for (i = 0; i < G_N_ELEMENTS (libdl_elements); i++) + { + JsonNode *subnode; + const LibdlStruct *libdl_element = &libdl_elements[i]; + + if (!json_object_has_member (json_arch_obj, libdl_element->member_name)) + continue; + + subnode = json_object_get_member (json_arch_obj, libdl_element->member_name); + + if (JSON_NODE_HOLDS_VALUE (subnode)) + { + *libdl_element->abi_member = g_strdup (json_node_get_string (subnode)); + } + else + { + JsonObject *json_element_obj; + GQuark error_domain; + int error_code; + const char *error_message; + + json_element_obj = json_object_get_object_member (json_arch_obj, + libdl_element->member_name); + + error_domain = g_quark_from_string (json_object_get_string_member_with_default (json_element_obj, + "error-domain", + NULL)); + error_code = json_object_get_int_member_with_default (json_element_obj, + "error-code", + -1); + error_message = json_object_get_string_member_with_default (json_element_obj, + "error", + "Unknown error"); + + g_set_error_literal (libdl_element->abi_member_error, error_domain, error_code, + error_message); + } + } +} + /** * srt_system_info_new_from_json: * @path: (not nullable) (type filename): Path to a JSON report @@ -806,6 +882,8 @@ srt_system_info_new_from_json (const char *path, abi->can_run = _srt_architecture_can_run_from_report (json_arch_obj); + get_libdl_from_report (info, abi, json_arch_obj); + abi->libraries_cache_available = TRUE; abi->cached_combined_issues = _srt_library_get_issues_from_report (json_arch_obj); @@ -4411,3 +4489,147 @@ srt_system_info_check_runtime_linker (SrtSystemInfo *self, g_return_val_if_reached (FALSE); } } + +/** + * srt_system_info_dup_libdl_lib: + * @self: The #SrtSystemInfo object + * @multiarch_tuple: A multiarch tuple defining an ABI, as printed + * by `gcc -print-multiarch` in the Steam Runtime + * @error: Used to raise an error on failure. + * + * Return the expansion of the dynamic linker string token `$LIB`, + * if possible. + * + * If the library path to be loaded with `dlopen()` or similar contains + * the literal tokens `$LIB` or `${LIB}`, the dynamic linker will replace + * them with the library directory returned by this function. See `ld.so(8)` + * section "Dynamic string tokens" for more details. + * + * Because there is currently no glibc API to determine how this token would + * be expanded, only a finite number of known values can currently be detected. + * If called on a platform where `$LIB` has a different expansion, this + * function will return %NULL. + * + * %NULL is also returned if an error occurs while attempting to determine the + * expansion of this token. + * + * Typical values look like `lib`, `lib32`, `lib64`, `lib/x86-64-linux-gnu` + * or `lib/i386-linux-gnu`. + * + * Returns: (transfer full) (type filename) (nullable): A filename, or %NULL. + */ +gchar * +srt_system_info_dup_libdl_lib (SrtSystemInfo *self, + const char *multiarch_tuple, + GError **error) +{ + Abi *abi = NULL; + + g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), NULL); + g_return_val_if_fail (multiarch_tuple != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + abi = ensure_abi_unless_immutable (self, multiarch_tuple); + + if (abi == NULL) + return glnx_null_throw (error, "ABI \"%s\" not included in report", + multiarch_tuple); + + /* If we cached already the result, we return it */ + if (abi->libdl_lib != NULL) + { + return g_strdup (abi->libdl_lib); + } + else if (abi->libdl_lib_error != NULL) + { + if (error != NULL) + *error = g_error_copy (abi->libdl_lib_error); + return NULL; + } + + if (self->immutable_values) + return glnx_null_throw (error, "libdl LIB for ABI \"%s\" not included in report", + multiarch_tuple); + + abi->libdl_lib = _srt_libdl_detect_lib (self->env, + self->helpers_path, + multiarch_tuple, + &abi->libdl_lib_error); + + if (abi->libdl_lib_error != NULL && error != NULL) + *error = g_error_copy (abi->libdl_lib_error); + + return g_strdup (abi->libdl_lib); +} + +/** + * srt_system_info_dup_libdl_platform: + * @self: The #SrtSystemInfo object + * @multiarch_tuple: A multiarch tuple defining an ABI, as printed + * by `gcc -print-multiarch` in the Steam Runtime + * @error: Used to raise an error on failure. + * + * Return the expansion of the dynamic linker string token `$PLATFORM`, + * if possible. + * + * If the library path to be loaded with `dlopen()` or similar contains + * the literal tokens `$PLATFORM` or `${PLATFORM}`, the dynamic linker will + * replace them with the library directory returned by this function. See + * `ld.so(8)` section "Dynamic string tokens" for more details. + * + * Because there is currently no glibc API to determine how this token would + * be expanded, only a finite number of known values can currently be detected. + * If called on a platform where `$PLATFORM` has a different expansion, this + * function will return %NULL. + * + * %NULL is also returned if an error occurs while attempting to determine the + * expansion of this token. + * + * Typical values look like `x86_64`, `haswell`, `xeon_phi`, `i386`, `i486`, + * `i586`, or `i686`. + * + * Returns: (transfer full) (type filename) (nullable): A filename, or %NULL. + */ +gchar * +srt_system_info_dup_libdl_platform (SrtSystemInfo *self, + const char *multiarch_tuple, + GError **error) +{ + Abi *abi = NULL; + + g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), NULL); + g_return_val_if_fail (multiarch_tuple != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + abi = ensure_abi_unless_immutable (self, multiarch_tuple); + + if (abi == NULL) + return glnx_null_throw (error, "ABI \"%s\" not included in report", + multiarch_tuple); + + /* If we cached already the result, we return it */ + if (abi->libdl_platform != NULL) + { + return g_strdup (abi->libdl_platform); + } + else if (abi->libdl_platform_error != NULL) + { + if (error != NULL) + *error = g_error_copy (abi->libdl_platform_error); + return NULL; + } + + if (self->immutable_values) + return glnx_null_throw (error, "libdl PLATFORM for ABI \"%s\" not included in report", + multiarch_tuple); + + abi->libdl_platform = _srt_libdl_detect_platform (self->env, + self->helpers_path, + multiarch_tuple, + &abi->libdl_platform_error); + + if (abi->libdl_platform_error != NULL && error != NULL) + *error = g_error_copy (abi->libdl_platform_error); + + return g_strdup (abi->libdl_platform); +} diff --git a/steam-runtime-tools/system-info.h b/steam-runtime-tools/system-info.h index 387ed20815cb95fe669438f7f1d208d52f89db37..5b3c91a1320c6b3be826ecd851f1151c0d721531 100644 --- a/steam-runtime-tools/system-info.h +++ b/steam-runtime-tools/system-info.h @@ -288,6 +288,15 @@ gboolean srt_system_info_check_runtime_linker (SrtSystemInfo *self, gchar **real_path, GError **error); +_SRT_PUBLIC +gchar *srt_system_info_dup_libdl_lib (SrtSystemInfo *self, + const char *multiarch_tuple, + GError **error); +_SRT_PUBLIC +gchar *srt_system_info_dup_libdl_platform (SrtSystemInfo *self, + const char *multiarch_tuple, + GError **error); + #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 d12799f1e9714fe354508ff860a4cd1c218dafc8..985a3eb9363a7dad76ade3a38b8e978ebccd7dea 100644 --- a/tests/json-report/full-good-report.json +++ b/tests/json-report/full-good-report.json @@ -53,6 +53,12 @@ "architectures" : { "i386-linux-gnu" : { "can-run" : false, + "libdl-LIB" : "lib32", + "libdl-PLATFORM" : { + "error-domain" : "g-io-error-quark", + "error-code" : 1, + "error" : "Unable to find the library: ${ORIGIN}/i386-linux-gnu/${PLATFORM}/libidentify-platform.so: cannot open shared object file: No such file or directory" + }, "runtime-linker": { "path" : "/lib/ld-linux.so.2", "error-domain" : "g-io-error-quark", @@ -130,6 +136,8 @@ }, "x86_64-linux-gnu" : { "can-run" : true, + "libdl-LIB" : "lib", + "libdl-PLATFORM" : "x86_64", "runtime-linker": { "path" : "/lib64/ld-linux-x86-64.so.2", "resolved" : "/lib/x86_64-linux-gnu/ld-2.31.so"