PolicyKit: Branch 'master'
David Zeuthen
david at kemper.freedesktop.org
Mon Aug 9 08:28:32 PDT 2010
docs/polkit/polkit-1-sections.txt | 4
src/polkit/polkitauthority.c | 316 +++++++++++++++++++++++++++++++++-----
src/polkit/polkitauthority.h | 10 +
src/polkit/polkitpermission.c | 5
4 files changed, 292 insertions(+), 43 deletions(-)
New commits:
commit 322513b0d4ee1f0c291495712a7f637132bde149
Author: David Zeuthen <davidz at redhat.com>
Date: Mon Aug 9 11:27:08 2010 -0400
PolkitAuthority: Implement failable initialization
... and deprecate polkit_authority_get(). Also fix up locking in
PolkitAuthority.
Signed-off-by: David Zeuthen <davidz at redhat.com>
diff --git a/docs/polkit/polkit-1-sections.txt b/docs/polkit/polkit-1-sections.txt
index 1a0b869..c8cb971 100644
--- a/docs/polkit/polkit-1-sections.txt
+++ b/docs/polkit/polkit-1-sections.txt
@@ -21,7 +21,9 @@ POLKIT_UNIX_USER_GET_CLASS
PolkitAuthority
PolkitAuthorityFeatures
PolkitCheckAuthorizationFlags
-polkit_authority_get
+polkit_authority_get_sync
+polkit_authority_get_async
+polkit_authority_get_finish
polkit_authority_get_owner
polkit_authority_get_backend_name
polkit_authority_get_backend_version
diff --git a/src/polkit/polkitauthority.c b/src/polkit/polkitauthority.c
index f16b29c..14a1c1a 100644
--- a/src/polkit/polkitauthority.c
+++ b/src/polkit/polkitauthority.c
@@ -64,6 +64,9 @@ struct _PolkitAuthority
GDBusProxy *proxy;
guint cancellation_id_counter;
+
+ gboolean initialized;
+ GError *initialization_error;
};
struct _PolkitAuthorityClass
@@ -72,8 +75,7 @@ struct _PolkitAuthorityClass
};
-/* TODO: fix up locking */
-
+G_LOCK_DEFINE_STATIC (the_lock);
static PolkitAuthority *the_authority = NULL;
enum
@@ -93,7 +95,12 @@ enum
static guint signals[LAST_SIGNAL] = {0};
-G_DEFINE_TYPE (PolkitAuthority, polkit_authority, G_TYPE_OBJECT);
+static void initable_iface_init (GInitableIface *initable_iface);
+static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface);
+
+G_DEFINE_TYPE_WITH_CODE (PolkitAuthority, polkit_authority, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
+ G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init))
static void
on_proxy_signal (GDBusProxy *proxy,
@@ -121,31 +128,20 @@ on_notify_g_name_owner (GObject *object,
static void
polkit_authority_init (PolkitAuthority *authority)
{
- GError *error;
+}
- /* TODO: do this instead in GInitable and GAsyncInitable implementations */
- error = NULL;
- authority->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
- G_DBUS_PROXY_FLAGS_NONE,
- NULL, /* GDBusInterfaceInfo* */
- "org.freedesktop.PolicyKit1", /* name */
- "/org/freedesktop/PolicyKit1/Authority", /* path */
- "org.freedesktop.PolicyKit1.Authority", /* interface */
- NULL, /* GCancellable */
- &error);
- if (authority->proxy == NULL)
- {
- g_warning ("Error initializing authority: %s", error->message);
- g_error_free (error);
- }
- g_signal_connect (authority->proxy,
- "g-signal",
- G_CALLBACK (on_proxy_signal),
- authority);
- g_signal_connect (authority->proxy,
- "notify::g-name-owner",
- G_CALLBACK (on_notify_g_name_owner),
- authority);
+static void
+polkit_authority_dispose (GObject *object)
+{
+ PolkitAuthority *authority = POLKIT_AUTHORITY (object);
+
+ G_LOCK (the_lock);
+ if (authority == the_authority)
+ the_authority = NULL;
+ G_UNLOCK (the_lock);
+
+ if (G_OBJECT_CLASS (polkit_authority_parent_class)->dispose != NULL)
+ G_OBJECT_CLASS (polkit_authority_parent_class)->dispose (object);
}
static void
@@ -153,7 +149,8 @@ polkit_authority_finalize (GObject *object)
{
PolkitAuthority *authority = POLKIT_AUTHORITY (object);
- the_authority = NULL;
+ if (authority->initialization_error != NULL)
+ g_error_free (authority->initialization_error);
g_free (authority->name);
g_free (authority->version);
@@ -201,6 +198,7 @@ polkit_authority_class_init (PolkitAuthorityClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->dispose = polkit_authority_dispose;
gobject_class->finalize = polkit_authority_finalize;
gobject_class->get_property = polkit_authority_get_property;
@@ -288,36 +286,274 @@ polkit_authority_class_init (PolkitAuthorityClass *klass)
0);
}
-/**
- * polkit_authority_get:
- *
- * Gets a reference to the authority.
- *
- * Returns: A #PolkitAuthority. Free it with g_object_unref() when done with it.
- **/
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+polkit_authority_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ PolkitAuthority *authority = POLKIT_AUTHORITY (initable);
+ gboolean ret;
+
+ /* This method needs to be idempotent to work with the singleton
+ * pattern. See the docs for g_initable_init(). We implement this by
+ * locking.
+ */
+
+ ret = FALSE;
+
+ G_LOCK (the_lock);
+ if (authority->initialized)
+ {
+ if (authority->initialization_error == NULL)
+ ret = TRUE;
+ goto out;
+ }
+
+ authority->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL, /* TODO: pass GDBusInterfaceInfo* */
+ "org.freedesktop.PolicyKit1", /* name */
+ "/org/freedesktop/PolicyKit1/Authority", /* path */
+ "org.freedesktop.PolicyKit1.Authority", /* interface */
+ cancellable,
+ &authority->initialization_error);
+ if (authority->proxy == NULL)
+ {
+ g_prefix_error (&authority->initialization_error, "Error initializing authority: ");
+ goto out;
+ }
+ g_signal_connect (authority->proxy,
+ "g-signal",
+ G_CALLBACK (on_proxy_signal),
+ authority);
+ g_signal_connect (authority->proxy,
+ "notify::g-name-owner",
+ G_CALLBACK (on_notify_g_name_owner),
+ authority);
+
+ ret = TRUE;
+
+ out:
+ authority->initialized = TRUE;
+
+ if (!ret)
+ {
+ g_assert (authority->initialization_error != NULL);
+ g_propagate_error (error, g_error_copy (authority->initialization_error));
+ }
+ G_UNLOCK (the_lock);
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+initable_iface_init (GInitableIface *initable_iface)
+{
+ initable_iface->init = polkit_authority_initable_init;
+}
+
+static void
+async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
+{
+ /* for now, we use default implementation to run GInitable code in a
+ * thread - would probably be nice to have real async version to
+ * avoid the thread-overhead
+ */
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
PolkitAuthority *
polkit_authority_get (void)
{
- static volatile GQuark error_quark = 0;
+ GError *error;
+ PolkitAuthority *ret;
- if (error_quark == 0)
+ error = NULL;
+ ret = polkit_authority_get_sync (NULL, /* GCancellable* */
+ &error);
+ if (ret == NULL)
{
- error_quark = POLKIT_ERROR;
+ g_warning ("polkit_authority_get: Error getting authority: %s",
+ error->message);
+ g_error_free (error);
}
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static PolkitAuthority *
+get_uninitialized_authority (GCancellable *cancellable,
+ GError **error)
+{
+ static volatile GQuark error_quark = 0;
+
+ G_LOCK (the_lock);
+ if (error_quark == 0)
+ error_quark = POLKIT_ERROR;
if (the_authority != NULL)
{
g_object_ref (the_authority);
goto out;
}
-
the_authority = POLKIT_AUTHORITY (g_object_new (POLKIT_TYPE_AUTHORITY, NULL));
+ G_UNLOCK (the_lock);
out:
return the_authority;
}
+static void
+authority_get_async_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+ GError *error;
+
+ error = NULL;
+ if (!g_async_initable_init_finish (G_ASYNC_INITABLE (source_object),
+ res,
+ &error))
+ {
+ g_assert (error != NULL);
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ g_object_unref (source_object);
+ }
+ else
+ {
+ g_simple_async_result_set_op_res_gpointer (simple,
+ source_object,
+ g_object_unref);
+ }
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+}
+
+/**
+ * polkit_authority_get_async:
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
+ * @user_data: The data to pass to @callback.
+ *
+ * Asynchronously gets a reference to the authority.
+ *
+ * This is an asynchronous failable function. When the result is
+ * ready, @callback will be invoked and you can use
+ * polkit_authority_get_finish() to get the result. See
+ * polkit_authority_get_sync() for the synchronous version.
+ */
+void
+polkit_authority_get_async (GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ PolkitAuthority *authority;
+ GSimpleAsyncResult *simple;
+ GError *error;
+
+ simple = g_simple_async_result_new (NULL,
+ callback,
+ user_data,
+ polkit_authority_get_async);
+
+ error = NULL;
+ authority = get_uninitialized_authority (cancellable, &error);
+ if (authority == NULL)
+ {
+ g_assert (error != NULL);
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ }
+ else
+ {
+ g_async_initable_init_async (G_ASYNC_INITABLE (authority),
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ authority_get_async_cb,
+ simple);
+ }
+}
+
+/**
+ * polkit_authority_get_finish:
+ * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to polkit_authority_get_async().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes an operation started with polkit_authority_get_async().
+ *
+ * Returns: A #PolkitAuthority. Free it with g_object_unref() when
+ * done with it.
+ */
+PolkitAuthority *
+polkit_authority_get_finish (GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ GObject *object;
+ PolkitAuthority *ret;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == polkit_authority_get_async);
+
+ ret = NULL;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ goto out;
+
+ object = g_simple_async_result_get_op_res_gpointer (simple);
+ g_assert (object != NULL);
+ ret = g_object_ref (POLKIT_AUTHORITY (object));
+
+ out:
+ return ret;
+}
+
+/**
+ * polkit_authority_get_sync:
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Synchronously gets a reference to the authority.
+ *
+ * This is a synchronous failable function. See
+ * polkit_authority_get_async() for the synchronous version.
+ *
+ * Returns: A #PolkitAuthority. Free it with g_object_unref() when
+ * done with it.
+ */
+PolkitAuthority *
+polkit_authority_get_sync (GCancellable *cancellable,
+ GError **error)
+{
+ PolkitAuthority *authority;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ authority = get_uninitialized_authority (cancellable, error);
+ if (authority == NULL)
+ goto out;
+
+ if (!g_initable_init (G_INITABLE (authority), cancellable, error))
+ {
+ g_object_unref (authority);
+ authority = NULL;
+ }
+
+ out:
+ return authority;
+}
+
/* ---------------------------------------------------------------------------------------------------- */
typedef struct
@@ -616,8 +852,10 @@ polkit_authority_check_authorization (PolkitAuthority *authority,
callback,
user_data,
polkit_authority_check_authorization);
+ G_LOCK (the_lock);
if (cancellable != NULL)
data->cancellation_id = g_strdup_printf ("cancellation-id-%d", authority->cancellation_id_counter++);
+ G_UNLOCK (the_lock);
g_dbus_proxy_call (authority->proxy,
"CheckAuthorization",
diff --git a/src/polkit/polkitauthority.h b/src/polkit/polkitauthority.h
index 0556b34..f363228 100644
--- a/src/polkit/polkitauthority.h
+++ b/src/polkit/polkitauthority.h
@@ -47,7 +47,15 @@ typedef struct _PolkitAuthorityClass PolkitAuthorityClass;
GType polkit_authority_get_type (void) G_GNUC_CONST;
-PolkitAuthority *polkit_authority_get (void);
+PolkitAuthority *polkit_authority_get (void) G_GNUC_DEPRECATED_FOR (polkit_authority_get_sync);
+
+void polkit_authority_get_async (GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+PolkitAuthority *polkit_authority_get_finish (GAsyncResult *res,
+ GError **error);
+PolkitAuthority *polkit_authority_get_sync (GCancellable *cancellable,
+ GError **error);
gchar *polkit_authority_get_owner (PolkitAuthority *authority);
const gchar *polkit_authority_get_backend_name (PolkitAuthority *authority);
diff --git a/src/polkit/polkitpermission.c b/src/polkit/polkitpermission.c
index 857a584..7c54df5 100644
--- a/src/polkit/polkitpermission.c
+++ b/src/polkit/polkitpermission.c
@@ -408,8 +408,9 @@ polkit_permission_initable_init (GInitable *initable,
ret = FALSE;
- /* TODO: use sync failable getter instead */
- permission->authority = polkit_authority_get ();
+ permission->authority = polkit_authority_get_sync (cancellable, error);
+ if (permission->authority == NULL)
+ goto out;
g_signal_connect (permission->authority,
"changed",
More information about the hal-commit
mailing list