[Utopia] [patch] mount/unmount when starting/stopping
- From: David Zeuthen <david fubar dk>
- To: rml ximian com
- Cc: utopia-list gnome org
- Subject: [Utopia] [patch] mount/unmount when starting/stopping
- Date: Tue, 17 Aug 2004 15:42:08 +0200
Hey Robert,
So here's finally a patch that fixes the bug we've discussed somewhat at
length on utopia-list. This patch does the following:
1. When g-v-m starts it attempts to silently mount all volumes (e.g.
it doesn't popup any dialogs etc.).
2. During the life of the g-v-m instance, a list of volumes that have
mounted (including those mounted at startup) and are still mounted
is maintained.
3. When g-v-m is to be terminated (either through a 'die' signal from
the session manager or through a SIGTERM) all volumes in the list
mentioned in 2. are unmounted
4. We no longer listen on the EjectPressed signal from HAL - this
is removed from HAL as only a tiny fraction of drives implement it
5. gvm_mount_device now calls mount(1) synchronously; we need that
return value.
Patch is against CVS a few minutes ago - please apply.
Thanks
David
ChangeLog | 21 ++
src/manager.c | 292 +++++++++++++++++++++++++++++++++-----
2 files changed, 277 insertions(+), 36 deletions(-)
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gnome-volume-manager/ChangeLog,v
retrieving revision 1.87
diff -u -p -r1.87 ChangeLog
--- ChangeLog 13 Aug 2004 20:58:23 -0000 1.87
+++ ChangeLog 17 Aug 2004 13:33:50 -0000
@@ -1,3 +1,24 @@
+2004-08-17 David Zeuthen <david fubar dk>
+
+ * src/manager.c
+ (gvm_device_mount): Mount synchronously so we know whether it
+ fails and can report
+ (gvm_device_unmount): New function
+ (hal_property_modified): Respect the list of ignored UDI's.
+ Maintain the list of volumes that have been mounted during our
+ lifetime
+ (hal_device_condition): Don't listen for the EjectPressed
+ condition; HAL no longer emits it (it only works on a tiny
+ fraction of devices)
+ (mount_all): New function
+ (unmount_all): New function
+ (handle_sigterm): New function
+ (sigterm_iochn_data): New function
+ (gvm_die): New function
+ (main): Setup handler for 'die' signal. Setup SIGTERM handler and
+ create a pipe and integrate this pipe into the mainloop. Invoke
+ mount_all
+
2004-08-13 Adam Roben <aroben fas harvard edu>
* src/manager.c: storage.drive_type belongs to the media's parent in
Index: src/manager.c
===================================================================
RCS file: /cvs/gnome/gnome-volume-manager/src/manager.c,v
retrieving revision 1.28
diff -u -p -r1.28 manager.c
--- src/manager.c 13 Aug 2004 20:58:23 -0000 1.28
+++ src/manager.c 17 Aug 2004 13:33:50 -0000
@@ -21,6 +21,7 @@
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#include <libhal.h>
+#include <signal.h>
#include "gvm.h"
@@ -47,11 +48,18 @@
#define warn(fmt,arg...) g_warning("%s/%d: " fmt,__FILE__,__LINE__,##arg)
#define BIN_MOUNT "/bin/mount" /* what we mount with */
+#define BIN_UMOUNT "/bin/umount" /* what we unmount with */
#define NAUTILUS_COMMAND "/usr/bin/nautilus -n --no-desktop %m"
static struct gvm_configuration config;
static LibHalContext *hal_ctx;
+/** List of UDI's for volumes mounted when starting up */
+static GSList *mount_ignore_udi_list;
+
+/** List of UDI's of all volumes mounted during the lifetime of the program */
+static GSList *all_mounted_volumes;
+
/*
* gvm_load_config - synchronize gconf => config structure
*/
@@ -381,21 +389,55 @@ out:
*
* Note that this requires that the given device node is in /etc/fstab. This
* is intentional.
+ *
+ * @return TRUE iff the mount was succesful
*/
-static void
+static gboolean
gvm_device_mount (char *device)
{
char *argv[3];
GError *error = NULL;
+ gint exit_status;
argv[0] = BIN_MOUNT;
argv[1] = device;
argv[2] = NULL;
- g_spawn_async (g_get_home_dir (), argv, NULL, 0, NULL,
- NULL, NULL, &error);
- if (error)
+ if (!g_spawn_sync (g_get_home_dir (), argv, NULL, 0, NULL,
+ NULL, NULL, NULL, &exit_status, &error)) {
+ warn ("failed to exec " BIN_MOUNT ": %s\n", error->message);
+ return FALSE;
+ }
+
+ return exit_status == 0;
+}
+
+/*
+ * gvm_device_unmount - use BIN_UMOUNT to unmount the given device node.
+ *
+ * Note that this requires that the given device node is in /etc/fstab. This
+ * is intentional.
+ *
+ * @return TRUE iff the mount was succesful
+ */
+static gboolean
+gvm_device_unmount (char *device)
+{
+ char *argv[3];
+ GError *error = NULL;
+ gint exit_status;
+
+ argv[0] = BIN_UMOUNT;
+ argv[1] = device;
+ argv[2] = NULL;
+
+ if (!g_spawn_sync (g_get_home_dir (), argv, NULL, 0, NULL,
+ NULL, NULL, NULL, &exit_status, &error)) {
warn ("failed to exec " BIN_MOUNT ": %s\n", error->message);
+ return FALSE;
+ }
+
+ return exit_status == 0;
}
/*
@@ -688,16 +730,60 @@ hal_property_modified (LibHalContext *ct
dbus_bool_t is_removed __attribute__((__unused__)),
dbus_bool_t is_added __attribute__((__unused__)))
{
- if (!g_strcasecmp (key, "volume.is_mounted")) {
- dbus_bool_t val;
+ dbus_bool_t val;
+ GSList *i;
+
+ if (g_strcasecmp (key, "volume.is_mounted") != 0)
+ return;
+
+ val = hal_device_get_property_bool (hal_ctx, udi, key);
+ if (val == TRUE) {
+ gboolean ignore_mount;
+
+ dbg ("Mounted: %s\n", udi);
+
+ /* add to list of all volumes mounted during lifetime */
+ all_mounted_volumes = g_slist_append (all_mounted_volumes,
+ g_strdup (udi));
+
+ ignore_mount = FALSE;
+ for (i = mount_ignore_udi_list;
+ i != NULL;
+ i = g_slist_next (i)) {
+ if (strcmp (udi, (const char *)i->data) == 0) {
+ ignore_mount = TRUE;
+ g_free (i->data);
+ mount_ignore_udi_list =
+ g_slist_remove_link (
+ mount_ignore_udi_list,
+ i);
+ break;
+ }
+ }
+
- val = hal_device_get_property_bool (hal_ctx, udi, key);
- if (val == TRUE) {
- dbg ("Mounted: %s\n", udi);
+ /* only autorun if not in ignore list, cf.
+ * function mount_all
+ */
+ if (!ignore_mount)
gvm_device_autorun (udi);
- } else
- dbg ("Unmounted: %s\n", udi);
- }
+
+ } else {
+ dbg ("Unmounted: %s\n", udi);
+
+ /* remove from list of all volumes mounted during lifetime */
+
+ for (i=all_mounted_volumes; i != NULL; i = g_slist_next (i)) {
+ if (strcmp (udi, (const char *)i->data) == 0) {
+ g_free (i->data);
+ all_mounted_volumes =
+ g_slist_remove_link (
+ all_mounted_volumes, i);
+ break;
+ }
+ }
+
+ }
}
/** Invoked when a device in the GDL emits a condition that cannot be
@@ -714,29 +800,6 @@ hal_device_condition (LibHalContext *ctx
const char *condition_name __attribute__((__unused__)),
DBusMessage * message __attribute__((__unused__)))
{
- if (!g_strcasecmp (condition_name, "EjectPressed")) {
- char *argv[3];
- GError *error = NULL;
- char *device;
-
- device = hal_device_get_property_string (ctx, udi,
- "block.device");
- if (!device)
- warn ("cannot get block.device\n");
- else if (config.eject_command) {
- argv[0] = config.eject_command;
- argv[1] = device;
- argv[2] = NULL;
-
- g_spawn_async (g_get_home_dir (), argv, NULL, 0, NULL,
- NULL, NULL, &error);
- if (error)
- warn ("failed to exec %s: %s\n",
- config.eject_command, error->message);
- }
-
- hal_free_string (device);
- }
}
/** Invoked by libhal for integration with our mainloop.
@@ -793,6 +856,147 @@ gvm_do_hal_init (LibHalFunctions *functi
return ctx;
}
+/** Attempt to mount all volumes; should be called on startup.
+ *
+ * @param ctx LibHal context
+ */
+static void mount_all (LibHalContext *ctx)
+{
+ int i;
+ int num_volumes;
+ char **volumes;
+ char *udi;
+ char *device_file;
+
+ if (!config.automount_media)
+ return;
+
+ volumes = hal_find_device_by_capability (ctx, "volume", &num_volumes);
+ for (i = 0; i < num_volumes; i++) {
+ udi = volumes [i];
+
+ /* don't attempt to mount already mounted volumes */
+ if (!hal_device_property_exists (ctx, udi,
+ "volume.is_mounted") ||
+ hal_device_get_property_bool (ctx, udi,
+ "volume.is_mounted"))
+ continue;
+
+ /* only mount if the block device got a sensible filesystem */
+ if (!hal_device_property_exists (ctx, udi,
+ "volume.is_filesystem") ||
+ !hal_device_get_property_bool (ctx, udi,
+ "volume.is_filesystem"))
+ continue;
+
+ device_file = hal_device_get_property_string (ctx, udi,
+ "block.device");
+
+ if (device_file != NULL ) {
+
+ if (gvm_device_mount (device_file)) {
+ /* yay, it worked; add to list of
+ * udi's not to autorun from hal_property_
+ * changed
+ */
+
+ mount_ignore_udi_list =
+ g_slist_append (mount_ignore_udi_list,
+ g_strdup (udi));
+
+ }
+
+ hal_free_string (device_file);
+ } else {
+ warn ("no device_file for udi=%s\n", udi);
+ }
+ }
+
+ hal_free_string_array (volumes);
+}
+
+/* Unmount all volumes that were mounted during the lifetime of this
+ * g-v-m instance
+ *
+ * @param ctx LibHal context
+ */
+static void
+unmount_all (LibHalContext *ctx)
+{
+ GSList *i;
+ char *device_file;
+ char *udi;
+
+ dbg ("unmounting all volumes that we saw mounted in our life\n");
+
+ for (i = all_mounted_volumes; i != NULL; i = g_slist_next (i)) {
+
+ udi = i->data;
+
+ device_file = hal_device_get_property_string (ctx, udi,
+ "block.device");
+
+ if (device_file != NULL ) {
+ gvm_device_unmount (device_file);
+ hal_free_string (device_file);
+ } else {
+ warn ("no device_file for udi=%s\n", udi);
+ }
+ }
+}
+
+
+static int sigterm_unix_signal_pipe_fds[2];
+static GIOChannel *sigterm_iochn;
+
+static void
+handle_sigterm (int value)
+{
+ static char marker[1] = {'S'};
+
+ /* write a 'S' character to the other end to tell about
+ * the signal. Note that 'the other end' is a GIOChannel thingy
+ * that is only called from the mainloop - thus this is how we
+ * defer this since UNIX signal handlers are evil
+ *
+ * Oh, and write(2) is indeed reentrant */
+ write (sigterm_unix_signal_pipe_fds[1], marker, 1);
+}
+
+static gboolean
+sigterm_iochn_data (GIOChannel *source,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ GError *err = NULL;
+ gchar data[1];
+ gsize bytes_read;
+
+ /* Empty the pipe */
+ if (G_IO_STATUS_NORMAL !=
+ g_io_channel_read_chars (source, data, 1, &bytes_read, &err)) {
+ warn ("Error emptying callout notify pipe: %s",
+ err->message);
+ g_error_free (err);
+ goto out;
+ }
+
+ dbg ("Recieved SIGTERM, initiating shutdown");
+ unmount_all (hal_ctx);
+ gtk_main_quit();
+
+out:
+ return TRUE;
+}
+
+static void
+gvm_die (GnomeClient *client, gpointer user_data)
+{
+ dbg ("Recieved 'die', initiating shutdown");
+ unmount_all (hal_ctx);
+ gtk_main_quit ();
+}
+
int
main (int argc, char *argv[])
{
@@ -822,13 +1026,29 @@ main (int argc, char *argv[])
}
gtk_signal_connect (GTK_OBJECT (client), "die",
- GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+ GTK_SIGNAL_FUNC (gvm_die), NULL);
hal_ctx = gvm_do_hal_init (&hal_functions);
if (!hal_ctx)
return 1;
gvm_init_config ();
+
+ /* SIGTERM handling via pipes */
+ if (pipe (sigterm_unix_signal_pipe_fds) != 0) {
+ warn ("Could not setup pipe, errno=%d", errno);
+ return 1;
+ }
+ sigterm_iochn = g_io_channel_unix_new (sigterm_unix_signal_pipe_fds[0]);
+ if (sigterm_iochn == NULL) {
+ warn ("Could not create GIOChannel");
+ return 1;
+ }
+ g_io_add_watch (sigterm_iochn, G_IO_IN, sigterm_iochn_data, NULL);
+ signal (SIGTERM, handle_sigterm);
+
+
+ mount_all (hal_ctx);
gtk_main ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]