summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2007-10-10 13:39:15 -0400
committerWilliam Jon McCann <mccann@jhu.edu>2007-10-10 13:39:15 -0400
commitb2be103bd606291319dc312f07d1f3fcbfdf634c (patch)
tree54e295f2e273b6d2a6451ac5eec537d762d1d814
parentbd43c78b3ab2ec7f85b17cca46d4b46f8671cd29 (diff)
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.
-rw-r--r--src/Makefile.am2
-rw-r--r--src/ck-manager.c204
-rw-r--r--src/ck-seat.c86
-rw-r--r--src/ck-seat.h4
-rw-r--r--src/ck-session.c38
-rw-r--r--src/ck-session.h3
6 files changed, 330 insertions, 7 deletions
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 <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <errno.h>
#include <glib.h>
#include <glib/gi18n.h>
+#include <glib/gstdio.h>
#include <glib-object.h>
#define DBUS_API_SUBJECT_TO_CHANGE
#include <dbus/dbus-glib.h>
@@ -105,6 +107,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)
{
if (job != NULL) {
@@ -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);