diff --git a/bin/system-info.c b/bin/system-info.c index c9403bd635b65ed1188fc444e53adab069040b3c..23de35f6a42e54ed6547c4b003d4110780725e1c 100644 --- a/bin/system-info.c +++ b/bin/system-info.c @@ -648,10 +648,15 @@ static void jsonify_container (JsonBuilder *builder, SrtSystemInfo *info) { - SrtContainerType type = srt_system_info_get_container_type (info); - gchar *host_directory = srt_system_info_dup_container_host_directory (info); - gchar **env = NULL; - SrtSystemInfo *host = NULL; + SrtContainerInfo *container_info = srt_system_info_check_container (info); + SrtContainerType type = SRT_CONTAINER_TYPE_UNKNOWN; + const gchar *flatpak_version = NULL; + const gchar *host_directory = NULL; + g_autoptr(SrtSystemInfo) host = NULL; + + type = srt_container_info_get_container_type (container_info); + flatpak_version = srt_container_info_get_flatpak_version (container_info); + host_directory = srt_container_info_get_container_host_directory (container_info); json_builder_set_member_name (builder, "container"); json_builder_begin_object (builder); @@ -661,6 +666,12 @@ jsonify_container (JsonBuilder *builder, if (type != SRT_CONTAINER_TYPE_NONE) { + if (flatpak_version != NULL) + { + json_builder_set_member_name (builder, "flatpak_version"); + json_builder_add_string_value (builder, flatpak_version); + } + json_builder_set_member_name (builder, "host"); json_builder_begin_object (builder); { @@ -678,10 +689,6 @@ jsonify_container (JsonBuilder *builder, } } json_builder_end_object (builder); - - g_free (host_directory); - g_clear_object (&host); - g_strfreev (env); } static void diff --git a/bin/system-info.md b/bin/system-info.md index 233885754584f865e9cadf30b238bfec7121b4b4..4d492a02a14f6d009fca3e0e1e22816acc9c8f11 100644 --- a/bin/system-info.md +++ b/bin/system-info.md @@ -320,6 +320,11 @@ keys: **unknown** (if we appear to be in a container but the type is unknown), or **none** (if we do not appear to be in a container). + **flatpak_version** + : The version string describing the Flatpak container. This key is + optional and is not provided if it could not be determined or if the + container **type** is not **flatpak**. + **host** : An object describing the host system. The keys are strings: diff --git a/steam-runtime-tools/container-internal.h b/steam-runtime-tools/container-internal.h new file mode 100644 index 0000000000000000000000000000000000000000..db9dd42e1cb7664dd2c16b5d8a548ceb2b01adc7 --- /dev/null +++ b/steam-runtime-tools/container-internal.h @@ -0,0 +1,71 @@ +/*<private_header>*/ +/* + * 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. + */ + +#pragma once + +#include "steam-runtime-tools/container.h" + +#include <json-glib/json-glib.h> + +/* + * _srt_container_info_new: + * @type: Type of container + * @flatpak_version: (nullable): Flatpak container version, this value is + * relevant only if @type is %SRT_CONTAINER_TYPE_FLATPAK + * @host_directory: (nullable) (type filename): Directory where host files can + * be found + * + * Inline convenience function to create a new SrtContainerInfo. + * This is not part of the public API. + * + * Returns: (transfer full): A new #SrtContainerInfo + */ +static inline SrtContainerInfo *_srt_container_info_new (SrtContainerType type, + const gchar *flatpak_version, + const gchar *host_directory); + +#ifndef __GTK_DOC_IGNORE__ +static inline SrtContainerInfo * +_srt_container_info_new (SrtContainerType type, + const gchar *flatpak_version, + const gchar *host_directory) +{ + return g_object_new (SRT_TYPE_CONTAINER_INFO, + "type", type, + "flatpak-version", flatpak_version, + "host-directory", host_directory, + NULL); +} +#endif + +/* See flatpak-metadata(5) */ +#define FLATPAK_METADATA_GROUP_INSTANCE "Instance" +#define FLATPAK_METADATA_KEY_FLATPAK_VERSION "flatpak-version" + +SrtContainerInfo *_srt_check_container (int sysroot_fd, + const gchar *sysroot); + +SrtContainerInfo *_srt_container_info_get_from_report (JsonObject *json_obj); diff --git a/steam-runtime-tools/container.c b/steam-runtime-tools/container.c new file mode 100644 index 0000000000000000000000000000000000000000..e6506206ad275a8a3c1beae28094e97a5d70b070 --- /dev/null +++ b/steam-runtime-tools/container.c @@ -0,0 +1,490 @@ +/* + * 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/container.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <glib.h> +#include <gio/gio.h> + +#include "steam-runtime-tools/container-internal.h" +#include "steam-runtime-tools/enums.h" +#include "steam-runtime-tools/glib-backports-internal.h" +#include "steam-runtime-tools/json-glib-backports-internal.h" +#include "steam-runtime-tools/resolve-in-sysroot-internal.h" +#include "steam-runtime-tools/utils.h" +#include "steam-runtime-tools/utils-internal.h" + +/** + * SECTION:container-info + * @title: Container info + * @short_description: Information about the eventual container that is currently in use + * @include: steam-runtime-tools/steam-runtime-tools.h + */ + +struct _SrtContainerInfo +{ + /*< private >*/ + GObject parent; + gchar *flatpak_version; + gchar *host_directory; + SrtContainerType type; +}; + +struct _SrtContainerInfoClass +{ + /*< private >*/ + GObjectClass parent_class; +}; + +enum { + PROP_0, + PROP_FLATPAK_VERSION, + PROP_HOST_DIRECTORY, + PROP_TYPE, + N_PROPERTIES +}; + +G_DEFINE_TYPE (SrtContainerInfo, srt_container_info, G_TYPE_OBJECT) + +static void +srt_container_info_init (SrtContainerInfo *self) +{ +} + +static void +srt_container_info_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SrtContainerInfo *self = SRT_CONTAINER_INFO (object); + + switch (prop_id) + { + case PROP_FLATPAK_VERSION: + g_value_set_string (value, self->flatpak_version); + break; + + case PROP_HOST_DIRECTORY: + g_value_set_string (value, self->host_directory); + break; + + case PROP_TYPE: + g_value_set_enum (value, self->type); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +srt_container_info_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SrtContainerInfo *self = SRT_CONTAINER_INFO (object); + + switch (prop_id) + { + case PROP_FLATPAK_VERSION: + /* Construct-only */ + g_return_if_fail (self->flatpak_version == NULL); + self->flatpak_version = g_value_dup_string (value); + break; + + case PROP_HOST_DIRECTORY: + /* Construct-only */ + g_return_if_fail (self->host_directory == NULL); + self->host_directory = g_value_dup_string (value); + break; + + case PROP_TYPE: + /* Construct-only */ + g_return_if_fail (self->type == 0); + self->type = g_value_get_enum (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +srt_container_info_finalize (GObject *object) +{ + SrtContainerInfo *self = SRT_CONTAINER_INFO (object); + + g_free (self->flatpak_version); + g_free (self->host_directory); + + G_OBJECT_CLASS (srt_container_info_parent_class)->finalize (object); +} + +static GParamSpec *properties[N_PROPERTIES] = { NULL }; + +static void +srt_container_info_class_init (SrtContainerInfoClass *cls) +{ + GObjectClass *object_class = G_OBJECT_CLASS (cls); + + object_class->get_property = srt_container_info_get_property; + object_class->set_property = srt_container_info_set_property; + object_class->finalize = srt_container_info_finalize; + + properties[PROP_FLATPAK_VERSION] = + g_param_spec_string ("flatpak-version", "Flatpak version", + "Which Flatpak version, if any, is in use", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + properties[PROP_HOST_DIRECTORY] = + g_param_spec_string ("host-directory", "Host directory", + "Absolute path where important files from the host " + "system can be found", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + properties[PROP_TYPE] = + g_param_spec_enum ("type", "Container type", + "Which container type is currently in use", + SRT_TYPE_CONTAINER_TYPE, SRT_CONTAINER_TYPE_UNKNOWN, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, N_PROPERTIES, properties); +} + +typedef struct +{ + SrtContainerType type; + const char *name; +} ContainerTypeName; + +static const ContainerTypeName container_types[] = +{ + { SRT_CONTAINER_TYPE_DOCKER, "docker" }, + { SRT_CONTAINER_TYPE_FLATPAK, "flatpak" }, + { SRT_CONTAINER_TYPE_PODMAN, "podman" }, + { SRT_CONTAINER_TYPE_PRESSURE_VESSEL, "pressure-vessel" }, +}; + +static SrtContainerType +container_type_from_name (const char *name) +{ + gsize i; + + for (i = 0; i < G_N_ELEMENTS (container_types); i++) + { + const ContainerTypeName *entry = &container_types[i]; + + if (strcmp (entry->name, name) == 0) + return entry->type; + } + + return SRT_CONTAINER_TYPE_UNKNOWN; +} + +/** + * _srt_check_container: + * @sysroot_fd: Sysroot file descriptor + * @sysroot: (not nullable) (type filename): Path to the sysroot + * + * Gather and return information about the container that is currently in use. + * + * Returns: (transfer full): A new #SrtContainerInfo object. + * Free with g_object_unref(). + */ +SrtContainerInfo * +_srt_check_container (int sysroot_fd, + const gchar *sysroot) +{ + g_autofree gchar *contents = NULL; + g_autofree gchar *run_host_path = NULL; + g_autofree gchar *host_directory = NULL; + g_autofree gchar *flatpak_version = NULL; + SrtContainerType type = SRT_CONTAINER_TYPE_UNKNOWN; + glnx_autofd int run_host_fd = -1; + + g_return_val_if_fail (sysroot != NULL, NULL); + + if (sysroot_fd < 0) + { + g_debug ("Cannot find container info: previously failed to open " + "sysroot %s", sysroot); + goto out; + } + + g_debug ("Finding container info in sysroot %s...", sysroot); + + run_host_fd = _srt_resolve_in_sysroot (sysroot_fd, "/run/host", + SRT_RESOLVE_FLAGS_DIRECTORY, + &run_host_path, NULL); + + if (run_host_path != NULL) + host_directory = g_build_filename (sysroot, run_host_path, NULL); + + if (_srt_file_get_contents_in_sysroot (sysroot_fd, + "/run/host/container-manager", + &contents, NULL, NULL)) + { + g_strchomp (contents); + type = container_type_from_name (contents); + g_debug ("Type %d based on /run/host/container-manager", type); + goto out; + } + + if (_srt_file_get_contents_in_sysroot (sysroot_fd, + "/run/systemd/container", + &contents, NULL, NULL)) + { + g_strchomp (contents); + type = container_type_from_name (contents); + g_debug ("Type %d based on /run/systemd/container", type); + goto out; + } + + if (_srt_file_test_in_sysroot (sysroot, sysroot_fd, "/.flatpak-info", + G_FILE_TEST_IS_REGULAR)) + { + type = SRT_CONTAINER_TYPE_FLATPAK; + g_debug ("Flatpak based on /.flatpak-info"); + goto out; + } + + if (_srt_file_test_in_sysroot (sysroot, sysroot_fd, "/run/pressure-vessel", + G_FILE_TEST_IS_DIR)) + { + type = SRT_CONTAINER_TYPE_PRESSURE_VESSEL; + g_debug ("pressure-vessel based on /run/pressure-vessel"); + goto out; + } + + if (_srt_file_test_in_sysroot (sysroot, sysroot_fd, "/.dockerenv", + G_FILE_TEST_EXISTS)) + { + type = SRT_CONTAINER_TYPE_DOCKER; + g_debug ("Docker based on /.dockerenv"); + goto out; + } + + if (_srt_file_test_in_sysroot (sysroot, sysroot_fd, "/run/.containerenv", + G_FILE_TEST_EXISTS)) + { + type = SRT_CONTAINER_TYPE_PODMAN; + g_debug ("Podman based on /run/.containerenv"); + goto out; + } + + if (_srt_file_get_contents_in_sysroot (sysroot_fd, "/proc/1/cgroup", + &contents, NULL, NULL)) + { + if (strstr (contents, "/docker/") != NULL) + type = SRT_CONTAINER_TYPE_DOCKER; + + if (type != SRT_CONTAINER_TYPE_UNKNOWN) + { + g_debug ("Type %d based on /proc/1/cgroup", type); + goto out; + } + + g_clear_pointer (&contents, g_free); + } + + if (run_host_fd >= 0) + { + g_debug ("Unknown container technology based on /run/host"); + type = SRT_CONTAINER_TYPE_UNKNOWN; + goto out; + } + + /* We haven't found any particular evidence of being in a container */ + g_debug ("Probably not a container"); + type = SRT_CONTAINER_TYPE_NONE; + +out: + if (type == SRT_CONTAINER_TYPE_FLATPAK) + { + g_autoptr(GKeyFile) info = NULL; + g_autoptr(GError) local_error = NULL; + g_autofree gchar *flatpak_info_content = NULL; + gsize len; + + if (_srt_file_get_contents_in_sysroot (sysroot_fd, "/.flatpak-info", + &flatpak_info_content, + &len, NULL)) + { + info = g_key_file_new (); + + if (!g_key_file_load_from_data (info, flatpak_info_content, len, + G_KEY_FILE_NONE, &local_error)) + g_debug ("Unable to load Flatpak instance info: %s", local_error->message); + + flatpak_version = g_key_file_get_string (info, + FLATPAK_METADATA_GROUP_INSTANCE, + FLATPAK_METADATA_KEY_FLATPAK_VERSION, + NULL); + } + } + + return _srt_container_info_new (type, flatpak_version, host_directory); +} + +/** + * srt_container_info_get_container_type: + * @self: A SrtContainerInfo object + * + * If the program appears to be running in a container, return what sort + * of container it is. + * + * Implementation of srt_system_info_get_container_type(). + * + * Returns: A recognised container type, or %SRT_CONTAINER_TYPE_NONE + * if a container cannot be detected, or %SRT_CONTAINER_TYPE_UNKNOWN + * if unsure. + */ +SrtContainerType +srt_container_info_get_container_type (SrtContainerInfo *self) +{ + g_return_val_if_fail (SRT_IS_CONTAINER_INFO (self), SRT_CONTAINER_TYPE_UNKNOWN); + return self->type; +} + +/** + * srt_container_info_get_container_host_directory: + * @self: A SrtContainerInfo object + * + * If the program appears to be running in a container, return the + * directory where host files can be found. For example, if this function + * returns `/run/host`, it might be possible to load the host system's + * `/usr/lib/os-release` by reading `/run/host/usr/lib/os-release`. + * + * The returned directory is usually not complete. For example, + * in a Flatpak app, `/run/host` will sometimes contain the host system's + * `/etc` and `/usr`, but only if suitable permissions flags are set. + * + * Implementation of srt_system_info_dup_container_host_directory(). + * + * Returns: (type filename) (nullable): A path from which at least some + * host-system files can be loaded, typically `/run/host`, or %NULL if + * unknown or unavailable. + */ +const gchar * +srt_container_info_get_container_host_directory (SrtContainerInfo *self) +{ + g_return_val_if_fail (SRT_IS_CONTAINER_INFO (self), NULL); + return self->host_directory; +} + +/** + * srt_container_info_get_flatpak_version: + * @self: A SrtContainerInfo object + * + * If the program appears to be running in a container type + * %SRT_CONTAINER_TYPE_FLATPAK, return the Flatpak version. + * + * Returns: (type filename) (nullable): A filename, or %NULL if the container + * type is not %SRT_CONTAINER_TYPE_FLATPAK or if it was not able to identify + * the Flatpak version. + */ +const gchar * +srt_container_info_get_flatpak_version (SrtContainerInfo *self) +{ + g_return_val_if_fail (SRT_IS_CONTAINER_INFO (self), NULL); + + if (self->type != SRT_CONTAINER_TYPE_FLATPAK) + return NULL; + + return self->flatpak_version; +} + +/** + * _srt_system_info_get_container_info_from_report: + * @json_obj: (not nullable): A JSON Object used to search for "container" + * property + * @host_path: (not nullable): Used to return the host path + * + * If the provided @json_obj doesn't have a "container" member, + * %SRT_CONTAINER_TYPE_UNKNOWN will be returned. + * If @json_obj has some elements that we can't parse, the returned + * #SrtContainerType will be set to %SRT_CONTAINER_TYPE_UNKNOWN. + * + * Returns: The found container type + */ +SrtContainerInfo * +_srt_container_info_get_from_report (JsonObject *json_obj) +{ + JsonObject *json_sub_obj; + JsonObject *json_host_obj = NULL; + const gchar *type_string = NULL; + const gchar *flatpak_version = NULL; + const gchar *host_path = NULL; + SrtContainerType type = SRT_CONTAINER_TYPE_UNKNOWN; + + g_return_val_if_fail (json_obj != NULL, NULL); + + if (json_object_has_member (json_obj, "container")) + { + json_sub_obj = json_object_get_object_member (json_obj, "container"); + + if (json_sub_obj == NULL) + goto out; + + if (json_object_has_member (json_sub_obj, "type")) + { + type_string = json_object_get_string_member (json_sub_obj, "type"); + G_STATIC_ASSERT (sizeof (SrtContainerType) == sizeof (gint)); + if (!srt_enum_from_nick (SRT_TYPE_CONTAINER_TYPE, type_string, (gint *) &type, NULL)) + { + g_debug ("The parsed container type '%s' is not a known element", type_string); + type = SRT_CONTAINER_TYPE_UNKNOWN; + } + } + + flatpak_version = json_object_get_string_member_with_default (json_sub_obj, + "flatpak_version", + NULL); + + if (json_object_has_member (json_sub_obj, "host")) + { + json_host_obj = json_object_get_object_member (json_sub_obj, "host"); + host_path = json_object_get_string_member_with_default (json_host_obj, "path", + NULL); + } + } + +out: + return _srt_container_info_new (type, + flatpak_version, + host_path); +} diff --git a/steam-runtime-tools/container.h b/steam-runtime-tools/container.h new file mode 100644 index 0000000000000000000000000000000000000000..63e1177fdb5735f9fb1e3ce03ea16962f6aeb44d --- /dev/null +++ b/steam-runtime-tools/container.h @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#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 + +#include <glib.h> +#include <glib-object.h> + +#include <steam-runtime-tools/macros.h> + +typedef struct _SrtContainerInfo SrtContainerInfo; +typedef struct _SrtContainerInfoClass SrtContainerInfoClass; + +#define SRT_TYPE_CONTAINER_INFO srt_container_info_get_type () +#define SRT_CONTAINER_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SRT_TYPE_CONTAINER_INFO, SrtContainerInfo)) +#define SRT_CONTAINER_INFO_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST ((cls), SRT_TYPE_CONTAINER_INFO, SrtContainerInfoClass)) +#define SRT_IS_CONTAINER_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SRT_TYPE_CONTAINER_INFO)) +#define SRT_IS_CONTAINER_INFO_CLASS(cls) (G_TYPE_CHECK_CLASS_TYPE ((cls), SRT_TYPE_CONTAINER_INFO)) +#define SRT_CONTAINER_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), SRT_TYPE_CONTAINER_INFO, SrtContainerInfoClass) +_SRT_PUBLIC +GType srt_container_info_get_type (void); + +/** + * SrtContainerType: + * @SRT_CONTAINER_TYPE_UNKNOWN: Unknown container type + * @SRT_CONTAINER_TYPE_NONE: No container detected + * @SRT_CONTAINER_TYPE_FLATPAK: Running in a Flatpak app + * @SRT_CONTAINER_TYPE_PRESSURE_VESSEL: Running in a Steam Runtime container + * using pressure-vessel + * @SRT_CONTAINER_TYPE_DOCKER: Running in a Docker container + * @SRT_CONTAINER_TYPE_PODMAN: Running in a Podman container + * + * A type of container. + */ +typedef enum +{ + SRT_CONTAINER_TYPE_NONE = 0, + SRT_CONTAINER_TYPE_FLATPAK, + SRT_CONTAINER_TYPE_PRESSURE_VESSEL, + SRT_CONTAINER_TYPE_DOCKER, + SRT_CONTAINER_TYPE_PODMAN, + SRT_CONTAINER_TYPE_UNKNOWN = -1 +} SrtContainerType; + +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC (SrtContainerInfo, g_object_unref) +#endif + +_SRT_PUBLIC +SrtContainerType srt_container_info_get_container_type (SrtContainerInfo *self); +_SRT_PUBLIC +const gchar *srt_container_info_get_container_host_directory (SrtContainerInfo *self); +_SRT_PUBLIC +const gchar *srt_container_info_get_flatpak_version (SrtContainerInfo *self); diff --git a/steam-runtime-tools/meson.build b/steam-runtime-tools/meson.build index 1f5ea949bd7d893c3723cd4640f5e5c03263d8ae..bd647f8277544761102bd33151c73d451630c096 100644 --- a/steam-runtime-tools/meson.build +++ b/steam-runtime-tools/meson.build @@ -24,6 +24,7 @@ libsteamrt_sources = [ 'architecture-internal.h', 'architecture.c', + 'container.c', 'cpu-feature-internal.h', 'cpu-feature.c', 'desktop-entry-internal.h', @@ -69,6 +70,7 @@ libsteamrt_sources = [ libsteamrt_public_headers = [ 'architecture.h', + 'container.h', 'cpu-feature.h', 'desktop-entry.h', 'graphics.h', diff --git a/steam-runtime-tools/steam-runtime-tools.h b/steam-runtime-tools/steam-runtime-tools.h index c6009f7c81d70e17bca872da67e81f29f7542307..83ad7ca5315810466343badb71879da9c0f84de3 100644 --- a/steam-runtime-tools/steam-runtime-tools.h +++ b/steam-runtime-tools/steam-runtime-tools.h @@ -28,6 +28,7 @@ #define _SRT_IN_SINGLE_HEADER #include <steam-runtime-tools/architecture.h> +#include <steam-runtime-tools/container.h> #include <steam-runtime-tools/cpu-feature.h> #include <steam-runtime-tools/desktop-entry.h> #include <steam-runtime-tools/enums.h> diff --git a/steam-runtime-tools/system-info.c b/steam-runtime-tools/system-info.c index 4995bc6810f5cb776b9b701dca218071429c6366..be2c172f69ff8d638355c7df6e520ca2ca3a772e 100644 --- a/steam-runtime-tools/system-info.c +++ b/steam-runtime-tools/system-info.c @@ -32,6 +32,7 @@ #include "steam-runtime-tools/architecture.h" #include "steam-runtime-tools/architecture-internal.h" +#include "steam-runtime-tools/container-internal.h" #include "steam-runtime-tools/cpu-feature-internal.h" #include "steam-runtime-tools/desktop-entry-internal.h" #include "steam-runtime-tools/graphics.h" @@ -117,6 +118,7 @@ struct _SrtSystemInfo /* If %TRUE, #SrtSystemInfo cannot be changed anymore */ gboolean immutable_values; GHashTable *cached_hidden_deps; + SrtContainerInfo *container_info; SrtSteam *steam_data; SrtXdgPortal *xdg_portal_data; struct @@ -164,12 +166,6 @@ struct _SrtSystemInfo gboolean have_data; } pinned_libs; struct - { - SrtContainerType type; - gchar *host_directory; - gboolean have_data; - } container; - struct { GList *values; gboolean have_data; @@ -373,8 +369,6 @@ srt_system_info_init (SrtSystemInfo *self) _srt_os_release_init (&self->os_release); - self->container.type = SRT_CONTAINER_TYPE_UNKNOWN; - srt_system_info_set_sysroot (self, "/"); srt_system_info_set_environ (self, NULL); } @@ -433,9 +427,7 @@ forget_desktop_entries (SrtSystemInfo *self) static void forget_container_info (SrtSystemInfo *self) { - g_clear_pointer (&self->container.host_directory, g_free); - self->container.type = SRT_CONTAINER_TYPE_UNKNOWN; - self->container.have_data = FALSE; + g_clear_object (&self->container_info); } /* @@ -629,8 +621,6 @@ srt_system_info_new (const char *expectations) } static gchar ** _srt_system_info_driver_environment_from_report (JsonObject *json_obj); -static SrtContainerType _srt_system_info_get_container_info_from_report (JsonObject *json_obj, - gchar **host_path); static gchar ** _srt_system_info_get_pinned_libs_from_report (JsonObject *json_obj, const gchar *which, gchar ***messages); @@ -857,8 +847,7 @@ srt_system_info_new_from_json (const char *path, _srt_os_release_populate_from_report (json_obj, &info->os_release); - info->container.type = _srt_system_info_get_container_info_from_report (json_obj, - &info->container.host_directory); + info->container_info = _srt_container_info_get_from_report (json_obj); info->cached_driver_environment = _srt_system_info_driver_environment_from_report (json_obj); @@ -3859,151 +3848,31 @@ _srt_system_info_driver_environment_from_report (JsonObject *json_obj) "<invalid>"); } -typedef struct -{ - SrtContainerType type; - const char *name; -} ContainerTypeName; - -static const ContainerTypeName container_types[] = -{ - { SRT_CONTAINER_TYPE_DOCKER, "docker" }, - { SRT_CONTAINER_TYPE_FLATPAK, "flatpak" }, - { SRT_CONTAINER_TYPE_PODMAN, "podman" }, - { SRT_CONTAINER_TYPE_PRESSURE_VESSEL, "pressure-vessel" }, -}; - -static SrtContainerType -container_type_from_name (const char *name) -{ - gsize i; - - for (i = 0; i < G_N_ELEMENTS (container_types); i++) - { - const ContainerTypeName *entry = &container_types[i]; - - if (strcmp (entry->name, name) == 0) - return entry->type; - } - - return SRT_CONTAINER_TYPE_UNKNOWN; -} - static void ensure_container_info (SrtSystemInfo *self) { - g_autofree gchar *contents = NULL; - g_autofree gchar *run_host_path = NULL; - glnx_autofd int run_host_fd = -1; - - if (self->container.have_data || self->immutable_values) - return; - - g_assert (self->container.host_directory == NULL); - g_assert (self->container.type == SRT_CONTAINER_TYPE_UNKNOWN); - g_assert (self->sysroot != NULL); - - if (self->sysroot_fd < 0) - { - g_debug ("Cannot find container info: previously failed to open " - "sysroot %s", self->sysroot); - goto out; - } - - g_debug ("Finding container info in sysroot %s...", self->sysroot); - - run_host_fd = _srt_resolve_in_sysroot (self->sysroot_fd, "/run/host", - SRT_RESOLVE_FLAGS_DIRECTORY, - &run_host_path, NULL); - - if (run_host_path != NULL) - self->container.host_directory = g_build_filename (self->sysroot, - run_host_path, - NULL); - - if (_srt_file_get_contents_in_sysroot (self->sysroot_fd, - "/run/host/container-manager", - &contents, NULL, NULL)) - { - g_strchomp (contents); - self->container.type = container_type_from_name (contents); - g_debug ("Type %d based on /run/host/container-manager", - self->container.type); - goto out; - } - - if (_srt_file_get_contents_in_sysroot (self->sysroot_fd, - "/run/systemd/container", - &contents, NULL, NULL)) - { - g_strchomp (contents); - self->container.type = container_type_from_name (contents); - g_debug ("Type %d based on /run/systemd/container", - self->container.type); - goto out; - } - - if (_srt_file_test_in_sysroot (self->sysroot, self->sysroot_fd, - "/.flatpak-info", G_FILE_TEST_IS_REGULAR)) - { - self->container.type = SRT_CONTAINER_TYPE_FLATPAK; - g_debug ("Flatpak based on /.flatpak-info"); - goto out; - } - - if (_srt_file_test_in_sysroot (self->sysroot, self->sysroot_fd, - "/run/pressure-vessel", G_FILE_TEST_IS_DIR)) - { - self->container.type = SRT_CONTAINER_TYPE_PRESSURE_VESSEL; - g_debug ("pressure-vessel based on /run/pressure-vessel"); - goto out; - } - - if (_srt_file_test_in_sysroot (self->sysroot, self->sysroot_fd, - "/.dockerenv", G_FILE_TEST_EXISTS)) - { - self->container.type = SRT_CONTAINER_TYPE_DOCKER; - g_debug ("Docker based on /.dockerenv"); - goto out; - } - - if (_srt_file_test_in_sysroot (self->sysroot, self->sysroot_fd, - "/run/.containerenv", G_FILE_TEST_EXISTS)) - { - self->container.type = SRT_CONTAINER_TYPE_PODMAN; - g_debug ("Podman based on /run/.containerenv"); - goto out; - } - - if (_srt_file_get_contents_in_sysroot (self->sysroot_fd, - "/proc/1/cgroup", - &contents, NULL, NULL)) - { - if (strstr (contents, "/docker/") != NULL) - self->container.type = SRT_CONTAINER_TYPE_DOCKER; - - if (self->container.type != SRT_CONTAINER_TYPE_UNKNOWN) - { - g_debug ("Type %d based on /proc/1/cgroup", self->container.type); - goto out; - } - - g_clear_pointer (&contents, g_free); - } + g_return_if_fail (SRT_IS_SYSTEM_INFO (self)); - if (run_host_fd >= 0) - { - g_debug ("Unknown container technology based on /run/host"); - self->container.type = SRT_CONTAINER_TYPE_UNKNOWN; - goto out; - } + if (self->container_info == NULL && !self->immutable_values) + self->container_info = _srt_check_container (self->sysroot_fd, self->sysroot); +} - /* We haven't found any particular evidence of being in a container */ - g_debug ("Probably not a container"); - self->container.type = SRT_CONTAINER_TYPE_NONE; +/** + * srt_system_info_check_container: + * @self: The #SrtSystemInfo object + * + * Gather and return information about the container that is currently in use. + * + * Returns: (transfer full): An #SrtContainerInfo object. + * Free with g_object_unref(). + */ +SrtContainerInfo * +srt_system_info_check_container (SrtSystemInfo *self) +{ + g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), NULL); -out: - self->container.have_data = TRUE; + ensure_container_info (self); + return g_object_ref (self->container_info); } /** @@ -4023,7 +3892,7 @@ srt_system_info_get_container_type (SrtSystemInfo *self) g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), SRT_CONTAINER_TYPE_UNKNOWN); ensure_container_info (self); - return self->container.type; + return srt_container_info_get_container_type (self->container_info); } /** @@ -4048,60 +3917,7 @@ srt_system_info_dup_container_host_directory (SrtSystemInfo *self) g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), NULL); ensure_container_info (self); - return g_strdup (self->container.host_directory); -} - -/** - * _srt_system_info_get_container_info_from_report: - * @json_obj: (not nullable): A JSON Object used to search for "container" - * property - * @host_path: (not nullable): Used to return the host path - * - * If the provided @json_obj doesn't have a "container" member, - * %SRT_CONTAINER_TYPE_UNKNOWN will be returned. - * If @json_obj has some elements that we can't parse, the returned - * #SrtContainerType will be set to %SRT_CONTAINER_TYPE_UNKNOWN. - * - * Returns: The found container type - */ -static SrtContainerType -_srt_system_info_get_container_info_from_report (JsonObject *json_obj, - gchar **host_path) -{ - JsonObject *json_sub_obj; - JsonObject *json_host_obj = NULL; - const gchar *type_string = NULL; - SrtContainerType ret = SRT_CONTAINER_TYPE_UNKNOWN; - - g_return_val_if_fail (host_path != NULL && *host_path == NULL, SRT_CONTAINER_TYPE_UNKNOWN); - - if (json_object_has_member (json_obj, "container")) - { - json_sub_obj = json_object_get_object_member (json_obj, "container"); - - if (json_sub_obj == NULL) - goto out; - - if (json_object_has_member (json_sub_obj, "type")) - { - type_string = json_object_get_string_member (json_sub_obj, "type"); - if (!srt_enum_from_nick (SRT_TYPE_CONTAINER_TYPE, type_string, &ret, NULL)) - { - g_debug ("The parsed container type '%s' is not a known element", type_string); - ret = SRT_CONTAINER_TYPE_UNKNOWN; - } - } - - if (json_object_has_member (json_sub_obj, "host")) - { - json_host_obj = json_object_get_object_member (json_sub_obj, "host"); - *host_path = g_strdup (json_object_get_string_member_with_default (json_host_obj, "path", - NULL)); - } - } - -out: - return ret; + return g_strdup (srt_container_info_get_container_host_directory (self->container_info)); } static void @@ -4267,7 +4083,7 @@ ensure_xdg_portals_cached (SrtSystemInfo *self) _srt_check_xdg_portals (self->env, self->helpers_path, self->test_flags, - self->container.type, + srt_container_info_get_container_type (self->container_info), srt_system_info_get_primary_multiarch_tuple (self), &self->xdg_portal_data); } diff --git a/steam-runtime-tools/system-info.h b/steam-runtime-tools/system-info.h index 5b3c91a1320c6b3be826ecd851f1151c0d721531..935c82a2b66f23fac3040169809bc78554e0180e 100644 --- a/steam-runtime-tools/system-info.h +++ b/steam-runtime-tools/system-info.h @@ -32,6 +32,7 @@ #include <glib.h> #include <glib-object.h> +#include <steam-runtime-tools/container.h> #include <steam-runtime-tools/cpu-feature.h> #include <steam-runtime-tools/graphics.h> #include <steam-runtime-tools/library.h> @@ -74,28 +75,6 @@ typedef enum SRT_DRIVER_FLAGS_NONE = 0 } SrtDriverFlags; -/** - * SrtContainerType: - * @SRT_CONTAINER_TYPE_UNKNOWN: Unknown container type - * @SRT_CONTAINER_TYPE_NONE: No container detected - * @SRT_CONTAINER_TYPE_FLATPAK: Running in a Flatpak app - * @SRT_CONTAINER_TYPE_PRESSURE_VESSEL: Running in a Steam Runtime container - * using pressure-vessel - * @SRT_CONTAINER_TYPE_DOCKER: Running in a Docker container - * @SRT_CONTAINER_TYPE_PODMAN: Running in a Podman container - * - * A type of container. - */ -typedef enum -{ - SRT_CONTAINER_TYPE_NONE = 0, - SRT_CONTAINER_TYPE_FLATPAK, - SRT_CONTAINER_TYPE_PRESSURE_VESSEL, - SRT_CONTAINER_TYPE_DOCKER, - SRT_CONTAINER_TYPE_PODMAN, - SRT_CONTAINER_TYPE_UNKNOWN = -1 -} SrtContainerType; - typedef struct _SrtSystemInfo SrtSystemInfo; typedef struct _SrtSystemInfoClass SrtSystemInfoClass; @@ -120,6 +99,8 @@ _SRT_PUBLIC gboolean srt_system_info_can_run (SrtSystemInfo *self, const char *multiarch_tuple); _SRT_PUBLIC +SrtContainerInfo *srt_system_info_check_container (SrtSystemInfo *self); +_SRT_PUBLIC SrtContainerType srt_system_info_get_container_type (SrtSystemInfo *self); _SRT_PUBLIC gchar *srt_system_info_dup_container_host_directory (SrtSystemInfo *self); diff --git a/steam-runtime-tools/xdg-portal-internal.h b/steam-runtime-tools/xdg-portal-internal.h index 3eeddcfa5ba98de74696a7171ed9bcd661f7db3d..3999a9100010409f4ac58e96fb559112559ac5a1 100644 --- a/steam-runtime-tools/xdg-portal-internal.h +++ b/steam-runtime-tools/xdg-portal-internal.h @@ -27,6 +27,7 @@ #pragma once #include "steam-runtime-tools/steam-runtime-tools.h" +#include "steam-runtime-tools/container-internal.h" #include <json-glib/json-glib.h> diff --git a/steam-runtime-tools/xdg-portal.c b/steam-runtime-tools/xdg-portal.c index 36b12fec053a9a22e64839903911c57f99877ff1..8aa09c7720a730e4535079fd5ba33700434a6b61 100644 --- a/steam-runtime-tools/xdg-portal.c +++ b/steam-runtime-tools/xdg-portal.c @@ -25,6 +25,7 @@ #include "steam-runtime-tools/xdg-portal.h" +#include "steam-runtime-tools/container-internal.h" #include "steam-runtime-tools/enums.h" #include "steam-runtime-tools/glib-backports-internal.h" #include "steam-runtime-tools/json-glib-backports-internal.h" diff --git a/tests/container.c b/tests/container.c new file mode 100644 index 0000000000000000000000000000000000000000..50de5d803e549d8507625011ca14bee2cc11f3b7 --- /dev/null +++ b/tests/container.c @@ -0,0 +1,232 @@ +/* + * 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 it before steam-runtime-tools.h so that its backport of + * G_DEFINE_AUTOPTR_CLEANUP_FUNC will be visible to it */ +#include "steam-runtime-tools/glib-backports-internal.h" + +#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/container-internal.h" +#include "steam-runtime-tools/utils-internal.h" +#include "test-utils.h" + +static const char *argv0; +static gchar *global_sysroots; + +typedef struct +{ + gchar *builddir; +} Fixture; + +typedef struct +{ + int unused; +} Config; + +static void +setup (Fixture *f, + gconstpointer context) +{ + G_GNUC_UNUSED const Config *config = context; + f->builddir = g_strdup (g_getenv ("G_TEST_BUILDDIR")); + + if (f->builddir == NULL) + f->builddir = g_path_get_dirname (argv0); +} + +static void +teardown (Fixture *f, + gconstpointer context) +{ + G_GNUC_UNUSED const Config *config = context; + + g_free (f->builddir); +} + +/* + * Test basic functionality of the SrtContainerInfo object. + */ +static void +test_object (Fixture *f, + gconstpointer context) +{ + g_autoptr(SrtContainerInfo) container = NULL; + SrtContainerType type; + g_autofree gchar *flatpak_version = NULL; + g_autofree gchar *host_directory = NULL; + + container = _srt_container_info_new (SRT_CONTAINER_TYPE_FLATPAK, + "1.10.2", + "/run/host"); + + g_assert_cmpint (srt_container_info_get_container_type (container), ==, + SRT_CONTAINER_TYPE_FLATPAK); + g_assert_cmpstr (srt_container_info_get_flatpak_version (container), ==, "1.10.2"); + g_assert_cmpstr (srt_container_info_get_container_host_directory (container), ==, + "/run/host"); + g_object_get (container, + "type", &type, + "flatpak-version", &flatpak_version, + "host-directory", &host_directory, + NULL); + g_assert_cmpint (type, ==, SRT_CONTAINER_TYPE_FLATPAK); + g_assert_cmpstr (flatpak_version, ==, "1.10.2"); + g_assert_cmpstr (host_directory, ==, "/run/host"); +} + +typedef struct +{ + const char *description; + const char *sysroot; + SrtContainerType type; + const char *host_directory; + const char *flatpak_version; +} ContainerTest; + +static const ContainerTest container_tests[] = +{ + { + .description = "Has /.dockerenv", + .sysroot = "debian-unstable", + .type = SRT_CONTAINER_TYPE_DOCKER, + }, + { + .description = "Has an unknown value in /run/systemd/container", + .sysroot = "debian10", + .type = SRT_CONTAINER_TYPE_UNKNOWN, + }, + { + .description = "Has 'docker' in /run/systemd/container", + .sysroot = "fedora", + .type = SRT_CONTAINER_TYPE_DOCKER, + }, + { + .description = "Has /.flatpak-info and /run/host", + .sysroot = "flatpak-example", + .type = SRT_CONTAINER_TYPE_FLATPAK, + .host_directory = "/run/host", + .flatpak_version = "1.10.2", + }, + { + .description = "Has /run/host", + .sysroot = "invalid-os-release", + .type = SRT_CONTAINER_TYPE_UNKNOWN, + .host_directory = "/run/host", + }, + { + .description = "Has no evidence of being a container", + .sysroot = "no-os-release", + .type = SRT_CONTAINER_TYPE_NONE, + }, + { + .description = "Has /run/pressure-vessel", + .sysroot = "steamrt", + .type = SRT_CONTAINER_TYPE_PRESSURE_VESSEL, + }, + { + .description = "Has a Docker-looking /proc/1/cgroup", + .sysroot = "steamrt-unofficial", + .type = SRT_CONTAINER_TYPE_DOCKER, + }, + { + .description = "Has 'podman' in /run/host/container-manager", + .sysroot = "podman-example", + .type = SRT_CONTAINER_TYPE_PODMAN, + .host_directory = "/run/host", + }, +}; + +static void +test_containers (Fixture *f, + gconstpointer context) +{ + gsize i, j; + + for (i = 0; i < G_N_ELEMENTS (container_tests); i++) + { + const ContainerTest *test = &container_tests[i]; + g_autoptr(SrtSystemInfo) info; + g_autofree gchar *expected_host = NULL; + g_autofree gchar *sysroot = NULL; + + g_test_message ("%s: %s", test->sysroot, test->description); + + sysroot = g_build_filename (global_sysroots, test->sysroot, NULL); + + info = srt_system_info_new (NULL); + g_assert_nonnull (info); + srt_system_info_set_sysroot (info, sysroot); + + if (test->host_directory == NULL) + expected_host = NULL; + else + expected_host = g_build_filename (sysroot, test->host_directory, NULL); + + for (j = 0; j < 2; j++) + { + g_autoptr(SrtContainerInfo) container = NULL; + g_autofree gchar *host_dir_dup = NULL; + + container = srt_system_info_check_container (info); + g_assert_nonnull (container); + + g_assert_cmpint (srt_system_info_get_container_type (info), ==, + test->type); + g_assert_cmpint (srt_container_info_get_container_type (container), ==, + test->type); + + host_dir_dup = srt_system_info_dup_container_host_directory (info); + g_assert_cmpstr (host_dir_dup, ==, expected_host); + g_assert_cmpstr (srt_container_info_get_container_host_directory (container), + ==, expected_host); + + g_assert_cmpstr (srt_container_info_get_flatpak_version (container), + ==, test->flatpak_version); + } + } +} + +int +main (int argc, + char **argv) +{ + argv0 = argv[0]; + global_sysroots = _srt_global_setup_sysroots (argv0); + + g_test_init (&argc, &argv, NULL); + g_test_add ("/container/object", Fixture, NULL, + setup, test_object, teardown); + g_test_add ("/container/containers", Fixture, NULL, + setup, test_containers, teardown); + + return g_test_run (); +} diff --git a/tests/generate-sysroots.py b/tests/generate-sysroots.py index f64f7a3507479d5e4a52e60a5a1f77227a179b6e..ece15e13563215e80eceeee53a69e8f2d33c4c8c 100755 --- a/tests/generate-sysroots.py +++ b/tests/generate-sysroots.py @@ -117,6 +117,7 @@ no-os-release/custom_path64/dri no-os-release/custom_path64/va no-os-release/usr/lib/dri no-os-release/usr/lib/vdpau +podman-example/run/host steamrt/etc steamrt/overrides/bin steamrt/overrides/lib/x86_64-linux-gnu @@ -206,7 +207,6 @@ fedora/usr/lib64/libva.so.2 fedora/usr/lib64/libvdpau.so.1 fedora/usr/lib64/vdpau/libvdpau_r300.so fedora/usr/lib64/vdpau/libvdpau_radeonsi.so -flatpak-example/.flatpak-info flatpak-example/usr/lib/dri/r300_dri.so flatpak-example/usr/lib/dri/r600_drv_video.so flatpak-example/usr/lib/x86_64-mock-abi/GL/lib/dri/i965_dri.so @@ -307,6 +307,23 @@ for name, target in { except FileExistsError: pass +with open('flatpak-example/.flatpak-info', 'w') as writer: + writer.write('''\ +[Application] +name=com.valvesoftware.Steam +runtime=runtime/org.freedesktop.Platform/x86_64/20.08 + +[Instance] +branch=stable +arch=x86_64 +flatpak-version=1.10.2 +session-bus-proxy=true +system-bus-proxy=true +devel=true''') + +with open('podman-example/run/host/container-manager', 'w') as writer: + writer.write("podman") + with open('debian10/custom_path/Single-good-layer.json', 'w') as writer: writer.write('''\ { diff --git a/tests/json-report/partial-report.json b/tests/json-report/partial-report.json index b3e13c453f3ebe50dd1fd7f60c785ab2eb2f98b7..bec5fcd8caf34299c49914675ebd0b6b99893153 100644 --- a/tests/json-report/partial-report.json +++ b/tests/json-report/partial-report.json @@ -1,6 +1,7 @@ { "container" : { "type" : "flatpak", + "flatpak_version" : "1.10.2", "host" : { "path" : null } diff --git a/tests/meson.build b/tests/meson.build index 59b03554682d15c0870db70173c01ab1afa0a149..a372c1ca1353c03a1bef17ce7d375954073757cf 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -29,6 +29,7 @@ test_env.prepend('PATH', join_paths(meson.current_build_dir(), '..', 'bin')) tests = [ {'name': 'architecture'}, + {'name': 'container'}, {'name': 'desktop-entry'}, {'name': 'graphics'}, { diff --git a/tests/system-info.c b/tests/system-info.c index ca964d7ff5ad4a5c5b01a63b6ccac07c2a5faf19..268b2937ccf33106786e4bda13783d882cd93934 100644 --- a/tests/system-info.c +++ b/tests/system-info.c @@ -2388,75 +2388,6 @@ steamscript_env (Fixture *f, g_strfreev (envp); } -typedef struct -{ - const char *description; - const char *sysroot; - SrtContainerType type; - const char *host_directory; -} ContainerTest; - -static const ContainerTest container_tests[] = -{ - { "Has /.dockerenv", - "debian-unstable", SRT_CONTAINER_TYPE_DOCKER, NULL }, - { "Has an unknown value in /run/systemd/container", - "debian10", SRT_CONTAINER_TYPE_UNKNOWN, NULL }, - { "Has 'docker' in /run/systemd/container", - "fedora", SRT_CONTAINER_TYPE_DOCKER, NULL }, - { "Has /.flatpak-info and /run/host", - "flatpak-example", SRT_CONTAINER_TYPE_FLATPAK, "/run/host" }, - { "Has /run/host", - "invalid-os-release", SRT_CONTAINER_TYPE_UNKNOWN, "/run/host" }, - { "Has no evidence of being a container", - "no-os-release", SRT_CONTAINER_TYPE_NONE, NULL }, - { "Has /run/pressure-vessel", - "steamrt", SRT_CONTAINER_TYPE_PRESSURE_VESSEL, NULL }, - { "Has a Docker-looking /proc/1/cgroup", - "steamrt-unofficial", SRT_CONTAINER_TYPE_DOCKER, NULL }, -}; - -static void -test_containers (Fixture *f, - gconstpointer context) -{ - gsize i, j; - - for (i = 0; i < G_N_ELEMENTS (container_tests); i++) - { - const ContainerTest *test = &container_tests[i]; - SrtSystemInfo *info; - gchar *sysroot, *got, *expected; - - g_test_message ("%s: %s", test->sysroot, test->description); - - sysroot = g_build_filename (f->sysroots, test->sysroot, NULL); - - info = srt_system_info_new (NULL); - g_assert_nonnull (info); - srt_system_info_set_sysroot (info, sysroot); - - for (j = 0; j < 2; j++) - { - g_assert_cmpint (srt_system_info_get_container_type (info), ==, - test->type); - got = srt_system_info_dup_container_host_directory (info); - - if (test->host_directory == NULL) - expected = NULL; - else - expected = g_build_filename (sysroot, test->host_directory, NULL); - - g_assert_cmpstr (got, ==, expected); - g_free (got); - g_free (expected); - } - - g_object_unref (info); - g_free (sysroot); - } -} - /* For the purpose of this test an array that is NULL, and one with just one * NULL element, are considered to be equal */ static void @@ -2527,6 +2458,7 @@ typedef struct { SrtContainerType type; const gchar *host_path; + const gchar *flatpak_version; } ContTest; typedef struct @@ -3097,6 +3029,7 @@ static const JsonTest json_test[] = .container = { .type = SRT_CONTAINER_TYPE_FLATPAK, + .flatpak_version = "1.10.2", }, .driver_environment = { @@ -3506,6 +3439,7 @@ json_parsing (Fixture *f, g_autoptr(SrtObjectList) portal_backends = NULL; g_autoptr(SrtObjectList) explicit_layers = NULL; g_autoptr(SrtObjectList) implicit_layers = NULL; + g_autoptr(SrtContainerInfo) container = NULL; g_autofree gchar *portal_messages = NULL; g_autofree gchar *steamscript_path = NULL; g_autofree gchar *steamscript_version = NULL; @@ -3560,9 +3494,12 @@ json_parsing (Fixture *f, g_assert_cmpstr (t->os_release.name, ==, name); g_assert_cmpstr (t->os_release.pretty_name, ==, pretty_name); + container = srt_system_info_check_container (info); host_directory = srt_system_info_dup_container_host_directory (info); g_assert_cmpint (t->container.type, ==, srt_system_info_get_container_type (info)); g_assert_cmpstr (t->container.host_path, ==, host_directory); + g_assert_cmpstr (t->container.flatpak_version, ==, + srt_container_info_get_flatpak_version (container)); driver_environment_list = srt_system_info_list_driver_environment (info); assert_equal_strings_arrays (t->driver_environment, @@ -4088,9 +4025,6 @@ main (int argc, 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); - g_test_add ("/system-info/json_parsing", Fixture, NULL, setup, json_parsing, teardown);