diff options
author | David Zeuthen <davidz@redhat.com> | 2010-07-30 12:19:55 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2010-07-30 12:19:55 -0400 |
commit | 4a9e4f72db4ec00500d9334f7411a086d7c81d0f (patch) | |
tree | 566f3f3d3f56f90538e48e97fb8bf039db523b37 | |
parent | 2d0ef52d64707666fd8b6a85be50fa6e3e65ec9e (diff) | |
download | polkit-4a9e4f72db4ec00500d9334f7411a086d7c81d0f.tar.gz |
Make polkitd accept --replace and gracefully handle SIGINT
E.g. actually clean up everything before exiting. This makes it much
easier to chase memory leaks.
Signed-off-by: David Zeuthen <davidz@redhat.com>
-rw-r--r-- | docs/polkit/polkit-1-sections.txt | 3 | ||||
-rw-r--r-- | src/polkit/polkitauthorizationresult.c | 2 | ||||
-rw-r--r-- | src/polkitbackend/polkitbackendauthority.c | 112 | ||||
-rw-r--r-- | src/polkitbackend/polkitbackendauthority.h | 6 | ||||
-rw-r--r-- | src/polkitd/Makefile.am | 3 | ||||
-rw-r--r-- | src/polkitd/gposixsignal.c | 128 | ||||
-rw-r--r-- | src/polkitd/gposixsignal.h | 42 | ||||
-rw-r--r-- | src/polkitd/main.c | 135 |
8 files changed, 329 insertions, 102 deletions
diff --git a/docs/polkit/polkit-1-sections.txt b/docs/polkit/polkit-1-sections.txt index 6b03fa2..999abb2 100644 --- a/docs/polkit/polkit-1-sections.txt +++ b/docs/polkit/polkit-1-sections.txt @@ -293,7 +293,8 @@ polkit_backend_authority_add_lockdown_for_action_finish polkit_backend_authority_remove_lockdown_for_action polkit_backend_authority_remove_lockdown_for_action_finish polkit_backend_authority_get -polkit_backend_register_authority +polkit_backend_authority_register +polkit_backend_authority_unregister <SUBSECTION Standard> POLKIT_BACKEND_AUTHORITY POLKIT_BACKEND_IS_AUTHORITY diff --git a/src/polkit/polkitauthorizationresult.c b/src/polkit/polkitauthorizationresult.c index 85b039f..5bc1065 100644 --- a/src/polkit/polkitauthorizationresult.c +++ b/src/polkit/polkitauthorizationresult.c @@ -109,7 +109,7 @@ polkit_authorization_result_new (gboolean is_authorized, authorization_result = POLKIT_AUTHORIZATION_RESULT (g_object_new (POLKIT_TYPE_AUTHORIZATION_RESULT, NULL)); authorization_result->is_authorized = is_authorized; authorization_result->is_challenge = is_challenge; - authorization_result->details = g_object_ref (details); + authorization_result->details = details != NULL ? g_object_ref (details) : NULL; return authorization_result; } diff --git a/src/polkitbackend/polkitbackendauthority.c b/src/polkitbackend/polkitbackendauthority.c index 4373315..33c800f 100644 --- a/src/polkitbackend/polkitbackendauthority.c +++ b/src/polkitbackend/polkitbackendauthority.c @@ -657,11 +657,10 @@ typedef struct PolkitBackendAuthority *authority; - GDBusConnection *system_bus; + GDBusConnection *connection; gulong authority_changed_id; - gchar *well_known_name; gchar *object_path; GHashTable *cancellation_id_to_check_auth_data; @@ -670,21 +669,18 @@ typedef struct static void server_free (Server *server) { - g_free (server->well_known_name); g_free (server->object_path); - /* TODO: release well_known_name if not NULL */ - //g_signal_handler_disconnect (server->bus, server->name_owner_changed_id); if (server->authority_registration_id > 0) - g_dbus_connection_unregister_object (server->system_bus, server->authority_registration_id); + g_dbus_connection_unregister_object (server->connection, server->authority_registration_id); if (server->name_owner_changed_signal_id > 0) - g_dbus_connection_signal_unsubscribe (server->system_bus, server->name_owner_changed_signal_id); + g_dbus_connection_signal_unsubscribe (server->connection, server->name_owner_changed_signal_id); - if (server->system_bus != NULL) - g_object_unref (server->system_bus); + if (server->connection != NULL) + g_object_unref (server->connection); if (server->introspection_info != NULL) g_dbus_node_info_unref (server->introspection_info); @@ -695,6 +691,8 @@ server_free (Server *server) if (server->cancellation_id_to_check_auth_data != NULL) g_hash_table_unref (server->cancellation_id_to_check_auth_data); + g_object_unref (server->authority); + g_free (server); } @@ -706,7 +704,7 @@ on_authority_changed (PolkitBackendAuthority *authority, GError *error; error = NULL; - if (!g_dbus_connection_emit_signal (server->system_bus, + if (!g_dbus_connection_emit_signal (server->connection, NULL, /* destination bus name */ server->object_path, "org.freedesktop.PolicyKit1.Authority", @@ -719,14 +717,6 @@ on_authority_changed (PolkitBackendAuthority *authority, } } -static void -authority_died (gpointer user_data, - GObject *where_the_object_was) -{ - Server *server = user_data; - server_free (server); -} - static const gchar *server_introspection_data = "<node>" " <interface name='org.freedesktop.PolicyKit1.Authority'>" @@ -1455,19 +1445,32 @@ static const GDBusInterfaceVTable server_vtable = }; /** - * polkit_backend_register_authority: + * polkit_backend_authority_unregister: + * @registration_id: A #gpointer obtained from polkit_backend_authority_register(). + * + * Unregisters a #PolkitBackendAuthority registered with polkit_backend_authority_register(). + */ +void +polkit_backend_authority_unregister (gpointer registration_id) +{ + Server *server = registration_id; + server_free (server); +} + +/** + * polkit_backend_authority_register: + * @connection: The #GDBusConnection to register the authority on. * @authority: A #PolkitBackendAuthority. - * @well_known_name: Well-known name to claim on the system bus or %NULL to not claim a well-known name. * @object_path: Object path of the authority. * @error: Return location for error. * - * Registers @authority on the system message bus. + * Registers @authority on a #GDBusConnection. * - * Returns: %TRUE if @authority was registered, %FALSE if @error is set. - **/ -gboolean -polkit_backend_register_authority (PolkitBackendAuthority *authority, - const gchar *well_known_name, + * Returns: A #gpointer that can be used with polkit_backend_authority_unregister() or %NULL if @error is set. + */ +gpointer +polkit_backend_authority_register (PolkitBackendAuthority *authority, + GDBusConnection *connection, const gchar *object_path, GError **error) { @@ -1477,18 +1480,14 @@ polkit_backend_register_authority (PolkitBackendAuthority *authority, server->cancellation_id_to_check_auth_data = g_hash_table_new (g_str_hash, g_str_equal); - server->system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); - if (server->system_bus == NULL) - goto error; - - server->well_known_name = g_strdup (well_known_name); + server->connection = g_object_ref (connection); server->object_path = g_strdup (object_path); server->introspection_info = g_dbus_node_info_new_for_xml (server_introspection_data, error); if (server->introspection_info == NULL) goto error; - server->authority_registration_id = g_dbus_connection_register_object (server->system_bus, + server->authority_registration_id = g_dbus_connection_register_object (server->connection, object_path, g_dbus_node_info_lookup_interface (server->introspection_info, "org.freedesktop.PolicyKit1.Authority"), &server_vtable, @@ -1500,46 +1499,8 @@ polkit_backend_register_authority (PolkitBackendAuthority *authority, goto error; } - if (well_known_name != NULL) - { - GVariant *result; - guint32 request_name_result; - - /* TODO: use g_bus_own_name() instead */ - result = g_dbus_connection_call_sync (server->system_bus, - "org.freedesktop.DBus", /* name */ - "/org/freedesktop/DBus", /* path */ - "org.freedesktop.DBus", /* interface */ - "RequestName", - g_variant_new ("(su)", well_known_name, 0), - G_VARIANT_TYPE ("(u)"), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, /* GCancellable */ - error); - if (result == NULL) - { - g_prefix_error (error, - "Could not become primary name owner for `%s'. RequestName() failed with: ", - well_known_name); - goto error; - } - g_variant_get (result, "(u)", &request_name_result); - g_variant_unref (result); - if (request_name_result != 1) - { - g_set_error (error, - POLKIT_ERROR, - POLKIT_ERROR_FAILED, - "Could not become primary name owner for `%s'. RequestName returned %d", - well_known_name, - request_name_result); - goto error; - } - } - server->name_owner_changed_signal_id = - g_dbus_connection_signal_subscribe (server->system_bus, + g_dbus_connection_signal_subscribe (server->connection, "org.freedesktop.DBus", /* sender */ "org.freedesktop.DBus", /* interface */ "NameOwnerChanged", /* member */ @@ -1550,21 +1511,18 @@ polkit_backend_register_authority (PolkitBackendAuthority *authority, server, NULL); /* GDestroyNotify */ - server->authority = authority; + server->authority = g_object_ref (authority); server->authority_changed_id = g_signal_connect (server->authority, "changed", G_CALLBACK (on_authority_changed), server); - /* take a weak ref and kill server when listener dies */ - g_object_weak_ref (G_OBJECT (server->authority), authority_died, server); - - return TRUE; + return server; error: server_free (server); - return FALSE; + return NULL; } diff --git a/src/polkitbackend/polkitbackendauthority.h b/src/polkitbackend/polkitbackendauthority.h index 7ce5fde..626c4a5 100644 --- a/src/polkitbackend/polkitbackendauthority.h +++ b/src/polkitbackend/polkitbackendauthority.h @@ -329,11 +329,13 @@ gboolean polkit_backend_authority_remove_lockdown_for_action_finish (PolkitBacke PolkitBackendAuthority *polkit_backend_authority_get (void); -gboolean polkit_backend_register_authority (PolkitBackendAuthority *authority, - const gchar *well_known_name, +gpointer polkit_backend_authority_register (PolkitBackendAuthority *authority, + GDBusConnection *connection, const gchar *object_path, GError **error); +void polkit_backend_authority_unregister (gpointer registration_id); + G_END_DECLS #endif /* __POLKIT_BACKEND_AUTHORITY_H */ diff --git a/src/polkitd/Makefile.am b/src/polkitd/Makefile.am index 1234417..5ea3e95 100644 --- a/src/polkitd/Makefile.am +++ b/src/polkitd/Makefile.am @@ -17,7 +17,8 @@ INCLUDES = \ libexec_PROGRAMS = polkitd polkitd_SOURCES = \ - main.c \ + main.c \ + gposixsignal.h gposixsignal.c \ $(NULL) polkitd_CFLAGS = \ diff --git a/src/polkitd/gposixsignal.c b/src/polkitd/gposixsignal.c new file mode 100644 index 0000000..8e9bb65 --- /dev/null +++ b/src/polkitd/gposixsignal.c @@ -0,0 +1,128 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen <davidz@redhat.com> + */ + +#include "config.h" + +#include <unistd.h> +#include <sys/signalfd.h> +#include <signal.h> + +#include "gposixsignal.h" + +typedef struct +{ + GSource source; + GPollFD pollfd; + gint signum; +} _GPosixSignalSource; + +static gboolean +_g_posix_signal_source_prepare (GSource *_source, + gint *timeout) +{ + *timeout = -1; + return FALSE; +} + +static gboolean +_g_posix_signal_source_check (GSource *_source) +{ + _GPosixSignalSource *source = (_GPosixSignalSource *) _source; + return source->pollfd.revents != 0; +} + +static gboolean +_g_posix_signal_source_dispatch (GSource *_source, + GSourceFunc callback, + gpointer user_data) + +{ + _GPosixSignalWatchFunc func = (_GPosixSignalWatchFunc) callback; + g_warn_if_fail (func != NULL); + return (*func) (user_data); +} + +static void +_g_posix_signal_source_finalize (GSource *_source) +{ + _GPosixSignalSource *source = (_GPosixSignalSource *) _source; + close (source->pollfd.fd); +} + +static GSourceFuncs _g_posix_signal_source_funcs = +{ + _g_posix_signal_source_prepare, + _g_posix_signal_source_check, + _g_posix_signal_source_dispatch, + _g_posix_signal_source_finalize +}; + +GSource * +_g_posix_signal_source_new (gint signum) +{ + sigset_t sigset; + gint fd; + GSource *_source; + _GPosixSignalSource *source; + + _source = NULL; + + sigemptyset (&sigset); + sigaddset (&sigset, signum); + + if (sigprocmask (SIG_BLOCK, &sigset, NULL) == -1) + g_assert_not_reached (); + + fd = signalfd (-1, &sigset, SFD_NONBLOCK | SFD_CLOEXEC); + + _source = g_source_new (&_g_posix_signal_source_funcs, sizeof (_GPosixSignalSource)); + source = (_GPosixSignalSource *) _source; + + source->pollfd.fd = fd; + source->pollfd.events = G_IO_IN; + g_source_add_poll (_source, &source->pollfd); + + source->signum = signum; + return _source; +} + +guint +_g_posix_signal_watch_add (gint signum, + gint priority, + _GPosixSignalWatchFunc function, + gpointer user_data, + GDestroyNotify notify) +{ + GSource *source; + guint id; + + g_return_val_if_fail (function != NULL, 0); + + source = _g_posix_signal_source_new (signum); + if (priority != G_PRIORITY_DEFAULT_IDLE) + g_source_set_priority (source, priority); + g_source_set_callback (source, (GSourceFunc) function, user_data, notify); + id = g_source_attach (source, NULL); + g_source_unref (source); + + return id; +} diff --git a/src/polkitd/gposixsignal.h b/src/polkitd/gposixsignal.h new file mode 100644 index 0000000..f9b3249 --- /dev/null +++ b/src/polkitd/gposixsignal.h @@ -0,0 +1,42 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen <davidz@redhat.com> + */ + +#ifndef ___G_POSIX_SIGNAL_H__ +#define ___G_POSIX_SIGNAL_H__ + +#include <glib.h> + +G_BEGIN_DECLS + +typedef gboolean (*_GPosixSignalWatchFunc) (gpointer user_data); + +GSource *_g_posix_signal_source_new (gint signum); + +guint _g_posix_signal_watch_add (gint signum, + gint priority, + _GPosixSignalWatchFunc function, + gpointer user_data, + GDestroyNotify notify); + +G_END_DECLS + +#endif /* ___G_POSIX_SIGNAL_H__ */ diff --git a/src/polkitd/main.c b/src/polkitd/main.c index ff39dd9..4b1967a 100644 --- a/src/polkitd/main.c +++ b/src/polkitd/main.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Red Hat, Inc. + * Copyright (C) 2008-2010 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,49 +19,144 @@ * Author: David Zeuthen <davidz@redhat.com> */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif +#include "config.h" +#include <signal.h> #include <polkit/polkit.h> #include <polkitbackend/polkitbackend.h> -int -main (int argc, char **argv) +#include "gposixsignal.h" + +/* ---------------------------------------------------------------------------------------------------- */ + +static PolkitBackendAuthority *authority = NULL; +static gpointer registration_id = NULL; +static GMainLoop *loop = NULL; +static gboolean opt_replace = FALSE; +static GOptionEntry opt_entries[] = { + {"replace", 0, 0, G_OPTION_ARG_NONE, &opt_replace, "Replace existing daemon", NULL}, + {NULL } +}; + +static void +on_bus_acquired (GDBusConnection *connection, + const gchar *name, + gpointer user_data) { - int ret; GError *error; - GMainLoop *loop; - PolkitBackendAuthority *authority; - - ret = 1; - error = NULL; - authority = NULL; - g_type_init (); + g_print ("Connected to the system bus\n"); - loop = g_main_loop_new (NULL, FALSE); + g_assert (authority == NULL); + g_assert (registration_id == NULL); authority = polkit_backend_authority_get (); - g_print ("Using authority class %s\n", g_type_name (G_TYPE_FROM_INSTANCE (authority))); - if (!polkit_backend_register_authority (authority, - "org.freedesktop.PolicyKit1", - "/org/freedesktop/PolicyKit1/Authority", - &error)) + error = NULL; + registration_id = polkit_backend_authority_register (authority, + connection, + "/org/freedesktop/PolicyKit1/Authority", + &error); + if (registration_id == NULL) { g_printerr ("Error registering authority: %s\n", error->message); g_error_free (error); + g_main_loop_quit (loop); /* exit */ + } +} + +static void +on_name_lost (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + g_print ("Lost the name org.freedesktop.PolicyKit1 - exiting\n"); + g_main_loop_quit (loop); +} + +static void +on_name_acquired (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + g_print ("Acquired the name org.freedesktop.PolicyKit1\n"); +} + +static gboolean +on_sigint (gpointer user_data) +{ + g_print ("Handling SIGINT\n"); + g_main_loop_quit (loop); + return FALSE; +} +int +main (int argc, + char **argv) +{ + GError *error; + GOptionContext *opt_context; + gint ret; + guint name_owner_id; + guint sigint_id; + + ret = 1; + loop = NULL; + opt_context = NULL; + name_owner_id = 0; + sigint_id = 0; + registration_id = NULL; + + g_type_init (); + + opt_context = g_option_context_new ("polkit authority"); + g_option_context_add_main_entries (opt_context, opt_entries, NULL); + error = NULL; + if (!g_option_context_parse (opt_context, &argc, &argv, &error)) + { + g_printerr ("Error parsing options: %s", error->message); + g_error_free (error); goto out; } + loop = g_main_loop_new (NULL, FALSE); + + sigint_id = _g_posix_signal_watch_add (SIGINT, + G_PRIORITY_DEFAULT, + on_sigint, + NULL, + NULL); + + name_owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM, + "org.freedesktop.PolicyKit1", + G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | + (opt_replace ? G_BUS_NAME_OWNER_FLAGS_REPLACE : 0), + on_bus_acquired, + on_name_acquired, + on_name_lost, + NULL, + NULL); + + g_print ("Entering main event loop\n"); g_main_loop_run (loop); ret = 0; + g_print ("Shutting down\n"); out: + if (sigint_id > 0) + g_source_remove (sigint_id); + if (name_owner_id != 0) + g_bus_unown_name (name_owner_id); + if (registration_id != NULL) + polkit_backend_authority_unregister (registration_id); if (authority != NULL) g_object_unref (authority); + if (loop != NULL) + g_main_loop_unref (loop); + if (opt_context != NULL) + g_option_context_free (opt_context); + + g_print ("Exiting with code %d\n", ret); return ret; } |