From 5db2f7fdc2d1c5a45bc33d916d82c23178568923 Mon Sep 17 00:00:00 2001 From: William Jon McCann Date: Mon, 22 Oct 2007 20:54:10 -0400 Subject: move session leader stuff into a separate class This will make it easier to dump/restore. --- src/Makefile.am | 2 + src/ck-manager.c | 482 +++++++++-------------------------------- src/ck-session-leader.c | 558 ++++++++++++++++++++++++++++++++++++++++++++++++ src/ck-session-leader.h | 97 +++++++++ 4 files changed, 762 insertions(+), 377 deletions(-) create mode 100644 src/ck-session-leader.c create mode 100644 src/ck-session-leader.h diff --git a/src/Makefile.am b/src/Makefile.am index 3d08222..2f0d42d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -101,6 +101,8 @@ console_kit_daemon_SOURCES = \ ck-job.c \ ck-seat.h \ ck-seat.c \ + ck-session-leader.h \ + ck-session-leader.c \ ck-session.h \ ck-session.c \ ck-log.h \ diff --git a/src/ck-manager.c b/src/ck-manager.c index 79c7c91..396980c 100644 --- a/src/ck-manager.c +++ b/src/ck-manager.c @@ -41,8 +41,8 @@ #include "ck-manager.h" #include "ck-manager-glue.h" #include "ck-seat.h" +#include "ck-session-leader.h" #include "ck-session.h" -#include "ck-job.h" #include "ck-marshal.h" #include "ck-event-logger.h" @@ -56,12 +56,6 @@ #define CK_MANAGER_DBUS_PATH CK_DBUS_PATH "/Manager" #define CK_MANAGER_DBUS_NAME "org.freedesktop.ConsoleKit.Manager" -#define CK_TYPE_PARAMETER_STRUCT (dbus_g_type_get_struct ("GValueArray", \ - G_TYPE_STRING, \ - G_TYPE_VALUE, \ - G_TYPE_INVALID)) -#define CK_TYPE_PARAMETER_LIST (dbus_g_type_get_collection ("GPtrArray", \ - CK_TYPE_PARAMETER_STRUCT)) struct CkManagerPrivate { GHashTable *seats; @@ -79,18 +73,6 @@ struct CkManagerPrivate GTimeVal system_idle_since_hint; }; - -typedef struct { - int refcount; - gboolean cancelled; - uid_t uid; - pid_t pid; - char *service_name; - char *ssid; - char *cookie; - GList *pending_jobs; -} LeaderInfo; - enum { SEAT_ADDED, SEAT_REMOVED, @@ -217,67 +199,6 @@ error: } } -static void -remove_pending_job (CkJob *job) -{ - if (job != NULL) { - char *command; - - command = NULL; - ck_job_get_command (job, &command); - g_debug ("Removing pending job: %s", command); - g_free (command); - - ck_job_cancel (job); - g_object_unref (job); - } -} - -static void -_leader_info_free (LeaderInfo *info) -{ - g_debug ("Freeing leader info: %s", info->ssid); - - g_free (info->ssid); - info->ssid = NULL; - g_free (info->cookie); - info->cookie = NULL; - g_free (info->service_name); - info->service_name = NULL; - - g_free (info); -} - -static void -leader_info_cancel (LeaderInfo *info) -{ - if (info->pending_jobs != NULL) { - g_list_foreach (info->pending_jobs, (GFunc)remove_pending_job, NULL); - g_list_free (info->pending_jobs); - info->pending_jobs = NULL; - } - - info->cancelled = TRUE; -} - -static void -leader_info_unref (LeaderInfo *info) -{ - /* Probably should use some kind of atomic op here */ - info->refcount -= 1; - if (info->refcount == 0) { - _leader_info_free (info); - } -} - -static LeaderInfo * -leader_info_ref (LeaderInfo *info) -{ - info->refcount += 1; - - return info; -} - GQuark ck_manager_error_quark (void) { @@ -1082,16 +1003,21 @@ ck_manager_get_system_idle_since_hint (CkManager *manager, } static void -open_session_for_leader_info (CkManager *manager, - LeaderInfo *leader_info, - const GPtrArray *parameters, - DBusGMethodInvocation *context) +open_session_for_leader (CkManager *manager, + CkSessionLeader *leader, + const GPtrArray *parameters, + DBusGMethodInvocation *context) { CkSession *session; CkSeat *seat; + const char *ssid; + const char *cookie; + + ssid = ck_session_leader_peek_session_id (leader); + cookie = ck_session_leader_peek_cookie (leader); - session = ck_session_new_with_parameters (leader_info->ssid, - leader_info->cookie, + session = ck_session_new_with_parameters (ssid, + cookie, parameters); if (session == NULL) { @@ -1106,7 +1032,9 @@ open_session_for_leader_info (CkManager *manager, return; } - g_hash_table_insert (manager->priv->sessions, g_strdup (leader_info->ssid), g_object_ref (session)); + g_hash_table_insert (manager->priv->sessions, + g_strdup (ssid), + g_object_ref (session)); /* Add to seat */ seat = find_seat_for_session (manager, session); @@ -1127,247 +1055,55 @@ open_session_for_leader_info (CkManager *manager, g_object_unref (session); - dbus_g_method_return (context, leader_info->cookie); + dbus_g_method_return (context, cookie); } static void -verify_and_open_session_for_leader_info (CkManager *manager, - LeaderInfo *leader_info, - const GPtrArray *parameters, - DBusGMethodInvocation *context) +verify_and_open_session_for_leader (CkManager *manager, + CkSessionLeader *leader, + const GPtrArray *parameters, + DBusGMethodInvocation *context) { /* for now don't bother verifying since we protect OpenSessionWithParameters */ - open_session_for_leader_info (manager, - leader_info, - parameters, - context); -} - -static void -add_param_int (GPtrArray *parameters, - const char *key, - const char *value) -{ - GValue val = { 0, }; - GValue param_val = { 0, }; - int num; - - num = atoi (value); - - g_value_init (&val, G_TYPE_INT); - g_value_set_int (&val, num); - g_value_init (¶m_val, CK_TYPE_PARAMETER_STRUCT); - g_value_take_boxed (¶m_val, - dbus_g_type_specialized_construct (CK_TYPE_PARAMETER_STRUCT)); - dbus_g_type_struct_set (¶m_val, - 0, key, - 1, &val, - G_MAXUINT); - g_value_unset (&val); - - g_ptr_array_add (parameters, g_value_get_boxed (¶m_val)); -} - -static void -add_param_boolean (GPtrArray *parameters, - const char *key, - const char *value) -{ - GValue val = { 0, }; - GValue param_val = { 0, }; - gboolean b; - - if (value != NULL && strcmp (value, "true") == 0) { - b = TRUE; - } else { - b = FALSE; - } - - g_value_init (&val, G_TYPE_BOOLEAN); - g_value_set_boolean (&val, b); - g_value_init (¶m_val, CK_TYPE_PARAMETER_STRUCT); - g_value_take_boxed (¶m_val, - dbus_g_type_specialized_construct (CK_TYPE_PARAMETER_STRUCT)); - dbus_g_type_struct_set (¶m_val, - 0, key, - 1, &val, - G_MAXUINT); - g_value_unset (&val); - - g_ptr_array_add (parameters, g_value_get_boxed (¶m_val)); -} - -static void -add_param_string (GPtrArray *parameters, - const char *key, - const char *value) -{ - GValue val = { 0, }; - GValue param_val = { 0, }; - - g_value_init (&val, G_TYPE_STRING); - g_value_set_string (&val, value); - - g_value_init (¶m_val, CK_TYPE_PARAMETER_STRUCT); - g_value_take_boxed (¶m_val, - dbus_g_type_specialized_construct (CK_TYPE_PARAMETER_STRUCT)); - - dbus_g_type_struct_set (¶m_val, - 0, key, - 1, &val, - G_MAXUINT); - g_value_unset (&val); - - g_ptr_array_add (parameters, g_value_get_boxed (¶m_val)); -} - -typedef void (* CkAddParamFunc) (GPtrArray *arr, - const char *key, - const char *value); - -static struct { - char *key; - CkAddParamFunc func; -} parse_ops[] = { - { "display-device", add_param_string }, - { "x11-display-device", add_param_string }, - { "x11-display", add_param_string }, - { "remote-host-name", add_param_string }, - { "session-type", add_param_string }, - { "is-local", add_param_boolean }, - { "unix-user", add_param_int }, -}; - -static GPtrArray * -parse_output (const char *output) -{ - GPtrArray *parameters; - char **lines; - int i; - int j; - - lines = g_strsplit (output, "\n", -1); - if (lines == NULL) { - return NULL; - } - - parameters = g_ptr_array_sized_new (10); - - for (i = 0; lines[i] != NULL; i++) { - char **vals; - - vals = g_strsplit (lines[i], " = ", 2); - if (vals == NULL || vals[0] == NULL) { - g_strfreev (vals); - continue; - } - - for (j = 0; j < G_N_ELEMENTS (parse_ops); j++) { - if (strcmp (vals[0], parse_ops[j].key) == 0) { - parse_ops[j].func (parameters, vals[0], vals[1]); - break; - } - } - g_strfreev (vals); - } - - g_strfreev (lines); - - return parameters; + open_session_for_leader (manager, + leader, + parameters, + context); } -typedef struct { - CkManager *manager; - LeaderInfo *leader_info; - DBusGMethodInvocation *context; -} JobData; - static void -job_data_free (JobData *data) +collect_parameters_cb (CkSessionLeader *leader, + GPtrArray *parameters, + DBusGMethodInvocation *context, + CkManager *manager) { - leader_info_unref (data->leader_info); - g_free (data); -} - -static void -parameters_free (GPtrArray *parameters) -{ - int i; - - for (i = 0; i < parameters->len; i++) { - gpointer data; - data = g_ptr_array_index (parameters, i); - if (data != NULL) { - g_boxed_free (CK_TYPE_PARAMETER_STRUCT, data); - } - } - - g_ptr_array_free (parameters, TRUE); -} - -static void -job_completed (CkJob *job, - int status, - JobData *data) -{ - g_debug ("Job status: %d", status); - if (status == 0) { - char *output; - GPtrArray *parameters; - - output = NULL; - ck_job_get_stdout (job, &output); - g_debug ("Job output: %s", output); - - parameters = parse_output (output); - g_free (output); - - verify_and_open_session_for_leader_info (data->manager, - data->leader_info, - parameters, - data->context); - parameters_free (parameters); + if (parameters == NULL) { + GError *error; + error = g_error_new (CK_MANAGER_ERROR, + CK_MANAGER_ERROR_GENERAL, + "Unable to get information about the calling process"); + dbus_g_method_return_error (context, error); + g_error_free (error); + return; } - /* remove job from queue */ - data->leader_info->pending_jobs = g_list_remove (data->leader_info->pending_jobs, job); - - g_signal_handlers_disconnect_by_func (job, job_completed, data); - g_object_unref (job); + verify_and_open_session_for_leader (manager, + leader, + parameters, + context); } static void -generate_session_for_leader_info (CkManager *manager, - LeaderInfo *leader_info, - DBusGMethodInvocation *context) +generate_session_for_leader (CkManager *manager, + CkSessionLeader *leader, + DBusGMethodInvocation *context) { - GError *local_error; - char *command; - gboolean res; - CkJob *job; - JobData *data; - - command = g_strdup_printf ("%s --uid %u --pid %u", - LIBEXECDIR "/ck-collect-session-info", - leader_info->uid, - leader_info->pid); - job = ck_job_new (); - ck_job_set_command (job, command); - g_free (command); - - data = g_new0 (JobData, 1); - data->manager = manager; - data->leader_info = leader_info_ref (leader_info); - data->context = context; - g_signal_connect_data (job, - "completed", - G_CALLBACK (job_completed), - data, - (GClosureNotify)job_data_free, - 0); + gboolean res; - local_error = NULL; - res = ck_job_execute (job, &local_error); + res = ck_session_leader_collect_parameters (leader, + context, + (CkSessionLeaderDoneFunc)collect_parameters_cb, + manager); if (! res) { GError *error; error = g_error_new (CK_MANAGER_ERROR, @@ -1375,19 +1111,7 @@ generate_session_for_leader_info (CkManager *manager, "Unable to get information about the calling process"); dbus_g_method_return_error (context, error); g_error_free (error); - - if (local_error != NULL) { - g_debug ("stat on pid %d failed: %s", leader_info->pid, local_error->message); - g_error_free (local_error); - } - - g_object_unref (job); - - return; } - - /* Add job to queue */ - leader_info->pending_jobs = g_list_prepend (leader_info->pending_jobs, job); } static gboolean @@ -1396,12 +1120,12 @@ create_session_for_sender (CkManager *manager, const GPtrArray *parameters, DBusGMethodInvocation *context) { - pid_t pid; - uid_t uid; - gboolean res; - char *cookie; - char *ssid; - LeaderInfo *leader_info; + pid_t pid; + uid_t uid; + gboolean res; + char *cookie; + char *ssid; + CkSessionLeader *leader; res = get_caller_info (manager, sender, @@ -1422,27 +1146,27 @@ create_session_for_sender (CkManager *manager, g_debug ("Creating new session ssid: %s", ssid); - leader_info = g_new0 (LeaderInfo, 1); - leader_info->uid = uid; - leader_info->pid = pid; - leader_info->service_name = g_strdup (sender); - leader_info->ssid = g_strdup (ssid); - leader_info->cookie = g_strdup (cookie); + leader = ck_session_leader_new (); + ck_session_leader_set_uid (leader, uid); + ck_session_leader_set_pid (leader, pid); + ck_session_leader_set_service_name (leader, sender); + ck_session_leader_set_session_id (leader, ssid); + ck_session_leader_set_cookie (leader, cookie); /* need to store the leader info first so the pending request can be revoked */ g_hash_table_insert (manager->priv->leaders, - g_strdup (leader_info->cookie), - leader_info_ref (leader_info)); + g_strdup (cookie), + g_object_ref (leader)); if (parameters == NULL) { - generate_session_for_leader_info (manager, - leader_info, - context); + generate_session_for_leader (manager, + leader, + context); } else { - verify_and_open_session_for_leader_info (manager, - leader_info, - parameters, - context); + verify_and_open_session_for_leader (manager, + leader, + parameters, + context); } g_free (cookie); @@ -1463,15 +1187,15 @@ ck_manager_get_session_for_cookie (CkManager *manager, const char *cookie, DBusGMethodInvocation *context) { - gboolean res; - char *sender; - uid_t calling_uid; - pid_t calling_pid; - CkProcessStat *stat; - char *ssid; - CkSession *session; - LeaderInfo *leader_info; - GError *local_error; + gboolean res; + char *sender; + uid_t calling_uid; + pid_t calling_pid; + CkProcessStat *stat; + char *ssid; + CkSession *session; + CkSessionLeader *leader; + GError *local_error; ssid = NULL; @@ -1514,8 +1238,8 @@ ck_manager_get_session_for_cookie (CkManager *manager, /* FIXME: should we restrict this by uid? */ ck_process_stat_free (stat); - leader_info = g_hash_table_lookup (manager->priv->leaders, cookie); - if (leader_info == NULL) { + leader = g_hash_table_lookup (manager->priv->leaders, cookie); + if (leader == NULL) { GError *error; error = g_error_new (CK_MANAGER_ERROR, CK_MANAGER_ERROR_GENERAL, @@ -1525,7 +1249,7 @@ ck_manager_get_session_for_cookie (CkManager *manager, return FALSE; } - session = g_hash_table_lookup (manager->priv->sessions, leader_info->ssid); + session = g_hash_table_lookup (manager->priv->sessions, ck_session_leader_peek_session_id (leader)); if (session == NULL) { GError *error; error = g_error_new (CK_MANAGER_ERROR, @@ -1705,12 +1429,12 @@ remove_session_for_cookie (CkManager *manager, const char *cookie, GError **error) { - CkSession *orig_session; - char *orig_ssid; - LeaderInfo *leader_info; - char *sid; - gboolean res; - gboolean ret; + CkSession *orig_session; + char *orig_ssid; + CkSessionLeader *leader; + char *sid; + gboolean res; + gboolean ret; ret = FALSE; orig_ssid = NULL; @@ -1718,9 +1442,9 @@ remove_session_for_cookie (CkManager *manager, g_debug ("Removing session for cookie: %s", cookie); - leader_info = g_hash_table_lookup (manager->priv->leaders, cookie); + leader = g_hash_table_lookup (manager->priv->leaders, cookie); - if (leader_info == NULL) { + if (leader == NULL) { g_set_error (error, CK_MANAGER_ERROR, CK_MANAGER_ERROR_GENERAL, @@ -1730,7 +1454,7 @@ remove_session_for_cookie (CkManager *manager, /* Need to get the original key/value */ res = g_hash_table_lookup_extended (manager->priv->sessions, - leader_info->ssid, + ck_session_leader_peek_session_id (leader), (gpointer *)&orig_ssid, (gpointer *)&orig_session); if (! res) { @@ -1771,7 +1495,8 @@ remove_session_for_cookie (CkManager *manager, /* Remove the session from the list but don't call * unref until we are done with it */ - g_hash_table_steal (manager->priv->sessions, leader_info->ssid); + g_hash_table_steal (manager->priv->sessions, + ck_session_leader_peek_session_id (leader)); ck_manager_dump (manager); @@ -1794,7 +1519,7 @@ paranoia_check_is_cookie_owner (CkManager *manager, pid_t calling_pid, GError **error) { - LeaderInfo *leader_info; + CkSessionLeader *leader; if (cookie == NULL) { g_set_error (error, @@ -1804,8 +1529,8 @@ paranoia_check_is_cookie_owner (CkManager *manager, return FALSE; } - leader_info = g_hash_table_lookup (manager->priv->leaders, cookie); - if (leader_info == NULL) { + leader = g_hash_table_lookup (manager->priv->leaders, cookie); + if (leader == NULL) { g_set_error (error, CK_MANAGER_ERROR, CK_MANAGER_ERROR_GENERAL, @@ -1813,7 +1538,7 @@ paranoia_check_is_cookie_owner (CkManager *manager, return FALSE; } - if (leader_info->uid != calling_uid) { + if (ck_session_leader_get_uid (leader) != calling_uid) { g_set_error (error, CK_MANAGER_ERROR, CK_MANAGER_ERROR_GENERAL, @@ -1823,7 +1548,7 @@ paranoia_check_is_cookie_owner (CkManager *manager, } /* do we want to restrict to the same process? */ - if (leader_info->pid != calling_pid) { + if (ck_session_leader_get_pid (leader) != calling_pid) { g_set_error (error, CK_MANAGER_ERROR, CK_MANAGER_ERROR_GENERAL, @@ -1896,15 +1621,18 @@ typedef struct { static gboolean remove_leader_for_connection (const char *cookie, - LeaderInfo *info, + CkSessionLeader *leader, RemoveLeaderData *data) { - g_assert (info != NULL); + const char *name; + + g_assert (leader != NULL); g_assert (data->service_name != NULL); - if (strcmp (info->service_name, data->service_name) == 0) { + name = ck_session_leader_peek_service_name (leader); + if (strcmp (name, data->service_name) == 0) { remove_session_for_cookie (data->manager, cookie, NULL); - leader_info_cancel (info); + ck_session_leader_cancel (leader); return TRUE; } @@ -2188,7 +1916,7 @@ ck_manager_init (CkManager *manager) manager->priv->leaders = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, - (GDestroyNotify) leader_info_unref); + (GDestroyNotify) g_object_unref); manager->priv->logger = ck_event_logger_new (LOG_FILE); diff --git a/src/ck-session-leader.c b/src/ck-session-leader.c new file mode 100644 index 0000000..d9bb375 --- /dev/null +++ b/src/ck-session-leader.c @@ -0,0 +1,558 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2006-2007 William Jon McCann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#define DBUS_API_SUBJECT_TO_CHANGE +#include +#include + +#include "ck-session-leader.h" +#include "ck-job.h" + +#define CK_SESSION_LEADER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_SESSION_LEADER, CkSessionLeaderPrivate)) + +#define CK_TYPE_PARAMETER_STRUCT (dbus_g_type_get_struct ("GValueArray", \ + G_TYPE_STRING, \ + G_TYPE_VALUE, \ + G_TYPE_INVALID)) +#define CK_TYPE_PARAMETER_LIST (dbus_g_type_get_collection ("GPtrArray", \ + CK_TYPE_PARAMETER_STRUCT)) + +struct CkSessionLeaderPrivate +{ + gboolean cancelled; + + uid_t uid; + pid_t pid; + char *service_name; + char *session_id; + char *cookie; + GList *pending_jobs; +}; + +enum { + PROP_0, +}; + +static void ck_session_leader_class_init (CkSessionLeaderClass *klass); +static void ck_session_leader_init (CkSessionLeader *session_leader); +static void ck_session_leader_finalize (GObject *object); + +G_DEFINE_TYPE (CkSessionLeader, ck_session_leader, G_TYPE_OBJECT) + +GQuark +ck_session_leader_error_quark (void) +{ + static GQuark ret = 0; + if (ret == 0) { + ret = g_quark_from_static_string ("ck_session_leader_error"); + } + + return ret; +} + +static void +remove_pending_job (CkJob *job) +{ + if (job != NULL) { + char *command; + + command = NULL; + ck_job_get_command (job, &command); + g_debug ("Removing pending job: %s", command); + g_free (command); + + ck_job_cancel (job); + g_object_unref (job); + } +} + +void +ck_session_leader_cancel (CkSessionLeader *leader) +{ + g_return_if_fail (CK_IS_SESSION_LEADER (leader)); + + if (leader->priv->pending_jobs != NULL) { + g_list_foreach (leader->priv->pending_jobs, (GFunc)remove_pending_job, NULL); + g_list_free (leader->priv->pending_jobs); + leader->priv->pending_jobs = NULL; + } + + leader->priv->cancelled = TRUE; +} + + +static void +add_param_int (GPtrArray *parameters, + const char *key, + const char *value) +{ + GValue val = { 0, }; + GValue param_val = { 0, }; + int num; + + num = atoi (value); + + g_value_init (&val, G_TYPE_INT); + g_value_set_int (&val, num); + g_value_init (¶m_val, CK_TYPE_PARAMETER_STRUCT); + g_value_take_boxed (¶m_val, + dbus_g_type_specialized_construct (CK_TYPE_PARAMETER_STRUCT)); + dbus_g_type_struct_set (¶m_val, + 0, key, + 1, &val, + G_MAXUINT); + g_value_unset (&val); + + g_ptr_array_add (parameters, g_value_get_boxed (¶m_val)); +} + +static void +add_param_boolean (GPtrArray *parameters, + const char *key, + const char *value) +{ + GValue val = { 0, }; + GValue param_val = { 0, }; + gboolean b; + + if (value != NULL && strcmp (value, "true") == 0) { + b = TRUE; + } else { + b = FALSE; + } + + g_value_init (&val, G_TYPE_BOOLEAN); + g_value_set_boolean (&val, b); + g_value_init (¶m_val, CK_TYPE_PARAMETER_STRUCT); + g_value_take_boxed (¶m_val, + dbus_g_type_specialized_construct (CK_TYPE_PARAMETER_STRUCT)); + dbus_g_type_struct_set (¶m_val, + 0, key, + 1, &val, + G_MAXUINT); + g_value_unset (&val); + + g_ptr_array_add (parameters, g_value_get_boxed (¶m_val)); +} + +static void +add_param_string (GPtrArray *parameters, + const char *key, + const char *value) +{ + GValue val = { 0, }; + GValue param_val = { 0, }; + + g_value_init (&val, G_TYPE_STRING); + g_value_set_string (&val, value); + + g_value_init (¶m_val, CK_TYPE_PARAMETER_STRUCT); + g_value_take_boxed (¶m_val, + dbus_g_type_specialized_construct (CK_TYPE_PARAMETER_STRUCT)); + + dbus_g_type_struct_set (¶m_val, + 0, key, + 1, &val, + G_MAXUINT); + g_value_unset (&val); + + g_ptr_array_add (parameters, g_value_get_boxed (¶m_val)); +} + +typedef void (* CkAddParamFunc) (GPtrArray *arr, + const char *key, + const char *value); + +static struct { + char *key; + CkAddParamFunc func; +} parse_ops[] = { + { "display-device", add_param_string }, + { "x11-display-device", add_param_string }, + { "x11-display", add_param_string }, + { "remote-host-name", add_param_string }, + { "session-type", add_param_string }, + { "is-local", add_param_boolean }, + { "unix-user", add_param_int }, +}; + +static GPtrArray * +parse_output (const char *output) +{ + GPtrArray *parameters; + char **lines; + int i; + int j; + + lines = g_strsplit (output, "\n", -1); + if (lines == NULL) { + return NULL; + } + + parameters = g_ptr_array_sized_new (10); + + for (i = 0; lines[i] != NULL; i++) { + char **vals; + + vals = g_strsplit (lines[i], " = ", 2); + if (vals == NULL || vals[0] == NULL) { + g_strfreev (vals); + continue; + } + + for (j = 0; j < G_N_ELEMENTS (parse_ops); j++) { + if (strcmp (vals[0], parse_ops[j].key) == 0) { + parse_ops[j].func (parameters, vals[0], vals[1]); + break; + } + } + g_strfreev (vals); + } + + g_strfreev (lines); + + return parameters; +} + + +static void +parameters_free (GPtrArray *parameters) +{ + int i; + + for (i = 0; i < parameters->len; i++) { + gpointer data; + data = g_ptr_array_index (parameters, i); + if (data != NULL) { + g_boxed_free (CK_TYPE_PARAMETER_STRUCT, data); + } + } + + g_ptr_array_free (parameters, TRUE); +} + +typedef struct { + CkSessionLeader *leader; + CkSessionLeaderDoneFunc done_cb; + gpointer user_data; + DBusGMethodInvocation *context; +} JobData; + +static void +job_completed (CkJob *job, + int status, + JobData *data) +{ + g_debug ("Job status: %d", status); + if (status == 0) { + char *output; + GPtrArray *parameters; + + output = NULL; + ck_job_get_stdout (job, &output); + g_debug ("Job output: %s", output); + + parameters = parse_output (output); + g_free (output); + + data->done_cb (data->leader, + parameters, + data->context, + data->user_data); + parameters_free (parameters); + } else { + data->done_cb (data->leader, + NULL, + data->context, + data->user_data); + } + + /* remove job from queue */ + data->leader->priv->pending_jobs = g_list_remove (data->leader->priv->pending_jobs, job); + + g_signal_handlers_disconnect_by_func (job, job_completed, data); + g_object_unref (job); +} + +static void +job_data_free (JobData *data) +{ + g_free (data); +} + +gboolean +ck_session_leader_collect_parameters (CkSessionLeader *session_leader, + DBusGMethodInvocation *context, + CkSessionLeaderDoneFunc done_cb, + gpointer user_data) +{ + GError *local_error; + char *command; + gboolean res; + gboolean ret; + CkJob *job; + JobData *data; + + ret = FALSE; + + data = g_new0 (JobData, 1); + data->leader = session_leader; + data->done_cb = done_cb; + data->user_data = user_data; + data->context = context; + + command = g_strdup_printf ("%s --uid %u --pid %u", + LIBEXECDIR "/ck-collect-session-info", + session_leader->priv->uid, + session_leader->priv->pid); + job = ck_job_new (); + ck_job_set_command (job, command); + g_free (command); + + g_signal_connect_data (job, + "completed", + G_CALLBACK (job_completed), + data, + (GClosureNotify)job_data_free, + 0); + + local_error = NULL; + res = ck_job_execute (job, &local_error); + if (! res) { + if (local_error != NULL) { + g_debug ("stat on pid %d failed: %s", session_leader->priv->pid, local_error->message); + g_error_free (local_error); + } + + g_object_unref (job); + + goto out; + } + + /* Add job to queue */ + session_leader->priv->pending_jobs = g_list_prepend (session_leader->priv->pending_jobs, job); + ret = TRUE; + + out: + return ret; +} + + +const char * +ck_session_leader_peek_session_id (CkSessionLeader *session_leader) +{ + g_return_val_if_fail (CK_IS_SESSION_LEADER (session_leader), NULL); + return session_leader->priv->session_id; +} + +const char * +ck_session_leader_peek_cookie (CkSessionLeader *session_leader) +{ + g_return_val_if_fail (CK_IS_SESSION_LEADER (session_leader), NULL); + return session_leader->priv->cookie; +} + +const char * +ck_session_leader_peek_service_name (CkSessionLeader *session_leader) +{ + g_return_val_if_fail (CK_IS_SESSION_LEADER (session_leader), NULL); + return session_leader->priv->service_name; +} + +uid_t +ck_session_leader_get_uid (CkSessionLeader *session_leader) +{ + g_return_val_if_fail (CK_IS_SESSION_LEADER (session_leader), -1); + return session_leader->priv->uid; +} + +pid_t +ck_session_leader_get_pid (CkSessionLeader *session_leader) +{ + g_return_val_if_fail (CK_IS_SESSION_LEADER (session_leader), -1); + return session_leader->priv->pid; +} + +void +ck_session_leader_set_pid (CkSessionLeader *session_leader, + pid_t pid) +{ + g_return_if_fail (CK_IS_SESSION_LEADER (session_leader)); + session_leader->priv->pid = pid; +} + +void +ck_session_leader_set_uid (CkSessionLeader *session_leader, + uid_t uid) +{ + g_return_if_fail (CK_IS_SESSION_LEADER (session_leader)); + session_leader->priv->uid = uid; +} + +void +ck_session_leader_set_session_id (CkSessionLeader *session_leader, + const char *session_id) +{ + g_return_if_fail (CK_IS_SESSION_LEADER (session_leader)); + g_free (session_leader->priv->session_id); + session_leader->priv->session_id = g_strdup (session_id); +} + +void +ck_session_leader_set_cookie (CkSessionLeader *session_leader, + const char *cookie) +{ + g_return_if_fail (CK_IS_SESSION_LEADER (session_leader)); + g_free (session_leader->priv->cookie); + session_leader->priv->cookie = g_strdup (cookie); +} + +void +ck_session_leader_set_service_name (CkSessionLeader *session_leader, + const char *service_name) +{ + g_return_if_fail (CK_IS_SESSION_LEADER (session_leader)); + g_free (session_leader->priv->service_name); + session_leader->priv->service_name = g_strdup (service_name); +} + +static void +ck_session_leader_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + CkSessionLeader *self; + + self = CK_SESSION_LEADER (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ck_session_leader_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + CkSessionLeader *self; + + self = CK_SESSION_LEADER (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GObject * +ck_session_leader_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + CkSessionLeader *session_leader; + CkSessionLeaderClass *klass; + + klass = CK_SESSION_LEADER_CLASS (g_type_class_peek (CK_TYPE_SESSION_LEADER)); + + session_leader = CK_SESSION_LEADER (G_OBJECT_CLASS (ck_session_leader_parent_class)->constructor (type, + n_construct_properties, + construct_properties)); + + return G_OBJECT (session_leader); +} + +static void +ck_session_leader_class_init (CkSessionLeaderClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = ck_session_leader_constructor; + object_class->get_property = ck_session_leader_get_property; + object_class->set_property = ck_session_leader_set_property; + object_class->finalize = ck_session_leader_finalize; + + g_type_class_add_private (klass, sizeof (CkSessionLeaderPrivate)); +} + +static void +ck_session_leader_init (CkSessionLeader *session_leader) +{ + session_leader->priv = CK_SESSION_LEADER_GET_PRIVATE (session_leader); +} + +static void +ck_session_leader_finalize (GObject *object) +{ + CkSessionLeader *session_leader; + + g_return_if_fail (object != NULL); + g_return_if_fail (CK_IS_SESSION_LEADER (object)); + + session_leader = CK_SESSION_LEADER (object); + + g_return_if_fail (session_leader->priv != NULL); + + g_free (session_leader->priv->session_id); + session_leader->priv->session_id = NULL; + g_free (session_leader->priv->cookie); + session_leader->priv->cookie = NULL; + g_free (session_leader->priv->service_name); + session_leader->priv->service_name = NULL; + + G_OBJECT_CLASS (ck_session_leader_parent_class)->finalize (object); +} + +CkSessionLeader * +ck_session_leader_new (void) +{ + GObject *object; + + object = g_object_new (CK_TYPE_SESSION_LEADER, + NULL); + + return CK_SESSION_LEADER (object); +} + +void +ck_session_leader_dump (CkSessionLeader *session_leader, + GKeyFile *key_file) +{ +} + diff --git a/src/ck-session-leader.h b/src/ck-session-leader.h new file mode 100644 index 0000000..4eb8857 --- /dev/null +++ b/src/ck-session-leader.h @@ -0,0 +1,97 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2006-2007 William Jon McCann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + + +#ifndef __CK_SESSION_LEADER_H +#define __CK_SESSION_LEADER_H + +#include +#include + +G_BEGIN_DECLS + +#define CK_TYPE_SESSION_LEADER (ck_session_leader_get_type ()) +#define CK_SESSION_LEADER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CK_TYPE_SESSION_LEADER, CkSessionLeader)) +#define CK_SESSION_LEADER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CK_TYPE_SESSION_LEADER, CkSessionLeaderClass)) +#define CK_IS_SESSION_LEADER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CK_TYPE_SESSION_LEADER)) +#define CK_IS_SESSION_LEADER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CK_TYPE_SESSION_LEADER)) +#define CK_SESSION_LEADER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CK_TYPE_SESSION_LEADER, CkSessionLeaderClass)) + +typedef struct CkSessionLeaderPrivate CkSessionLeaderPrivate; + +typedef struct +{ + GObject parent; + CkSessionLeaderPrivate *priv; +} CkSessionLeader; + +typedef struct +{ + GObjectClass parent_class; + +} CkSessionLeaderClass; + +typedef enum +{ + CK_SESSION_LEADER_ERROR_GENERAL +} CkSessionLeaderError; + +#define CK_SESSION_LEADER_ERROR ck_session_leader_error_quark () + +typedef void (* CkSessionLeaderDoneFunc) (CkSessionLeader *session_leader, + GPtrArray *parameters, + DBusGMethodInvocation *context, + gpointer data); + +GQuark ck_session_leader_error_quark (void); +GType ck_session_leader_get_type (void); +CkSessionLeader * ck_session_leader_new (void); + +void ck_session_leader_set_pid (CkSessionLeader *session_leader, + pid_t pid); +void ck_session_leader_set_uid (CkSessionLeader *session_leader, + uid_t uid); +void ck_session_leader_set_session_id (CkSessionLeader *session_leader, + const char *session_id); +void ck_session_leader_set_cookie (CkSessionLeader *session_leader, + const char *cookie); +void ck_session_leader_set_service_name (CkSessionLeader *session_leader, + const char *sender); + +const char * ck_session_leader_peek_session_id (CkSessionLeader *session_leader); +const char * ck_session_leader_peek_cookie (CkSessionLeader *session_leader); +const char * ck_session_leader_peek_service_name (CkSessionLeader *session_leader); +uid_t ck_session_leader_get_uid (CkSessionLeader *session_leader); +pid_t ck_session_leader_get_pid (CkSessionLeader *session_leader); + + +gboolean ck_session_leader_collect_parameters (CkSessionLeader *session_leader, + DBusGMethodInvocation *context, + CkSessionLeaderDoneFunc done_cb, + gpointer data); +void ck_session_leader_cancel (CkSessionLeader *session_leader); + +void ck_session_leader_dump (CkSessionLeader *session_leader, + GKeyFile *key_file); + + +G_END_DECLS + +#endif /* __CK_SESSION_LEADER_H */ -- cgit