summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2011-08-09 15:14:17 -0400
committerDavid Zeuthen <davidz@redhat.com>2011-08-09 15:14:17 -0400
commit018322ba8d00d9bbee0450910715ae1acde49679 (patch)
tree582649e6ad0f0c2d80f1119915939b844fda4757
parent9a206870bac8d118e8da12ef854aef8d79d7d818 (diff)
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 <davidz@redhat.com>
-rw-r--r--data/org.freedesktop.UDisks2.xml76
-rw-r--r--doc/udisks2-docs.xml2
-rw-r--r--doc/udisks2-sections.txt44
-rw-r--r--doc/udisks2.types2
-rw-r--r--policy/org.freedesktop.udisks2.policy.in11
-rw-r--r--src/Makefile.am2
-rw-r--r--src/udisksdaemon.c29
-rw-r--r--src/udisksdaemon.h1
-rw-r--r--src/udisksdaemontypes.h6
-rw-r--r--src/udiskslinuxblock.c431
-rw-r--r--src/udiskslinuxfilesystem.c13
-rw-r--r--src/udiskslinuxprovider.c69
-rw-r--r--src/udisksprivate.h2
13 files changed, 687 insertions, 1 deletions
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 @@
-->
<property name="IdUUID" type="ay" access="read"/>
+ <!-- Configuration:
+ The configuration sources for the device.
+
+ This is an array of pairs of (@type, @details) where @type is
+ a string identifying the configuration source
+ (e.g. <literal>fstab</literal>) and @details contains the
+ actual configuration data.
+
+ For entries of type <literal>fstab</literal>, it means that
+ the block device is referenced in the system-wide
+ <filename>/etc/fstab</filename> file. Known configuration
+ items for type <literal>fstab</literal> are
+ <variablelist>
+ <varlistentry>
+ <term>fsname (type <literal>'ay'</literal>)</term>
+ <listitem><para>The special device</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>dir (type <literal>'ay'</literal>)</term>
+ <listitem><para>The mount point</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>type (type <literal>'ay'</literal>)</term>
+ <listitem><para>The filesystem type</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>opts (type <literal>'ay'</literal>)</term>
+ <listitem><para>Options</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>freq (type <literal>'i'</literal>)</term>
+ <listitem><para>Dump frequency in days</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>passno (type <literal>'i'</literal>)</term>
+ <listitem><para>Pass number of parallel fsck</para></listitem>
+ </varlistentry>
+ </variablelist>
+
+ Use the
+ org.freedesktop.UDisks2.BlockDevice.AddConfigurationItem()
+ and
+ org.freedesktop.UDisks2.BlockDevice.RemoveConfigurationItem()
+ methods to add/remove configuration items.
+ -->
+ <property name="Configuration" type="a(sa{sv})" access="read"/>
+
<!-- CryptoBackingDevice:
The #org.freedesktop.UDisks2.BlockDevice object that is
backing the device or <literal>/</literal> if unknown or if
@@ -441,6 +488,35 @@
<literal>/</literal> if the device is not a partition.
-->
<property name="PartEntryTable" type="o" access="read"/>
+
+ <!--
+ AddConfigurationItem:
+ @item: The configuration item to add.
+ @options: Options (currently unused except for <link linkend="udisks-std-options">standard options</link>).
+
+ Adds a new configuration item. See the
+ #org.freedesktop.UDisks2.BlockDevice:Configuration property
+ for details about valid configuration items.
+ -->
+ <method name="AddConfigurationItem">
+ <arg name="item" direction="in" type="(sa{sv})"/>
+ <arg name="options" direction="in" type="a{sv}"/>
+ </method>
+
+ <!--
+ RemoveConfigurationItem:
+ @item: The configuration item to remove.
+ @options: Options (currently unused except for <link linkend="udisks-std-options">standard options</link>).
+
+ Removes a new configuration item. See the
+ #org.freedesktop.UDisks2.BlockDevice:Configuration property
+ for details about valid configuration items.
+ -->
+ <method name="RemoveConfigurationItem">
+ <arg name="item" direction="in" type="(sa{sv})"/>
+ <arg name="options" direction="in" type="a{sv}"/>
+ </method>
+
</interface>
<!-- ********************************************************************** -->
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 @@
<xi:include href="xml/udiskslogging.xml"/>
<xi:include href="xml/udisksmount.xml"/>
<xi:include href="xml/udisksmountmonitor.xml"/>
+ <xi:include href="xml/udisksfstabentry.xml"/>
+ <xi:include href="xml/udisksfstabmonitor.xml"/>
<xi:include href="xml/udiskspersistentstore.xml"/>
<xi:include href="xml/udiskscleanup.xml"/>
<xi:include href="xml/udisksprovider.xml"/>
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
</SECTION>
+
+<SECTION>
+<FILE>udisksfstabentry</FILE>
+<TITLE>UDisksFstabEntry</TITLE>
+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
+<SUBSECTION Standard>
+UDISKS_TYPE_FSTAB_ENTRY
+UDISKS_FSTAB_ENTRY
+UDISKS_IS_FSTAB_ENTRY
+<SUBSECTION Private>
+udisks_fstab_entry_get_type
+</SECTION>
+
+<SECTION>
+<FILE>udisksfstabmonitor</FILE>
+<TITLE>UDisksFstabMonitor</TITLE>
+UDisksFstabMonitor
+udisks_fstab_monitor_new
+udisks_fstab_monitor_get_entries
+<SUBSECTION Standard>
+UDISKS_TYPE_FSTAB_MONITOR
+UDISKS_FSTAB_MONITOR
+UDISKS_IS_FSTAB_MONITOR
+<SUBSECTION Private>
+udisks_fstab_monitor_get_type
+</SECTION>
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 @@
</defaults>
</action>
+ <!-- Manage system-wide configuration files such as /etc/fstab -->
+ <action id="org.freedesktop.udisks2.modify-system-configuration">
+ <_description>Modify system-wide configuration</_description>
+ <_message>Authentication is required to modify system-wide configuration</_message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ </action>
+
</policyconfig>
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 <sys/types.h>
#include <pwd.h>
#include <grp.h>
+#include <mntent.h>
#include <string.h>
#include <stdlib.h>
@@ -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__ */