From 52443c7793ca55cf53036ecb29a6032e9823b7dd Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Thu, 2 Apr 2009 13:54:20 -0400 Subject: [PATCH] use /proc/self/mountinfo and handle a device being mounted in multiple places This is an effort to fix https://bugzilla.redhat.com/show_bug.cgi?id=491924 Basically we have to somehow cope with a device being mounted in multiple places. So we replace the property String device-mount-path with an array of mount paths String device-mount-paths[] We also try to make an effort to ensure that the shortest mount point is shown before others. E.g. if you bind mount / on /foo then device-mount-paths = ["/", "/foo"] This means that desktop clients can just take the first mount path. Also make a note that this is the mount point in the root namespace. On systems clients running in other namespaces care has to be taken; in this case the client probably needs to examine /proc/self/mountinfo on his own to determine if a given block device is mounted or not. Also drop support for the 'remount' option; we might add it back later but since we now support multiple mount points it makes everything a bit weird. --- src/devkit-disks-daemon.c | 4 +- src/devkit-disks-device-private.c | 12 +- src/devkit-disks-device-private.h | 4 +- src/devkit-disks-device.c | 238 +++++++++++-------------- src/devkit-disks-device.h | 1 - src/devkit-disks-mount-file.c | 5 +- src/devkit-disks-mount-monitor.c | 175 ++++++++++++------ src/devkit-disks-mount-monitor.h | 11 +- src/devkit-disks-mount.c | 2 +- src/job-shared.h | 2 +- src/org.freedesktop.DeviceKit.Disks.Device.xml | 9 +- tools/devkit-disks.c | 20 ++- 12 files changed, 272 insertions(+), 211 deletions(-) diff --git a/src/devkit-disks-daemon.c b/src/devkit-disks-daemon.c index bbccc82..8e4b423 100644 --- a/src/devkit-disks-daemon.c +++ b/src/devkit-disks-daemon.c @@ -1067,8 +1067,8 @@ register_disks_daemon (DevkitDisksDaemon *daemon) G_CALLBACK (device_event_signal_handler), daemon); daemon->priv->mount_monitor = devkit_disks_mount_monitor_new (); - g_signal_connect (daemon->priv->mount_monitor, "mounted", (GCallback) mount_added, daemon); - g_signal_connect (daemon->priv->mount_monitor, "unmounted", (GCallback) mount_removed, daemon); + g_signal_connect (daemon->priv->mount_monitor, "mount-added", (GCallback) mount_added, daemon); + g_signal_connect (daemon->priv->mount_monitor, "mount-removed", (GCallback) mount_removed, daemon); return TRUE; error: diff --git a/src/devkit-disks-device-private.c b/src/devkit-disks-device-private.c index 9752523..63b4f85 100644 --- a/src/devkit-disks-device-private.c +++ b/src/devkit-disks-device-private.c @@ -69,7 +69,7 @@ ptr_str_array_equals_strv (GPtrArray *a, GStrv b) if (a->len == 0 && b == NULL) return TRUE; - b_len = g_strv_length (b); + b_len = (b != NULL ? g_strv_length (b) : 0); if (a->len != b_len) return FALSE; @@ -409,13 +409,13 @@ devkit_disks_device_set_device_is_mounted (DevkitDisksDevice *device, gboolean v } void -devkit_disks_device_set_device_mount_path (DevkitDisksDevice *device, const gchar *value) +devkit_disks_device_set_device_mount_paths (DevkitDisksDevice *device, GStrv value) { - if (G_UNLIKELY (g_strcmp0 (device->priv->device_mount_path, value) != 0)) + if (G_UNLIKELY (!ptr_str_array_equals_strv (device->priv->device_mount_paths, value))) { - g_free (device->priv->device_mount_path); - device->priv->device_mount_path = g_strdup (value); - emit_changed (device, "device_mount_path"); + ptr_str_array_free (device->priv->device_mount_paths); + device->priv->device_mount_paths = ptr_str_array_from_strv (value); + emit_changed (device, "device_mount_paths"); } } diff --git a/src/devkit-disks-device-private.h b/src/devkit-disks-device-private.h index 9bd3f10..09b9cb1 100644 --- a/src/devkit-disks-device-private.h +++ b/src/devkit-disks-device-private.h @@ -121,7 +121,7 @@ struct DevkitDisksDevicePrivate guint64 device_size; guint64 device_block_size; gboolean device_is_mounted; - char *device_mount_path; + GPtrArray *device_mount_paths; uid_t device_mounted_by_uid; char *device_presentation_name; char *device_presentation_icon_name; @@ -251,7 +251,7 @@ void devkit_disks_device_set_device_is_linux_md (DevkitDisksDevice *device, gboo void devkit_disks_device_set_device_size (DevkitDisksDevice *device, guint64 value); void devkit_disks_device_set_device_block_size (DevkitDisksDevice *device, guint64 value); void devkit_disks_device_set_device_is_mounted (DevkitDisksDevice *device, gboolean value); -void devkit_disks_device_set_device_mount_path (DevkitDisksDevice *device, const gchar *value); +void devkit_disks_device_set_device_mount_paths (DevkitDisksDevice *device, GStrv value); void devkit_disks_device_set_device_mounted_by_uid (DevkitDisksDevice *device, guint value); void devkit_disks_device_set_device_presentation_name (DevkitDisksDevice *device, const gchar *value); void devkit_disks_device_set_device_presentation_icon_name (DevkitDisksDevice *device, const gchar *value); diff --git a/src/devkit-disks-device.c b/src/devkit-disks-device.c index fb7cd49..4d2f90b 100644 --- a/src/devkit-disks-device.c +++ b/src/devkit-disks-device.c @@ -154,7 +154,7 @@ enum PROP_DEVICE_BLOCK_SIZE, PROP_DEVICE_IS_MOUNTED, PROP_DEVICE_IS_BUSY, - PROP_DEVICE_MOUNT_PATH, + PROP_DEVICE_MOUNT_PATHS, PROP_DEVICE_MOUNTED_BY_UID, PROP_DEVICE_PRESENTATION_NAME, PROP_DEVICE_PRESENTATION_ICON_NAME, @@ -367,8 +367,8 @@ get_property (GObject *object, /* this property is special; it's value is computed on demand */ g_value_set_boolean (value, devkit_disks_device_local_is_busy (device)); break; - case PROP_DEVICE_MOUNT_PATH: - g_value_set_string (value, device->priv->device_mount_path); + case PROP_DEVICE_MOUNT_PATHS: + g_value_set_boxed (value, device->priv->device_mount_paths); break; case PROP_DEVICE_MOUNTED_BY_UID: g_value_set_uint (value, device->priv->device_mounted_by_uid); @@ -800,8 +800,10 @@ devkit_disks_device_class_init (DevkitDisksDeviceClass *klass) g_param_spec_boolean ("device-is-busy", NULL, NULL, FALSE, G_PARAM_READABLE)); g_object_class_install_property ( object_class, - PROP_DEVICE_MOUNT_PATH, - g_param_spec_string ("device-mount-path", NULL, NULL, NULL, G_PARAM_READABLE)); + PROP_DEVICE_MOUNT_PATHS, + g_param_spec_boxed ("device-mount-paths", NULL, NULL, + dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING), + G_PARAM_READABLE)); g_object_class_install_property ( object_class, PROP_DEVICE_MOUNTED_BY_UID, @@ -1177,6 +1179,7 @@ devkit_disks_device_init (DevkitDisksDevice *device) device->priv->device_file_by_id = g_ptr_array_new (); device->priv->device_file_by_path = g_ptr_array_new (); + device->priv->device_mount_paths = g_ptr_array_new (); device->priv->partition_flags = g_ptr_array_new (); device->priv->drive_media_compatibility = g_ptr_array_new (); device->priv->linux_md_component_state = g_ptr_array_new (); @@ -1227,7 +1230,7 @@ devkit_disks_device_finalize (GObject *object) g_ptr_array_foreach (device->priv->device_file_by_path, (GFunc) g_free, NULL); g_ptr_array_free (device->priv->device_file_by_id, TRUE); g_ptr_array_free (device->priv->device_file_by_path, TRUE); - g_free (device->priv->device_mount_path); + g_ptr_array_free (device->priv->device_mount_paths, TRUE); g_free (device->priv->device_presentation_name); g_free (device->priv->device_presentation_icon_name); @@ -2659,10 +2662,10 @@ update_info_mount_state (DevkitDisksDevice *device) { DevkitDisksMountMonitor *monitor; DevkitDisksMount *mount; + GList *mounts; gboolean was_mounted; - gchar *old_mount_path; - old_mount_path = NULL; + mounts = NULL; /* defer setting the mount point until FilesystemMount returns and * the mounts file is written @@ -2671,14 +2674,24 @@ update_info_mount_state (DevkitDisksDevice *device) goto out; monitor = devkit_disks_daemon_local_get_mount_monitor (device->priv->daemon); - mount = devkit_disks_mount_monitor_get_mount_for_dev (monitor, device->priv->dev); + + mounts = devkit_disks_mount_monitor_get_mounts_for_dev (monitor, device->priv->dev); was_mounted = device->priv->device_is_mounted; - old_mount_path = g_strdup (device->priv->device_mount_path); - if (mount != NULL) { + if (mounts != NULL) { + GList *l; + guint n; + gchar **mount_paths; + + mount = g_object_ref (mounts->data); + mount_paths = g_new0 (gchar *, g_list_length (mounts) + 1); + for (l = mounts, n = 0; l != NULL; l = l->next, n++) { + mount_paths[n] = g_strdup (devkit_disks_mount_get_mount_path (DEVKIT_DISKS_MOUNT (l->data))); + } + devkit_disks_device_set_device_is_mounted (device, TRUE); - devkit_disks_device_set_device_mount_path (device, devkit_disks_mount_get_mount_path (mount)); + devkit_disks_device_set_device_mount_paths (device, mount_paths); if (!was_mounted) { uid_t mounted_by_uid; @@ -2686,16 +2699,26 @@ update_info_mount_state (DevkitDisksDevice *device) mounted_by_uid = 0; devkit_disks_device_set_device_mounted_by_uid (device, mounted_by_uid); } + + g_strfreev (mount_paths); + } else { gboolean remove_dir_on_unmount; + gchar *old_mount_path; + + old_mount_path = NULL; + if (device->priv->device_mount_paths->len > 0) + old_mount_path = g_strdup (((gchar **) device->priv->device_mount_paths->pdata)[0]); devkit_disks_device_set_device_is_mounted (device, FALSE); - devkit_disks_device_set_device_mount_path (device, NULL); + devkit_disks_device_set_device_mount_paths (device, NULL); devkit_disks_device_set_device_mounted_by_uid (device, 0); /* clean up stale mount directory */ remove_dir_on_unmount = FALSE; - if (was_mounted && devkit_disks_mount_file_has_device (device->priv->device_file, NULL, &remove_dir_on_unmount)) { + if (was_mounted && devkit_disks_mount_file_has_device (device->priv->device_file, + NULL, + &remove_dir_on_unmount)) { devkit_disks_mount_file_remove (device->priv->device_file, old_mount_path); if (remove_dir_on_unmount) { if (g_rmdir (old_mount_path) != 0) { @@ -2704,10 +2727,13 @@ update_info_mount_state (DevkitDisksDevice *device) } } + g_free (old_mount_path); + } out: - g_free (old_mount_path); + g_list_foreach (mounts, (GFunc) g_object_unref, NULL); + g_list_free (mounts); return TRUE; } @@ -3501,12 +3527,6 @@ devkit_disks_device_local_get_device_file (DevkitDisksDevice *device) return device->priv->device_file; } -const char * -devkit_disks_device_local_get_mount_path (DevkitDisksDevice *device) -{ - return device->priv->device_mount_path; -} - /*--------------------------------------------------------------------------------------------------------------*/ static gboolean @@ -3933,17 +3953,15 @@ out: typedef struct { char *mount_point; gboolean remove_dir_on_unmount; - gboolean is_remount; } MountData; static MountData * -filesystem_mount_data_new (const char *mount_point, gboolean remove_dir_on_unmount, gboolean is_remount) +filesystem_mount_data_new (const char *mount_point, gboolean remove_dir_on_unmount) { MountData *data; data = g_new0 (MountData, 1); data->mount_point = g_strdup (mount_point); data->remove_dir_on_unmount = remove_dir_on_unmount; - data->is_remount = is_remount; return data; } @@ -4091,7 +4109,6 @@ static const char *any_allow[] = {"exec", "atime", "noatime", "nodiratime", - "remount", "ro", "rw", "sync", @@ -4332,13 +4349,11 @@ filesystem_mount_completed_cb (DBusGMethodInvocation *context, dbus_g_method_return (context, data->mount_point); } else { - if (!data->is_remount) { - devkit_disks_mount_file_remove (device->priv->device_file, data->mount_point); + devkit_disks_mount_file_remove (device->priv->device_file, data->mount_point); - if (data->remove_dir_on_unmount) { - if (g_rmdir (data->mount_point) != 0) { - g_warning ("Error removing dir in late mount error path: %m"); - } + if (data->remove_dir_on_unmount) { + if (g_rmdir (data->mount_point) != 0) { + g_warning ("Error removing dir in late mount error path: %m"); } } @@ -4374,14 +4389,12 @@ devkit_disks_device_filesystem_mount (DevkitDisksDevice *device, gboolean remove_dir_on_unmount; const FSMountOptions *fsmo; char **options; - gboolean is_remount; char uid_buf[32]; fstype = NULL; options = NULL; mount_options = NULL; mount_point = NULL; - is_remount = FALSE; if ((pk_caller = devkit_disks_damon_local_get_caller_for_context (device->priv->daemon, context)) == NULL) goto out; @@ -4467,9 +4480,6 @@ devkit_disks_device_filesystem_mount (DevkitDisksDevice *device, goto out; } - if (strcmp (option, "remount") == 0) - is_remount = TRUE; - g_string_append_c (s, ','); g_string_append (s, option); } @@ -4478,94 +4488,59 @@ devkit_disks_device_filesystem_mount (DevkitDisksDevice *device, g_print ("**** USING MOUNT OPTIONS '%s' FOR DEVICE %s\n", mount_options, device->priv->device_file); if (device->priv->device_is_mounted) { - if (!is_remount) { - throw_error (context, DEVKIT_DISKS_ERROR_ALREADY_MOUNTED, - "Device is already mounted"); - goto out; - } + throw_error (context, DEVKIT_DISKS_ERROR_ALREADY_MOUNTED, + "Device is already mounted"); + goto out; } - /* TODO: check for auth if user tries to remount something mounted by another user */ - - /* handle some constraints required by remount */ - if (is_remount) { - if (!device->priv->device_is_mounted || - device->priv->device_mount_path == NULL) { - throw_error (context, - DEVKIT_DISKS_ERROR_NOT_MOUNTED, - "Can't remount a device that is not mounted"); - goto out; - } - - if (strlen (filesystem_type) > 0) { - throw_error (context, - DEVKIT_DISKS_ERROR_FAILED, - "Can't remount a device with a different file system type"); - goto out; - } + /* Determine the mount point to use. + * + * TODO: use characteristics of the drive such as the name, connection etc. + * to get better names (/media/disk is kinda lame). + */ + if (device->priv->id_label != NULL && strlen (device->priv->id_label) > 0 ) { + mount_point = g_build_filename ("/media", device->priv->id_label, NULL); + } else if (device->priv->id_uuid != NULL && strlen (device->priv->id_uuid) > 0) { + mount_point = g_build_filename ("/media", device->priv->id_uuid, NULL); + } else { + mount_point = g_strdup ("/media/disk"); } - if (!is_remount) { - /* Determine the mount point to use. - * - * TODO: use characteristics of the drive such as the name, connection etc. - * to get better names (/media/disk is kinda lame). - */ - if (device->priv->id_label != NULL && strlen (device->priv->id_label) > 0 ) { - mount_point = g_build_filename ("/media", device->priv->id_label, NULL); - } else if (device->priv->id_uuid != NULL && strlen (device->priv->id_uuid) > 0) { - mount_point = g_build_filename ("/media", device->priv->id_uuid, NULL); - } else { - mount_point = g_strdup ("/media/disk"); - } - try_another_mount_point: - /* ... then uniqify the mount point and mkdir it */ - if (g_file_test (mount_point, G_FILE_TEST_EXISTS)) { - char *s = mount_point; - /* TODO: append numbers instead of _, __ and so on */ - mount_point = g_strdup_printf ("%s_", mount_point); - g_free (s); - goto try_another_mount_point; - } + /* ... then uniqify the mount point and mkdir it */ + if (g_file_test (mount_point, G_FILE_TEST_EXISTS)) { + char *s = mount_point; + /* TODO: append numbers instead of _, __ and so on */ + mount_point = g_strdup_printf ("%s_", mount_point); + g_free (s); + goto try_another_mount_point; + } - remove_dir_on_unmount = TRUE; + remove_dir_on_unmount = TRUE; - if (g_mkdir (mount_point, 0700) != 0) { - throw_error (context, DEVKIT_DISKS_ERROR_FAILED, "Error creating moint point: %m"); - goto out; - } - - n = 0; - argv[n++] = "mount"; - argv[n++] = "-t"; - argv[n++] = fstype; - argv[n++] = "-o"; - argv[n++] = mount_options; - argv[n++] = device->priv->device_file; - argv[n++] = mount_point; - argv[n++] = NULL; - } else { - /* we recycle the mount point on remount */ - mount_point = g_strdup (device->priv->device_mount_path); - n = 0; - argv[n++] = "mount"; - argv[n++] = "-o"; - argv[n++] = mount_options; - argv[n++] = mount_point; - argv[n++] = NULL; + if (g_mkdir (mount_point, 0700) != 0) { + throw_error (context, DEVKIT_DISKS_ERROR_FAILED, "Error creating moint point: %m"); + goto out; } + n = 0; + argv[n++] = "mount"; + argv[n++] = "-t"; + argv[n++] = fstype; + argv[n++] = "-o"; + argv[n++] = mount_options; + argv[n++] = device->priv->device_file; + argv[n++] = mount_point; + argv[n++] = NULL; + run_job: - if (!is_remount) { - /* now that we have a mount point, immediately add it to the - * /var/lib/DeviceKit-disks/mtab file - */ - devkit_disks_mount_file_add (device->priv->device_file, - mount_point, - caller_uid, - remove_dir_on_unmount); - } + /* now that we have a mount point, immediately add it to the + * /var/lib/DeviceKit-disks/mtab file + */ + devkit_disks_mount_file_add (device->priv->device_file, + mount_point, + caller_uid, + remove_dir_on_unmount); error = NULL; if (!job_new (context, @@ -4576,14 +4551,12 @@ run_job: argv, NULL, filesystem_mount_completed_cb, - filesystem_mount_data_new (mount_point, remove_dir_on_unmount, is_remount), + filesystem_mount_data_new (mount_point, remove_dir_on_unmount), (GDestroyNotify) filesystem_mount_data_free)) { - if (!is_remount) { - devkit_disks_mount_file_remove (device->priv->device_file, mount_point); - if (remove_dir_on_unmount) { - if (g_rmdir (mount_point) != 0) { - g_warning ("Error removing dir in early mount error path: %m"); - } + devkit_disks_mount_file_remove (device->priv->device_file, mount_point); + if (remove_dir_on_unmount) { + if (g_rmdir (mount_point) != 0) { + g_warning ("Error removing dir in early mount error path: %m"); } } goto out; @@ -4661,7 +4634,7 @@ devkit_disks_device_filesystem_unmount (DevkitDisksDevice *device, polkit_caller_get_uid (pk_caller, &uid); if (!device->priv->device_is_mounted || - device->priv->device_mount_path == NULL) { + device->priv->device_mount_paths->len == 0) { throw_error (context, DEVKIT_DISKS_ERROR_NOT_MOUNTED, "Device is not mounted"); @@ -4727,17 +4700,17 @@ devkit_disks_device_filesystem_unmount (DevkitDisksDevice *device, goto out; } + mount_path = g_strdup (((gchar **) device->priv->device_mount_paths->pdata)[0]); + n = 0; argv[n++] = "umount"; if (force_unmount) { /* on Linux we currently only have lazy unmount to emulate this */ argv[n++] = "-l"; } - argv[n++] = device->priv->device_mount_path; + argv[n++] = mount_path; argv[n++] = NULL; - mount_path = g_strdup (device->priv->device_mount_path); - run_job: error = NULL; if (!job_new (context, @@ -4877,7 +4850,7 @@ devkit_disks_device_filesystem_list_open_files (DevkitDisksDevice *device, goto out; if (!device->priv->device_is_mounted || - device->priv->device_mount_path == NULL) { + device->priv->device_mount_paths->len == 0) { throw_error (context, DEVKIT_DISKS_ERROR_NOT_MOUNTED, "Device is not mounted"); @@ -4895,7 +4868,7 @@ devkit_disks_device_filesystem_list_open_files (DevkitDisksDevice *device, n = 0; argv[n++] = "lsof"; argv[n++] = "-t"; - argv[n++] = device->priv->device_mount_path; + argv[n++] = ((gchar **) device->priv->device_mount_paths->pdata)[0]; argv[n++] = NULL; error = NULL; @@ -8688,7 +8661,7 @@ typedef struct { } ForceUnmountData; static ForceUnmountData * -force_unmount_data_new (char *mount_path, +force_unmount_data_new (const gchar *mount_path, ForceRemovalCompleteFunc fr_callback, gpointer fr_user_data) { @@ -8752,12 +8725,15 @@ force_unmount (DevkitDisksDevice *device, int n; char *argv[16]; GError *error; + const gchar *mount_path; + + mount_path = ((gchar **) device->priv->device_mount_paths->pdata)[0]; n = 0; argv[n++] = "umount"; /* on Linux, we only have lazy unmount for now */ argv[n++] = "-l"; - argv[n++] = device->priv->device_mount_path; + argv[n++] = (gchar *) mount_path; argv[n++] = NULL; error = NULL; @@ -8769,7 +8745,7 @@ force_unmount (DevkitDisksDevice *device, argv, NULL, force_unmount_completed_cb, - force_unmount_data_new (device->priv->device_mount_path, callback, user_data), + force_unmount_data_new (mount_path, callback, user_data), (GDestroyNotify) force_unmount_data_unref)) { g_warning ("Couldn't spawn unmount for force unmounting: %s", error->message); g_error_free (error); @@ -8928,7 +8904,7 @@ force_removal (DevkitDisksDevice *device, * companion. If so, tear it down if it was setup by us. * */ - if (device->priv->device_is_mounted && device->priv->device_mount_path != NULL) { + if (device->priv->device_is_mounted && device->priv->device_mount_paths->len > 0) { gboolean remove_dir_on_unmount; if (devkit_disks_mount_file_has_device (device->priv->device_file, NULL, &remove_dir_on_unmount)) { diff --git a/src/devkit-disks-device.h b/src/devkit-disks-device.h index 667870c..3ca79ab 100644 --- a/src/devkit-disks-device.h +++ b/src/devkit-disks-device.h @@ -68,7 +68,6 @@ const char *devkit_disks_device_local_get_native_path (DevkitDisksDev dev_t devkit_disks_device_local_get_dev (DevkitDisksDevice *device); const char *devkit_disks_device_local_get_device_file (DevkitDisksDevice *device); -const char *devkit_disks_device_local_get_mount_path (DevkitDisksDevice *device); /* exported methods */ diff --git a/src/devkit-disks-mount-file.c b/src/devkit-disks-mount-file.c index 5de48fc..ae5cdb2 100644 --- a/src/devkit-disks-mount-file.c +++ b/src/devkit-disks-mount-file.c @@ -298,11 +298,10 @@ devkit_disks_mount_file_clean_stale (GList *existing_devices) char *mount_path_escaped; if (!device->priv->device_is_mounted || - device->priv->device_mount_path == NULL) + device->priv->device_mount_paths == NULL) continue; - mount_path_escaped = - g_uri_escape_string (device->priv->device_mount_path, NULL, TRUE); + mount_path_escaped = g_uri_escape_string (((gchar **) device->priv->device_mount_paths->pdata)[0], NULL, TRUE); if (strcmp (line_mount_path, mount_path_escaped) == 0) { entry_is_valid = TRUE; diff --git a/src/devkit-disks-mount-monitor.c b/src/devkit-disks-mount-monitor.c index ff4722a..0868473 100644 --- a/src/devkit-disks-mount-monitor.c +++ b/src/devkit-disks-mount-monitor.c @@ -43,8 +43,8 @@ enum { - MOUNTED_SIGNAL, - UNMOUNTED_SIGNAL, + MOUNT_ADDED_SIGNAL, + MOUNT_REMOVED_SIGNAL, LAST_SIGNAL, }; @@ -53,8 +53,8 @@ static guint signals[LAST_SIGNAL] = { 0 }; struct DevkitDisksMountMonitorPrivate { GIOChannel *mounts_channel; - GHashTable *mounts; gboolean have_data; + GList *mounts; }; G_DEFINE_TYPE (DevkitDisksMountMonitor, devkit_disks_mount_monitor, G_TYPE_OBJECT) @@ -69,7 +69,8 @@ devkit_disks_mount_monitor_finalize (GObject *object) if (monitor->priv->mounts_channel != NULL) g_io_channel_unref (monitor->priv->mounts_channel); - g_hash_table_unref (monitor->priv->mounts); + g_list_foreach (monitor->priv->mounts, (GFunc) g_object_unref, NULL); + g_list_free (monitor->priv->mounts); if (G_OBJECT_CLASS (devkit_disks_mount_monitor_parent_class)->finalize != NULL) (* G_OBJECT_CLASS (devkit_disks_mount_monitor_parent_class)->finalize) (object); @@ -82,10 +83,7 @@ devkit_disks_mount_monitor_init (DevkitDisksMountMonitor *monitor) DEVKIT_DISKS_TYPE_MOUNT_MONITOR, DevkitDisksMountMonitorPrivate); - monitor->priv->mounts = g_hash_table_new_full (g_direct_hash, - g_direct_equal, - NULL, - g_object_unref); + monitor->priv->mounts = NULL; } static void @@ -98,17 +96,17 @@ devkit_disks_mount_monitor_class_init (DevkitDisksMountMonitorClass *klass) g_type_class_add_private (klass, sizeof (DevkitDisksMountMonitorPrivate)); /** - * DevkitDisksMountMonitor::mounted + * DevkitDisksMountMonitor::mount-added * @monitor: A #DevkitDisksMountMonitor. - * @mount: The #DevkitDisksMount that was mounted. + * @mount: The #DevkitDisksMount that was added. * - * Emitted when a filesystem is mounted. + * Emitted when a mount is added. */ - signals[MOUNTED_SIGNAL] = - g_signal_new ("mounted", + signals[MOUNT_ADDED_SIGNAL] = + g_signal_new ("mount-added", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, + G_STRUCT_OFFSET (DevkitDisksMountMonitorClass, mount_added), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, @@ -117,17 +115,17 @@ devkit_disks_mount_monitor_class_init (DevkitDisksMountMonitorClass *klass) DEVKIT_DISKS_TYPE_MOUNT); /** - * DevkitDisksMountMonitor::unmounted + * DevkitDisksMountMonitor::mount-removed * @monitor: A #DevkitDisksMountMonitor. - * @mount: The #DevkitDisksMount that was unmounted. + * @mount: The #DevkitDisksMount that was removed. * - * Emitted when a filesystem is unmounted. + * Emitted when a mount is removed. */ - signals[UNMOUNTED_SIGNAL] = - g_signal_new ("unmounted", + signals[MOUNT_REMOVED_SIGNAL] = + g_signal_new ("mount-removed", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, + G_STRUCT_OFFSET (DevkitDisksMountMonitorClass, mount_removed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, @@ -193,14 +191,17 @@ mounts_changed_event (GIOChannel *channel, GIOCondition cond, gpointer user_data if (cond & ~G_IO_ERR) goto out; + g_debug ("/proc/self/mountinfo changed"); + devkit_disks_mount_monitor_ensure (monitor); - old_mounts = g_hash_table_get_values (monitor->priv->mounts); + + old_mounts = g_list_copy (monitor->priv->mounts); g_list_foreach (old_mounts, (GFunc) g_object_ref, NULL); devkit_disks_mount_monitor_invalidate (monitor); devkit_disks_mount_monitor_ensure (monitor); - cur_mounts = g_hash_table_get_values (monitor->priv->mounts); + cur_mounts = g_list_copy (monitor->priv->mounts); old_mounts = g_list_sort (old_mounts, (GCompareFunc) devkit_disks_mount_compare); cur_mounts = g_list_sort (cur_mounts, (GCompareFunc) devkit_disks_mount_compare); @@ -214,7 +215,7 @@ mounts_changed_event (GIOChannel *channel, GIOCondition cond, gpointer user_data for (l = removed; l != NULL; l = l->next) { DevkitDisksMount *mount = DEVKIT_DISKS_MOUNT (l->data); g_signal_emit (monitor, - signals[UNMOUNTED_SIGNAL], + signals[MOUNT_REMOVED_SIGNAL], 0, mount); } @@ -222,7 +223,7 @@ mounts_changed_event (GIOChannel *channel, GIOCondition cond, gpointer user_data for (l = added; l != NULL; l = l->next) { DevkitDisksMount *mount = DEVKIT_DISKS_MOUNT (l->data); g_signal_emit (monitor, - signals[MOUNTED_SIGNAL], + signals[MOUNT_ADDED_SIGNAL], 0, mount); } @@ -247,11 +248,11 @@ devkit_disks_mount_monitor_new (void) mount_monitor = DEVKIT_DISKS_MOUNT_MONITOR (g_object_new (DEVKIT_DISKS_TYPE_MOUNT_MONITOR, NULL)); error = NULL; - mount_monitor->priv->mounts_channel = g_io_channel_new_file ("/proc/mounts", "r", &error); + mount_monitor->priv->mounts_channel = g_io_channel_new_file ("/proc/self/mountinfo", "r", &error); if (mount_monitor->priv->mounts_channel != NULL) { g_io_add_watch (mount_monitor->priv->mounts_channel, G_IO_ERR, mounts_changed_event, mount_monitor); } else { - g_warning ("No /proc/mounts file: %s", error->message); + g_warning ("No /proc/self/mountinfo file: %s", error->message); g_error_free (error); g_object_unref (mount_monitor); mount_monitor = NULL; @@ -266,59 +267,131 @@ void devkit_disks_mount_monitor_invalidate (DevkitDisksMountMonitor *monitor) { monitor->priv->have_data = FALSE; - g_hash_table_remove_all (monitor->priv->mounts); + + g_list_foreach (monitor->priv->mounts, (GFunc) g_object_unref, NULL); + g_list_free (monitor->priv->mounts); + monitor->priv->mounts = NULL; +} + +static gboolean +have_mount (DevkitDisksMountMonitor *monitor, + dev_t dev, + const gchar *mount_point) +{ + GList *l; + gboolean ret; + + ret = FALSE; + + for (l = monitor->priv->mounts; l != NULL; l = l->next) { + DevkitDisksMount *mount = DEVKIT_DISKS_MOUNT (l->data); + if (devkit_disks_mount_get_dev (mount) == dev && + g_strcmp0 (devkit_disks_mount_get_mount_path (mount), mount_point) == 0) { + ret = TRUE; + break; + } + } + + return ret; } static void devkit_disks_mount_monitor_ensure (DevkitDisksMountMonitor *monitor) { - struct mntent *m; - FILE *f; + gchar *contents; + gchar **lines; + GError *error; + guint n; + + contents = NULL; + lines = NULL; if (monitor->priv->have_data) goto out; - f = fopen ("/proc/mounts", "r"); - if (f == NULL) { - g_warning ("error opening /proc/mounts: %m"); + error = NULL; + if (!g_file_get_contents ("/proc/self/mountinfo", &contents, NULL, &error)) { + g_warning ("Error reading /proc/self/mountinfo: %s", error->message); + g_error_free (error); goto out; } - while ((m = getmntent (f)) != NULL) { - DevkitDisksMount *mount; - struct stat statbuf; - /* ignore if not an absolute patch */ - if (m->mnt_fsname[0] != '/') + /* See Documentation/filesystems/proc.txt for the format of /proc/self/mountinfo + * + * Note that things like space are encoded as \020. + */ + + lines = g_strsplit (contents, "\n", 0); + for (n = 0; lines[n] != NULL; n++) { + guint mount_id; + guint parent_id; + guint major, minor; + gchar encoded_root[PATH_MAX]; + gchar encoded_mount_point[PATH_MAX]; + gchar *mount_point; + dev_t dev; + + if (strlen (lines[n]) == 0) + continue; + + if (sscanf (lines[n], "%d %d %d:%d %s %s", + &mount_id, + &parent_id, + &major, + &minor, + encoded_root, + encoded_mount_point) != 6) { + g_warning ("Error parsing line '%s'", lines[n]); + continue; + } + + /* ignore mounts where only a subtree of a filesystem is mounted */ + if (g_strcmp0 (encoded_root, "/") != 0) continue; - if (stat (m->mnt_fsname, &statbuf) != 0) { - g_warning ("Cannot stat %s: %m", m->mnt_fsname); - } else if (statbuf.st_rdev != 0) { + mount_point = g_strcompress (encoded_mount_point); - mount = _devkit_disks_mount_new (statbuf.st_rdev, m->mnt_dir); + dev = makedev (major, minor); - g_hash_table_insert (monitor->priv->mounts, - GINT_TO_POINTER (statbuf.st_rdev), - mount); + /* TODO: we can probably use a hash table or something if this turns out to be slow */ + if (!have_mount (monitor, dev, mount_point)) { + DevkitDisksMount *mount; + mount = _devkit_disks_mount_new (dev, mount_point); + monitor->priv->mounts = g_list_prepend (monitor->priv->mounts, mount); + g_debug ("SUP ADDING %d:%d on %s", major, minor, mount_point); } + + g_free (mount_point); } - fclose (f); monitor->priv->have_data = TRUE; out: - ; + g_free (contents); + g_strfreev (lines); } -DevkitDisksMount * -devkit_disks_mount_monitor_get_mount_for_dev (DevkitDisksMountMonitor *monitor, - dev_t dev) +GList * +devkit_disks_mount_monitor_get_mounts_for_dev (DevkitDisksMountMonitor *monitor, + dev_t dev) { - DevkitDisksMount *ret; + GList *ret; + GList *l; + + ret = NULL; devkit_disks_mount_monitor_ensure (monitor); - ret = g_hash_table_lookup (monitor->priv->mounts, GINT_TO_POINTER (dev)); + for (l = monitor->priv->mounts; l != NULL; l = l->next) { + DevkitDisksMount *mount = DEVKIT_DISKS_MOUNT (l->data); + + if (devkit_disks_mount_get_dev (mount) == dev) { + ret = g_list_prepend (ret, g_object_ref (mount)); + } + } + + /* Sort the list to ensure that shortest mount paths appear first */ + ret = g_list_sort (ret, (GCompareFunc) devkit_disks_mount_compare); return ret; } diff --git a/src/devkit-disks-mount-monitor.h b/src/devkit-disks-mount-monitor.h index ac9a9ee..8727580 100644 --- a/src/devkit-disks-mount-monitor.h +++ b/src/devkit-disks-mount-monitor.h @@ -38,17 +38,26 @@ typedef struct DevkitDisksMountMonitorPrivate DevkitDisksMountMonitorPrivate; struct DevkitDisksMountMonitor { GObject parent; + + /*< private >*/ DevkitDisksMountMonitorPrivate *priv; }; struct DevkitDisksMountMonitorClass { GObjectClass parent_class; + + /*< public >*/ + /* signals */ + void (*mount_added) (DevkitDisksMountMonitor *monitor, + DevkitDisksMount *mount); + void (*mount_removed) (DevkitDisksMountMonitor *monitor, + DevkitDisksMount *mount); }; GType devkit_disks_mount_monitor_get_type (void) G_GNUC_CONST; DevkitDisksMountMonitor *devkit_disks_mount_monitor_new (void); -DevkitDisksMount *devkit_disks_mount_monitor_get_mount_for_dev (DevkitDisksMountMonitor *monitor, +GList *devkit_disks_mount_monitor_get_mounts_for_dev (DevkitDisksMountMonitor *monitor, dev_t dev); void devkit_disks_mount_monitor_invalidate (DevkitDisksMountMonitor *monitor); diff --git a/src/devkit-disks-mount.c b/src/devkit-disks-mount.c index 3f71375..c4bdbf3 100644 --- a/src/devkit-disks-mount.c +++ b/src/devkit-disks-mount.c @@ -110,7 +110,7 @@ devkit_disks_mount_compare (DevkitDisksMount *a, { gint ret; - ret = g_strcmp0 (a->priv->mount_path, b->priv->mount_path); + ret = g_strcmp0 (b->priv->mount_path, a->priv->mount_path); if (ret != 0) goto out; diff --git a/src/job-shared.h b/src/job-shared.h index 24d4e17..7b04ddd 100644 --- a/src/job-shared.h +++ b/src/job-shared.h @@ -225,8 +225,8 @@ task_zero_device (const char *device, guint64 offset, guint64 size, int num_pass goto out; cursor += num; - percent = 100 * cursor / size; + if (percent > old_percent) { g_print ("progress: %d %d %d zeroing\n", cur_task, num_tasks, percent); old_percent = percent; diff --git a/src/org.freedesktop.DeviceKit.Disks.Device.xml b/src/org.freedesktop.DeviceKit.Disks.Device.xml index 3a87285..de0163d 100644 --- a/src/org.freedesktop.DeviceKit.Disks.Device.xml +++ b/src/org.freedesktop.DeviceKit.Disks.Device.xml @@ -46,7 +46,7 @@ Most methods on this interface take an array of strings for options that can affect what the method does. Some of these options are literal strings (such - as remount) while some are encoded in the + as noatime) while some are encoded in the form of a key/value pair (such as label=). While the documentation for each method will specify exactly what set of options are @@ -561,7 +561,7 @@ File system type to use. - Mount Options. Valid mount options include 'remount' and other mount options accepted by the native mount program. + Mount Options. Valid mount options include mount options accepted by the native mount program. Where the device was mounted. @@ -601,7 +601,6 @@ if the device is not a mountable file system if an invalid or malformed mount option was given if the device is already mounted - if the remount option was given and the device wasn't mounted @@ -1379,9 +1378,9 @@ TRUE if the device is mounted. - + - Where the device is mounted. + A list of paths in the root namespace where the root of the device is mounted. This property is only valid if device-is-mounted is TRUE. diff --git a/tools/devkit-disks.c b/tools/devkit-disks.c index 47ebe9f..d85ca86 100644 --- a/tools/devkit-disks.c +++ b/tools/devkit-disks.c @@ -366,7 +366,7 @@ typedef struct gboolean device_is_busy; gboolean device_is_linux_md_component; gboolean device_is_linux_md; - char *device_mount_path; + char **device_mount_paths; uid_t device_mounted_by_uid; char *device_presentation_name; char *device_presentation_icon_name; @@ -518,8 +518,8 @@ collect_props (const char *key, const GValue *value, DeviceProperties *props) props->device_is_mounted = g_value_get_boolean (value); else if (strcmp (key, "device-is-busy") == 0) props->device_is_busy = g_value_get_boolean (value); - else if (strcmp (key, "device-mount-path") == 0) - props->device_mount_path = g_strdup (g_value_get_string (value)); + else if (strcmp (key, "device-mount-paths") == 0) + props->device_mount_paths = g_strdupv (g_value_get_boxed (value)); else if (strcmp (key, "device-mounted-by-uid") == 0) props->device_mounted_by_uid = g_value_get_uint (value); else if (strcmp (key, "device-presentation-name") == 0) @@ -732,7 +732,7 @@ device_properties_free (DeviceProperties *props) g_free (props->device_file); g_strfreev (props->device_file_by_id); g_strfreev (props->device_file_by_path); - g_free (props->device_mount_path); + g_strfreev (props->device_mount_paths); g_free (props->device_presentation_name); g_free (props->device_presentation_icon_name); g_free (props->job_id); @@ -997,7 +997,13 @@ do_show_info (const char *object_path) g_print (" is read only: %d\n", props->device_is_read_only); g_print (" is mounted: %d\n", props->device_is_mounted); g_print (" is busy: %d\n", props->device_is_busy); - g_print (" mount path: %s\n", props->device_mount_path); + g_print (" mount paths: "); + for (n = 0; props->device_mount_paths != NULL && props->device_mount_paths[n] != NULL; n++) { + if (n != 0) + g_print (", "); + g_print ("%s", props->device_mount_paths[n]); + } + g_print ("\n"); g_print (" mounted by uid: %d\n", props->device_mounted_by_uid); g_print (" presentation name: %s\n", props->device_presentation_name); g_print (" presentation icon: %s\n", props->device_presentation_icon_name); @@ -1185,9 +1191,9 @@ do_show_info (const char *object_path) val = props->drive_ata_smart_power_on_seconds; if (val > 60 * 60 * 24) { - power_on_text = g_strdup_printf (_("%.3g days"), val / 60.0 / 60.0 / 24.0); + power_on_text = g_strdup_printf ("%.3g days", val / 60.0 / 60.0 / 24.0); } else { - power_on_text = g_strdup_printf (_("%.3g hours"), val / 60.0 / 60.0); + power_on_text = g_strdup_printf ("%.3g hours", val / 60.0 / 60.0); } g_print (" powered on: %s\n", power_on_text); -- 2.7.4