diff options
| author | William Jon McCann <mccann@jhu.edu> | 2007-10-22 20:54:10 -0400 | 
|---|---|---|
| committer | William Jon McCann <mccann@jhu.edu> | 2007-10-22 20:54:10 -0400 | 
| commit | 5db2f7fdc2d1c5a45bc33d916d82c23178568923 (patch) | |
| tree | c8c6d50deeaf2e9115e2a209f32f082e7dcb7370 | |
| parent | 252f542201036d36aa01ade9bd381624391cfb34 (diff) | |
move session leader stuff into a separate class
This will make it easier to dump/restore.
| -rw-r--r-- | src/Makefile.am | 2 | ||||
| -rw-r--r-- | src/ck-manager.c | 482 | ||||
| -rw-r--r-- | src/ck-session-leader.c | 558 | ||||
| -rw-r--r-- | src/ck-session-leader.h | 97 | 
4 files changed, 762 insertions, 377 deletions
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 <mccann@jhu.edu> + * + * 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 <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <string.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> +#include <dbus/dbus-glib-lowlevel.h> + +#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 <mccann@jhu.edu> + * + * 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 <glib-object.h> +#include <dbus/dbus-glib.h> + +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 */  | 
