Enable GnuTLS-based GHmac in Fedora and reenable glib2-static in RHEL
Consolidate GDesktopAppInfo changes into gdesktopappinfo.patch Disable check-rpath since it seems to be broken
This commit is contained in:
parent
ba26123977
commit
1f79f05203
@ -1,30 +0,0 @@
|
|||||||
From 5e42384cc4499293259a8a37a737014a56de34df Mon Sep 17 00:00:00 2001
|
|
||||||
From: Benjamin Berg <bberg@redhat.com>
|
|
||||||
Date: Fri, 23 Oct 2020 18:20:01 +0200
|
|
||||||
Subject: [PATCH 1/4] tests: Iterate mainloop during launch test
|
|
||||||
|
|
||||||
When launching an application, we wait for the DBus response from
|
|
||||||
systemd before executing the binary. Because of this the main loop needs
|
|
||||||
to be iterated for spawning to completed and the file to be created.
|
|
||||||
|
|
||||||
Without this the test will time out if GLib was able to connect to the
|
|
||||||
session bus.
|
|
||||||
---
|
|
||||||
gio/tests/desktop-app-info.c | 1 +
|
|
||||||
1 file changed, 1 insertion(+)
|
|
||||||
|
|
||||||
diff --git a/gio/tests/desktop-app-info.c b/gio/tests/desktop-app-info.c
|
|
||||||
index fcc29c579..743230cbb 100644
|
|
||||||
--- a/gio/tests/desktop-app-info.c
|
|
||||||
+++ b/gio/tests/desktop-app-info.c
|
|
||||||
@@ -334,6 +334,7 @@ wait_for_file (const gchar *want_this,
|
|
||||||
*/
|
|
||||||
while (access (want_this, F_OK) != 0)
|
|
||||||
{
|
|
||||||
+ g_main_context_iteration (NULL, FALSE);
|
|
||||||
g_usleep (100000); /* 100ms */
|
|
||||||
g_assert_cmpuint (retries, >, 0);
|
|
||||||
retries--;
|
|
||||||
--
|
|
||||||
2.31.1
|
|
||||||
|
|
@ -1,388 +0,0 @@
|
|||||||
From ba3b85a8fea0151e74de50e841a7f16f9b077a56 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Benjamin Berg <bberg@redhat.com>
|
|
||||||
Date: Mon, 27 Jul 2020 22:22:32 +0200
|
|
||||||
Subject: [PATCH 2/4] gdesktopappinfo: Move launched applications into
|
|
||||||
transient scope
|
|
||||||
|
|
||||||
Try to move the spawned executable into its own systemd scope. To avoid
|
|
||||||
possible race conditions and ensure proper accounting, we delay the
|
|
||||||
execution of the real command until after the DBus call to systemd has
|
|
||||||
finished.
|
|
||||||
|
|
||||||
From the two approaches we can take here, this is better in the sense
|
|
||||||
that we have a child that the API consumer can watch. API consumers
|
|
||||||
should not be doing this, however, gnome-session needs to watch children
|
|
||||||
during session startup. Until gnome-session is fixed, we will not be
|
|
||||||
able to change this.
|
|
||||||
|
|
||||||
The alternative approach is to delegate launching itself to systemd by
|
|
||||||
creating a transient .service unit instead. This is cleaner and has e.g.
|
|
||||||
the advantage that systemd will take care of log redirection and similar
|
|
||||||
issues.
|
|
||||||
|
|
||||||
Note that this patch is incomplete. The DBus call is done in a "fire and
|
|
||||||
forget" manner, which is fine in most cases, but means that "gio open"
|
|
||||||
will fail to move the child into the new scope as gio quits before the
|
|
||||||
DBus call finishes.
|
|
||||||
---
|
|
||||||
gio/gdesktopappinfo.c | 264 ++++++++++++++++++++++++++++++++++++------
|
|
||||||
1 file changed, 227 insertions(+), 37 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
|
|
||||||
index 1a4b97918..afdcd42ac 100644
|
|
||||||
--- a/gio/gdesktopappinfo.c
|
|
||||||
+++ b/gio/gdesktopappinfo.c
|
|
||||||
@@ -2730,6 +2730,148 @@ notify_desktop_launch (GDBusConnection *session_bus,
|
|
||||||
|
|
||||||
#define _SPAWN_FLAGS_DEFAULT (G_SPAWN_SEARCH_PATH)
|
|
||||||
|
|
||||||
+#if defined(__linux__) && !defined(__BIONIC__)
|
|
||||||
+typedef struct {
|
|
||||||
+ int pipe[2];
|
|
||||||
+ GSpawnChildSetupFunc user_setup;
|
|
||||||
+ gpointer user_setup_data;
|
|
||||||
+} SpawnWrapperData;
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+launch_uris_with_spawn_delay_exec (gpointer user_data)
|
|
||||||
+{
|
|
||||||
+ SpawnWrapperData *data = user_data;
|
|
||||||
+
|
|
||||||
+ /* Clear CLOEXEC again, as that was set due to
|
|
||||||
+ * G_SPAWN_LEAVE_DESCRIPTORS_OPEN not being set. */
|
|
||||||
+ fcntl (data->pipe[0], F_SETFD, 0);
|
|
||||||
+
|
|
||||||
+ /* No need to close read side, we have CLOEXEC set. */
|
|
||||||
+
|
|
||||||
+ if (data->user_setup)
|
|
||||||
+ data->user_setup (data->user_setup_data);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static gchar *
|
|
||||||
+systemd_unit_name_escape (const gchar *in)
|
|
||||||
+{
|
|
||||||
+ /* Adapted from systemd source */
|
|
||||||
+ GString * const str = g_string_sized_new (strlen (in));
|
|
||||||
+
|
|
||||||
+ for (; *in; in++)
|
|
||||||
+ {
|
|
||||||
+ if (g_ascii_isalnum (*in) || *in == ':' || *in == '_' || *in == '.')
|
|
||||||
+ g_string_append_c (str, *in);
|
|
||||||
+ else
|
|
||||||
+ g_string_append_printf (str, "\\x%02x", *in);
|
|
||||||
+ }
|
|
||||||
+ return g_string_free (str, FALSE);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+create_systemd_scope (GDBusConnection *session_bus,
|
|
||||||
+ GDesktopAppInfo *info,
|
|
||||||
+ gint pid,
|
|
||||||
+ GAsyncReadyCallback callback,
|
|
||||||
+ gpointer user_data)
|
|
||||||
+{
|
|
||||||
+ GVariantBuilder builder;
|
|
||||||
+ const char *app_name = g_get_application_name ();
|
|
||||||
+ char *appid = NULL;
|
|
||||||
+ char *appid_escaped = NULL;
|
|
||||||
+ char *snid_escaped = NULL;
|
|
||||||
+ char *unit_name = NULL;
|
|
||||||
+
|
|
||||||
+ /* In this order:
|
|
||||||
+ * 1. Actual application ID from file
|
|
||||||
+ * 2. Stripping the .desktop from the desktop ID
|
|
||||||
+ * 3. Fall back to using the binary name
|
|
||||||
+ */
|
|
||||||
+ if (info->app_id)
|
|
||||||
+ appid = g_strdup (info->app_id);
|
|
||||||
+ else if (info->desktop_id && g_str_has_suffix (info->desktop_id, ".desktop"))
|
|
||||||
+ appid = g_strndup (info->desktop_id, strlen (info->desktop_id) - 8);
|
|
||||||
+ else
|
|
||||||
+ appid = g_path_get_basename (info->binary);
|
|
||||||
+
|
|
||||||
+ appid_escaped = systemd_unit_name_escape (appid);
|
|
||||||
+
|
|
||||||
+ /* Generate a name conforming to
|
|
||||||
+ * https://systemd.io/DESKTOP_ENVIRONMENTS/
|
|
||||||
+ * We use the PID to disambiguate, as that should be unique enough.
|
|
||||||
+ */
|
|
||||||
+ unit_name = g_strdup_printf ("app-glib-%s-%d.scope", appid_escaped, pid);
|
|
||||||
+
|
|
||||||
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ssa(sv)a(sa(sv)))"));
|
|
||||||
+ g_variant_builder_add (&builder, "s", unit_name);
|
|
||||||
+ g_variant_builder_add (&builder, "s", "fail");
|
|
||||||
+
|
|
||||||
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(sv)"));
|
|
||||||
+
|
|
||||||
+ /* Add a generic human readable description, can be changed at will. */
|
|
||||||
+ if (app_name)
|
|
||||||
+ g_variant_builder_add (&builder,
|
|
||||||
+ "(sv)",
|
|
||||||
+ "Description",
|
|
||||||
+ g_variant_new_take_string (g_strdup_printf ("Application launched by %s",
|
|
||||||
+ app_name)));
|
|
||||||
+ g_variant_builder_add (&builder,
|
|
||||||
+ "(sv)",
|
|
||||||
+ "PIDs",
|
|
||||||
+ g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, &pid, 1, 4));
|
|
||||||
+ /* Default to let systemd garbage collect failed applications we launched. */
|
|
||||||
+ g_variant_builder_add (&builder,
|
|
||||||
+ "(sv)",
|
|
||||||
+ "CollectMode",
|
|
||||||
+ g_variant_new_string ("inactive-or-failed"));
|
|
||||||
+
|
|
||||||
+ g_variant_builder_close (&builder);
|
|
||||||
+
|
|
||||||
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(sa(sv))"));
|
|
||||||
+ g_variant_builder_close (&builder);
|
|
||||||
+
|
|
||||||
+ g_dbus_connection_call (session_bus,
|
|
||||||
+ "org.freedesktop.systemd1",
|
|
||||||
+ "/org/freedesktop/systemd1",
|
|
||||||
+ "org.freedesktop.systemd1.Manager",
|
|
||||||
+ "StartTransientUnit",
|
|
||||||
+ g_variant_builder_end (&builder),
|
|
||||||
+ G_VARIANT_TYPE ("(o)"),
|
|
||||||
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
|
||||||
+ 1000,
|
|
||||||
+ NULL,
|
|
||||||
+ callback,
|
|
||||||
+ user_data);
|
|
||||||
+
|
|
||||||
+ g_free (appid);
|
|
||||||
+ g_free (appid_escaped);
|
|
||||||
+ g_free (snid_escaped);
|
|
||||||
+ g_free (unit_name);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+systemd_scope_created_cb (GObject *object,
|
|
||||||
+ GAsyncResult *result,
|
|
||||||
+ gpointer user_data)
|
|
||||||
+{
|
|
||||||
+ GVariant *res = NULL;
|
|
||||||
+ GError *error = NULL;
|
|
||||||
+
|
|
||||||
+ res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error);
|
|
||||||
+ if (error != NULL)
|
|
||||||
+ {
|
|
||||||
+ g_debug ("Failed to move new child into scope: %s", error->message);
|
|
||||||
+ g_error_free (error);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Unblock the waiting wrapper binary. */
|
|
||||||
+ close (GPOINTER_TO_INT (user_data));
|
|
||||||
+
|
|
||||||
+ if (res)
|
|
||||||
+ g_variant_unref (res);
|
|
||||||
+}
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
static gboolean
|
|
||||||
g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|
||||||
GDBusConnection *session_bus,
|
|
||||||
@@ -2750,13 +2892,14 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|
||||||
GList *old_uris;
|
|
||||||
GList *dup_uris;
|
|
||||||
|
|
||||||
- char **argv, **envp;
|
|
||||||
+ GStrv argv = NULL, envp = NULL;
|
|
||||||
+ GStrv wrapped_argv = NULL;
|
|
||||||
+ GList *launched_uris = NULL;
|
|
||||||
+ char *sn_id = NULL;
|
|
||||||
int argc;
|
|
||||||
|
|
||||||
g_return_val_if_fail (info != NULL, FALSE);
|
|
||||||
|
|
||||||
- argv = NULL;
|
|
||||||
-
|
|
||||||
if (launch_context)
|
|
||||||
envp = g_app_launch_context_get_environment (launch_context);
|
|
||||||
else
|
|
||||||
@@ -2770,27 +2913,19 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|
||||||
do
|
|
||||||
{
|
|
||||||
GPid pid;
|
|
||||||
- GList *launched_uris;
|
|
||||||
GList *iter;
|
|
||||||
- char *sn_id = NULL;
|
|
||||||
- char **wrapped_argv;
|
|
||||||
int i;
|
|
||||||
- gsize j;
|
|
||||||
- const gchar * const wrapper_argv[] =
|
|
||||||
- {
|
|
||||||
- "/bin/sh",
|
|
||||||
- "-e",
|
|
||||||
- "-u",
|
|
||||||
- "-c", "export GIO_LAUNCHED_DESKTOP_FILE_PID=$$; exec \"$@\"",
|
|
||||||
- "sh", /* argv[0] for sh */
|
|
||||||
- };
|
|
||||||
+#if defined(__linux__) && !defined(__BIONIC__)
|
|
||||||
+ SpawnWrapperData wrapper_data;
|
|
||||||
+#endif
|
|
||||||
+ GSpawnChildSetupFunc setup = user_setup;
|
|
||||||
+ gpointer setup_data = user_setup_data;
|
|
||||||
|
|
||||||
old_uris = dup_uris;
|
|
||||||
if (!expand_application_parameters (info, exec_line, &dup_uris, &argc, &argv, error))
|
|
||||||
- goto out;
|
|
||||||
+ return FALSE;
|
|
||||||
|
|
||||||
/* Get the subset of URIs we're launching with this process */
|
|
||||||
- launched_uris = NULL;
|
|
||||||
for (iter = old_uris; iter != NULL && iter != dup_uris; iter = iter->next)
|
|
||||||
launched_uris = g_list_prepend (launched_uris, iter->data);
|
|
||||||
launched_uris = g_list_reverse (launched_uris);
|
|
||||||
@@ -2799,7 +2934,7 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|
||||||
{
|
|
||||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
_("Unable to find terminal required for application"));
|
|
||||||
- goto out;
|
|
||||||
+ return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->filename)
|
|
||||||
@@ -2808,7 +2943,6 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|
||||||
info->filename,
|
|
||||||
TRUE);
|
|
||||||
|
|
||||||
- sn_id = NULL;
|
|
||||||
if (launch_context)
|
|
||||||
{
|
|
||||||
GList *launched_files = create_files_for_uris (launched_uris);
|
|
||||||
@@ -2837,38 +2971,93 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|
||||||
* with a wrapper program (grep the GLib git history for
|
|
||||||
* `gio-launch-desktop` for an example of this which could be
|
|
||||||
* resurrected). */
|
|
||||||
- wrapped_argv = g_new (char *, argc + G_N_ELEMENTS (wrapper_argv) + 1);
|
|
||||||
+ wrapped_argv = g_new (char *, argc + 6 + 1);
|
|
||||||
+
|
|
||||||
+ wrapped_argv[0] = g_strdup ("/bin/sh");
|
|
||||||
+ wrapped_argv[1] = g_strdup ("-e");
|
|
||||||
+ wrapped_argv[2] = g_strdup ("-u");
|
|
||||||
+ wrapped_argv[3] = g_strdup ("-c");
|
|
||||||
+ /* argument 4 is filled in below */
|
|
||||||
+ wrapped_argv[5] = g_strdup ("sh");
|
|
||||||
|
|
||||||
- for (j = 0; j < G_N_ELEMENTS (wrapper_argv); j++)
|
|
||||||
- wrapped_argv[j] = g_strdup (wrapper_argv[j]);
|
|
||||||
for (i = 0; i < argc; i++)
|
|
||||||
- wrapped_argv[i + G_N_ELEMENTS (wrapper_argv)] = g_steal_pointer (&argv[i]);
|
|
||||||
+ wrapped_argv[i + 6] = g_steal_pointer (&argv[i]);
|
|
||||||
+
|
|
||||||
+ wrapped_argv[i + 6] = NULL;
|
|
||||||
+ g_clear_pointer (&argv, g_free);
|
|
||||||
+
|
|
||||||
+#if defined(__linux__) && !defined(__BIONIC__)
|
|
||||||
+ /* Create pipes, if we use a setup func, then set cloexec,
|
|
||||||
+ * otherwise our wrapper script will close both sides. */
|
|
||||||
+ if (!g_unix_open_pipe (wrapper_data.pipe, 0, NULL))
|
|
||||||
+ {
|
|
||||||
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
+ _("Unable to create pipe for systemd synchronization"));
|
|
||||||
+ return FALSE;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Set CLOEXEC on the write pipe, so we don't need to deal with it in the child. */
|
|
||||||
+ fcntl (wrapper_data.pipe[1], F_SETFD, FD_CLOEXEC);
|
|
||||||
|
|
||||||
- wrapped_argv[i + G_N_ELEMENTS (wrapper_argv)] = NULL;
|
|
||||||
- g_free (argv);
|
|
||||||
- argv = NULL;
|
|
||||||
+ if (!(spawn_flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN))
|
|
||||||
+ {
|
|
||||||
+ /* In this case, we use a setup function (which could probably also
|
|
||||||
+ * overwrite envp to set GIO_LAUNCHED_DESKTOP_FILE_PID).
|
|
||||||
+ *
|
|
||||||
+ * Note that this does not incur an additional cost because
|
|
||||||
+ * G_SPAWN_LEAVE_DESCRIPTOR_OPEN must be set in order to use
|
|
||||||
+ * posix_spawn. */
|
|
||||||
+ wrapper_data.user_setup = setup;
|
|
||||||
+ wrapper_data.user_setup_data = setup_data;
|
|
||||||
+
|
|
||||||
+ setup = launch_uris_with_spawn_delay_exec;
|
|
||||||
+ setup_data = &wrapper_data;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ wrapped_argv[4] = g_strdup_printf ("export GIO_LAUNCHED_DESKTOP_FILE_PID=$$; cat <&%1$d; exec \"$@\" %1$d<&-",
|
|
||||||
+ wrapper_data.pipe[0]);
|
|
||||||
+#else
|
|
||||||
+ wrapped_argv[4] = g_strdup ("export GIO_LAUNCHED_DESKTOP_FILE_PID=$$; exec \"$@\"");
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
if (!g_spawn_async_with_fds (info->path,
|
|
||||||
wrapped_argv,
|
|
||||||
envp,
|
|
||||||
spawn_flags,
|
|
||||||
- user_setup,
|
|
||||||
- user_setup_data,
|
|
||||||
+ setup,
|
|
||||||
+ setup_data,
|
|
||||||
&pid,
|
|
||||||
stdin_fd,
|
|
||||||
stdout_fd,
|
|
||||||
stderr_fd,
|
|
||||||
error))
|
|
||||||
{
|
|
||||||
+#if defined(__linux__) && !defined(__BIONIC__)
|
|
||||||
+ close (wrapper_data.pipe[0]);
|
|
||||||
+ close (wrapper_data.pipe[1]);
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
if (sn_id)
|
|
||||||
g_app_launch_context_launch_failed (launch_context, sn_id);
|
|
||||||
|
|
||||||
- g_free (sn_id);
|
|
||||||
- g_list_free (launched_uris);
|
|
||||||
-
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
+#if defined(__linux__) && !defined(__BIONIC__)
|
|
||||||
+ /* We close write side asynchronously later on when the dbus call
|
|
||||||
+ * to systemd finishes. */
|
|
||||||
+ close (wrapper_data.pipe[0]);
|
|
||||||
+
|
|
||||||
+ if (session_bus)
|
|
||||||
+ create_systemd_scope (session_bus,
|
|
||||||
+ info,
|
|
||||||
+ pid,
|
|
||||||
+ systemd_scope_created_cb,
|
|
||||||
+ GINT_TO_POINTER (wrapper_data.pipe[1]));
|
|
||||||
+ else
|
|
||||||
+ close (wrapper_data.pipe[1]);
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
if (pid_callback != NULL)
|
|
||||||
pid_callback (info, pid, pid_callback_data);
|
|
||||||
|
|
||||||
@@ -2893,19 +3082,20 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|
||||||
sn_id,
|
|
||||||
launched_uris);
|
|
||||||
|
|
||||||
- g_free (sn_id);
|
|
||||||
- g_list_free (launched_uris);
|
|
||||||
-
|
|
||||||
- g_strfreev (wrapped_argv);
|
|
||||||
- wrapped_argv = NULL;
|
|
||||||
+ g_clear_pointer (&sn_id, g_free);
|
|
||||||
+ g_clear_pointer (&launched_uris, g_list_free);
|
|
||||||
+ g_clear_pointer (&wrapped_argv, g_strfreev);
|
|
||||||
}
|
|
||||||
while (dup_uris != NULL);
|
|
||||||
|
|
||||||
completed = TRUE;
|
|
||||||
|
|
||||||
- out:
|
|
||||||
+out:
|
|
||||||
g_strfreev (argv);
|
|
||||||
g_strfreev (envp);
|
|
||||||
+ g_clear_pointer (&wrapped_argv, g_strfreev);
|
|
||||||
+ g_list_free (launched_uris);
|
|
||||||
+ g_free (sn_id);
|
|
||||||
|
|
||||||
return completed;
|
|
||||||
}
|
|
||||||
--
|
|
||||||
2.31.1
|
|
||||||
|
|
@ -1,382 +0,0 @@
|
|||||||
From cd67a1b0256d2397dac0836e154f3449b63a6b19 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Benjamin Berg <bberg@redhat.com>
|
|
||||||
Date: Tue, 28 Jul 2020 12:11:13 +0200
|
|
||||||
Subject: [PATCH 3/4] gdesktopappinfo: Handle task completion from spawn
|
|
||||||
function
|
|
||||||
|
|
||||||
This allows delaying the return of the task until all dbus calls (in
|
|
||||||
particular the ones to setup the scope) have finished.
|
|
||||||
|
|
||||||
This fixes the behaviour of the previous commit which would not
|
|
||||||
correctly move the process into the scope if the application exited
|
|
||||||
right after the task returned.
|
|
||||||
---
|
|
||||||
gio/gdesktopappinfo.c | 212 +++++++++++++++++++++++++++++-------------
|
|
||||||
1 file changed, 146 insertions(+), 66 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
|
|
||||||
index afdcd42ac..8d0f1688e 100644
|
|
||||||
--- a/gio/gdesktopappinfo.c
|
|
||||||
+++ b/gio/gdesktopappinfo.c
|
|
||||||
@@ -2849,11 +2849,17 @@ create_systemd_scope (GDBusConnection *session_bus,
|
|
||||||
g_free (unit_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
+typedef struct {
|
|
||||||
+ GTask *task;
|
|
||||||
+ int fd;
|
|
||||||
+} ScopeCreatedData;
|
|
||||||
+
|
|
||||||
static void
|
|
||||||
systemd_scope_created_cb (GObject *object,
|
|
||||||
GAsyncResult *result,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
+ ScopeCreatedData *data = user_data;
|
|
||||||
GVariant *res = NULL;
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
@@ -2865,13 +2871,47 @@ systemd_scope_created_cb (GObject *object,
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unblock the waiting wrapper binary. */
|
|
||||||
- close (GPOINTER_TO_INT (user_data));
|
|
||||||
+
|
|
||||||
+ close (data->fd);
|
|
||||||
+
|
|
||||||
+ if (data->task)
|
|
||||||
+ {
|
|
||||||
+ gint pending;
|
|
||||||
+ pending = GPOINTER_TO_INT (g_task_get_task_data (data->task));
|
|
||||||
+ pending -= 1;
|
|
||||||
+ g_task_set_task_data (data->task, GINT_TO_POINTER (pending), NULL);
|
|
||||||
+
|
|
||||||
+ if (pending == 0 && !g_task_get_completed (data->task))
|
|
||||||
+ g_task_return_boolean (data->task, TRUE);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
if (res)
|
|
||||||
g_variant_unref (res);
|
|
||||||
+ g_clear_object (&data->task);
|
|
||||||
+ g_free (data);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+static void
|
|
||||||
+launch_uris_with_spawn_flush_cb (GObject *object,
|
|
||||||
+ GAsyncResult *result,
|
|
||||||
+ gpointer user_data)
|
|
||||||
+{
|
|
||||||
+ GTask *task = G_TASK (user_data);
|
|
||||||
+ gint pending;
|
|
||||||
+
|
|
||||||
+ g_dbus_connection_flush_finish (G_DBUS_CONNECTION (object), result, NULL);
|
|
||||||
+
|
|
||||||
+ pending = GPOINTER_TO_INT (g_task_get_task_data (task));
|
|
||||||
+ pending -= 1;
|
|
||||||
+ g_task_set_task_data (task, GINT_TO_POINTER (pending), NULL);
|
|
||||||
+
|
|
||||||
+ if (pending == 0 && !g_task_get_completed (task))
|
|
||||||
+ g_task_return_boolean (task, TRUE);
|
|
||||||
+
|
|
||||||
+ g_object_unref (task);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static gboolean
|
|
||||||
g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|
||||||
GDBusConnection *session_bus,
|
|
||||||
@@ -2886,9 +2926,10 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|
||||||
gint stdin_fd,
|
|
||||||
gint stdout_fd,
|
|
||||||
gint stderr_fd,
|
|
||||||
- GError **error)
|
|
||||||
+ GTask *task,
|
|
||||||
+ GError **error_out)
|
|
||||||
{
|
|
||||||
- gboolean completed = FALSE;
|
|
||||||
+ GError *error = NULL;
|
|
||||||
GList *old_uris;
|
|
||||||
GList *dup_uris;
|
|
||||||
|
|
||||||
@@ -2898,8 +2939,15 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|
||||||
char *sn_id = NULL;
|
|
||||||
int argc;
|
|
||||||
|
|
||||||
+ /* We may get a task to report back on or an error. But never both. */
|
|
||||||
+ g_assert (!(task && error_out));
|
|
||||||
g_return_val_if_fail (info != NULL, FALSE);
|
|
||||||
|
|
||||||
+ /* Surrounding code must not have set any data on the task
|
|
||||||
+ * (it is cleared before calling this function). */
|
|
||||||
+ if (session_bus && task)
|
|
||||||
+ g_assert (g_task_get_task_data (task) == NULL);
|
|
||||||
+
|
|
||||||
if (launch_context)
|
|
||||||
envp = g_app_launch_context_get_environment (launch_context);
|
|
||||||
else
|
|
||||||
@@ -2922,8 +2970,8 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|
||||||
gpointer setup_data = user_setup_data;
|
|
||||||
|
|
||||||
old_uris = dup_uris;
|
|
||||||
- if (!expand_application_parameters (info, exec_line, &dup_uris, &argc, &argv, error))
|
|
||||||
- return FALSE;
|
|
||||||
+ if (!expand_application_parameters (info, exec_line, &dup_uris, &argc, &argv, &error))
|
|
||||||
+ goto out;
|
|
||||||
|
|
||||||
/* Get the subset of URIs we're launching with this process */
|
|
||||||
for (iter = old_uris; iter != NULL && iter != dup_uris; iter = iter->next)
|
|
||||||
@@ -2932,9 +2980,9 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|
||||||
|
|
||||||
if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
|
|
||||||
{
|
|
||||||
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
- _("Unable to find terminal required for application"));
|
|
||||||
- return FALSE;
|
|
||||||
+ error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
+ _("Unable to find terminal required for application"));
|
|
||||||
+ goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->filename)
|
|
||||||
@@ -2991,9 +3039,9 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|
||||||
* otherwise our wrapper script will close both sides. */
|
|
||||||
if (!g_unix_open_pipe (wrapper_data.pipe, 0, NULL))
|
|
||||||
{
|
|
||||||
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
- _("Unable to create pipe for systemd synchronization"));
|
|
||||||
- return FALSE;
|
|
||||||
+ error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
+ _("Unable to create pipe for systemd synchronization"));
|
|
||||||
+ goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set CLOEXEC on the write pipe, so we don't need to deal with it in the child. */
|
|
||||||
@@ -3030,7 +3078,7 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|
||||||
stdin_fd,
|
|
||||||
stdout_fd,
|
|
||||||
stderr_fd,
|
|
||||||
- error))
|
|
||||||
+ &error))
|
|
||||||
{
|
|
||||||
#if defined(__linux__) && !defined(__BIONIC__)
|
|
||||||
close (wrapper_data.pipe[0]);
|
|
||||||
@@ -3049,11 +3097,29 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|
||||||
close (wrapper_data.pipe[0]);
|
|
||||||
|
|
||||||
if (session_bus)
|
|
||||||
- create_systemd_scope (session_bus,
|
|
||||||
- info,
|
|
||||||
- pid,
|
|
||||||
- systemd_scope_created_cb,
|
|
||||||
- GINT_TO_POINTER (wrapper_data.pipe[1]));
|
|
||||||
+ {
|
|
||||||
+ ScopeCreatedData *data;
|
|
||||||
+
|
|
||||||
+ data = g_new0 (ScopeCreatedData, 1);
|
|
||||||
+
|
|
||||||
+ if (task)
|
|
||||||
+ {
|
|
||||||
+ gint pending;
|
|
||||||
+ pending = GPOINTER_TO_INT (g_task_get_task_data (task));
|
|
||||||
+ pending += 1;
|
|
||||||
+ g_task_set_task_data (task, GINT_TO_POINTER (pending), NULL);
|
|
||||||
+
|
|
||||||
+ data->task = g_object_ref (task);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ data->fd = wrapper_data.pipe[1];
|
|
||||||
+
|
|
||||||
+ create_systemd_scope (session_bus,
|
|
||||||
+ info,
|
|
||||||
+ pid,
|
|
||||||
+ systemd_scope_created_cb,
|
|
||||||
+ data);
|
|
||||||
+ }
|
|
||||||
else
|
|
||||||
close (wrapper_data.pipe[1]);
|
|
||||||
#endif
|
|
||||||
@@ -3088,8 +3154,6 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|
||||||
}
|
|
||||||
while (dup_uris != NULL);
|
|
||||||
|
|
||||||
- completed = TRUE;
|
|
||||||
-
|
|
||||||
out:
|
|
||||||
g_strfreev (argv);
|
|
||||||
g_strfreev (envp);
|
|
||||||
@@ -3097,7 +3161,52 @@ out:
|
|
||||||
g_list_free (launched_uris);
|
|
||||||
g_free (sn_id);
|
|
||||||
|
|
||||||
- return completed;
|
|
||||||
+ if (!error)
|
|
||||||
+ {
|
|
||||||
+ if (session_bus && task)
|
|
||||||
+ {
|
|
||||||
+ GCancellable *cancellable = g_task_get_cancellable (task);
|
|
||||||
+ gint pending;
|
|
||||||
+ pending = GPOINTER_TO_INT (g_task_get_task_data (task));
|
|
||||||
+ pending += 1;
|
|
||||||
+ g_task_set_task_data (task, GINT_TO_POINTER (pending), NULL);
|
|
||||||
+
|
|
||||||
+ /* FIXME: The D-Bus message from the notify_desktop_launch() function
|
|
||||||
+ * can be still lost even if flush is called later. See:
|
|
||||||
+ * https://gitlab.freedesktop.org/dbus/dbus/issues/72
|
|
||||||
+ */
|
|
||||||
+ g_dbus_connection_flush (session_bus,
|
|
||||||
+ cancellable,
|
|
||||||
+ launch_uris_with_spawn_flush_cb,
|
|
||||||
+ g_steal_pointer (&task));
|
|
||||||
+ }
|
|
||||||
+ else if (session_bus)
|
|
||||||
+ {
|
|
||||||
+ /* No task available. */
|
|
||||||
+ g_dbus_connection_flush (session_bus,
|
|
||||||
+ NULL,
|
|
||||||
+ NULL,
|
|
||||||
+ NULL);
|
|
||||||
+ }
|
|
||||||
+ else if (task)
|
|
||||||
+ {
|
|
||||||
+ /* Return the given task. */
|
|
||||||
+ g_task_return_boolean (task, TRUE);
|
|
||||||
+ g_object_unref (task);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ else
|
|
||||||
+ {
|
|
||||||
+ if (task)
|
|
||||||
+ {
|
|
||||||
+ g_task_return_error (task, error);
|
|
||||||
+ g_object_unref (task);
|
|
||||||
+ }
|
|
||||||
+ else
|
|
||||||
+ g_propagate_error (error_out, error);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return !error;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gchar *
|
|
||||||
@@ -3246,17 +3355,9 @@ g_desktop_app_info_launch_uris_internal (GAppInfo *appinfo,
|
|
||||||
success = g_desktop_app_info_launch_uris_with_spawn (info, session_bus, info->exec, uris, launch_context,
|
|
||||||
spawn_flags, user_setup, user_setup_data,
|
|
||||||
pid_callback, pid_callback_data,
|
|
||||||
- stdin_fd, stdout_fd, stderr_fd, error);
|
|
||||||
+ stdin_fd, stdout_fd, stderr_fd, NULL, error);
|
|
||||||
|
|
||||||
- if (session_bus != NULL)
|
|
||||||
- {
|
|
||||||
- /* This asynchronous flush holds a reference until it completes,
|
|
||||||
- * which ensures that the following unref won't immediately kill
|
|
||||||
- * the connection if we were the initial owner.
|
|
||||||
- */
|
|
||||||
- g_dbus_connection_flush (session_bus, NULL, NULL, NULL);
|
|
||||||
- g_object_unref (session_bus);
|
|
||||||
- }
|
|
||||||
+ g_clear_object (&session_bus);
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
@@ -3310,18 +3411,6 @@ launch_uris_with_dbus_cb (GObject *object,
|
|
||||||
g_object_unref (task);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void
|
|
||||||
-launch_uris_flush_cb (GObject *object,
|
|
||||||
- GAsyncResult *result,
|
|
||||||
- gpointer user_data)
|
|
||||||
-{
|
|
||||||
- GTask *task = G_TASK (user_data);
|
|
||||||
-
|
|
||||||
- g_dbus_connection_flush_finish (G_DBUS_CONNECTION (object), result, NULL);
|
|
||||||
- g_task_return_boolean (task, TRUE);
|
|
||||||
- g_object_unref (task);
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
static void
|
|
||||||
launch_uris_bus_get_cb (GObject *object,
|
|
||||||
GAsyncResult *result,
|
|
||||||
@@ -3330,12 +3419,20 @@ launch_uris_bus_get_cb (GObject *object,
|
|
||||||
GTask *task = G_TASK (user_data);
|
|
||||||
GDesktopAppInfo *info = G_DESKTOP_APP_INFO (g_task_get_source_object (task));
|
|
||||||
LaunchUrisData *data = g_task_get_task_data (task);
|
|
||||||
+ LaunchUrisData *data_copy = NULL;
|
|
||||||
GCancellable *cancellable = g_task_get_cancellable (task);
|
|
||||||
GDBusConnection *session_bus;
|
|
||||||
- GError *error = NULL;
|
|
||||||
|
|
||||||
session_bus = g_bus_get_finish (result, NULL);
|
|
||||||
|
|
||||||
+ data_copy = g_new0 (LaunchUrisData, 1);
|
|
||||||
+ data_copy->appinfo = g_steal_pointer (&data->appinfo);
|
|
||||||
+ data_copy->uris = g_steal_pointer (&data->uris);
|
|
||||||
+ data_copy->context = g_steal_pointer (&data->context);
|
|
||||||
+
|
|
||||||
+ /* Allow other data to be attached to the task. */
|
|
||||||
+ g_task_set_task_data (task, NULL, NULL);
|
|
||||||
+
|
|
||||||
if (session_bus && info->app_id)
|
|
||||||
{
|
|
||||||
/* FIXME: The g_document_portal_add_documents() function, which is called
|
|
||||||
@@ -3343,34 +3440,21 @@ launch_uris_bus_get_cb (GObject *object,
|
|
||||||
* uses blocking calls.
|
|
||||||
*/
|
|
||||||
g_desktop_app_info_launch_uris_with_dbus (info, session_bus,
|
|
||||||
- data->uris, data->context,
|
|
||||||
+ data_copy->uris, data_copy->context,
|
|
||||||
cancellable,
|
|
||||||
launch_uris_with_dbus_cb,
|
|
||||||
g_steal_pointer (&task));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
- /* FIXME: The D-Bus message from the notify_desktop_launch() function
|
|
||||||
- * can be still lost even if flush is called later. See:
|
|
||||||
- * https://gitlab.freedesktop.org/dbus/dbus/issues/72
|
|
||||||
- */
|
|
||||||
g_desktop_app_info_launch_uris_with_spawn (info, session_bus, info->exec,
|
|
||||||
- data->uris, data->context,
|
|
||||||
+ data_copy->uris, data_copy->context,
|
|
||||||
_SPAWN_FLAGS_DEFAULT, NULL,
|
|
||||||
NULL, NULL, NULL, -1, -1, -1,
|
|
||||||
- &error);
|
|
||||||
- if (error != NULL)
|
|
||||||
- {
|
|
||||||
- g_task_return_error (task, g_steal_pointer (&error));
|
|
||||||
- g_object_unref (task);
|
|
||||||
- }
|
|
||||||
- else
|
|
||||||
- g_dbus_connection_flush (session_bus,
|
|
||||||
- cancellable,
|
|
||||||
- launch_uris_flush_cb,
|
|
||||||
- g_steal_pointer (&task));
|
|
||||||
+ g_steal_pointer (&task), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ launch_uris_data_free (data_copy);
|
|
||||||
g_clear_object (&session_bus);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -5186,16 +5270,12 @@ g_desktop_app_info_launch_action (GDesktopAppInfo *info,
|
|
||||||
if (exec_line)
|
|
||||||
g_desktop_app_info_launch_uris_with_spawn (info, session_bus, exec_line, NULL, launch_context,
|
|
||||||
_SPAWN_FLAGS_DEFAULT, NULL, NULL, NULL, NULL,
|
|
||||||
- -1, -1, -1, NULL);
|
|
||||||
+ -1, -1, -1, NULL, NULL);
|
|
||||||
|
|
||||||
g_free (exec_line);
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (session_bus != NULL)
|
|
||||||
- {
|
|
||||||
- g_dbus_connection_flush (session_bus, NULL, NULL, NULL);
|
|
||||||
- g_object_unref (session_bus);
|
|
||||||
- }
|
|
||||||
+ g_clear_object (&session_bus);
|
|
||||||
}
|
|
||||||
/* Epilogue {{{1 */
|
|
||||||
|
|
||||||
--
|
|
||||||
2.31.1
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
|||||||
From 8da8a3ef6df8af6de8bd388192bebe8b51b3e782 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Benjamin Berg <bberg@redhat.com>
|
|
||||||
Date: Thu, 17 Sep 2020 17:35:58 +0200
|
|
||||||
Subject: [PATCH 4/4] gdesktopappinfo: Add SourcePath= to transient systemd
|
|
||||||
units
|
|
||||||
|
|
||||||
systemd allows setting a SourcePath= which shows the file that the unit
|
|
||||||
has been generated from. KDE is starting to set this and it seems like a
|
|
||||||
good idea, so do the same here.
|
|
||||||
|
|
||||||
See https://invent.kde.org/frameworks/kio/-/merge_requests/124
|
|
||||||
---
|
|
||||||
gio/gdesktopappinfo.c | 13 +++++++++++++
|
|
||||||
1 file changed, 13 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
|
|
||||||
index 8d0f1688e..a833de4e6 100644
|
|
||||||
--- a/gio/gdesktopappinfo.c
|
|
||||||
+++ b/gio/gdesktopappinfo.c
|
|
||||||
@@ -2777,6 +2777,7 @@ create_systemd_scope (GDBusConnection *session_bus,
|
|
||||||
{
|
|
||||||
GVariantBuilder builder;
|
|
||||||
const char *app_name = g_get_application_name ();
|
|
||||||
+ const char *source_path = NULL;
|
|
||||||
char *appid = NULL;
|
|
||||||
char *appid_escaped = NULL;
|
|
||||||
char *snid_escaped = NULL;
|
|
||||||
@@ -2802,6 +2803,8 @@ create_systemd_scope (GDBusConnection *session_bus,
|
|
||||||
*/
|
|
||||||
unit_name = g_strdup_printf ("app-glib-%s-%d.scope", appid_escaped, pid);
|
|
||||||
|
|
||||||
+ source_path = g_desktop_app_info_get_filename (info);
|
|
||||||
+
|
|
||||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ssa(sv)a(sa(sv)))"));
|
|
||||||
g_variant_builder_add (&builder, "s", unit_name);
|
|
||||||
g_variant_builder_add (&builder, "s", "fail");
|
|
||||||
@@ -2815,6 +2818,16 @@ create_systemd_scope (GDBusConnection *session_bus,
|
|
||||||
"Description",
|
|
||||||
g_variant_new_take_string (g_strdup_printf ("Application launched by %s",
|
|
||||||
app_name)));
|
|
||||||
+
|
|
||||||
+ /* If we have a .desktop file, document that the scope has been "generated"
|
|
||||||
+ * from it.
|
|
||||||
+ */
|
|
||||||
+ if (source_path && g_utf8_validate (source_path, -1, NULL))
|
|
||||||
+ g_variant_builder_add (&builder,
|
|
||||||
+ "(sv)",
|
|
||||||
+ "SourcePath",
|
|
||||||
+ g_variant_new_string (source_path));
|
|
||||||
+
|
|
||||||
g_variant_builder_add (&builder,
|
|
||||||
"(sv)",
|
|
||||||
"PIDs",
|
|
||||||
--
|
|
||||||
2.31.1
|
|
||||||
|
|
855
gdesktopappinfo.patch
Normal file
855
gdesktopappinfo.patch
Normal file
@ -0,0 +1,855 @@
|
|||||||
|
From 5e42384cc4499293259a8a37a737014a56de34df Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Berg <bberg@redhat.com>
|
||||||
|
Date: Fri, 23 Oct 2020 18:20:01 +0200
|
||||||
|
Subject: [PATCH 1/4] tests: Iterate mainloop during launch test
|
||||||
|
|
||||||
|
When launching an application, we wait for the DBus response from
|
||||||
|
systemd before executing the binary. Because of this the main loop needs
|
||||||
|
to be iterated for spawning to completed and the file to be created.
|
||||||
|
|
||||||
|
Without this the test will time out if GLib was able to connect to the
|
||||||
|
session bus.
|
||||||
|
---
|
||||||
|
gio/tests/desktop-app-info.c | 1 +
|
||||||
|
1 file changed, 1 insertion(+)
|
||||||
|
|
||||||
|
diff --git a/gio/tests/desktop-app-info.c b/gio/tests/desktop-app-info.c
|
||||||
|
index fcc29c579..743230cbb 100644
|
||||||
|
--- a/gio/tests/desktop-app-info.c
|
||||||
|
+++ b/gio/tests/desktop-app-info.c
|
||||||
|
@@ -334,6 +334,7 @@ wait_for_file (const gchar *want_this,
|
||||||
|
*/
|
||||||
|
while (access (want_this, F_OK) != 0)
|
||||||
|
{
|
||||||
|
+ g_main_context_iteration (NULL, FALSE);
|
||||||
|
g_usleep (100000); /* 100ms */
|
||||||
|
g_assert_cmpuint (retries, >, 0);
|
||||||
|
retries--;
|
||||||
|
--
|
||||||
|
2.31.1
|
||||||
|
|
||||||
|
From ba3b85a8fea0151e74de50e841a7f16f9b077a56 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Berg <bberg@redhat.com>
|
||||||
|
Date: Mon, 27 Jul 2020 22:22:32 +0200
|
||||||
|
Subject: [PATCH 2/4] gdesktopappinfo: Move launched applications into
|
||||||
|
transient scope
|
||||||
|
|
||||||
|
Try to move the spawned executable into its own systemd scope. To avoid
|
||||||
|
possible race conditions and ensure proper accounting, we delay the
|
||||||
|
execution of the real command until after the DBus call to systemd has
|
||||||
|
finished.
|
||||||
|
|
||||||
|
From the two approaches we can take here, this is better in the sense
|
||||||
|
that we have a child that the API consumer can watch. API consumers
|
||||||
|
should not be doing this, however, gnome-session needs to watch children
|
||||||
|
during session startup. Until gnome-session is fixed, we will not be
|
||||||
|
able to change this.
|
||||||
|
|
||||||
|
The alternative approach is to delegate launching itself to systemd by
|
||||||
|
creating a transient .service unit instead. This is cleaner and has e.g.
|
||||||
|
the advantage that systemd will take care of log redirection and similar
|
||||||
|
issues.
|
||||||
|
|
||||||
|
Note that this patch is incomplete. The DBus call is done in a "fire and
|
||||||
|
forget" manner, which is fine in most cases, but means that "gio open"
|
||||||
|
will fail to move the child into the new scope as gio quits before the
|
||||||
|
DBus call finishes.
|
||||||
|
---
|
||||||
|
gio/gdesktopappinfo.c | 264 ++++++++++++++++++++++++++++++++++++------
|
||||||
|
1 file changed, 227 insertions(+), 37 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
|
||||||
|
index 1a4b97918..afdcd42ac 100644
|
||||||
|
--- a/gio/gdesktopappinfo.c
|
||||||
|
+++ b/gio/gdesktopappinfo.c
|
||||||
|
@@ -2730,6 +2730,148 @@ notify_desktop_launch (GDBusConnection *session_bus,
|
||||||
|
|
||||||
|
#define _SPAWN_FLAGS_DEFAULT (G_SPAWN_SEARCH_PATH)
|
||||||
|
|
||||||
|
+#if defined(__linux__) && !defined(__BIONIC__)
|
||||||
|
+typedef struct {
|
||||||
|
+ int pipe[2];
|
||||||
|
+ GSpawnChildSetupFunc user_setup;
|
||||||
|
+ gpointer user_setup_data;
|
||||||
|
+} SpawnWrapperData;
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+launch_uris_with_spawn_delay_exec (gpointer user_data)
|
||||||
|
+{
|
||||||
|
+ SpawnWrapperData *data = user_data;
|
||||||
|
+
|
||||||
|
+ /* Clear CLOEXEC again, as that was set due to
|
||||||
|
+ * G_SPAWN_LEAVE_DESCRIPTORS_OPEN not being set. */
|
||||||
|
+ fcntl (data->pipe[0], F_SETFD, 0);
|
||||||
|
+
|
||||||
|
+ /* No need to close read side, we have CLOEXEC set. */
|
||||||
|
+
|
||||||
|
+ if (data->user_setup)
|
||||||
|
+ data->user_setup (data->user_setup_data);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static gchar *
|
||||||
|
+systemd_unit_name_escape (const gchar *in)
|
||||||
|
+{
|
||||||
|
+ /* Adapted from systemd source */
|
||||||
|
+ GString * const str = g_string_sized_new (strlen (in));
|
||||||
|
+
|
||||||
|
+ for (; *in; in++)
|
||||||
|
+ {
|
||||||
|
+ if (g_ascii_isalnum (*in) || *in == ':' || *in == '_' || *in == '.')
|
||||||
|
+ g_string_append_c (str, *in);
|
||||||
|
+ else
|
||||||
|
+ g_string_append_printf (str, "\\x%02x", *in);
|
||||||
|
+ }
|
||||||
|
+ return g_string_free (str, FALSE);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+create_systemd_scope (GDBusConnection *session_bus,
|
||||||
|
+ GDesktopAppInfo *info,
|
||||||
|
+ gint pid,
|
||||||
|
+ GAsyncReadyCallback callback,
|
||||||
|
+ gpointer user_data)
|
||||||
|
+{
|
||||||
|
+ GVariantBuilder builder;
|
||||||
|
+ const char *app_name = g_get_application_name ();
|
||||||
|
+ char *appid = NULL;
|
||||||
|
+ char *appid_escaped = NULL;
|
||||||
|
+ char *snid_escaped = NULL;
|
||||||
|
+ char *unit_name = NULL;
|
||||||
|
+
|
||||||
|
+ /* In this order:
|
||||||
|
+ * 1. Actual application ID from file
|
||||||
|
+ * 2. Stripping the .desktop from the desktop ID
|
||||||
|
+ * 3. Fall back to using the binary name
|
||||||
|
+ */
|
||||||
|
+ if (info->app_id)
|
||||||
|
+ appid = g_strdup (info->app_id);
|
||||||
|
+ else if (info->desktop_id && g_str_has_suffix (info->desktop_id, ".desktop"))
|
||||||
|
+ appid = g_strndup (info->desktop_id, strlen (info->desktop_id) - 8);
|
||||||
|
+ else
|
||||||
|
+ appid = g_path_get_basename (info->binary);
|
||||||
|
+
|
||||||
|
+ appid_escaped = systemd_unit_name_escape (appid);
|
||||||
|
+
|
||||||
|
+ /* Generate a name conforming to
|
||||||
|
+ * https://systemd.io/DESKTOP_ENVIRONMENTS/
|
||||||
|
+ * We use the PID to disambiguate, as that should be unique enough.
|
||||||
|
+ */
|
||||||
|
+ unit_name = g_strdup_printf ("app-glib-%s-%d.scope", appid_escaped, pid);
|
||||||
|
+
|
||||||
|
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ssa(sv)a(sa(sv)))"));
|
||||||
|
+ g_variant_builder_add (&builder, "s", unit_name);
|
||||||
|
+ g_variant_builder_add (&builder, "s", "fail");
|
||||||
|
+
|
||||||
|
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(sv)"));
|
||||||
|
+
|
||||||
|
+ /* Add a generic human readable description, can be changed at will. */
|
||||||
|
+ if (app_name)
|
||||||
|
+ g_variant_builder_add (&builder,
|
||||||
|
+ "(sv)",
|
||||||
|
+ "Description",
|
||||||
|
+ g_variant_new_take_string (g_strdup_printf ("Application launched by %s",
|
||||||
|
+ app_name)));
|
||||||
|
+ g_variant_builder_add (&builder,
|
||||||
|
+ "(sv)",
|
||||||
|
+ "PIDs",
|
||||||
|
+ g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, &pid, 1, 4));
|
||||||
|
+ /* Default to let systemd garbage collect failed applications we launched. */
|
||||||
|
+ g_variant_builder_add (&builder,
|
||||||
|
+ "(sv)",
|
||||||
|
+ "CollectMode",
|
||||||
|
+ g_variant_new_string ("inactive-or-failed"));
|
||||||
|
+
|
||||||
|
+ g_variant_builder_close (&builder);
|
||||||
|
+
|
||||||
|
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(sa(sv))"));
|
||||||
|
+ g_variant_builder_close (&builder);
|
||||||
|
+
|
||||||
|
+ g_dbus_connection_call (session_bus,
|
||||||
|
+ "org.freedesktop.systemd1",
|
||||||
|
+ "/org/freedesktop/systemd1",
|
||||||
|
+ "org.freedesktop.systemd1.Manager",
|
||||||
|
+ "StartTransientUnit",
|
||||||
|
+ g_variant_builder_end (&builder),
|
||||||
|
+ G_VARIANT_TYPE ("(o)"),
|
||||||
|
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
||||||
|
+ 1000,
|
||||||
|
+ NULL,
|
||||||
|
+ callback,
|
||||||
|
+ user_data);
|
||||||
|
+
|
||||||
|
+ g_free (appid);
|
||||||
|
+ g_free (appid_escaped);
|
||||||
|
+ g_free (snid_escaped);
|
||||||
|
+ g_free (unit_name);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+systemd_scope_created_cb (GObject *object,
|
||||||
|
+ GAsyncResult *result,
|
||||||
|
+ gpointer user_data)
|
||||||
|
+{
|
||||||
|
+ GVariant *res = NULL;
|
||||||
|
+ GError *error = NULL;
|
||||||
|
+
|
||||||
|
+ res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error);
|
||||||
|
+ if (error != NULL)
|
||||||
|
+ {
|
||||||
|
+ g_debug ("Failed to move new child into scope: %s", error->message);
|
||||||
|
+ g_error_free (error);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Unblock the waiting wrapper binary. */
|
||||||
|
+ close (GPOINTER_TO_INT (user_data));
|
||||||
|
+
|
||||||
|
+ if (res)
|
||||||
|
+ g_variant_unref (res);
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
static gboolean
|
||||||
|
g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
|
GDBusConnection *session_bus,
|
||||||
|
@@ -2750,13 +2892,14 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
|
GList *old_uris;
|
||||||
|
GList *dup_uris;
|
||||||
|
|
||||||
|
- char **argv, **envp;
|
||||||
|
+ GStrv argv = NULL, envp = NULL;
|
||||||
|
+ GStrv wrapped_argv = NULL;
|
||||||
|
+ GList *launched_uris = NULL;
|
||||||
|
+ char *sn_id = NULL;
|
||||||
|
int argc;
|
||||||
|
|
||||||
|
g_return_val_if_fail (info != NULL, FALSE);
|
||||||
|
|
||||||
|
- argv = NULL;
|
||||||
|
-
|
||||||
|
if (launch_context)
|
||||||
|
envp = g_app_launch_context_get_environment (launch_context);
|
||||||
|
else
|
||||||
|
@@ -2770,27 +2913,19 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
|
do
|
||||||
|
{
|
||||||
|
GPid pid;
|
||||||
|
- GList *launched_uris;
|
||||||
|
GList *iter;
|
||||||
|
- char *sn_id = NULL;
|
||||||
|
- char **wrapped_argv;
|
||||||
|
int i;
|
||||||
|
- gsize j;
|
||||||
|
- const gchar * const wrapper_argv[] =
|
||||||
|
- {
|
||||||
|
- "/bin/sh",
|
||||||
|
- "-e",
|
||||||
|
- "-u",
|
||||||
|
- "-c", "export GIO_LAUNCHED_DESKTOP_FILE_PID=$$; exec \"$@\"",
|
||||||
|
- "sh", /* argv[0] for sh */
|
||||||
|
- };
|
||||||
|
+#if defined(__linux__) && !defined(__BIONIC__)
|
||||||
|
+ SpawnWrapperData wrapper_data;
|
||||||
|
+#endif
|
||||||
|
+ GSpawnChildSetupFunc setup = user_setup;
|
||||||
|
+ gpointer setup_data = user_setup_data;
|
||||||
|
|
||||||
|
old_uris = dup_uris;
|
||||||
|
if (!expand_application_parameters (info, exec_line, &dup_uris, &argc, &argv, error))
|
||||||
|
- goto out;
|
||||||
|
+ return FALSE;
|
||||||
|
|
||||||
|
/* Get the subset of URIs we're launching with this process */
|
||||||
|
- launched_uris = NULL;
|
||||||
|
for (iter = old_uris; iter != NULL && iter != dup_uris; iter = iter->next)
|
||||||
|
launched_uris = g_list_prepend (launched_uris, iter->data);
|
||||||
|
launched_uris = g_list_reverse (launched_uris);
|
||||||
|
@@ -2799,7 +2934,7 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
|
{
|
||||||
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
_("Unable to find terminal required for application"));
|
||||||
|
- goto out;
|
||||||
|
+ return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->filename)
|
||||||
|
@@ -2808,7 +2943,6 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
|
info->filename,
|
||||||
|
TRUE);
|
||||||
|
|
||||||
|
- sn_id = NULL;
|
||||||
|
if (launch_context)
|
||||||
|
{
|
||||||
|
GList *launched_files = create_files_for_uris (launched_uris);
|
||||||
|
@@ -2837,38 +2971,93 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
|
* with a wrapper program (grep the GLib git history for
|
||||||
|
* `gio-launch-desktop` for an example of this which could be
|
||||||
|
* resurrected). */
|
||||||
|
- wrapped_argv = g_new (char *, argc + G_N_ELEMENTS (wrapper_argv) + 1);
|
||||||
|
+ wrapped_argv = g_new (char *, argc + 6 + 1);
|
||||||
|
+
|
||||||
|
+ wrapped_argv[0] = g_strdup ("/bin/sh");
|
||||||
|
+ wrapped_argv[1] = g_strdup ("-e");
|
||||||
|
+ wrapped_argv[2] = g_strdup ("-u");
|
||||||
|
+ wrapped_argv[3] = g_strdup ("-c");
|
||||||
|
+ /* argument 4 is filled in below */
|
||||||
|
+ wrapped_argv[5] = g_strdup ("sh");
|
||||||
|
|
||||||
|
- for (j = 0; j < G_N_ELEMENTS (wrapper_argv); j++)
|
||||||
|
- wrapped_argv[j] = g_strdup (wrapper_argv[j]);
|
||||||
|
for (i = 0; i < argc; i++)
|
||||||
|
- wrapped_argv[i + G_N_ELEMENTS (wrapper_argv)] = g_steal_pointer (&argv[i]);
|
||||||
|
+ wrapped_argv[i + 6] = g_steal_pointer (&argv[i]);
|
||||||
|
+
|
||||||
|
+ wrapped_argv[i + 6] = NULL;
|
||||||
|
+ g_clear_pointer (&argv, g_free);
|
||||||
|
+
|
||||||
|
+#if defined(__linux__) && !defined(__BIONIC__)
|
||||||
|
+ /* Create pipes, if we use a setup func, then set cloexec,
|
||||||
|
+ * otherwise our wrapper script will close both sides. */
|
||||||
|
+ if (!g_unix_open_pipe (wrapper_data.pipe, 0, NULL))
|
||||||
|
+ {
|
||||||
|
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
+ _("Unable to create pipe for systemd synchronization"));
|
||||||
|
+ return FALSE;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Set CLOEXEC on the write pipe, so we don't need to deal with it in the child. */
|
||||||
|
+ fcntl (wrapper_data.pipe[1], F_SETFD, FD_CLOEXEC);
|
||||||
|
|
||||||
|
- wrapped_argv[i + G_N_ELEMENTS (wrapper_argv)] = NULL;
|
||||||
|
- g_free (argv);
|
||||||
|
- argv = NULL;
|
||||||
|
+ if (!(spawn_flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN))
|
||||||
|
+ {
|
||||||
|
+ /* In this case, we use a setup function (which could probably also
|
||||||
|
+ * overwrite envp to set GIO_LAUNCHED_DESKTOP_FILE_PID).
|
||||||
|
+ *
|
||||||
|
+ * Note that this does not incur an additional cost because
|
||||||
|
+ * G_SPAWN_LEAVE_DESCRIPTOR_OPEN must be set in order to use
|
||||||
|
+ * posix_spawn. */
|
||||||
|
+ wrapper_data.user_setup = setup;
|
||||||
|
+ wrapper_data.user_setup_data = setup_data;
|
||||||
|
+
|
||||||
|
+ setup = launch_uris_with_spawn_delay_exec;
|
||||||
|
+ setup_data = &wrapper_data;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ wrapped_argv[4] = g_strdup_printf ("export GIO_LAUNCHED_DESKTOP_FILE_PID=$$; cat <&%1$d; exec \"$@\" %1$d<&-",
|
||||||
|
+ wrapper_data.pipe[0]);
|
||||||
|
+#else
|
||||||
|
+ wrapped_argv[4] = g_strdup ("export GIO_LAUNCHED_DESKTOP_FILE_PID=$$; exec \"$@\"");
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
if (!g_spawn_async_with_fds (info->path,
|
||||||
|
wrapped_argv,
|
||||||
|
envp,
|
||||||
|
spawn_flags,
|
||||||
|
- user_setup,
|
||||||
|
- user_setup_data,
|
||||||
|
+ setup,
|
||||||
|
+ setup_data,
|
||||||
|
&pid,
|
||||||
|
stdin_fd,
|
||||||
|
stdout_fd,
|
||||||
|
stderr_fd,
|
||||||
|
error))
|
||||||
|
{
|
||||||
|
+#if defined(__linux__) && !defined(__BIONIC__)
|
||||||
|
+ close (wrapper_data.pipe[0]);
|
||||||
|
+ close (wrapper_data.pipe[1]);
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
if (sn_id)
|
||||||
|
g_app_launch_context_launch_failed (launch_context, sn_id);
|
||||||
|
|
||||||
|
- g_free (sn_id);
|
||||||
|
- g_list_free (launched_uris);
|
||||||
|
-
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
+#if defined(__linux__) && !defined(__BIONIC__)
|
||||||
|
+ /* We close write side asynchronously later on when the dbus call
|
||||||
|
+ * to systemd finishes. */
|
||||||
|
+ close (wrapper_data.pipe[0]);
|
||||||
|
+
|
||||||
|
+ if (session_bus)
|
||||||
|
+ create_systemd_scope (session_bus,
|
||||||
|
+ info,
|
||||||
|
+ pid,
|
||||||
|
+ systemd_scope_created_cb,
|
||||||
|
+ GINT_TO_POINTER (wrapper_data.pipe[1]));
|
||||||
|
+ else
|
||||||
|
+ close (wrapper_data.pipe[1]);
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
if (pid_callback != NULL)
|
||||||
|
pid_callback (info, pid, pid_callback_data);
|
||||||
|
|
||||||
|
@@ -2893,19 +3082,20 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
|
sn_id,
|
||||||
|
launched_uris);
|
||||||
|
|
||||||
|
- g_free (sn_id);
|
||||||
|
- g_list_free (launched_uris);
|
||||||
|
-
|
||||||
|
- g_strfreev (wrapped_argv);
|
||||||
|
- wrapped_argv = NULL;
|
||||||
|
+ g_clear_pointer (&sn_id, g_free);
|
||||||
|
+ g_clear_pointer (&launched_uris, g_list_free);
|
||||||
|
+ g_clear_pointer (&wrapped_argv, g_strfreev);
|
||||||
|
}
|
||||||
|
while (dup_uris != NULL);
|
||||||
|
|
||||||
|
completed = TRUE;
|
||||||
|
|
||||||
|
- out:
|
||||||
|
+out:
|
||||||
|
g_strfreev (argv);
|
||||||
|
g_strfreev (envp);
|
||||||
|
+ g_clear_pointer (&wrapped_argv, g_strfreev);
|
||||||
|
+ g_list_free (launched_uris);
|
||||||
|
+ g_free (sn_id);
|
||||||
|
|
||||||
|
return completed;
|
||||||
|
}
|
||||||
|
--
|
||||||
|
2.31.1
|
||||||
|
|
||||||
|
From cd67a1b0256d2397dac0836e154f3449b63a6b19 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Berg <bberg@redhat.com>
|
||||||
|
Date: Tue, 28 Jul 2020 12:11:13 +0200
|
||||||
|
Subject: [PATCH 3/4] gdesktopappinfo: Handle task completion from spawn
|
||||||
|
function
|
||||||
|
|
||||||
|
This allows delaying the return of the task until all dbus calls (in
|
||||||
|
particular the ones to setup the scope) have finished.
|
||||||
|
|
||||||
|
This fixes the behaviour of the previous commit which would not
|
||||||
|
correctly move the process into the scope if the application exited
|
||||||
|
right after the task returned.
|
||||||
|
---
|
||||||
|
gio/gdesktopappinfo.c | 212 +++++++++++++++++++++++++++++-------------
|
||||||
|
1 file changed, 146 insertions(+), 66 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
|
||||||
|
index afdcd42ac..8d0f1688e 100644
|
||||||
|
--- a/gio/gdesktopappinfo.c
|
||||||
|
+++ b/gio/gdesktopappinfo.c
|
||||||
|
@@ -2849,11 +2849,17 @@ create_systemd_scope (GDBusConnection *session_bus,
|
||||||
|
g_free (unit_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
+typedef struct {
|
||||||
|
+ GTask *task;
|
||||||
|
+ int fd;
|
||||||
|
+} ScopeCreatedData;
|
||||||
|
+
|
||||||
|
static void
|
||||||
|
systemd_scope_created_cb (GObject *object,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
+ ScopeCreatedData *data = user_data;
|
||||||
|
GVariant *res = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
@@ -2865,13 +2871,47 @@ systemd_scope_created_cb (GObject *object,
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unblock the waiting wrapper binary. */
|
||||||
|
- close (GPOINTER_TO_INT (user_data));
|
||||||
|
+
|
||||||
|
+ close (data->fd);
|
||||||
|
+
|
||||||
|
+ if (data->task)
|
||||||
|
+ {
|
||||||
|
+ gint pending;
|
||||||
|
+ pending = GPOINTER_TO_INT (g_task_get_task_data (data->task));
|
||||||
|
+ pending -= 1;
|
||||||
|
+ g_task_set_task_data (data->task, GINT_TO_POINTER (pending), NULL);
|
||||||
|
+
|
||||||
|
+ if (pending == 0 && !g_task_get_completed (data->task))
|
||||||
|
+ g_task_return_boolean (data->task, TRUE);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
g_variant_unref (res);
|
||||||
|
+ g_clear_object (&data->task);
|
||||||
|
+ g_free (data);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+static void
|
||||||
|
+launch_uris_with_spawn_flush_cb (GObject *object,
|
||||||
|
+ GAsyncResult *result,
|
||||||
|
+ gpointer user_data)
|
||||||
|
+{
|
||||||
|
+ GTask *task = G_TASK (user_data);
|
||||||
|
+ gint pending;
|
||||||
|
+
|
||||||
|
+ g_dbus_connection_flush_finish (G_DBUS_CONNECTION (object), result, NULL);
|
||||||
|
+
|
||||||
|
+ pending = GPOINTER_TO_INT (g_task_get_task_data (task));
|
||||||
|
+ pending -= 1;
|
||||||
|
+ g_task_set_task_data (task, GINT_TO_POINTER (pending), NULL);
|
||||||
|
+
|
||||||
|
+ if (pending == 0 && !g_task_get_completed (task))
|
||||||
|
+ g_task_return_boolean (task, TRUE);
|
||||||
|
+
|
||||||
|
+ g_object_unref (task);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static gboolean
|
||||||
|
g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
|
GDBusConnection *session_bus,
|
||||||
|
@@ -2886,9 +2926,10 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
|
gint stdin_fd,
|
||||||
|
gint stdout_fd,
|
||||||
|
gint stderr_fd,
|
||||||
|
- GError **error)
|
||||||
|
+ GTask *task,
|
||||||
|
+ GError **error_out)
|
||||||
|
{
|
||||||
|
- gboolean completed = FALSE;
|
||||||
|
+ GError *error = NULL;
|
||||||
|
GList *old_uris;
|
||||||
|
GList *dup_uris;
|
||||||
|
|
||||||
|
@@ -2898,8 +2939,15 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
|
char *sn_id = NULL;
|
||||||
|
int argc;
|
||||||
|
|
||||||
|
+ /* We may get a task to report back on or an error. But never both. */
|
||||||
|
+ g_assert (!(task && error_out));
|
||||||
|
g_return_val_if_fail (info != NULL, FALSE);
|
||||||
|
|
||||||
|
+ /* Surrounding code must not have set any data on the task
|
||||||
|
+ * (it is cleared before calling this function). */
|
||||||
|
+ if (session_bus && task)
|
||||||
|
+ g_assert (g_task_get_task_data (task) == NULL);
|
||||||
|
+
|
||||||
|
if (launch_context)
|
||||||
|
envp = g_app_launch_context_get_environment (launch_context);
|
||||||
|
else
|
||||||
|
@@ -2922,8 +2970,8 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
|
gpointer setup_data = user_setup_data;
|
||||||
|
|
||||||
|
old_uris = dup_uris;
|
||||||
|
- if (!expand_application_parameters (info, exec_line, &dup_uris, &argc, &argv, error))
|
||||||
|
- return FALSE;
|
||||||
|
+ if (!expand_application_parameters (info, exec_line, &dup_uris, &argc, &argv, &error))
|
||||||
|
+ goto out;
|
||||||
|
|
||||||
|
/* Get the subset of URIs we're launching with this process */
|
||||||
|
for (iter = old_uris; iter != NULL && iter != dup_uris; iter = iter->next)
|
||||||
|
@@ -2932,9 +2980,9 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
|
|
||||||
|
if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
|
||||||
|
{
|
||||||
|
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
- _("Unable to find terminal required for application"));
|
||||||
|
- return FALSE;
|
||||||
|
+ error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
+ _("Unable to find terminal required for application"));
|
||||||
|
+ goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->filename)
|
||||||
|
@@ -2991,9 +3039,9 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
|
* otherwise our wrapper script will close both sides. */
|
||||||
|
if (!g_unix_open_pipe (wrapper_data.pipe, 0, NULL))
|
||||||
|
{
|
||||||
|
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
- _("Unable to create pipe for systemd synchronization"));
|
||||||
|
- return FALSE;
|
||||||
|
+ error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
+ _("Unable to create pipe for systemd synchronization"));
|
||||||
|
+ goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set CLOEXEC on the write pipe, so we don't need to deal with it in the child. */
|
||||||
|
@@ -3030,7 +3078,7 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
|
stdin_fd,
|
||||||
|
stdout_fd,
|
||||||
|
stderr_fd,
|
||||||
|
- error))
|
||||||
|
+ &error))
|
||||||
|
{
|
||||||
|
#if defined(__linux__) && !defined(__BIONIC__)
|
||||||
|
close (wrapper_data.pipe[0]);
|
||||||
|
@@ -3049,11 +3097,29 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
|
close (wrapper_data.pipe[0]);
|
||||||
|
|
||||||
|
if (session_bus)
|
||||||
|
- create_systemd_scope (session_bus,
|
||||||
|
- info,
|
||||||
|
- pid,
|
||||||
|
- systemd_scope_created_cb,
|
||||||
|
- GINT_TO_POINTER (wrapper_data.pipe[1]));
|
||||||
|
+ {
|
||||||
|
+ ScopeCreatedData *data;
|
||||||
|
+
|
||||||
|
+ data = g_new0 (ScopeCreatedData, 1);
|
||||||
|
+
|
||||||
|
+ if (task)
|
||||||
|
+ {
|
||||||
|
+ gint pending;
|
||||||
|
+ pending = GPOINTER_TO_INT (g_task_get_task_data (task));
|
||||||
|
+ pending += 1;
|
||||||
|
+ g_task_set_task_data (task, GINT_TO_POINTER (pending), NULL);
|
||||||
|
+
|
||||||
|
+ data->task = g_object_ref (task);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ data->fd = wrapper_data.pipe[1];
|
||||||
|
+
|
||||||
|
+ create_systemd_scope (session_bus,
|
||||||
|
+ info,
|
||||||
|
+ pid,
|
||||||
|
+ systemd_scope_created_cb,
|
||||||
|
+ data);
|
||||||
|
+ }
|
||||||
|
else
|
||||||
|
close (wrapper_data.pipe[1]);
|
||||||
|
#endif
|
||||||
|
@@ -3088,8 +3154,6 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
|
}
|
||||||
|
while (dup_uris != NULL);
|
||||||
|
|
||||||
|
- completed = TRUE;
|
||||||
|
-
|
||||||
|
out:
|
||||||
|
g_strfreev (argv);
|
||||||
|
g_strfreev (envp);
|
||||||
|
@@ -3097,7 +3161,52 @@ out:
|
||||||
|
g_list_free (launched_uris);
|
||||||
|
g_free (sn_id);
|
||||||
|
|
||||||
|
- return completed;
|
||||||
|
+ if (!error)
|
||||||
|
+ {
|
||||||
|
+ if (session_bus && task)
|
||||||
|
+ {
|
||||||
|
+ GCancellable *cancellable = g_task_get_cancellable (task);
|
||||||
|
+ gint pending;
|
||||||
|
+ pending = GPOINTER_TO_INT (g_task_get_task_data (task));
|
||||||
|
+ pending += 1;
|
||||||
|
+ g_task_set_task_data (task, GINT_TO_POINTER (pending), NULL);
|
||||||
|
+
|
||||||
|
+ /* FIXME: The D-Bus message from the notify_desktop_launch() function
|
||||||
|
+ * can be still lost even if flush is called later. See:
|
||||||
|
+ * https://gitlab.freedesktop.org/dbus/dbus/issues/72
|
||||||
|
+ */
|
||||||
|
+ g_dbus_connection_flush (session_bus,
|
||||||
|
+ cancellable,
|
||||||
|
+ launch_uris_with_spawn_flush_cb,
|
||||||
|
+ g_steal_pointer (&task));
|
||||||
|
+ }
|
||||||
|
+ else if (session_bus)
|
||||||
|
+ {
|
||||||
|
+ /* No task available. */
|
||||||
|
+ g_dbus_connection_flush (session_bus,
|
||||||
|
+ NULL,
|
||||||
|
+ NULL,
|
||||||
|
+ NULL);
|
||||||
|
+ }
|
||||||
|
+ else if (task)
|
||||||
|
+ {
|
||||||
|
+ /* Return the given task. */
|
||||||
|
+ g_task_return_boolean (task, TRUE);
|
||||||
|
+ g_object_unref (task);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ if (task)
|
||||||
|
+ {
|
||||||
|
+ g_task_return_error (task, error);
|
||||||
|
+ g_object_unref (task);
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ g_propagate_error (error_out, error);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return !error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gchar *
|
||||||
|
@@ -3246,17 +3355,9 @@ g_desktop_app_info_launch_uris_internal (GAppInfo *appinfo,
|
||||||
|
success = g_desktop_app_info_launch_uris_with_spawn (info, session_bus, info->exec, uris, launch_context,
|
||||||
|
spawn_flags, user_setup, user_setup_data,
|
||||||
|
pid_callback, pid_callback_data,
|
||||||
|
- stdin_fd, stdout_fd, stderr_fd, error);
|
||||||
|
+ stdin_fd, stdout_fd, stderr_fd, NULL, error);
|
||||||
|
|
||||||
|
- if (session_bus != NULL)
|
||||||
|
- {
|
||||||
|
- /* This asynchronous flush holds a reference until it completes,
|
||||||
|
- * which ensures that the following unref won't immediately kill
|
||||||
|
- * the connection if we were the initial owner.
|
||||||
|
- */
|
||||||
|
- g_dbus_connection_flush (session_bus, NULL, NULL, NULL);
|
||||||
|
- g_object_unref (session_bus);
|
||||||
|
- }
|
||||||
|
+ g_clear_object (&session_bus);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
@@ -3310,18 +3411,6 @@ launch_uris_with_dbus_cb (GObject *object,
|
||||||
|
g_object_unref (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
-static void
|
||||||
|
-launch_uris_flush_cb (GObject *object,
|
||||||
|
- GAsyncResult *result,
|
||||||
|
- gpointer user_data)
|
||||||
|
-{
|
||||||
|
- GTask *task = G_TASK (user_data);
|
||||||
|
-
|
||||||
|
- g_dbus_connection_flush_finish (G_DBUS_CONNECTION (object), result, NULL);
|
||||||
|
- g_task_return_boolean (task, TRUE);
|
||||||
|
- g_object_unref (task);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static void
|
||||||
|
launch_uris_bus_get_cb (GObject *object,
|
||||||
|
GAsyncResult *result,
|
||||||
|
@@ -3330,12 +3419,20 @@ launch_uris_bus_get_cb (GObject *object,
|
||||||
|
GTask *task = G_TASK (user_data);
|
||||||
|
GDesktopAppInfo *info = G_DESKTOP_APP_INFO (g_task_get_source_object (task));
|
||||||
|
LaunchUrisData *data = g_task_get_task_data (task);
|
||||||
|
+ LaunchUrisData *data_copy = NULL;
|
||||||
|
GCancellable *cancellable = g_task_get_cancellable (task);
|
||||||
|
GDBusConnection *session_bus;
|
||||||
|
- GError *error = NULL;
|
||||||
|
|
||||||
|
session_bus = g_bus_get_finish (result, NULL);
|
||||||
|
|
||||||
|
+ data_copy = g_new0 (LaunchUrisData, 1);
|
||||||
|
+ data_copy->appinfo = g_steal_pointer (&data->appinfo);
|
||||||
|
+ data_copy->uris = g_steal_pointer (&data->uris);
|
||||||
|
+ data_copy->context = g_steal_pointer (&data->context);
|
||||||
|
+
|
||||||
|
+ /* Allow other data to be attached to the task. */
|
||||||
|
+ g_task_set_task_data (task, NULL, NULL);
|
||||||
|
+
|
||||||
|
if (session_bus && info->app_id)
|
||||||
|
{
|
||||||
|
/* FIXME: The g_document_portal_add_documents() function, which is called
|
||||||
|
@@ -3343,34 +3440,21 @@ launch_uris_bus_get_cb (GObject *object,
|
||||||
|
* uses blocking calls.
|
||||||
|
*/
|
||||||
|
g_desktop_app_info_launch_uris_with_dbus (info, session_bus,
|
||||||
|
- data->uris, data->context,
|
||||||
|
+ data_copy->uris, data_copy->context,
|
||||||
|
cancellable,
|
||||||
|
launch_uris_with_dbus_cb,
|
||||||
|
g_steal_pointer (&task));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
- /* FIXME: The D-Bus message from the notify_desktop_launch() function
|
||||||
|
- * can be still lost even if flush is called later. See:
|
||||||
|
- * https://gitlab.freedesktop.org/dbus/dbus/issues/72
|
||||||
|
- */
|
||||||
|
g_desktop_app_info_launch_uris_with_spawn (info, session_bus, info->exec,
|
||||||
|
- data->uris, data->context,
|
||||||
|
+ data_copy->uris, data_copy->context,
|
||||||
|
_SPAWN_FLAGS_DEFAULT, NULL,
|
||||||
|
NULL, NULL, NULL, -1, -1, -1,
|
||||||
|
- &error);
|
||||||
|
- if (error != NULL)
|
||||||
|
- {
|
||||||
|
- g_task_return_error (task, g_steal_pointer (&error));
|
||||||
|
- g_object_unref (task);
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- g_dbus_connection_flush (session_bus,
|
||||||
|
- cancellable,
|
||||||
|
- launch_uris_flush_cb,
|
||||||
|
- g_steal_pointer (&task));
|
||||||
|
+ g_steal_pointer (&task), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ launch_uris_data_free (data_copy);
|
||||||
|
g_clear_object (&session_bus);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -5186,16 +5270,12 @@ g_desktop_app_info_launch_action (GDesktopAppInfo *info,
|
||||||
|
if (exec_line)
|
||||||
|
g_desktop_app_info_launch_uris_with_spawn (info, session_bus, exec_line, NULL, launch_context,
|
||||||
|
_SPAWN_FLAGS_DEFAULT, NULL, NULL, NULL, NULL,
|
||||||
|
- -1, -1, -1, NULL);
|
||||||
|
+ -1, -1, -1, NULL, NULL);
|
||||||
|
|
||||||
|
g_free (exec_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (session_bus != NULL)
|
||||||
|
- {
|
||||||
|
- g_dbus_connection_flush (session_bus, NULL, NULL, NULL);
|
||||||
|
- g_object_unref (session_bus);
|
||||||
|
- }
|
||||||
|
+ g_clear_object (&session_bus);
|
||||||
|
}
|
||||||
|
/* Epilogue {{{1 */
|
||||||
|
|
||||||
|
--
|
||||||
|
2.31.1
|
||||||
|
|
||||||
|
From 8da8a3ef6df8af6de8bd388192bebe8b51b3e782 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benjamin Berg <bberg@redhat.com>
|
||||||
|
Date: Thu, 17 Sep 2020 17:35:58 +0200
|
||||||
|
Subject: [PATCH 4/4] gdesktopappinfo: Add SourcePath= to transient systemd
|
||||||
|
units
|
||||||
|
|
||||||
|
systemd allows setting a SourcePath= which shows the file that the unit
|
||||||
|
has been generated from. KDE is starting to set this and it seems like a
|
||||||
|
good idea, so do the same here.
|
||||||
|
|
||||||
|
See https://invent.kde.org/frameworks/kio/-/merge_requests/124
|
||||||
|
---
|
||||||
|
gio/gdesktopappinfo.c | 13 +++++++++++++
|
||||||
|
1 file changed, 13 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
|
||||||
|
index 8d0f1688e..a833de4e6 100644
|
||||||
|
--- a/gio/gdesktopappinfo.c
|
||||||
|
+++ b/gio/gdesktopappinfo.c
|
||||||
|
@@ -2777,6 +2777,7 @@ create_systemd_scope (GDBusConnection *session_bus,
|
||||||
|
{
|
||||||
|
GVariantBuilder builder;
|
||||||
|
const char *app_name = g_get_application_name ();
|
||||||
|
+ const char *source_path = NULL;
|
||||||
|
char *appid = NULL;
|
||||||
|
char *appid_escaped = NULL;
|
||||||
|
char *snid_escaped = NULL;
|
||||||
|
@@ -2802,6 +2803,8 @@ create_systemd_scope (GDBusConnection *session_bus,
|
||||||
|
*/
|
||||||
|
unit_name = g_strdup_printf ("app-glib-%s-%d.scope", appid_escaped, pid);
|
||||||
|
|
||||||
|
+ source_path = g_desktop_app_info_get_filename (info);
|
||||||
|
+
|
||||||
|
g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ssa(sv)a(sa(sv)))"));
|
||||||
|
g_variant_builder_add (&builder, "s", unit_name);
|
||||||
|
g_variant_builder_add (&builder, "s", "fail");
|
||||||
|
@@ -2815,6 +2818,16 @@ create_systemd_scope (GDBusConnection *session_bus,
|
||||||
|
"Description",
|
||||||
|
g_variant_new_take_string (g_strdup_printf ("Application launched by %s",
|
||||||
|
app_name)));
|
||||||
|
+
|
||||||
|
+ /* If we have a .desktop file, document that the scope has been "generated"
|
||||||
|
+ * from it.
|
||||||
|
+ */
|
||||||
|
+ if (source_path && g_utf8_validate (source_path, -1, NULL))
|
||||||
|
+ g_variant_builder_add (&builder,
|
||||||
|
+ "(sv)",
|
||||||
|
+ "SourcePath",
|
||||||
|
+ g_variant_new_string (source_path));
|
||||||
|
+
|
||||||
|
g_variant_builder_add (&builder,
|
||||||
|
"(sv)",
|
||||||
|
"PIDs",
|
||||||
|
--
|
||||||
|
2.31.1
|
44
glib2.spec
44
glib2.spec
@ -1,25 +1,24 @@
|
|||||||
|
# https://bugzilla.redhat.com/show_bug.cgi?id=1973304
|
||||||
|
%global __brp_check_rpaths %{nil}
|
||||||
|
|
||||||
Name: glib2
|
Name: glib2
|
||||||
Version: 2.68.2
|
Version: 2.68.2
|
||||||
Release: 1%{?dist}
|
Release: 2%{?dist}
|
||||||
Summary: A library of handy utility functions
|
Summary: A library of handy utility functions
|
||||||
|
|
||||||
License: LGPLv2+
|
License: LGPLv2+
|
||||||
URL: http://www.gtk.org
|
URL: http://www.gtk.org
|
||||||
Source0: http://download.gnome.org/sources/glib/2.68/glib-%{version}.tar.xz
|
Source0: http://download.gnome.org/sources/glib/2.68/glib-%{version}.tar.xz
|
||||||
|
|
||||||
%if 0%{?rhel}
|
# Required for RHEL core crypto components policy. Good for Fedora too.
|
||||||
# Required for RHEL core crypto components policy.
|
# https://bugzilla.redhat.com/show_bug.cgi?id=1630260
|
||||||
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/903
|
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/903
|
||||||
Patch0: gnutls-hmac.patch
|
Patch0: gnutls-hmac.patch
|
||||||
%endif
|
|
||||||
|
|
||||||
# Add patches to move applications into systemd scopes in compliance with
|
# Add patches to move applications into systemd scopes in compliance with
|
||||||
# https://systemd.io/DESKTOP_ENVIRONMENTS/
|
# https://systemd.io/DESKTOP_ENVIRONMENTS/
|
||||||
# Proposed upstream at https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1596
|
# Proposed upstream at https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1596
|
||||||
Patch001: 0001-tests-Iterate-mainloop-during-launch-test.patch
|
Patch1: gdesktopappinfo.patch
|
||||||
Patch002: 0002-gdesktopappinfo-Move-launched-applications-into-tran.patch
|
|
||||||
Patch003: 0003-gdesktopappinfo-Handle-task-completion-from-spawn-fu.patch
|
|
||||||
Patch004: 0004-gdesktopappinfo-Add-SourcePath-to-transient-systemd-.patch
|
|
||||||
|
|
||||||
BuildRequires: chrpath
|
BuildRequires: chrpath
|
||||||
BuildRequires: gcc
|
BuildRequires: gcc
|
||||||
@ -34,10 +33,6 @@ BuildRequires: libselinux-devel
|
|||||||
BuildRequires: meson
|
BuildRequires: meson
|
||||||
# for sys/sdt.h
|
# for sys/sdt.h
|
||||||
BuildRequires: systemtap-sdt-devel
|
BuildRequires: systemtap-sdt-devel
|
||||||
%if 0%{?rhel}
|
|
||||||
# For gnutls-hmac.patch
|
|
||||||
BuildRequires: pkgconfig(gnutls)
|
|
||||||
%endif
|
|
||||||
BuildRequires: pkgconfig(libelf)
|
BuildRequires: pkgconfig(libelf)
|
||||||
BuildRequires: pkgconfig(libffi)
|
BuildRequires: pkgconfig(libffi)
|
||||||
BuildRequires: pkgconfig(libpcre)
|
BuildRequires: pkgconfig(libpcre)
|
||||||
@ -46,6 +41,15 @@ BuildRequires: pkgconfig(sysprof-capture-4)
|
|||||||
BuildRequires: pkgconfig(zlib)
|
BuildRequires: pkgconfig(zlib)
|
||||||
BuildRequires: python3-devel
|
BuildRequires: python3-devel
|
||||||
|
|
||||||
|
# For gnutls-hmac.patch. We now dlopen libgnutls.so.30 so that we can build a
|
||||||
|
# static glib2 without depending on a static build of GnuTLS as well. This will
|
||||||
|
# ensure we notice if the GnuTLS soname bumps, so that we can update our patch.
|
||||||
|
%if 0%{__isa_bits} == 64
|
||||||
|
Requires: libgnutls.so.30()(64bit)
|
||||||
|
%else
|
||||||
|
Requires: libgnutls.so.30()
|
||||||
|
%endif
|
||||||
|
|
||||||
# for GIO content-type support
|
# for GIO content-type support
|
||||||
Recommends: shared-mime-info
|
Recommends: shared-mime-info
|
||||||
|
|
||||||
@ -82,14 +86,12 @@ BuildArch: noarch
|
|||||||
%description doc
|
%description doc
|
||||||
The glib2-doc package includes documentation for the GLib library.
|
The glib2-doc package includes documentation for the GLib library.
|
||||||
|
|
||||||
%if !0%{?rhel}
|
|
||||||
%package static
|
%package static
|
||||||
Summary: glib static
|
Summary: glib static
|
||||||
Requires: %{name}-devel = %{version}-%{release}
|
Requires: %{name}-devel = %{version}-%{release}
|
||||||
|
|
||||||
%description static
|
%description static
|
||||||
The %{name}-static subpackage contains static libraries for %{name}.
|
The %{name}-static subpackage contains static libraries for %{name}.
|
||||||
%endif
|
|
||||||
|
|
||||||
%package tests
|
%package tests
|
||||||
Summary: Tests for the glib2 package
|
Summary: Tests for the glib2 package
|
||||||
@ -107,9 +109,6 @@ the functionality of the installed glib2 package.
|
|||||||
rm -rf glib/pcre
|
rm -rf glib/pcre
|
||||||
rm -rf subprojects
|
rm -rf subprojects
|
||||||
|
|
||||||
# We cannot build with GnuTLS in Fedora since there is no gnutls-static
|
|
||||||
# subpackage. (glib2-static is needed by qemu in Fedora, but not in RHEL.)
|
|
||||||
# Accordingly, we can't build a usable glib2-static in RHEL.
|
|
||||||
%meson \
|
%meson \
|
||||||
-Dman=true \
|
-Dman=true \
|
||||||
-Ddtrace=true \
|
-Ddtrace=true \
|
||||||
@ -118,12 +117,8 @@ rm -rf subprojects
|
|||||||
-Dglib_debug=disabled \
|
-Dglib_debug=disabled \
|
||||||
-Dgtk_doc=true \
|
-Dgtk_doc=true \
|
||||||
-Dinstalled_tests=true \
|
-Dinstalled_tests=true \
|
||||||
%if 0%{?rhel}
|
|
||||||
-Dgnutls=true \
|
-Dgnutls=true \
|
||||||
%endif
|
|
||||||
%if !0%{?rhel}
|
|
||||||
--default-library=both \
|
--default-library=both \
|
||||||
%endif
|
|
||||||
%{nil}
|
%{nil}
|
||||||
|
|
||||||
%meson_build
|
%meson_build
|
||||||
@ -233,20 +228,23 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
|
|||||||
%files doc
|
%files doc
|
||||||
%{_datadir}/gtk-doc/
|
%{_datadir}/gtk-doc/
|
||||||
|
|
||||||
%if !0%{?rhel}
|
|
||||||
%files static
|
%files static
|
||||||
%{_libdir}/libgio-2.0.a
|
%{_libdir}/libgio-2.0.a
|
||||||
%{_libdir}/libglib-2.0.a
|
%{_libdir}/libglib-2.0.a
|
||||||
%{_libdir}/libgmodule-2.0.a
|
%{_libdir}/libgmodule-2.0.a
|
||||||
%{_libdir}/libgobject-2.0.a
|
%{_libdir}/libgobject-2.0.a
|
||||||
%{_libdir}/libgthread-2.0.a
|
%{_libdir}/libgthread-2.0.a
|
||||||
%endif
|
|
||||||
|
|
||||||
%files tests
|
%files tests
|
||||||
%{_libexecdir}/installed-tests
|
%{_libexecdir}/installed-tests
|
||||||
%{_datadir}/installed-tests
|
%{_datadir}/installed-tests
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Thu Jun 17 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.2-2
|
||||||
|
- Enable GnuTLS-based GHmac in Fedora and reenable glib2-static in RHEL
|
||||||
|
- Consolidate GDesktopAppInfo changes into gdesktopappinfo.patch
|
||||||
|
- Disable check-rpath since it seems to be broken
|
||||||
|
|
||||||
* Tue May 11 2021 Kalev Lember <klember@redhat.com> - 2.68.2-1
|
* Tue May 11 2021 Kalev Lember <klember@redhat.com> - 2.68.2-1
|
||||||
- Update to 2.68.2
|
- Update to 2.68.2
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
From 12e9cd51eb0ef07c3554cd035f92d8b7b5b82304 Mon Sep 17 00:00:00 2001
|
From 86412ea2265ae018ba6146d525cafce78782c0fc Mon Sep 17 00:00:00 2001
|
||||||
From: Colin Walters <walters@verbum.org>
|
From: Colin Walters <walters@verbum.org>
|
||||||
Date: Fri, 7 Jun 2019 18:44:43 +0000
|
Date: Fri, 7 Jun 2019 18:44:43 +0000
|
||||||
Subject: [PATCH 1/2] ghmac: Split off wrapper functions into ghmac-utils.c
|
Subject: [PATCH 1/4] ghmac: Split off wrapper functions into ghmac-utils.c
|
||||||
|
|
||||||
Prep for adding a GnuTLS HMAC implementation; these are just
|
Prep for adding a GnuTLS HMAC implementation; these are just
|
||||||
utility functions that call the "core" API.
|
utility functions that call the "core" API.
|
||||||
@ -284,10 +284,10 @@ index 49fd272f0..4f181f21f 100644
|
|||||||
- (const guchar *) str, length);
|
- (const guchar *) str, length);
|
||||||
-}
|
-}
|
||||||
diff --git a/glib/meson.build b/glib/meson.build
|
diff --git a/glib/meson.build b/glib/meson.build
|
||||||
index 8c18e6de4..329b8d197 100644
|
index 28bfae200..0a37d19ea 100644
|
||||||
--- a/glib/meson.build
|
--- a/glib/meson.build
|
||||||
+++ b/glib/meson.build
|
+++ b/glib/meson.build
|
||||||
@@ -253,6 +253,7 @@ glib_sources = files(
|
@@ -254,6 +254,7 @@ glib_sources = files(
|
||||||
'ggettext.c',
|
'ggettext.c',
|
||||||
'ghash.c',
|
'ghash.c',
|
||||||
'ghmac.c',
|
'ghmac.c',
|
||||||
@ -296,13 +296,12 @@ index 8c18e6de4..329b8d197 100644
|
|||||||
'ghostutils.c',
|
'ghostutils.c',
|
||||||
'giochannel.c',
|
'giochannel.c',
|
||||||
--
|
--
|
||||||
2.29.2
|
2.31.1
|
||||||
|
|
||||||
|
From a5ee9970772e182de1c249ee514e87ef38e08360 Mon Sep 17 00:00:00 2001
|
||||||
From 231ed985074af4a354405cf1961fabf9c60bce43 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Colin Walters <walters@verbum.org>
|
From: Colin Walters <walters@verbum.org>
|
||||||
Date: Fri, 7 Jun 2019 19:36:54 +0000
|
Date: Fri, 7 Jun 2019 19:36:54 +0000
|
||||||
Subject: [PATCH 2/2] Add a gnutls backend for GHmac
|
Subject: [PATCH 2/4] Add a gnutls backend for GHmac
|
||||||
|
|
||||||
For RHEL we want apps to use FIPS-certified crypto libraries,
|
For RHEL we want apps to use FIPS-certified crypto libraries,
|
||||||
and HMAC apparently counts as "keyed" and hence needs to
|
and HMAC apparently counts as "keyed" and hence needs to
|
||||||
@ -316,18 +315,47 @@ Most distributors ship glib-networking built with GnuTLS, and
|
|||||||
most apps use glib-networking, so this isn't a net-new library
|
most apps use glib-networking, so this isn't a net-new library
|
||||||
in most cases.
|
in most cases.
|
||||||
|
|
||||||
mcatanzaro note: I've updated Colin's original patch to implement
|
=======================================================================
|
||||||
g_hmac_copy() using gnutls_hmac_copy(), which didn't exist when Colin
|
|
||||||
developed this patch.
|
mcatanzaro note:
|
||||||
|
|
||||||
|
I've updated Colin's original patch with several enhancements:
|
||||||
|
|
||||||
|
Implement g_hmac_copy() using gnutls_hmac_copy(), which didn't exist
|
||||||
|
when Colin developed this patch.
|
||||||
|
|
||||||
|
Removed use of GSlice
|
||||||
|
|
||||||
|
Better error checking in g_hmac_new(). It is possible for
|
||||||
|
gnutls_hmac_init() to fail if running in FIPS mode and an MD5 digest is
|
||||||
|
requested. In this case, we should return NULL rather than returning a
|
||||||
|
broken GHmac with a NULL gnutls_hmac_hd_t. This was leading to a later
|
||||||
|
null pointer dereference inside gnutls_hmac_update(). Applications are
|
||||||
|
responsible for checking to ensure the return value of g_hmac_new() is
|
||||||
|
not NULL since it is annotated as nullable. Added documentation to
|
||||||
|
indicate this possibility.
|
||||||
|
|
||||||
|
Properly handle length -1 in g_hmac_update(). This means we've been
|
||||||
|
given a NUL-terminated string and should use strlen(). GnuTLS doesn't
|
||||||
|
accept -1, so let's call strlen() ourselves.
|
||||||
|
|
||||||
|
Crash the application with g_error() if gnutls_hmac() fails for any
|
||||||
|
reason. This is necessary because g_hmac_update() is not fallible, so we
|
||||||
|
have no way to indicate error. Crashing seems better than returning the
|
||||||
|
wrong result later when g_hmac_get_string() or g_hmac_get_digest() is
|
||||||
|
later called. (Those functions are also not fallible.) Fortunately, I
|
||||||
|
don't think this error should actually be hit in practice.
|
||||||
|
|
||||||
|
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/903
|
||||||
---
|
---
|
||||||
glib/gchecksum.c | 9 ++-
|
glib/gchecksum.c | 9 +-
|
||||||
glib/gchecksumprivate.h | 32 ++++++++
|
glib/gchecksumprivate.h | 32 +++++++
|
||||||
glib/ghmac-gnutls.c | 164 ++++++++++++++++++++++++++++++++++++++++
|
glib/ghmac-gnutls.c | 187 ++++++++++++++++++++++++++++++++++++++++
|
||||||
glib/ghmac.c | 3 +
|
glib/ghmac.c | 15 ++++
|
||||||
glib/meson.build | 10 ++-
|
glib/meson.build | 10 ++-
|
||||||
meson.build | 7 ++
|
meson.build | 7 ++
|
||||||
meson_options.txt | 5 ++
|
meson_options.txt | 5 ++
|
||||||
7 files changed, 224 insertions(+), 6 deletions(-)
|
7 files changed, 259 insertions(+), 6 deletions(-)
|
||||||
create mode 100644 glib/gchecksumprivate.h
|
create mode 100644 glib/gchecksumprivate.h
|
||||||
create mode 100644 glib/ghmac-gnutls.c
|
create mode 100644 glib/ghmac-gnutls.c
|
||||||
|
|
||||||
@ -406,10 +434,10 @@ index 000000000..86c7a3b61
|
|||||||
\ No newline at end of file
|
\ No newline at end of file
|
||||||
diff --git a/glib/ghmac-gnutls.c b/glib/ghmac-gnutls.c
|
diff --git a/glib/ghmac-gnutls.c b/glib/ghmac-gnutls.c
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 000000000..f1a74a849
|
index 000000000..a55375060
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/glib/ghmac-gnutls.c
|
+++ b/glib/ghmac-gnutls.c
|
||||||
@@ -0,0 +1,164 @@
|
@@ -0,0 +1,187 @@
|
||||||
+/* ghmac.h - data hashing functions
|
+/* ghmac.h - data hashing functions
|
||||||
+ *
|
+ *
|
||||||
+ * Copyright (C) 2011 Collabora Ltd.
|
+ * Copyright (C) 2011 Collabora Ltd.
|
||||||
@ -464,7 +492,9 @@ index 000000000..f1a74a849
|
|||||||
+ gsize key_len)
|
+ gsize key_len)
|
||||||
+{
|
+{
|
||||||
+ gnutls_mac_algorithm_t algo;
|
+ gnutls_mac_algorithm_t algo;
|
||||||
+ GHmac *hmac = g_slice_new0 (GHmac);
|
+ GHmac *hmac = g_new0 (GHmac, 1);
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
+ hmac->ref_count = 1;
|
+ hmac->ref_count = 1;
|
||||||
+ hmac->digest_type = digest_type;
|
+ hmac->digest_type = digest_type;
|
||||||
+
|
+
|
||||||
@ -489,7 +519,16 @@ index 000000000..f1a74a849
|
|||||||
+ g_return_val_if_reached (NULL);
|
+ g_return_val_if_reached (NULL);
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ gnutls_hmac_init (&hmac->hmac, algo, key, key_len);
|
+ ret = gnutls_hmac_init (&hmac->hmac, algo, key, key_len);
|
||||||
|
+ if (ret != 0)
|
||||||
|
+ {
|
||||||
|
+ /* There is no way to report an error here, but one possible cause of
|
||||||
|
+ * failure is that the requested digest may be disabled by Fedora or RHEL
|
||||||
|
+ * system crypto policy. As of 2021, MD5 and SHA-1 are likely disabled.
|
||||||
|
+ */
|
||||||
|
+ g_free (hmac->hmac);
|
||||||
|
+ return NULL;
|
||||||
|
+ }
|
||||||
+
|
+
|
||||||
+ return hmac;
|
+ return hmac;
|
||||||
+}
|
+}
|
||||||
@ -501,11 +540,15 @@ index 000000000..f1a74a849
|
|||||||
+
|
+
|
||||||
+ g_return_val_if_fail (hmac != NULL, NULL);
|
+ g_return_val_if_fail (hmac != NULL, NULL);
|
||||||
+
|
+
|
||||||
+ copy = g_slice_new0 (GHmac);
|
+ copy = g_new0 (GHmac, 1);
|
||||||
+ copy->ref_count = 1;
|
+ copy->ref_count = 1;
|
||||||
+ copy->digest_type = hmac->digest_type;
|
+ copy->digest_type = hmac->digest_type;
|
||||||
+ copy->hmac = gnutls_hmac_copy (hmac->hmac);
|
+ copy->hmac = gnutls_hmac_copy (hmac->hmac);
|
||||||
+
|
+
|
||||||
|
+ /* g_hmac_copy is not allowed to fail, so we'll have to crash on error. */
|
||||||
|
+ if (!copy->hmac)
|
||||||
|
+ g_error ("gnutls_hmac_copy failed");
|
||||||
|
+
|
||||||
+ return copy;
|
+ return copy;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
@ -528,7 +571,7 @@ index 000000000..f1a74a849
|
|||||||
+ {
|
+ {
|
||||||
+ gnutls_hmac_deinit (hmac->hmac, NULL);
|
+ gnutls_hmac_deinit (hmac->hmac, NULL);
|
||||||
+ g_free (hmac->digest_str);
|
+ g_free (hmac->digest_str);
|
||||||
+ g_slice_free (GHmac, hmac);
|
+ g_free (hmac);
|
||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
@ -538,10 +581,18 @@ index 000000000..f1a74a849
|
|||||||
+ const guchar *data,
|
+ const guchar *data,
|
||||||
+ gssize length)
|
+ gssize length)
|
||||||
+{
|
+{
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
+ g_return_if_fail (hmac != NULL);
|
+ g_return_if_fail (hmac != NULL);
|
||||||
+ g_return_if_fail (length == 0 || data != NULL);
|
+ g_return_if_fail (length == 0 || data != NULL);
|
||||||
+
|
+
|
||||||
+ gnutls_hmac (hmac->hmac, data, length);
|
+ if (length == -1)
|
||||||
|
+ length = strlen ((const char *)data);
|
||||||
|
+
|
||||||
|
+ /* g_hmac_update is not allowed to fail, so we'll have to crash on error. */
|
||||||
|
+ ret = gnutls_hmac (hmac->hmac, data, length);
|
||||||
|
+ if (ret != 0)
|
||||||
|
+ g_error ("gnutls_hmac failed: %s", gnutls_strerror (ret));
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+const gchar *
|
+const gchar *
|
||||||
@ -575,7 +626,7 @@ index 000000000..f1a74a849
|
|||||||
+ *digest_len = g_checksum_type_get_length (hmac->digest_type);
|
+ *digest_len = g_checksum_type_get_length (hmac->digest_type);
|
||||||
+}
|
+}
|
||||||
diff --git a/glib/ghmac.c b/glib/ghmac.c
|
diff --git a/glib/ghmac.c b/glib/ghmac.c
|
||||||
index 4f181f21f..c62d9ce4e 100644
|
index 4f181f21f..0e39ea40a 100644
|
||||||
--- a/glib/ghmac.c
|
--- a/glib/ghmac.c
|
||||||
+++ b/glib/ghmac.c
|
+++ b/glib/ghmac.c
|
||||||
@@ -33,6 +33,9 @@
|
@@ -33,6 +33,9 @@
|
||||||
@ -588,11 +639,30 @@ index 4f181f21f..c62d9ce4e 100644
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION:hmac
|
* SECTION:hmac
|
||||||
|
@@ -84,6 +87,18 @@ struct _GHmac
|
||||||
|
* Support for digests of type %G_CHECKSUM_SHA512 has been added in GLib 2.42.
|
||||||
|
* Support for %G_CHECKSUM_SHA384 was added in GLib 2.52.
|
||||||
|
*
|
||||||
|
+ * Note that #GHmac creation may fail, in which case this function will
|
||||||
|
+ * return %NULL. Since there is no error parameter, it is not possible
|
||||||
|
+ * to indicate why.
|
||||||
|
+ *
|
||||||
|
+ * In Fedora, CentOS Stream, and Red Hat Enterprise Linux, GLib is
|
||||||
|
+ * configured to use GnuTLS to implement #GHmac in order to support FIPS
|
||||||
|
+ * compliance. This introduces additional failure possibilities that are
|
||||||
|
+ * not present in upstream GLib. For example, the creation of a #GHmac
|
||||||
|
+ * will fail if @digest_type is %G_CHECKSUM_MD5 and the system is
|
||||||
|
+ * running in FIPS mode. #GHmac creation may also fail if GLib is unable
|
||||||
|
+ * to load GnuTLS.
|
||||||
|
+ *
|
||||||
|
* Returns: the newly created #GHmac, or %NULL.
|
||||||
|
* Use g_hmac_unref() to free the memory allocated by it.
|
||||||
|
*
|
||||||
diff --git a/glib/meson.build b/glib/meson.build
|
diff --git a/glib/meson.build b/glib/meson.build
|
||||||
index 329b8d197..2942a7e9b 100644
|
index 0a37d19ea..b17c89dd9 100644
|
||||||
--- a/glib/meson.build
|
--- a/glib/meson.build
|
||||||
+++ b/glib/meson.build
|
+++ b/glib/meson.build
|
||||||
@@ -252,7 +252,6 @@ glib_sources = files(
|
@@ -253,7 +253,6 @@ glib_sources = files(
|
||||||
'gfileutils.c',
|
'gfileutils.c',
|
||||||
'ggettext.c',
|
'ggettext.c',
|
||||||
'ghash.c',
|
'ghash.c',
|
||||||
@ -600,7 +670,7 @@ index 329b8d197..2942a7e9b 100644
|
|||||||
'ghmac-utils.c',
|
'ghmac-utils.c',
|
||||||
'ghook.c',
|
'ghook.c',
|
||||||
'ghostutils.c',
|
'ghostutils.c',
|
||||||
@@ -308,6 +307,7 @@ glib_sources = files(
|
@@ -309,6 +308,7 @@ glib_sources = files(
|
||||||
'guriprivate.h',
|
'guriprivate.h',
|
||||||
'gutils.c',
|
'gutils.c',
|
||||||
'gutilsprivate.h',
|
'gutilsprivate.h',
|
||||||
@ -608,7 +678,7 @@ index 329b8d197..2942a7e9b 100644
|
|||||||
'guuid.c',
|
'guuid.c',
|
||||||
'gvariant.c',
|
'gvariant.c',
|
||||||
'gvariant-core.c',
|
'gvariant-core.c',
|
||||||
@@ -352,6 +352,12 @@ else
|
@@ -353,6 +353,12 @@ else
|
||||||
glib_dtrace_hdr = []
|
glib_dtrace_hdr = []
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -621,7 +691,7 @@ index 329b8d197..2942a7e9b 100644
|
|||||||
pcre_static_args = []
|
pcre_static_args = []
|
||||||
|
|
||||||
if use_pcre_static_flag
|
if use_pcre_static_flag
|
||||||
@@ -378,7 +384,7 @@ libglib = library('glib-2.0',
|
@@ -379,7 +385,7 @@ libglib = library('glib-2.0',
|
||||||
# intl.lib is not compatible with SAFESEH
|
# intl.lib is not compatible with SAFESEH
|
||||||
link_args : [noseh_link_args, glib_link_flags, win32_ldflags],
|
link_args : [noseh_link_args, glib_link_flags, win32_ldflags],
|
||||||
include_directories : configinc,
|
include_directories : configinc,
|
||||||
@ -631,10 +701,10 @@ index 329b8d197..2942a7e9b 100644
|
|||||||
objc_args : glib_c_args,
|
objc_args : glib_c_args,
|
||||||
)
|
)
|
||||||
diff --git a/meson.build b/meson.build
|
diff --git a/meson.build b/meson.build
|
||||||
index 0d892fb2d..091029fea 100644
|
index a0ee8b774..064dba800 100644
|
||||||
--- a/meson.build
|
--- a/meson.build
|
||||||
+++ b/meson.build
|
+++ b/meson.build
|
||||||
@@ -2078,6 +2078,13 @@ if host_system == 'linux'
|
@@ -2104,6 +2104,13 @@ if host_system == 'linux'
|
||||||
glib_conf.set('HAVE_LIBMOUNT', libmount_dep.found())
|
glib_conf.set('HAVE_LIBMOUNT', libmount_dep.found())
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -665,5 +735,351 @@ index 072765361..d2370042f 100644
|
|||||||
type : 'boolean',
|
type : 'boolean',
|
||||||
value : false,
|
value : false,
|
||||||
--
|
--
|
||||||
2.29.2
|
2.31.1
|
||||||
|
|
||||||
|
From cde56a63aa12ae7c30f85af7d058fa5e666aa2e9 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Michael Catanzaro <mcatanzaro@redhat.com>
|
||||||
|
Date: Wed, 16 Jun 2021 20:35:00 -0500
|
||||||
|
Subject: [PATCH 3/4] dlopen GnuTLS instead of linking directly
|
||||||
|
|
||||||
|
I'd like to enable our GnuTLS GHmac patchset in Fedora in order to
|
||||||
|
ensure it is receiving sufficient real-world testing, since we've
|
||||||
|
discovered several bugs thus far. Problem is Fedora has one requirement
|
||||||
|
that RHEL does not: it needs to build glib as a static lib. This is
|
||||||
|
needed by QEMU in Fedora for complicated technical reasons that I don't
|
||||||
|
understand. However, nothing in RHEL needs it. This means we failed to
|
||||||
|
notice that glib2-static is broken in RHEL, because there is no
|
||||||
|
gnutls-static! We could fix this by adding a gnutls-static package, but
|
||||||
|
that seems like overkill, and adding more static libraries where they're
|
||||||
|
not truly necessary is not the direction we want to move in anyway. So
|
||||||
|
instead, let's just dlopen GnuTLS to sidestep this problem entirely.
|
||||||
|
|
||||||
|
This would not be a good solution for upstream, but upstream has made
|
||||||
|
clear that this patchset is already non-upstreamable, so it will be fine
|
||||||
|
for our purposes.
|
||||||
|
---
|
||||||
|
glib/ghmac-gnutls.c | 101 ++++++++++++++++++++++++++++++++++++++++++--
|
||||||
|
glib/ghmac.c | 2 +-
|
||||||
|
glib/meson.build | 2 +-
|
||||||
|
meson.build | 6 +--
|
||||||
|
4 files changed, 102 insertions(+), 9 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/glib/ghmac-gnutls.c b/glib/ghmac-gnutls.c
|
||||||
|
index a55375060..0469d2bd0 100644
|
||||||
|
--- a/glib/ghmac-gnutls.c
|
||||||
|
+++ b/glib/ghmac-gnutls.c
|
||||||
|
@@ -19,8 +19,8 @@
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
+#include <dlfcn.h>
|
||||||
|
#include <string.h>
|
||||||
|
-#include <gnutls/crypto.h>
|
||||||
|
|
||||||
|
#include "ghmac.h"
|
||||||
|
|
||||||
|
@@ -31,13 +31,16 @@
|
||||||
|
#include "gstrfuncs.h"
|
||||||
|
#include "gchecksumprivate.h"
|
||||||
|
#include "gtestutils.h"
|
||||||
|
+#include "gthread.h"
|
||||||
|
#include "gtypes.h"
|
||||||
|
#include "glibintl.h"
|
||||||
|
|
||||||
|
-#ifndef HAVE_GNUTLS
|
||||||
|
+#ifndef USE_GNUTLS
|
||||||
|
#error "build configuration error"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+typedef gpointer gnutls_hmac_hd_t;
|
||||||
|
+
|
||||||
|
struct _GHmac
|
||||||
|
{
|
||||||
|
int ref_count;
|
||||||
|
@@ -46,15 +49,107 @@ struct _GHmac
|
||||||
|
gchar *digest_str;
|
||||||
|
};
|
||||||
|
|
||||||
|
+typedef enum
|
||||||
|
+{
|
||||||
|
+ GNUTLS_MAC_MD5 = 2,
|
||||||
|
+ GNUTLS_MAC_SHA1 = 3,
|
||||||
|
+ GNUTLS_MAC_SHA256 = 6,
|
||||||
|
+ GNUTLS_MAC_SHA384 = 7,
|
||||||
|
+ GNUTLS_MAC_SHA512 = 8,
|
||||||
|
+} gnutls_mac_algorithm_t;
|
||||||
|
+
|
||||||
|
+/* Why are we dlopening GnuTLS instead of linking to it directly? Because we
|
||||||
|
+ * want to be able to build GLib as a static library without depending on a
|
||||||
|
+ * static build of GnuTLS. QEMU depends on static linking with GLib, but Fedora
|
||||||
|
+ * does not ship a static build of GnuTLS, and this allows us to avoid changing
|
||||||
|
+ * that.
|
||||||
|
+ */
|
||||||
|
+static int (*gnutls_hmac_init) (gnutls_hmac_hd_t *dig, gnutls_mac_algorithm_t algorithm, const void *key, size_t keylen);
|
||||||
|
+static gnutls_hmac_hd_t (*gnutls_hmac_copy) (gnutls_hmac_hd_t handle);
|
||||||
|
+static void (*gnutls_hmac_deinit) (gnutls_hmac_hd_t handle, void *digest);
|
||||||
|
+static int (*gnutls_hmac) (gnutls_hmac_hd_t handle, const void *ptext, size_t ptext_len);
|
||||||
|
+static void (*gnutls_hmac_output) (gnutls_hmac_hd_t handle, void *digest);
|
||||||
|
+static const char * (*gnutls_strerror) (int error);
|
||||||
|
+
|
||||||
|
+static gsize gnutls_initialize_attempted = 0;
|
||||||
|
+static gboolean gnutls_initialize_successful = FALSE;
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+initialize_gnutls (void)
|
||||||
|
+{
|
||||||
|
+ gpointer libgnutls;
|
||||||
|
+
|
||||||
|
+ libgnutls = dlopen ("libgnutls.so.30", RTLD_LAZY | RTLD_GLOBAL);
|
||||||
|
+ if (!libgnutls)
|
||||||
|
+ {
|
||||||
|
+ g_warning ("Cannot use GHmac: failed to load libgnutls.so.30: %s", dlerror ());
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ gnutls_hmac_init = dlsym (libgnutls, "gnutls_hmac_init");
|
||||||
|
+ if (!gnutls_hmac_init)
|
||||||
|
+ {
|
||||||
|
+ g_warning ("Cannot use GHmac: failed to load gnutls_hmac_init: %s", dlerror ());
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ gnutls_hmac_copy = dlsym (libgnutls, "gnutls_hmac_copy");
|
||||||
|
+ if (!gnutls_hmac_copy)
|
||||||
|
+ {
|
||||||
|
+ g_warning ("Cannot use GHmac: failed to load gnutls_hmac_copy: %s", dlerror ());
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ gnutls_hmac_deinit = dlsym (libgnutls, "gnutls_hmac_deinit");
|
||||||
|
+ if (!gnutls_hmac_deinit)
|
||||||
|
+ {
|
||||||
|
+ g_warning ("Cannot use GHmac: failed to load gnutls_hmac_deinit: %s", dlerror ());
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ gnutls_hmac = dlsym (libgnutls, "gnutls_hmac");
|
||||||
|
+ if (!gnutls_hmac)
|
||||||
|
+ {
|
||||||
|
+ g_warning ("Cannot use GHmac: failed to load gnutls_hmac: %s", dlerror ());
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ gnutls_hmac_output = dlsym (libgnutls, "gnutls_hmac_output");
|
||||||
|
+ if (!gnutls_hmac_output)
|
||||||
|
+ {
|
||||||
|
+ g_warning ("Cannot use GHmac: failed to load gnutls_hmac_output: %s", dlerror ());
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ gnutls_strerror = dlsym (libgnutls, "gnutls_strerror");
|
||||||
|
+ if (!gnutls_strerror)
|
||||||
|
+ {
|
||||||
|
+ g_warning ("Cannot use GHmac: failed to load gnutls_strerror: %s", dlerror ());
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ gnutls_initialize_successful = TRUE;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
GHmac *
|
||||||
|
g_hmac_new (GChecksumType digest_type,
|
||||||
|
const guchar *key,
|
||||||
|
gsize key_len)
|
||||||
|
{
|
||||||
|
gnutls_mac_algorithm_t algo;
|
||||||
|
- GHmac *hmac = g_new0 (GHmac, 1);
|
||||||
|
+ GHmac *hmac;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
+ if (g_once_init_enter (&gnutls_initialize_attempted))
|
||||||
|
+ {
|
||||||
|
+ initialize_gnutls ();
|
||||||
|
+ g_once_init_leave (&gnutls_initialize_attempted, 1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!gnutls_initialize_successful)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ hmac = g_new0 (GHmac, 1);
|
||||||
|
hmac->ref_count = 1;
|
||||||
|
hmac->digest_type = digest_type;
|
||||||
|
|
||||||
|
diff --git a/glib/ghmac.c b/glib/ghmac.c
|
||||||
|
index 0e39ea40a..2d9be91b8 100644
|
||||||
|
--- a/glib/ghmac.c
|
||||||
|
+++ b/glib/ghmac.c
|
||||||
|
@@ -33,7 +33,7 @@
|
||||||
|
#include "gtypes.h"
|
||||||
|
#include "glibintl.h"
|
||||||
|
|
||||||
|
-#ifdef HAVE_GNUTLS
|
||||||
|
+#ifdef USE_GNUTLS
|
||||||
|
#error "build configuration error"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
diff --git a/glib/meson.build b/glib/meson.build
|
||||||
|
index b17c89dd9..a015f7755 100644
|
||||||
|
--- a/glib/meson.build
|
||||||
|
+++ b/glib/meson.build
|
||||||
|
@@ -385,7 +385,7 @@ libglib = library('glib-2.0',
|
||||||
|
# intl.lib is not compatible with SAFESEH
|
||||||
|
link_args : [noseh_link_args, glib_link_flags, win32_ldflags],
|
||||||
|
include_directories : configinc,
|
||||||
|
- dependencies : pcre_deps + libgnutls_dep + [thread_dep, librt] + libintl_deps + libiconv + platform_deps + [gnulib_libm_dependency, libm] + [libsysprof_capture_dep],
|
||||||
|
+ dependencies : pcre_deps + [thread_dep, librt] + libintl_deps + libiconv + platform_deps + [gnulib_libm_dependency, libm] + [libsysprof_capture_dep] + [libdl_dep],
|
||||||
|
c_args : glib_c_args,
|
||||||
|
objc_args : glib_c_args,
|
||||||
|
)
|
||||||
|
diff --git a/meson.build b/meson.build
|
||||||
|
index 064dba800..7aae7dfea 100644
|
||||||
|
--- a/meson.build
|
||||||
|
+++ b/meson.build
|
||||||
|
@@ -2104,11 +2104,9 @@ if host_system == 'linux'
|
||||||
|
glib_conf.set('HAVE_LIBMOUNT', libmount_dep.found())
|
||||||
|
endif
|
||||||
|
|
||||||
|
-# gnutls is used optionally by ghmac
|
||||||
|
-libgnutls_dep = []
|
||||||
|
+# gnutls is used optionally by GHmac
|
||||||
|
if get_option('gnutls')
|
||||||
|
- libgnutls_dep = [dependency('gnutls', version : '>=3.6.9', required : true)]
|
||||||
|
- glib_conf.set('HAVE_GNUTLS', 1)
|
||||||
|
+ glib_conf.set('USE_GNUTLS', 1)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if host_system == 'windows'
|
||||||
|
--
|
||||||
|
2.31.1
|
||||||
|
|
||||||
|
From b61ea19037287cae2e6152e9616767a691bf4af0 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Michael Catanzaro <mcatanzaro@redhat.com>
|
||||||
|
Date: Wed, 16 Jun 2021 20:46:24 -0500
|
||||||
|
Subject: [PATCH 4/4] Add test for GHmac in FIPS mode
|
||||||
|
|
||||||
|
This will test a few problems that we hit recently:
|
||||||
|
|
||||||
|
g_hmac_copy() is broken, https://bugzilla.redhat.com/show_bug.cgi?id=1786538
|
||||||
|
|
||||||
|
Crash in g_hmac_update() in FIPS mode, https://bugzilla.redhat.com/show_bug.cgi?id=1971533
|
||||||
|
|
||||||
|
Crash when passing -1 length to g_hmac_update() (discovered in #1971533)
|
||||||
|
|
||||||
|
We'll also test to ensure MD5 fails, and stop compiling the other MD5
|
||||||
|
tests.
|
||||||
|
---
|
||||||
|
glib/tests/hmac.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
1 file changed, 45 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/glib/tests/hmac.c b/glib/tests/hmac.c
|
||||||
|
index 3ac3206df..6698c4d19 100644
|
||||||
|
--- a/glib/tests/hmac.c
|
||||||
|
+++ b/glib/tests/hmac.c
|
||||||
|
@@ -1,7 +1,10 @@
|
||||||
|
+#include "config.h"
|
||||||
|
+
|
||||||
|
#include <glib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
+#ifndef USE_GNUTLS
|
||||||
|
/* HMAC-MD5 test vectors as per RFC 2202 */
|
||||||
|
|
||||||
|
/* Test 1 */
|
||||||
|
@@ -81,6 +84,7 @@ guint8 key_md5_test7[] = {
|
||||||
|
guint8 result_md5_test7[] = {
|
||||||
|
0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd, 0xa0, 0xee, 0x1f, 0xb1,
|
||||||
|
0xf5, 0x62, 0xdb, 0x3a, 0xa5, 0x3e };
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
/* HMAC-SHA1, HMAC-SHA256, HMAC-SHA384 and HMAC-SHA512 test vectors
|
||||||
|
* as per RFCs 2202 and 4868.
|
||||||
|
@@ -299,6 +303,7 @@ typedef struct {
|
||||||
|
gconstpointer result;
|
||||||
|
} HmacCase;
|
||||||
|
|
||||||
|
+#ifndef USE_GNUTLS
|
||||||
|
HmacCase hmac_md5_tests[] = {
|
||||||
|
{ G_CHECKSUM_MD5, key_md5_test1, 16, "Hi There", 8, result_md5_test1 },
|
||||||
|
{ G_CHECKSUM_MD5, "Jefe", 4, "what do ya want for nothing?", 28,
|
||||||
|
@@ -317,6 +322,7 @@ HmacCase hmac_md5_tests[] = {
|
||||||
|
73, result_md5_test7 },
|
||||||
|
{ -1, NULL, 0, NULL, 0, NULL },
|
||||||
|
};
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
HmacCase hmac_sha1_tests[] = {
|
||||||
|
{ G_CHECKSUM_SHA1, key_sha_test1, 20, "Hi There", 8, result_sha1_test1 },
|
||||||
|
@@ -493,11 +499,44 @@ test_hmac_for_bytes (void)
|
||||||
|
g_bytes_unref (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
+#ifdef USE_GNUTLS
|
||||||
|
+static void
|
||||||
|
+test_gnutls_fips_mode (void)
|
||||||
|
+{
|
||||||
|
+ GHmac *hmac;
|
||||||
|
+ GHmac *copy;
|
||||||
|
+
|
||||||
|
+ /* No MD5 in FIPS mode. */
|
||||||
|
+ hmac = g_hmac_new (G_CHECKSUM_MD5, "abc123", sizeof ("abc123"));
|
||||||
|
+ g_assert_null (hmac);
|
||||||
|
+
|
||||||
|
+ /* SHA-256 should be good. */
|
||||||
|
+ hmac = g_hmac_new (G_CHECKSUM_SHA256, "abc123", sizeof ("abc123"));
|
||||||
|
+ g_assert_nonnull (hmac);
|
||||||
|
+
|
||||||
|
+ /* Ensure g_hmac_update() does not crash when called with -1. */
|
||||||
|
+ g_hmac_update (hmac, "You win again, gravity!", -1);
|
||||||
|
+
|
||||||
|
+ /* Ensure g_hmac_copy() does not crash. */
|
||||||
|
+ copy = g_hmac_copy (hmac);
|
||||||
|
+ g_assert_nonnull (hmac);
|
||||||
|
+ g_hmac_unref (hmac);
|
||||||
|
+
|
||||||
|
+ g_assert_cmpstr (g_hmac_get_string (copy), ==, "795ba6900bcb22e8ce65c2ec02db4e85697da921deb960ee3143bf88a4a60f83");
|
||||||
|
+ g_hmac_unref (copy);
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
int
|
||||||
|
main (int argc,
|
||||||
|
char **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
+
|
||||||
|
+#ifdef USE_GNUTLS
|
||||||
|
+ g_setenv ("GNUTLS_FORCE_FIPS_MODE", "1", FALSE);
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
g_test_init (&argc, &argv, NULL);
|
||||||
|
|
||||||
|
for (i = 0 ; hmac_sha1_tests[i].key_len > 0 ; i++)
|
||||||
|
@@ -532,6 +571,7 @@ main (int argc,
|
||||||
|
g_free (name);
|
||||||
|
}
|
||||||
|
|
||||||
|
+#ifndef USE_GNUTLS
|
||||||
|
for (i = 0 ; hmac_md5_tests[i].key_len > 0 ; i++)
|
||||||
|
{
|
||||||
|
gchar *name = g_strdup_printf ("/hmac/md5-%d", i + 1);
|
||||||
|
@@ -539,6 +579,7 @@ main (int argc,
|
||||||
|
(void (*)(const void *)) test_hmac);
|
||||||
|
g_free (name);
|
||||||
|
}
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
g_test_add_func ("/hmac/ref-unref", test_hmac_ref_unref);
|
||||||
|
g_test_add_func ("/hmac/copy", test_hmac_copy);
|
||||||
|
@@ -546,5 +587,9 @@ main (int argc,
|
||||||
|
g_test_add_func ("/hmac/for-string", test_hmac_for_string);
|
||||||
|
g_test_add_func ("/hmac/for-bytes", test_hmac_for_bytes);
|
||||||
|
|
||||||
|
+#ifdef USE_GNUTLS
|
||||||
|
+ g_test_add_func ("/hmac/gnutls-fips-mode", test_gnutls_fips_mode);
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
return g_test_run ();
|
||||||
|
}
|
||||||
|
--
|
||||||
|
2.31.1
|
||||||
|
Loading…
Reference in New Issue
Block a user