From b2be103bd606291319dc312f07d1f3fcbfdf634c Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Wed, 10 Oct 2007 13:39:15 -0400 Subject: maintain a file with the dump of the local database This feature is useful for programs wanting to read the database without going through the D-Bus interface. This is sometimes desirable when both performance and runtime dependencies are important. For security reasons the file is only readable for the super user. --- src/Makefile.am | 2 + src/ck-manager.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/ck-seat.c | 86 ++++++++++++++++++++++- src/ck-seat.h | 4 ++ src/ck-session.c | 38 +++++++++++ src/ck-session.h | 3 + 6 files changed, 330 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index ec4e04f..d72ec35 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,6 +17,7 @@ INCLUDES = \ -DLIBEXECDIR=\""$(libexecdir)"\" \ -DDATADIR=\""$(datadir)"\" \ -DSYSCONFDIR=\""$(sysconfdir)"\" \ + -DLOCALSTATEDIR=\""$(localstatedir)"\" \ -DCONSOLE_KIT_PID_FILE=\""$(CONSOLE_KIT_PID_FILE)"\" \ $(WARN_CFLAGS) \ $(DEBUG_CFLAGS) \ @@ -169,3 +170,4 @@ MAINTAINERCLEANFILES = \ install-data-local: -mkdir -p $(DESTDIR)$(sysconfdir)/ConsoleKit/run-session.d -mkdir -p $(DESTDIR)$(libdir)/ConsoleKit/run-session.d + -mkdir -p $(DESTDIR)$(localstatedir)/run/ConsoleKit diff --git a/src/ck-manager.c b/src/ck-manager.c index c957896..74d488c 100644 --- a/src/ck-manager.c +++ b/src/ck-manager.c @@ -28,9 +28,11 @@ #include #include #include +#include #include #include +#include #include #define DBUS_API_SUBJECT_TO_CHANGE #include @@ -104,6 +106,115 @@ static gpointer manager_object = NULL; G_DEFINE_TYPE (CkManager, ck_manager, G_TYPE_OBJECT) +static void +dump_state_seat_iter (char *id, + CkSeat *seat, + GKeyFile *key_file) +{ + ck_seat_dump (seat, key_file); +} + +static void +dump_state_session_iter (char *id, + CkSession *session, + GKeyFile *key_file) +{ + ck_session_dump (session, key_file); +} + +static gboolean +do_dump (CkManager *manager, + int fd) +{ + char *str; + gsize str_len; + GKeyFile *key_file; + GError *error; + gboolean ret; + + str = NULL; + error = NULL; + ret = FALSE; + + key_file = g_key_file_new (); + + g_hash_table_foreach (manager->priv->seats, (GHFunc) dump_state_seat_iter, key_file); + g_hash_table_foreach (manager->priv->sessions, (GHFunc) dump_state_session_iter, key_file); + + str = g_key_file_to_data (key_file, &str_len, &error); + g_key_file_free (key_file); + if (str != NULL) { + ssize_t written; + + written = 0; + while (written < str_len) { + ssize_t ret; + ret = write (fd, str + written, str_len - written); + if (ret < 0) { + if (errno == EAGAIN || errno == EINTR) { + continue; + } else { + g_warning ("Error writing state file: %s", strerror (errno)); + goto out; + } + } + written += ret; + } + } else { + g_warning ("Couldn't construct state file: %s", error->message); + g_error_free (error); + } + + ret = TRUE; + +out: + g_free (str); + return ret; +} + +static void +ck_manager_dump (CkManager *manager) +{ + const char *filename = LOCALSTATEDIR "/run/ConsoleKit/database"; + const char *filename_tmp = LOCALSTATEDIR "/run/ConsoleKit/database~"; + if (manager != NULL) { + int fd; + + fd = g_open (filename_tmp, O_CREAT | O_WRONLY, 0600); + if (fd == -1) { + g_warning ("Cannot create file %s: %s", filename_tmp, g_strerror (errno)); + goto error; + } + + if (! do_dump (manager, fd)) { + g_warning ("Cannot write to file %s", filename_tmp); + close (fd); + goto error; + } + again: + if (close (fd) != 0) { + if (errno == EINTR) + goto again; + else { + g_warning ("Cannot close fd for %s: %s", filename_tmp, g_strerror (errno)); + goto error; + } + } + + if (g_rename (filename_tmp, filename) != 0) { + g_warning ("Cannot rename %s to %s: %s", filename_tmp, filename, g_strerror (errno)); + goto error; + } + } + + return; +error: + /* For security reasons; unlink the existing file since it contains outdated information */ + if (g_unlink (filename) != 0) { + g_warning ("Cannot unlink %s: %s", filename, g_strerror (errno)); + } +} + static void remove_pending_job (CkJob *job) { @@ -277,6 +388,68 @@ generate_seat_id (CkManager *manager) return id; } +static void +on_seat_active_session_changed (CkSeat *seat, + const char *ssid, + CkManager *manager) +{ + ck_manager_dump (manager); +} + +static void +on_seat_session_added (CkSeat *seat, + const char *ssid, + CkManager *manager) +{ + ck_manager_dump (manager); +} + +static void +on_seat_session_removed (CkSeat *seat, + const char *ssid, + CkManager *manager) +{ + ck_manager_dump (manager); +} + +static void +on_seat_device_added (CkSeat *seat, + GValueArray *device, + CkManager *manager) +{ + ck_manager_dump (manager); +} + +static void +on_seat_device_removed (CkSeat *seat, + GValueArray *device, + CkManager *manager) +{ + ck_manager_dump (manager); +} + +static void +connect_seat_signals (CkManager *manager, + CkSeat *seat) +{ + g_signal_connect (seat, "active-session-changed", G_CALLBACK (on_seat_active_session_changed), manager); + g_signal_connect (seat, "session-added", G_CALLBACK (on_seat_session_added), manager); + g_signal_connect (seat, "session-removed", G_CALLBACK (on_seat_session_removed), manager); + g_signal_connect (seat, "device-added", G_CALLBACK (on_seat_device_added), manager); + g_signal_connect (seat, "device-removed", G_CALLBACK (on_seat_device_removed), manager); +} + +static void +disconnect_seat_signals (CkManager *manager, + CkSeat *seat) +{ + g_signal_handlers_disconnect_by_func (seat, on_seat_active_session_changed, manager); + g_signal_handlers_disconnect_by_func (seat, on_seat_session_added, manager); + g_signal_handlers_disconnect_by_func (seat, on_seat_session_removed, manager); + g_signal_handlers_disconnect_by_func (seat, on_seat_device_added, manager); + g_signal_handlers_disconnect_by_func (seat, on_seat_device_removed, manager); +} + static CkSeat * add_new_seat (CkManager *manager, CkSeatKind kind) @@ -293,10 +466,14 @@ add_new_seat (CkManager *manager, goto out; } + connect_seat_signals (manager, seat); + g_hash_table_insert (manager->priv->seats, sid, seat); g_debug ("Added seat: %s kind:%d", sid, kind); + ck_manager_dump (manager); + g_signal_emit (manager, signals [SEAT_ADDED], 0, sid); out: @@ -329,10 +506,14 @@ remove_seat (CkManager *manager, * unref until the signal is emitted */ g_hash_table_steal (manager->priv->seats, sid); + disconnect_seat_signals (manager, orig_seat); + if (sid != NULL) { g_hash_table_remove (manager->priv->seats, sid); } + ck_manager_dump (manager); + g_debug ("Emitting seat-removed: %s", sid); g_signal_emit (manager, signals [SEAT_REMOVED], 0, sid); @@ -1204,6 +1385,11 @@ remove_session_for_cookie (CkManager *manager, LeaderInfo *leader_info; char *sid; gboolean res; + gboolean ret; + + ret = FALSE; + orig_ssid = NULL; + orig_session = NULL; g_debug ("Removing session for cookie: %s", cookie); @@ -1214,7 +1400,7 @@ remove_session_for_cookie (CkManager *manager, CK_MANAGER_ERROR, CK_MANAGER_ERROR_GENERAL, "Unable to find session for cookie"); - return FALSE; + goto out; } /* Need to get the original key/value */ @@ -1227,7 +1413,7 @@ remove_session_for_cookie (CkManager *manager, CK_MANAGER_ERROR, CK_MANAGER_ERROR_GENERAL, "Unable to find session for cookie"); - return FALSE; + goto out; } /* Remove the session from the list but don't call @@ -1255,14 +1441,18 @@ remove_session_for_cookie (CkManager *manager, } g_free (sid); + ck_manager_dump (manager); + + manager_update_system_idle_hint (manager); + + ret = TRUE; + out: if (orig_session != NULL) { g_object_unref (orig_session); } g_free (orig_ssid); - manager_update_system_idle_hint (manager); - - return TRUE; + return ret; } static gboolean @@ -1595,10 +1785,14 @@ add_seat_for_file (CkManager *manager, return; } + connect_seat_signals (manager, seat); + g_hash_table_insert (manager->priv->seats, sid, seat); g_debug ("Added seat: %s", sid); + ck_manager_dump (manager); + g_signal_emit (manager, signals [SEAT_ADDED], 0, sid); } diff --git a/src/ck-seat.c b/src/ck-seat.c index 66bf728..526640e 100644 --- a/src/ck-seat.c +++ b/src/ck-seat.c @@ -656,7 +656,6 @@ ck_seat_add_device (CkSeat *seat, g_ptr_array_add (seat->priv->devices, g_boxed_copy (CK_TYPE_DEVICE, device)); g_debug ("Emitting device added signal"); - g_signal_emit (seat, signals [DEVICE_ADDED], 0, device); return TRUE; @@ -672,7 +671,6 @@ ck_seat_remove_device (CkSeat *seat, /* FIXME: check if already present */ if (0) { g_debug ("Emitting device removed signal"); - g_signal_emit (seat, signals [DEVICE_REMOVED], 0, device); } @@ -1122,3 +1120,87 @@ ck_seat_new_from_file (const char *sid, return seat; } + +static void +dump_seat_session_iter (char *id, + CkSession *session, + GString *str) +{ + char *session_id; + GError *error; + + error = NULL; + if (! ck_session_get_id (session, &session_id, &error)) { + g_warning ("Cannot get session id from seat: %s", error->message); + g_error_free (error); + } else { + if (str->len > 0) { + g_string_append_c (str, ' '); + } + g_string_append (str, session_id); + g_free (session_id); + } +} + +void +ck_seat_dump (CkSeat *seat, + GKeyFile *key_file) +{ + char *group_name; + GString *str; + char *s; + int n; + + group_name = g_strdup_printf ("Seat %s", seat->priv->id); + + g_key_file_set_integer (key_file, group_name, "kind", seat->priv->kind); + + str = g_string_new (NULL); + g_hash_table_foreach (seat->priv->sessions, (GHFunc) dump_seat_session_iter, str); + s = g_string_free (str, FALSE); + g_key_file_set_string (key_file, group_name, "sessions", s); + g_free (s); + + str = g_string_new (NULL); + if (seat->priv->devices != NULL) { + for (n = 0; n < seat->priv->devices->len; n++) { + int m; + GValueArray *va; + + va = seat->priv->devices->pdata[n]; + + if (str->len > 0) + g_string_append_c (str, ' '); + for (m = 0; m < va->n_values; m++) { + if (m > 0) + g_string_append_c (str, ':'); + g_string_append (str, g_value_get_string ((const GValue *) &((va->values)[m]))); + } + + g_debug ("foo %d", va->n_values); + } + } + s = g_string_free (str, FALSE); + g_key_file_set_string (key_file, group_name, "devices", s); + g_free (s); + + + if (seat->priv->active_session != NULL) { + char *session_id; + GError *error; + + error = NULL; + if (! ck_session_get_id (seat->priv->active_session, &session_id, &error)) { + g_warning ("Cannot get session id for active session on seat %s: %s", + seat->priv->id, + error->message); + g_error_free (error); + } else { + g_key_file_set_string (key_file, group_name, "active_session", session_id); + g_free (session_id); + } + } + + g_free (group_name); +} + diff --git a/src/ck-seat.h b/src/ck-seat.h index 63ab3d5..5977781 100644 --- a/src/ck-seat.h +++ b/src/ck-seat.h @@ -90,6 +90,10 @@ CkSeat * ck_seat_new_from_file (const char *sid, CkSeat * ck_seat_new_with_devices (const char *sid, CkSeatKind kind, GPtrArray *devices); + +void ck_seat_dump (CkSeat *seat, + GKeyFile *key_file); + gboolean ck_seat_get_kind (CkSeat *seat, CkSeatKind *kind, GError **error); diff --git a/src/ck-session.c b/src/ck-session.c index 6f16720..a700786 100644 --- a/src/ck-session.c +++ b/src/ck-session.c @@ -1245,3 +1245,41 @@ ck_session_run_programs (CkSession *session, g_free (extra_env[n]); } } + +void +ck_session_dump (CkSession *session, + GKeyFile *key_file) +{ + char *s; + char *group_name; + + group_name = g_strdup_printf ("Session %s", session->priv->id); + g_key_file_set_integer (key_file, group_name, "uid", session->priv->uid); + g_key_file_set_string (key_file, group_name, "seat", session->priv->seat_id); + g_key_file_set_string (key_file, group_name, "cookie", session->priv->cookie); + if (session->priv->session_type != NULL) { + g_key_file_set_string (key_file, group_name, "type", session->priv->session_type); + } + if (session->priv->display_device != NULL && strlen (session->priv->display_device) > 0) { + g_key_file_set_string (key_file, group_name, "display_device", session->priv->display_device); + } + if (session->priv->x11_display_device != NULL && strlen (session->priv->x11_display_device) > 0) { + g_key_file_set_string (key_file, group_name, "x11_display_device", session->priv->x11_display_device); + } + if (session->priv->x11_display != NULL && strlen (session->priv->x11_display) > 0) { + g_key_file_set_string (key_file, group_name, "x11_display", session->priv->x11_display); + } + if (session->priv->remote_host_name != NULL && strlen (session->priv->remote_host_name) > 0) { + g_key_file_set_string (key_file, group_name, "remote_host_name", session->priv->remote_host_name); + } + g_key_file_set_string (key_file, group_name, "remote_host_name", session->priv->remote_host_name); + g_key_file_set_boolean (key_file, group_name, "is_active", session->priv->active); + g_key_file_set_boolean (key_file, group_name, "is_local", session->priv->is_local); + + s = g_time_val_to_iso8601 (&(session->priv->creation_time)); + g_key_file_set_string (key_file, group_name, "creation_time", s); + g_free (s); + + g_free (group_name); +} + diff --git a/src/ck-session.h b/src/ck-session.h index fea3a71..8c5c00e 100644 --- a/src/ck-session.h +++ b/src/ck-session.h @@ -74,6 +74,9 @@ CkSession * ck_session_new_with_parameters (const char *ss const char *cookie, const GPtrArray *parameters); +void ck_session_dump (CkSession *session, + GKeyFile *key_file); + gboolean ck_session_set_active (CkSession *session, gboolean active, GError **error); -- cgit