[gnome-software/wip/ubuntu-3-22] apt: Support debconf



commit fb4e6a91585b53eec9db304c41a7fb965f7813b8
Author: Robert Ancell <robert ancell canonical com>
Date:   Thu Apr 20 16:46:36 2017 +1200

    apt: Support debconf

 src/plugins/gs-plugin-apt.cc |  223 +++++++++++++++++++++++++++++++++++-------
 1 files changed, 187 insertions(+), 36 deletions(-)
---
diff --git a/src/plugins/gs-plugin-apt.cc b/src/plugins/gs-plugin-apt.cc
index d03b005..a573c5d 100644
--- a/src/plugins/gs-plugin-apt.cc
+++ b/src/plugins/gs-plugin-apt.cc
@@ -24,6 +24,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#include <gio/gunixsocketaddress.h>
+#include <glib-unix.h>
 
 #include <apt-pkg/init.h>
 #include <apt-pkg/cachefile.h>
@@ -725,14 +727,62 @@ gs_plugin_add_installed (GsPlugin *plugin,
 
 typedef struct {
        GsPlugin *plugin;
+       GCancellable *cancellable;
        GsApp *app;
        GList *apps;
-       gchar **result;
-       GMutex mutex;
-       GCond cond;
-       gboolean finished;
+       gchar *result;
+       GMainContext *context;
+       GMainLoop *loop;
+       GSocket *debconf_connection;
+       GSource *debconf_read_source;
+       GSource *debconf_client_read_source;
+       GPid debconf_pid;
+       gint stdin_pipe;
+       gint stdout_pipe;
+       gint stderr_pipe;
 } TransactionData;
 
+static TransactionData *
+transaction_data_new (GsPlugin *plugin, GCancellable *cancellable)
+{
+       TransactionData *data;
+
+       data = g_slice_new0 (TransactionData);
+       data->plugin = (GsPlugin *) g_object_ref (plugin);
+       data->cancellable = (GCancellable *) g_object_ref (cancellable);
+       data->context = g_main_context_new ();
+       data->loop = g_main_loop_new (data->context, FALSE);
+       data->stdin_pipe = -1;
+       data->stdout_pipe = -1;
+       data->stderr_pipe = -1;
+
+       return data;
+}
+
+static void
+transaction_data_free (TransactionData *data)
+{
+       g_clear_object (&data->plugin);
+       g_clear_object (&data->cancellable);
+       g_free (data->result);
+       g_clear_pointer (&data->context, g_main_context_unref);
+       g_clear_pointer (&data->loop, g_main_loop_unref);
+       g_clear_object (&data->debconf_connection);
+       g_clear_pointer (&data->debconf_read_source, g_source_unref);
+       g_clear_pointer (&data->debconf_client_read_source, g_source_unref);
+       if (data->stdin_pipe > 0)
+               close (data->stdin_pipe);
+       if (data->stdout_pipe > 0)
+               close (data->stdout_pipe);
+       if (data->stderr_pipe > 0)
+               close (data->stderr_pipe);
+       if (data->debconf_pid > 0)
+               kill (data->debconf_pid, SIGTERM);
+       g_slice_free (TransactionData, data);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(TransactionData, transaction_data_free)
+
 static void
 transaction_property_changed_cb (GDBusConnection *connection,
                                 const gchar *sender_name,
@@ -775,17 +825,14 @@ transaction_finished_cb (GDBusConnection *connection,
        TransactionData *data = (TransactionData *) user_data;
 
        if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(s)")))
-               g_variant_get (parameters, "(s)", data->result);
+               g_variant_get (parameters, "(s)", &data->result);
        else
                g_warning ("Unknown parameters in %s.%s: %s",
                           interface_name,
                           signal_name,
                           g_variant_get_type_string (parameters));
 
-       g_mutex_lock (&data->mutex);
-       data->finished = TRUE;
-       g_cond_signal (&data->cond);
-       g_mutex_unlock (&data->mutex);
+       g_main_loop_quit (data->loop);
 }
 
 static void
@@ -814,6 +861,95 @@ notify_unity_launcher (GsApp *app, const gchar *transaction_path)
 }
 
 static gboolean
+debconf_read_cb (GSocket *socket, GIOCondition condition, gpointer user_data)
+{
+       TransactionData *data = (TransactionData *) user_data;
+       gchar buffer[1024];
+       gssize n_read;
+       g_autoptr(GError) error = NULL;
+
+       n_read = g_socket_receive (socket, buffer, 1024, data->cancellable, &error);
+       if (n_read == 0)
+               return G_SOURCE_REMOVE;
+       if (n_read < 0) {
+               g_warning ("Error reading from debconf socket: %s\n", g_strerror (errno));
+               return G_SOURCE_CONTINUE;
+       }
+
+       if (write (data->stdin_pipe, buffer, n_read) < 0) {
+               g_warning ("Error writing to debconf client: %s\n", error->message);
+               return G_SOURCE_CONTINUE;
+       }
+
+       return G_SOURCE_CONTINUE;
+}
+
+static gboolean
+debconf_client_read_cb (gint fd, GIOCondition condition, gpointer user_data)
+{
+       TransactionData *data = (TransactionData *) user_data;
+       gchar buffer[1024];
+       gsize n_read;
+       g_autoptr(GError) error = NULL;
+
+       n_read = read (fd, buffer, 1024);
+       if (n_read < 0) {
+               g_warning ("Error reading from debconf client: %s\n", g_strerror (errno));
+               return G_SOURCE_CONTINUE;
+       }
+       if (n_read == 0)
+               return G_SOURCE_REMOVE;
+
+       if (!g_socket_send (data->debconf_connection, buffer, n_read, data->cancellable, &error)) {
+               g_warning ("Error writing to debconf socket: %s\n", error->message);
+               return G_SOURCE_CONTINUE;
+       }
+
+       return G_SOURCE_CONTINUE;
+}
+
+static gboolean
+debconf_accept_cb (GSocket *socket, GIOCondition condition, gpointer user_data)
+{
+       TransactionData *data = (TransactionData *) user_data;
+       g_autoptr(GPtrArray) argv = NULL;
+       g_auto(GStrv) envp = NULL;
+       g_autoptr(GError) error = NULL;
+
+       data->debconf_connection = g_socket_accept (socket, data->cancellable, &error);
+       data->debconf_read_source = g_socket_create_source (data->debconf_connection, G_IO_IN, 
data->cancellable);
+       g_source_set_callback (data->debconf_read_source, (GSourceFunc) debconf_read_cb, data, NULL);
+       g_source_attach (data->debconf_read_source, data->context);
+
+       argv = g_ptr_array_new ();
+       g_ptr_array_add (argv, (gpointer) "debconf-communicate");
+       g_ptr_array_add (argv, NULL);
+       envp = g_get_environ ();
+       envp = g_environ_setenv (envp, "DEBCONF_DB_REPLACE", "configdb", TRUE);
+       envp = g_environ_setenv (envp, "DEBCONF_DB_OVERRIDE", "Pipe{infd:none outfd:none}", TRUE);
+       envp = g_environ_setenv (envp, "DEBIAN_FRONTEND", "gnome", TRUE);
+       if (!g_spawn_async_with_pipes (NULL,
+                                      (gchar **) argv->pdata,
+                                      envp,
+                                      G_SPAWN_SEARCH_PATH,
+                                      NULL, NULL,
+                                      &data->debconf_pid,
+                                      &data->stdin_pipe,
+                                      &data->stdout_pipe,
+                                      &data->stderr_pipe,
+                                      &error)) {
+               g_warning ("Failed to launch debconf-communicate: %s", error->message);
+               g_socket_close (data->debconf_connection, NULL);
+               return G_SOURCE_CONTINUE;
+       }
+       data->debconf_client_read_source = g_unix_fd_source_new (data->stdout_pipe, G_IO_IN);
+       g_source_set_callback (data->debconf_client_read_source, (GSourceFunc) debconf_client_read_cb, data, 
NULL);
+       g_source_attach (data->debconf_client_read_source, data->context);
+
+       return G_SOURCE_REMOVE;
+}
+
+static gboolean
 aptd_transaction (GsPlugin     *plugin,
                  const gchar  *method,
                  GsApp        *app,
@@ -824,18 +960,12 @@ aptd_transaction (GsPlugin     *plugin,
 {
        g_autoptr(GDBusConnection) conn = NULL;
        g_autoptr(GVariant) result = NULL;
-       g_autofree gchar *transaction_path = NULL, *transaction_result = NULL;
+       g_autofree gchar *transaction_path = NULL, *temp_dir = NULL, *debconf_socket_path = NULL;
+       g_autoptr(GSocketAddress) address = NULL;
+       g_autoptr(GSource) accept_source = NULL;
        guint property_signal, finished_signal;
-       guint64 end_time;
-       TransactionData data;
-       g_auto(GMutex) mutex;
-       g_auto(GCond) cond;
-
-       g_mutex_init (&mutex);
-       g_cond_init (&cond);
-       data.mutex = mutex;
-       data.cond = cond;
-       data.finished = FALSE;
+       g_autoptr(GSocket) debconf_socket = NULL;
+       g_autoptr(TransactionData) data = NULL;
 
        conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, cancellable, error);
        if (conn == NULL)
@@ -858,16 +988,41 @@ aptd_transaction (GsPlugin     *plugin,
        if (result == NULL)
                return FALSE;
        g_variant_get (result, "(s)", &transaction_path);
-       g_variant_unref (result);
+       g_clear_pointer (&result, g_variant_unref);
+
+       data = transaction_data_new (plugin, cancellable);
+       data->app = app;
+       data->apps = apps;
+
+       temp_dir = g_dir_make_tmp ("gnome-software-XXXXXX", NULL);
+       debconf_socket_path = g_build_filename (temp_dir, "debconf.socket", NULL);
+       debconf_socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, 
error);
+       address = g_unix_socket_address_new (debconf_socket_path);
+       if (debconf_socket == NULL || !g_socket_bind (debconf_socket, address, FALSE, error))
+               return FALSE;
+       accept_source = g_socket_create_source (debconf_socket, G_IO_IN, cancellable);
+       g_source_set_callback (accept_source, (GSourceFunc) debconf_accept_cb, data, NULL);
+       g_source_attach (accept_source, data->context);
+       if (!g_socket_listen (debconf_socket, error))
+               return FALSE;
+       result = g_dbus_connection_call_sync (conn,
+                                              "org.debian.apt",
+                                              transaction_path,
+                                              "org.freedesktop.DBus.Properties",
+                                              "Set",
+                                              g_variant_new ("(ssv)", "org.debian.apt.transaction", 
"DebconfSocket", g_variant_new_string (debconf_socket_path)),
+                                              G_VARIANT_TYPE ("()"),
+                                              G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             cancellable,
+                                             error);
+       if (result == NULL)
+               return FALSE;
+       g_clear_pointer (&result, g_variant_unref);
 
        if (!g_strcmp0(method, "InstallPackages"))
                notify_unity_launcher (app, transaction_path);
 
-       data.plugin = plugin;
-       data.app = app;
-       data.apps = apps;
-       data.result = &transaction_result;
-
        property_signal = g_dbus_connection_signal_subscribe (conn,
                                                              "org.debian.apt",
                                                              "org.debian.apt.transaction",
@@ -876,7 +1031,7 @@ aptd_transaction (GsPlugin     *plugin,
                                                              NULL,
                                                              G_DBUS_SIGNAL_FLAGS_NONE,
                                                              transaction_property_changed_cb,
-                                                             &data,
+                                                             data,
                                                              NULL);
 
        finished_signal = g_dbus_connection_signal_subscribe (conn,
@@ -887,7 +1042,7 @@ aptd_transaction (GsPlugin     *plugin,
                                                              NULL,
                                                              G_DBUS_SIGNAL_FLAGS_NONE,
                                                              transaction_finished_cb,
-                                                             &data,
+                                                             data,
                                                              NULL);
 
        result = g_dbus_connection_call_sync (conn,
@@ -902,12 +1057,8 @@ aptd_transaction (GsPlugin     *plugin,
                                              cancellable,
                                              error);
 
-       if (result) {
-               g_mutex_lock (&data.mutex);
-               while (!data.finished)
-                       g_cond_wait (&data.cond, &data.mutex);
-               g_mutex_unlock (&data.mutex);
-       }
+       if (result)
+               g_main_loop_run (data->loop);
 
        g_dbus_connection_signal_unsubscribe (conn, property_signal);
        g_dbus_connection_signal_unsubscribe (conn, finished_signal);
@@ -915,11 +1066,11 @@ aptd_transaction (GsPlugin     *plugin,
        if (result == NULL)
                return FALSE;
 
-       if (g_strcmp0 (transaction_result, "exit-success") != 0) {
+       if (g_strcmp0 (data->result, "exit-success") != 0) {
                g_set_error (error,
                             GS_PLUGIN_ERROR,
                             GS_PLUGIN_ERROR_FAILED,
-                            "apt transaction returned result %s", transaction_result);
+                            "apt transaction returned result %s", data->result);
                return FALSE;
        }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]