summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.in1
-rw-r--r--doc/man/Makefile.am4
-rw-r--r--doc/man/hal-disable-polling.1.in137
-rw-r--r--tools/Makefile.am6
-rw-r--r--tools/hal-disable-polling.c276
5 files changed, 421 insertions, 3 deletions
diff --git a/configure.in b/configure.in
index 349102a3..d3dd295e 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 4f22641c..5f5416dd 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 00000000..26f27697
--- /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@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-@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@fubar.dk> with a lot of help from many
+others.
+
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 0f73f61c..1a8347b6 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_LIBS@ $(top_builddir)/libhal/libhal.la
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 00000000..44d886cf
--- /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@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;
+}