summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/org.freedesktop.UDisks2.xml28
-rw-r--r--src/Makefile.am1
-rw-r--r--src/udisksfilesystemimpl.c1244
-rw-r--r--src/udisksfilesystemimpl.h36
-rw-r--r--src/udiskslinuxblock.c1259
-rw-r--r--tools/udisksctl.c40
-rw-r--r--tools/umount-udisks.c22
7 files changed, 1220 insertions, 1410 deletions
diff --git a/data/org.freedesktop.UDisks2.xml b/data/org.freedesktop.UDisks2.xml
index e485fc3..545ff43 100644
--- a/data/org.freedesktop.UDisks2.xml
+++ b/data/org.freedesktop.UDisks2.xml
@@ -37,30 +37,22 @@
to, or '/' if no such object exists.
-->
<property name="Drive" type="o" access="read"/>
- </interface>
-
- <interface name="org.freedesktop.UDisks2.BlockDevice.Probed">
- <!-- Prereq: org.freedesktop.UDisks2.BlockDevice -->
- <property name="Usage" type="s" access="read"/>
- <property name="Type" type="s" access="read"/>
- <property name="Version" type="s" access="read"/>
- <property name="Label" type="ay" access="read"/>
- <property name="UUID" type="ay" access="read"/>
- </interface>
+ <!-- Properties related what's on the block device -->
+ <property name="IdUsage" type="s" access="read"/>
+ <property name="IdType" type="s" access="read"/>
+ <property name="IdVersion" type="s" access="read"/>
+ <property name="IdLabel" type="ay" access="read"/>
+ <property name="IdUUID" type="ay" access="read"/>
- <interface name="org.freedesktop.UDisks2.Filesystem">
- <!-- Prereq: org.freedesktop.UDisks2.BlockDevice -->
-
- <property name="MountPoints" type="aay" access="read"/>
-
- <method name="Mount">
+ <!-- Properties related to whether the device holds a filesystem -->
+ <property name="FilesystemMountPoints" type="aay" access="read"/>
+ <method name="FilesystemMount">
<arg name="filesystem_type" direction="in" type="s"/>
<arg name="options" direction="in" type="as"/>
<arg name="mount_path" direction="out" type="ay"/>
</method>
-
- <method name="Unmount">
+ <method name="FilesystemUnmount">
<arg name="options" direction="in" type="as"/>
</method>
</interface>
diff --git a/src/Makefile.am b/src/Makefile.am
index adc70ab..7a8c9b9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -50,7 +50,6 @@ libudisks_daemon_la_SOURCES = \
udisksfstabprovider.h udisksfstabprovider.c \
udiskslinuxblock.h udiskslinuxblock.c \
udiskslinuxdrive.h udiskslinuxdrive.c \
- udisksfilesystemimpl.h udisksfilesystemimpl.c \
udisksbasejob.h udisksbasejob.c \
udisksspawnedjob.h udisksspawnedjob.c \
udisksthreadedjob.h udisksthreadedjob.c \
diff --git a/src/udisksfilesystemimpl.c b/src/udisksfilesystemimpl.c
deleted file mode 100644
index 445dde5..0000000
--- a/src/udisksfilesystemimpl.c
+++ /dev/null
@@ -1,1244 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2007-2010 David Zeuthen <zeuthen@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-
-#include <sys/types.h>
-#include <pwd.h>
-#include <grp.h>
-
-#include <glib/gstdio.h>
-
-#include <string.h>
-
-#include "udisksdaemon.h"
-#include "udiskslinuxblock.h"
-#include "udisksbasejob.h"
-#include "udiskssimplejob.h"
-#include "udisksfilesystemimpl.h"
-#include "udiskspersistentstore.h"
-
-/**
- * SECTION:udisksfilesystemimpl
- * @title: UDisksFilesystemImpl
- * @short_description: Filesystem Implementation
- *
- * This type provides an implementation of the #UDisksFilesystem
- * interface that uses the <command>mount</command> and
- * <command>umount</command> commands.
- *
- * TODO: mention other impl details like
- * <filename>/var/lib/udisks/mtab</filename>, how mount options work,
- * what role <filename>/etc/fstab</filename> plays and so on.
- */
-
-
-typedef struct _UDisksFilesystemImplClass UDisksFilesystemImplClass;
-
-/**
- * UDisksFilesystemImpl:
- *
- * The #UDisksFilesystemImpl structure contains only private data and
- * should only be accessed using the provided API.
- */
-struct _UDisksFilesystemImpl
-{
- UDisksFilesystemStub parent_instance;
-};
-
-struct _UDisksFilesystemImplClass
-{
- UDisksFilesystemStubClass parent_class;
-};
-
-static void filesystem_iface_init (UDisksFilesystemIface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (UDisksFilesystemImpl, udisks_filesystem_impl, UDISKS_TYPE_FILESYSTEM_STUB,
- G_IMPLEMENT_INTERFACE (UDISKS_TYPE_FILESYSTEM, filesystem_iface_init));
-
-static void
-udisks_filesystem_impl_init (UDisksFilesystemImpl *filesystem)
-{
- g_dbus_interface_set_flags (G_DBUS_INTERFACE (filesystem),
- G_DBUS_INTERFACE_FLAGS_RUN_IN_THREAD);
-}
-
-static void
-udisks_filesystem_impl_class_init (UDisksFilesystemImplClass *klass)
-{
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gboolean
-get_uid_sync (GDBusMethodInvocation *invocation,
- GCancellable *cancellable,
- uid_t *out_uid,
- GError **error)
-{
- gboolean ret;
- const gchar *caller;
- GVariant *value;
- GError *local_error;
-
- ret = FALSE;
-
- caller = g_dbus_method_invocation_get_sender (invocation);
-
- local_error = NULL;
- value = g_dbus_connection_call_sync (g_dbus_method_invocation_get_connection (invocation),
- "org.freedesktop.DBus", /* bus name */
- "/org/freedesktop/DBus", /* object path */
- "org.freedesktop.DBus", /* interface */
- "GetConnectionUnixUser", /* method */
- g_variant_new ("(s)", caller),
- G_VARIANT_TYPE ("(u)"),
- G_DBUS_CALL_FLAGS_NONE,
- -1, /* timeout_msec */
- cancellable,
- &local_error);
- if (value == NULL)
- {
- g_set_error (error,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "Error determining uid of caller %s: %s (%s, %d)",
- caller,
- local_error->message,
- g_quark_to_string (local_error->domain),
- local_error->code);
- g_error_free (local_error);
- goto out;
- }
-
- G_STATIC_ASSERT (sizeof (uid_t) == sizeof (guint32));
- g_variant_get (value, "(u)", out_uid);
-
- ret = TRUE;
-
- out:
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-typedef struct
-{
- const gchar *fstype;
- const gchar * const *defaults;
- const gchar * const *allow;
- const gchar * const *allow_uid_self;
- const gchar * const *allow_gid_self;
-} FSMountOptions;
-
-/* ---------------------- vfat -------------------- */
-
-static const gchar *vfat_defaults[] = { "uid=", "gid=", "shortname=mixed", "dmask=0077", "utf8=1", "showexec", NULL };
-static const gchar *vfat_allow[] = { "flush", "utf8=", "shortname=", "umask=", "dmask=", "fmask=", "codepage=", "iocharset=", "usefree", "showexec", NULL };
-static const gchar *vfat_allow_uid_self[] = { "uid=", NULL };
-static const gchar *vfat_allow_gid_self[] = { "gid=", NULL };
-
-/* ---------------------- ntfs -------------------- */
-/* this is assuming that ntfs-3g is used */
-
-static const gchar *ntfs_defaults[] = { "uid=", "gid=", "dmask=0077", "fmask=0177", NULL };
-static const gchar *ntfs_allow[] = { "umask=", "dmask=", "fmask=", NULL };
-static const gchar *ntfs_allow_uid_self[] = { "uid=", NULL };
-static const gchar *ntfs_allow_gid_self[] = { "gid=", NULL };
-
-/* ---------------------- iso9660 -------------------- */
-
-static const gchar *iso9660_defaults[] = { "uid=", "gid=", "iocharset=utf8", "mode=0400", "dmode=0500", NULL };
-static const gchar *iso9660_allow[] = { "norock", "nojoliet", "iocharset=", "mode=", "dmode=", NULL };
-static const gchar *iso9660_allow_uid_self[] = { "uid=", NULL };
-static const gchar *iso9660_allow_gid_self[] = { "gid=", NULL };
-
-/* ---------------------- udf -------------------- */
-
-static const gchar *udf_defaults[] = { "uid=", "gid=", "iocharset=utf8", "umask=0077", NULL };
-static const gchar *udf_allow[] = { "iocharset=", "umask=", NULL };
-static const gchar *udf_allow_uid_self[] = { "uid=", NULL };
-static const gchar *udf_allow_gid_self[] = { "gid=", NULL };
-
-/* ------------------------------------------------ */
-/* TODO: support context= */
-
-static const gchar *any_allow[] = { "exec", "noexec", "nodev", "nosuid", "atime", "noatime", "nodiratime", "ro", "rw", "sync", "dirsync", NULL };
-
-static const FSMountOptions fs_mount_options[] =
- {
- { "vfat", vfat_defaults, vfat_allow, vfat_allow_uid_self, vfat_allow_gid_self },
- { "ntfs", ntfs_defaults, ntfs_allow, ntfs_allow_uid_self, ntfs_allow_gid_self },
- { "iso9660", iso9660_defaults, iso9660_allow, iso9660_allow_uid_self, iso9660_allow_gid_self },
- { "udf", udf_defaults, udf_allow, udf_allow_uid_self, udf_allow_gid_self },
- };
-
-/* ------------------------------------------------ */
-
-static int num_fs_mount_options = sizeof(fs_mount_options) / sizeof(FSMountOptions);
-
-static const FSMountOptions *
-find_mount_options_for_fs (const gchar *fstype)
-{
- int n;
- const FSMountOptions *fsmo;
-
- for (n = 0; n < num_fs_mount_options; n++)
- {
- fsmo = fs_mount_options + n;
- if (strcmp (fsmo->fstype, fstype) == 0)
- goto out;
- }
-
- fsmo = NULL;
- out:
- return fsmo;
-}
-
-static gid_t
-find_primary_gid (uid_t uid)
-{
- struct passwd *pw;
- gid_t gid;
-
- gid = (gid_t) - 1;
-
- pw = getpwuid (uid);
- if (pw == NULL)
- {
- g_warning ("Couldn't look up uid %d: %m", uid);
- goto out;
- }
- gid = pw->pw_gid;
-
- out:
- return gid;
-}
-
-static gboolean
-is_uid_in_gid (uid_t uid,
- gid_t gid)
-{
- gboolean ret;
- struct passwd *pw;
- static gid_t supplementary_groups[128];
- int num_supplementary_groups = 128;
- int n;
-
- /* TODO: use some #define instead of harcoding some random number like 128 */
-
- ret = FALSE;
-
- pw = getpwuid (uid);
- if (pw == NULL)
- {
- g_warning ("Couldn't look up uid %d: %m", uid);
- goto out;
- }
- if (pw->pw_gid == gid)
- {
- ret = TRUE;
- goto out;
- }
-
- if (getgrouplist (pw->pw_name, pw->pw_gid, supplementary_groups, &num_supplementary_groups) < 0)
- {
- g_warning ("Couldn't find supplementary groups for uid %d: %m", uid);
- goto out;
- }
-
- for (n = 0; n < num_supplementary_groups; n++)
- {
- if (supplementary_groups[n] == gid)
- {
- ret = TRUE;
- goto out;
- }
- }
-
- out:
- return ret;
-}
-
-static gboolean
-is_mount_option_allowed (const FSMountOptions *fsmo,
- const gchar *option,
- uid_t caller_uid)
-{
- int n;
- gchar *endp;
- uid_t uid;
- gid_t gid;
- gboolean allowed;
- const gchar *ep;
- gsize ep_len;
-
- allowed = FALSE;
-
- /* first run through the allowed mount options */
- if (fsmo != NULL)
- {
- for (n = 0; fsmo->allow != NULL && fsmo->allow[n] != NULL; n++)
- {
- ep = strstr (fsmo->allow[n], "=");
- if (ep != NULL && ep[1] == '\0')
- {
- ep_len = ep - fsmo->allow[n] + 1;
- if (strncmp (fsmo->allow[n], option, ep_len) == 0)
- {
- allowed = TRUE;
- goto out;
- }
- }
- else
- {
- if (strcmp (fsmo->allow[n], option) == 0)
- {
- allowed = TRUE;
- goto out;
- }
- }
- }
- }
- for (n = 0; any_allow[n] != NULL; n++)
- {
- ep = strstr (any_allow[n], "=");
- if (ep != NULL && ep[1] == '\0')
- {
- ep_len = ep - any_allow[n] + 1;
- if (strncmp (any_allow[n], option, ep_len) == 0)
- {
- allowed = TRUE;
- goto out;
- }
- }
- else
- {
- if (strcmp (any_allow[n], option) == 0)
- {
- allowed = TRUE;
- goto out;
- }
- }
- }
-
- /* .. then check for mount options where the caller is allowed to pass
- * in his own uid
- */
- if (fsmo != NULL)
- {
- for (n = 0; fsmo->allow_uid_self != NULL && fsmo->allow_uid_self[n] != NULL; n++)
- {
- const gchar *r_mount_option = fsmo->allow_uid_self[n];
- if (g_str_has_prefix (option, r_mount_option))
- {
- uid = strtol (option + strlen (r_mount_option), &endp, 10);
- if (*endp != '\0')
- continue;
- if (uid == caller_uid)
- {
- allowed = TRUE;
- goto out;
- }
- }
- }
- }
-
- /* .. ditto for gid
- */
- if (fsmo != NULL)
- {
- for (n = 0; fsmo->allow_gid_self != NULL && fsmo->allow_gid_self[n] != NULL; n++)
- {
- const gchar *r_mount_option = fsmo->allow_gid_self[n];
- if (g_str_has_prefix (option, r_mount_option))
- {
- gid = strtol (option + strlen (r_mount_option), &endp, 10);
- if (*endp != '\0')
- continue;
- if (is_uid_in_gid (caller_uid, gid))
- {
- allowed = TRUE;
- goto out;
- }
- }
- }
- }
-
- out:
- return allowed;
-}
-
-static gchar **
-prepend_default_mount_options (const FSMountOptions *fsmo,
- uid_t caller_uid,
- const gchar * const *given_options)
-{
- GPtrArray *options;
- int n;
- gchar *s;
- gid_t gid;
-
- options = g_ptr_array_new ();
- if (fsmo != NULL)
- {
- for (n = 0; fsmo->defaults != NULL && fsmo->defaults[n] != NULL; n++)
- {
- const gchar *option = fsmo->defaults[n];
-
- if (strcmp (option, "uid=") == 0)
- {
- s = g_strdup_printf ("uid=%d", caller_uid);
- g_ptr_array_add (options, s);
- }
- else if (strcmp (option, "gid=") == 0)
- {
- gid = find_primary_gid (caller_uid);
- if (gid != (gid_t) - 1)
- {
- s = g_strdup_printf ("gid=%d", gid);
- g_ptr_array_add (options, s);
- }
- }
- else
- {
- g_ptr_array_add (options, g_strdup (option));
- }
- }
- }
- for (n = 0; given_options[n] != NULL; n++)
- {
- g_ptr_array_add (options, g_strdup (given_options[n]));
- }
-
- g_ptr_array_add (options, NULL);
-
- return (char **) g_ptr_array_free (options, FALSE);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-/*
- * calculate_fs_type: <internal>
- * @block: A #UDisksBlockDevice.
- * @block_probed: A #UDisksBlockDeviceProbed or %NULL.
- * @requested_fs_type: The requested file system type or %NULL.
- * @error: Return location for error or %NULL.
- *
- * Calculates the file system type to use.
- *
- * Returns: A valid UTF-8 string with the filesystem type (may be "auto") or %NULL if @error is set. Free with g_free().
- */
-static gchar *
-calculate_fs_type (UDisksBlockDevice *block,
- UDisksBlockDeviceProbed *block_probed,
- const gchar *requested_fs_type,
- GError **error)
-{
- gchar *fs_type_to_use;
- const gchar *probed_fs_usage;
- const gchar *probed_fs_type;
-
- probed_fs_usage = NULL;
- probed_fs_type = NULL;
- if (block_probed != NULL)
- {
- probed_fs_usage = udisks_block_device_probed_get_usage (block_probed);
- probed_fs_type = udisks_block_device_probed_get_type (block_probed);
- }
-
- fs_type_to_use = NULL;
- if (requested_fs_type != NULL && strlen (requested_fs_type) > 0)
- {
- /* TODO: maybe check that it's compatible with probed_fs_type */
- fs_type_to_use = g_strdup (requested_fs_type);
- }
- else
- {
- if (probed_fs_type != NULL && strlen (probed_fs_type) > 0)
- fs_type_to_use = g_strdup (probed_fs_type);
- else
- fs_type_to_use = g_strdup ("auto");
- }
-
- g_assert (fs_type_to_use == NULL || g_utf8_validate (fs_type_to_use, -1, NULL));
-
- return fs_type_to_use;
-}
-
-/*
- * calculate_mount_options: <internal>
- * @block: A #UDisksBlockDevice.
- * @block_probed: A #UDisksBlockDeviceProbed or %NULL.
- * @caller_uid: The uid of the caller making the request.
- * @fs_type: The filesystem type to use or %NULL.
- * @requested_options: Options requested by the caller.
- * @out_auth_no_user_interaction: Return location for whether the 'auth_no_user_interaction' option was passed or %NULL.
- * @error: Return location for error or %NULL.
- *
- * Calculates the mount option string to use. Ensures (by returning an
- * error) that only safe options are used.
- *
- * Returns: A string with mount options or %NULL if @error is set. Free with g_free().
- */
-static gchar *
-calculate_mount_options (UDisksBlockDevice *block,
- UDisksBlockDeviceProbed *block_probed,
- uid_t caller_uid,
- const gchar *fs_type,
- const gchar *const *requested_options,
- gboolean *out_auth_no_user_interaction,
- GError **error)
-{
- const FSMountOptions *fsmo;
- gchar **options_to_use;
- gchar *options_to_use_str;
- GString *str;
- guint n;
- gboolean auth_no_user_interaction;
-
- options_to_use = NULL;
- options_to_use_str = NULL;
- auth_no_user_interaction = FALSE;
-
- fsmo = find_mount_options_for_fs (fs_type);
-
- /* always prepend some reasonable default mount options; these are
- * chosen here; the user can override them if he wants to
- */
- options_to_use = prepend_default_mount_options (fsmo, caller_uid, requested_options);
-
- /* validate mount options */
- str = g_string_new ("uhelper=udisks2,nodev,nosuid");
- for (n = 0; options_to_use[n] != NULL; n++)
- {
- const gchar *option = options_to_use[n];
-
- if (g_strcmp0 (option, "auth_no_user_interaction") == 0)
- {
- auth_no_user_interaction = TRUE;
- continue;
- }
-
- /* avoid attacks like passing "shortname=lower,uid=0" as a single mount option */
- if (strstr (option, ",") != NULL)
- {
- g_set_error (error,
- UDISKS_ERROR,
- UDISKS_ERROR_OPTION_NOT_PERMITTED,
- "Malformed mount option `%s'",
- option);
- g_string_free (str, TRUE);
- goto out;
- }
-
- /* first check if the mount option is allowed */
- if (!is_mount_option_allowed (fsmo, option, caller_uid))
- {
- g_set_error (error,
- UDISKS_ERROR,
- UDISKS_ERROR_OPTION_NOT_PERMITTED,
- "Mount option `%s' is not allowed",
- option);
- g_string_free (str, TRUE);
- goto out;
- }
-
- g_string_append_c (str, ',');
- g_string_append (str, option);
- }
- options_to_use_str = g_string_free (str, FALSE);
-
- out:
- g_strfreev (options_to_use);
-
- g_assert (options_to_use_str == NULL || g_utf8_validate (options_to_use_str, -1, NULL));
-
- if (out_auth_no_user_interaction != NULL)
- *out_auth_no_user_interaction = auth_no_user_interaction;
-
- return options_to_use_str;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gchar *
-ensure_utf8 (const gchar *s)
-{
- const gchar *end;
- gchar *ret;
-
- if (!g_utf8_validate (s, -1, &end))
- {
- gchar *tmp;
- gint pos;
- /* TODO: could possibly return a nicer UTF-8 string */
- pos = (gint) (end - s);
- tmp = g_strndup (s, end - s);
- ret = g_strdup_printf ("%s (Invalid UTF-8 at byte %d)", tmp, pos);
- g_free (tmp);
- }
- else
- {
- ret = g_strdup (s);
- }
-
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-/*
- * calculate_mount_point: <internal>
- * @block: A #UDisksBlockDevice.
- * @block_probed: A #UDisksBlockDeviceProbed or %NULL.
- * @fs_type: The file system type to mount with
- * @error: Return location for error or %NULL.
- *
- * Calculates the mount point to use.
- *
- * Returns: A UTF-8 string with the mount point to use or %NULL if @error is set. Free with g_free().
- */
-static gchar *
-calculate_mount_point (UDisksBlockDevice *block,
- UDisksBlockDeviceProbed *block_probed,
- const gchar *fs_type,
- GError **error)
-{
- const gchar *label;
- const gchar *uuid;
- gchar *mount_point;
- gchar *orig_mount_point;
- GString *str;
- gchar *s;
- guint n;
-
- label = NULL;
- uuid = NULL;
- if (block_probed != NULL)
- {
- label = udisks_block_device_probed_get_label (block_probed);
- uuid = udisks_block_device_probed_get_uuid (block_probed);
- }
-
- /* NOTE: UTF-8 has the nice property that valid UTF-8 strings only contains
- * the byte 0x2F if it's for the '/' character (U+002F SOLIDUS).
- *
- * See http://en.wikipedia.org/wiki/UTF-8 for details.
- */
-
- if (label != NULL && strlen (label) > 0)
- {
- str = g_string_new ("/media/");
- s = ensure_utf8 (label);
- for (n = 0; s[n] != '\0'; n++)
- {
- gint c = s[n];
- if (c == '/')
- g_string_append_c (str, '_');
- else
- g_string_append_c (str, c);
- }
- mount_point = g_string_free (str, FALSE);
- g_free (s);
- }
- else if (uuid != NULL && strlen (uuid) > 0)
- {
- str = g_string_new ("/media/");
- s = ensure_utf8 (uuid);
- for (n = 0; s[n] != '\0'; n++)
- {
- gint c = s[n];
- if (c == '/')
- g_string_append_c (str, '_');
- else
- g_string_append_c (str, c);
- }
- mount_point = g_string_free (str, FALSE);
- g_free (s);
- }
- else
- {
- mount_point = g_strdup ("/media/disk");
- }
-
- /* ... then uniqify the mount point */
- orig_mount_point = g_strdup (mount_point);
- n = 1;
- while (TRUE)
- {
- if (!g_file_test (mount_point, G_FILE_TEST_EXISTS))
- {
- break;
- }
- else
- {
- g_free (mount_point);
- mount_point = g_strdup_printf ("%s%d", orig_mount_point, n++);
- }
- }
- g_free (orig_mount_point);
-
- return mount_point;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-/* runs in thread dedicated to handling method call */
-static gboolean
-handle_mount (UDisksFilesystem *filesystem,
- GDBusMethodInvocation *invocation,
- const gchar *requested_fs_type,
- const gchar* const *requested_options)
-{
- GDBusObject *object;
- UDisksDaemon *daemon;
- UDisksPersistentStore *store;
- gboolean ret;
- uid_t caller_uid;
- UDisksBlockDevice *block;
- UDisksBlockDeviceProbed *block_probed;
- GDBusInterface *iface;
- const gchar * const *existing_mount_points;
- const gchar *probed_fs_usage;
- const gchar *probed_fs_type;
- gchar *fs_type_to_use;
- gchar *mount_options_to_use;
- gchar *mount_point_to_use;
- gchar *escaped_fs_type_to_use;
- gchar *escaped_mount_options_to_use;
- gchar *escaped_mount_point_to_use;
- gchar *error_message;
- GError *error;
- PolkitSubject *auth_subject;
- const gchar *auth_action_id;
- PolkitDetails *auth_details;
- gboolean auth_no_user_interaction;
- PolkitCheckAuthorizationFlags auth_flags;
- PolkitAuthorizationResult *auth_result;
-
- ret = FALSE;
- object = NULL;
- daemon = NULL;
- block = NULL;
- block_probed = NULL;
- error_message = NULL;
- fs_type_to_use = NULL;
- mount_options_to_use = NULL;
- mount_point_to_use = NULL;
- escaped_fs_type_to_use = NULL;
- escaped_mount_options_to_use = NULL;
- escaped_mount_point_to_use = NULL;
- auth_subject = NULL;
- auth_details = NULL;
- auth_result = NULL;
- auth_no_user_interaction = FALSE;
-
- object = g_dbus_interface_get_object (G_DBUS_INTERFACE (filesystem));
- block = UDISKS_BLOCK_DEVICE (g_dbus_object_lookup_interface (object, "org.freedesktop.UDisks2.BlockDevice"));
- iface = g_dbus_object_lookup_interface (object, "org.freedesktop.UDisks2.BlockDevice.Probed");
- block_probed = iface != NULL ? UDISKS_BLOCK_DEVICE_PROBED (iface) : NULL;
-
- daemon = udisks_linux_block_get_daemon (UDISKS_LINUX_BLOCK (object));
- store = udisks_daemon_get_persistent_store (daemon);
-
- /* TODO: check if mount point is managed by e.g. /etc/fstab or
- * similar - if so, use that instead of managing mount points
- * in /media
- */
-
- /* Fail if the device is already mounted */
- existing_mount_points = udisks_filesystem_get_mount_points (filesystem);
- if (existing_mount_points != NULL && g_strv_length ((gchar **) existing_mount_points) > 0)
- {
- GString *str;
- guint n;
- str = g_string_new (NULL);
- for (n = 0; existing_mount_points[n] != NULL; n++)
- {
- if (n > 0)
- g_string_append (str, ", ");
- g_string_append_printf (str, "`%s'", existing_mount_points[n]);
- }
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_ALREADY_MOUNTED,
- "Device %s is already mounted at %s.\n",
- udisks_block_device_get_device (block),
- str->str);
- g_string_free (str, TRUE);
- goto out;
- }
-
- /* Fail if the device is not mountable - we actually allow mounting
- * devices that are not probed since since it could be that we just
- * don't have the data in the udev database but the device has a
- * filesystem *anyway*...
- *
- * For example, this applies to PC floppy devices - automatically
- * probing for media them creates annoying noise. So they won't
- * appear in the udev database.
- */
- probed_fs_usage = NULL;
- probed_fs_type = NULL;
- if (block_probed != NULL)
- {
- probed_fs_usage = udisks_block_device_probed_get_usage (block_probed);
- probed_fs_type = udisks_block_device_probed_get_type (block_probed);
- }
- if (probed_fs_usage != NULL && strlen (probed_fs_usage) > 0 &&
- g_strcmp0 (probed_fs_usage, "filesystem") != 0)
- {
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "Cannot mount block device %s with probed usage `%s' - expected `filesystem'",
- udisks_block_device_get_device (block),
- probed_fs_usage);
- goto out;
- }
-
- /* we need the uid of the caller to check mount options */
- error = NULL;
- if (!get_uid_sync (invocation, NULL /* GCancellable */, &caller_uid, &error))
- {
- g_dbus_method_invocation_return_gerror (invocation, error);
- g_error_free (error);
- goto out;
- }
-
- /* calculate filesystem type (guaranteed to be valid UTF-8) */
- error = NULL;
- fs_type_to_use = calculate_fs_type (block,
- block_probed,
- requested_fs_type,
- &error);
- if (fs_type_to_use == NULL)
- {
- g_dbus_method_invocation_return_gerror (invocation, error);
- g_error_free (error);
- goto out;
- }
-
- /* calculate mount options (guaranteed to be valid UTF-8) */
- error = NULL;
- mount_options_to_use = calculate_mount_options (block,
- block_probed,
- caller_uid,
- fs_type_to_use,
- requested_options,
- &auth_no_user_interaction,
- &error);
- if (mount_options_to_use == NULL)
- {
- g_dbus_method_invocation_return_gerror (invocation, error);
- g_error_free (error);
- goto out;
- }
-
- /* calculate mount point (guaranteed to be valid UTF-8) */
- error = NULL;
- mount_point_to_use = calculate_mount_point (block,
- block_probed,
- fs_type_to_use,
- &error);
- if (mount_point_to_use == NULL)
- {
- g_dbus_method_invocation_return_gerror (invocation, error);
- g_error_free (error);
- goto out;
- }
-
- /* now check that the user is actually authorized to mount the device
- *
- * (TODO: fill in details and pick the right action_id)
- */
- auth_action_id = "org.freedesktop.udisks2.filesystem-mount",
- auth_subject = polkit_system_bus_name_new (g_dbus_method_invocation_get_sender (invocation));
- auth_flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE;
- if (!auth_no_user_interaction)
- auth_flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION;
- error = NULL;
- auth_result = polkit_authority_check_authorization_sync (udisks_daemon_get_authority (daemon),
- auth_subject,
- auth_action_id,
- auth_details,
- auth_flags,
- NULL, /* GCancellable* */
- &error);
- if (auth_result == NULL)
- {
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "Error checking authorization: %s (%s, %d)",
- error->message,
- g_quark_to_string (error->domain),
- error->code);
- g_error_free (error);
- goto out;
- }
- if (!polkit_authorization_result_get_is_authorized (auth_result))
- {
- g_dbus_method_invocation_return_error_literal (invocation,
- UDISKS_ERROR,
- polkit_authorization_result_get_is_challenge (auth_result) ?
- UDISKS_ERROR_NOT_AUTHORIZED_CAN_OBTAIN :
- UDISKS_ERROR_NOT_AUTHORIZED,
- "Not authorized to perform operation");
- goto out;
- }
-
- /* create the mount point */
- if (g_mkdir (mount_point_to_use, 0700) != 0)
- {
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "Error creating mount point `%s': %m",
- mount_point_to_use);
- goto out;
- }
-
- /* update the mounted-fs file */
- if (!udisks_persistent_store_mounted_fs_add (store,
- udisks_block_device_get_device (block),
- mount_point_to_use,
- caller_uid,
- &error))
- goto out;
-
- escaped_fs_type_to_use = g_strescape (fs_type_to_use, NULL);
- escaped_mount_options_to_use = g_strescape (mount_options_to_use, NULL);
- escaped_mount_point_to_use = g_strescape (mount_point_to_use, NULL);
-
- /* run mount(8) */
- if (!udisks_daemon_launch_spawned_job_sync (daemon,
- NULL, /* GCancellable */
- &error_message,
- NULL, /* input_string */
- "mount -t \"%s\" -o \"%s\" \"%s\" \"%s\"",
- escaped_fs_type_to_use,
- escaped_mount_options_to_use,
- udisks_block_device_get_device (block),
- escaped_mount_point_to_use))
- {
- /* ugh, something went wrong.. we need to clean up the created mount point
- * and also remove the entry from our mounted-fs file
- *
- * Either of these operations shouldn't really fail...
- */
- error = NULL;
- if (!udisks_persistent_store_mounted_fs_remove (store,
- mount_point_to_use,
- &error))
- {
- udisks_daemon_log (daemon,
- UDISKS_LOG_LEVEL_WARNING,
- "Error removing mount point %s from filesystems file: %s (%s, %d)",
- mount_point_to_use,
- error->message,
- g_quark_to_string (error->domain),
- error->code);
- g_error_free (error);
- }
- if (g_rmdir (mount_point_to_use) != 0)
- {
- udisks_daemon_log (daemon,
- UDISKS_LOG_LEVEL_WARNING,
- "Error removing directory %s: %m",
- mount_point_to_use);
- }
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "Error mounting %s at %s: %s",
- udisks_block_device_get_device (block),
- mount_point_to_use,
- error_message);
- goto out;
- }
-
- udisks_daemon_log (daemon,
- UDISKS_LOG_LEVEL_INFO,
- "Mounted %s at %s on behalf of uid %d",
- udisks_block_device_get_device (block),
- mount_point_to_use,
- caller_uid);
-
- udisks_filesystem_complete_mount (filesystem, invocation, mount_point_to_use);
-
- out:
- if (auth_subject != NULL)
- g_object_unref (auth_subject);
- if (auth_details != NULL)
- g_object_unref (auth_details);
- if (auth_result != NULL)
- g_object_unref (auth_result);
- g_free (error_message);
- g_free (escaped_fs_type_to_use);
- g_free (escaped_mount_options_to_use);
- g_free (escaped_mount_point_to_use);
- g_free (fs_type_to_use);
- g_free (mount_options_to_use);
- g_free (mount_point_to_use);
- if (object != NULL)
- g_object_unref (object);
- if (block != NULL)
- g_object_unref (block);
- if (block_probed != NULL)
- g_object_unref (block_probed);
-
- return TRUE; /* returning TRUE means that we handled the method invocation */
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-/* runs in thread dedicated to handling method call */
-static gboolean
-handle_unmount (UDisksFilesystem *filesystem,
- GDBusMethodInvocation *invocation,
- const gchar* const *options)
-{
- GDBusObject *object;
- UDisksBlockDevice *block;
- UDisksDaemon *daemon;
- UDisksPersistentStore *store;
- gchar *mount_point;
- gchar *escaped_mount_point;
- GError *error;
- uid_t mounted_by_uid;
- uid_t caller_uid;
- gchar *error_message;
- const gchar *const *mount_points;
- guint n;
- gboolean opt_force;
- gboolean rc;
-
- mount_point = NULL;
- escaped_mount_point = NULL;
- error_message = NULL;
- opt_force = FALSE;
-
- object = g_dbus_interface_get_object (G_DBUS_INTERFACE (filesystem));
- block = UDISKS_BLOCK_DEVICE (g_dbus_object_lookup_interface (object, "org.freedesktop.UDisks2.BlockDevice"));
- daemon = udisks_linux_block_get_daemon (UDISKS_LINUX_BLOCK (object));
- store = udisks_daemon_get_persistent_store (daemon);
-
- for (n = 0; options != NULL && options[n] != NULL; n++)
- {
- const gchar *option = options[n];
- if (g_strcmp0 (option, "force") == 0)
- {
- opt_force = TRUE;
- }
- else
- {
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_OPTION_NOT_PERMITTED,
- "Unsupported option `%s'",
- option);
- goto out;
- }
- }
-
- mount_points = udisks_filesystem_get_mount_points (filesystem);
- if (mount_points == NULL || g_strv_length ((gchar **) mount_points) == 0)
- {
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_NOT_MOUNTED,
- "Device `%s' is not mounted",
- udisks_block_device_get_device (block));
- goto out;
- }
-
- error = NULL;
- mount_point = udisks_persistent_store_mounted_fs_find (store,
- udisks_block_device_get_device (block),
- &mounted_by_uid,
- &error);
- if (error != NULL)
- {
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "Error when looking for entry `%s' in mounted-fs: %s (%s, %d)",
- udisks_block_device_get_device (block),
- error->message,
- g_quark_to_string (error->domain),
- error->code);
- g_error_free (error);
- goto out;
- }
- if (mount_point == NULL)
- {
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "Entry for `%s' not found in mounted-fs",
- udisks_block_device_get_device (block));
- goto out;
- }
-
- /* TODO: allow unmounting stuff not in the mounted-fs file? */
-
- error = NULL;
- if (!get_uid_sync (invocation, NULL, &caller_uid, &error))
- {
- g_dbus_method_invocation_return_gerror (invocation, error);
- g_error_free (error);
- goto out;
- }
-
- if (caller_uid != 0 && (caller_uid != mounted_by_uid))
- {
- /* TODO: allow with special authorization (unmount-others) */
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_MOUNTED_BY_OTHER_USER,
- "Cannot unmount filesystem at `%s' mounted by other user with uid %d",
- mount_point,
- mounted_by_uid);
- goto out;
- }
-
- /* otherwise go ahead and unmount the filesystem */
- if (!udisks_persistent_store_mounted_fs_currently_unmounting_add (store, mount_point))
- {
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_ALREADY_UNMOUNTING,
- "Cannot unmount %s: Mount point `%s' is currently being unmounted",
- udisks_block_device_get_device (block),
- mount_point);
- goto out;
- }
-
- escaped_mount_point = g_strescape (mount_point, NULL);
- if (opt_force)
- {
- /* right now -l is the only way to "force unmount" file systems... */
- rc = udisks_daemon_launch_spawned_job_sync (daemon,
- NULL, /* GCancellable */
- &error_message,
- NULL, /* input_string */
- "umount -l \"%s\"",
- escaped_mount_point);
- }
- else
- {
- rc = udisks_daemon_launch_spawned_job_sync (daemon,
- NULL, /* GCancellable */
- &error_message,
- NULL, /* input_string */
- "umount \"%s\"",
- escaped_mount_point);
- }
- if (!rc)
- {
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "Error unmounting %s from %s: %s",
- udisks_block_device_get_device (block),
- mount_point,
- error_message);
- udisks_persistent_store_mounted_fs_currently_unmounting_remove (store, mount_point);
- goto out;
- }
-
- /* OK, filesystem unmounted.. now to remove the entry from mounted-fs as well as the mount point */
- error = NULL;
- if (!udisks_persistent_store_mounted_fs_remove (store,
- mount_point,
- &error))
- {
- if (error == NULL)
- {
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "Error removing entry for `%s' from mounted-fs: Entry not found",
- mount_point);
- }
- else
- {
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "Error removing entry for `%s' from mounted-fs: %s (%s, %d)",
- mount_point,
- error->message,
- g_quark_to_string (error->domain),
- error->code);
- g_error_free (error);
- }
- udisks_persistent_store_mounted_fs_currently_unmounting_remove (store, mount_point);
- goto out;
- }
- udisks_persistent_store_mounted_fs_currently_unmounting_remove (store, mount_point);
-
- /* OK, removed the entry. Finally: nuke the mount point */
- if (g_rmdir (mount_point) != 0)
- {
- udisks_daemon_log (daemon,
- UDISKS_LOG_LEVEL_ERROR,
- "Error removing mount point `%s': %m",
- mount_point);
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "Error removing mount point `%s': %m",
- mount_point);
- goto out;
- }
-
- udisks_daemon_log (daemon,
- UDISKS_LOG_LEVEL_INFO,
- "Unmounted %s from %s on behalf of uid %d",
- udisks_block_device_get_device (block),
- mount_point,
- caller_uid);
-
- udisks_filesystem_complete_unmount (filesystem, invocation);
-
- out:
- g_free (error_message);
- g_free (escaped_mount_point);
- g_free (mount_point);
- g_object_unref (block);
- g_object_unref (object);
- return TRUE;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-filesystem_iface_init (UDisksFilesystemIface *iface)
-{
- iface->handle_mount = handle_mount;
- iface->handle_unmount = handle_unmount;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/udisksfilesystemimpl.h b/src/udisksfilesystemimpl.h
deleted file mode 100644
index 1f17943..0000000
--- a/src/udisksfilesystemimpl.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2007-2010 David Zeuthen <zeuthen@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifndef __UDISKS_FILESYSTEM_IMPL_H__
-#define __UDISKS_FILESYSTEM_IMPL_H__
-
-#include "types.h"
-
-G_BEGIN_DECLS
-
-#define UDISKS_TYPE_FILESYSTEM_IMPL (udisks_filesystem_impl_get_type ())
-#define UDISKS_FILESYSTEM_IMPL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UDISKS_TYPE_FILESYSTEM_IMPL, UDisksFilesystemImpl))
-#define UDISKS_IS_FILESYSTEM_IMPL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UDISKS_TYPE_FILESYSTEM_IMPL))
-
-GType udisks_filesystem_impl_get_type (void) G_GNUC_CONST;
-
-G_END_DECLS
-
-#endif /* __UDISKS_FILESYSTEM_IMPL_H__ */
diff --git a/src/udiskslinuxblock.c b/src/udiskslinuxblock.c
index f94b395..2778b53 100644
--- a/src/udiskslinuxblock.c
+++ b/src/udiskslinuxblock.c
@@ -20,13 +20,21 @@
#include "config.h"
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <glib/gstdio.h>
+
#include "udisksdaemon.h"
#include "udisksdaemonutil.h"
#include "udiskslinuxblock.h"
-#include "udisksfilesystemimpl.h"
#include "udisksmount.h"
#include "udisksmountmonitor.h"
#include "udiskslinuxdrive.h"
+#include "udiskspersistentstore.h"
/**
* SECTION:udiskslinuxblock
@@ -56,8 +64,6 @@ struct _UDisksLinuxBlock
/* interface */
UDisksLinuxSysfsDevice *iface_linux_sysfs_device;
UDisksBlockDevice *iface_block_device;
- UDisksBlockDeviceProbed *iface_block_device_probed;
- UDisksFilesystem *iface_filesystem;
};
struct _UDisksLinuxBlockClass
@@ -96,10 +102,6 @@ udisks_linux_block_finalize (GObject *object)
g_object_unref (block->iface_linux_sysfs_device);
if (block->iface_block_device != NULL)
g_object_unref (block->iface_block_device);
- if (block->iface_block_device_probed != NULL)
- g_object_unref (block->iface_block_device_probed);
- if (block->iface_filesystem != NULL)
- g_object_unref (block->iface_filesystem);
if (G_OBJECT_CLASS (udisks_linux_block_parent_class)->finalize != NULL)
G_OBJECT_CLASS (udisks_linux_block_parent_class)->finalize (object);
@@ -292,6 +294,7 @@ udisks_linux_block_get_device (UDisksLinuxBlock *block)
/* ---------------------------------------------------------------------------------------------------- */
typedef gboolean (*HasInterfaceFunc) (UDisksLinuxBlock *block);
+typedef void (*ConnectInterfaceFunc) (UDisksLinuxBlock *block);
typedef void (*UpdateInterfaceFunc) (UDisksLinuxBlock *block,
const gchar *uevent_action,
GDBusInterface *interface);
@@ -300,6 +303,7 @@ static void
update_iface (UDisksLinuxBlock *block,
const gchar *uevent_action,
HasInterfaceFunc has_func,
+ ConnectInterfaceFunc connect_func,
UpdateInterfaceFunc update_func,
GType stub_type,
gpointer _interface_pointer)
@@ -323,6 +327,8 @@ update_iface (UDisksLinuxBlock *block,
if (has)
{
*interface_pointer = g_object_new (stub_type, NULL);
+ if (connect_func != NULL)
+ connect_func (block);
add = TRUE;
}
}
@@ -356,6 +362,30 @@ block_device_check (UDisksLinuxBlock *block)
return TRUE;
}
+static gboolean
+handle_mount (UDisksBlockDevice *block,
+ GDBusMethodInvocation *invocation,
+ const gchar *requested_fs_type,
+ const gchar* const *requested_options);
+
+static gboolean
+handle_unmount (UDisksBlockDevice *block,
+ GDBusMethodInvocation *invocation,
+ const gchar* const *options);
+
+static void
+block_device_connect (UDisksLinuxBlock *block)
+{
+ g_signal_connect (block->iface_block_device,
+ "handle-filesystem-mount",
+ G_CALLBACK (handle_mount),
+ NULL);
+ g_signal_connect (block->iface_block_device,
+ "handle-filesystem-unmount",
+ G_CALLBACK (handle_unmount),
+ NULL);
+}
+
static gchar *
find_drive (GDBusObjectManager *object_manager,
GUdevDevice *block_device)
@@ -416,6 +446,10 @@ block_device_update (UDisksLinuxBlock *block,
GUdevDeviceNumber dev;
GDBusObjectManager *object_manager;
gchar *drive_object_path;
+ gchar *s;
+ GList *mounts;
+ GList *l;
+ GPtrArray *p;
dev = g_udev_device_get_device_number (block->device);
@@ -439,36 +473,33 @@ block_device_update (UDisksLinuxBlock *block,
{
udisks_block_device_set_drive (iface, "/");
}
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-/* org.freedesktop.UDisks.BlockDeviceProbed */
-
-static gboolean
-block_device_probed_check (UDisksLinuxBlock *block)
-{
- return g_udev_device_has_property (block->device, "ID_FS_USAGE");
-}
-
-static void
-block_device_probed_update (UDisksLinuxBlock *block,
- const gchar *uevent_action,
- GDBusInterface *_iface)
-{
- UDisksBlockDeviceProbed *iface = UDISKS_BLOCK_DEVICE_PROBED (_iface);
- gchar *s;
-
- udisks_block_device_probed_set_usage (iface, g_udev_device_get_property (block->device, "ID_FS_USAGE"));
- udisks_block_device_probed_set_type (iface, g_udev_device_get_property (block->device, "ID_FS_TYPE"));
- udisks_block_device_probed_set_version (iface, g_udev_device_get_property (block->device, "ID_FS_VERSION"));
+ udisks_block_device_set_id_usage (iface, g_udev_device_get_property (block->device, "ID_FS_USAGE"));
+ udisks_block_device_set_id_type (iface, g_udev_device_get_property (block->device, "ID_FS_TYPE"));
+ udisks_block_device_set_id_version (iface, g_udev_device_get_property (block->device, "ID_FS_VERSION"));
s = udisks_decode_udev_string (g_udev_device_get_property (block->device, "ID_FS_LABEL_ENC"));
- udisks_block_device_probed_set_label (iface, s);
+ udisks_block_device_set_id_label (iface, s);
g_free (s);
-
s = udisks_decode_udev_string (g_udev_device_get_property (block->device, "ID_FS_UUID_ENC"));
- udisks_block_device_probed_set_uuid (iface, s);
+ udisks_block_device_set_id_uuid (iface, s);
g_free (s);
+
+ p = g_ptr_array_new ();
+ mounts = udisks_mount_monitor_get_mounts_for_dev (block->mount_monitor,
+ g_udev_device_get_device_number (block->device));
+ /* we are guaranteed that the list is sorted so if there are
+ * multiple mounts we'll always get the same order
+ */
+ for (l = mounts; l != NULL; l = l->next)
+ {
+ UDisksMount *mount = UDISKS_MOUNT (l->data);
+ g_ptr_array_add (p, (gpointer) udisks_mount_get_mount_path (mount));
+ }
+ g_ptr_array_add (p, NULL);
+ udisks_block_device_set_filesystem_mount_points (iface, (const gchar *const *) p->pdata);
+ g_ptr_array_free (p, TRUE);
+ g_list_foreach (mounts, (GFunc) g_object_unref, NULL);
+ g_list_free (mounts);
}
/* ---------------------------------------------------------------------------------------------------- */
@@ -495,44 +526,6 @@ linux_sysfs_device_update (UDisksLinuxBlock *block,
}
/* ---------------------------------------------------------------------------------------------------- */
-/* org.freedesktop.UDisks.Filesystem */
-
-static gboolean
-filesystem_check (UDisksLinuxBlock *block)
-{
- return g_strcmp0 (g_udev_device_get_property (block->device, "ID_FS_USAGE"), "filesystem") == 0;
-}
-
-static void
-filesystem_update (UDisksLinuxBlock *block,
- const gchar *uevent_action,
- GDBusInterface *_iface)
-{
- UDisksFilesystem *iface = UDISKS_FILESYSTEM (_iface);
- GList *mounts;
- GList *l;
- GPtrArray *p;
-
- p = g_ptr_array_new ();
- mounts = udisks_mount_monitor_get_mounts_for_dev (block->mount_monitor,
- g_udev_device_get_device_number (block->device));
- /* we are guaranteed that the list is sorted so if there are
- * multiple mounts we'll always get the same order
- */
- for (l = mounts; l != NULL; l = l->next)
- {
- UDisksMount *mount = UDISKS_MOUNT (l->data);
- g_ptr_array_add (p, (gpointer) udisks_mount_get_mount_path (mount));
- }
- g_ptr_array_add (p, NULL);
- udisks_filesystem_set_mount_points (iface, (const gchar *const *) p->pdata);
- g_ptr_array_free (p, TRUE);
-
- g_list_foreach (mounts, (GFunc) g_object_unref, NULL);
- g_list_free (mounts);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
/**
* udisks_linux_block_uevent:
@@ -557,14 +550,10 @@ udisks_linux_block_uevent (UDisksLinuxBlock *block,
g_object_notify (G_OBJECT (block), "device");
}
- update_iface (block, action, linux_sysfs_device_check, linux_sysfs_device_update,
+ update_iface (block, action, linux_sysfs_device_check, NULL, linux_sysfs_device_update,
UDISKS_TYPE_LINUX_SYSFS_DEVICE_STUB, &block->iface_linux_sysfs_device);
- update_iface (block, action, block_device_check, block_device_update,
+ update_iface (block, action, block_device_check, block_device_connect, block_device_update,
UDISKS_TYPE_BLOCK_DEVICE_STUB, &block->iface_block_device);
- update_iface (block, action, block_device_probed_check, block_device_probed_update,
- UDISKS_TYPE_BLOCK_DEVICE_PROBED_STUB, &block->iface_block_device_probed);
- update_iface (block, action, filesystem_check, filesystem_update,
- UDISKS_TYPE_FILESYSTEM_IMPL, &block->iface_filesystem);
}
/* ---------------------------------------------------------------------------------------------------- */
@@ -590,3 +579,1121 @@ on_mount_monitor_mount_removed (UDisksMountMonitor *monitor,
}
/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+get_uid_sync (GDBusMethodInvocation *invocation,
+ GCancellable *cancellable,
+ uid_t *out_uid,
+ GError **error)
+{
+ gboolean ret;
+ const gchar *caller;
+ GVariant *value;
+ GError *local_error;
+
+ ret = FALSE;
+
+ caller = g_dbus_method_invocation_get_sender (invocation);
+
+ local_error = NULL;
+ value = g_dbus_connection_call_sync (g_dbus_method_invocation_get_connection (invocation),
+ "org.freedesktop.DBus", /* bus name */
+ "/org/freedesktop/DBus", /* object path */
+ "org.freedesktop.DBus", /* interface */
+ "GetConnectionUnixUser", /* method */
+ g_variant_new ("(s)", caller),
+ G_VARIANT_TYPE ("(u)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, /* timeout_msec */
+ cancellable,
+ &local_error);
+ if (value == NULL)
+ {
+ g_set_error (error,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error determining uid of caller %s: %s (%s, %d)",
+ caller,
+ local_error->message,
+ g_quark_to_string (local_error->domain),
+ local_error->code);
+ g_error_free (local_error);
+ goto out;
+ }
+
+ G_STATIC_ASSERT (sizeof (uid_t) == sizeof (guint32));
+ g_variant_get (value, "(u)", out_uid);
+
+ ret = TRUE;
+
+ out:
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+ const gchar *fstype;
+ const gchar * const *defaults;
+ const gchar * const *allow;
+ const gchar * const *allow_uid_self;
+ const gchar * const *allow_gid_self;
+} FSMountOptions;
+
+/* ---------------------- vfat -------------------- */
+
+static const gchar *vfat_defaults[] = { "uid=", "gid=", "shortname=mixed", "dmask=0077", "utf8=1", "showexec", NULL };
+static const gchar *vfat_allow[] = { "flush", "utf8=", "shortname=", "umask=", "dmask=", "fmask=", "codepage=", "iocharset=", "usefree", "showexec", NULL };
+static const gchar *vfat_allow_uid_self[] = { "uid=", NULL };
+static const gchar *vfat_allow_gid_self[] = { "gid=", NULL };
+
+/* ---------------------- ntfs -------------------- */
+/* this is assuming that ntfs-3g is used */
+
+static const gchar *ntfs_defaults[] = { "uid=", "gid=", "dmask=0077", "fmask=0177", NULL };
+static const gchar *ntfs_allow[] = { "umask=", "dmask=", "fmask=", NULL };
+static const gchar *ntfs_allow_uid_self[] = { "uid=", NULL };
+static const gchar *ntfs_allow_gid_self[] = { "gid=", NULL };
+
+/* ---------------------- iso9660 -------------------- */
+
+static const gchar *iso9660_defaults[] = { "uid=", "gid=", "iocharset=utf8", "mode=0400", "dmode=0500", NULL };
+static const gchar *iso9660_allow[] = { "norock", "nojoliet", "iocharset=", "mode=", "dmode=", NULL };
+static const gchar *iso9660_allow_uid_self[] = { "uid=", NULL };
+static const gchar *iso9660_allow_gid_self[] = { "gid=", NULL };
+
+/* ---------------------- udf -------------------- */
+
+static const gchar *udf_defaults[] = { "uid=", "gid=", "iocharset=utf8", "umask=0077", NULL };
+static const gchar *udf_allow[] = { "iocharset=", "umask=", NULL };
+static const gchar *udf_allow_uid_self[] = { "uid=", NULL };
+static const gchar *udf_allow_gid_self[] = { "gid=", NULL };
+
+/* ------------------------------------------------ */
+/* TODO: support context= */
+
+static const gchar *any_allow[] = { "exec", "noexec", "nodev", "nosuid", "atime", "noatime", "nodiratime", "ro", "rw", "sync", "dirsync", NULL };
+
+static const FSMountOptions fs_mount_options[] =
+ {
+ { "vfat", vfat_defaults, vfat_allow, vfat_allow_uid_self, vfat_allow_gid_self },
+ { "ntfs", ntfs_defaults, ntfs_allow, ntfs_allow_uid_self, ntfs_allow_gid_self },
+ { "iso9660", iso9660_defaults, iso9660_allow, iso9660_allow_uid_self, iso9660_allow_gid_self },
+ { "udf", udf_defaults, udf_allow, udf_allow_uid_self, udf_allow_gid_self },
+ };
+
+/* ------------------------------------------------ */
+
+static int num_fs_mount_options = sizeof(fs_mount_options) / sizeof(FSMountOptions);
+
+static const FSMountOptions *
+find_mount_options_for_fs (const gchar *fstype)
+{
+ int n;
+ const FSMountOptions *fsmo;
+
+ for (n = 0; n < num_fs_mount_options; n++)
+ {
+ fsmo = fs_mount_options + n;
+ if (g_strcmp0 (fsmo->fstype, fstype) == 0)
+ goto out;
+ }
+
+ fsmo = NULL;
+ out:
+ return fsmo;
+}
+
+static gid_t
+find_primary_gid (uid_t uid)
+{
+ struct passwd *pw;
+ gid_t gid;
+
+ gid = (gid_t) - 1;
+
+ pw = getpwuid (uid);
+ if (pw == NULL)
+ {
+ g_warning ("Couldn't look up uid %d: %m", uid);
+ goto out;
+ }
+ gid = pw->pw_gid;
+
+ out:
+ return gid;
+}
+
+static gboolean
+is_uid_in_gid (uid_t uid,
+ gid_t gid)
+{
+ gboolean ret;
+ struct passwd *pw;
+ static gid_t supplementary_groups[128];
+ int num_supplementary_groups = 128;
+ int n;
+
+ /* TODO: use some #define instead of harcoding some random number like 128 */
+
+ ret = FALSE;
+
+ pw = getpwuid (uid);
+ if (pw == NULL)
+ {
+ g_warning ("Couldn't look up uid %d: %m", uid);
+ goto out;
+ }
+ if (pw->pw_gid == gid)
+ {
+ ret = TRUE;
+ goto out;
+ }
+
+ if (getgrouplist (pw->pw_name, pw->pw_gid, supplementary_groups, &num_supplementary_groups) < 0)
+ {
+ g_warning ("Couldn't find supplementary groups for uid %d: %m", uid);
+ goto out;
+ }
+
+ for (n = 0; n < num_supplementary_groups; n++)
+ {
+ if (supplementary_groups[n] == gid)
+ {
+ ret = TRUE;
+ goto out;
+ }
+ }
+
+ out:
+ return ret;
+}
+
+static gboolean
+is_mount_option_allowed (const FSMountOptions *fsmo,
+ const gchar *option,
+ uid_t caller_uid)
+{
+ int n;
+ gchar *endp;
+ uid_t uid;
+ gid_t gid;
+ gboolean allowed;
+ const gchar *ep;
+ gsize ep_len;
+
+ allowed = FALSE;
+
+ /* first run through the allowed mount options */
+ if (fsmo != NULL)
+ {
+ for (n = 0; fsmo->allow != NULL && fsmo->allow[n] != NULL; n++)
+ {
+ ep = strstr (fsmo->allow[n], "=");
+ if (ep != NULL && ep[1] == '\0')
+ {
+ ep_len = ep - fsmo->allow[n] + 1;
+ if (strncmp (fsmo->allow[n], option, ep_len) == 0)
+ {
+ allowed = TRUE;
+ goto out;
+ }
+ }
+ else
+ {
+ if (strcmp (fsmo->allow[n], option) == 0)
+ {
+ allowed = TRUE;
+ goto out;
+ }
+ }
+ }
+ }
+ for (n = 0; any_allow[n] != NULL; n++)
+ {
+ ep = strstr (any_allow[n], "=");
+ if (ep != NULL && ep[1] == '\0')
+ {
+ ep_len = ep - any_allow[n] + 1;
+ if (strncmp (any_allow[n], option, ep_len) == 0)
+ {
+ allowed = TRUE;
+ goto out;
+ }
+ }
+ else
+ {
+ if (strcmp (any_allow[n], option) == 0)
+ {
+ allowed = TRUE;
+ goto out;
+ }
+ }
+ }
+
+ /* .. then check for mount options where the caller is allowed to pass
+ * in his own uid
+ */
+ if (fsmo != NULL)
+ {
+ for (n = 0; fsmo->allow_uid_self != NULL && fsmo->allow_uid_self[n] != NULL; n++)
+ {
+ const gchar *r_mount_option = fsmo->allow_uid_self[n];
+ if (g_str_has_prefix (option, r_mount_option))
+ {
+ uid = strtol (option + strlen (r_mount_option), &endp, 10);
+ if (*endp != '\0')
+ continue;
+ if (uid == caller_uid)
+ {
+ allowed = TRUE;
+ goto out;
+ }
+ }
+ }
+ }
+
+ /* .. ditto for gid
+ */
+ if (fsmo != NULL)
+ {
+ for (n = 0; fsmo->allow_gid_self != NULL && fsmo->allow_gid_self[n] != NULL; n++)
+ {
+ const gchar *r_mount_option = fsmo->allow_gid_self[n];
+ if (g_str_has_prefix (option, r_mount_option))
+ {
+ gid = strtol (option + strlen (r_mount_option), &endp, 10);
+ if (*endp != '\0')
+ continue;
+ if (is_uid_in_gid (caller_uid, gid))
+ {
+ allowed = TRUE;
+ goto out;
+ }
+ }
+ }
+ }
+
+ out:
+ return allowed;
+}
+
+static gchar **
+prepend_default_mount_options (const FSMountOptions *fsmo,
+ uid_t caller_uid,
+ const gchar * const *given_options)
+{
+ GPtrArray *options;
+ int n;
+ gchar *s;
+ gid_t gid;
+
+ options = g_ptr_array_new ();
+ if (fsmo != NULL)
+ {
+ for (n = 0; fsmo->defaults != NULL && fsmo->defaults[n] != NULL; n++)
+ {
+ const gchar *option = fsmo->defaults[n];
+
+ if (strcmp (option, "uid=") == 0)
+ {
+ s = g_strdup_printf ("uid=%d", caller_uid);
+ g_ptr_array_add (options, s);
+ }
+ else if (strcmp (option, "gid=") == 0)
+ {
+ gid = find_primary_gid (caller_uid);
+ if (gid != (gid_t) - 1)
+ {
+ s = g_strdup_printf ("gid=%d", gid);
+ g_ptr_array_add (options, s);
+ }
+ }
+ else
+ {
+ g_ptr_array_add (options, g_strdup (option));
+ }
+ }
+ }
+ for (n = 0; given_options[n] != NULL; n++)
+ {
+ g_ptr_array_add (options, g_strdup (given_options[n]));
+ }
+
+ g_ptr_array_add (options, NULL);
+
+ return (char **) g_ptr_array_free (options, FALSE);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/*
+ * calculate_fs_type: <internal>
+ * @block: A #UDisksBlockDevice.
+ * @requested_fs_type: The requested file system type or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Calculates the file system type to use.
+ *
+ * Returns: A valid UTF-8 string with the filesystem type (may be "auto") or %NULL if @error is set. Free with g_free().
+ */
+static gchar *
+calculate_fs_type (UDisksBlockDevice *block,
+ const gchar *requested_fs_type,
+ GError **error)
+{
+ gchar *fs_type_to_use;
+ const gchar *probed_fs_usage;
+ const gchar *probed_fs_type;
+
+ probed_fs_usage = NULL;
+ probed_fs_type = NULL;
+ if (block != NULL)
+ {
+ probed_fs_usage = udisks_block_device_get_id_usage (block);
+ probed_fs_type = udisks_block_device_get_id_type (block);
+ }
+
+ fs_type_to_use = NULL;
+ if (requested_fs_type != NULL && strlen (requested_fs_type) > 0)
+ {
+ /* TODO: maybe check that it's compatible with probed_fs_type */
+ fs_type_to_use = g_strdup (requested_fs_type);
+ }
+ else
+ {
+ if (probed_fs_type != NULL && strlen (probed_fs_type) > 0)
+ fs_type_to_use = g_strdup (probed_fs_type);
+ else
+ fs_type_to_use = g_strdup ("auto");
+ }
+
+ g_assert (fs_type_to_use == NULL || g_utf8_validate (fs_type_to_use, -1, NULL));
+
+ return fs_type_to_use;
+}
+
+/*
+ * calculate_mount_options: <internal>
+ * @block: A #UDisksBlockDevice.
+ * @caller_uid: The uid of the caller making the request.
+ * @fs_type: The filesystem type to use or %NULL.
+ * @requested_options: Options requested by the caller.
+ * @out_auth_no_user_interaction: Return location for whether the 'auth_no_user_interaction' option was passed or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Calculates the mount option string to use. Ensures (by returning an
+ * error) that only safe options are used.
+ *
+ * Returns: A string with mount options or %NULL if @error is set. Free with g_free().
+ */
+static gchar *
+calculate_mount_options (UDisksBlockDevice *block,
+ uid_t caller_uid,
+ const gchar *fs_type,
+ const gchar *const *requested_options,
+ gboolean *out_auth_no_user_interaction,
+ GError **error)
+{
+ const FSMountOptions *fsmo;
+ gchar **options_to_use;
+ gchar *options_to_use_str;
+ GString *str;
+ guint n;
+ gboolean auth_no_user_interaction;
+
+ options_to_use = NULL;
+ options_to_use_str = NULL;
+ auth_no_user_interaction = FALSE;
+
+ fsmo = find_mount_options_for_fs (fs_type);
+
+ /* always prepend some reasonable default mount options; these are
+ * chosen here; the user can override them if he wants to
+ */
+ options_to_use = prepend_default_mount_options (fsmo, caller_uid, requested_options);
+
+ /* validate mount options */
+ str = g_string_new ("uhelper=udisks2,nodev,nosuid");
+ for (n = 0; options_to_use[n] != NULL; n++)
+ {
+ const gchar *option = options_to_use[n];
+
+ if (g_strcmp0 (option, "auth_no_user_interaction") == 0)
+ {
+ auth_no_user_interaction = TRUE;
+ continue;
+ }
+
+ /* avoid attacks like passing "shortname=lower,uid=0" as a single mount option */
+ if (strstr (option, ",") != NULL)
+ {
+ g_set_error (error,
+ UDISKS_ERROR,
+ UDISKS_ERROR_OPTION_NOT_PERMITTED,
+ "Malformed mount option `%s'",
+ option);
+ g_string_free (str, TRUE);
+ goto out;
+ }
+
+ /* first check if the mount option is allowed */
+ if (!is_mount_option_allowed (fsmo, option, caller_uid))
+ {
+ g_set_error (error,
+ UDISKS_ERROR,
+ UDISKS_ERROR_OPTION_NOT_PERMITTED,
+ "Mount option `%s' is not allowed",
+ option);
+ g_string_free (str, TRUE);
+ goto out;
+ }
+
+ g_string_append_c (str, ',');
+ g_string_append (str, option);
+ }
+ options_to_use_str = g_string_free (str, FALSE);
+
+ out:
+ g_strfreev (options_to_use);
+
+ g_assert (options_to_use_str == NULL || g_utf8_validate (options_to_use_str, -1, NULL));
+
+ if (out_auth_no_user_interaction != NULL)
+ *out_auth_no_user_interaction = auth_no_user_interaction;
+
+ return options_to_use_str;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gchar *
+ensure_utf8 (const gchar *s)
+{
+ const gchar *end;
+ gchar *ret;
+
+ if (!g_utf8_validate (s, -1, &end))
+ {
+ gchar *tmp;
+ gint pos;
+ /* TODO: could possibly return a nicer UTF-8 string */
+ pos = (gint) (end - s);
+ tmp = g_strndup (s, end - s);
+ ret = g_strdup_printf ("%s (Invalid UTF-8 at byte %d)", tmp, pos);
+ g_free (tmp);
+ }
+ else
+ {
+ ret = g_strdup (s);
+ }
+
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/*
+ * calculate_mount_point: <internal>
+ * @block: A #UDisksBlockDevice.
+ * @fs_type: The file system type to mount with
+ * @error: Return location for error or %NULL.
+ *
+ * Calculates the mount point to use.
+ *
+ * Returns: A UTF-8 string with the mount point to use or %NULL if @error is set. Free with g_free().
+ */
+static gchar *
+calculate_mount_point (UDisksBlockDevice *block,
+ const gchar *fs_type,
+ GError **error)
+{
+ const gchar *label;
+ const gchar *uuid;
+ gchar *mount_point;
+ gchar *orig_mount_point;
+ GString *str;
+ gchar *s;
+ guint n;
+
+ label = NULL;
+ uuid = NULL;
+ if (block != NULL)
+ {
+ label = udisks_block_device_get_id_label (block);
+ uuid = udisks_block_device_get_id_uuid (block);
+ }
+
+ /* NOTE: UTF-8 has the nice property that valid UTF-8 strings only contains
+ * the byte 0x2F if it's for the '/' character (U+002F SOLIDUS).
+ *
+ * See http://en.wikipedia.org/wiki/UTF-8 for details.
+ */
+
+ if (label != NULL && strlen (label) > 0)
+ {
+ str = g_string_new ("/media/");
+ s = ensure_utf8 (label);
+ for (n = 0; s[n] != '\0'; n++)
+ {
+ gint c = s[n];
+ if (c == '/')
+ g_string_append_c (str, '_');
+ else
+ g_string_append_c (str, c);
+ }
+ mount_point = g_string_free (str, FALSE);
+ g_free (s);
+ }
+ else if (uuid != NULL && strlen (uuid) > 0)
+ {
+ str = g_string_new ("/media/");
+ s = ensure_utf8 (uuid);
+ for (n = 0; s[n] != '\0'; n++)
+ {
+ gint c = s[n];
+ if (c == '/')
+ g_string_append_c (str, '_');
+ else
+ g_string_append_c (str, c);
+ }
+ mount_point = g_string_free (str, FALSE);
+ g_free (s);
+ }
+ else
+ {
+ mount_point = g_strdup ("/media/disk");
+ }
+
+ /* ... then uniqify the mount point */
+ orig_mount_point = g_strdup (mount_point);
+ n = 1;
+ while (TRUE)
+ {
+ if (!g_file_test (mount_point, G_FILE_TEST_EXISTS))
+ {
+ break;
+ }
+ else
+ {
+ g_free (mount_point);
+ mount_point = g_strdup_printf ("%s%d", orig_mount_point, n++);
+ }
+ }
+ g_free (orig_mount_point);
+
+ return mount_point;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/* runs in thread dedicated to handling method call */
+static gboolean
+handle_mount (UDisksBlockDevice *block,
+ GDBusMethodInvocation *invocation,
+ const gchar *requested_fs_type,
+ const gchar* const *requested_options)
+{
+ GDBusObject *object;
+ UDisksDaemon *daemon;
+ UDisksPersistentStore *store;
+ gboolean ret;
+ uid_t caller_uid;
+ const gchar * const *existing_mount_points;
+ const gchar *probed_fs_usage;
+ const gchar *probed_fs_type;
+ gchar *fs_type_to_use;
+ gchar *mount_options_to_use;
+ gchar *mount_point_to_use;
+ gchar *escaped_fs_type_to_use;
+ gchar *escaped_mount_options_to_use;
+ gchar *escaped_mount_point_to_use;
+ gchar *error_message;
+ GError *error;
+ PolkitSubject *auth_subject;
+ const gchar *auth_action_id;
+ PolkitDetails *auth_details;
+ gboolean auth_no_user_interaction;
+ PolkitCheckAuthorizationFlags auth_flags;
+ PolkitAuthorizationResult *auth_result;
+
+ ret = FALSE;
+ object = NULL;
+ daemon = NULL;
+ error_message = NULL;
+ fs_type_to_use = NULL;
+ mount_options_to_use = NULL;
+ mount_point_to_use = NULL;
+ escaped_fs_type_to_use = NULL;
+ escaped_mount_options_to_use = NULL;
+ escaped_mount_point_to_use = NULL;
+ auth_subject = NULL;
+ auth_details = NULL;
+ auth_result = NULL;
+ auth_no_user_interaction = FALSE;
+
+ object = g_dbus_interface_get_object (G_DBUS_INTERFACE (block));
+ daemon = udisks_linux_block_get_daemon (UDISKS_LINUX_BLOCK (object));
+ store = udisks_daemon_get_persistent_store (daemon);
+
+ /* TODO: check if mount point is managed by e.g. /etc/fstab or
+ * similar - if so, use that instead of managing mount points
+ * in /media
+ */
+
+ /* Fail if the device is already mounted */
+ existing_mount_points = udisks_block_device_get_filesystem_mount_points (block);
+ if (existing_mount_points != NULL && g_strv_length ((gchar **) existing_mount_points) > 0)
+ {
+ GString *str;
+ guint n;
+ str = g_string_new (NULL);
+ for (n = 0; existing_mount_points[n] != NULL; n++)
+ {
+ if (n > 0)
+ g_string_append (str, ", ");
+ g_string_append_printf (str, "`%s'", existing_mount_points[n]);
+ }
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_ALREADY_MOUNTED,
+ "Device %s is already mounted at %s.\n",
+ udisks_block_device_get_device (block),
+ str->str);
+ g_string_free (str, TRUE);
+ goto out;
+ }
+
+ /* Fail if the device is not mountable - we actually allow mounting
+ * devices that are not probed since since it could be that we just
+ * don't have the data in the udev database but the device has a
+ * filesystem *anyway*...
+ *
+ * For example, this applies to PC floppy devices - automatically
+ * probing for media them creates annoying noise. So they won't
+ * appear in the udev database.
+ */
+ probed_fs_usage = NULL;
+ probed_fs_type = NULL;
+ if (block != NULL)
+ {
+ probed_fs_usage = udisks_block_device_get_id_usage (block);
+ probed_fs_type = udisks_block_device_get_id_type (block);
+ }
+ if (probed_fs_usage != NULL && strlen (probed_fs_usage) > 0 &&
+ g_strcmp0 (probed_fs_usage, "filesystem") != 0)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Cannot mount block device %s with probed usage `%s' - expected `filesystem'",
+ udisks_block_device_get_device (block),
+ probed_fs_usage);
+ goto out;
+ }
+
+ /* we need the uid of the caller to check mount options */
+ error = NULL;
+ if (!get_uid_sync (invocation, NULL /* GCancellable */, &caller_uid, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* calculate filesystem type (guaranteed to be valid UTF-8) */
+ error = NULL;
+ fs_type_to_use = calculate_fs_type (block,
+ requested_fs_type,
+ &error);
+ if (fs_type_to_use == NULL)
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* calculate mount options (guaranteed to be valid UTF-8) */
+ error = NULL;
+ mount_options_to_use = calculate_mount_options (block,
+ caller_uid,
+ fs_type_to_use,
+ requested_options,
+ &auth_no_user_interaction,
+ &error);
+ if (mount_options_to_use == NULL)
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* calculate mount point (guaranteed to be valid UTF-8) */
+ error = NULL;
+ mount_point_to_use = calculate_mount_point (block,
+ fs_type_to_use,
+ &error);
+ if (mount_point_to_use == NULL)
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* now check that the user is actually authorized to mount the device
+ *
+ * (TODO: fill in details and pick the right action_id)
+ */
+ auth_action_id = "org.freedesktop.udisks2.filesystem-mount",
+ auth_subject = polkit_system_bus_name_new (g_dbus_method_invocation_get_sender (invocation));
+ auth_flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE;
+ if (!auth_no_user_interaction)
+ auth_flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION;
+ error = NULL;
+ auth_result = polkit_authority_check_authorization_sync (udisks_daemon_get_authority (daemon),
+ auth_subject,
+ auth_action_id,
+ auth_details,
+ auth_flags,
+ NULL, /* GCancellable* */
+ &error);
+ if (auth_result == NULL)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error checking authorization: %s (%s, %d)",
+ error->message,
+ g_quark_to_string (error->domain),
+ error->code);
+ g_error_free (error);
+ goto out;
+ }
+ if (!polkit_authorization_result_get_is_authorized (auth_result))
+ {
+ g_dbus_method_invocation_return_error_literal (invocation,
+ UDISKS_ERROR,
+ polkit_authorization_result_get_is_challenge (auth_result) ?
+ UDISKS_ERROR_NOT_AUTHORIZED_CAN_OBTAIN :
+ UDISKS_ERROR_NOT_AUTHORIZED,
+ "Not authorized to perform operation");
+ goto out;
+ }
+
+ /* create the mount point */
+ if (g_mkdir (mount_point_to_use, 0700) != 0)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error creating mount point `%s': %m",
+ mount_point_to_use);
+ goto out;
+ }
+
+ /* update the mounted-fs file */
+ if (!udisks_persistent_store_mounted_fs_add (store,
+ udisks_block_device_get_device (block),
+ mount_point_to_use,
+ caller_uid,
+ &error))
+ goto out;
+
+ escaped_fs_type_to_use = g_strescape (fs_type_to_use, NULL);
+ escaped_mount_options_to_use = g_strescape (mount_options_to_use, NULL);
+ escaped_mount_point_to_use = g_strescape (mount_point_to_use, NULL);
+
+ /* run mount(8) */
+ if (!udisks_daemon_launch_spawned_job_sync (daemon,
+ NULL, /* GCancellable */
+ &error_message,
+ NULL, /* input_string */
+ "mount -t \"%s\" -o \"%s\" \"%s\" \"%s\"",
+ escaped_fs_type_to_use,
+ escaped_mount_options_to_use,
+ udisks_block_device_get_device (block),
+ escaped_mount_point_to_use))
+ {
+ /* ugh, something went wrong.. we need to clean up the created mount point
+ * and also remove the entry from our mounted-fs file
+ *
+ * Either of these operations shouldn't really fail...
+ */
+ error = NULL;
+ if (!udisks_persistent_store_mounted_fs_remove (store,
+ mount_point_to_use,
+ &error))
+ {
+ udisks_daemon_log (daemon,
+ UDISKS_LOG_LEVEL_WARNING,
+ "Error removing mount point %s from filesystems file: %s (%s, %d)",
+ mount_point_to_use,
+ error->message,
+ g_quark_to_string (error->domain),
+ error->code);
+ g_error_free (error);
+ }
+ if (g_rmdir (mount_point_to_use) != 0)
+ {
+ udisks_daemon_log (daemon,
+ UDISKS_LOG_LEVEL_WARNING,
+ "Error removing directory %s: %m",
+ mount_point_to_use);
+ }
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error mounting %s at %s: %s",
+ udisks_block_device_get_device (block),
+ mount_point_to_use,
+ error_message);
+ goto out;
+ }
+
+ udisks_daemon_log (daemon,
+ UDISKS_LOG_LEVEL_INFO,
+ "Mounted %s at %s on behalf of uid %d",
+ udisks_block_device_get_device (block),
+ mount_point_to_use,
+ caller_uid);
+
+ udisks_block_device_complete_filesystem_mount (block, invocation, mount_point_to_use);
+
+ out:
+ if (auth_subject != NULL)
+ g_object_unref (auth_subject);
+ if (auth_details != NULL)
+ g_object_unref (auth_details);
+ if (auth_result != NULL)
+ g_object_unref (auth_result);
+ g_free (error_message);
+ g_free (escaped_fs_type_to_use);
+ g_free (escaped_mount_options_to_use);
+ g_free (escaped_mount_point_to_use);
+ g_free (fs_type_to_use);
+ g_free (mount_options_to_use);
+ g_free (mount_point_to_use);
+ if (object != NULL)
+ g_object_unref (object);
+
+ return TRUE; /* returning TRUE means that we handled the method invocation */
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/* runs in thread dedicated to handling method call */
+static gboolean
+handle_unmount (UDisksBlockDevice *block,
+ GDBusMethodInvocation *invocation,
+ const gchar* const *options)
+{
+ GDBusObject *object;
+ UDisksDaemon *daemon;
+ UDisksPersistentStore *store;
+ gchar *mount_point;
+ gchar *escaped_mount_point;
+ GError *error;
+ uid_t mounted_by_uid;
+ uid_t caller_uid;
+ gchar *error_message;
+ const gchar *const *mount_points;
+ guint n;
+ gboolean opt_force;
+ gboolean rc;
+
+ mount_point = NULL;
+ escaped_mount_point = NULL;
+ error_message = NULL;
+ opt_force = FALSE;
+
+ object = g_dbus_interface_get_object (G_DBUS_INTERFACE (block));
+ daemon = udisks_linux_block_get_daemon (UDISKS_LINUX_BLOCK (object));
+ store = udisks_daemon_get_persistent_store (daemon);
+
+ for (n = 0; options != NULL && options[n] != NULL; n++)
+ {
+ const gchar *option = options[n];
+ if (g_strcmp0 (option, "force") == 0)
+ {
+ opt_force = TRUE;
+ }
+ else
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_OPTION_NOT_PERMITTED,
+ "Unsupported option `%s'",
+ option);
+ goto out;
+ }
+ }
+
+ mount_points = udisks_block_device_get_filesystem_mount_points (block);
+ if (mount_points == NULL || g_strv_length ((gchar **) mount_points) == 0)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_NOT_MOUNTED,
+ "Device `%s' is not mounted",
+ udisks_block_device_get_device (block));
+ goto out;
+ }
+
+ error = NULL;
+ mount_point = udisks_persistent_store_mounted_fs_find (store,
+ udisks_block_device_get_device (block),
+ &mounted_by_uid,
+ &error);
+ if (error != NULL)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error when looking for entry `%s' in mounted-fs: %s (%s, %d)",
+ udisks_block_device_get_device (block),
+ error->message,
+ g_quark_to_string (error->domain),
+ error->code);
+ g_error_free (error);
+ goto out;
+ }
+ if (mount_point == NULL)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Entry for `%s' not found in mounted-fs",
+ udisks_block_device_get_device (block));
+ goto out;
+ }
+
+ /* TODO: allow unmounting stuff not in the mounted-fs file? */
+
+ error = NULL;
+ if (!get_uid_sync (invocation, NULL, &caller_uid, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_error_free (error);
+ goto out;
+ }
+
+ if (caller_uid != 0 && (caller_uid != mounted_by_uid))
+ {
+ /* TODO: allow with special authorization (unmount-others) */
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_MOUNTED_BY_OTHER_USER,
+ "Cannot unmount filesystem at `%s' mounted by other user with uid %d",
+ mount_point,
+ mounted_by_uid);
+ goto out;
+ }
+
+ /* otherwise go ahead and unmount the filesystem */
+ if (!udisks_persistent_store_mounted_fs_currently_unmounting_add (store, mount_point))
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_ALREADY_UNMOUNTING,
+ "Cannot unmount %s: Mount point `%s' is currently being unmounted",
+ udisks_block_device_get_device (block),
+ mount_point);
+ goto out;
+ }
+
+ escaped_mount_point = g_strescape (mount_point, NULL);
+ if (opt_force)
+ {
+ /* right now -l is the only way to "force unmount" file systems... */
+ rc = udisks_daemon_launch_spawned_job_sync (daemon,
+ NULL, /* GCancellable */
+ &error_message,
+ NULL, /* input_string */
+ "umount -l \"%s\"",
+ escaped_mount_point);
+ }
+ else
+ {
+ rc = udisks_daemon_launch_spawned_job_sync (daemon,
+ NULL, /* GCancellable */
+ &error_message,
+ NULL, /* input_string */
+ "umount \"%s\"",
+ escaped_mount_point);
+ }
+ if (!rc)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error unmounting %s from %s: %s",
+ udisks_block_device_get_device (block),
+ mount_point,
+ error_message);
+ udisks_persistent_store_mounted_fs_currently_unmounting_remove (store, mount_point);
+ goto out;
+ }
+
+ /* OK, filesystem unmounted.. now to remove the entry from mounted-fs as well as the mount point */
+ error = NULL;
+ if (!udisks_persistent_store_mounted_fs_remove (store,
+ mount_point,
+ &error))
+ {
+ if (error == NULL)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error removing entry for `%s' from mounted-fs: Entry not found",
+ mount_point);
+ }
+ else
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error removing entry for `%s' from mounted-fs: %s (%s, %d)",
+ mount_point,
+ error->message,
+ g_quark_to_string (error->domain),
+ error->code);
+ g_error_free (error);
+ }
+ udisks_persistent_store_mounted_fs_currently_unmounting_remove (store, mount_point);
+ goto out;
+ }
+ udisks_persistent_store_mounted_fs_currently_unmounting_remove (store, mount_point);
+
+ /* OK, removed the entry. Finally: nuke the mount point */
+ if (g_rmdir (mount_point) != 0)
+ {
+ udisks_daemon_log (daemon,
+ UDISKS_LOG_LEVEL_ERROR,
+ "Error removing mount point `%s': %m",
+ mount_point);
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error removing mount point `%s': %m",
+ mount_point);
+ goto out;
+ }
+
+ udisks_daemon_log (daemon,
+ UDISKS_LOG_LEVEL_INFO,
+ "Unmounted %s from %s on behalf of uid %d",
+ udisks_block_device_get_device (block),
+ mount_point,
+ caller_uid);
+
+ udisks_block_device_complete_filesystem_unmount (block, invocation);
+
+ out:
+ g_free (error_message);
+ g_free (escaped_mount_point);
+ g_free (mount_point);
+ g_object_unref (object);
+ return TRUE;
+}
diff --git a/tools/udisksctl.c b/tools/udisksctl.c
index c1a859e..8be94bc 100644
--- a/tools/udisksctl.c
+++ b/tools/udisksctl.c
@@ -570,8 +570,8 @@ handle_command_mount_unmount (gint *argc,
GList *object_proxies;
GDBusObjectProxy *object_proxy;
UDisksBlockDevice *block;
- UDisksFilesystem *filesystem;
guint n;
+ const gchar * const *mount_points;
ret = 1;
opt_mount_unmount_object_path = NULL;
@@ -637,17 +637,16 @@ handle_command_mount_unmount (gint *argc,
object_proxies = g_dbus_proxy_manager_get_all (manager);
for (l = object_proxies; l != NULL; l = l->next)
{
- const gchar * const *mount_points;
gboolean is_mounted;
object_proxy = G_DBUS_OBJECT_PROXY (l->data);
- filesystem = UDISKS_PEEK_FILESYSTEM (object_proxy);
+ block = UDISKS_PEEK_BLOCK_DEVICE (object_proxy);
- if (filesystem == NULL)
+ if (block == NULL)
continue;
is_mounted = FALSE;
- mount_points = udisks_filesystem_get_mount_points (filesystem);
+ mount_points = udisks_block_device_get_filesystem_mount_points (block);
if (mount_points != NULL && g_strv_length ((gchar **) mount_points) > 0)
is_mounted = TRUE;
@@ -670,15 +669,13 @@ handle_command_mount_unmount (gint *argc,
{
object_proxy = G_DBUS_OBJECT_PROXY (l->data);
block = UDISKS_PEEK_BLOCK_DEVICE (object_proxy);
- filesystem = UDISKS_PEEK_FILESYSTEM (object_proxy);
- if (block != NULL && filesystem != NULL)
+ if (block != NULL)
{
- const gchar * const *mount_points;
gboolean is_mounted;
is_mounted = FALSE;
- mount_points = udisks_filesystem_get_mount_points (filesystem);
+ mount_points = udisks_block_device_get_filesystem_mount_points (block);
if (mount_points != NULL && g_strv_length ((gchar **) mount_points) > 0)
is_mounted = TRUE;
@@ -735,8 +732,9 @@ handle_command_mount_unmount (gint *argc,
goto out;
}
- filesystem = UDISKS_PEEK_FILESYSTEM (object_proxy);
- if (filesystem == NULL)
+ mount_points = udisks_block_device_get_filesystem_mount_points (block);
+ if (g_strv_length ((gchar **) mount_points) == 0 &&
+ g_strcmp0 (udisks_block_device_get_id_usage (block), "filesystem") != 0)
{
g_printerr ("Device %s is not a filesystem.\n", udisks_block_device_get_device (block));
g_object_unref (object_proxy);
@@ -755,12 +753,12 @@ handle_command_mount_unmount (gint *argc,
gchar *mount_path;
error = NULL;
- if (!udisks_filesystem_call_mount_sync (filesystem,
- opt_mount_filesystem_type,
- (const gchar *const *) opt_mount_unmount_options,
- &mount_path,
- NULL, /* GCancellable */
- &error))
+ if (!udisks_block_device_call_filesystem_mount_sync (block,
+ opt_mount_filesystem_type,
+ (const gchar *const *) opt_mount_unmount_options,
+ &mount_path,
+ NULL, /* GCancellable */
+ &error))
{
if (error->domain == UDISKS_ERROR &&
error->code == UDISKS_ERROR_NOT_AUTHORIZED_CAN_OBTAIN &&
@@ -786,10 +784,10 @@ handle_command_mount_unmount (gint *argc,
GError *error;
error = NULL;
- if (!udisks_filesystem_call_unmount_sync (filesystem,
- (const gchar *const *) opt_mount_unmount_options,
- NULL, /* GCancellable */
- &error))
+ if (!udisks_block_device_call_filesystem_unmount_sync (block,
+ (const gchar *const *) opt_mount_unmount_options,
+ NULL, /* GCancellable */
+ &error))
{
if (error->domain == UDISKS_ERROR &&
error->code == UDISKS_ERROR_NOT_AUTHORIZED_CAN_OBTAIN &&
diff --git a/tools/umount-udisks.c b/tools/umount-udisks.c
index 797210f..1c369f4 100644
--- a/tools/umount-udisks.c
+++ b/tools/umount-udisks.c
@@ -27,6 +27,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <string.h>
#include <udisks/udisks.h>
@@ -89,14 +90,14 @@ main (int argc, char *argv[])
GError *error;
struct stat statbuf;
GDBusObjectProxy *object_proxy;
- UDisksFilesystem *filesystem;
+ UDisksBlockDevice *block;
const gchar *unmount_options[1] = {NULL};
ret = 1;
manager = NULL;
block_device_file = NULL;
object_proxy = NULL;
- filesystem = NULL;
+ block = NULL;
g_type_init ();
@@ -142,18 +143,13 @@ main (int argc, char *argv[])
goto out;
}
- filesystem = UDISKS_GET_FILESYSTEM (object_proxy);
- if (filesystem == NULL)
- {
- g_printerr ("Object for block device file %s does not appear to be a file system\n", block_device_file);
- goto out;
- }
+ block = UDISKS_PEEK_BLOCK_DEVICE (object_proxy);
error = NULL;
- if (!udisks_filesystem_call_unmount_sync (filesystem,
- unmount_options,
- NULL, /* GCancellable */
- &error))
+ if (!udisks_block_device_call_filesystem_unmount_sync (block,
+ unmount_options,
+ NULL, /* GCancellable */
+ &error))
{
g_printerr ("Error unmounting %s: %s\n", block_device_file, error->message);
g_error_free (error);
@@ -163,8 +159,6 @@ main (int argc, char *argv[])
ret = 0;
out:
- if (filesystem != NULL)
- g_object_unref (filesystem);
if (object_proxy != NULL)
g_object_unref (object_proxy);
g_free (block_device_file);