hal: Branch 'master' - 7 commits
David Zeuthen
david at kemper.freedesktop.org
Sun Apr 1 00:03:34 PDT 2007
HACKING | 8
configure.in | 2
doc/man/Makefile.am | 6
doc/man/hal-disable-polling.1.in | 137 +++++++++++++++
doc/man/hal-find-by-capability.1.in | 2
doc/man/hal-find-by-property.1.in | 2
doc/man/hal-get-property.1.in | 2
doc/man/hal-is-caller-locked-out.1.in | 2
doc/man/hal-lock.1.in | 12 +
doc/man/hal-set-property.1.in | 2
doc/spec/hal-spec-interfaces.xml | 70 +++++++
doc/spec/hal-spec-locking.xml | 197 +++++++++++++++++++--
examples/interface-locking-test.py | 21 +-
hald/access-check.c | 211 +++++++++++++++++------
hald/access-check.h | 5
hald/ci-tracker.c | 26 ++
hald/ci-tracker.h | 1
hald/device.c | 77 +++++++-
hald/device.h | 10 +
hald/device_store.c | 63 +++++++
hald/device_store.h | 10 +
hald/hald.c | 35 +++
hald/hald_dbus.c | 305 ++++++++++++++++++++++++++++++++--
hald/hald_dbus.h | 6
hald/hald_marshal.list | 2
hald/linux/addons/addon-storage.c | 113 ++++++++++++
libhal/libhal.c | 281 ++++++++++++++++++++++++++++++-
libhal/libhal.h | 79 ++++++++
tools/Makefile.am | 6
tools/hal-disable-polling.c | 276 ++++++++++++++++++++++++++++++
tools/hal-lock.c | 141 ++++++++++++++-
tools/lshal.c | 75 ++++++++
32 files changed, 2048 insertions(+), 137 deletions(-)
New commits:
diff-tree c003685ace0936d4c813bf1ba422d521c72d4d62 (from 6d5d221b3130a8b30b05313ba69e0d7ec77fbdd6)
Author: David Zeuthen <davidz at redhat.com>
Date: Sun Apr 1 02:56:53 2007 -0400
add hal-disable-polling(1) program along with a man page
diff --git a/configure.in b/configure.in
index 349102a..d3dd295 100644
--- a/configure.in
+++ b/configure.in
@@ -893,6 +893,7 @@ doc/man/hal-find-by-property.1
doc/man/hal-find-by-capability.1
doc/man/hal-is-caller-locked-out.1
doc/man/hal-lock.1
+doc/man/hal-disable-polling.1
po/Makefile.in
])
diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am
index 4f22641..5f5416d 100644
--- a/doc/man/Makefile.am
+++ b/doc/man/Makefile.am
@@ -1,9 +1,9 @@
if MAN_PAGES_ENABLED
-MAN_IN_FILES = hald.1.in lshal.1.in hal-get-property.1.in hal-set-property.1.in hal-find-by-property.1.in hal-find-by-capability.1.in hal-is-caller-locked-out.1.in hal-lock.1.in
+MAN_IN_FILES = hald.1.in lshal.1.in hal-get-property.1.in hal-set-property.1.in hal-find-by-property.1.in hal-find-by-capability.1.in hal-is-caller-locked-out.1.in hal-lock.1.in hal-disable-polling.1.in
-man_MANS = hald.1 lshal.1 hal-get-property.1 hal-set-property.1 hal-find-by-property.1 hal-find-by-capability.1 hal-is-caller-locked-out.1 hal-lock.1
+man_MANS = hald.1 lshal.1 hal-get-property.1 hal-set-property.1 hal-find-by-property.1 hal-find-by-capability.1 hal-is-caller-locked-out.1 hal-lock.1 hal-disable-polling.1
endif # MAN_PAGES_ENABLED
diff --git a/doc/man/hal-disable-polling.1.in b/doc/man/hal-disable-polling.1.in
new file mode 100644
index 0000000..26f2769
--- /dev/null
+++ b/doc/man/hal-disable-polling.1.in
@@ -0,0 +1,137 @@
+.\"
+.\" hal-disable-polling manual page.
+.\" Copyright (C) 2007 David Zeuthen <david at fubar.dk>
+.\"
+.TH HAL-DISABLE-POLLING 1
+.SH NAME
+hal-disable-polling \- disable polling on drives with removable media
+.SH SYNOPSIS
+.PP
+.B hal-disable-polling
+[options]
+
+.SH DESCRIPTION
+
+\fIhal-disable-polling\fP can be used to to disable and enable media
+detection on drives with removable storage. 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- at VERSION@/spec/hal-spec.html"
+depending on the distribution.
+
+.SH OPTIONS
+The following options are supported:
+.TP
+.I "--udi"
+The UDI (\fIUnique Device Identifier\fP) of the device object.
+.TP
+.I "--device"
+The device file of the drive.
+.TP
+.I "--enable-polling"
+Enable polling instead of disabling it.
+.TP
+.I "--help"
+Print out usage.
+.TP
+.I "--version"
+Print the version.
+
+.SH NOTES
+.PP
+This program requires super user privileges.
+
+.SH RETURN VALUE
+.PP
+If the requested operation was successful, this program will exit with
+exit code 0.
+
+.SH HISTORY
+.PP
+Polling a storage drive is a necessary evil to detect when the user
+inserts or removes media. Human computer interaction studies have
+shown that a broad class of users expect their system to react within
+a few seconds of this. Thus, the
+.I hald
+daemon polls through the
+.I hald-addon-storage
+addon (one instance for each drive with removable media).
+
+The purpose of the
+.I hald-addon-storage
+addon is simply to open the special device file at a regular interval
+(either every 2 or every 16 seconds) to check for new media. This
+program tries to open the device file using the
+.B O_EXCL
+option which means that programs like \&\fIcdrecord\fR\|(1) that uses
+.B O_EXCL
+automatically prevents the
+.I hald-addon-storage
+for interferring by continously opening the device file. In addition,
+if the drive is locked using HAL (see \&\fIhal-lock\fR\|(1)) the addon
+also stops polling.
+
+Unfortunately, polling a storage drive can have adverse side effects
+if the hardware and/or device driver for the hardware is
+malfunctioning. Additionally, the operating system kernel itself may
+offer multiple interfaces for the same device (e.g. \&\fI/dev/sg0\fR\|
+and \&\fI/dev/scd0\fR\|) so even
+.B O_EXCL
+won't work. Also, polling a drive may decrease throughput in certain
+(odd and/or broken) configurations; for example, if two IDE drives
+shares the same host (master/slave), bus traffic and contention caused
+by polling e.g. the optical drive (slave) can reduce throughput to the
+hard disk (master) and/or interfere with CD burning on another optical
+drive (master). Finally, polling a drive incurs an overhead both in
+the host system (processes get woken up often, preventing the CPU to
+stay in a deep power saving states) and it may prevent the actual
+drive from reaching deep power states as well. As a result, more power
+is consumed and this affects battery life for laptops.
+
+Despite the existence of support for asynchronous media change
+notification in recent MMC (Multi-Media Commands) specifications,
+virtually no optical drives are compliant with the
+specification. Fortunately newer SATA ATAPI hardware seems to support
+Asynchronous Notification (AN) and at this time of writing (March
+2007) work is underway to make both the
+.I Linux
+operating system kernel and
+.I HAL
+take advantage of this.
+
+It is the position of the
+.I HAL
+team that polling should be avoided at all costs as long as it doesn't
+heavily impact the user experience in a negative way. This tool is
+provided as a stop-gap measure to use if a system is rendered useless
+due to bugs in drivers and/or hardware that is provoked by HAL polling
+the drive. If such a bug is encountered it should be reported (see the
+.B BUGS
+section below) so it can be fixed - historically
+.B hald
+have triggered a number of bugs in
+.I Linux
+storage drivers and related subsystems (such as USB) that have later
+been fixed.
+
+.SH BUGS
+.PP
+Please send bug reports to either the distribution or the HAL
+mailing list, see
+.I "http://lists.freedesktop.org/mailman/listinfo/hal"
+on how to subscribe.
+
+.SH SEE ALSO
+.PP
+\&\fIhald\fR\|(1),
+\&\fIlshal\fR\|(1),
+\&\fIhal-lock\fR\|(1),
+\&\fIopen\fR\|(2),
+\&\fIhttp://www.t10.org/scsi-3.htm\fR\|,
+\&\fIhttps://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=halpolling\fR\|
+
+.SH AUTHOR
+Written by David Zeuthen <david at fubar.dk> with a lot of help from many
+others.
+
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 0f73f61..1a8347b 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -31,7 +31,8 @@ bin_PROGRAMS = \
hal-find-by-property \
hal-device \
hal-is-caller-locked-out \
- hal-lock
+ hal-lock \
+ hal-disable-polling
lshal_SOURCES = lshal.c
lshal_LDADD = @GLIB_LIBS@ $(top_builddir)/libhal/libhal.la
@@ -57,6 +58,9 @@ hal_is_caller_locked_out_LDADD = @DBUS_L
hal_lock_SOURCES = hal-lock.c
hal_lock_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ $(top_builddir)/libhal/libhal.la
+hal_disable_polling_SOURCES = hal-disable-polling.c
+hal_disable_polling_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ $(top_builddir)/libhal/libhal.la
+
libexec_PROGRAMS = \
hal-storage-mount \
hal-storage-unmount \
diff --git a/tools/hal-disable-polling.c b/tools/hal-disable-polling.c
new file mode 100644
index 0000000..44d886c
--- /dev/null
+++ b/tools/hal-disable-polling.c
@@ -0,0 +1,276 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * hal-disable-polling.c : Disable polling on a drive
+ *
+ * Copyright (C) 2007 David Zeuthen, <david at fubar.dk>
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <glib.h>
+#include <libhal.h>
+
+/**
+ * usage:
+ * @argc: Number of arguments given to program
+ * @argv: Arguments given to program
+ *
+ * Print out program usage.
+ */
+static void
+usage (int argc, char *argv[])
+{
+ fprintf (stderr,
+ "\n"
+ "usage : hal-disable-polling [--udi <udi> | --device <device-file>]\n"
+ " [--enable-polling]\n"
+ " [--help] [--version]\n");
+ fprintf (stderr,
+ "\n"
+ " --udi Unique Device Id\n"
+ " --device Device file\n"
+ " --enable-polling Enable polling instead of disabling it\n"
+ " --version Show version and exit\n"
+ " --help Show this information and exit\n"
+ "\n"
+ "This program is provided to make HAL stop polling a drive. Please read.\n"
+ "the entire manual page before using this program.\n"
+ "\n");
+}
+
+/**
+ * main:
+ * @argc: Number of arguments given to program
+ * @argv: Arguments given to program
+ *
+ * Returns: Return code
+ *
+ * Main entry point
+ */
+int
+main (int argc, char *argv[])
+{
+ char *udi = NULL;
+ char *device = NULL;
+ dbus_bool_t is_version = FALSE;
+ dbus_bool_t enable_polling = FALSE;
+ DBusError error;
+ LibHalContext *hal_ctx;
+ FILE *f;
+ char *filename;
+
+ if (argc <= 1) {
+ usage (argc, argv);
+ return 1;
+ }
+
+ while (1) {
+ int c;
+ int option_index = 0;
+ const char *opt;
+ static struct option long_options[] = {
+ {"udi", 1, NULL, 0},
+ {"device", 1, NULL, 0},
+ {"enable-polling", 0, NULL, 0},
+ {"version", 0, NULL, 0},
+ {"help", 0, NULL, 0},
+ {NULL, 0, NULL, 0}
+ };
+
+ c = getopt_long (argc, argv, "",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 0:
+ opt = long_options[option_index].name;
+
+ if (strcmp (opt, "help") == 0) {
+ usage (argc, argv);
+ return 0;
+ } else if (strcmp (opt, "version") == 0) {
+ is_version = TRUE;
+ } else if (strcmp (opt, "udi") == 0) {
+ udi = strdup (optarg);
+ } else if (strcmp (opt, "device") == 0) {
+ device = strdup (optarg);
+ } else if (strcmp (opt, "enable-polling") == 0) {
+ enable_polling = TRUE;
+ }
+ break;
+
+ default:
+ usage (argc, argv);
+ return 1;
+ break;
+ }
+ }
+
+ if (is_version) {
+ printf ("hal-disable-polling " PACKAGE_VERSION "\n");
+ return 0;
+ }
+
+ if (udi == NULL && device == NULL) {
+ usage (argc, argv);
+ return 1;
+ }
+
+ if (udi != NULL && device != NULL) {
+ usage (argc, argv);
+ return 1;
+ }
+
+ dbus_error_init (&error);
+ if ((hal_ctx = libhal_ctx_new ()) == NULL) {
+ fprintf (stderr, "error: libhal_ctx_new\n");
+ return 1;
+ }
+ 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);
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ return 1;
+ }
+ 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);
+ dbus_error_free (&error);
+ }
+ fprintf (stderr, "Could not initialise connection to hald.\n"
+ "Normally this means the HAL daemon (hald) is not running or not ready.\n");
+ return 1;
+ }
+
+ if (getuid () != 0) {
+ fprintf (stderr, "This program requires super user (root) privileges.\n");
+ return 1;
+ }
+
+ if (device != NULL) {
+ char **devices;
+ int num_devices;
+ int n;
+
+ devices = libhal_manager_find_device_string_match (hal_ctx, "block.device", device, &num_devices, NULL);
+ if (devices == NULL) {
+ fprintf (stderr, "Cannot find device %s.\n", device);
+ return 1;
+ }
+
+ for (n = 0; devices[n] != NULL; n++) {
+ if (libhal_device_query_capability (hal_ctx, devices[n], "storage", NULL)) {
+ udi = devices[n];
+ break;
+ }
+ }
+
+ if (udi == NULL) {
+ fprintf (stderr, "Cannot find storage device %s.\n", device);
+ return 1;
+ }
+
+ /* mmmkay, we don't care about leaking the variable devices... mmkay? mmkay! */
+ } else {
+ if (!libhal_device_exists (hal_ctx, udi, &error)) {
+ fprintf (stderr, "Cannot find device with udi %s.\n", udi);
+ return 1;
+ }
+ if (!libhal_device_query_capability (hal_ctx, udi, "storage", NULL)) {
+ fprintf (stderr, "Device with udi %s is not a storage device.\n", udi);
+ return 1;
+ }
+ device = libhal_device_get_property_string (hal_ctx, udi, "block.device", NULL);
+ if (device == NULL) {
+ fprintf (stderr, "Device with udi %s does not have block.device set.\n", udi);
+ return 1;
+ }
+ }
+
+ if (!libhal_device_get_property_bool (hal_ctx, udi, "storage.removable", NULL)) {
+ fprintf (stderr, "The given drive don't use removable media so it's not polled anyway.\n");
+ return 1;
+ }
+
+ filename = g_strdup_printf (PACKAGE_SYSCONF_DIR "/hal/fdi/information/media-check-disable-%s.fdi",
+ g_basename (udi));
+
+ if (enable_polling) {
+ if (libhal_device_get_property_bool (hal_ctx, udi, "storage.media_check_enabled", NULL)) {
+ fprintf (stderr, "Polling is already enabled on the given drive.\n");
+ return 1;
+ }
+
+ if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
+ fprintf (stderr, "Cannot find fdi file %s. Perhaps polling wasn't disabled using this tool?\n", filename);
+ return 1;
+ }
+ if (unlink (filename) != 0) {
+ fprintf (stderr, "Cannot delete fdi file %s.\n", filename);
+ return 1;
+ }
+ } else {
+ if (!libhal_device_get_property_bool (hal_ctx, udi, "storage.media_check_enabled", NULL)) {
+ fprintf (stderr, "Polling is already disabled on the given drive.\n");
+ return 1;
+ }
+
+ if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
+ fprintf (stderr, "The fdi file %s already exist. Cowardly refusing to overwrite it.\n", filename);
+ return 1;
+ }
+
+ f = fopen (filename, "w");
+ if (f == NULL) {
+ fprintf (stderr, "Cannot open %s for writing.\n", filename);
+ return 1;
+ }
+ fprintf (f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "\n"
+ "<deviceinfo version=\"0.2\">\n"
+ " <device>\n"
+ " <match key=\"info.udi\" string=\"%s\">\n"
+ " <merge key=\"storage.media_check_enabled\" type=\"bool\">false</merge>\n"
+ " </match>\n"
+ " </device>\n"
+ "</deviceinfo>\n"
+ "\n", udi);
+ fclose (f);
+ }
+
+ libhal_device_reprobe (hal_ctx, udi, &error);
+
+ if (enable_polling)
+ printf ("Polling for drive %s have been enabled. The fdi file deleted was\n"
+ " %s\n", device, filename);
+ else
+ printf ("Polling for drive %s have been disabled. The fdi file written was\n"
+ " %s\n", device, filename);
+
+ return 0;
+}
diff-tree 6d5d221b3130a8b30b05313ba69e0d7ec77fbdd6 (from dfef8c679fd3f46c64b257cce7edb1872e467de8)
Author: David Zeuthen <davidz at redhat.com>
Date: Sun Apr 1 00:43:38 2007 -0400
update hal-lock(1)'s man page and fix usage()
diff --git a/doc/man/hal-lock.1.in b/doc/man/hal-lock.1.in
index a5c5492..bbff769 100644
--- a/doc/man/hal-lock.1.in
+++ b/doc/man/hal-lock.1.in
@@ -41,6 +41,11 @@ Kill the program if the acquired lock is
.I UDI
due to the semantics of HAL locks.
.TP
+.I "--exit-with-dev"
+Kill the program if the device is removed. 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/tools/hal-lock.c b/tools/hal-lock.c
index 4d02c05..09fec20 100644
--- a/tools/hal-lock.c
+++ b/tools/hal-lock.c
@@ -58,7 +58,7 @@ usage (int argc, char *argv[])
" [--udi <udi>]\n"
" [--exclusive]\n"
" [--exit-with-lock]\n"
- " [--exit-with-device]\n"
+ " [--exit-with-dev]\n"
" [--help] [--version]\n");
fprintf (stderr,
"\n"
diff-tree dfef8c679fd3f46c64b257cce7edb1872e467de8 (from a3b09f0ed8364e74405538dfecf1cebbaa8773b8)
Author: David Zeuthen <davidz at redhat.com>
Date: Sun Apr 1 00:41:50 2007 -0400
make hal-lock(1) provide an --exit-with-dev option
diff --git a/tools/hal-lock.c b/tools/hal-lock.c
index f58431e..4d02c05 100644
--- a/tools/hal-lock.c
+++ b/tools/hal-lock.c
@@ -57,7 +57,8 @@ usage (int argc, char *argv[])
" --run <program-and-args>\n"
" [--udi <udi>]\n"
" [--exclusive]\n"
- " [--exit-with-lock]"
+ " [--exit-with-lock]\n"
+ " [--exit-with-device]\n"
" [--help] [--version]\n");
fprintf (stderr,
"\n"
@@ -67,6 +68,7 @@ usage (int argc, char *argv[])
" 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"
+ " --exit-with-dev Kill the program if the locked device is removed\n"
" --version Show version and exit\n"
" --help Show this information and exit\n"
"\n"
@@ -93,6 +95,15 @@ guardian (GPid pid, int status, gpointer
}
static void
+device_removed (LibHalContext *ctx, const char *_udi)
+{
+ if (strcmp (udi, _udi) == 0) {
+ fprintf (stderr, "Lost the device; killing child...\n");
+ kill (child_pid, SIGTERM);
+ }
+}
+
+static void
interface_lock_released (LibHalContext *ctx,
const char *_udi,
const char *_interface,
@@ -126,6 +137,7 @@ main (int argc, char *argv[])
dbus_bool_t exclusive = FALSE;
dbus_bool_t got_lock = FALSE;
dbus_bool_t exit_with_lock = FALSE;
+ dbus_bool_t exit_with_dev = FALSE;
DBusConnection *con;
DBusError error;
LibHalContext *hal_ctx;
@@ -150,6 +162,7 @@ main (int argc, char *argv[])
{"run", 1, NULL, 0},
{"exclusive", 0, NULL, 0},
{"exit-with-lock", 0, NULL, 0},
+ {"exit-with-dev", 0, NULL, 0},
{"version", 0, NULL, 0},
{"help", 0, NULL, 0},
{NULL, 0, NULL, 0}
@@ -179,6 +192,8 @@ main (int argc, char *argv[])
interface = strdup (optarg);
} else if (strcmp (opt, "exit-with-lock") == 0) {
exit_with_lock = TRUE;
+ } else if (strcmp (opt, "exit-with-dev") == 0) {
+ exit_with_dev = TRUE;
}
break;
@@ -206,7 +221,13 @@ main (int argc, char *argv[])
goto out;
}
- if (exit_with_lock)
+ if (exit_with_dev && udi == NULL) {
+ fprintf (stderr, "--exit-with-lock requires UDI to be given.\n");
+ usage (argc, argv);
+ goto out;
+ }
+
+ if (exit_with_lock || exit_with_dev)
loop = g_main_loop_new (NULL, FALSE);
else
loop = NULL;
@@ -228,13 +249,17 @@ main (int argc, char *argv[])
goto out;
}
- if (exit_with_lock) {
+ if (exit_with_lock || exit_with_dev) {
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 (exit_with_lock)
+ libhal_ctx_set_interface_lock_released (hal_ctx, interface_lock_released);
+
+ if (exit_with_dev)
+ libhal_ctx_set_device_removed (hal_ctx, device_removed);
+
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);
@@ -276,7 +301,7 @@ main (int argc, char *argv[])
goto out;
}
- if (exit_with_lock) {
+ if (exit_with_lock || exit_with_dev) {
int _argc;
char **_argv;
diff-tree a3b09f0ed8364e74405538dfecf1cebbaa8773b8 (from 9548dacbb323101ca0a9dcbb45678eb58acc3a5d)
Author: David Zeuthen <davidz at redhat.com>
Date: Sun Apr 1 00:41:23 2007 -0400
avoid polling when a drive is locked
Also update the proc title if the device file is locked using O_EXCL
diff --git a/hald/linux/addons/addon-storage.c b/hald/linux/addons/addon-storage.c
index 469fc2a..a58b8aa 100644
--- a/hald/linux/addons/addon-storage.c
+++ b/hald/linux/addons/addon-storage.c
@@ -59,6 +59,7 @@ static DBusConnection *con = NULL;
static guint poll_timer = -1;
static GMainLoop *loop;
static gboolean system_is_idle = FALSE;
+static gboolean check_lock_state = TRUE;
static void
force_unmount (LibHalContext *ctx, const char *udi)
@@ -277,11 +278,30 @@ enum {
static gboolean poll_for_media (gpointer user_data);
+static int interval_in_seconds = 2;
+
+static gboolean is_locked_by_hal = FALSE;
+static gboolean is_locked_via_o_excl = FALSE;
+
static void
-update_polling_interval (void)
+update_proc_title (void)
{
- int interval_in_seconds;
+ if (is_locked_by_hal) {
+ if (is_locked_via_o_excl) {
+ hal_set_proc_title ("hald-addon-storage: no polling because %s is locked via HAL and O_EXCL", device_file);
+ } else {
+ hal_set_proc_title ("hald-addon-storage: no polling because %s is locked via HAL", device_file);
+ }
+ } else if (is_locked_via_o_excl) {
+ hal_set_proc_title ("hald-addon-storage: no polling because %s is locked via O_EXCL", device_file);
+ } else {
+ hal_set_proc_title ("hald-addon-storage: polling %s (every %d sec)", device_file, interval_in_seconds);
+ }
+}
+static void
+update_polling_interval (void)
+{
/* TODO: ideally we want all things that do polling to do it
* at the same time.. such as to minimize battery
* usage. Suppose we want to wake up to do poll_for_media()
@@ -308,7 +328,8 @@ update_polling_interval (void)
if (poll_timer > 0)
g_source_remove (poll_timer);
poll_timer = g_timeout_add (interval_in_seconds * 1000, poll_for_media, NULL);
- hal_set_proc_title ("hald-addon-storage: polling %s (every %d sec)", device_file, interval_in_seconds);
+
+ update_proc_title ();
}
static gboolean
@@ -316,6 +337,29 @@ poll_for_media (gpointer user_data)
{
int fd;
int got_media;
+
+ if (check_lock_state) {
+ DBusError error;
+
+ check_lock_state = FALSE;
+
+ HAL_INFO (("Checking whether device %s is locked on HAL", device_file));
+ dbus_error_init (&error);
+ if (libhal_device_is_locked_by_others (ctx, udi, "org.freedesktop.Hal.Device.Storage", &error)) {
+ HAL_INFO (("... device %s is locked on HAL", device_file));
+ is_locked_by_hal = TRUE;
+ update_proc_title ();
+ goto skip_check;
+ } else {
+ HAL_INFO (("... device %s is not locked on HAL", device_file));
+ is_locked_by_hal = FALSE;
+ update_proc_title ();
+ }
+ }
+
+ /* TODO: we could remove the timeout completely... */
+ if (is_locked_by_hal)
+ goto skip_check;
got_media = FALSE;
@@ -333,8 +377,15 @@ poll_for_media (gpointer user_data)
* actually is mounted. If it is we retry to open
* without O_EXCL
*/
- if (!is_mounted (device_file))
+ if (!is_mounted (device_file)) {
+ if (!is_locked_via_o_excl) {
+ is_locked_via_o_excl = TRUE;
+ update_proc_title ();
+ } else {
+ is_locked_via_o_excl = TRUE;
+ }
goto skip_check;
+ }
fd = open (device_file, O_RDONLY | O_NONBLOCK);
}
@@ -343,6 +394,11 @@ poll_for_media (gpointer user_data)
HAL_ERROR (("open failed for %s: %s", device_file, strerror (errno)));
goto skip_check;
}
+
+ if (is_locked_via_o_excl) {
+ is_locked_via_o_excl = FALSE;
+ update_proc_title ();
+ }
/* Check if a disc is in the drive
@@ -517,6 +573,7 @@ error:
}
#endif /* HAVE_CONKIT */
+
static DBusHandlerResult
dbus_filter_function (DBusConnection *connection, DBusMessage *message, void *user_data)
{
@@ -538,9 +595,24 @@ dbus_filter_function (DBusConnection *co
update_polling_interval ();
}
}
+
out:
#endif /* HAVE_CONKIT */
+ /* Check, just before the next poll, whether lock state have changed;
+ *
+ * Note that we get called on at least these signals
+ *
+ * 1. CK.Manager - SystemIdleHintChanged
+ * 2. CK.Seat - ActiveSessionChanged
+ * 2. HAL.Manager - GlobalLockAcquired, GlobalLockReleased
+ * 3. HAL.Device - LockAcquired, LockReleased
+ *
+ * meaning that every time the locking situation changes, we
+ * will get updated.
+ */
+ check_lock_state = TRUE;
+
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -551,6 +623,7 @@ main (int argc, char *argv[])
char *bus;
char *drive_type;
char *support_media_changed_str;
+ char *str;
hal_set_proc_title_init (argc, argv);
@@ -616,9 +689,39 @@ main (int argc, char *argv[])
"type='signal'"
",interface='org.freedesktop.ConsoleKit.Manager'"
",sender='org.freedesktop.ConsoleKit'"
- ",member='SystemIdleHintChanged'",
+ ",member='SystemIdleHintChanged'",
+ NULL);
+ dbus_bus_add_match (con,
+ "type='signal'"
+ ",interface='org.freedesktop.ConsoleKit.Seat'"
+ ",sender='org.freedesktop.ConsoleKit'"
+ ",member='ActiveSessionChanged'",
NULL);
#endif
+
+ /* this is a bit weird; but we want to listen to signals about
+ * locking from hald.. and signals are not pushed over direct
+ * connections (for a good reason).
+ */
+ dbus_bus_add_match (con,
+ "type='signal'"
+ ",interface='org.freedesktop.Hal.Manager'"
+ ",sender='org.freedesktop.Hal'",
+ NULL);
+ dbus_bus_add_match (con,
+ "type='signal'"
+ ",interface='org.freedesktop.Hal.Manager'"
+ ",sender='org.freedesktop.Hal'",
+ NULL);
+ str = g_strdup_printf ("type='signal'"
+ ",interface='org.freedesktop.Hal.Device'"
+ ",sender='org.freedesktop.Hal'"
+ ",path='%s'",
+ udi);
+ dbus_bus_add_match (con,
+ str,
+ NULL);
+ g_free (str);
dbus_connection_add_filter (con, dbus_filter_function, NULL, NULL);
update_polling_interval ();
diff-tree 9548dacbb323101ca0a9dcbb45678eb58acc3a5d (from 4a36ab4a5c0b0b9b9c7e593e8d227af99cd3a5dc)
Author: David Zeuthen <davidz at redhat.com>
Date: Sun Apr 1 00:40:13 2007 -0400
avoid crash if an addon is using IsLockedByOthers()
diff --git a/hald/access-check.c b/hald/access-check.c
index ab68ce4..a17d34f 100644
--- a/hald/access-check.c
+++ b/hald/access-check.c
@@ -362,7 +362,8 @@ access_check_locked_by_others (CITracker
if (holders != NULL) {
for (n = 0; holders[n] != NULL; n++) {
- if (strcmp (holders[n], caller_unique_sysbus_name) != 0) {
+ if (caller_unique_sysbus_name == NULL || /* <-- callers using direct connection to hald */
+ strcmp (holders[n], caller_unique_sysbus_name) != 0) {
/* someone else is holding the lock */
goto out;
}
@@ -371,7 +372,8 @@ access_check_locked_by_others (CITracker
if (global_holders != NULL) {
for (n = 0; global_holders[n] != NULL; n++) {
- if (strcmp (global_holders[n], caller_unique_sysbus_name) != 0) {
+ if (caller_unique_sysbus_name == NULL || /* <-- callers using direct connection to hald */
+ 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 */
diff-tree 4a36ab4a5c0b0b9b9c7e593e8d227af99cd3a5dc (from 975a4defadb47ec8d3d6156f3eb20f6a67ec3009)
Author: David Zeuthen <davidz at redhat.com>
Date: Sat Mar 31 22:37:48 2007 -0400
change locking semantics slightly and add missing locking bits
diff --git a/HACKING b/HACKING
index 7e9bb5b..2a77fdc 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 8e14728..349102a 100644
--- a/configure.in
+++ b/configure.in
@@ -140,6 +140,7 @@ AC_ARG_ENABLE(verbose-mode, [ --ena
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 295c694..4f22641 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 5d7e155..5c593ca 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 cap
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- at 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 0dd29c3..73bc99b 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 pro
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- at 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 d61e459..87ab9d9 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- at 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 3df1c1d..d5de39a 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
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- at 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 abd6af3..a5c5492 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. Fo
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- at VERSION@/spec/hal-spec.html"
depending on the distribution.
.SH OPTIONS
@@ -36,6 +36,11 @@ is ommitted, the global lock will be tri
.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 2c4294c..d62bfcd 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- at 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 9858c71..1ad525b 100644
--- a/doc/spec/hal-spec-interfaces.xml
+++ b/doc/spec/hal-spec-interfaces.xml
@@ -112,6 +112,28 @@ $ dbus-send --system --print-reply --des
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 --des
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 --des
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 --des
device. See <xref linkend="locking"/> for details.
</entry>
</row>
-
<row>
<entry>ReleaseInterfaceLock</entry>
<entry></entry>
@@ -399,7 +433,6 @@ $ dbus-send --system --print-reply --des
<xref linkend="locking"/> for details.
</entry>
</row>
-
<row>
<entry>IsCallerLockedOut</entry>
<entry>Bool</entry>
@@ -412,6 +445,17 @@ $ dbus-send --system --print-reply --des
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 --des
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 df62f0a..7306dbb 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 ca60a91..51552b4 100755
--- a/examples/interface-locking-test.py
+++ b/examples/interface-locking-test.py
@@ -22,11 +22,15 @@ device_volume = dbus.Interface(bus.get_o
"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 6f0542b..ab68ce4 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_devic
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 (CITracke
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 (CITracke
/* 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 ab05f07..3da49ed 100644
--- a/hald/access-check.h
+++ b/hald/access-check.h
@@ -35,10 +35,15 @@ gboolean access_check_message_caller_is_
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 6a8bd81..af83654 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, con
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
}
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 7d762e9..5b0794a 100644
--- a/hald/ci-tracker.h
+++ b/hald/ci-tracker.h
@@ -63,6 +63,7 @@ uid_t ci_tracker_caller_get_uid
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 f1f5847..e95cc19 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 *k
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 *devi
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 *devi
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 *
}
/**
+ * 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 ch
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 5dd11f5..1942e2f 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 (H
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 7c06aab..23c054d 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 (HalDeviceSt
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, 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 *st
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
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 0e1578a..300f4c7 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 c130ca8..1a13a31 100644
--- a/hald/hald.c
+++ b/hald/hald.c
@@ -161,6 +161,32 @@ gdl_capability_added (HalDeviceStore *st
/*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 2816947..90dc9f7 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 (DBusConne
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 (DBusConne
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 (DBusConne
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 (DBusConnect
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 *connecti
" <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 *connecti
" <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 *connecti
" <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 (DBusCon
"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 (DBusCon
/* 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 (DBusConnectio
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 *track
/* 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 (CKTrac
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 d7f9acc..4a5deb1 100644
--- a/hald/hald_dbus.h
+++ b/hald/hald_dbus.h
@@ -83,6 +83,12 @@ void manager_send_signal_device_removed
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 8e3863a..14dd6f8 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 b5f3c1e..8e76032 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 (LibHalChan
}
+/**
+ * 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 (Li
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_interf
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_interf
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_interf
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 (LibH
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 897787a..015406c 100644
--- a/libhal/libhal.h
+++ b/libhal/libhal.h
@@ -191,6 +191,67 @@ typedef void (*LibHalDeviceCondition) (L
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_pro
/* 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_lock
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 cd54f26..f58431e 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 0951657..7e2bf82 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);
diff-tree 975a4defadb47ec8d3d6156f3eb20f6a67ec3009 (from 154c2bac8ec500eba9a4f15a9e5ea244be1c9e5d)
Author: David Zeuthen <davidz at redhat.com>
Date: Sat Mar 31 18:07:59 2007 -0400
change locking semantics a bit and add guidelines for SystemPowerManagement
The change in locking semantics is that a lock-holder can now access a
device even if other processes have locks on the device.
diff --git a/doc/spec/hal-spec-interfaces.xml b/doc/spec/hal-spec-interfaces.xml
index fe0c112..9858c71 100644
--- a/doc/spec/hal-spec-interfaces.xml
+++ b/doc/spec/hal-spec-interfaces.xml
@@ -653,6 +653,12 @@ $ dbus-send --system --print-reply --des
<para>
This interface does not emit any signals.
</para>
+
+ <para>
+ Implementors of power management daemons should make sure that
+ their software respects the locking guidelines described in
+ <xref linkend="interfaces"/>.
+ </para>
</sect1>
<sect1 id="interface-cpufreq">
diff --git a/doc/spec/hal-spec-locking.xml b/doc/spec/hal-spec-locking.xml
index 443ac48..df62f0a 100644
--- a/doc/spec/hal-spec-locking.xml
+++ b/doc/spec/hal-spec-locking.xml
@@ -5,8 +5,8 @@
<title>Locking</title>
<para>
- As HAL enables programs in a desktop session to automatically
- enforce the policy of the users choice, unexpected things can
+ As HAL is a mechanism that enables programs in a desktop session
+ to enforce the policy of the users choice, unexpected things can
happen. For example, if the user is in the middle of partitioning
a disk drive, it is desirable to keep the desktop from mounting
partitions that have not yet been prepared with a suitable file
@@ -72,37 +72,42 @@
also be obtained exclusively if the caller so desires. Unlike
per-device interface locking, it is not checked at locking time
whether the locker have access to a given device; instead
- checking is done when callers attempt to access the interface.
+ checking is done when callers attempt to access the
+ interface.
</para>
<para>
The algorithm used for determining if a caller is locked out is
- shown below. A caller is locked out if:
+ shown below. A caller A is locked out of an interface IFACE on a
+ device object DEVICE if, and only if,
</para>
<orderedlist>
<listitem>
<para>
- another caller is holding a lock on the interface on the
- device (non-withstanding that the caller to check for holds
- the lock himself).
+ Another caller B is holding a lock on the interface IFACE on
+ DEVICE and A don't have either a global lock on IFACE or a
+ lock on IFACE on DEVICE; or
</para>
</listitem>
<listitem>
<para>
- Another caller is holding the global lock for the interface
- and that other caller has access to the device in question.
+ Another caller B is holding the global lock on the
+ interface IFACE and B has access to DEVICE and and A don't
+ have either a global lock on IFACE or a lock on IFACE on
+ DEVICE.
</para>
</listitem>
</orderedlist>
<para>
- In other words, a client Foo can grab a global lock, but that
- doesn't mean Foo can lock other clients out of devices that Foo
- doesn't have access to. Specifically a caller is not locked out
- if he has locked an interface and he is the only one holding the
- lock. However, if two clients have a lock on a device neither of
- them can access the device.
+ In other words, a caller A can grab a global lock, but that
+ doesn't mean A can lock other clients out of devices that A
+ doesn't have access to. Specifically a caller is never locked
+ out if he has locked an interface either globally or on the
+ device in question. However, if two clients have a lock on a
+ device, then both can access it. To ensure that everyone is
+ locked out, a caller needs to use an exclusive lock.
</para>
<para>
@@ -135,21 +140,148 @@
block devices directly (and pokes the kernel to reload the
partitioning table) should lock out automounters by either
a) obtaining
- the <literal>org.freedesktop.Hal.Device.Storage</literal> on
- each drive being processed; or b) obtaintaing the global
+ the <literal>org.freedesktop.Hal.Device.Storage</literal>
+ lock on each drive being processed; or b) obtaintaing the
+ global
<literal>org.freedesktop.Hal.Device.Storage</literal>
lock. This includes programs like fdisk, gparted, parted and
operating system installers. See also
- <xref linkend="interface-device-volume"/>.
+ <xref linkend="interface-device-volume"/> and
+ the <literal>hal-lock</literal>(1) program and manual page.
</para>
</listitem>
<listitem><para>
- <emphasis>System-wide Power Management</emphasis>
+ <emphasis>Power Management</emphasis>
</para>
<para>
- (this guideline is not finalized!)
+ Typically, a desktop session includes a session-wide power
+ management daemon that enforces the policy of the users
+ choice, e.g. whether the system should suspend to ram on lid
+ close, whether to hibernate the system after the user being
+ idle for 30 minutes and so on. In a multi-user setup (both
+ fast user switching and multi-seat), this can break in
+ various interesting ways unless the power management daemons
+ cooperate. Also, there may be software running at the system
+ level who will want to inhibit a desktop session power
+ management daemon from suspending / shutting down.
</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ System-level software that do not wish to be interrupted
+ by the effect of someone calling into the
+ <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
+ interface MUST hold the
+ <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
+ lock non-exclusively on the root computer device
+ object. For example, the YUM software updater should
+ hold the lock when doing an RPM transaction.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ In addition, any power management session daemon instance
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ ... MUST hold the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal> lock
+ non-exclusively on the root computer device object
+ unless it is prepared to call into this interface
+ itself. This typically means that the PM daemon instance
+ simply acquires the lock on start up and releases it
+ just before it calls into
+ the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
+ interface. In other words, the PM daemon instance needs
+ to hold the lock exactly when it doesn't want other PM
+ daemon instances to call into
+ the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal> interface.
+ This means that if the user have configured the PM
+ daemon instance to go to sleep after 30 minutes of
+ inactivity, the lock should be released then.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ ... MUST not hold the lock when the session is inactive
+ (fast user switching) UNLESS an application in the
+ session have explicitly called Inhibit() on
+ the <literal>org.freedesktop.PowerManagement</literal>
+ D-Bus session bus interface of the PM daemon.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ ... MUST check that no other process is holding the lock
+ before calling into
+ the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
+ interface. If another process is holding the lock, it
+ means that either 1) another session is not prepared to
+ call into
+ the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
+ interface; OR 2) some system-level software is holding
+ the lock. The PM daemon instance MUST respect this by
+ not calling into
+ the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
+ interface itself.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+ <para>
+ However, any Power management daemon instance
+ </para>
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ ... MAY prompt the user, if applicable, to ask if she
+ still wants to perform the requested action (e.g. call
+ into
+ the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
+ interface) despite the fact that another process
+ (possibly from another user) is indicating that it does
+ not want the system to e.g. suspend. Only if the user
+ agrees, the power management instance should call into
+ the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
+ interface. Typically, it's only useful to prompt the
+ user with such questions if the request to call into
+ the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
+ interface originates from user input, e.g. either a
+ hotkey, the user clicking a suspend button in the UI or
+ an application invoking the <literal>Suspend()</literal> method on the
+ <literal>org.freedesktop.PowerManagement</literal> D-Bus
+ session interface of the PM daemon.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ ... MAY ignore that other processes are holding the lock
+ and call into
+ the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
+ interface anyway, but ONLY if if the request to call
+ into
+ the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
+ interface originated from e.g. lid close, critically low
+ battery or other similar conditions.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ ... MAY still call <literal>SetPowerSave()</literal> on
+ the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
+ interface even if other processes are holding the lock.
+ </para>
+ </listitem>
+ </itemizedlist>
</listitem>
</itemizedlist>
diff --git a/examples/interface-locking-test.py b/examples/interface-locking-test.py
index 3b98cd1..ca60a91 100755
--- a/examples/interface-locking-test.py
+++ b/examples/interface-locking-test.py
@@ -17,9 +17,16 @@ device = dbus.Interface(bus.get_object("
"/org/freedesktop/Hal/devices/volume_uuid_2232_1F11"),
"org.freedesktop.Hal.Device")
-manager.AcquireGlobalInterfaceLock("org.freedesktop.Hal.Device.Storage", True)
-#device.AcquireInterfaceLock("org.freedesktop.Hal.Device.Volume", True)
+device_volume = dbus.Interface(bus.get_object("org.freedesktop.Hal",
+ "/org/freedesktop/Hal/devices/volume_uuid_2232_1F11"),
+ "org.freedesktop.Hal.Device.Volume")
+
+#manager.AcquireGlobalInterfaceLock("org.freedesktop.Hal.Device.Storage", True)
+#time.sleep(2)
+#manager.ReleaseGlobalInterfaceLock("org.freedesktop.Hal.Device.Storage")
+
+device.AcquireInterfaceLock("org.freedesktop.Hal.Device.Volume", False)
+device_volume.Mount("", "", [])
time.sleep(2)
-manager.ReleaseGlobalInterfaceLock("org.freedesktop.Hal.Device.Storage")
-#device.ReleaseInterfaceLock("org.freedesktop.Hal.Device.Volume")
+device.ReleaseInterfaceLock("org.freedesktop.Hal.Device.Volume")
diff --git a/hald/access-check.c b/hald/access-check.c
index d96ddaa..6f0542b 100644
--- a/hald/access-check.c
+++ b/hald/access-check.c
@@ -180,24 +180,24 @@ out:
* @interface_name: the interface to check for
*
* This method determines if a caller is locked out to access a given
- * interface on a given device. A caller is locked out when:
+ * interface on a given device. A caller A is locked out of an
+ * interface IFACE on a device object DEVICE if, and only if
*
- * 1. Another caller is holding a lock on the interface on the device
- * non-withstanding that the caller to check for holds the lock
- * himself.
+ * 1. Another caller B is holding a lock on the interface IFACE on
+ * DEVICE and A don't have either a global lock on IFACE or a lock
+ * on IFACE on DEVICE; or
*
- * 2. Another caller is holding the global lock for the interface on
- * the root computer device object and that other caller has
- * access to the device in question.
+ * 2. Another caller B is holding the global lock on the interface
+ * IFACE and B has access to DEVICE and and A don't have either a
+ * global lock on IFACE or a lock on IFACE on DEVICE.
*
- * (In other words, a client Foo can grab a lock on the root
- * computer device object, but that doesn't mean Foo can lock
- * other clients out of devices that Foo doesn't have access to.)
- *
- * Specifically a caller is not locked out if he has locked the
- * interface and he is the only one holding the lock. However, if two
- * clients have a lock on a device neither of them can access the
- * device.
+ * In other words, a caller A can grab a global lock, but that doesn't
+ * mean A can lock other clients out of devices that A doesn't have
+ * access to. Specifically a caller is never locked out if he has
+ * locked an interface either globally or on the device in
+ * question. However, if two clients have a lock on a device, then
+ * both can access it. To ensure that everyone else is locked out, a
+ * caller needs to use an exclusive lock.
*
* Returns: TRUE iff the caller is locked out
*/
@@ -213,6 +213,8 @@ access_check_caller_locked_out (CITracke
char **holders;
char **global_holders;
HalDevice *computer;
+ gboolean is_locked;
+ gboolean is_locked_by_self;
global_lock_name = NULL;
holders = NULL;
@@ -234,16 +236,15 @@ access_check_caller_locked_out (CITracke
* assumed to have access to the device since they got to hold
* the lock in the first place.
*/
+ is_locked = FALSE;
+ is_locked_by_self = FALSE;
if (holders != NULL) {
for (n = 0; holders[n] != NULL; n++) {
- if (strcmp (holders[n], caller_unique_sysbus_name) != 0) {
- /* Yup, there's someone else... can't do it Sally */
- HAL_INFO (("Caller '%s' is locked out of interface '%s' on device '%s' "
- "because caller '%s' got a lock on the interface on the device",
- caller_unique_sysbus_name,
- interface_name,
- hal_device_get_udi (device),
- holders[n]));
+ is_locked = TRUE;
+ if (strcmp (holders[n], caller_unique_sysbus_name) == 0) {
+ is_locked_by_self = TRUE;
+ /* this is good enough; we are holding the lock ourselves */
+ ret = FALSE;
goto out;
}
}
@@ -251,27 +252,37 @@ access_check_caller_locked_out (CITracke
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.. check if that someone actually have
- * access to the device...
- */
+ 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])) {
- /* They certainly do. Give up. */
-
- HAL_INFO (("Caller '%s' is locked out of interface '%s' on device '%s' "
- "because caller '%s' got a lock on the global interface and "
- "have access to the device",
- caller_unique_sysbus_name,
- interface_name,
- hal_device_get_udi (device),
- 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 */
+ ret = FALSE;
goto out;
}
+ } else {
+ /* 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])) {
+ /* They certainly do. Mark as locked. */
+ is_locked = TRUE;
+ }
}
}
}
+ if (is_locked && !is_locked_by_self) {
+ /* Yup, there's someone else... can't do it Sally */
+ HAL_INFO (("Caller '%s' is locked out of interface '%s' on device '%s' "
+ "because someone else got a lock on the interface on the device",
+ caller_unique_sysbus_name,
+ interface_name,
+ hal_device_get_udi (device)));
+ goto out;
+ }
+
/* done all the checks so we're not locked out */
ret = FALSE;
More information about the hal-commit
mailing list