summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HACKING8
-rw-r--r--configure.in1
-rw-r--r--doc/man/Makefile.am2
-rw-r--r--doc/man/hal-find-by-capability.1.in2
-rw-r--r--doc/man/hal-find-by-property.1.in2
-rw-r--r--doc/man/hal-get-property.1.in2
-rw-r--r--doc/man/hal-is-caller-locked-out.1.in2
-rw-r--r--doc/man/hal-lock.1.in7
-rw-r--r--doc/man/hal-set-property.1.in2
-rw-r--r--doc/spec/hal-spec-interfaces.xml64
-rw-r--r--doc/spec/hal-spec-locking.xml27
-rwxr-xr-xexamples/interface-locking-test.py10
-rw-r--r--hald/access-check.c122
-rw-r--r--hald/access-check.h5
-rw-r--r--hald/ci-tracker.c26
-rw-r--r--hald/ci-tracker.h1
-rw-r--r--hald/device.c77
-rw-r--r--hald/device.h10
-rw-r--r--hald/device_store.c63
-rw-r--r--hald/device_store.h10
-rw-r--r--hald/hald.c35
-rw-r--r--hald/hald_dbus.c305
-rw-r--r--hald/hald_dbus.h6
-rw-r--r--hald/hald_marshal.list2
-rw-r--r--libhal/libhal.c281
-rw-r--r--libhal/libhal.h79
-rw-r--r--tools/hal-lock.c116
-rw-r--r--tools/lshal.c75
28 files changed, 1272 insertions, 70 deletions
diff --git a/HACKING b/HACKING
index 7e9bb5b5..2a77fdc8 100644
--- a/HACKING
+++ b/HACKING
@@ -131,3 +131,11 @@ Coding Style
heuristically parse a file and accept not-well-formed
data). Avoiding heuristics is also important for security reasons;
if it looks funny, ignore it (or exit, or disconnect).
+
+Configuring the sources
+===
+
+To configure the HAL sources for a generic Linux desktop distribution
+using Linux 2.6.20, one should use
+
+--enable-console-kit --enable-acl-management --enable-docbook-docs --enable-acpi-ibm --enable-acpi-toshiba
diff --git a/configure.in b/configure.in
index 8e14728f..349102a3 100644
--- a/configure.in
+++ b/configure.in
@@ -140,6 +140,7 @@ AC_ARG_ENABLE(verbose-mode, [ --enable-verbose-mode support verbose debug
AC_ARG_ENABLE(docbook-docs, [ --enable-docbook-docs build documentation (requires xmlto)],enable_docbook_docs=$enableval,enable_docbook_docs=no)
AC_ARG_ENABLE(man-pages, [ --enable-man-pages build manual pages],enable_man_pages=$enableval,enable_man_pages=yes)
AM_CONDITIONAL(MAN_PAGES_ENABLED, test x$enable_man_pages = xyes)
+AC_SUBST(MAN_PAGES_ENABLED)
## eject
AC_ARG_WITH(eject, [ --with-eject=<path> Specify eject program. (default /usr/bin/eject)])
diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am
index 295c6948..4f22641c 100644
--- a/doc/man/Makefile.am
+++ b/doc/man/Makefile.am
@@ -10,4 +10,4 @@ endif # MAN_PAGES_ENABLED
EXTRA_DIST=$(man_MANS) $(MAN_IN_FILES)
clean-local:
- rm -f *~
+ rm -f *~ *.1
diff --git a/doc/man/hal-find-by-capability.1.in b/doc/man/hal-find-by-capability.1.in
index 5d7e1550..5c593ca3 100644
--- a/doc/man/hal-find-by-capability.1.in
+++ b/doc/man/hal-find-by-capability.1.in
@@ -19,7 +19,7 @@ device database by looking at device capabilities. For
more information about both the big picture and specific
.B HAL
properties, refer to the \fIHAL spec\fP which can be found in
-.I "/usr/share/doc/hal-0.5.9/spec/hal-spec.html"
+.I "/usr/share/doc/hal-@VERSION@/spec/hal-spec.html"
depending on the distribution.
.SH OPTIONS
diff --git a/doc/man/hal-find-by-property.1.in b/doc/man/hal-find-by-property.1.in
index 0dd29c3c..73bc99b2 100644
--- a/doc/man/hal-find-by-property.1.in
+++ b/doc/man/hal-find-by-property.1.in
@@ -19,7 +19,7 @@ device database by looking at device properties. For
more information about both the big picture and specific
.B HAL
properties, refer to the \fIHAL spec\fP which can be found in
-.I "/usr/share/doc/hal-0.5.9/spec/hal-spec.html"
+.I "/usr/share/doc/hal-@VERSION@/spec/hal-spec.html"
depending on the distribution.
.SH OPTIONS
diff --git a/doc/man/hal-get-property.1.in b/doc/man/hal-get-property.1.in
index d61e4594..87ab9d99 100644
--- a/doc/man/hal-get-property.1.in
+++ b/doc/man/hal-get-property.1.in
@@ -19,7 +19,7 @@ device database. For
more information about both the big picture and specific
.B HAL
properties, refer to the \fIHAL spec\fP which can be found in
-.I "/usr/share/doc/hal-0.5.9/spec/hal-spec.html"
+.I "/usr/share/doc/hal-@VERSION@/spec/hal-spec.html"
depending on the distribution.
.SH OPTIONS
diff --git a/doc/man/hal-is-caller-locked-out.1.in b/doc/man/hal-is-caller-locked-out.1.in
index 3df1c1d5..d5de39a1 100644
--- a/doc/man/hal-is-caller-locked-out.1.in
+++ b/doc/man/hal-is-caller-locked-out.1.in
@@ -17,7 +17,7 @@ locked out of a specific D-Bus interface on a specific device. For
more information about both the big picture and specific
.B HAL
properties, refer to the \fIHAL spec\fP which can be found in
-.I "/usr/share/doc/hal-0.5.9/spec/hal-spec.html"
+.I "/usr/share/doc/hal-@VERSION@/spec/hal-spec.html"
depending on the distribution.
.SH OPTIONS
diff --git a/doc/man/hal-lock.1.in b/doc/man/hal-lock.1.in
index abd6af37..a5c54924 100644
--- a/doc/man/hal-lock.1.in
+++ b/doc/man/hal-lock.1.in
@@ -17,7 +17,7 @@ either on a given device or globally. For more information about both
the big picture and the semantics of
.B HAL
locks, refer to the \fIHAL spec\fP which can be found in
-.I "/usr/share/doc/hal-0.5.9/spec/hal-spec.html"
+.I "/usr/share/doc/hal-@VERSION@/spec/hal-spec.html"
depending on the distribution.
.SH OPTIONS
@@ -36,6 +36,11 @@ is ommitted, the global lock will be tried.
.I "--exclusive"
Whether the lock can be held by others.
.TP
+.I "--exit-with-lock"
+Kill the program if the acquired lock is lost. This only makes sense if you pass a specific
+.I UDI
+due to the semantics of HAL locks.
+.TP
.I "--help"
Print out usage.
.TP
diff --git a/doc/man/hal-set-property.1.in b/doc/man/hal-set-property.1.in
index 2c4294c3..d62bfcda 100644
--- a/doc/man/hal-set-property.1.in
+++ b/doc/man/hal-set-property.1.in
@@ -19,7 +19,7 @@ device database. For
more information about both the big picture and specific
.B HAL
properties, refer to the \fIHAL spec\fP which can be found in
-.I "/usr/share/doc/hal-0.5.9/spec/hal-spec.html"
+.I "/usr/share/doc/hal-@VERSION@/spec/hal-spec.html"
depending on the distribution.
.SH OPTIONS
diff --git a/doc/spec/hal-spec-interfaces.xml b/doc/spec/hal-spec-interfaces.xml
index 9858c717..1ad525b0 100644
--- a/doc/spec/hal-spec-interfaces.xml
+++ b/doc/spec/hal-spec-interfaces.xml
@@ -112,6 +112,28 @@ $ dbus-send --system --print-reply --dest=org.freedesktop.Hal \
the global device list (GDL). Caller must be uid 0.
</entry>
</row>
+
+ <row>
+ <entry>AcquireGlobalInterfaceLock</entry>
+ <entry></entry>
+ <entry>String interface_name, Bool exclusive</entry>
+ <entry>Device.InterfaceAlreadyLocked</entry>
+ <entry>
+ Acquires a global lock on an interface. See
+ <xref linkend="locking"/> for details.
+ </entry>
+ </row>
+ <row>
+ <entry>ReleaseGlobalInterfaceLock</entry>
+ <entry></entry>
+ <entry>String interface_name</entry>
+ <entry>Device.InterfaceNotLocked</entry>
+ <entry>
+ Releases a global lock on an interface. See
+ <xref linkend="locking"/> for details.
+ </entry>
+ </row>
+
</tbody>
</tgroup>
</informaltable>
@@ -151,6 +173,20 @@ $ dbus-send --system --print-reply --dest=org.freedesktop.Hal \
A device gained a new capability.
</entry>
</row>
+ <row>
+ <entry>GlobalInterfaceLockAcquired</entry>
+ <entry>String lock_name, String lock_owner, Int num_holders</entry>
+ <entry>
+ Sent when a process acquires a global interface lock.
+ </entry>
+ </row>
+ <row>
+ <entry>GlobalInterfaceLockReleased</entry>
+ <entry>String lock_name, String lock_owner, Int num_holders</entry>
+ <entry>
+ Sent when a process releases a global interface lock.
+ </entry>
+ </row>
</tbody>
</tgroup>
</informaltable>
@@ -377,7 +413,6 @@ $ dbus-send --system --print-reply --dest=org.freedesktop.Hal \
Releases an advisory lock on the device. Returns TRUE if the lock was released.
</entry>
</row>
-
<row>
<entry>AcquireInterfaceLock</entry>
<entry></entry>
@@ -388,7 +423,6 @@ $ dbus-send --system --print-reply --dest=org.freedesktop.Hal \
device. See <xref linkend="locking"/> for details.
</entry>
</row>
-
<row>
<entry>ReleaseInterfaceLock</entry>
<entry></entry>
@@ -399,7 +433,6 @@ $ dbus-send --system --print-reply --dest=org.freedesktop.Hal \
<xref linkend="locking"/> for details.
</entry>
</row>
-
<row>
<entry>IsCallerLockedOut</entry>
<entry>Bool</entry>
@@ -412,6 +445,17 @@ $ dbus-send --system --print-reply --dest=org.freedesktop.Hal \
method. See <xref linkend="locking"/> for details.
</entry>
</row>
+ <row>
+ <entry>IsLockedByOthers</entry>
+ <entry>Bool</entry>
+ <entry>String interface_name</entry>
+ <entry></entry>
+ <entry>
+ Determines whether a determines other processes than the
+ caller holds a lock on the given device. See
+ <xref linkend="locking"/> for details.
+ </entry>
+ </row>
<row>
<entry>StringListAppend</entry>
@@ -539,6 +583,20 @@ $ dbus-send --system --print-reply --dest=org.freedesktop.Hal \
dedicated interface.).
</entry>
</row>
+ <row>
+ <entry>InterfaceLockAcquired</entry>
+ <entry>String lock_name, String lock_owner, Int num_holders</entry>
+ <entry>
+ Sent when a process acquires an interface lock on the device.
+ </entry>
+ </row>
+ <row>
+ <entry>InterfaceLockReleased</entry>
+ <entry>String lock_name, String lock_owner, Int num_holders</entry>
+ <entry>
+ Sent when a process releases an interface lock on the device.
+ </entry>
+ </row>
</tbody>
</tgroup>
</informaltable>
diff --git a/doc/spec/hal-spec-locking.xml b/doc/spec/hal-spec-locking.xml
index df62f0ae..7306dbb5 100644
--- a/doc/spec/hal-spec-locking.xml
+++ b/doc/spec/hal-spec-locking.xml
@@ -52,11 +52,28 @@
interface on the given device. The locker can specify whether
the lock is <emphasis>exclusive</emphasis> meaning if multiple
clients clients can hold the lock or if only one client can hold
- the lock at one time. If a client don't have access to a device,
- attempts to lock will fail with
+ the lock at one time. If a client don't have access to the
+ interface of the device, attempts to lock will fail with
a <literal>org.freedesktop.Hal.PermissionDenied</literal>
- exception. If another client already holds the lock exclusively,
- attempts from other clients to acquire the lock will fail with
+ exception. If a client loses access to a device (say, if his
+ session is switched away from using fast user switching) while
+ holding a lock, he will lose the lock; this can be tracked by
+ listening to the <literal>InterfaceLockReleased</literal>
+ signal.
+ </para>
+
+ <para>
+ All local clients, whether they are active or not, can always
+ lock interfaces on the root computer device object (this doesn't
+ mean that they are privileged to use the interfaces though) -
+ the rationale is that this device object represents shared
+ infrastructure, e.g. power management, and even inactive
+ sessions needs to participate in managing this.
+ </para>
+
+ <para>
+ If another client already holds a lock exclusively, attempts
+ from other clients to acquire the lock will fail with
the <literal>org.freedesktop.Hal.Device.InterfaceAlreadyLocked</literal>
exception even if they have access to the device.
</para>
@@ -218,7 +235,7 @@
<listitem>
<para>
- ... MUST check that no other process is holding the lock
+ ... MUST check that no other process is holding the lock (using the <literal>IsLockedByOthers</literal> method on the standard <literal>org.freedesktop.Hal.Device</literal> interface)
before calling into
the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
interface. If another process is holding the lock, it
diff --git a/examples/interface-locking-test.py b/examples/interface-locking-test.py
index ca60a910..51552b4c 100755
--- a/examples/interface-locking-test.py
+++ b/examples/interface-locking-test.py
@@ -22,11 +22,15 @@ device_volume = dbus.Interface(bus.get_object("org.freedesktop.Hal",
"org.freedesktop.Hal.Device.Volume")
#manager.AcquireGlobalInterfaceLock("org.freedesktop.Hal.Device.Storage", True)
-#time.sleep(2)
+#time.sleep(10)
#manager.ReleaseGlobalInterfaceLock("org.freedesktop.Hal.Device.Storage")
device.AcquireInterfaceLock("org.freedesktop.Hal.Device.Volume", False)
-device_volume.Mount("", "", [])
-time.sleep(2)
+#device_volume.Mount("", "", [])
+if device.IsLockedByOthers("org.freedesktop.Hal.Device.Volume"):
+ print "device is locked by another process too!"
+else:
+ print "we are the only process locking the device"
+time.sleep(10)
device.ReleaseInterfaceLock("org.freedesktop.Hal.Device.Volume")
diff --git a/hald/access-check.c b/hald/access-check.c
index 6f0542b6..ab68ce4f 100644
--- a/hald/access-check.c
+++ b/hald/access-check.c
@@ -110,17 +110,30 @@ out:
* access_check_caller_have_access_to_device:
* @cit: the CITracker object
* @device: The device to check for
- * @caller_unique_sysbus_name: The unique system bus connection name (e.g. ":1.43") of the caller
+ * @privilege: the type of access; right now this can be #NULL or
+ * "lock"; will be replaced by PolicyKit privileges in the future
+ * @caller_unique_sysbus_name: The unique system bus connection
+ * name (e.g. ":1.43") of the caller
*
* Determine if a given caller should have access to a device. This
* depends on how the security is set up and may change according to
* how the system is configured.
*
- * If ConsoleKit is used this function currently will return TRUE if,
- * and only if, the caller is in an active session. TODO: once
- * multi-seat is properly supported it will also depend on what seat
- * the device belongs to and what seat the caller's session belongs
- * to.
+ * If the privilege parameter is #NULL, it means "check if the caller
+ * can access D-Bus interfaces". If it is "lock" it means "check if
+ * the caller can lock an interface on the device".
+ *
+ * If ConsoleKit is used this function currently will return TRUE when
+ * privilege is #NULL if, and only if, the caller is in an active
+ * local session. If privilege is "lock" the only difference is that
+ * the it will always return TRUE for the root computer device
+ * object. This is used to ensure that any caller can always lock the
+ * SystemPowerManagement interface cf. the "Locking Guidelines"
+ * section of the HAL spec.
+ *
+ * (TODO: once PolicyKit and multi-seat is properly supported, this
+ * result from this function will also depend on what seat the device
+ * belongs to and what seat the caller's session belongs to.)
*
* If ConsoleKit is not used, this function will just return TRUE; the
* OS vendor is supposed to have locked down access to HAL through OS
@@ -132,7 +145,7 @@ out:
* Returns: TRUE iff the caller have access to the device.
*/
gboolean
-access_check_caller_have_access_to_device (CITracker *cit, HalDevice *device, const char *caller_unique_sysbus_name)
+access_check_caller_have_access_to_device (CITracker *cit, HalDevice *device, const char *privilege, const char *caller_unique_sysbus_name)
#ifdef HAVE_CONKIT
{
gboolean ret;
@@ -152,19 +165,30 @@ access_check_caller_have_access_to_device (CITracker *cit, HalDevice *device, co
goto out;
}
+ /* must be tracked by ConsoleKit */
if (ci_tracker_caller_get_ck_session_path (ci) == NULL) {
goto out;
}
+ /* require caller to be local */
+ if (!ci_tracker_caller_is_local (ci))
+ goto out;
- if (!ci_tracker_caller_in_active_session (ci)) {
+ /* allow inactive sessions to lock interfaces on root computer device object */
+ if (privilege != NULL &&
+ strcmp (privilege, "lock") == 0 &&
+ strcmp (hal_device_get_udi (device), "/org/freedesktop/Hal/devices/computer") == 0) {
+ ret = TRUE;
goto out;
}
-
+
+ /* require caller to be in active session */
+ if (!ci_tracker_caller_in_active_session (ci))
+ goto out;
+
ret = TRUE;
out:
return ret;
-
}
#else /* HAVE_CONKIT */
{
@@ -254,7 +278,7 @@ access_check_caller_locked_out (CITracker *cit,
for (n = 0; global_holders[n] != NULL; n++) {
if (strcmp (global_holders[n], caller_unique_sysbus_name) == 0) {
/* we are holding the global lock... */
- if (access_check_caller_have_access_to_device (cit, device, global_holders[n])) {
+ if (access_check_caller_have_access_to_device (cit, device, NULL, global_holders[n])) {
/* only applies if the caller can access the device... */
is_locked_by_self = TRUE;
/* this is good enough; we are holding the lock ourselves */
@@ -265,7 +289,7 @@ access_check_caller_locked_out (CITracker *cit,
/* Someone else is holding the global lock.. check if that someone
* actually have access to the device...
*/
- if (access_check_caller_have_access_to_device (cit, device, global_holders[n])) {
+ if (access_check_caller_have_access_to_device (cit, device, NULL, global_holders[n])) {
/* They certainly do. Mark as locked. */
is_locked = TRUE;
}
@@ -293,3 +317,77 @@ out:
return ret;
}
+
+
+/**
+ * access_check_locked_by_others:
+ * @cit: the CITracker object
+ * @device: The device to check for
+ * @caller_unique_sysbus_name: The unique system bus connection name (e.g. ":1.43") of the caller
+ * @interface_name: the interface to check for
+ *
+ * This method determines other processes than the caller holds a lock
+ * on the given device.
+ *
+ * Returns: TRUE iff other processes is holding a lock on the device
+ */
+gboolean
+access_check_locked_by_others (CITracker *cit,
+ HalDevice *device,
+ const char *caller_unique_sysbus_name,
+ const char *interface_name)
+{
+ int n;
+ gboolean ret;
+ char *global_lock_name;
+ char **holders;
+ char **global_holders;
+ HalDevice *computer;
+
+ global_lock_name = NULL;
+ holders = NULL;
+ global_holders = NULL;
+ ret = TRUE;
+
+ computer = hal_device_store_find (hald_get_gdl (), "/org/freedesktop/Hal/devices/computer");
+ if (computer == NULL)
+ computer = hal_device_store_find (hald_get_tdl (), "/org/freedesktop/Hal/devices/computer");
+ if (computer == NULL)
+ goto out;
+
+ global_lock_name = g_strdup_printf ("Global.%s", interface_name);
+
+ holders = hal_device_get_lock_holders (device, interface_name);
+ global_holders = hal_device_get_lock_holders (computer, global_lock_name);
+
+ if (holders != NULL) {
+ for (n = 0; holders[n] != NULL; n++) {
+ if (strcmp (holders[n], caller_unique_sysbus_name) != 0) {
+ /* someone else is holding the lock */
+ goto out;
+ }
+ }
+ }
+
+ if (global_holders != NULL) {
+ for (n = 0; global_holders[n] != NULL; n++) {
+ if (strcmp (global_holders[n], caller_unique_sysbus_name) != 0) {
+ /* someone else is holding the global lock... */
+ if (access_check_caller_have_access_to_device (cit, device, NULL, global_holders[n])) {
+ /* ... and they can can access the device */
+ goto out;
+ }
+ }
+ }
+ }
+
+ /* done all the checks so noone else is locking... */
+ ret = FALSE;
+
+out:
+ g_strfreev (global_holders);
+ g_strfreev (holders);
+ g_free (global_lock_name);
+ return ret;
+}
+
diff --git a/hald/access-check.h b/hald/access-check.h
index ab05f074..3da49ed4 100644
--- a/hald/access-check.h
+++ b/hald/access-check.h
@@ -35,10 +35,15 @@ gboolean access_check_message_caller_is_root_or_hal (CITracker *cit,
DBusMessage *message);
gboolean access_check_caller_have_access_to_device (CITracker *cit,
HalDevice *device,
+ const char *privilege,
const char *caller_unique_sysbus_name);
gboolean access_check_caller_locked_out (CITracker *cit,
HalDevice *device,
const char *caller_unique_sysbus_name,
const char *interface_name);
+gboolean access_check_locked_by_others (CITracker *cit,
+ HalDevice *device,
+ const char *caller_unique_sysbus_name,
+ const char *interface_name);
#endif /* ACCESS_CHECK_H */
diff --git a/hald/ci-tracker.c b/hald/ci-tracker.c
index 6a8bd816..af836547 100644
--- a/hald/ci-tracker.c
+++ b/hald/ci-tracker.c
@@ -52,6 +52,7 @@ struct CICallerInfo_s {
#ifdef HAVE_CONKIT
pid_t pid; /* process ID of caller */
gboolean in_active_session; /* caller is in an active session */
+ gboolean is_local; /* session is on a local seat */
char *session_objpath; /* obj path of ConsoleKit session */
#endif
char *system_bus_unique_name; /* unique name of caller on the system bus */
@@ -261,6 +262,25 @@ ci_tracker_get_info (CITracker *cit, const char *system_bus_unique_name)
dbus_message_iter_get_basic (&iter, &ci->in_active_session);
dbus_message_unref (message);
dbus_message_unref (reply);
+
+
+ message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit",
+ ci->session_objpath,
+ "org.freedesktop.ConsoleKit.Session",
+ "IsLocal");
+ dbus_error_init (&error);
+ reply = dbus_connection_send_with_reply_and_block (cit->dbus_connection, message, -1, &error);
+ if (reply == NULL || dbus_error_is_set (&error)) {
+ HAL_WARNING (("Error doing IsLocal on ConsoleKit: %s: %s", error.name, error.message));
+ dbus_message_unref (message);
+ if (reply != NULL)
+ dbus_message_unref (reply);
+ goto error;
+ }
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_get_basic (&iter, &ci->is_local);
+ dbus_message_unref (message);
+ dbus_message_unref (reply);
store_caller_info:
#endif /* HAVE_CONKIT */
@@ -311,6 +331,12 @@ ci_tracker_caller_get_pid (CICallerInfo *ci)
}
gboolean
+ci_tracker_caller_is_local (CICallerInfo *ci)
+{
+ return ci->is_local;
+}
+
+gboolean
ci_tracker_caller_in_active_session (CICallerInfo *ci)
{
return ci->in_active_session;
diff --git a/hald/ci-tracker.h b/hald/ci-tracker.h
index 7d762e98..5b0794a7 100644
--- a/hald/ci-tracker.h
+++ b/hald/ci-tracker.h
@@ -63,6 +63,7 @@ uid_t ci_tracker_caller_get_uid (CICallerInfo *ci);
const char *ci_tracker_caller_get_sysbus_unique_name (CICallerInfo *ci);
#ifdef HAVE_CONKIT
pid_t ci_tracker_caller_get_pid (CICallerInfo *ci);
+gboolean ci_tracker_caller_is_local (CICallerInfo *ci);
gboolean ci_tracker_caller_in_active_session (CICallerInfo *ci);
const char *ci_tracker_caller_get_ck_session_path (CICallerInfo *ci);
#endif
diff --git a/hald/device.c b/hald/device.c
index f1f58477..e95cc19f 100644
--- a/hald/device.c
+++ b/hald/device.c
@@ -376,6 +376,8 @@ struct _HalDevicePrivate
enum {
PROPERTY_CHANGED,
CAPABILITY_ADDED,
+ LOCK_ACQUIRED,
+ LOCK_RELEASED,
LAST_SIGNAL
};
@@ -441,6 +443,30 @@ hal_device_class_init (HalDeviceClass *klass)
hald_marshal_VOID__STRING,
G_TYPE_NONE, 1,
G_TYPE_STRING);
+
+ signals[LOCK_ACQUIRED] =
+ g_signal_new ("lock_acquired",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (HalDeviceClass,
+ lock_acquired),
+ NULL, NULL,
+ hald_marshal_VOID__STRING_STRING,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+
+ signals[LOCK_RELEASED] =
+ g_signal_new ("lock_released",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (HalDeviceClass,
+ lock_released),
+ NULL, NULL,
+ hald_marshal_VOID__STRING_STRING,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
}
static void
@@ -1654,6 +1680,8 @@ hal_device_acquire_lock (HalDevice *device, const char *lock_name, gboolean excl
add_to_locked_set (device);
+ g_signal_emit (device, signals[LOCK_ACQUIRED], 0, lock_name, sender);
+
ret = TRUE;
out:
return ret;
@@ -1711,6 +1739,8 @@ hal_device_release_lock (HalDevice *device, const char *lock_name, const char *s
hal_device_property_strlist_remove (device, buf, sender);
}
+ g_signal_emit (device, signals[LOCK_RELEASED], 0, lock_name, sender);
+
ret = TRUE;
out:
@@ -1740,6 +1770,32 @@ hal_device_get_lock_holders (HalDevice *device, const char *lock_name)
}
/**
+ * hal_device_get_lock_holders:
+ * @device: the device to check for
+ * @lock_name: the lock name
+ *
+ * Get the number of lock holders on a device.
+ *
+ * Returns: Number of callers holding the given lock.
+ */
+int
+hal_device_get_num_lock_holders (HalDevice *device, const char *lock_name)
+{
+ int num;
+ char **holders;
+
+ num = 0;
+ holders = hal_device_get_lock_holders (device, lock_name);
+ if (holders == NULL)
+ goto out;
+
+ num = g_strv_length (holders);
+ g_strfreev (holders);
+out:
+ return num;
+}
+
+/**
* hal_device_client_disconnected:
* @sender: the client that disconnected from the bus
*
@@ -1756,20 +1812,19 @@ hal_device_client_disconnected (const char *sender)
for (i = locked_devices; i != NULL; i = g_slist_next (i)) {
HalDevice *device = i->data;
- GSList *locks;
- GSList *j;
- GSList *k;
+ char **locks;
+ int n;
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);
+ locks = hal_device_property_dup_strlist_as_strv (device, "info.named_locks");
+ if (locks != NULL) {
+ for (n = 0; locks[n] != NULL; n++) {
+ char *lock_name = locks[n];
+ HAL_INFO (("Lock '%s'", lock_name));
+ hal_device_release_lock (device, lock_name, sender);
+ }
+ g_strfreev (locks);
}
}
}
diff --git a/hald/device.h b/hald/device.h
index 5dd11f57..1942e2f2 100644
--- a/hald/device.h
+++ b/hald/device.h
@@ -53,6 +53,14 @@ struct _HalDeviceClass {
void (*capability_added) (HalDevice *device,
const char *capability);
+
+ void (*lock_acquired) (HalDevice *device,
+ const char *lock_name,
+ const char *lock_owner);
+
+ void (*lock_released) (HalDevice *device,
+ const char *lock_name,
+ const char *lock_owner);
};
#define HAL_TYPE_DEVICE (hal_device_get_type ())
@@ -212,6 +220,8 @@ gboolean hal_device_release_lock (HalDevice *device, const char *lock_name,
char **hal_device_get_lock_holders (HalDevice *device, const char *lock_name);
+int hal_device_get_num_lock_holders (HalDevice *device, const char *lock_name);
+
/* static method */
void hal_device_client_disconnected (const char *sender);
diff --git a/hald/device_store.c b/hald/device_store.c
index 7c06aabe..23c054d3 100644
--- a/hald/device_store.c
+++ b/hald/device_store.c
@@ -41,6 +41,8 @@ enum {
STORE_CHANGED,
DEVICE_PROPERTY_CHANGED,
DEVICE_CAPABILITY_ADDED,
+ DEVICE_LOCK_ACQUIRED,
+ DEVICE_LOCK_RELEASED,
LAST_SIGNAL
};
@@ -103,6 +105,33 @@ hal_device_store_class_init (HalDeviceStoreClass *klass)
G_TYPE_NONE, 2,
G_TYPE_OBJECT,
G_TYPE_STRING);
+
+ signals[DEVICE_LOCK_ACQUIRED] =
+ g_signal_new ("device_lock_acquired",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (HalDeviceStoreClass,
+ device_lock_acquired),
+ NULL, NULL,
+ hald_marshal_VOID__OBJECT_STRING_STRING,
+ G_TYPE_NONE, 3,
+ G_TYPE_OBJECT,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+
+ signals[DEVICE_LOCK_RELEASED] =
+ g_signal_new ("device_lock_released",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (HalDeviceStoreClass,
+ device_lock_released),
+ NULL, NULL,
+ hald_marshal_VOID__OBJECT_STRING_STRING,
+ G_TYPE_NONE, 3,
+ G_TYPE_OBJECT,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+
}
static void
@@ -169,6 +198,30 @@ emit_device_capability_added (HalDevice *device,
device, capability);
}
+static void
+emit_device_lock_acquired (HalDevice *device,
+ const char *lock_name,
+ const char *lock_owner,
+ gpointer data)
+{
+ HalDeviceStore *store = HAL_DEVICE_STORE (data);
+
+ g_signal_emit (store, signals[DEVICE_LOCK_ACQUIRED], 0,
+ device, lock_name, lock_owner);
+}
+
+static void
+emit_device_lock_released (HalDevice *device,
+ const char *lock_name,
+ const char *lock_owner,
+ gpointer data)
+{
+ HalDeviceStore *store = HAL_DEVICE_STORE (data);
+
+ g_signal_emit (store, signals[DEVICE_LOCK_RELEASED], 0,
+ device, lock_name, lock_owner);
+}
+
void
hal_device_store_add (HalDeviceStore *store, HalDevice *device)
{
@@ -187,6 +240,10 @@ hal_device_store_add (HalDeviceStore *store, HalDevice *device)
G_CALLBACK (emit_device_property_changed), store);
g_signal_connect (device, "capability_added",
G_CALLBACK (emit_device_capability_added), store);
+ g_signal_connect (device, "lock_acquired",
+ G_CALLBACK (emit_device_lock_acquired), store);
+ g_signal_connect (device, "lock_released",
+ G_CALLBACK (emit_device_lock_released), store);
g_signal_emit (store, signals[STORE_CHANGED], 0, device, TRUE);
@@ -208,6 +265,12 @@ hal_device_store_remove (HalDeviceStore *store, HalDevice *device)
g_signal_handlers_disconnect_by_func (device,
(gpointer)emit_device_capability_added,
store);
+ g_signal_handlers_disconnect_by_func (device,
+ (gpointer)emit_device_lock_acquired,
+ store);
+ g_signal_handlers_disconnect_by_func (device,
+ (gpointer)emit_device_lock_released,
+ store);
g_signal_emit (store, signals[STORE_CHANGED], 0, device, FALSE);
diff --git a/hald/device_store.h b/hald/device_store.h
index 0e1578a4..300f4c70 100644
--- a/hald/device_store.h
+++ b/hald/device_store.h
@@ -58,6 +58,16 @@ struct _HalDeviceStoreClass {
HalDevice *device,
const char *capability);
+
+ void (*device_lock_acquired) (HalDeviceStore *store,
+ HalDevice *device,
+ const char *lock_name,
+ const char *lock_owner);
+
+ void (*device_lock_released) (HalDeviceStore *store,
+ HalDevice *device,
+ const char *lock_name,
+ const char *lock_owner);
};
#define HAL_TYPE_DEVICE_STORE (hal_device_store_get_type ())
diff --git a/hald/hald.c b/hald/hald.c
index c130ca80..1a13a316 100644
--- a/hald/hald.c
+++ b/hald/hald.c
@@ -161,6 +161,32 @@ gdl_capability_added (HalDeviceStore *store, HalDevice *device,
/*hal_callout_capability (device, capability, TRUE)*/;
}
+static void
+gdl_lock_acquired (HalDeviceStore *store, HalDevice *device, const char *lock_name, const char *lock_owner)
+{
+ if (hal_device_are_all_addons_ready (device)) {
+ if (strncmp (lock_name, "Global.", 7) == 0 &&
+ strcmp (hal_device_get_udi (device), "/org/freedesktop/Hal/devices/computer") == 0) {
+ manager_send_signal_interface_lock_acquired (lock_name + 7, lock_owner);
+ } else {
+ device_send_signal_interface_lock_acquired (device, lock_name, lock_owner);
+ }
+ }
+}
+
+static void
+gdl_lock_released (HalDeviceStore *store, HalDevice *device, const char *lock_name, const char *lock_owner)
+{
+ if (hal_device_are_all_addons_ready (device)) {
+ if (strncmp (lock_name, "Global.", 7) == 0 &&
+ strcmp (hal_device_get_udi (device), "/org/freedesktop/Hal/devices/computer") == 0) {
+ manager_send_signal_interface_lock_released (lock_name + 7, lock_owner);
+ } else {
+ device_send_signal_interface_lock_released (device, lock_name, lock_owner);
+ }
+ }
+}
+
HalDeviceStore *
hald_get_gdl (void)
{
@@ -176,6 +202,15 @@ hald_get_gdl (void)
g_signal_connect (global_device_list,
"device_capability_added",
G_CALLBACK (gdl_capability_added), NULL);
+ g_signal_connect (global_device_list,
+ "device_property_changed",
+ G_CALLBACK (gdl_property_changed), NULL);
+ g_signal_connect (global_device_list,
+ "device_lock_acquired",
+ G_CALLBACK (gdl_lock_acquired), NULL);
+ g_signal_connect (global_device_list,
+ "device_lock_released",
+ G_CALLBACK (gdl_lock_released), NULL);
}
return global_device_list;
diff --git a/hald/hald_dbus.c b/hald/hald_dbus.c
index 28169475..90dc9f7c 100644
--- a/hald/hald_dbus.c
+++ b/hald/hald_dbus.c
@@ -761,6 +761,146 @@ out:
;
}
+void
+manager_send_signal_interface_lock_acquired (const char *interface_name, const char *sender)
+{
+ const char *udi;
+ char *lock_name;
+ int num_locks;
+ HalDevice *d;
+ DBusMessage *message;
+ DBusMessageIter iter;
+
+ if (dbus_connection == NULL || hald_is_initialising)
+ goto out;
+
+ udi = "/org/freedesktop/Hal/devices/computer";
+ d = hal_device_store_find (hald_get_gdl (), udi);
+ if (d == NULL)
+ d = hal_device_store_find (hald_get_tdl (), udi);
+ if (d == NULL)
+ goto out;
+
+ lock_name = g_strdup_printf ("Global.%s", interface_name);
+ num_locks = hal_device_get_num_lock_holders (d, lock_name);
+ g_free (lock_name);
+
+ message = dbus_message_new_signal ("/org/freedesktop/Hal/Manager",
+ "org.freedesktop.Hal.Manager",
+ "GlobalInterfaceLockAcquired");
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface_name);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &sender);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &num_locks);
+
+ if (!dbus_connection_send (dbus_connection, message, NULL))
+ DIE (("error broadcasting message"));
+
+ dbus_message_unref (message);
+out:
+ ;
+}
+
+void
+manager_send_signal_interface_lock_released (const char *interface_name, const char *sender)
+{
+ const char *udi;
+ char *lock_name;
+ int num_locks;
+ HalDevice *d;
+ DBusMessage *message;
+ DBusMessageIter iter;
+
+ if (dbus_connection == NULL || hald_is_initialising)
+ goto out;
+
+ udi = "/org/freedesktop/Hal/devices/computer";
+ d = hal_device_store_find (hald_get_gdl (), udi);
+ if (d == NULL)
+ d = hal_device_store_find (hald_get_tdl (), udi);
+ if (d == NULL)
+ goto out;
+
+ lock_name = g_strdup_printf ("Global.%s", interface_name);
+ num_locks = hal_device_get_num_lock_holders (d, lock_name);
+ g_free (lock_name);
+
+ message = dbus_message_new_signal ("/org/freedesktop/Hal/Manager",
+ "org.freedesktop.Hal.Manager",
+ "GlobalInterfaceLockReleased");
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface_name);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &sender);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &num_locks);
+
+ if (!dbus_connection_send (dbus_connection, message, NULL))
+ DIE (("error broadcasting message"));
+
+ dbus_message_unref (message);
+out:
+ ;
+}
+
+void
+device_send_signal_interface_lock_acquired (HalDevice *device, const char *interface_name, const char *sender)
+{
+ int num_locks;
+ DBusMessage *message;
+ DBusMessageIter iter;
+
+ if (dbus_connection == NULL || hald_is_initialising)
+ goto out;
+
+ num_locks = hal_device_get_num_lock_holders (device, interface_name);
+
+ message = dbus_message_new_signal (hal_device_get_udi (device),
+ "org.freedesktop.Hal.Device",
+ "InterfaceLockAcquired");
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface_name);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &sender);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &num_locks);
+
+ if (!dbus_connection_send (dbus_connection, message, NULL))
+ DIE (("error broadcasting message"));
+
+ dbus_message_unref (message);
+out:
+ ;
+}
+
+void
+device_send_signal_interface_lock_released (HalDevice *device, const char *interface_name, const char *sender)
+{
+ int num_locks;
+ DBusMessage *message;
+ DBusMessageIter iter;
+
+ if (dbus_connection == NULL || hald_is_initialising)
+ goto out;
+
+ num_locks = hal_device_get_num_lock_holders (device, interface_name);
+
+ message = dbus_message_new_signal (hal_device_get_udi (device),
+ "org.freedesktop.Hal.Device",
+ "InterfaceLockReleased");
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface_name);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &sender);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &num_locks);
+
+ if (!dbus_connection_send (dbus_connection, message, NULL))
+ DIE (("error broadcasting message"));
+
+ dbus_message_unref (message);
+out:
+ ;
+}
+
static void
foreach_property_append (HalDevice *device,
const char *key,
@@ -1903,7 +2043,7 @@ device_acquire_interface_lock (DBusConnection *connection, DBusMessage *message,
sender = dbus_message_get_sender (message);
if (!local_interface) {
- if (!access_check_caller_have_access_to_device (ci_tracker, d, sender)) {
+ if (!access_check_caller_have_access_to_device (ci_tracker, d, "lock", sender)) {
raise_permission_denied (connection, message, "AcquireInterfaceLock: no access to device");
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -1960,7 +2100,7 @@ device_release_interface_lock (DBusConnection *connection, DBusMessage *message,
sender = dbus_message_get_sender (message);
if (!local_interface) {
- if (!access_check_caller_have_access_to_device (ci_tracker, d, sender)) {
+ if (!access_check_caller_have_access_to_device (ci_tracker, d, "lock", sender)) {
raise_permission_denied (connection, message, "ReleaseInterfaceLock: no access to device");
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -1990,7 +2130,6 @@ device_release_interface_lock (DBusConnection *connection, DBusMessage *message,
return DBUS_HANDLER_RESULT_HANDLED;
}
-
static DBusHandlerResult
device_is_caller_locked_out (DBusConnection *connection, DBusMessage *message, dbus_bool_t local_interface)
{
@@ -2049,6 +2188,62 @@ device_is_caller_locked_out (DBusConnection *connection, DBusMessage *message, d
return DBUS_HANDLER_RESULT_HANDLED;
}
+
+/*------------------------------------------------------------------------*/
+
+static DBusHandlerResult
+device_is_locked_by_others (DBusConnection *connection, DBusMessage *message, dbus_bool_t local_interface)
+{
+ const char *udi;
+ HalDevice *d;
+ DBusMessage *reply;
+ DBusError error;
+ const char *sender;
+ char *interface_name;
+ dbus_bool_t result;
+ DBusMessageIter iter;
+
+ 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;
+ }
+
+ sender = dbus_message_get_sender (message);
+
+ /* anyone can ask this question */
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &interface_name,
+ DBUS_TYPE_INVALID)) {
+ raise_syntax (connection, message, "IsLockedByOthers");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ result = access_check_locked_by_others (ci_tracker, d, sender, interface_name);
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ DIE (("No memory"));
+
+ dbus_message_iter_init_append (reply, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &result);
+
+ if (!dbus_connection_send (connection, reply, NULL))
+ DIE (("No memory"));
+
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
/*------------------------------------------------------------------------*/
static DBusHandlerResult
@@ -3707,6 +3902,16 @@ do_introspect (DBusConnection *connection,
" <arg name=\"udi\" type=\"s\"/>\n"
" <arg name=\"cap_name\" type=\"s\"/>\n"
" </signal>\n"
+ " <signal name=\"GlobalInterfaceLockAcquired\">\n"
+ " <arg name=\"interface_name\" type=\"s\"/>\n"
+ " <arg name=\"lock_holder\" type=\"s\"/>\n"
+ " <arg name=\"num_locks\" type=\"i\"/>\n"
+ " </signal>\n"
+ " <signal name=\"GlobalInterfaceLockReleased\">\n"
+ " <arg name=\"interface_name\" type=\"s\"/>\n"
+ " <arg name=\"lock_holder\" type=\"s\"/>\n"
+ " <arg name=\"num_locks\" type=\"i\"/>\n"
+ " </signal>\n"
" </interface>\n");
} else {
@@ -3816,6 +4021,10 @@ do_introspect (DBusConnection *connection,
" <arg name=\"caller_sysbus_name\" direction=\"in\" type=\"s\"/>\n"
" <arg name=\"whether_caller_is_locked_out\" direction=\"out\" type=\"b\"/>\n"
" </method>\n"
+ " <method name=\"IsLockedByOthers\">\n"
+ " <arg name=\"interface_name\" direction=\"in\" type=\"s\"/>\n"
+ " <arg name=\"whether_it_is_locked_by_others\" direction=\"out\" type=\"b\"/>\n"
+ " </method>\n"
" <method name=\"StringListAppend\">\n"
" <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
@@ -3860,6 +4069,17 @@ do_introspect (DBusConnection *connection,
" <arg name=\"cond_details\" type=\"s\"/>\n"
" </signal>\n"
+ " <signal name=\"InterfaceLockAcquired\">\n"
+ " <arg name=\"interface_name\" type=\"s\"/>\n"
+ " <arg name=\"lock_holder\" type=\"s\"/>\n"
+ " <arg name=\"num_locks\" type=\"i\"/>\n"
+ " </signal>\n"
+ " <signal name=\"InterfaceLockReleased\">\n"
+ " <arg name=\"interface_name\" type=\"s\"/>\n"
+ " <arg name=\"lock_holder\" type=\"s\"/>\n"
+ " <arg name=\"num_locks\" type=\"i\"/>\n"
+ " </signal>\n"
+
" </interface>\n");
HalDeviceStrListIter if_iter;
@@ -4085,7 +4305,10 @@ hald_dbus_filter_handle_methods (DBusConnection *connection, DBusMessage *messag
"org.freedesktop.Hal.Device",
"IsCallerLockedOut")) {
return device_is_caller_locked_out (connection, message, local_interface);
-
+ } else if (dbus_message_is_method_call (message,
+ "org.freedesktop.Hal.Device",
+ "IsLockedByOthers")) {
+ return device_is_locked_by_others (connection, message, local_interface);
} else if (dbus_message_is_method_call (message,
"org.freedesktop.Hal.Device",
"GetAllProperties")) {
@@ -4249,7 +4472,7 @@ hald_dbus_filter_handle_methods (DBusConnection *connection, DBusMessage *messag
/* bypass security checks on direct connections */
if (!local_interface) {
- if (!access_check_caller_have_access_to_device (ci_tracker, d, caller)) {
+ if (!access_check_caller_have_access_to_device (ci_tracker, d, NULL, caller)) {
HAL_INFO (("Caller '%s' does not have access to device '%s'", caller, udi));
/* TODO: need to fix up reason */
raise_permission_denied (connection, message, "Not in active session");
@@ -4366,13 +4589,6 @@ DBusHandlerResult
hald_dbus_filter_function (DBusConnection * connection,
DBusMessage * message, void *user_data)
{
-#ifdef HAVE_CONKIT
- /* TODO: only push the appropriate messages to the tracker; see ck-tracker.h */
- if (ck_tracker != NULL) {
- ck_tracker_process_system_bus_message (ck_tracker, message);
- }
-#endif
-
if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") &&
strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) {
@@ -4439,10 +4655,26 @@ hald_dbus_filter_function (DBusConnection * connection,
HAL_INFO (("active=%d for session %s", is_active, session_objpath));
ci_tracker_active_changed (ci_tracker, session_objpath, is_active);
#endif /* HAVE_CONKIT */
- } else
+ } else {
+
+#ifdef HAVE_CONKIT
+ /* TODO: only push the appropriate messages to the tracker; see ck-tracker.h */
+ if (ck_tracker != NULL) {
+ ck_tracker_process_system_bus_message (ck_tracker, message);
+ }
+#endif
return hald_dbus_filter_handle_methods (connection, message, user_data, FALSE);
+ }
out:
+
+#ifdef HAVE_CONKIT
+ /* TODO: only push the appropriate messages to the tracker; see ck-tracker.h */
+ if (ck_tracker != NULL) {
+ ck_tracker_process_system_bus_message (ck_tracker, message);
+ }
+#endif
+
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -4698,6 +4930,50 @@ hald_dbus_seat_removed (CKTracker *tracker, CKSeat *seat, void *user_data)
/* TODO: we could run callouts here... but they wouldn't do anything useful right now */
}
+static gboolean
+validate_lock_for_device (HalDeviceStore *store,
+ HalDevice *device,
+ gpointer user_data)
+{
+ int n, m;
+ char **holders;
+ char **locked_interfaces;
+
+ locked_interfaces = hal_device_property_dup_strlist_as_strv (device, "info.named_locks");
+ if (locked_interfaces == NULL)
+ goto out;
+
+ for (n = 0; locked_interfaces[n] != NULL; n++) {
+ holders = hal_device_get_lock_holders (device, locked_interfaces[n]);
+ if (holders == NULL)
+ continue;
+ for (m = 0; holders[m] != NULL; m++) {
+ HAL_INFO (("Validating lock holder '%s' on interface '%s' on udi '%s'",
+ holders[m], locked_interfaces[n], hal_device_get_udi (device)));
+
+ if (!access_check_caller_have_access_to_device (ci_tracker, device, "lock", holders[m])) {
+ HAL_INFO (("Kicking out lock holder '%s' on interface '%s' on udi '%s' "
+ "as he no longer has access to the device",
+ holders[m], locked_interfaces[n], hal_device_get_udi (device)));
+ hal_device_release_lock (device, locked_interfaces[n], holders[m]);
+ }
+
+ }
+ g_strfreev (holders);
+ }
+
+ g_strfreev (locked_interfaces);
+out:
+ return TRUE;
+}
+
+static void
+validate_locks (void)
+{
+ hal_device_store_foreach (hald_get_tdl (), validate_lock_for_device, NULL);
+ hal_device_store_foreach (hald_get_gdl (), validate_lock_for_device, NULL);
+}
+
static void
hald_dbus_session_active_changed (CKTracker *tracker, CKSession *session, void *user_data)
{
@@ -4713,6 +4989,9 @@ hald_dbus_session_active_changed (CKTracker *tracker, CKSession *session, void *
ck_session_get_id (session),
ck_session_is_active (session) ? "ACTIVE" : "INACTIVE"));
+ /* revalidate all locks (to remove locks from callers in that session who no longer has access to devices */
+ validate_locks ();
+
d = hal_device_store_find (hald_get_gdl (), "/org/freedesktop/Hal/devices/computer");
if (d == NULL) {
d = hal_device_store_find (hald_get_tdl (), "/org/freedesktop/Hal/devices/computer");
diff --git a/hald/hald_dbus.h b/hald/hald_dbus.h
index d7f9accd..4a5deb18 100644
--- a/hald/hald_dbus.h
+++ b/hald/hald_dbus.h
@@ -83,6 +83,12 @@ void manager_send_signal_device_removed (HalDevice *device);
void manager_send_signal_new_capability (HalDevice *device,
const char *capability);
+void manager_send_signal_interface_lock_acquired (const char *interface_name, const char *sender);
+void manager_send_signal_interface_lock_released (const char *interface_name, const char *sender);
+
+void device_send_signal_interface_lock_acquired (HalDevice *device, const char *interface_name, const char *sender);
+void device_send_signal_interface_lock_released (HalDevice *device, const char *interface_name, const char *sender);
+
void device_send_signal_property_modified (HalDevice *device,
const char *key,
dbus_bool_t removed,
diff --git a/hald/hald_marshal.list b/hald/hald_marshal.list
index 8e3863a8..14dd6f82 100644
--- a/hald/hald_marshal.list
+++ b/hald/hald_marshal.list
@@ -1,3 +1,5 @@
+VOID:OBJECT,STRING,STRING
+VOID:STRING,STRING
VOID:STRING,BOOL,BOOL
VOID:STRING
VOID:OBJECT,BOOL
diff --git a/libhal/libhal.c b/libhal/libhal.c
index b5f3c1e7..8e760321 100644
--- a/libhal/libhal.c
+++ b/libhal/libhal.c
@@ -245,6 +245,18 @@ struct LibHalContext_s {
/** A non-continous event on the device occured */
LibHalDeviceCondition device_condition;
+
+ /** A global interface lock is acquired */
+ LibHalGlobalInterfaceLockAcquired global_interface_lock_acquired;
+
+ /** A global interface lock is released */
+ LibHalGlobalInterfaceLockReleased global_interface_lock_released;
+
+ /** An interface lock is acquired */
+ LibHalInterfaceLockAcquired interface_lock_acquired;
+
+ /** An interface lock is released */
+ LibHalInterfaceLockReleased interface_lock_released;
void *user_data; /**< User data */
};
@@ -512,10 +524,11 @@ oom:
return NULL;
}
-/* libhal_property_set_sort:
+/**
+ * libhal_property_set_sort:
* @set: property-set to sort
*
- * sort all properties according to property name
+ * Sort all properties according to property name.
*/
void
libhal_property_set_sort (LibHalPropertySet *set)
@@ -824,6 +837,38 @@ filter_func (DBusConnection * connection,
LIBHAL_FREE_DBUS_ERROR(&error);
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ } else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Manager","GlobalInterfaceLockAcquired")) {
+ char *lock_name;
+ char *lock_owner;
+ int num_locks;
+ if (dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &lock_name,
+ DBUS_TYPE_STRING, &lock_owner,
+ DBUS_TYPE_INT32, &num_locks,
+ DBUS_TYPE_INVALID)) {
+ if (ctx->global_interface_lock_acquired != NULL) {
+ ctx->global_interface_lock_acquired (ctx, lock_name, lock_owner, num_locks);
+ }
+ } else {
+ LIBHAL_FREE_DBUS_ERROR(&error);
+ }
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ } else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Manager","GlobalInterfaceLockReleased")) {
+ char *lock_name;
+ char *lock_owner;
+ int num_locks;
+ if (dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &lock_name,
+ DBUS_TYPE_STRING, &lock_owner,
+ DBUS_TYPE_INT32, &num_locks,
+ DBUS_TYPE_INVALID)) {
+ if (ctx->global_interface_lock_released != NULL) {
+ ctx->global_interface_lock_released (ctx, lock_name, lock_owner, num_locks);
+ }
+ } else {
+ LIBHAL_FREE_DBUS_ERROR(&error);
+ }
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
} else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Device", "Condition")) {
char *condition_name;
char *condition_detail;
@@ -838,6 +883,38 @@ filter_func (DBusConnection * connection,
LIBHAL_FREE_DBUS_ERROR(&error);
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ } else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Device","InterfaceLockAcquired")) {
+ char *lock_name;
+ char *lock_owner;
+ int num_locks;
+ if (dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &lock_name,
+ DBUS_TYPE_STRING, &lock_owner,
+ DBUS_TYPE_INT32, &num_locks,
+ DBUS_TYPE_INVALID)) {
+ if (ctx->interface_lock_acquired != NULL) {
+ ctx->interface_lock_acquired (ctx, object_path, lock_name, lock_owner, num_locks);
+ }
+ } else {
+ LIBHAL_FREE_DBUS_ERROR(&error);
+ }
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ } else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Device","InterfaceLockReleased")) {
+ char *lock_name;
+ char *lock_owner;
+ int num_locks;
+ if (dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &lock_name,
+ DBUS_TYPE_STRING, &lock_owner,
+ DBUS_TYPE_INT32, &num_locks,
+ DBUS_TYPE_INVALID)) {
+ if (ctx->interface_lock_released != NULL) {
+ ctx->interface_lock_released (ctx, object_path, lock_name, lock_owner, num_locks);
+ }
+ } else {
+ LIBHAL_FREE_DBUS_ERROR(&error);
+ }
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
} else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Device", "PropertyModified")) {
if (ctx->device_property_modified != NULL) {
int i;
@@ -3901,7 +3978,7 @@ out:
}
/**
- * libhal_device_set_property_strlist:
+ * libhal_changeset_set_property_strlist:
* @changeset: the changeset
* @key: key of property
* @value: the value to set - NULL terminated array of strings
@@ -4130,6 +4207,18 @@ libhal_device_free_changeset (LibHalChangeSet *changeset)
}
+/**
+ * libhal_device_acquire_interface_lock:
+ * @ctx: the context for the connection to hald
+ * @udi: the Unique id of device
+ * @interface: the intername name to lock
+ * @exclusive: whether the lock should be exclusive
+ * @error: pointer to an initialized dbus error object for returning errors
+ *
+ * Releases a lock on an interface for a specific device.
+ *
+ * Returns: TRUE iff the lock was acquired
+ **/
dbus_bool_t
libhal_device_acquire_interface_lock (LibHalContext *ctx,
const char *udi,
@@ -4179,6 +4268,17 @@ libhal_device_acquire_interface_lock (LibHalContext *ctx,
return TRUE;
}
+/**
+ * libhal_device_release_interface_lock:
+ * @ctx: the context for the connection to hald
+ * @udi: the Unique id of device
+ * @interface: the intername name to unlock
+ * @error: pointer to an initialized dbus error object for returning errors
+ *
+ * Acquires a lock on an interface for a specific device.
+ *
+ * Returns: TRUE iff the lock was released.
+ **/
dbus_bool_t libhal_device_release_interface_lock (LibHalContext *ctx,
const char *udi,
const char *interface,
@@ -4225,6 +4325,17 @@ dbus_bool_t libhal_device_release_interface_lock (LibHalContext *ctx,
return TRUE;
}
+/**
+ * libhal_acquire_global_interface_lock:
+ * @ctx: the context for the connection to hald
+ * @interface: the intername name to lock
+ * @exclusive: whether the lock should be exclusive
+ * @error: pointer to an initialized dbus error object for returning errors
+ *
+ * Acquires a global lock on an interface.
+ *
+ * Returns: TRUE iff the lock was acquired
+ **/
dbus_bool_t libhal_acquire_global_interface_lock (LibHalContext *ctx,
const char *interface,
dbus_bool_t exclusive,
@@ -4271,6 +4382,16 @@ dbus_bool_t libhal_acquire_global_interface_lock (LibHalContext *ctx,
return TRUE;
}
+/**
+ * libhal_release_global_interface_lock:
+ * @ctx: the context for the connection to hald
+ * @interface: the intername name to unlock
+ * @error: pointer to an initialized dbus error object for returning errors
+ *
+ * Releases a global lock on an interface.
+ *
+ * Returns: TRUE iff the lock was released
+ **/
dbus_bool_t libhal_release_global_interface_lock (LibHalContext *ctx,
const char *interface,
DBusError *error)
@@ -4315,6 +4436,20 @@ dbus_bool_t libhal_release_global_interface_lock (LibHalContext *ctx,
return TRUE;
}
+/**
+ * libhal_device_is_caller_locked_out:
+ * @ctx: the context for the connection to hald
+ * @udi: the Unique id of device
+ * @interface: the intername name to check
+ * @caller: the caller to check for
+ * @error: pointer to an initialized dbus error object for returning errors
+ *
+ * Determines whether a given process on the system message bus is
+ * locked out from an interface on a specific device. Only HAL helpers
+ * are privileged to use this method.
+ *
+ * Returns: Whether the given caller is locked out
+ **/
dbus_bool_t
libhal_device_is_caller_locked_out (LibHalContext *ctx,
const char *udi,
@@ -4375,3 +4510,143 @@ libhal_device_is_caller_locked_out (LibHalContext *ctx,
return value;
}
+
+/**
+ * libhal_ctx_set_global_interface_lock_acquired:
+ * @ctx: the context for the connection to hald
+ * @callback: the callback
+ *
+ * Set the callback for when a global interface lock is acquired.
+ *
+ * Returns: TRUE if callback was successfully set, FALSE otherwise
+ */
+dbus_bool_t
+libhal_ctx_set_global_interface_lock_acquired (LibHalContext *ctx, LibHalGlobalInterfaceLockAcquired callback)
+{
+ LIBHAL_CHECK_LIBHALCONTEXT (ctx, FALSE);
+ ctx->global_interface_lock_acquired = callback;
+ return TRUE;
+}
+
+/**
+ * libhal_ctx_set_global_interface_lock_released:
+ * @ctx: the context for the connection to hald
+ * @callback: the callback
+ *
+ * Set the callback for when a global interface lock is released.
+ *
+ * Returns: TRUE if callback was successfully set, FALSE otherwise
+ */
+dbus_bool_t
+libhal_ctx_set_global_interface_lock_released (LibHalContext *ctx, LibHalGlobalInterfaceLockReleased callback)
+{
+ LIBHAL_CHECK_LIBHALCONTEXT (ctx, FALSE);
+ ctx->global_interface_lock_released = callback;
+ return TRUE;
+}
+
+
+/**
+ * libhal_ctx_set_interface_lock_acquired:
+ * @ctx: the context for the connection to hald
+ * @callback: the callback
+ *
+ * Set the callback for when an interface lock is acquired.
+ *
+ * Returns: TRUE if callback was successfully set, FALSE otherwise
+ */
+dbus_bool_t
+libhal_ctx_set_interface_lock_acquired (LibHalContext *ctx, LibHalInterfaceLockAcquired callback)
+{
+ LIBHAL_CHECK_LIBHALCONTEXT (ctx, FALSE);
+ ctx->interface_lock_acquired = callback;
+ return TRUE;
+}
+
+/**
+ * libhal_ctx_set_interface_lock_released:
+ * @ctx: the context for the connection to hald
+ * @callback: the callback
+ *
+ * Set the callback for when an interface lock is released.
+ *
+ * Returns: TRUE if callback was successfully set, FALSE otherwise
+ */
+dbus_bool_t
+libhal_ctx_set_interface_lock_released (LibHalContext *ctx, LibHalInterfaceLockReleased callback)
+{
+ LIBHAL_CHECK_LIBHALCONTEXT (ctx, FALSE);
+ ctx->interface_lock_released = callback;
+ return TRUE;
+}
+
+
+
+/**
+ * libhal_device_is_locked_by_others:
+ * @ctx: the context for the connection to hald
+ * @udi: the Unique id of device
+ * @interface: the intername name to check
+ * @error: pointer to an initialized dbus error object for returning errors or NULL
+ *
+ * Determines whether a determines other processes than the caller holds a lock on the given device.
+ *
+ * Returns: If another process is holding a lock on the device
+ **/
+dbus_bool_t
+libhal_device_is_locked_by_others (LibHalContext *ctx,
+ const char *udi,
+ const char *interface,
+ DBusError *error)
+{
+ DBusMessage *message;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ DBusMessageIter reply_iter;
+ dbus_bool_t value;
+
+ LIBHAL_CHECK_LIBHALCONTEXT(ctx, TRUE);
+ LIBHAL_CHECK_PARAM_VALID(udi, "*udi", TRUE);
+ LIBHAL_CHECK_PARAM_VALID(interface, "*interface", TRUE);
+
+ message = dbus_message_new_method_call ("org.freedesktop.Hal",
+ udi,
+ "org.freedesktop.Hal.Device",
+ "IsLockedByOthers");
+
+ if (message == NULL) {
+ fprintf (stderr,
+ "%s %d : Couldn't allocate D-BUS message\n",
+ __FILE__, __LINE__);
+ return TRUE;
+ }
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface);
+
+ reply = dbus_connection_send_with_reply_and_block (ctx->connection,
+ message, -1,
+ error);
+
+ if (error != NULL && dbus_error_is_set (error)) {
+ dbus_message_unref (message);
+ return TRUE;
+ }
+
+ dbus_message_unref (message);
+
+ if (reply == NULL)
+ return TRUE;
+
+ /* now analyze reply */
+ dbus_message_iter_init (reply, &reply_iter);
+ if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) {
+ dbus_message_unref (message);
+ dbus_message_unref (reply);
+ return TRUE;
+ }
+ dbus_message_iter_get_basic (&reply_iter, &value);
+ dbus_message_unref (reply);
+ return value;
+}
+
diff --git a/libhal/libhal.h b/libhal/libhal.h
index 897787a0..015406c3 100644
--- a/libhal/libhal.h
+++ b/libhal/libhal.h
@@ -191,6 +191,67 @@ typedef void (*LibHalDeviceCondition) (LibHalContext *ctx,
const char *condition_name,
const char *condition_detail);
+/**
+ * LibHalGlobalInterfaceLockAcquired:
+ * @ctx: context for connection to hald
+ * @interface_name: the name of the interface
+ * @lock_owner: what service acquired the lock
+ * @num_locks: number of locks on the interface
+ *
+ * Type for callback when someone acquires a global lock.
+ */
+typedef void (*LibHalGlobalInterfaceLockAcquired) (LibHalContext *ctx,
+ const char *interface_name,
+ const char *lock_owner,
+ int num_locks);
+
+/**
+ * LibHalGlobalInterfaceLockReleased:
+ * @ctx: context for connection to hald
+ * @interface_name: the name of the interface
+ * @lock_owner: what service released the lock
+ * @num_locks: number of locks on the interface
+ *
+ * Type for callback when someone releases a global lock.
+ */
+typedef void (*LibHalGlobalInterfaceLockReleased) (LibHalContext *ctx,
+ const char *interface_name,
+ const char *lock_owner,
+ int num_locks);
+
+/**
+ * LibHalInterfaceLockAcquired:
+ * @ctx: context for connection to hald
+ * @udi: the Unique Device Id
+ * @interface_name: the name of the interface
+ * @lock_owner: what service acquired the lock
+ * @num_locks: number of locks on the interface
+ *
+ * Type for callback when someone acquires a lock on a device.
+ */
+typedef void (*LibHalInterfaceLockAcquired) (LibHalContext *ctx,
+ const char *udi,
+ const char *interface_name,
+ const char *lock_owner,
+ int num_locks);
+
+/**
+ * LibHalInterfaceLockReleased:
+ * @ctx: context for connection to hald
+ * @udi: the Unique Device Id
+ * @interface_name: the name of the interface
+ * @lock_owner: what service released the lock
+ * @num_locks: number of locks on the interface
+ *
+ * Type for callback when someone acquires a lock on a device.
+ */
+typedef void (*LibHalInterfaceLockReleased) (LibHalContext *ctx,
+ const char *udi,
+ const char *interface_name,
+ const char *lock_owner,
+ int num_locks);
+
+
/* Create a new context for a connection with hald */
LibHalContext *libhal_ctx_new (void);
@@ -228,6 +289,18 @@ dbus_bool_t libhal_ctx_set_device_property_modified (LibHalContext *ctx, LibH
/* Set the callback for when a device emits a condition */
dbus_bool_t libhal_ctx_set_device_condition (LibHalContext *ctx, LibHalDeviceCondition callback);
+/* Set the callback for when a global interface lock is acquired */
+dbus_bool_t libhal_ctx_set_global_interface_lock_acquired (LibHalContext *ctx, LibHalGlobalInterfaceLockAcquired callback);
+
+/* Set the callback for when a global interface lock is released */
+dbus_bool_t libhal_ctx_set_global_interface_lock_released (LibHalContext *ctx, LibHalGlobalInterfaceLockReleased callback);
+
+/* Set the callback for when an interface lock is acquired */
+dbus_bool_t libhal_ctx_set_interface_lock_acquired (LibHalContext *ctx, LibHalInterfaceLockAcquired callback);
+
+/* Set the callback for when an interface lock is released */
+dbus_bool_t libhal_ctx_set_interface_lock_released (LibHalContext *ctx, LibHalInterfaceLockReleased callback);
+
/* Initialize the connection to hald */
dbus_bool_t libhal_ctx_init (LibHalContext *ctx, DBusError *error);
@@ -634,6 +707,12 @@ dbus_bool_t libhal_device_is_caller_locked_out (LibHalContext *ctx,
const char *caller,
DBusError *error);
+/* Determines whether a determines other processes than the caller holds a lock on the given device. */
+dbus_bool_t libhal_device_is_locked_by_others (LibHalContext *ctx,
+ const char *udi,
+ const char *interface,
+ DBusError *error);
+
#if defined(__cplusplus)
}
diff --git a/tools/hal-lock.c b/tools/hal-lock.c
index cd54f26d..f58431e4 100644
--- a/tools/hal-lock.c
+++ b/tools/hal-lock.c
@@ -37,6 +37,7 @@
#include <sys/wait.h>
#include <signal.h>
#include <glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
#include "libhal.h"
@@ -56,6 +57,7 @@ usage (int argc, char *argv[])
" --run <program-and-args>\n"
" [--udi <udi>]\n"
" [--exclusive]\n"
+ " [--exit-with-lock]"
" [--help] [--version]\n");
fprintf (stderr,
"\n"
@@ -64,6 +66,7 @@ usage (int argc, char *argv[])
" --udi Unique Device Id of device to lock. If\n"
" ommitted the global lock will be tried\n"
" --exclusive Whether the lock can be held by others\n"
+ " --exit-with-lock Kill the program if the acquired lock is lost\n"
" --version Show version and exit\n"
" --help Show this information and exit\n"
"\n"
@@ -77,6 +80,35 @@ usage (int argc, char *argv[])
"\n");
}
+static char *udi = NULL;
+static char *interface = NULL;
+static const char *unique_name;
+static GPid child_pid;
+
+static void
+guardian (GPid pid, int status, gpointer data)
+{
+ /* exit along with the child */
+ exit (0);
+}
+
+static void
+interface_lock_released (LibHalContext *ctx,
+ const char *_udi,
+ const char *_interface,
+ const char *lock_owner,
+ int num_locks)
+{
+
+
+ if (strcmp (udi, _udi) == 0 &&
+ strcmp (interface, _interface) == 0 &&
+ strcmp (lock_owner, unique_name) == 0) {
+ fprintf (stderr, "Lost the lock; killing child...\n");
+ kill (child_pid, SIGTERM);
+ }
+}
+
/**
* main:
* @argc: Number of arguments given to program
@@ -89,16 +121,17 @@ usage (int argc, char *argv[])
int
main (int argc, char *argv[])
{
- char *udi = NULL;
- char *interface = NULL;
char *run = NULL;
dbus_bool_t is_version = FALSE;
dbus_bool_t exclusive = FALSE;
dbus_bool_t got_lock = FALSE;
+ dbus_bool_t exit_with_lock = FALSE;
+ DBusConnection *con;
DBusError error;
LibHalContext *hal_ctx;
int ret;
GError *g_error = NULL;
+ GMainLoop *loop;
ret = 1;
@@ -116,6 +149,7 @@ main (int argc, char *argv[])
{"interface", 1, NULL, 0},
{"run", 1, NULL, 0},
{"exclusive", 0, NULL, 0},
+ {"exit-with-lock", 0, NULL, 0},
{"version", 0, NULL, 0},
{"help", 0, NULL, 0},
{NULL, 0, NULL, 0}
@@ -143,6 +177,8 @@ main (int argc, char *argv[])
exclusive = TRUE;
} else if (strcmp (opt, "interface") == 0) {
interface = strdup (optarg);
+ } else if (strcmp (opt, "exit-with-lock") == 0) {
+ exit_with_lock = TRUE;
}
break;
@@ -164,17 +200,41 @@ main (int argc, char *argv[])
goto out;
}
+ if (exit_with_lock && udi == NULL) {
+ fprintf (stderr, "--exit-with-lock requires UDI to be given.\n");
+ usage (argc, argv);
+ goto out;
+ }
+
+ if (exit_with_lock)
+ loop = g_main_loop_new (NULL, FALSE);
+ else
+ loop = NULL;
+
dbus_error_init (&error);
if ((hal_ctx = libhal_ctx_new ()) == NULL) {
fprintf (stderr, "error: libhal_ctx_new\n");
goto out;
}
- if (!libhal_ctx_set_dbus_connection (hal_ctx, dbus_bus_get (DBUS_BUS_SYSTEM, &error))) {
- fprintf (stderr, "error: libhal_ctx_set_dbus_connection: %s: %s\n", error.name, error.message);
+ con = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (con == NULL) {
+ fprintf (stderr, "error: dbus_bus_get: %s: %s\n", error.name, error.message);
LIBHAL_FREE_DBUS_ERROR (&error);
goto out;
}
+ if (!libhal_ctx_set_dbus_connection (hal_ctx, con)) {
+ fprintf (stderr, "error: libhal_ctx_set_dbus_connection\n");
+ goto out;
+ }
+
+ if (exit_with_lock) {
+ unique_name = dbus_bus_get_unique_name (con);
+ fprintf (stderr, "unique name is '%s'\n", unique_name);
+ libhal_ctx_set_interface_lock_released (hal_ctx, interface_lock_released);
+ dbus_connection_setup_with_g_main (con, NULL);
+ }
+
if (!libhal_ctx_init (hal_ctx, &error)) {
if (dbus_error_is_set(&error)) {
fprintf (stderr, "error: libhal_ctx_init: %s: %s\n", error.name, error.message);
@@ -184,6 +244,9 @@ main (int argc, char *argv[])
"Normally this means the HAL daemon (hald) is not running or not ready.\n");
goto out;
}
+
+ if (exit_with_lock)
+ libhal_device_add_property_watch (hal_ctx, udi, &error);
if (udi != NULL) {
got_lock = libhal_device_acquire_interface_lock (hal_ctx,
@@ -213,16 +276,43 @@ main (int argc, char *argv[])
goto out;
}
- /* now run the program while holding the lock */
- if (!g_spawn_command_line_sync (run,
- NULL,
- NULL,
- NULL,
- &g_error)) {
+ if (exit_with_lock) {
+ int _argc;
+ char **_argv;
+
+ if (!g_shell_parse_argv (run, &_argc, &_argv, &g_error)) {
+ fprintf (stderr, "error: g_shell_parse_argv: %s\n", g_error->message);
+ g_error_free (g_error);
+ goto out;
+ }
- fprintf (stderr, "error: g_spawn_command_line_sync: %s\n", g_error->message);
- g_error_free (g_error);
- goto out;
+ if (!g_spawn_async (NULL,
+ _argv,
+ NULL,
+ G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL,
+ NULL,
+ &child_pid,
+ &g_error)) {
+ fprintf (stderr, "error: g_spawn_command_line_async: %s\n", g_error->message);
+ g_error_free (g_error);
+ goto out;
+ }
+ g_child_watch_add (child_pid, guardian, NULL);
+ g_main_loop_run (loop);
+
+ } else {
+ /* now run the program while holding the lock */
+ if (!g_spawn_command_line_sync (run,
+ NULL,
+ NULL,
+ NULL,
+ &g_error)) {
+
+ fprintf (stderr, "error: g_spawn_command_line_sync: %s\n", g_error->message);
+ g_error_free (g_error);
+ goto out;
+ }
}
ret = 0;
diff --git a/tools/lshal.c b/tools/lshal.c
index 09516574..7e2bf824 100644
--- a/tools/lshal.c
+++ b/tools/lshal.c
@@ -581,6 +581,77 @@ device_condition (LibHalContext *ctx,
}
}
+static void
+do_interface_lock (LibHalContext *ctx,
+ dbus_bool_t acquired,
+ dbus_bool_t global,
+ const char *udi,
+ const char *interface_name,
+ const char *lock_owner,
+ int num_locks)
+{
+ if (show_device && strcmp(show_device, udi))
+ return;
+
+ if (long_list) {
+ if (global)
+ printf ("*** %s: lshal: global_interface_lock_%s\n", get_time (), acquired ? "acquired" : "released");
+ else
+ printf ("*** %s: lshal: interface_lock_%s, udi=%s\n", get_time (), acquired ? "acquired" : "released", udi);
+ printf (" interface_name=%s\n", interface_name);
+ printf (" lock_owner=%s\n", lock_owner);
+ printf (" num_locks=%d\n", num_locks);
+ printf ("\n");
+ } else {
+ if (global)
+ printf ("%s: global_interface_lock_%s %s by %s (%d lockers)\n", get_time (),
+ acquired ? "acquired" : "released",
+ interface_name, lock_owner, num_locks);
+ else
+ printf ("%s: %s interface_lock_%s %s by %s (%d lockers)\n", get_time (), short_name (udi),
+ acquired ? "acquired" : "released",
+ interface_name, lock_owner, num_locks);
+ }
+}
+
+static void
+global_interface_lock_acquired (LibHalContext *ctx,
+ const char *interface_name,
+ const char *lock_owner,
+ int num_locks)
+{
+ do_interface_lock (ctx, TRUE, TRUE, NULL, interface_name, lock_owner, num_locks);
+}
+
+static void
+global_interface_lock_released (LibHalContext *ctx,
+ const char *interface_name,
+ const char *lock_owner,
+ int num_locks)
+{
+ do_interface_lock (ctx, FALSE, TRUE, NULL, interface_name, lock_owner, num_locks);
+}
+
+static void
+interface_lock_acquired (LibHalContext *ctx,
+ const char *udi,
+ const char *interface_name,
+ const char *lock_owner,
+ int num_locks)
+{
+ do_interface_lock (ctx, TRUE, FALSE, udi, interface_name, lock_owner, num_locks);
+}
+
+static void
+interface_lock_released (LibHalContext *ctx,
+ const char *udi,
+ const char *interface_name,
+ const char *lock_owner,
+ int num_locks)
+{
+ do_interface_lock (ctx, FALSE, FALSE, udi, interface_name, lock_owner, num_locks);
+}
+
/**
* usage:
@@ -750,6 +821,10 @@ main (int argc, char *argv[])
libhal_ctx_set_device_lost_capability (hal_ctx, device_lost_capability);
libhal_ctx_set_device_property_modified (hal_ctx, property_modified);
libhal_ctx_set_device_condition (hal_ctx, device_condition);
+ libhal_ctx_set_global_interface_lock_acquired (hal_ctx, global_interface_lock_acquired);
+ libhal_ctx_set_global_interface_lock_released (hal_ctx, global_interface_lock_released);
+ libhal_ctx_set_interface_lock_acquired (hal_ctx, interface_lock_acquired);
+ libhal_ctx_set_interface_lock_released (hal_ctx, interface_lock_released);
if (show_device)
dump_device (show_device);