From cde3c42fbd61825a56a41fe3af0eb51bf0cfc065 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Mon, 25 Oct 2010 13:32:28 -0400 Subject: [PATCH] Check with polkit whether the user is authorized to mount the device Also make the udisks program accept mount/unmount options and the desired file system type. Signed-off-by: David Zeuthen --- doc/udisks-sections.txt.in | 1 + src/types.h | 1 + src/udisksdaemon.c | 30 ++++++ src/udisksdaemon.h | 1 + src/udisksfilesystemimpl.c | 230 ++++++++++++++++++++++++++++++++++++++------- src/udiskslinuxblock.c | 65 ++++++++++++- tools/udisks.c | 123 +++++++++++++++++++----- 7 files changed, 394 insertions(+), 57 deletions(-) diff --git a/doc/udisks-sections.txt.in b/doc/udisks-sections.txt.in index 7ac03b9..07b6143 100644 --- a/doc/udisks-sections.txt.in +++ b/doc/udisks-sections.txt.in @@ -9,6 +9,7 @@ udisks_daemon_get_mount_monitor udisks_daemon_get_linux_provider udisks_daemon_get_fstab_provider udisks_daemon_get_persistent_store +udisks_daemon_get_authority udisks_daemon_launch_simple_job udisks_daemon_launch_spawned_job udisks_daemon_launch_spawned_job_sync diff --git a/src/types.h b/src/types.h index 9257f86..eab52bf 100644 --- a/src/types.h +++ b/src/types.h @@ -22,6 +22,7 @@ #define __TYPES_H__ #include +#include #include #include diff --git a/src/udisksdaemon.c b/src/udisksdaemon.c index 7daf6b3..db21122 100644 --- a/src/udisksdaemon.c +++ b/src/udisksdaemon.c @@ -62,6 +62,8 @@ struct _UDisksDaemon UDisksLinuxProvider *linux_provider; UDisksFstabProvider *fstab_provider; + + PolkitAuthority *authority; }; struct _UDisksDaemonClass @@ -84,6 +86,7 @@ udisks_daemon_finalize (GObject *object) { UDisksDaemon *daemon = UDISKS_DAEMON (object); + g_object_unref (daemon->authority); g_object_unref (daemon->persistent_store); g_object_unref (daemon->fstab_provider); g_object_unref (daemon->object_manager); @@ -164,6 +167,18 @@ static void udisks_daemon_constructed (GObject *object) { UDisksDaemon *daemon = UDISKS_DAEMON (object); + GError *error; + + error = NULL; + daemon->authority = polkit_authority_get_sync (NULL, &error); + if (daemon->authority == NULL) + { + g_warning ("Error initializing PolicyKit authority: %s (%s, %d)", + error->message, + g_quark_to_string (error->domain), + error->code); + g_error_free (error); + } daemon->object_manager = g_dbus_object_manager_new (daemon->connection, "/org/freedesktop/UDisks"); @@ -367,6 +382,21 @@ udisks_daemon_get_persistent_store (UDisksDaemon *daemon) return daemon->persistent_store; } +/** + * udisks_daemon_get_authority: + * @daemon: A #UDisksDaemon. + * + * Gets the PolicyKit authority used by @daemon. + * + * Returns: A #PolkitAuthority instance. Do not free, the object is owned by @daemon. + */ +PolkitAuthority * +udisks_daemon_get_authority (UDisksDaemon *daemon) +{ + g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL); + return daemon->authority; +} + /* ---------------------------------------------------------------------------------------------------- */ static void diff --git a/src/udisksdaemon.h b/src/udisksdaemon.h index c2bd2e0..dd0ae1c 100644 --- a/src/udisksdaemon.h +++ b/src/udisksdaemon.h @@ -37,6 +37,7 @@ UDisksMountMonitor *udisks_daemon_get_mount_monitor (UDisksDaemon *dae UDisksLinuxProvider *udisks_daemon_get_linux_provider (UDisksDaemon *daemon); UDisksFstabProvider *udisks_daemon_get_fstab_provider (UDisksDaemon *daemon); UDisksPersistentStore *udisks_daemon_get_persistent_store (UDisksDaemon *daemon); +PolkitAuthority *udisks_daemon_get_authority (UDisksDaemon *daemon); UDisksBaseJob *udisks_daemon_launch_simple_job (UDisksDaemon *daemon, GCancellable *cancellable); UDisksBaseJob *udisks_daemon_launch_spawned_job (UDisksDaemon *daemon, diff --git a/src/udisksfilesystemimpl.c b/src/udisksfilesystemimpl.c index 5c1961d..19a6c5d 100644 --- a/src/udisksfilesystemimpl.c +++ b/src/udisksfilesystemimpl.c @@ -444,7 +444,7 @@ prepend_default_mount_options (const FSMountOptions *fsmo, * * Calculates the file system type to use. * - * Returns: A string with the filesystem type (may be "auto") or %NULL if @error is set. Free with g_free(). + * 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, @@ -478,6 +478,8 @@ calculate_fs_type (UDisksBlockDevice *block, 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; } @@ -488,6 +490,7 @@ calculate_fs_type (UDisksBlockDevice *block, * @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 @@ -501,6 +504,7 @@ 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; @@ -508,9 +512,11 @@ calculate_mount_options (UDisksBlockDevice *block, 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); @@ -525,6 +531,12 @@ calculate_mount_options (UDisksBlockDevice *block, { 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) { @@ -556,11 +568,43 @@ calculate_mount_options (UDisksBlockDevice *block, 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: * @block: A #UDisksBlockDevice. @@ -570,7 +614,7 @@ calculate_mount_options (UDisksBlockDevice *block, * * Calculates the mount point to use. * - * Returns: A string with the mount point to use or %NULL if @error is set. Free with g_free(). + * 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, @@ -583,6 +627,7 @@ calculate_mount_point (UDisksBlockDevice *block, gchar *mount_point; gchar *orig_mount_point; GString *str; + gchar *s; guint n; label = NULL; @@ -593,31 +638,41 @@ calculate_mount_point (UDisksBlockDevice *block, 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/"); - for (n = 0; label[n] != '\0'; n++) + s = ensure_utf8 (label); + for (n = 0; s[n] != '\0'; n++) { - gint c = label[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/"); - for (n = 0; uuid[n] != '\0'; n++) + s = ensure_utf8 (uuid); + for (n = 0; s[n] != '\0'; n++) { - gint c = uuid[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 { @@ -657,7 +712,6 @@ handle_mount (UDisksFilesystem *filesystem, UDisksDaemon *daemon; UDisksPersistentStore *store; gboolean ret; - gchar *mount_point_to_use; uid_t caller_uid; UDisksBlockDevice *block; UDisksBlockDeviceProbed *block_probed; @@ -667,18 +721,35 @@ handle_mount (UDisksFilesystem *filesystem, 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; - error_message = 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.UDisks.BlockDevice")); @@ -693,9 +764,6 @@ handle_mount (UDisksFilesystem *filesystem, * in /media */ - /* TODO: check authorization */ - - /* 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) @@ -756,7 +824,7 @@ handle_mount (UDisksFilesystem *filesystem, goto out; } - /* calculate filesystem type */ + /* calculate filesystem type (guaranteed to be valid UTF-8) */ error = NULL; fs_type_to_use = calculate_fs_type (block, block_probed, @@ -769,13 +837,14 @@ handle_mount (UDisksFilesystem *filesystem, goto out; } - /* calculate mount options */ + /* 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) { @@ -784,7 +853,7 @@ handle_mount (UDisksFilesystem *filesystem, goto out; } - /* calculate mount point */ + /* calculate mount point (guaranteed to be valid UTF-8) */ error = NULL; mount_point_to_use = calculate_mount_point (block, block_probed, @@ -797,7 +866,43 @@ handle_mount (UDisksFilesystem *filesystem, goto out; } - /* TODO: ensure that mount point is UTF-8 .. */ + /* 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.udisks.filesystem-mount-system-internal", + 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, + UDISKS_ERROR_FAILED, + "Not authorized"); + goto out; + } /* create the mount point */ if (g_mkdir (mount_point_to_use, 0700) != 0) @@ -818,17 +923,20 @@ handle_mount (UDisksFilesystem *filesystem, &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\"", - /* TODO: ensure that passed args does not have double-quotes in them... */ - fs_type_to_use, - mount_options_to_use, + escaped_fs_type_to_use, + escaped_mount_options_to_use, udisks_block_device_get_device (block), - mount_point_to_use)) + 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 @@ -840,16 +948,21 @@ handle_mount (UDisksFilesystem *filesystem, mount_point_to_use, &error)) { - g_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); + 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) { - g_warning ("Error removing directory %s: %m", mount_point_to_use); + 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, @@ -871,10 +984,19 @@ handle_mount (UDisksFilesystem *filesystem, 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 (mount_point_to_use); - g_free (mount_options_to_use); + 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) @@ -898,20 +1020,44 @@ handle_unmount (UDisksFilesystem *filesystem, 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.UDisks.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_FAILED, + "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) { @@ -920,7 +1066,6 @@ handle_unmount (UDisksFilesystem *filesystem, UDISKS_ERROR_FAILED, "Device `%s' is not mounted", udisks_block_device_get_device (block)); - g_error_free (error); goto out; } @@ -985,12 +1130,28 @@ handle_unmount (UDisksFilesystem *filesystem, mount_point); goto out; } - if (!udisks_daemon_launch_spawned_job_sync (daemon, - NULL, /* GCancellable */ - &error_message, - NULL, /* input_string */ - "umount \"%s\"", - mount_point)) + + 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, @@ -1060,6 +1221,7 @@ handle_unmount (UDisksFilesystem *filesystem, out: g_free (error_message); + g_free (escaped_mount_point); g_free (mount_point); g_object_unref (block); g_object_unref (object); diff --git a/src/udiskslinuxblock.c b/src/udiskslinuxblock.c index 6ef48f1..03e32cd 100644 --- a/src/udiskslinuxblock.c +++ b/src/udiskslinuxblock.c @@ -447,6 +447,60 @@ block_device_update (UDisksLinuxBlock *block, /* ---------------------------------------------------------------------------------------------------- */ /* org.freedesktop.UDisks.BlockDeviceProbed */ +/* Unescapes sequences like \x20 to " " and ensures the returned string is valid UTF-8. + * + * If the string is not valid UTF-8, return as much as possible and complain on stderr. + * + * See udev_util_encode_string() in libudev/libudev-util.c in the udev + * tree for the encoder. + */ +static gchar * +decode_udev_encoded_string (const gchar *str) +{ + GString *s; + gchar *ret; + const gchar *end_valid; + guint n; + + s = g_string_new (NULL); + for (n = 0; str[n] != '\0'; n++) + { + if (str[n] == '\\') + { + gint val; + + if (str[n + 1] != 'x' || str[n + 2] == '\0' || str[n + 3] == '\0') + { + g_warning ("**** NOTE: malformed encoded string `%s'", str); + break; + } + + val = (g_ascii_xdigit_value (str[n + 2]) << 4) | g_ascii_xdigit_value (str[n + 3]); + + g_string_append_c (s, val); + + n += 3; + } + else + { + g_string_append_c (s, str[n]); + } + } + + if (!g_utf8_validate (s->str, -1, &end_valid)) + { + g_warning ("The string `%s' is not valid UTF-8. Invalid characters begins at `%s'", s->str, end_valid); + ret = g_strndup (s->str, end_valid - s->str); + g_string_free (s, TRUE); + } + else + { + ret = g_string_free (s, FALSE); + } + + return ret; +} + static gboolean block_device_probed_check (UDisksLinuxBlock *block) { @@ -459,12 +513,19 @@ block_device_probed_update (UDisksLinuxBlock *block, 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_probed_set_label (iface, g_udev_device_get_property (block->device, "ID_FS_LABEL_ENC")); - udisks_block_device_probed_set_uuid (iface, g_udev_device_get_property (block->device, "ID_FS_UUID_ENC")); + + s = decode_udev_encoded_string (g_udev_device_get_property (block->device, "ID_FS_LABEL_ENC")); + udisks_block_device_probed_set_label (iface, s); + g_free (s); + + s = decode_udev_encoded_string (g_udev_device_get_property (block->device, "ID_FS_UUID_ENC")); + udisks_block_device_probed_set_uuid (iface, s); + g_free (s); } /* ---------------------------------------------------------------------------------------------------- */ diff --git a/tools/udisks.c b/tools/udisks.c index cb23f0b..394d4f4 100644 --- a/tools/udisks.c +++ b/tools/udisks.c @@ -358,14 +358,86 @@ lookup_object_proxy_by_device (const gchar *device) /* ---------------------------------------------------------------------------------------------------- */ -static gchar *opt_mount_unmount_object = NULL; -static gchar *opt_mount_unmount_device = NULL; +static gchar *opt_mount_unmount_object_path = NULL; +static gchar *opt_mount_unmount_device = NULL; +static gchar **opt_mount_unmount_options = NULL; +static gchar *opt_mount_filesystem_type = NULL; -static const GOptionEntry command_mount_unmount_entries[] = +static const GOptionEntry command_mount_entries[] = { - { "object", 'o', 0, G_OPTION_ARG_STRING, &opt_mount_unmount_object, "Object to get perform operation on", NULL}, - { "block-device", 'b', 0, G_OPTION_ARG_STRING, &opt_mount_unmount_device, "Block device to perform operation on", NULL}, - { NULL } + { + "object-path", + 'p', + 0, + G_OPTION_ARG_STRING, + &opt_mount_unmount_object_path, + "Object to mount", + NULL + }, + { + "block-device", + 'b', + 0, + G_OPTION_ARG_STRING, + &opt_mount_unmount_device, + "Block device to mount", + NULL + }, + { + "filesystem-type", + 't', + 0, + G_OPTION_ARG_STRING, + &opt_mount_filesystem_type, + "Filesystem type to use", + NULL + }, + { + "option", + 'o', + 0, + G_OPTION_ARG_STRING_ARRAY, + &opt_mount_unmount_options, + "Mount option (can be used several times)", + NULL + }, + { + NULL + } +}; + +static const GOptionEntry command_unmount_entries[] = +{ + { + "object-path", + 'p', + 0, + G_OPTION_ARG_STRING, + &opt_mount_unmount_object_path, + "Object to unmount", + NULL + }, + { + "block-device", + 'b', + 0, + G_OPTION_ARG_STRING, + &opt_mount_unmount_device, + "Block device to unmount", + NULL + }, + { + "option", + 'o', + 0, + G_OPTION_ARG_STRING_ARRAY, + &opt_mount_unmount_options, + "Unmount option (can be used several times)", + NULL + }, + { + NULL + } }; /* TODO: make 'mount' and 'unmount' take options? Probably... */ @@ -391,8 +463,10 @@ handle_command_mount_unmount (gint *argc, guint n; ret = 1; - opt_mount_unmount_object = NULL; + opt_mount_unmount_object_path = NULL; opt_mount_unmount_device = NULL; + opt_mount_unmount_options = NULL; + opt_mount_filesystem_type = NULL; object_proxy = NULL; if (is_mount) @@ -408,10 +482,12 @@ handle_command_mount_unmount (gint *argc, g_option_context_set_summary (o, "Mount a device."); else g_option_context_set_summary (o, "Unmount a device."); - g_option_context_add_main_entries (o, command_mount_unmount_entries, NULL /* GETTEXT_PACKAGE*/); + g_option_context_add_main_entries (o, + is_mount ? command_mount_entries : command_unmount_entries, + NULL /* GETTEXT_PACKAGE*/); complete_objects = FALSE; - if (request_completion && (g_strcmp0 (completion_prev, "--object") == 0 || g_strcmp0 (completion_prev, "-o") == 0)) + if (request_completion && (g_strcmp0 (completion_prev, "--object-path") == 0 || g_strcmp0 (completion_prev, "-p") == 0)) { complete_objects = TRUE; remove_arg ((*argc) - 1, argc, argv); @@ -436,10 +512,10 @@ handle_command_mount_unmount (gint *argc, } if (request_completion && - (opt_mount_unmount_object == NULL && !complete_objects) && + (opt_mount_unmount_object_path == NULL && !complete_objects) && (opt_mount_unmount_device == NULL && !complete_devices)) { - g_print ("--object \n" + g_print ("--object-path \n" "--block-device \n"); } @@ -514,12 +590,12 @@ handle_command_mount_unmount (gint *argc, if (request_completion) goto out; - if (opt_mount_unmount_object != NULL) + if (opt_mount_unmount_object_path != NULL) { - object_proxy = lookup_object_proxy_by_path (opt_mount_unmount_object); + object_proxy = lookup_object_proxy_by_path (opt_mount_unmount_object_path); if (object_proxy == NULL) { - g_printerr ("Error looking up object with path %s\n", opt_mount_unmount_object); + g_printerr ("Error looking up object with path %s\n", opt_mount_unmount_object_path); goto out; } } @@ -556,18 +632,22 @@ handle_command_mount_unmount (gint *argc, goto out; } + if (opt_mount_filesystem_type == NULL) + opt_mount_filesystem_type = g_strdup (""); + if (opt_mount_unmount_options == NULL) + opt_mount_unmount_options = g_new0 (gchar *, 1); + if (is_mount) { GError *error; gchar *mount_path; - const gchar *options[1] = {NULL}; error = NULL; if (!udisks_filesystem_call_mount_sync (filesystem, - "", /* filesystem_type */ - options, /* options */ + opt_mount_filesystem_type, + (const gchar *const *) opt_mount_unmount_options, &mount_path, - NULL, /* GCancellable */ + NULL, /* GCancellable */ &error)) { g_printerr ("Error mounting %s: %s\n", @@ -585,11 +665,10 @@ handle_command_mount_unmount (gint *argc, else { GError *error; - const gchar *options[1] = {NULL}; error = NULL; if (!udisks_filesystem_call_unmount_sync (filesystem, - options, /* options */ + (const gchar *const *) opt_mount_unmount_options, NULL, /* GCancellable */ &error)) { @@ -610,8 +689,10 @@ handle_command_mount_unmount (gint *argc, out: g_option_context_free (o); - g_free (opt_mount_unmount_object); + g_free (opt_mount_unmount_object_path); g_free (opt_mount_unmount_device); + g_strfreev (opt_mount_unmount_options); + g_free (opt_mount_filesystem_type); return ret; } -- 2.7.4