summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xexamples/mandatory-locking-test.py20
-rw-r--r--hald/device.c171
-rw-r--r--hald/device.h9
-rw-r--r--hald/hald_dbus.c324
-rw-r--r--hald/hald_dbus.h4
5 files changed, 528 insertions, 0 deletions
diff --git a/examples/mandatory-locking-test.py b/examples/mandatory-locking-test.py
new file mode 100755
index 00000000..d863814f
--- /dev/null
+++ b/examples/mandatory-locking-test.py
@@ -0,0 +1,20 @@
+#!/usr/bin/python
+
+
+import dbus
+import sys
+import time
+import os
+
+bus = dbus.Bus(dbus.Bus.TYPE_SYSTEM)
+device = dbus.Interface(bus.get_object("org.freedesktop.Hal",
+ "/org/freedesktop/Hal/devices/computer"),
+# "/org/freedesktop/Hal/devices/volume_label_EOS_DIGITAL"),
+ "org.freedesktop.Hal.Device")
+
+device.AcquireMandatoryLock("foo")
+device.AcquireMandatoryLock("foo2")
+time.sleep(2)
+device.ReleaseMandatoryLock("foo2")
+#device.ReleaseMandatoryLock("foo")
+time.sleep(2)
diff --git a/hald/device.c b/hald/device.c
index a9b67f87..81cfa91c 100644
--- a/hald/device.c
+++ b/hald/device.c
@@ -37,6 +37,24 @@
#include "logger.h"
#include "hald_runner.h"
+static GSList *locked_devices = NULL;
+
+static void
+add_to_locked_set (HalDevice *device)
+{
+ if (g_slist_find (locked_devices, device) != NULL)
+ return;
+
+ locked_devices = g_slist_prepend (locked_devices, device);
+}
+
+
+static void
+remove_from_locked_set (HalDevice *device)
+{
+ locked_devices = g_slist_remove (locked_devices, device);
+}
+
struct _HalProperty {
int type;
union {
@@ -374,6 +392,8 @@ hal_device_finalize (GObject *obj)
runner_device_finalized (device);
+ remove_from_locked_set (device);
+
#ifdef HALD_MEMLEAK_DBG
dbg_hal_device_object_delta--;
printf ("************* in finalize for udi=%s\n", device->private->udi);
@@ -629,6 +649,29 @@ hal_device_property_get_strlist_length (HalDevice *device,
return 0;
}
+gboolean
+hal_device_property_strlist_contains (HalDevice *device,
+ const char *key,
+ const char *value)
+{
+ GSList *i;
+ GSList *elems;
+ gboolean ret;
+
+ ret = FALSE;
+
+ elems = hal_device_property_get_strlist (device, key);
+ for (i = elems; i != NULL; i = g_slist_next (i)) {
+ if (strcmp (i->data, value) == 0) {
+ ret = TRUE;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+
void
hal_device_property_strlist_iter_init (HalDevice *device,
const char *key,
@@ -1567,3 +1610,131 @@ hal_device_are_all_addons_ready (HalDevice *device)
return FALSE;
}
}
+
+/**
+ * hal_device_acquire_lock:
+ * @device: the device to acquire a lock on
+ * @lock_name: name of the lock
+ * @sender: the caller to acquire the lock
+ *
+ * Acquires a named lock on a device.
+ *
+ * Returns: FALSE if the caller already holds this lock. TRUE if the caller got the lock.
+ */
+gboolean
+hal_device_acquire_lock (HalDevice *device, const char *lock_name, const char *sender)
+{
+ gboolean ret;
+ char buf[256];
+
+ ret = FALSE;
+
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.dbus_name", lock_name);
+ if (hal_device_property_strlist_contains (device, buf, sender)) {
+ /* already locked */
+ goto out;
+ }
+ hal_device_property_strlist_append (device, buf, sender);
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.locked", lock_name);
+ hal_device_property_set_bool (device, buf, TRUE);
+
+ hal_device_property_strlist_append (device, "info.named_locks", lock_name);
+
+ add_to_locked_set (device);
+
+ ret = TRUE;
+out:
+ return ret;
+}
+
+/**
+ * hal_device_release_lock:
+ * @device: the device to acquire a lock on
+ * @lock_name: name of the lock
+ * @sender: the caller to acquire the lock
+ *
+ * Releases a named lock on a device.
+ *
+ * Returns: FALSE if the caller didn't hold this lock. True if the lock was removed.
+ */
+gboolean
+hal_device_release_lock (HalDevice *device, const char *lock_name, const char *sender)
+{
+ gboolean ret;
+ char buf[256];
+
+ ret = FALSE;
+
+ HAL_INFO (("Removing lock '%s' from '%s'", lock_name, sender));
+
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.locked", lock_name);
+ if (!hal_device_property_get_bool (device, buf)) {
+ /* not locked */
+ goto out;
+ }
+
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.dbus_name", lock_name);
+ if (!hal_device_property_strlist_contains (device, buf, sender)) {
+ /* not locked by sender */
+ goto out;
+ }
+
+ if (hal_device_property_get_strlist_length (device, buf) == 1) {
+ /* last one to hold the lock */
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.locked", lock_name);
+ hal_device_property_remove (device, buf);
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.dbus_name", lock_name);
+ hal_device_property_remove (device, buf);
+
+ if (hal_device_property_get_strlist_length (device, "info.named_locks") == 1) {
+ hal_device_property_remove (device, "info.named_locks");
+ remove_from_locked_set (device);
+ } else {
+ hal_device_property_strlist_remove (device, "info.named_locks", lock_name);
+ }
+ } else {
+ /* there are additional holders */
+ hal_device_property_strlist_remove (device, buf, sender);
+ }
+
+ ret = TRUE;
+
+out:
+ return ret;
+}
+
+/**
+ * hal_device_client_disconnected:
+ * @sender: the client that disconnected from the bus
+ *
+ * Will remove locks held by this client on locked devices. This is a
+ * static class method that affects all devices that are locked.
+ *
+ */
+void
+hal_device_client_disconnected (const char *sender)
+{
+ GSList *i;
+
+ HAL_INFO (("Removing locks from '%s'", sender));
+
+ for (i = locked_devices; i != NULL; i = g_slist_next (i)) {
+ HalDevice *device = i->data;
+ GSList *locks;
+ GSList *j;
+ GSList *k;
+
+ HAL_INFO (("Looking at udi '%s'", device->private->udi));
+
+ locks = hal_device_property_get_strlist (device, "info.named_locks");
+ for (j = locks; j != NULL; j = k) {
+ char *lock_name = j->data;
+ k = g_slist_next (j);
+
+ HAL_INFO (("Lock '%s'", lock_name));
+
+ hal_device_release_lock (device, lock_name, sender);
+ }
+ }
+}
+
diff --git a/hald/device.h b/hald/device.h
index 5bab299a..774d3dc0 100644
--- a/hald/device.h
+++ b/hald/device.h
@@ -136,6 +136,9 @@ const char *hal_device_property_get_strlist_elem (HalDevice *device,
guint index);
guint hal_device_property_get_strlist_length (HalDevice *device,
const char *key);
+gboolean hal_device_property_strlist_contains (HalDevice *device,
+ const char *key,
+ const char *value);
char **hal_device_property_dup_strlist_as_strv (HalDevice *device,
const char *key);
@@ -203,5 +206,11 @@ gboolean hal_device_inc_num_ready_addons (HalDevice *device);
gboolean hal_device_are_all_addons_ready (HalDevice *device);
+gboolean hal_device_acquire_lock (HalDevice *device, const char *lock_name, const char *sender);
+
+gboolean hal_device_release_lock (HalDevice *device, const char *lock_name, const char *sender);
+
+/* static method */
+void hal_device_client_disconnected (const char *sender);
#endif /* DEVICE_H */
diff --git a/hald/hald_dbus.c b/hald/hald_dbus.c
index effcd449..b69cbb70 100644
--- a/hald/hald_dbus.c
+++ b/hald/hald_dbus.c
@@ -2072,6 +2072,291 @@ device_query_capability (DBusConnection * connection,
return DBUS_HANDLER_RESULT_HANDLED;
}
+#if 0
+/* map: service name -> list of {lock_name, udi}
+ */
+static GHashTable *services_with_mlocks = NULL;
+
+typedef struct
+{
+ char *lock_name;
+ char *udi;
+} MLockEntry;
+
+static void
+free_mlock_entry (MLockEntry *me)
+{
+ g_free (me->lock_name);
+ g_free (me->udi);
+ g_free (me);
+}
+
+static MLockEntry *
+new_mlock_entry (const char *lock_name, const char *udi)
+{
+ MLockEntry *me;
+ me = g_new0 (MLockEntry, 1);
+ me->lock_name = g_strdup (lock_name);
+ me->udi = g_strdup (udi);
+ return me;
+}
+
+static void
+free_mlock_list (GSList *mlock_list)
+{
+ g_slist_foreach (mlock_list, (GFunc) free_mlock_entry, NULL);
+ g_slist_free (mlock_list);
+}
+
+static void
+print_mlock_per_service (const char *service, GSList *mlock_list, gpointer userdata)
+{
+ GSList *i;
+ HAL_INFO ((" mlocks for service %s", service));
+ for (i = mlock_list; i != NULL; i = g_slist_next (i)) {
+ MLockEntry *me = i->data;
+ HAL_INFO ((" lock_name=%s udi=%s", me->lock_name, me->udi));
+ }
+}
+
+static void
+dump_mlocks (void)
+{
+ HAL_INFO (("--- Dumping mlocks"));
+ g_hash_table_foreach (services_with_mlocks, (GHFunc) print_mlock_per_service, NULL);
+ HAL_INFO (("------------------"));
+}
+#endif
+
+/**
+ * device_acquire_mandatory_lock:
+ * @connection: D-BUS connection
+ * @message: Message
+ *
+ * Returns: What to do with the message
+ *
+ * Acquire a named mandatory lock on a device.
+ *
+ * <pre>
+ * void Device.AcquireMandatoryLock(string lock_name)
+ *
+ * raises org.freedesktop.Hal.NoSuchDevice,
+ * org.freedesktop.Hal.DeviceAlreadyLocked (if the caller already got a lock on the device with the given name)
+ * </pre>
+ */
+DBusHandlerResult
+device_acquire_mandatory_lock (DBusConnection *connection, DBusMessage *message)
+{
+ const char *udi;
+ HalDevice *d;
+ DBusMessage *reply;
+ DBusError error;
+ char *lock_name;
+ const char *sender;
+
+ HAL_TRACE (("entering"));
+
+ udi = dbus_message_get_path (message);
+
+ d = hal_device_store_find (hald_get_gdl (), udi);
+ if (d == NULL)
+ d = hal_device_store_find (hald_get_tdl (), udi);
+
+ if (d == NULL) {
+ raise_no_such_device (connection, message, udi);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &lock_name,
+ DBUS_TYPE_INVALID)) {
+ raise_syntax (connection, message, "AqcuireMandatoryLock");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ sender = dbus_message_get_sender (message);
+
+ if (!hal_device_acquire_lock (d, lock_name, sender)) {
+ raise_device_already_locked (connection, message, d);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ DIE (("No memory"));
+
+ if (!dbus_connection_send (connection, reply, NULL))
+ DIE (("No memory"));
+
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+
+#if 0
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ DIE (("No memory"));
+
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.dbus_name", lock_name);
+ if (hal_device_property_strlist_contains (d, buf, sender)) {
+ raise_device_already_locked (connection, message, d);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ hal_device_property_strlist_append (d, buf, sender);
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.locked", lock_name);
+ hal_device_property_set_bool (d, buf, TRUE);
+
+ GSList *mlock_list;
+ if (services_with_mlocks == NULL) {
+ services_with_mlocks = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) free_mlock_list);
+ mlock_list = g_slist_append (NULL, new_mlock_entry (lock_name, udi));
+ g_hash_table_insert (services_with_mlocks, g_strdup (sender), mlock_list);
+ } else {
+ mlock_list = g_hash_table_lookup (services_with_mlocks, sender);
+ if (mlock_list != NULL) {
+ /* head is guarenteed not to change */
+ g_slist_append (mlock_list, new_mlock_entry (lock_name, udi));
+ } else {
+ mlock_list = g_slist_append (NULL, new_mlock_entry (lock_name, udi));
+ g_hash_table_insert (services_with_mlocks, g_strdup (sender), mlock_list);
+ }
+ }
+ dump_mlocks ();
+
+ if (!dbus_connection_send (connection, reply, NULL))
+ DIE (("No memory"));
+
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+#endif
+
+
+/**
+ * device_release_mandatory_lock:
+ * @connection: D-BUS connection
+ * @message: Message
+ *
+ * Returns: What to do with the message
+ *
+ * Released a named mandatory lock on a device.
+ *
+ * <pre>
+ * void Device.ReleaseMandatoryLock(string lock_name)
+ *
+ * raises org.freedesktop.Hal.NoSuchDevice,
+ * org.freedesktop.Hal.DeviceNotLocked (if the caller haven't a lock on the device with the given name)
+ * </pre>
+ */
+DBusHandlerResult
+device_release_mandatory_lock (DBusConnection *connection, DBusMessage *message)
+{
+ const char *udi;
+ HalDevice *d;
+ DBusMessage *reply;
+ DBusError error;
+ const char *sender;
+ char *lock_name;
+
+ HAL_TRACE (("entering"));
+
+ udi = dbus_message_get_path (message);
+
+ d = hal_device_store_find (hald_get_gdl (), udi);
+ if (d == NULL)
+ d = hal_device_store_find (hald_get_tdl (), udi);
+
+ if (d == NULL) {
+ raise_no_such_device (connection, message, udi);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &lock_name,
+ DBUS_TYPE_INVALID)) {
+ raise_syntax (connection, message, "ReleaseMandatoryLock");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ sender = dbus_message_get_sender (message);
+
+ if (!hal_device_release_lock (d, lock_name, sender)) {
+ raise_device_already_locked (connection, message, d);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ DIE (("No memory"));
+
+ if (!dbus_connection_send (connection, reply, NULL))
+ DIE (("No memory"));
+
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+#if 0
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ DIE (("No memory"));
+
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.locked", lock_name);
+ if (!hal_device_property_get_bool (d, buf)) {
+ raise_device_not_locked (connection, message, d);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ sender = dbus_message_get_sender (message);
+
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.dbus_name", lock_name);
+ if (!hal_device_property_strlist_contains (d, buf, sender)) {
+ raise_permission_denied (connection, message, "Not locked by you");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (hal_device_property_get_strlist_length (d, buf) == 1) {
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.locked", lock_name);
+ hal_device_property_remove (d, buf);
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.dbus_name", lock_name);
+ hal_device_property_remove (d, buf);
+ } else {
+ hal_device_property_strlist_remove (d, buf, sender);
+ }
+
+ GSList *mlock_list;
+ mlock_list = g_hash_table_lookup (services_with_mlocks, sender);
+ if (mlock_list != NULL) {
+ GSList *i;
+ GSList *new_mlock_list = NULL;
+ for (i = mlock_list; i != NULL; i = g_slist_next (i)) {
+ MLockEntry *me = i->data;
+ if (!(strcmp (me->udi, udi) == 0 && strcmp (me->lock_name, lock_name) == 0)) {
+ new_mlock_list = g_slist_append (new_mlock_list, new_mlock_entry (lock_name, udi));
+ }
+ }
+ if (new_mlock_list != NULL)
+ g_hash_table_replace (services_with_mlocks, g_strdup (sender), new_mlock_list);
+ else
+ g_hash_table_remove (services_with_mlocks, sender);
+ }
+ dump_mlocks ();
+
+ if (!dbus_connection_send (connection, reply, NULL))
+ DIE (("No memory"));
+
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+#endif
+
+/*------------------------------------------------------------------------*/
+
static GHashTable *services_with_locks = NULL;
/**
@@ -3720,6 +4005,13 @@ do_introspect (DBusConnection *connection,
" <arg name=\"released_lock\" direction=\"out\" type=\"b\"/>\n"
" </method>\n"
+ " <method name=\"AcquireMandatoryLock\">\n"
+ " <arg name=\"lock_name\" direction=\"in\" type=\"s\"/>\n"
+ " </method>\n"
+ " <method name=\"ReleaseMandatoryLock\">\n"
+ " <arg name=\"lock_name\" direction=\"in\" type=\"s\"/>\n"
+ " </method>\n"
+
" <method name=\"StringListAppend\">\n"
" <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
" <arg name=\"value\" direction=\"in\" type=\"s\"/>\n"
@@ -4037,6 +4329,14 @@ hald_dbus_filter_handle_methods (DBusConnection *connection, DBusMessage *messag
return device_unlock (connection, message);
} else if (dbus_message_is_method_call (message,
"org.freedesktop.Hal.Device",
+ "AcquireMandatoryLock")) {
+ return device_acquire_mandatory_lock (connection, message);
+ } else if (dbus_message_is_method_call (message,
+ "org.freedesktop.Hal.Device",
+ "ReleaseMandatoryLock")) {
+ return device_release_mandatory_lock (connection, message);
+ } else if (dbus_message_is_method_call (message,
+ "org.freedesktop.Hal.Device",
"StringListAppend")) {
return device_string_list_append_prepend (connection, message, FALSE);
} else if (dbus_message_is_method_call (message,
@@ -4295,6 +4595,30 @@ hald_dbus_filter_function (DBusConnection * connection,
}
}
+ if (strlen (old_service_name) > 0)
+ hal_device_client_disconnected (old_service_name);
+#if 0
+ if (services_with_mlocks != NULL) {
+ GSList *i;
+ GSList *mlock_list;
+ mlock_list = g_hash_table_lookup (services_with_mlocks, new_service_name);
+ for (i = mlock_list; i != NULL; i = g_slist_next (i)) {
+#if 0
+ if (hal_device_property_get_strlist_length (d, buf) == 1) {
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.locked", lock_name);
+ hal_device_property_remove (d, buf);
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.dbus_name", lock_name);
+ hal_device_property_remove (d, buf);
+ } else {
+ hal_device_property_strlist_remove (d, buf, sender);
+ }
+#endif
+ }
+ g_hash_table_remove (services_with_mlocks, new_service_name);
+ dump_mlocks ();
+ }
+#endif
+
#ifdef HAVE_CONKIT
} else if (dbus_message_is_signal (message,
"org.freedesktop.ConsoleKit.Session",
diff --git a/hald/hald_dbus.h b/hald/hald_dbus.h
index d7f9accd..3fba19d7 100644
--- a/hald/hald_dbus.h
+++ b/hald/hald_dbus.h
@@ -64,6 +64,10 @@ DBusHandlerResult device_lock (DBusConnection *connection,
DBusMessage *message);
DBusHandlerResult device_unlock (DBusConnection *connection,
DBusMessage *message);
+DBusHandlerResult device_acquire_mandatory_lock (DBusConnection *connection,
+ DBusMessage *message);
+DBusHandlerResult device_release_mandatory_lock (DBusConnection *connection,
+ DBusMessage *message);
DBusHandlerResult manager_new_device (DBusConnection *connection,
DBusMessage *message,
dbus_bool_t local_interface);