From da7e3fdcfd25698b78210d878a1d6ac167d9b4f7 Mon Sep 17 00:00:00 2001 From: Simon McVittie <smcv@collabora.com> Date: Thu, 26 Sep 2019 12:51:18 +0100 Subject: [PATCH] Add support for ID_LIKE os-release(5) field This one is a bit different because the raw field is a space-separated list. For convenience, srt_system_info_dup_os_id_like() can be asked to include the OS itself, for use in logic like this pseudocode: for id in info.dup_os_id_like(True): if id in special_cases: special_cases[id].run() break else: do_generic_behaviour() Signed-off-by: Simon McVittie <smcv@collabora.com> --- bin/system-info.c | 16 ++++++ bin/system-info.md | 13 +++++ steam-runtime-tools/os-internal.h | 1 + steam-runtime-tools/os.c | 11 ++++ steam-runtime-tools/system-info.c | 88 ++++++++++++++++++++++++++++--- steam-runtime-tools/system-info.h | 2 + tests/system-info.c | 74 ++++++++++++++++++++++++++ 7 files changed, 197 insertions(+), 8 deletions(-) diff --git a/bin/system-info.c b/bin/system-info.c index 3d159ea4c..264599791 100644 --- a/bin/system-info.c +++ b/bin/system-info.c @@ -546,6 +546,8 @@ main (int argc, json_builder_set_member_name (builder, "os-release"); json_builder_begin_object (builder); { + GStrv strv; + gsize i; gchar *tmp; tmp = srt_system_info_dup_os_id (info); @@ -557,6 +559,20 @@ main (int argc, g_free (tmp); } + strv = srt_system_info_dup_os_id_like (info, FALSE); + + if (strv != NULL) + { + json_builder_set_member_name (builder, "id_like"); + json_builder_begin_array (builder); + { + for (i = 0; strv[i] != NULL; i++) + json_builder_add_string_value (builder, strv[i]); + } + json_builder_end_array (builder); + g_strfreev (strv); + } + tmp = srt_system_info_dup_os_name (info); if (tmp != NULL) diff --git a/bin/system-info.md b/bin/system-info.md index a675ccc79..114929ff7 100644 --- a/bin/system-info.md +++ b/bin/system-info.md @@ -152,6 +152,19 @@ keys: If **os-release**(5) is not available, future versions of this library might derive a similar ID from **lsb_release**(1). + **id_like** + : An array of short lower-case strings identifying operating systems + that this one was derived from. For example, Steam Runtime 1 'scout' + is derived from Ubuntu, which is itself derived from Debian, so + in a scout chroot or container this will be **["ubuntu", "debian"]**. + + This is the **ID_LIKE** field from **os-release**(5), split + at whitespace. It does not include the **id**. + + If **os-release**(5) is not available, future versions of this + library might derive a similar array from **lsb_release**(1) + or from hard-coded knowledge of particular operating systems. + **name** : A human-readable name for the operating system without its version, for example **Debian GNU/Linux** or **Arch Linux**. diff --git a/steam-runtime-tools/os-internal.h b/steam-runtime-tools/os-internal.h index b22888ca9..ed65cae0a 100644 --- a/steam-runtime-tools/os-internal.h +++ b/steam-runtime-tools/os-internal.h @@ -33,6 +33,7 @@ typedef struct { gchar *build_id; gchar *id; + gchar *id_like; gchar *name; gchar *pretty_name; gchar *variant; diff --git a/steam-runtime-tools/os.c b/steam-runtime-tools/os.c index 710b94e12..d5334e675 100644 --- a/steam-runtime-tools/os.c +++ b/steam-runtime-tools/os.c @@ -38,6 +38,7 @@ _srt_os_release_init (SrtOsRelease *self) { self->build_id = NULL; self->id = NULL; + self->id_like = NULL; self->name = NULL; self->pretty_name = NULL; self->variant = NULL; @@ -96,6 +97,8 @@ do_line (SrtOsRelease *self, dest = &self->build_id; else if (strcmp (line, "ID") == 0) dest = &self->id; + else if (strcmp (line, "ID_LIKE") == 0) + dest = &self->id_like; else if (strcmp (line, "NAME") == 0) dest = &self->name; else if (strcmp (line, "PRETTY_NAME") == 0) @@ -209,6 +212,13 @@ _srt_os_release_populate (SrtOsRelease *self, && g_strcmp0 (self->version_id, "1") == 0) self->version_codename = g_strdup ("scout"); + /* Special case for the Steam Runtime: we got this wrong in the past. */ + if (g_strcmp0 (self->id_like, "ubuntu") == 0) + { + g_free (self->id_like); + self->id_like = g_strdup ("ubuntu debian"); + } + self->populated = TRUE; } @@ -217,6 +227,7 @@ _srt_os_release_clear (SrtOsRelease *self) { g_clear_pointer (&self->build_id, g_free); g_clear_pointer (&self->id, g_free); + g_clear_pointer (&self->id_like, g_free); g_clear_pointer (&self->name, g_free); g_clear_pointer (&self->pretty_name, g_free); g_clear_pointer (&self->variant, g_free); diff --git a/steam-runtime-tools/system-info.c b/steam-runtime-tools/system-info.c index 602c4fb7e..1bcc1149b 100644 --- a/steam-runtime-tools/system-info.c +++ b/steam-runtime-tools/system-info.c @@ -1187,7 +1187,8 @@ ensure_os_cached (SrtSystemInfo *self) * * This is the `BUILD_ID` from os-release(5). * - * Returns: (transfer full) (type utf8): The build ID, or %NULL if not known + * Returns: (transfer full) (type utf8): The build ID, or %NULL if not known. + * Free with g_free(). */ gchar * srt_system_info_dup_os_build_id (SrtSystemInfo *self) @@ -1210,7 +1211,8 @@ srt_system_info_dup_os_build_id (SrtSystemInfo *self) * future versions of this library might derive a similar ID from * lsb_release(1). * - * Returns: (transfer full) (type utf8): The OS ID, or %NULL if not known + * Returns: (transfer full) (type utf8): The OS ID, or %NULL if not known. + * Free with g_free(). */ gchar * srt_system_info_dup_os_id (SrtSystemInfo *self) @@ -1221,6 +1223,70 @@ srt_system_info_dup_os_id (SrtSystemInfo *self) return g_strdup (self->os_release.id); } +static const char WHITESPACE[] = " \t\n\r"; + +/** + * srt_system_info_dup_os_id_like: + * @self: The #SrtSystemInfo object + * @include_self: If %TRUE, include srt_system_info_dup_os_id() in the + * returned array (if known) + * + * Return an array of lower-case machine-readable operating system + * identifiers similar to srt_system_info_dup_os_id() describing OSs + * that this one resembles or is derived from. + * + * For example, the Steam Runtime 1 'scout' is derived from Ubuntu, + * which is itself derived from Debian, so srt_system_info_dup_os_id_like() + * would return `{ "debian", "ubuntu", NULL }` if @include_self is false, + * `{ "steamrt", "debian", "ubuntu", NULL }` otherwise. + * + * This is the `ID_LIKE` field from os-release(5), possibly combined + * with the `ID` field. + * + * Returns: (array zero-terminated=1) (transfer full) (element-type utf8) (nullable): An + * array of OS IDs, or %NULL if nothing is known. + * Free with g_strfreev(). + */ +gchar ** +srt_system_info_dup_os_id_like (SrtSystemInfo *self, + gboolean include_self) +{ + GPtrArray *builder; + g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), NULL); + + ensure_os_cached (self); + + builder = g_ptr_array_new_with_free_func (g_free); + + if (self->os_release.id != NULL && include_self) + g_ptr_array_add (builder, g_strdup (self->os_release.id)); + + if (self->os_release.id_like != NULL) + { + GStrv split; + gsize i; + + split = g_strsplit_set (self->os_release.id_like, WHITESPACE, -1); + + for (i = 0; split != NULL && split[i] != NULL; i++) + g_ptr_array_add (builder, g_steal_pointer (&split[i])); + + /* We already transferred ownership of the contents */ + g_free (split); + } + + if (builder->len > 0) + { + g_ptr_array_add (builder, NULL); + return (gchar **) g_ptr_array_free (builder, FALSE); + } + else + { + g_ptr_array_free (builder, TRUE); + return NULL; + } +} + /** * srt_system_info_dup_os_name: * @self: The #SrtSystemInfo object @@ -1232,7 +1298,8 @@ srt_system_info_dup_os_id (SrtSystemInfo *self) * available, future versions of this library might derive a similar * name from lsb_release(1). * - * Returns: (transfer full) (type utf8): The name, or %NULL if not known + * Returns: (transfer full) (type utf8): The name, or %NULL if not known. + * Free with g_free(). */ gchar * srt_system_info_dup_os_name (SrtSystemInfo *self) @@ -1258,7 +1325,8 @@ srt_system_info_dup_os_name (SrtSystemInfo *self) * available, future versions of this library might derive a similar * name from lsb_release(1). * - * Returns: (transfer full) (type utf8): The name, or %NULL if not known + * Returns: (transfer full) (type utf8): The name, or %NULL if not known. + * Free with g_free(). */ gchar * srt_system_info_dup_os_pretty_name (SrtSystemInfo *self) @@ -1280,7 +1348,8 @@ srt_system_info_dup_os_pretty_name (SrtSystemInfo *self) * * This is the `VARIANT` in os-release(5). * - * Returns: (transfer full) (type utf8): The name, or %NULL if not known + * Returns: (transfer full) (type utf8): The name, or %NULL if not known. + * Free with g_free(). */ gchar * srt_system_info_dup_os_variant (SrtSystemInfo *self) @@ -1302,7 +1371,8 @@ srt_system_info_dup_os_variant (SrtSystemInfo *self) * * This is the `VARIANT_ID` in os-release(5). * - * Returns: (transfer full) (type utf8): The name, or %NULL if not known + * Returns: (transfer full) (type utf8): The variant ID, or %NULL if not known. + * Free with g_free(). */ gchar * srt_system_info_dup_os_variant_id (SrtSystemInfo *self) @@ -1326,7 +1396,8 @@ srt_system_info_dup_os_variant_id (SrtSystemInfo *self) * available, future versions of this library might derive a similar * codename from lsb_release(1). * - * Returns: (transfer full) (type utf8): The name, or %NULL if not known + * Returns: (transfer full) (type utf8): The codename, or %NULL if not known. + * Free with g_free(). */ gchar * srt_system_info_dup_os_version_codename (SrtSystemInfo *self) @@ -1351,7 +1422,8 @@ srt_system_info_dup_os_version_codename (SrtSystemInfo *self) * available, future versions of this library might derive a similar * identifier from lsb_release(1). * - * Returns: (transfer full) (type utf8): The name, or %NULL if not known + * Returns: (transfer full) (type utf8): The ID, or %NULL if not known. + * Free with g_free(). */ gchar * srt_system_info_dup_os_version_id (SrtSystemInfo *self) diff --git a/steam-runtime-tools/system-info.h b/steam-runtime-tools/system-info.h index 567313c87..4aabb3b73 100644 --- a/steam-runtime-tools/system-info.h +++ b/steam-runtime-tools/system-info.h @@ -120,6 +120,8 @@ SrtLocale *srt_system_info_check_locale (SrtSystemInfo *self, gchar *srt_system_info_dup_os_build_id (SrtSystemInfo *self); gchar *srt_system_info_dup_os_id (SrtSystemInfo *self); +gchar **srt_system_info_dup_os_id_like (SrtSystemInfo *self, + gboolean include_self); gchar *srt_system_info_dup_os_name (SrtSystemInfo *self); gchar *srt_system_info_dup_os_pretty_name (SrtSystemInfo *self); gchar *srt_system_info_dup_os_variant (SrtSystemInfo *self); diff --git a/tests/system-info.c b/tests/system-info.c index f79069abb..04334ac0a 100644 --- a/tests/system-info.c +++ b/tests/system-info.c @@ -1231,6 +1231,7 @@ os_debian10 (Fixture *f, { SrtSystemInfo *info; gchar **envp; + gchar **strv; gchar *sysroot; gchar *s; @@ -1249,6 +1250,16 @@ os_debian10 (Fixture *f, g_assert_cmpstr (s, ==, "debian"); g_free (s); + strv = srt_system_info_dup_os_id_like (info, FALSE); + g_assert_null (strv); + g_strfreev (strv); + + strv = srt_system_info_dup_os_id_like (info, TRUE); + g_assert_nonnull (strv); + g_assert_cmpstr (strv[0], ==, "debian"); + g_assert_cmpstr (strv[1], ==, NULL); + g_strfreev (strv); + s = srt_system_info_dup_os_name (info); g_assert_cmpstr (s, ==, "Debian GNU/Linux"); g_free (s); @@ -1284,6 +1295,7 @@ os_debian_unstable (Fixture *f, { SrtSystemInfo *info; gchar **envp; + gchar **strv; gchar *sysroot; gchar *s; @@ -1302,6 +1314,16 @@ os_debian_unstable (Fixture *f, g_assert_cmpstr (s, ==, "debian"); g_free (s); + strv = srt_system_info_dup_os_id_like (info, FALSE); + g_assert_null (strv); + g_strfreev (strv); + + strv = srt_system_info_dup_os_id_like (info, TRUE); + g_assert_nonnull (strv); + g_assert_cmpstr (strv[0], ==, "debian"); + g_assert_cmpstr (strv[1], ==, NULL); + g_strfreev (strv); + s = srt_system_info_dup_os_name (info); g_assert_cmpstr (s, ==, "Debian GNU/Linux"); g_free (s); @@ -1337,6 +1359,7 @@ os_steamrt (Fixture *f, { SrtSystemInfo *info; gchar **envp; + gchar **strv; gchar *sysroot; gchar *s; @@ -1356,6 +1379,21 @@ os_steamrt (Fixture *f, g_assert_cmpstr (s, ==, "steamrt"); g_free (s); + strv = srt_system_info_dup_os_id_like (info, FALSE); + g_assert_nonnull (strv); + g_assert_cmpstr (strv[0], ==, "ubuntu"); + g_assert_cmpstr (strv[1], ==, "debian"); + g_assert_cmpstr (strv[2], ==, NULL); + g_strfreev (strv); + + strv = srt_system_info_dup_os_id_like (info, TRUE); + g_assert_nonnull (strv); + g_assert_cmpstr (strv[0], ==, "steamrt"); + g_assert_cmpstr (strv[1], ==, "ubuntu"); + g_assert_cmpstr (strv[2], ==, "debian"); + g_assert_cmpstr (strv[3], ==, NULL); + g_strfreev (strv); + s = srt_system_info_dup_os_name (info); g_assert_cmpstr (s, ==, "Steam Runtime"); g_free (s); @@ -1392,6 +1430,7 @@ os_steamrt_unofficial (Fixture *f, { SrtSystemInfo *info; gchar **envp; + gchar **strv; gchar *sysroot; gchar *s; @@ -1412,6 +1451,21 @@ os_steamrt_unofficial (Fixture *f, g_assert_cmpstr (s, ==, "steamrt"); g_free (s); + strv = srt_system_info_dup_os_id_like (info, FALSE); + g_assert_nonnull (strv); + g_assert_cmpstr (strv[0], ==, "ubuntu"); + g_assert_cmpstr (strv[1], ==, "debian"); + g_assert_cmpstr (strv[2], ==, NULL); + g_strfreev (strv); + + strv = srt_system_info_dup_os_id_like (info, TRUE); + g_assert_nonnull (strv); + g_assert_cmpstr (strv[0], ==, "steamrt"); + g_assert_cmpstr (strv[1], ==, "ubuntu"); + g_assert_cmpstr (strv[2], ==, "debian"); + g_assert_cmpstr (strv[3], ==, NULL); + g_strfreev (strv); + s = srt_system_info_dup_os_name (info); g_assert_cmpstr (s, ==, "Steam Runtime"); g_free (s); @@ -1448,6 +1502,7 @@ os_invalid_os_release (Fixture *f, { SrtSystemInfo *info; gchar **envp; + gchar **strv; gchar *sysroot; gchar *s; @@ -1468,6 +1523,16 @@ os_invalid_os_release (Fixture *f, g_assert_cmpstr (s, ==, "steamrt"); g_free (s); + strv = srt_system_info_dup_os_id_like (info, FALSE); + g_assert_null (strv); + g_strfreev (strv); + + strv = srt_system_info_dup_os_id_like (info, TRUE); + g_assert_nonnull (strv); + g_assert_cmpstr (strv[0], ==, "steamrt"); + g_assert_cmpstr (strv[1], ==, NULL); + g_strfreev (strv); + s = srt_system_info_dup_os_name (info); g_assert_cmpstr (s, ==, "This file does not end with a newline"); g_free (s); @@ -1503,6 +1568,7 @@ os_no_os_release (Fixture *f, { SrtSystemInfo *info; gchar **envp; + gchar **strv; gchar *sysroot; gchar *s; @@ -1521,6 +1587,14 @@ os_no_os_release (Fixture *f, g_assert_cmpstr (s, ==, NULL); g_free (s); + strv = srt_system_info_dup_os_id_like (info, FALSE); + g_assert_null (strv); + g_strfreev (strv); + + strv = srt_system_info_dup_os_id_like (info, TRUE); + g_assert_null (strv); + g_strfreev (strv); + s = srt_system_info_dup_os_name (info); g_assert_cmpstr (s, ==, NULL); g_free (s); -- GitLab