PolicyKit: Branch 'master'

David Zeuthen david at kemper.freedesktop.org
Thu Oct 18 10:44:17 PDT 2007


 polkit-dbus/polkit-dbus.c |  195 ++++++++++++++++++++++++++++++++++++++++++++--
 polkit-dbus/polkit-dbus.h |    4 
 2 files changed, 191 insertions(+), 8 deletions(-)

New commits:
commit 0d7cdd74326c59bffe90be367329b012d23726b9
Author: David Zeuthen <davidz at redhat.com>
Date:   Thu Oct 18 13:44:16 2007 -0400

    add support to PolKitTracker for also asking on pid

diff --git a/polkit-dbus/polkit-dbus.c b/polkit-dbus/polkit-dbus.c
index c18f5b2..d8c22b5 100644
--- a/polkit-dbus/polkit-dbus.c
+++ b/polkit-dbus/polkit-dbus.c
@@ -37,7 +37,8 @@
  * If the mechanism itself is a daemon exposing a remote services via
  * the system message bus it's often a better idea, to reduce
  * roundtrips, to use the high-level #PolKitTracker class rather than
- * the low-level function polkit_caller_new_from_dbus_name().
+ * the low-level functions polkit_caller_new_from_dbus_name() and
+ * polkit_caller_new_from_pid().
  **/
 
 #ifdef HAVE_CONFIG_H
@@ -359,8 +360,7 @@ out:
  * both the system bus daemon and the ConsoleKit daemon for
  * information. Note that this will do a lot of blocking IO so it is
  * best avoided if your process already tracks/caches all the
- * information. For example you can use the #PolKitTracker class for
- * this.
+ * information. You can use the #PolKitTracker class for this.
  * 
  * Returns: the new object or #NULL if an error occured (in which case
  * @error will be set)
@@ -567,7 +567,8 @@ out:
  * both information in /proc (on Linux) and the ConsoleKit daemon for
  * information about a given process. Note that this will do a lot of
  * blocking IO so it is best avoided if your process already
- * tracks/caches all the information.
+ * tracks/caches all the information. You can use the #PolKitTracker
+ * class for this.
  * 
  * Returns: the new object or #NULL if an error occured (in which case
  * @error will be set)
@@ -792,8 +793,45 @@ struct _PolKitTracker {
         DBusConnection *con;
 
         GHashTable *dbus_name_to_caller;
+
+        GHashTable *pid_start_time_to_caller;
 };
 
+typedef struct {
+        pid_t pid;
+        polkit_uint64_t start_time;
+} _PidStartTimePair;
+
+static _PidStartTimePair *
+_pid_start_time_new (pid_t pid, polkit_uint64_t start_time)
+{
+        _PidStartTimePair *obj;
+        obj = g_new (_PidStartTimePair, 1);
+        obj->pid = pid;
+        obj->start_time = start_time;
+        return obj;
+}
+
+static guint
+_pid_start_time_hash (gconstpointer a)
+{
+        int val;
+        _PidStartTimePair *pst = (_PidStartTimePair *) a;
+
+        val = pst->pid + ((int) pst->start_time);
+
+        return g_int_hash (&val);
+}
+
+static gboolean
+_pid_start_time_equal (gconstpointer a, gconstpointer b)
+{
+        _PidStartTimePair *_a = (_PidStartTimePair *) a;
+        _PidStartTimePair *_b = (_PidStartTimePair *) b;
+
+        return (_a->pid == _b->pid) && (_a->start_time == _b->start_time);
+}
+
 /**
  * polkit_tracker_new:
  * 
@@ -811,6 +849,10 @@ polkit_tracker_new (void)
                                                                  g_str_equal,
                                                                  g_free,
                                                                  (GDestroyNotify) polkit_caller_unref);
+        pk_tracker->pid_start_time_to_caller = g_hash_table_new_full (_pid_start_time_hash,
+                                                                      _pid_start_time_equal,
+                                                                      g_free,
+                                                                      (GDestroyNotify) polkit_caller_unref);
         return pk_tracker;
 }
 
@@ -846,6 +888,7 @@ polkit_tracker_unref (PolKitTracker *pk_tracker)
         if (pk_tracker->refcount > 0) 
                 return;
         g_hash_table_unref (pk_tracker->dbus_name_to_caller);
+        g_hash_table_unref (pk_tracker->pid_start_time_to_caller);
         dbus_connection_unref (pk_tracker->con);
         g_free (pk_tracker);
 }
@@ -972,10 +1015,15 @@ _remove_caller_by_dbus_name (PolKitTracker *pk_tracker, const char *dbus_name)
  * The owner of the #PolKitTracker object must pass signals from the
  * system message bus (just NameOwnerChanged will do) and all signals
  * from the ConsoleKit service into this function.
+ *
+ * Returns: #TRUE only if there was a change in the ConsoleKit database.
  */
-void
+polkit_bool_t
 polkit_tracker_dbus_func (PolKitTracker *pk_tracker, DBusMessage *message)
 {
+        gboolean ret;
+
+        ret = FALSE;
 
         if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
 		char *name;
@@ -1003,6 +1051,8 @@ polkit_tracker_dbus_func (PolKitTracker *pk_tracker, DBusMessage *message)
                 DBusError error;
                 const char *session_objpath;
 
+                ret = TRUE;
+
                 dbus_error_init (&error);
                 session_objpath = dbus_message_get_path (message);
                 if (!dbus_message_get_args (message, &error, 
@@ -1024,6 +1074,7 @@ polkit_tracker_dbus_func (PolKitTracker *pk_tracker, DBusMessage *message)
 
                 /* now go through all Caller objects and update the is_active field as appropriate */
                 _update_session_is_active (pk_tracker, session_objpath, is_active);
+
         }
 
         /* TODO: when ConsoleKit gains the ability to attach/detach a session to a seat (think
@@ -1031,7 +1082,7 @@ polkit_tracker_dbus_func (PolKitTracker *pk_tracker, DBusMessage *message)
          */
 
 out:
-        ;
+        return ret;
 }
 
 /**
@@ -1058,11 +1109,13 @@ polkit_tracker_get_caller_from_dbus_name (PolKitTracker *pk_tracker, const char
         g_return_val_if_fail (pk_tracker->con != NULL, NULL);
         g_return_val_if_fail (! dbus_error_is_set (error), NULL);
 
+        g_debug ("Looking up cache for PolKitCaller for dbus_name %s...", dbus_name);
+
         caller = g_hash_table_lookup (pk_tracker->dbus_name_to_caller, dbus_name);
         if (caller != NULL)
                 return polkit_caller_ref (caller);
 
-        g_debug ("Have to look up %s...", dbus_name);
+        g_debug ("Have to compute PolKitCaller for dbus_name %s...", dbus_name);
 
         caller = polkit_caller_new_from_dbus_name (pk_tracker->con, dbus_name, error);
         if (caller == NULL)
@@ -1071,3 +1124,131 @@ polkit_tracker_get_caller_from_dbus_name (PolKitTracker *pk_tracker, const char
         g_hash_table_insert (pk_tracker->dbus_name_to_caller, g_strdup (dbus_name), caller);
         return polkit_caller_ref (caller);
 }
+
+/* TODO FIXME: this is Linux specific */
+static polkit_uint64_t 
+_get_start_time_for_pid (pid_t pid)
+{
+        char *filename;
+        char *contents;
+        gsize length;
+        polkit_uint64_t start_time;
+        GError *error = NULL;
+        char **tokens;
+        char *p;
+        char *endp;
+
+        start_time = 0;
+        contents = NULL;
+
+        filename = g_strdup_printf ("/proc/%d/stat", pid);
+        if (filename == NULL) {
+                fprintf (stderr, "Out of memory\n");
+                goto out;
+        }
+
+        if (!g_file_get_contents (filename, &contents, &length, &error)) {
+                fprintf (stderr, "Cannot get contents of '%s': %s\n", filename, error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        /* start time is the 19th token after the '(process name)' entry */
+
+        p = strchr (contents, ')');
+        if (p == NULL) {
+                goto out;
+        }
+        p += 2; /* skip ') ' */
+        if (p - contents >= (int) length) {
+                goto out;
+        }
+
+        tokens = g_strsplit (p, " ", 0);
+        if (g_strv_length (tokens) < 20) {
+                goto out;
+        }
+
+        start_time = strtoll (tokens[19], &endp, 10);
+        if (endp == tokens[19]) {
+                goto out;
+        }
+
+        g_strfreev (tokens);
+
+out:
+        g_free (filename);
+        g_free (contents);
+        return start_time;
+}
+
+/**
+ * polkit_tracker_get_caller_from_pid:
+ * @pk_tracker: the tracker object
+ * @pid: UNIX process id to look at
+ * @error: D-Bus error
+ *
+ * This function is similar to polkit_caller_new_from_pid()
+ * except that it uses the cache in #PolKitTracker. So on the second
+ * and subsequent calls, for the same D-Bus name, there will be no
+ * IPC overhead in calling this function. 
+ *
+ * There will be some syscall overhead to lookup the time when the
+ * given process is started (on Linux, looking up /proc/$pid/stat);
+ * this is needed because pid's can be recycled and the cache thus
+ * needs to record this in addition to the pid.
+ * 
+ * Returns: A #PolKitCaller object; the caller must use
+ * polkit_caller_unref() on the object when done with it. Returns
+ * #NULL if an error occured (in which case error will be set).
+ */
+PolKitCaller *
+polkit_tracker_get_caller_from_pid (PolKitTracker *pk_tracker, pid_t pid, DBusError *error)
+{
+        PolKitCaller *caller;
+        polkit_uint64_t start_time;
+        _PidStartTimePair *pst;
+
+        g_return_val_if_fail (pk_tracker != NULL, NULL);
+        g_return_val_if_fail (pk_tracker->con != NULL, NULL);
+        g_return_val_if_fail (! dbus_error_is_set (error), NULL);
+
+        start_time = _get_start_time_for_pid (pid);
+        if (start_time == 0) {
+                if (error != NULL) {
+                        dbus_set_error (error, 
+                                        "org.freedesktop.PolicyKit",
+                                        "Cannot look up start time for pid %d", pid);
+                }
+                return NULL;
+        }
+
+        pst = _pid_start_time_new (pid, start_time);
+
+        g_debug ("Looking up cache for pid %d (start_time %lld)...", pid, start_time);
+
+        caller = g_hash_table_lookup (pk_tracker->pid_start_time_to_caller, pst);
+        if (caller != NULL) {
+                g_free (pst);
+                return polkit_caller_ref (caller);
+        }
+
+        g_debug ("Have to compute PolKitCaller from pid %d (start_time %lld)...", pid, start_time);
+
+        caller = polkit_caller_new_from_pid (pk_tracker->con, pid, error);
+        if (caller == NULL) {
+                g_free (pst);
+                return NULL;
+        }
+
+        /* TODO: we need to evict old entries.. 
+         *
+         * Say, timestamp the entries in _PidStartTimePair and do
+         * garbage collection every hour or so (e.g. record when we
+         * last did garbage collection and check this time on the next
+         * call into this function).
+         */
+
+        g_hash_table_insert (pk_tracker->pid_start_time_to_caller, pst, caller);
+        return polkit_caller_ref (caller);
+}
diff --git a/polkit-dbus/polkit-dbus.h b/polkit-dbus/polkit-dbus.h
index d0fa9f6..10b5c90 100644
--- a/polkit-dbus/polkit-dbus.h
+++ b/polkit-dbus/polkit-dbus.h
@@ -48,10 +48,12 @@ void           polkit_tracker_unref                      (PolKitTracker *pk_trac
 void           polkit_tracker_set_system_bus_connection  (PolKitTracker *pk_tracker, DBusConnection *con);
 void           polkit_tracker_init                       (PolKitTracker *pk_tracker);
 
-void           polkit_tracker_dbus_func                  (PolKitTracker *pk_tracker, DBusMessage *message);
+polkit_bool_t  polkit_tracker_dbus_func                  (PolKitTracker *pk_tracker, DBusMessage *message);
 
 PolKitCaller  *polkit_tracker_get_caller_from_dbus_name  (PolKitTracker *pk_tracker, const char *dbus_name, DBusError *error);
 
+PolKitCaller  *polkit_tracker_get_caller_from_pid        (PolKitTracker *pk_tracker, pid_t pid, DBusError *error);
+
 
 #endif /* POLKIT_DBUS_H */
 


More information about the hal-commit mailing list