[glib/wip/lantw/use-uname-as-a-fallback-to-get-os-info] gutils: Use uname to report OS info when there is no os-release file
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/lantw/use-uname-as-a-fallback-to-get-os-info] gutils: Use uname to report OS info when there is no os-release file
- Date: Mon, 14 Oct 2019 12:42:18 +0000 (UTC)
commit d219b3553cda011ed3070acdb33918e1608a536d
Author: Ting-Wei Lan <lantw src gnome org>
Date: Sun Oct 13 20:44:24 2019 +0800
gutils: Use uname to report OS info when there is no os-release file
There are a lot of Unix-like systems which have not implemented the
os-release spec. On such system, we can use POSIX uname function as a
fallback to get basic information of the system.
glib/gutils.c | 186 +++++++++++++++++++++++++++++++++++++++++------------
glib/tests/utils.c | 9 ++-
2 files changed, 154 insertions(+), 41 deletions(-)
---
diff --git a/glib/gutils.c b/glib/gutils.c
index d52224ce0..4aadf76f2 100644
--- a/glib/gutils.c
+++ b/glib/gutils.c
@@ -42,6 +42,7 @@
#include <sys/stat.h>
#ifdef G_OS_UNIX
#include <pwd.h>
+#include <sys/utsname.h>
#include <unistd.h>
#endif
#include <sys/types.h>
@@ -1350,6 +1351,137 @@ get_windows_version (gboolean with_windows)
}
#endif
+#ifdef G_OS_UNIX
+static gchar *
+get_os_info_from_os_release (const gchar *key_name,
+ const gchar *buffer)
+{
+ GStrv lines;
+ gchar *prefix;
+ size_t i;
+ gchar *result = NULL;
+
+ lines = g_strsplit (buffer, "\n", -1);
+ prefix = g_strdup_printf ("%s=", key_name);
+ for (i = 0; lines[i] != NULL; i++)
+ {
+ const gchar *line = lines[i];
+ const gchar *value;
+
+ if (g_str_has_prefix (line, prefix))
+ {
+ value = line + strlen (prefix);
+ result = g_shell_unquote (value, NULL);
+ if (result == NULL)
+ result = g_strdup (value);
+ break;
+ }
+ }
+ g_strfreev (lines);
+ g_free (prefix);
+
+#ifdef __linux__
+ /* Default values in spec */
+ if (result == NULL)
+ {
+ if (g_str_equal (key_name, G_OS_INFO_KEY_NAME))
+ return g_strdup ("Linux");
+ if (g_str_equal (key_name, G_OS_INFO_KEY_ID))
+ return g_strdup ("linux");
+ if (g_str_equal (key_name, G_OS_INFO_KEY_PRETTY_NAME))
+ return g_strdup ("Linux");
+ }
+#endif
+
+ return g_steal_pointer (&result);
+}
+
+static gchar *
+get_os_info_from_uname (const gchar *key_name)
+{
+ struct utsname info;
+
+ if (uname (&info) == -1)
+ return NULL;
+
+ if (strcmp (key_name, G_OS_INFO_KEY_NAME) == 0)
+ return g_strdup (info.sysname);
+ else if (strcmp (key_name, G_OS_INFO_KEY_VERSION) == 0)
+ return g_strdup (info.release);
+ else if (strcmp (key_name, G_OS_INFO_KEY_PRETTY_NAME) == 0)
+ return g_strdup_printf ("%s %s", info.sysname, info.release);
+ else if (strcmp (key_name, G_OS_INFO_KEY_ID) == 0)
+ {
+ gchar *result = g_ascii_strdown (info.sysname, -1);
+
+ g_strcanon (result, "abcdefghijklmnopqrstuvwxyz0123456789_-.", '_');
+ return g_steal_pointer (&result);
+ }
+ else if (strcmp (key_name, G_OS_INFO_KEY_VERSION_ID) == 0)
+ {
+ /* We attempt to convert the version string to the format returned by
+ * config.guess, which is the script used to generate target triplets
+ * in GNU autotools. There are a lot of rules in the script. We only
+ * implement a few rules which are easy to understand here.
+ *
+ * config.guess can be found at https://savannah.gnu.org/projects/config.
+ */
+ gchar *result;
+
+ if (strcmp (info.sysname, "NetBSD") == 0)
+ {
+ /* sed -e 's,[-_].*,,' */
+ gssize len = G_MAXSSIZE;
+ const gchar *c;
+
+ if ((c = strchr (info.release, '-')) != NULL)
+ len = MIN (len, c - info.release);
+ if ((c = strchr (info.release, '_')) != NULL)
+ len = MIN (len, c - info.release);
+ if (len == G_MAXSSIZE)
+ len = -1;
+
+ result = g_ascii_strdown (info.release, len);
+ }
+ else if (strcmp (info.sysname, "GNU") == 0)
+ {
+ /* sed -e 's,/.*$,,' */
+ gssize len = -1;
+ const gchar *c = strchr (info.release, '/');
+
+ if (c != NULL)
+ len = c - info.release;
+
+ result = g_ascii_strdown (info.release, len);
+ }
+ else if (g_str_has_prefix (info.sysname, "GNU/") ||
+ strcmp (info.sysname, "FreeBSD") == 0 ||
+ strcmp (info.sysname, "DragonFly") == 0)
+ {
+ /* sed -e 's,[-(].*,,' */
+ gssize len = G_MAXSSIZE;
+ const gchar *c;
+
+ if ((c = strchr (info.release, '-')) != NULL)
+ len = MIN (len, c - info.release);
+ if ((c = strchr (info.release, '(')) != NULL)
+ len = MIN (len, c - info.release);
+ if (len == G_MAXSSIZE)
+ len = -1;
+
+ result = g_ascii_strdown (info.release, len);
+ }
+ else
+ result = g_ascii_strdown (info.release, -1);
+
+ g_strcanon (result, "abcdefghijklmnopqrstuvwxyz0123456789_-.", '_');
+ return g_steal_pointer (&result);
+ }
+ else
+ return NULL;
+}
+#endif
+
/**
* g_get_os_info:
* @key_name: a key for the OS info being requested, for example %G_OS_INFO_KEY_NAME.
@@ -1377,60 +1509,34 @@ g_get_os_info (const gchar *key_name)
else
return NULL;
#elif defined (G_OS_UNIX)
- gchar *buffer;
- gchar *prefix;
- GStrv lines;
- int i;
+ const gchar * const os_release_files[] = { "/etc/os-release", "/usr/lib/os-release" };
+ gsize i;
+ gchar *buffer = NULL;
gchar *result = NULL;
- GError *error = NULL;
g_return_val_if_fail (key_name != NULL, NULL);
- if (!g_file_get_contents ("/etc/os-release", &buffer, NULL, &error))
+ for (i = 0; i < G_N_ELEMENTS (os_release_files); i++)
{
+ GError *error = NULL;
gboolean file_missing;
+ if (g_file_get_contents (os_release_files[i], &buffer, NULL, &error))
+ break;
+
file_missing = g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT);
g_clear_error (&error);
- if (!file_missing ||
- !g_file_get_contents ("/usr/lib/os-release", &buffer, NULL, NULL))
+ if (!file_missing)
return NULL;
}
- lines = g_strsplit (buffer, "\n", -1);
- g_free (buffer);
- prefix = g_strdup_printf ("%s=", key_name);
- for (i = 0; lines[i] != NULL; i++)
- {
- const gchar *line = lines[i];
- const gchar *value;
-
- if (g_str_has_prefix (line, prefix))
- {
- value = line + strlen (prefix);
- result = g_shell_unquote (value, NULL);
- if (result == NULL)
- result = g_strdup (value);
- break;
- }
- }
- g_strfreev (lines);
- g_free (prefix);
-
-#ifdef __linux__
- /* Default values in spec */
- if (result == NULL)
- {
- if (g_str_equal (key_name, G_OS_INFO_KEY_NAME))
- return g_strdup ("Linux");
- if (g_str_equal (key_name, G_OS_INFO_KEY_ID))
- return g_strdup ("linux");
- if (g_str_equal (key_name, G_OS_INFO_KEY_PRETTY_NAME))
- return g_strdup ("Linux");
- }
-#endif
+ if (buffer != NULL)
+ result = get_os_info_from_os_release (key_name, buffer);
+ else
+ result = get_os_info_from_uname (key_name);
+ g_free (buffer);
return g_steal_pointer (&result);
#elif defined (G_OS_WIN32)
if (g_strcmp0 (key_name, G_OS_INFO_KEY_NAME) == 0)
diff --git a/glib/tests/utils.c b/glib/tests/utils.c
index ce956a270..cf8a5cbc3 100644
--- a/glib/tests/utils.c
+++ b/glib/tests/utils.c
@@ -29,6 +29,9 @@
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
+#ifdef G_OS_UNIX
+#include <sys/utsname.h>
+#endif
#ifdef G_OS_WIN32
#include <windows.h>
#endif
@@ -522,6 +525,9 @@ test_os_info (void)
{
gchar *name;
gchar *contents = NULL;
+#ifdef G_OS_UNIX
+ struct utsname info;
+#endif
/* Whether this is implemented or not, it must not crash */
name = g_get_os_info (G_OS_INFO_KEY_NAME);
@@ -534,7 +540,8 @@ test_os_info (void)
g_assert_nonnull (name);
#elif defined (G_OS_UNIX)
if (g_file_get_contents ("/etc/os-release", &contents, NULL, NULL) ||
- g_file_get_contents ("/usr/lib/os-release", &contents, NULL, NULL))
+ g_file_get_contents ("/usr/lib/os-release", &contents, NULL, NULL) ||
+ uname (&info) == 0)
g_assert_nonnull (name);
else
g_test_skip ("os-release(5) API not implemented on this platform");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]