[gvfs/wip/udisks2] udisks2: support unmounting non-udisks mounts using the /bin/umount command



commit 4f37ff4df75c9a8e80f06b9da2498d0e409923b0
Author: David Zeuthen <davidz redhat com>
Date:   Thu Sep 29 16:27:56 2011 -0400

    udisks2: support unmounting non-udisks mounts using the /bin/umount command
    
    Signed-off-by: David Zeuthen <davidz redhat com>

 monitor/udisks2/gvfsudisks2mount.c         |  178 ++++++++++++++++++++--------
 monitor/udisks2/gvfsudisks2volumemonitor.c |   37 ++++++
 2 files changed, 165 insertions(+), 50 deletions(-)
---
diff --git a/monitor/udisks2/gvfsudisks2mount.c b/monitor/udisks2/gvfsudisks2mount.c
index a4e105e..0c8ab54 100644
--- a/monitor/udisks2/gvfsudisks2mount.c
+++ b/monitor/udisks2/gvfsudisks2mount.c
@@ -57,6 +57,8 @@ struct _GVfsUDisks2Mount
   GObject parent;
 
   GVfsUDisks2VolumeMonitor *monitor; /* owned by volume monitor */
+
+  /* may be NULL */
   GVfsUDisks2Volume        *volume;  /* owned by volume monitor */
 
   /* the following members are set in update_mount() */
@@ -68,7 +70,7 @@ struct _GVfsUDisks2Mount
   gchar *mount_path;
   gboolean can_unmount;
   gchar *mount_entry_name;
-  GIcon *mount_entry_icon;
+  gchar *mount_entry_fs_type;
 
   gboolean is_burn_mount;
 
@@ -115,8 +117,7 @@ gvfs_udisks2_mount_finalize (GObject *object)
   g_free (mount->mount_path);
 
   g_free (mount->mount_entry_name);
-  if (mount->mount_entry_icon != NULL)
-    g_object_unref (mount->mount_entry_icon);
+  g_free (mount->mount_entry_fs_type);
 
   if (mount->autorun_icon != NULL)
     g_object_unref (mount->autorun_icon);
@@ -247,7 +248,20 @@ update_mount (GVfsUDisks2Mount *mount)
       else if (mount->autorun_icon != NULL)
         mount->icon = g_object_ref (mount->autorun_icon);
       else
-        mount->icon = mount->mount_entry_icon != NULL ? g_object_ref (mount->mount_entry_icon) : NULL;
+        {
+          const gchar *icon_name;
+          if (g_strcmp0 (mount->mount_entry_fs_type, "nfs") == 0 ||
+              g_strcmp0 (mount->mount_entry_fs_type, "nfs4") == 0 ||
+              g_strcmp0 (mount->mount_entry_fs_type, "cifs") == 0)
+            {
+              icon_name = "folder-remote";
+            }
+          else
+            {
+              icon_name = "drive-removable-media";
+            }
+          mount->icon = g_themed_icon_new_with_default_fallbacks (icon_name);
+        }
 
       g_free (mount->name);
 
@@ -332,7 +346,7 @@ gvfs_udisks2_mount_new (GVfsUDisks2VolumeMonitor *monitor,
     {
       /* No ref on GUnixMountEntry so save values for later use */
       mount->mount_entry_name = g_unix_mount_guess_name (mount_entry);
-      mount->mount_entry_icon = g_unix_mount_guess_icon (mount_entry);
+      mount->mount_entry_fs_type = g_strdup (g_unix_mount_get_fs_type (mount_entry));
       mount->device_file = g_strdup (g_unix_mount_get_device_path (mount_entry));
       mount->mount_path = g_strdup (g_unix_mount_get_mount_path (mount_entry));
       mount->root = g_file_new_for_path (mount->mount_path);
@@ -446,7 +460,7 @@ gvfs_udisks2_mount_get_volume (GMount *_mount)
   GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (_mount);
   GVolume *volume = NULL;
 
-  if (mount->volume)
+  if (mount->volume != NULL)
     volume = G_VOLUME (g_object_ref (mount->volume));
   return volume;
 }
@@ -657,6 +671,44 @@ on_mount_op_reply (GMountOperation       *mount_operation,
 }
 
 static void
+unmount_show_busy (UnmountData        *data,
+                   const gchar *const *mount_points)
+{
+  GArray *processes;
+  const gchar *choices[3] = {NULL, NULL, NULL};
+  const gchar *message;
+
+  processes = get_busy_processes (mount_points);
+
+  if (data->mount_op_reply_handler_id == 0)
+    {
+      data->mount_op_reply_handler_id = g_signal_connect (data->mount_operation,
+                                                          "reply",
+                                                          G_CALLBACK (on_mount_op_reply),
+                                                          data);
+    }
+  choices[0] = _("Unmount Anyway");
+  choices[1] = _("Cancel");
+  message = _("Volume is busy\n"
+              "One or more applications are keeping the volume busy.");
+  g_signal_emit_by_name (data->mount_operation,
+                         "show-processes",
+                         message,
+                         processes,
+                         choices);
+  /* set up a timer to try unmounting every two seconds - this will also
+   * update the list of busy processes
+   */
+  if (data->retry_unmount_timer_id == 0)
+    {
+      data->retry_unmount_timer_id = g_timeout_add_seconds (2,
+                                                            on_retry_timer_cb,
+                                                            data);
+    }
+  g_array_free (processes, TRUE);
+}
+
+static void
 unmount_cb (GObject       *source_object,
             GAsyncResult  *res,
             gpointer       user_data)
@@ -675,39 +727,7 @@ unmount_cb (GObject       *source_object,
       /* if the user passed in a GMountOperation, then do the GMountOperation::show-processes dance ... */
       if (error->code == G_IO_ERROR_BUSY && data->mount_operation != NULL)
         {
-          GArray *processes;
-          const gchar *choices[3] = {NULL, NULL, NULL};
-          const gchar *message;
-
-          processes = get_busy_processes (udisks_filesystem_get_mount_points (filesystem));
-
-          if (data->mount_op_reply_handler_id == 0)
-            {
-              data->mount_op_reply_handler_id = g_signal_connect (data->mount_operation,
-                                                                  "reply",
-                                                                  G_CALLBACK (on_mount_op_reply),
-                                                                  data);
-            }
-          choices[0] = _("Unmount Anyway");
-          choices[1] = _("Cancel");
-          message = _("Volume is busy\n"
-                      "One or more applications are keeping the volume busy.");
-          g_signal_emit_by_name (data->mount_operation,
-                                 "show-processes",
-                                 message,
-                                 processes,
-                                 choices);
-          /* set up a timer to try unmounting every two seconds - this will also
-           * update the list of busy processes
-           */
-          if (data->retry_unmount_timer_id == 0)
-            {
-              data->retry_unmount_timer_id = g_timeout_add_seconds (2,
-                                                                    on_retry_timer_cb,
-                                                                    data);
-            }
-
-          g_array_free (processes, TRUE);
+          unmount_show_busy (data, udisks_filesystem_get_mount_points (filesystem));
           goto out;
         }
       else
@@ -728,28 +748,86 @@ unmount_cb (GObject       *source_object,
 }
 
 static void
-unmount_do (UnmountData *data,
-            gboolean     force)
+unmount_do_command (UnmountData *data,
+                    gboolean     force)
 {
-  UDisksBlock *block;
-  UDisksFilesystem *filesystem;
-  GVariantBuilder builder;
+  GError *error;
+  gint exit_status;
+  gchar *standard_error = NULL;
+  const gchar *umount_argv[4] = {"umount", NULL, NULL, NULL};
 
-  if (data->mount->volume != NULL)
+  if (force)
     {
-      block = gvfs_udisks2_volume_get_block (data->mount->volume);
+      umount_argv[1] = "-l";
+      umount_argv[2] = data->mount->mount_path;
     }
   else
     {
-      g_simple_async_result_set_error (data->simple,
-                                       G_IO_ERROR,
-                                       G_IO_ERROR_FAILED,
-                                       "Don't know how to unmount non-udisks object yet (TODO)");
+      umount_argv[1] = data->mount->mount_path;
+    }
+
+  /* TODO: we could do this async but it's probably not worth the effort */
+  error = NULL;
+  if (!g_spawn_sync (NULL,            /* working dir */
+                     (gchar **) umount_argv,
+                     NULL,            /* envp */
+                     G_SPAWN_SEARCH_PATH,
+                     NULL,            /* child_setup */
+                     NULL,            /* user_data for child_setup */
+                     NULL,            /* standard_output */
+                     &standard_error, /* standard_error */
+                     &exit_status,
+                     &error))
+    {
+      g_prefix_error (&error, "Error running umount: ");
+      g_simple_async_result_take_error (data->simple, error);
       g_simple_async_result_complete (data->simple);
       unmount_data_free (data);
       goto out;
     }
 
+  if (WIFEXITED (exit_status) && WEXITSTATUS (exit_status) == 0)
+    {
+      gvfs_udisks2_volume_monitor_update (data->mount->monitor);
+      g_simple_async_result_complete (data->simple);
+      unmount_data_free (data);
+      goto out;
+    }
+
+  if (standard_error != NULL && strstr (standard_error, "device is busy") != NULL)
+    {
+      const gchar *mount_points[2] = {NULL, NULL};
+      mount_points[0] = data->mount->mount_path;
+      unmount_show_busy (data, mount_points);
+      goto out;
+    }
+
+  g_simple_async_result_set_error (data->simple,
+                                   G_IO_ERROR,
+                                   G_IO_ERROR_FAILED,
+                                   standard_error);
+  g_simple_async_result_complete (data->simple);
+  unmount_data_free (data);
+
+ out:
+  g_free (standard_error);
+}
+
+static void
+unmount_do (UnmountData *data,
+            gboolean     force)
+{
+  UDisksBlock *block;
+  UDisksFilesystem *filesystem;
+  GVariantBuilder builder;
+
+  if (data->mount->volume == NULL)
+    {
+      unmount_do_command (data, force);
+      goto out;
+    }
+
+  block = gvfs_udisks2_volume_get_block (data->mount->volume);
   filesystem = udisks_object_peek_filesystem (UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (block))));
   if (filesystem == NULL)
     {
diff --git a/monitor/udisks2/gvfsudisks2volumemonitor.c b/monitor/udisks2/gvfsudisks2volumemonitor.c
index f21c56d..3b46478 100644
--- a/monitor/udisks2/gvfsudisks2volumemonitor.c
+++ b/monitor/udisks2/gvfsudisks2volumemonitor.c
@@ -55,6 +55,7 @@ struct _GVfsUDisks2VolumeMonitor
 
   UDisksClient *client;
   GUdevClient *gudev_client;
+  GUnixMountMonitor *mount_monitor;
 
   GList *last_mounts;
 
@@ -112,6 +113,12 @@ static void on_interface_proxy_properties_changed (GDBusObjectManagerClient   *m
                                                    const gchar *const         *invalidated_properties,
                                                    gpointer                    user_data);
 
+static void mountpoints_changed      (GUnixMountMonitor  *mount_monitor,
+                                      gpointer            user_data);
+
+static void mounts_changed           (GUnixMountMonitor  *mount_monitor,
+                                      gpointer            user_data);
+
 G_DEFINE_TYPE (GVfsUDisks2VolumeMonitor, gvfs_udisks2_volume_monitor, G_TYPE_NATIVE_VOLUME_MONITOR)
 
 static void
@@ -129,6 +136,10 @@ gvfs_udisks2_volume_monitor_finalize (GObject *object)
   GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (object);
   GDBusObjectManager *object_manager;
 
+  g_signal_handlers_disconnect_by_func (monitor->mount_monitor, mountpoints_changed, monitor);
+  g_signal_handlers_disconnect_by_func (monitor->mount_monitor, mounts_changed, monitor);
+  g_clear_object (&monitor->mount_monitor);
+
   object_manager = udisks_client_get_object_manager (monitor->client);
   g_signal_handlers_disconnect_by_func (object_manager,
                                         G_CALLBACK (on_object_added),
@@ -346,6 +357,16 @@ gvfs_udisks2_volume_monitor_init (GVfsUDisks2VolumeMonitor *monitor)
                     G_CALLBACK (on_interface_proxy_properties_changed),
                     monitor);
 
+  monitor->mount_monitor = g_unix_mount_monitor_new ();
+  g_signal_connect (monitor->mount_monitor,
+                    "mounts-changed",
+                    G_CALLBACK (mounts_changed),
+                    monitor);
+  g_signal_connect (monitor->mount_monitor,
+                    "mountpoints-changed",
+                    G_CALLBACK (mountpoints_changed),
+                    monitor);
+
   update_all (monitor, FALSE);
 }
 
@@ -567,6 +588,22 @@ on_interface_proxy_properties_changed (GDBusObjectManagerClient   *manager,
   update_all (monitor, TRUE);
 }
 
+static void
+mountpoints_changed (GUnixMountMonitor *mount_monitor,
+                     gpointer           user_data)
+{
+  GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (user_data);
+  update_all (monitor, TRUE);
+}
+
+static void
+mounts_changed (GUnixMountMonitor *mount_monitor,
+                gpointer           user_data)
+{
+  GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (user_data);
+  update_all (monitor, TRUE);
+}
+
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]