From 018322ba8d00d9bbee0450910715ae1acde49679 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Tue, 9 Aug 2011 15:14:17 -0400 Subject: [PATCH] Add facilities for adding/removing a block device to /etc/fstab http://people.freedesktop.org/~david/palimpsest-fstab-1.png http://people.freedesktop.org/~david/palimpsest-fstab-2.png Signed-off-by: David Zeuthen --- data/org.freedesktop.UDisks2.xml | 76 ++++++ doc/udisks2-docs.xml | 2 + doc/udisks2-sections.txt | 44 ++++ doc/udisks2.types | 2 + policy/org.freedesktop.udisks2.policy.in | 11 + src/Makefile.am | 2 + src/udisksdaemon.c | 29 ++- src/udisksdaemon.h | 1 + src/udisksdaemontypes.h | 6 + src/udiskslinuxblock.c | 431 +++++++++++++++++++++++++++++++ src/udiskslinuxfilesystem.c | 13 + src/udiskslinuxprovider.c | 69 +++++ src/udisksprivate.h | 2 + 13 files changed, 687 insertions(+), 1 deletion(-) diff --git a/data/org.freedesktop.UDisks2.xml b/data/org.freedesktop.UDisks2.xml index f019b4a..7048cee 100644 --- a/data/org.freedesktop.UDisks2.xml +++ b/data/org.freedesktop.UDisks2.xml @@ -371,6 +371,53 @@ --> + + + + + + + + + + + + + + + + diff --git a/doc/udisks2-docs.xml b/doc/udisks2-docs.xml index 896cbf7..8cd93c6 100644 --- a/doc/udisks2-docs.xml +++ b/doc/udisks2-docs.xml @@ -176,6 +176,8 @@ + + diff --git a/doc/udisks2-sections.txt b/doc/udisks2-sections.txt index 39b2bb1..b29bcc1 100644 --- a/doc/udisks2-sections.txt +++ b/doc/udisks2-sections.txt @@ -58,6 +58,7 @@ udisks_daemon_new udisks_daemon_get_connection udisks_daemon_get_object_manager udisks_daemon_get_mount_monitor +udisks_daemon_get_fstab_monitor udisks_daemon_get_linux_provider udisks_daemon_get_persistent_store udisks_daemon_get_authority @@ -760,6 +761,15 @@ UDisksBlockDevice UDisksBlockDeviceIface udisks_block_device_interface_info udisks_block_device_override_properties +udisks_block_device_call_add_configuration_item +udisks_block_device_call_add_configuration_item_finish +udisks_block_device_call_add_configuration_item_sync +udisks_block_device_complete_add_configuration_item +udisks_block_device_call_remove_configuration_item +udisks_block_device_call_remove_configuration_item_finish +udisks_block_device_call_remove_configuration_item_sync +udisks_block_device_complete_remove_configuration_item +udisks_block_device_get_configuration udisks_block_device_get_crypto_backing_device udisks_block_device_get_device udisks_block_device_get_drive @@ -790,6 +800,7 @@ udisks_block_device_get_hint_ignore udisks_block_device_get_hint_auto udisks_block_device_get_hint_name udisks_block_device_get_hint_icon_name +udisks_block_device_set_configuration udisks_block_device_set_crypto_backing_device udisks_block_device_set_device udisks_block_device_set_drive @@ -974,3 +985,36 @@ udisks_loop_get_type udisks_loop_proxy_get_type udisks_loop_skeleton_get_type + +
+udisksfstabentry +UDisksFstabEntry +UDisksFstabEntry +udisks_fstab_entry_get_fsname +udisks_fstab_entry_get_dir +udisks_fstab_entry_get_fstype +udisks_fstab_entry_get_opts +udisks_fstab_entry_get_freq +udisks_fstab_entry_get_passno +udisks_fstab_entry_compare + +UDISKS_TYPE_FSTAB_ENTRY +UDISKS_FSTAB_ENTRY +UDISKS_IS_FSTAB_ENTRY + +udisks_fstab_entry_get_type +
+ +
+udisksfstabmonitor +UDisksFstabMonitor +UDisksFstabMonitor +udisks_fstab_monitor_new +udisks_fstab_monitor_get_entries + +UDISKS_TYPE_FSTAB_MONITOR +UDISKS_FSTAB_MONITOR +UDISKS_IS_FSTAB_MONITOR + +udisks_fstab_monitor_get_type +
diff --git a/doc/udisks2.types b/doc/udisks2.types index 7a99f3d..79031a2 100644 --- a/doc/udisks2.types +++ b/doc/udisks2.types @@ -18,6 +18,8 @@ udisks_linux_swapspace_get_type udisks_linux_loop_get_type udisks_linux_manager_get_type udisks_cleanup_get_type +udisks_fstab_entry_get_type +udisks_fstab_monitor_get_type udisks_drive_get_type udisks_drive_proxy_get_type diff --git a/policy/org.freedesktop.udisks2.policy.in b/policy/org.freedesktop.udisks2.policy.in index 65e8858..9d76a85 100644 --- a/policy/org.freedesktop.udisks2.policy.in +++ b/policy/org.freedesktop.udisks2.policy.in @@ -132,4 +132,15 @@ + + + <_description>Modify system-wide configuration + <_message>Authentication is required to modify system-wide configuration + + auth_admin + auth_admin + auth_admin_keep + + + diff --git a/src/Makefile.am b/src/Makefile.am index 63f0d8b..b23e7de 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -65,6 +65,8 @@ libudisks_daemon_la_SOURCES = \ udiskslogging.h udiskslogging.c \ udiskscleanup.h udiskscleanup.c \ udisksprivate.h \ + udisksfstabentry.h udisksfstabentry.c \ + udisksfstabmonitor.h udisksfstabmonitor.c \ $(BUILT_SOURCES) \ $(NULL) diff --git a/src/udisksdaemon.c b/src/udisksdaemon.c index 2b048e0..3b72b26 100644 --- a/src/udisksdaemon.c +++ b/src/udisksdaemon.c @@ -33,6 +33,8 @@ #include "udisksthreadedjob.h" #include "udiskssimplejob.h" #include "udiskscleanup.h" +#include "udisksfstabmonitor.h" +#include "udisksfstabentry.h" /** * SECTION:udisksdaemon @@ -65,6 +67,8 @@ struct _UDisksDaemon PolkitAuthority *authority; UDisksCleanup *cleanup; + + UDisksFstabMonitor *fstab_monitor; }; struct _UDisksDaemonClass @@ -77,7 +81,8 @@ enum PROP_0, PROP_CONNECTION, PROP_OBJECT_MANAGER, - PROP_MOUNT_MONITOR + PROP_MOUNT_MONITOR, + PROP_FSTAB_MONITOR, }; G_DEFINE_TYPE (UDisksDaemon, udisks_daemon, G_TYPE_OBJECT); @@ -96,6 +101,7 @@ udisks_daemon_finalize (GObject *object) g_object_unref (daemon->linux_provider); g_object_unref (daemon->mount_monitor); g_object_unref (daemon->connection); + g_object_unref (daemon->fstab_monitor); if (G_OBJECT_CLASS (udisks_daemon_parent_class)->finalize != NULL) G_OBJECT_CLASS (udisks_daemon_parent_class)->finalize (object); @@ -123,6 +129,10 @@ udisks_daemon_get_property (GObject *object, g_value_set_object (value, udisks_daemon_get_mount_monitor (daemon)); break; + case PROP_FSTAB_MONITOR: + g_value_set_object (value, udisks_daemon_get_fstab_monitor (daemon)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -207,6 +217,8 @@ udisks_daemon_constructed (GObject *object) G_CALLBACK (mount_monitor_on_mount_removed), daemon); + daemon->fstab_monitor = udisks_fstab_monitor_new (); + /* now add providers */ daemon->linux_provider = udisks_linux_provider_new (daemon); @@ -344,6 +356,21 @@ udisks_daemon_get_mount_monitor (UDisksDaemon *daemon) } /** + * udisks_daemon_get_fstab_monitor: + * @daemon: A #UDisksDaemon + * + * Gets the fstab monitor used by @daemon. + * + * Returns: A #UDisksFstabMonitor. Do not free, the object is owned by @daemon. + */ +UDisksFstabMonitor * +udisks_daemon_get_fstab_monitor (UDisksDaemon *daemon) +{ + g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL); + return daemon->fstab_monitor; +} + +/** * udisks_daemon_get_linux_provider: * @daemon: A #UDisksDaemon. * diff --git a/src/udisksdaemon.h b/src/udisksdaemon.h index 305b79a..684e673 100644 --- a/src/udisksdaemon.h +++ b/src/udisksdaemon.h @@ -34,6 +34,7 @@ UDisksDaemon *udisks_daemon_new (GDBusConnection * GDBusConnection *udisks_daemon_get_connection (UDisksDaemon *daemon); GDBusObjectManagerServer *udisks_daemon_get_object_manager (UDisksDaemon *daemon); UDisksMountMonitor *udisks_daemon_get_mount_monitor (UDisksDaemon *daemon); +UDisksFstabMonitor *udisks_daemon_get_fstab_monitor (UDisksDaemon *daemon); UDisksLinuxProvider *udisks_daemon_get_linux_provider (UDisksDaemon *daemon); UDisksPersistentStore *udisks_daemon_get_persistent_store (UDisksDaemon *daemon); PolkitAuthority *udisks_daemon_get_authority (UDisksDaemon *daemon); diff --git a/src/udisksdaemontypes.h b/src/udisksdaemontypes.h index 526e078..fe4b1ba 100644 --- a/src/udisksdaemontypes.h +++ b/src/udisksdaemontypes.h @@ -76,6 +76,12 @@ typedef struct _UDisksLinuxManager UDisksLinuxManager; struct _UDisksLinuxSwapspace; typedef struct _UDisksLinuxSwapspace UDisksLinuxSwapspace; +struct _UDisksFstabMonitor; +typedef struct _UDisksFstabMonitor UDisksFstabMonitor; + +struct _UDisksFstabEntry; +typedef struct _UDisksFstabEntry UDisksFstabEntry; + /** * UDisksThreadedJobFunc: * @job: A #UDisksThreadedJob. diff --git a/src/udiskslinuxblock.c b/src/udiskslinuxblock.c index 845ead4..027c940 100644 --- a/src/udiskslinuxblock.c +++ b/src/udiskslinuxblock.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,8 @@ #include "udiskslinuxloop.h" #include "udiskspersistentstore.h" #include "udiskslinuxprovider.h" +#include "udisksfstabmonitor.h" +#include "udisksfstabentry.h" /** * SECTION:udiskslinuxblock @@ -368,6 +371,322 @@ update_iface (UDisksLinuxBlock *block, /* ---------------------------------------------------------------------------------------------------- */ +static gchar * +escape_fstab (const gchar *source) +{ + GString *s; + guint n; + s = g_string_new (NULL); + for (n = 0; source[n] != '\0'; n++) + { + switch (source[n]) + { + case ' ': + case '\t': + case '\n': + case '\\': + g_string_append_printf (s, "\\%03o", source[n]); + break; + + default: + g_string_append_c (s, source[n]); + break; + } + } + return g_string_free (s, FALSE); +} + +/* based on g_strcompress() */ +static gchar * +unescape_fstab (const gchar *source) +{ + const gchar *p = source, *octal; + gchar *dest = g_malloc (strlen (source) + 1); + gchar *q = dest; + + while (*p) + { + if (*p == '\\') + { + p++; + switch (*p) + { + case '\0': + g_warning ("unescape_fstab: trailing \\"); + goto out; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': + *q = 0; + octal = p; + while ((p < octal + 3) && (*p >= '0') && (*p <= '7')) + { + *q = (*q * 8) + (*p - '0'); + p++; + } + q++; + p--; + break; + default: /* Also handles \" and \\ */ + *q++ = *p; + break; + } + } + else + *q++ = *p; + p++; + } +out: + *q = 0; + + return dest; +} + +static gboolean +add_remove_fstab_entry (GVariant *add, + GVariant *remove, + GError **error) +{ + struct mntent mntent_remove; + struct mntent mntent_add; + gboolean ret; + gchar *contents; + gchar **lines; + GString *str; + gboolean removed; + guint n; + + contents = NULL; + lines = NULL; + str = NULL; + ret = FALSE; + + if (remove != NULL) + { + if (!g_variant_lookup (remove, "fsname", "^&ay", &mntent_remove.mnt_fsname) || + !g_variant_lookup (remove, "dir", "^&ay", &mntent_remove.mnt_dir) || + !g_variant_lookup (remove, "type", "^&ay", &mntent_remove.mnt_type) || + !g_variant_lookup (remove, "opts", "^&ay", &mntent_remove.mnt_opts) || + !g_variant_lookup (remove, "freq", "i", &mntent_remove.mnt_freq) || + !g_variant_lookup (remove, "passno", "i", &mntent_remove.mnt_passno)) + { + g_set_error (error, + UDISKS_ERROR, + UDISKS_ERROR_FAILED, + "Missing fsname, dir, type, opts, freq or passno parameter in entry to remove"); + goto out; + } + } + + if (add != NULL) + { + if (!g_variant_lookup (add, "fsname", "^&ay", &mntent_add.mnt_fsname) || + !g_variant_lookup (add, "dir", "^&ay", &mntent_add.mnt_dir) || + !g_variant_lookup (add, "type", "^&ay", &mntent_add.mnt_type) || + !g_variant_lookup (add, "opts", "^&ay", &mntent_add.mnt_opts) || + !g_variant_lookup (add, "freq", "i", &mntent_add.mnt_freq) || + !g_variant_lookup (add, "passno", "i", &mntent_add.mnt_passno)) + { + g_set_error (error, + UDISKS_ERROR, + UDISKS_ERROR_FAILED, + "Missing fsname, dir, type, opts, freq or passno parameter in entry to add"); + goto out; + } + } + + if (!g_file_get_contents ("/etc/fstab", + &contents, + NULL, + error)) + goto out; + + lines = g_strsplit (contents, "\n", 0); + + str = g_string_new (NULL); + removed = FALSE; + for (n = 0; lines != NULL && lines[n] != NULL; n++) + { + const gchar *line = lines[n]; + if (strlen (line) == 0 && lines[n+1] == NULL) + break; + if (remove != NULL && !removed) + { + gchar parsed_fsname[512]; + gchar parsed_dir[512]; + gchar parsed_type[512]; + gchar parsed_opts[512]; + gint parsed_freq; + gint parsed_passno; + if (sscanf (line, "%511s %511s %511s %511s %d %d", + parsed_fsname, + parsed_dir, + parsed_type, + parsed_opts, + &parsed_freq, + &parsed_passno) == 6) + { + gchar *unescaped_fsname = unescape_fstab (parsed_fsname); + gchar *unescaped_dir = unescape_fstab (parsed_dir); + gchar *unescaped_type = unescape_fstab (parsed_type); + gchar *unescaped_opts = unescape_fstab (parsed_opts); + gboolean matches = FALSE; + if (g_strcmp0 (unescaped_fsname, mntent_remove.mnt_fsname) == 0 && + g_strcmp0 (unescaped_dir, mntent_remove.mnt_dir) == 0 && + g_strcmp0 (unescaped_type, mntent_remove.mnt_type) == 0 && + g_strcmp0 (unescaped_opts, mntent_remove.mnt_opts) == 0 && + parsed_freq == mntent_remove.mnt_freq && + parsed_passno == mntent_remove.mnt_passno) + { + matches = TRUE; + } + g_free (unescaped_fsname); + g_free (unescaped_dir); + g_free (unescaped_type); + g_free (unescaped_opts); + if (matches) + { + removed = TRUE; + continue; + } + } + } + g_string_append (str, line); + g_string_append_c (str, '\n'); + } + + if (remove != NULL && !removed) + { + g_set_error (error, + UDISKS_ERROR, + UDISKS_ERROR_FAILED, + "Didn't find entry to remove"); + goto out; + } + + if (add != NULL) + { + gchar *escaped_fsname = escape_fstab (mntent_add.mnt_fsname); + gchar *escaped_dir = escape_fstab (mntent_add.mnt_dir); + gchar *escaped_type = escape_fstab (mntent_add.mnt_type); + gchar *escaped_opts = escape_fstab (mntent_add.mnt_opts); + g_string_append_printf (str, "%s %s %s %s %d %d\n", + escaped_fsname, + escaped_dir, + escaped_type, + escaped_opts, + mntent_add.mnt_freq, + mntent_add.mnt_passno); + g_free (escaped_fsname); + g_free (escaped_dir); + g_free (escaped_type); + g_free (escaped_opts); + } + + if (!g_file_set_contents ("/etc/fstab", + str->str, + -1, + error) != 0) + goto out; + + ret = TRUE; + + out: + g_strfreev (lines); + g_free (contents); + if (str != NULL) + g_string_free (str, TRUE); + return ret; +} + +static gboolean +on_add_configuration_item (UDisksBlockDevice *block, + GDBusMethodInvocation *invocation, + GVariant *item, + GVariant *options, + gpointer user_data) +{ + UDisksLinuxBlock *object = UDISKS_LINUX_BLOCK (user_data); + const gchar *type; + GVariant *details; + GError *error; + + g_variant_get (item, "(&s@a{sv})", &type, &details); + + if (g_strcmp0 (type, "fstab") != 0) + { + g_dbus_method_invocation_return_error (invocation, + UDISKS_ERROR, + UDISKS_ERROR_FAILED, + "Only fstab items can be added"); + goto out; + } + + if (!udisks_daemon_util_check_authorization_sync (object->daemon, + NULL, + "org.freedesktop.udisks2.modify-system-configuration", + options, + N_("Authentication is required to modify the /etc/fstab file"), + invocation)) + goto out; + + error = NULL; + if (!add_remove_fstab_entry (details, NULL, &error)) + { + g_dbus_method_invocation_take_error (invocation, error); + goto out; + } + + udisks_block_device_complete_add_configuration_item (block, invocation); + + out: + g_variant_unref (details); + return TRUE; /* returning TRUE means that we handled the method invocation */ +} + +static gboolean +on_remove_configuration_item (UDisksBlockDevice *block, + GDBusMethodInvocation *invocation, + GVariant *item, + GVariant *options, + gpointer user_data) +{ + UDisksLinuxBlock *object = UDISKS_LINUX_BLOCK (user_data); + const gchar *type; + GVariant *details; + GError *error; + + g_variant_get (item, "(&s@a{sv})", &type, &details); + + if (g_strcmp0 (type, "fstab") != 0) + { + g_dbus_method_invocation_return_error (invocation, + UDISKS_ERROR, + UDISKS_ERROR_FAILED, + "Only fstab items can be removed"); + goto out; + } + + if (!udisks_daemon_util_check_authorization_sync (object->daemon, + NULL, + "org.freedesktop.udisks2.modify-system-configuration", + options, + N_("Authentication is required to modify the /etc/fstab file"), + invocation)) + goto out; + + error = NULL; + if (!add_remove_fstab_entry (NULL, details, &error)) + { + g_dbus_method_invocation_take_error (invocation, error); + goto out; + } + + udisks_block_device_complete_add_configuration_item (block, invocation); + + out: + g_variant_unref (details); + return TRUE; /* returning TRUE means that we handled the method invocation */ +} /* ---------------------------------------------------------------------------------------------------- */ /* org.freedesktop.UDisks.BlockDevice */ @@ -381,6 +700,14 @@ block_device_check (UDisksLinuxBlock *block) static void block_device_connect (UDisksLinuxBlock *block) { + g_signal_connect (block->iface_block_device, + "handle-add-configuration-item", + G_CALLBACK (on_add_configuration_item), + block); + g_signal_connect (block->iface_block_device, + "handle-remove-configuration-item", + G_CALLBACK (on_remove_configuration_item), + block); } static gchar * @@ -556,6 +883,109 @@ block_device_update_hints (UDisksLinuxBlock *block, udisks_block_device_set_hint_icon_name (iface, hint_icon_name); } +static GList * +find_fstab_entries_for_device (UDisksLinuxBlock *block) +{ + GList *entries; + GList *l; + GList *ret; + + ret = NULL; + + /* if this is too slow, we could add lookup methods to UDisksFstabMonitor... */ + entries = udisks_fstab_monitor_get_entries (udisks_daemon_get_fstab_monitor (block->daemon)); + for (l = entries; l != NULL; l = l->next) + { + UDisksFstabEntry *entry = UDISKS_FSTAB_ENTRY (l->data); + const gchar *const *symlinks; + const gchar *fsname; + gchar *device; + guint n; + + fsname = udisks_fstab_entry_get_fsname (entry); + device = NULL; + if (g_str_has_prefix (fsname, "UUID=")) + { + device = g_strdup_printf ("/dev/disk/by-uuid/%s", fsname + 5); + } + else if (g_str_has_prefix (fsname, "LABEL=")) + { + device = g_strdup_printf ("/dev/disk/by-label/%s", fsname + 6); + } + else if (g_str_has_prefix (fsname, "/dev")) + { + device = g_strdup (fsname); + } + else + { + /* ignore non-device entries */ + goto continue_loop; + } + + symlinks = udisks_block_device_get_symlinks (block->iface_block_device); + if (symlinks != NULL) + { + for (n = 0; symlinks[n] != NULL; n++) + { + if (g_strcmp0 (device, symlinks[n]) == 0) + { + ret = g_list_prepend (ret, g_object_ref (entry)); + } + } + } + + continue_loop: + g_free (device); + } + + g_list_foreach (entries, (GFunc) g_object_unref, NULL); + g_list_free (entries); + return ret; +} + +static void +block_device_update_configuration (UDisksLinuxBlock *block, + const gchar *uevent_action, + UDisksBlockDevice *iface, + const gchar *device_file, + UDisksDrive *drive) +{ + GList *entries; + GList *l; + GVariantBuilder builder; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sa{sv})")); + entries = find_fstab_entries_for_device (block); + for (l = entries; l != NULL; l = l->next) + { + UDisksFstabEntry *entry = UDISKS_FSTAB_ENTRY (l->data); + GVariantBuilder dict_builder; + + g_variant_builder_init (&dict_builder, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&dict_builder, "{sv}", "fsname", + g_variant_new_bytestring (udisks_fstab_entry_get_fsname (entry))); + g_variant_builder_add (&dict_builder, "{sv}", "dir", + g_variant_new_bytestring (udisks_fstab_entry_get_dir (entry))); + g_variant_builder_add (&dict_builder, "{sv}", "type", + g_variant_new_bytestring (udisks_fstab_entry_get_fstype (entry))); + g_variant_builder_add (&dict_builder, "{sv}", "opts", + g_variant_new_bytestring (udisks_fstab_entry_get_opts (entry))); + g_variant_builder_add (&dict_builder, "{sv}", "freq", + g_variant_new_int32 (udisks_fstab_entry_get_freq (entry))); + g_variant_builder_add (&dict_builder, "{sv}", "passno", + g_variant_new_int32 (udisks_fstab_entry_get_passno (entry))); + g_variant_builder_add (&builder, + "(sa{sv})", + "fstab", &dict_builder); + } + + udisks_block_device_set_configuration (block->iface_block_device, + g_variant_builder_end (&builder)); + + g_list_foreach (entries, (GFunc) g_object_unref, NULL); + g_list_free (entries); +} + static void block_device_update (UDisksLinuxBlock *block, const gchar *uevent_action, @@ -778,6 +1208,7 @@ block_device_update (UDisksLinuxBlock *block, } block_device_update_hints (block, uevent_action, iface, device_file, drive); + block_device_update_configuration (block, uevent_action, iface, device_file, drive); if (drive != NULL) g_object_unref (drive); diff --git a/src/udiskslinuxfilesystem.c b/src/udiskslinuxfilesystem.c index ef67db5..728feab 100644 --- a/src/udiskslinuxfilesystem.c +++ b/src/udiskslinuxfilesystem.c @@ -829,6 +829,19 @@ handle_mount (UDisksFilesystem *filesystem, */ if (system_managed) { + if (!g_file_test (mount_point_to_use, G_FILE_TEST_IS_DIR)) + { + if (g_mkdir_with_parents (mount_point_to_use, 0755) != 0) + { + g_dbus_method_invocation_return_error (invocation, + UDISKS_ERROR, + UDISKS_ERROR_FAILED, + "Error creating directory `%s' to be used for mounting %s: %m", + mount_point_to_use, + udisks_block_device_get_device (block)); + goto out; + } + } escaped_mount_point_to_use = g_strescape (mount_point_to_use, NULL); if (!udisks_daemon_launch_spawned_job_sync (daemon, NULL, /* GCancellable */ diff --git a/src/udiskslinuxprovider.c b/src/udiskslinuxprovider.c index 8f29311..3a4f5be 100644 --- a/src/udiskslinuxprovider.c +++ b/src/udiskslinuxprovider.c @@ -85,12 +85,23 @@ static void udisks_linux_provider_handle_uevent (UDisksLinuxProvider *provider, static gboolean on_housekeeping_timeout (gpointer user_data); +static void fstab_monitor_on_entry_added (UDisksFstabMonitor *monitor, + UDisksFstabEntry *entry, + gpointer user_data); + +static void fstab_monitor_on_entry_removed (UDisksFstabMonitor *monitor, + UDisksFstabEntry *entry, + gpointer user_data); + G_DEFINE_TYPE (UDisksLinuxProvider, udisks_linux_provider, UDISKS_TYPE_PROVIDER); static void udisks_linux_provider_finalize (GObject *object) { UDisksLinuxProvider *provider = UDISKS_LINUX_PROVIDER (object); + UDisksDaemon *daemon; + + daemon = udisks_provider_get_daemon (UDISKS_PROVIDER (provider)); g_hash_table_unref (provider->sysfs_to_block); g_hash_table_unref (provider->vpd_to_drive); @@ -103,6 +114,13 @@ udisks_linux_provider_finalize (GObject *object) if (provider->housekeeping_timeout > 0) g_source_remove (provider->housekeeping_timeout); + g_signal_handlers_disconnect_by_func (udisks_daemon_get_fstab_monitor (daemon), + G_CALLBACK (fstab_monitor_on_entry_added), + provider); + g_signal_handlers_disconnect_by_func (udisks_daemon_get_fstab_monitor (daemon), + G_CALLBACK (fstab_monitor_on_entry_removed), + provider); + if (G_OBJECT_CLASS (udisks_linux_provider_parent_class)->finalize != NULL) G_OBJECT_CLASS (udisks_linux_provider_parent_class)->finalize (object); } @@ -182,6 +200,16 @@ udisks_linux_provider_start (UDisksProvider *_provider) on_housekeeping_timeout (provider); provider->coldplug = FALSE; + + /* update BlockDevice:FstabEntries whenever fstab entries are added or removed */ + g_signal_connect (udisks_daemon_get_fstab_monitor (daemon), + "entry-added", + G_CALLBACK (fstab_monitor_on_entry_added), + provider); + g_signal_connect (udisks_daemon_get_fstab_monitor (daemon), + "entry-removed", + G_CALLBACK (fstab_monitor_on_entry_removed), + provider); } @@ -517,3 +545,44 @@ on_housekeeping_timeout (gpointer user_data) return TRUE; /* keep timeout around */ } + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +update_all_block_devices (UDisksLinuxProvider *provider) +{ + GList *block_devices; + GList *l; + + G_LOCK (provider_lock); + block_devices = g_hash_table_get_values (provider->sysfs_to_block); + g_list_foreach (block_devices, (GFunc) g_object_ref, NULL); + G_UNLOCK (provider_lock); + + for (l = block_devices; l != NULL; l = l->next) + { + UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (l->data); + udisks_linux_block_uevent (block, "change", NULL); + } + + g_list_foreach (block_devices, (GFunc) g_object_unref, NULL); + g_list_free (block_devices); +} + +static void +fstab_monitor_on_entry_added (UDisksFstabMonitor *monitor, + UDisksFstabEntry *entry, + gpointer user_data) +{ + UDisksLinuxProvider *provider = UDISKS_LINUX_PROVIDER (user_data); + update_all_block_devices (provider); +} + +static void +fstab_monitor_on_entry_removed (UDisksFstabMonitor *monitor, + UDisksFstabEntry *entry, + gpointer user_data) +{ + UDisksLinuxProvider *provider = UDISKS_LINUX_PROVIDER (user_data); + update_all_block_devices (provider); +} diff --git a/src/udisksprivate.h b/src/udisksprivate.h index 114fbc7..3cc2bf8 100644 --- a/src/udisksprivate.h +++ b/src/udisksprivate.h @@ -29,6 +29,8 @@ UDisksMount *_udisks_mount_new (dev_t dev, const gchar *mount_path, UDisksMountType type); +UDisksFstabEntry *_udisks_fstab_entry_new (const struct mntent *mntent); + G_END_DECLS #endif /* __UDISKS_PRIVATE_H__ */ -- 2.7.4