diff --git a/steam-runtime-tools/libdl-internal.h b/steam-runtime-tools/libdl-internal.h index dc3b70179a36918ee4521ebb22d480d507501119..09799f90d1e0b8ac13f811d3a2eab6123a3f7d09 100644 --- a/steam-runtime-tools/libdl-internal.h +++ b/steam-runtime-tools/libdl-internal.h @@ -35,3 +35,23 @@ G_GNUC_INTERNAL gchar *_srt_libdl_detect_lib (gchar **envp, const char *helpers_path, const char *multiarch_tuple, GError **error); + +typedef enum +{ + SRT_LOADABLE_KIND_ERROR, + SRT_LOADABLE_KIND_BASENAME, + SRT_LOADABLE_KIND_PATH, +} SrtLoadableKind; + +typedef enum +{ + SRT_LOADABLE_FLAGS_DYNAMIC_TOKENS = (1 << 0), + SRT_LOADABLE_FLAGS_ABI_DEPENDENT = (1 << 1), + SRT_LOADABLE_FLAGS_ORIGIN = (1 << 2), + SRT_LOADABLE_FLAGS_UNKNOWN_TOKENS = (1 << 3), + SRT_LOADABLE_FLAGS_NONE = 0 +} SrtLoadableFlags; + +G_GNUC_INTERNAL +SrtLoadableKind _srt_loadable_classify (const char *loadable, + SrtLoadableFlags *flags_out); diff --git a/steam-runtime-tools/libdl.c b/steam-runtime-tools/libdl.c index 7223f4366ca559578025d635459abbb8f1b756ab..5debbef237c4101970355cbfffe40702b0962fee 100644 --- a/steam-runtime-tools/libdl.c +++ b/steam-runtime-tools/libdl.c @@ -126,3 +126,97 @@ _srt_libdl_detect_lib (gchar **envp, "detect-lib", error); } + +SrtLoadableKind +_srt_loadable_classify (const char *loadable, + SrtLoadableFlags *flags_out) +{ + SrtLoadableFlags flags = SRT_LOADABLE_FLAGS_NONE; + SrtLoadableKind kind; + gsize i; + + g_return_val_if_fail (loadable != NULL, SRT_LOADABLE_KIND_ERROR); + + if (loadable[0] == '\0') + { + kind = SRT_LOADABLE_KIND_ERROR; + goto out; + } + + if (strchr (loadable, '/') != NULL) + { + kind = SRT_LOADABLE_KIND_PATH; + } + else + { + /* Dynamic string tokens are not interpreted in a bare SONAME + * so we don't need to do that part. */ + kind = SRT_LOADABLE_KIND_BASENAME; + goto out; + } + + for (i = 0; loadable[i] != '\0'; i++) + { + if (loadable[i] == '$') + { + const char *token = loadable + i + 1; + gsize len; + + flags |= SRT_LOADABLE_FLAGS_DYNAMIC_TOKENS; + + if (token[0] == '{') + { + token++; + len = strcspn (token, "}"); + } + else + { + len = 0; + + while (g_ascii_isalnum (token[len]) || token[len] == '_') + len++; + } + + switch (len) + { + case 3: + if (strncmp ("LIB", token, len) == 0) + { + flags |= SRT_LOADABLE_FLAGS_ABI_DEPENDENT; + continue; + } + + break; + + case 6: + if (strncmp ("ORIGIN", token, len) == 0) + { + flags |= SRT_LOADABLE_FLAGS_ORIGIN; + continue; + } + + break; + + case 8: + if (strncmp ("PLATFORM", token, len) == 0) + { + flags |= SRT_LOADABLE_FLAGS_ABI_DEPENDENT; + continue; + } + + break; + + default: + break; + } + + flags |= SRT_LOADABLE_FLAGS_UNKNOWN_TOKENS; + } + } + +out: + if (flags_out != NULL) + *flags_out = flags; + + return kind; +} diff --git a/tests/libdl.c b/tests/libdl.c new file mode 100644 index 0000000000000000000000000000000000000000..964d0c54295ab1cc42202ed73aa45cd100b17063 --- /dev/null +++ b/tests/libdl.c @@ -0,0 +1,131 @@ +/* + * 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-runtime-tools.h> + +#include <string.h> +#include <unistd.h> + +#include <glib.h> +#include <glib/gstdio.h> + +#include "steam-runtime-tools/libdl-internal.h" +#include "test-utils.h" + +typedef struct +{ + int unused; +} Fixture; + +typedef struct +{ + int unused; +} Config; + +static void +setup (Fixture *f, + gconstpointer context) +{ + G_GNUC_UNUSED const Config *config = context; +} + +static void +teardown (Fixture *f, + gconstpointer context) +{ + G_GNUC_UNUSED const Config *config = context; +} + +#define ERROR SRT_LOADABLE_KIND_ERROR +#define PATH SRT_LOADABLE_KIND_PATH +#define BASE SRT_LOADABLE_KIND_BASENAME +#define DYN SRT_LOADABLE_FLAGS_DYNAMIC_TOKENS +#define ABI SRT_LOADABLE_FLAGS_ABI_DEPENDENT +#define ORIGIN SRT_LOADABLE_FLAGS_ORIGIN +#define UNKNOWN SRT_LOADABLE_FLAGS_UNKNOWN_TOKENS +#define NONE SRT_LOADABLE_FLAGS_NONE +static const struct +{ + const char *loadable; + SrtLoadableKind kind; + SrtLoadableFlags flags; +} +libdl_classify_tests[] = +{ + { "", ERROR, NONE }, + { "/usr/lib/libc.so.6", PATH, NONE }, + { "/usr/$LIB/libMangoHud.so", PATH, DYN|ABI }, + { "${LIB}/libfoo.so", PATH, DYN|ABI }, + { "/usr/plat-$PLATFORM/libc.so.6", PATH, DYN|ABI }, + { "${PLATFORM}/libc.so.6", PATH, DYN|ABI }, + { "${ORIGIN}/../${LIB}/libc.so.6", PATH, DYN|ABI|ORIGIN }, + { "/$ORIGIN/libfoo", PATH, DYN|ORIGIN }, + { "$ORIGIN/$FUTURE/${PLATFORM}-libfoo.so", PATH, DYN|ORIGIN|ABI|UNKNOWN }, + { "${FUTURE}/libfoo.so", PATH, DYN|UNKNOWN }, + { "libc.so.6", BASE, NONE }, + { "libMangoHud.so", BASE, NONE }, + { "looks-like-${TOKENS}-interpreted-but-not-really", BASE, NONE }, +}; +#undef ERROR +#undef PATH +#undef BASE +#undef DYN +#undef ABI +#undef ORIGIN +#undef UNKNOWN +#undef NONE + +static void +test_libdl_classify (Fixture *f, + gconstpointer context) +{ + gsize i; + + for (i = 0; i < G_N_ELEMENTS (libdl_classify_tests); i++) + { + SrtLoadableFlags flags = -1; + SrtLoadableKind kind; + + kind = _srt_loadable_classify (libdl_classify_tests[i].loadable, &flags); + + g_assert_cmpuint (kind, ==, libdl_classify_tests[i].kind); + g_assert_cmphex (flags, ==, libdl_classify_tests[i].flags); + + kind = _srt_loadable_classify (libdl_classify_tests[i].loadable, NULL); + g_assert_cmpuint (kind, ==, libdl_classify_tests[i].kind); + } +} + +int +main (int argc, + char **argv) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add ("/libdl/classify", Fixture, NULL, setup, + test_libdl_classify, teardown); + + return g_test_run (); +} diff --git a/tests/meson.build b/tests/meson.build index 101e75e31900a75015316012b12cd4b6e6627e54..ff8b1be0d1dfa32104d1d2deb0f52c033fe07d57 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -42,6 +42,7 @@ tests = [ ], }, {'name': 'json-utils', 'static': true}, + {'name': 'libdl', 'static': true}, {'name': 'library'}, {'name': 'locale'}, {'name': 'system-info'},