1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
3
* Copyright (C) 2007-2010 David Zeuthen <zeuthen@gmail.com>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
#include <glib/gi18n-lib.h>
24
#include <sys/types.h>
31
#include <sys/types.h>
35
#include <glib/gstdio.h>
37
#include "udiskslogging.h"
38
#include "udiskslinuxfilesystem.h"
39
#include "udiskslinuxblockobject.h"
40
#include "udiskslinuxfsinfo.h"
41
#include "udisksdaemon.h"
42
#include "udisksstate.h"
43
#include "udisksdaemonutil.h"
44
#include "udisksmountmonitor.h"
45
#include "udisksmount.h"
46
#include "udiskslinuxdevice.h"
49
* SECTION:udiskslinuxfilesystem
50
* @title: UDisksLinuxFilesystem
51
* @short_description: Linux implementation of #UDisksFilesystem
53
* This type provides an implementation of the #UDisksFilesystem
57
typedef struct _UDisksLinuxFilesystemClass UDisksLinuxFilesystemClass;
60
* UDisksLinuxFilesystem:
62
* The #UDisksLinuxFilesystem structure contains only private data and should
63
* only be accessed using the provided API.
65
struct _UDisksLinuxFilesystem
67
UDisksFilesystemSkeleton parent_instance;
71
struct _UDisksLinuxFilesystemClass
73
UDisksFilesystemSkeletonClass parent_class;
76
static void filesystem_iface_init (UDisksFilesystemIface *iface);
78
G_DEFINE_TYPE_WITH_CODE (UDisksLinuxFilesystem, udisks_linux_filesystem, UDISKS_TYPE_FILESYSTEM_SKELETON,
79
G_IMPLEMENT_INTERFACE (UDISKS_TYPE_FILESYSTEM, filesystem_iface_init));
81
/* ---------------------------------------------------------------------------------------------------- */
84
udisks_linux_filesystem_finalize (GObject *object)
86
UDisksLinuxFilesystem *filesystem = UDISKS_LINUX_FILESYSTEM (object);
88
g_mutex_clear (&(filesystem->lock));
90
if (G_OBJECT_CLASS (udisks_linux_filesystem_parent_class)->finalize != NULL)
91
G_OBJECT_CLASS (udisks_linux_filesystem_parent_class)->finalize (object);
95
udisks_linux_filesystem_init (UDisksLinuxFilesystem *filesystem)
97
g_mutex_init (&filesystem->lock);
98
g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (filesystem),
99
G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
103
udisks_linux_filesystem_class_init (UDisksLinuxFilesystemClass *klass)
105
GObjectClass *gobject_class;
107
gobject_class = G_OBJECT_CLASS (klass);
108
gobject_class->finalize = udisks_linux_filesystem_finalize;
112
* udisks_linux_filesystem_new:
114
* Creates a new #UDisksLinuxFilesystem instance.
116
* Returns: A new #UDisksLinuxFilesystem. Free with g_object_unref().
119
udisks_linux_filesystem_new (void)
121
return UDISKS_FILESYSTEM (g_object_new (UDISKS_TYPE_LINUX_FILESYSTEM,
125
/* ---------------------------------------------------------------------------------------------------- */
128
* udisks_linux_filesystem_update:
129
* @filesystem: A #UDisksLinuxFilesystem.
130
* @object: The enclosing #UDisksLinuxBlockObject instance.
132
* Updates the interface.
135
udisks_linux_filesystem_update (UDisksLinuxFilesystem *filesystem,
136
UDisksLinuxBlockObject *object)
138
UDisksMountMonitor *mount_monitor;
139
UDisksLinuxDevice *device;
144
mount_monitor = udisks_daemon_get_mount_monitor (udisks_linux_block_object_get_daemon (object));
145
device = udisks_linux_block_object_get_device (object);
147
p = g_ptr_array_new ();
148
mounts = udisks_mount_monitor_get_mounts_for_dev (mount_monitor, g_udev_device_get_device_number (device->udev_device));
149
/* we are guaranteed that the list is sorted so if there are
150
* multiple mounts we'll always get the same order
152
for (l = mounts; l != NULL; l = l->next)
154
UDisksMount *mount = UDISKS_MOUNT (l->data);
155
if (udisks_mount_get_mount_type (mount) == UDISKS_MOUNT_TYPE_FILESYSTEM)
156
g_ptr_array_add (p, (gpointer) udisks_mount_get_mount_path (mount));
158
g_ptr_array_add (p, NULL);
159
udisks_filesystem_set_mount_points (UDISKS_FILESYSTEM (filesystem),
160
(const gchar *const *) p->pdata);
161
g_ptr_array_free (p, TRUE);
162
g_list_foreach (mounts, (GFunc) g_object_unref, NULL);
163
g_list_free (mounts);
164
g_object_unref (device);
167
/* ---------------------------------------------------------------------------------------------------- */
169
static const gchar *well_known_filesystems[] =
191
is_in_filesystem_file (const gchar *filesystems_file,
194
gchar *filesystems = NULL;
195
GError *error = NULL;
196
gboolean ret = FALSE;
197
gchar **lines = NULL;
200
if (!g_file_get_contents (filesystems_file,
202
NULL, /* gsize *out_length */
205
udisks_warning ("Error reading %s: %s (%s %d)",
208
g_quark_to_string (error->domain),
210
g_error_free (error);
214
lines = g_strsplit (filesystems, "\n", -1);
215
for (n = 0; lines != NULL && lines[n] != NULL && !ret; n++)
219
g_strdelimit (lines[n], " \t", ' ');
220
g_strstrip (lines[n]);
221
tokens = g_strsplit (lines[n], " ", -1);
222
num_tokens = g_strv_length (tokens);
223
if (num_tokens == 1 && g_strcmp0 (tokens[0], fstype) == 0)
232
g_free (filesystems);
237
is_well_known_filesystem (const gchar *fstype)
239
gboolean ret = FALSE;
242
for (n = 0; well_known_filesystems[n] != NULL; n++)
244
if (g_strcmp0 (well_known_filesystems[n], fstype) == 0)
254
/* this is not a very efficient implementation but it's very rarely
255
* called so no real point in optimizing it...
258
is_allowed_filesystem (const gchar *fstype)
260
return is_well_known_filesystem (fstype) ||
261
is_in_filesystem_file ("/proc/filesystems", fstype) ||
262
is_in_filesystem_file ("/etc/filesystems", fstype);
265
/* ---------------------------------------------------------------------------------------------------- */
270
const gchar * const *defaults;
271
const gchar * const *allow;
272
const gchar * const *allow_uid_self;
273
const gchar * const *allow_gid_self;
276
/* ---------------------- vfat -------------------- */
278
static const gchar *vfat_defaults[] = { "uid=", "gid=", "shortname=mixed", "dmask=0077", "utf8=1", "showexec", "flush", NULL };
279
static const gchar *vfat_allow[] = { "flush", "utf8=", "shortname=", "umask=", "dmask=", "fmask=", "codepage=", "iocharset=", "usefree", "showexec", NULL };
280
static const gchar *vfat_allow_uid_self[] = { "uid=", NULL };
281
static const gchar *vfat_allow_gid_self[] = { "gid=", NULL };
283
/* ---------------------- ntfs -------------------- */
284
/* this is assuming that ntfs-3g is used */
286
static const gchar *ntfs_defaults[] = { "uid=", "gid=", "dmask=0077", "fmask=0177", NULL };
287
static const gchar *ntfs_allow[] = { "umask=", "dmask=", "fmask=", "locale=", "norecover", "ignore_case", "windows_names", "compression", "nocompression", NULL };
288
static const gchar *ntfs_allow_uid_self[] = { "uid=", NULL };
289
static const gchar *ntfs_allow_gid_self[] = { "gid=", NULL };
291
/* ---------------------- iso9660 -------------------- */
293
static const gchar *iso9660_defaults[] = { "uid=", "gid=", "iocharset=utf8", "mode=0400", "dmode=0500", NULL };
294
static const gchar *iso9660_allow[] = { "norock", "nojoliet", "iocharset=", "mode=", "dmode=", NULL };
295
static const gchar *iso9660_allow_uid_self[] = { "uid=", NULL };
296
static const gchar *iso9660_allow_gid_self[] = { "gid=", NULL };
298
/* ---------------------- udf -------------------- */
300
static const gchar *udf_defaults[] = { "uid=", "gid=", "iocharset=utf8", "umask=0077", NULL };
301
static const gchar *udf_allow[] = { "iocharset=", "umask=", NULL };
302
static const gchar *udf_allow_uid_self[] = { "uid=", NULL };
303
static const gchar *udf_allow_gid_self[] = { "gid=", NULL };
305
/* ---------------------- exfat -------------------- */
307
static const gchar *exfat_defaults[] = { "uid=", "gid=", "iocharset=utf8", "namecase=0", "errors=remount-ro", "umask=0077", NULL };
308
static const gchar *exfat_allow[] = { "dmask=", "errors=", "fmask=", "iocharset=", "namecase=", "umask=", NULL };
309
static const gchar *exfat_allow_uid_self[] = { "uid=", NULL };
310
static const gchar *exfat_allow_gid_self[] = { "gid=", NULL };
312
/* ------------------------------------------------ */
313
/* TODO: support context= */
315
static const gchar *any_allow[] = { "exec", "noexec", "nodev", "nosuid", "atime", "noatime", "nodiratime", "ro", "rw", "sync", "dirsync", NULL };
317
static const FSMountOptions fs_mount_options[] =
319
{ "vfat", vfat_defaults, vfat_allow, vfat_allow_uid_self, vfat_allow_gid_self },
320
{ "ntfs", ntfs_defaults, ntfs_allow, ntfs_allow_uid_self, ntfs_allow_gid_self },
321
{ "iso9660", iso9660_defaults, iso9660_allow, iso9660_allow_uid_self, iso9660_allow_gid_self },
322
{ "udf", udf_defaults, udf_allow, udf_allow_uid_self, udf_allow_gid_self },
323
{ "exfat", exfat_defaults, exfat_allow, exfat_allow_uid_self, exfat_allow_gid_self },
326
/* ------------------------------------------------ */
328
static int num_fs_mount_options = sizeof(fs_mount_options) / sizeof(FSMountOptions);
330
static const FSMountOptions *
331
find_mount_options_for_fs (const gchar *fstype)
334
const FSMountOptions *fsmo;
336
for (n = 0; n < num_fs_mount_options; n++)
338
fsmo = fs_mount_options + n;
339
if (g_strcmp0 (fsmo->fstype, fstype) == 0)
349
find_primary_gid (uid_t uid)
351
struct passwd *pw = NULL;
352
struct passwd pwstruct;
359
rc = getpwuid_r (uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
360
if (rc != 0 || pw == NULL)
362
udisks_warning ("Error looking up uid %d: %m", uid);
372
is_uid_in_gid (uid_t uid,
376
struct passwd *pw = NULL;
377
struct passwd pwstruct;
380
static gid_t supplementary_groups[128];
381
int num_supplementary_groups = 128;
384
/* TODO: use some #define instead of harcoding some random number like 128 */
388
rc = getpwuid_r (uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
389
if (rc != 0 || pw == NULL)
391
udisks_warning ("Error looking up uid %d: %m", uid);
394
if (pw->pw_gid == gid)
400
if (getgrouplist (pw->pw_name, pw->pw_gid, supplementary_groups, &num_supplementary_groups) < 0)
402
udisks_warning ("Error getting supplementary groups for uid %d: %m", uid);
406
for (n = 0; n < num_supplementary_groups; n++)
408
if (supplementary_groups[n] == gid)
420
is_mount_option_allowed (const FSMountOptions *fsmo,
434
/* first run through the allowed mount options */
437
for (n = 0; fsmo->allow != NULL && fsmo->allow[n] != NULL; n++)
439
ep = strstr (fsmo->allow[n], "=");
440
if (ep != NULL && ep[1] == '\0')
442
ep_len = ep - fsmo->allow[n] + 1;
443
if (strncmp (fsmo->allow[n], option, ep_len) == 0)
451
if (strcmp (fsmo->allow[n], option) == 0)
459
for (n = 0; any_allow[n] != NULL; n++)
461
ep = strstr (any_allow[n], "=");
462
if (ep != NULL && ep[1] == '\0')
464
ep_len = ep - any_allow[n] + 1;
465
if (strncmp (any_allow[n], option, ep_len) == 0)
473
if (strcmp (any_allow[n], option) == 0)
481
/* .. then check for mount options where the caller is allowed to pass
486
for (n = 0; fsmo->allow_uid_self != NULL && fsmo->allow_uid_self[n] != NULL; n++)
488
const gchar *r_mount_option = fsmo->allow_uid_self[n];
489
if (g_str_has_prefix (option, r_mount_option))
491
uid = strtol (option + strlen (r_mount_option), &endp, 10);
494
if (uid == caller_uid)
507
for (n = 0; fsmo->allow_gid_self != NULL && fsmo->allow_gid_self[n] != NULL; n++)
509
const gchar *r_mount_option = fsmo->allow_gid_self[n];
510
if (g_str_has_prefix (option, r_mount_option))
512
gid = strtol (option + strlen (r_mount_option), &endp, 10);
515
if (is_uid_in_gid (caller_uid, gid))
529
prepend_default_mount_options (const FSMountOptions *fsmo,
531
GVariant *given_options)
537
const gchar *option_string;
539
options = g_ptr_array_new ();
542
const gchar *const *defaults = fsmo->defaults;
544
for (n = 0; defaults != NULL && defaults[n] != NULL; n++)
546
const gchar *option = defaults[n];
548
if (strcmp (option, "uid=") == 0)
550
s = g_strdup_printf ("uid=%d", caller_uid);
551
g_ptr_array_add (options, s);
553
else if (strcmp (option, "gid=") == 0)
555
gid = find_primary_gid (caller_uid);
556
if (gid != (gid_t) - 1)
558
s = g_strdup_printf ("gid=%d", gid);
559
g_ptr_array_add (options, s);
564
g_ptr_array_add (options, g_strdup (option));
569
if (g_variant_lookup (given_options,
571
"&s", &option_string))
573
gchar **split_option_string;
574
split_option_string = g_strsplit (option_string, ",", -1);
575
for (n = 0; split_option_string[n] != NULL; n++)
576
g_ptr_array_add (options, split_option_string[n]); /* steals string */
577
g_free (split_option_string);
579
g_ptr_array_add (options, NULL);
581
return (char **) g_ptr_array_free (options, FALSE);
585
subst_str (const gchar *str,
592
parts = g_strsplit (str, from, 0);
593
result = g_strjoinv (to, parts);
599
subst_str_and_escape (const gchar *str,
603
gchar *quoted_and_escaped;
605
quoted_and_escaped = udisks_daemon_util_escape_and_quote (to);
606
ret = subst_str (str, from, quoted_and_escaped);
607
g_free (quoted_and_escaped);
611
/* ---------------------------------------------------------------------------------------------------- */
614
* calculate_fs_type: <internal>
615
* @block: A #UDisksBlock.
616
* @given_options: The a{sv} #GVariant.
617
* @error: Return location for error or %NULL.
619
* Calculates the file system type to use.
621
* Returns: A valid UTF-8 string with the filesystem type (may be "auto") or %NULL if @error is set. Free with g_free().
624
calculate_fs_type (UDisksBlock *block,
625
GVariant *given_options,
628
gchar *fs_type_to_use = NULL;
629
const gchar *probed_fs_type = NULL;
630
const gchar *requested_fs_type;
632
probed_fs_type = NULL;
634
probed_fs_type = udisks_block_get_id_type (block);
636
if (g_variant_lookup (given_options,
638
"&s", &requested_fs_type) &&
639
strlen (requested_fs_type) > 0)
641
/* If the user requests the filesystem type, error out unless the
644
* - well-known [1]; or
645
* - in the /proc/filesystems file; or
646
* - in the /etc/filesystems file
648
* in that order. We do this because mount(8) on Linux allows
649
* loading any arbitrary kernel module (when invoked as root) by
650
* passing something appropriate to the -t option. So we have to
651
* validate whatever we pass...
653
* See https://bugs.freedesktop.org/show_bug.cgi?id=32232 for more
656
* [1] : since /etc/filesystems may be horribly out of date and
657
* not contain e.g. ext4
659
if (g_strcmp0 (requested_fs_type, "auto") != 0)
661
if (!is_allowed_filesystem (requested_fs_type))
665
UDISKS_ERROR_OPTION_NOT_PERMITTED,
666
"Requested filesystem type `%s' is neither well-known nor "
667
"in /proc/filesystems nor in /etc/filesystems",
673
/* TODO: maybe check that it's compatible with probed_fs_type */
674
fs_type_to_use = g_strdup (requested_fs_type);
678
if (probed_fs_type != NULL && strlen (probed_fs_type) > 0)
679
fs_type_to_use = g_strdup (probed_fs_type);
681
fs_type_to_use = g_strdup ("auto");
685
g_assert (fs_type_to_use == NULL || g_utf8_validate (fs_type_to_use, -1, NULL));
687
return fs_type_to_use;
691
* calculate_mount_options: <internal>
692
* @daemon: A #UDisksDaemon.
693
* @block: A #UDisksBlock.
694
* @caller_uid: The uid of the caller making the request.
695
* @fs_type: The filesystem type to use or %NULL.
696
* @options: Options requested by the caller.
697
* @error: Return location for error or %NULL.
699
* Calculates the mount option string to use. Ensures (by returning an
700
* error) that only safe options are used.
702
* Returns: A string with mount options or %NULL if @error is set. Free with g_free().
705
calculate_mount_options (UDisksDaemon *daemon,
708
const gchar *fs_type,
712
const FSMountOptions *fsmo;
713
gchar **options_to_use;
714
gchar *options_to_use_str;
718
options_to_use = NULL;
719
options_to_use_str = NULL;
721
fsmo = find_mount_options_for_fs (fs_type);
723
/* always prepend some reasonable default mount options; these are
724
* chosen here; the user can override them if he wants to
726
options_to_use = prepend_default_mount_options (fsmo, caller_uid, options);
728
/* validate mount options */
729
str = g_string_new ("uhelper=udisks2,nodev,nosuid");
730
for (n = 0; options_to_use[n] != NULL; n++)
732
const gchar *option = options_to_use[n];
734
/* avoid attacks like passing "shortname=lower,uid=0" as a single mount option */
735
if (strstr (option, ",") != NULL)
739
UDISKS_ERROR_OPTION_NOT_PERMITTED,
740
"Malformed mount option `%s'",
742
g_string_free (str, TRUE);
746
/* first check if the mount option is allowed */
747
if (!is_mount_option_allowed (fsmo, option, caller_uid))
751
UDISKS_ERROR_OPTION_NOT_PERMITTED,
752
"Mount option `%s' is not allowed",
754
g_string_free (str, TRUE);
758
g_string_append_c (str, ',');
759
g_string_append (str, option);
761
options_to_use_str = g_string_free (str, FALSE);
764
g_strfreev (options_to_use);
766
g_assert (options_to_use_str == NULL || g_utf8_validate (options_to_use_str, -1, NULL));
768
return options_to_use_str;
771
/* ---------------------------------------------------------------------------------------------------- */
774
ensure_utf8 (const gchar *s)
779
if (!g_utf8_validate (s, -1, &end))
783
/* TODO: could possibly return a nicer UTF-8 string */
784
pos = (gint) (end - s);
785
tmp = g_strndup (s, end - s);
786
ret = g_strdup_printf ("%s (Invalid UTF-8 at byte %d)", tmp, pos);
797
/* ---------------------------------------------------------------------------------------------------- */
800
add_acl (const gchar *path,
804
gboolean ret = FALSE;
807
acl_permset_t permset;
809
acl = acl_get_file(path, ACL_TYPE_ACCESS);
811
acl_create_entry (&acl, &entry) == -1 ||
812
acl_set_tag_type (entry, ACL_USER) == -1 ||
813
acl_set_qualifier (entry, &uid) == -1 ||
814
acl_get_permset (entry, &permset) == -1 ||
815
acl_add_perm (permset, ACL_READ|ACL_EXECUTE) == -1 ||
816
acl_calc_mask (&acl) == -1 ||
817
acl_set_file (path, ACL_TYPE_ACCESS, acl) == -1)
821
g_io_error_from_errno (errno),
822
"Adding read ACL for uid %d to `%s' failed: %m",
836
* calculate_mount_point: <internal>
837
* @dameon: A #UDisksDaemon.
838
* @block: A #UDisksBlock.
839
* @uid: user id of the calling user
840
* @gid: group id of the calling user
841
* @user_name: user name of the calling user
842
* @fs_type: The file system type to mount with
843
* @error: Return location for error or %NULL.
845
* Calculates the mount point to use.
847
* Returns: A UTF-8 string with the mount point to use or %NULL if @error is set. Free with g_free().
850
calculate_mount_point (UDisksDaemon *daemon,
854
const gchar *user_name,
855
const gchar *fs_type,
858
UDisksLinuxBlockObject *object = NULL;
859
gboolean fs_shared = FALSE;
860
const gchar *label = NULL;
861
const gchar *uuid = NULL;
862
gchar *escaped_user_name = NULL;
863
gchar *mount_dir = NULL;
864
gchar *mount_point = NULL;
865
gchar *orig_mount_point;
874
label = udisks_block_get_id_label (block);
875
uuid = udisks_block_get_id_uuid (block);
878
object = udisks_daemon_util_dup_object (block, NULL);
881
UDisksLinuxDevice *device = udisks_linux_block_object_get_device (object);
884
if (device->udev_device != NULL)
886
/* TODO: maybe introduce Block:HintFilesystemShared instead of pulling it directly from the udev device */
887
fs_shared = g_udev_device_get_property_as_boolean (device->udev_device, "UDISKS_FILESYSTEM_SHARED");
889
g_object_unref (device);
893
/* If we know the user-name and it doesn't have any '/' character in
894
* it, mount in /run/media/$USER
896
if (!fs_shared && (user_name != NULL && strstr (user_name, "/") == NULL))
898
mount_dir = g_strdup_printf ("/run/media/%s", user_name);
899
if (!g_file_test (mount_dir, G_FILE_TEST_EXISTS))
901
/* First ensure that /run/media exists */
902
if (!g_file_test ("/run/media", G_FILE_TEST_EXISTS))
904
if (g_mkdir ("/run/media", 0755) != 0)
909
"Error creating directory /run/media: %m");
913
/* Then create the per-user /run/media/$USER */
914
if (g_mkdir (mount_dir, 0700) != 0)
919
"Error creating directory `%s': %m",
923
/* Finally, add the read+execute ACL for $USER */
924
if (!add_acl (mount_dir, uid, error))
926
if (rmdir (mount_dir) != 0)
927
udisks_warning ("Error calling rmdir() on %s: %m", mount_dir);
932
/* otherwise fall back to mounting in /media */
933
if (mount_dir == NULL)
934
mount_dir = g_strdup ("/media");
936
/* NOTE: UTF-8 has the nice property that valid UTF-8 strings only contains
937
* the byte 0x2F if it's for the '/' character (U+002F SOLIDUS).
939
* See http://en.wikipedia.org/wiki/UTF-8 for details.
941
if (label != NULL && strlen (label) > 0)
943
str = g_string_new (NULL);
944
g_string_append_printf (str, "%s/", mount_dir);
945
s = ensure_utf8 (label);
946
for (n = 0; s[n] != '\0'; n++)
950
g_string_append_c (str, '_');
952
g_string_append_c (str, c);
954
mount_point = g_string_free (str, FALSE);
957
else if (uuid != NULL && strlen (uuid) > 0)
959
str = g_string_new (NULL);
960
g_string_append_printf (str, "%s/", mount_dir);
961
s = ensure_utf8 (uuid);
962
for (n = 0; s[n] != '\0'; n++)
966
g_string_append_c (str, '_');
968
g_string_append_c (str, c);
970
mount_point = g_string_free (str, FALSE);
975
mount_point = g_strdup_printf ("%s/disk", mount_dir);
978
/* ... then uniqify the mount point */
979
orig_mount_point = g_strdup (mount_point);
983
if (!g_file_test (mount_point, G_FILE_TEST_EXISTS))
989
g_free (mount_point);
990
mount_point = g_strdup_printf ("%s%d", orig_mount_point, n++);
993
g_free (orig_mount_point);
997
g_clear_object (&object);
998
g_free (escaped_user_name);
1002
/* ---------------------------------------------------------------------------------------------------- */
1005
has_option (const gchar *options,
1006
const gchar *option)
1008
gboolean ret = FALSE;
1012
tokens = g_strsplit (options, ",", -1);
1013
for (n = 0; tokens != NULL && tokens[n] != NULL; n++)
1015
if (g_strcmp0 (tokens[n], option) == 0)
1021
g_strfreev (tokens);
1028
is_in_fstab (UDisksBlock *block,
1029
const gchar *fstab_path,
1030
gchar **out_mount_point,
1031
gchar **out_mount_options)
1040
f = fopen (fstab_path, "r");
1043
udisks_warning ("Error opening fstab file %s: %m", fstab_path);
1047
while ((m = getmntent_r (f, &mbuf, buf, sizeof (buf))) != NULL && !ret)
1053
if (g_str_has_prefix (m->mnt_fsname, "UUID="))
1055
device = g_strdup_printf ("/dev/disk/by-uuid/%s", m->mnt_fsname + 5);
1057
else if (g_str_has_prefix (m->mnt_fsname, "LABEL="))
1059
device = g_strdup_printf ("/dev/disk/by-label/%s", m->mnt_fsname + 6);
1061
else if (g_str_has_prefix (m->mnt_fsname, "/dev"))
1063
device = g_strdup (m->mnt_fsname);
1067
/* ignore non-device entries */
1071
if (stat (device, &sb) != 0)
1073
udisks_debug ("Error statting %s (for entry %s): %m", device, m->mnt_fsname);
1076
if (!S_ISBLK (sb.st_mode))
1078
udisks_debug ("Device %s (for entry %s) is not a block device", device, m->mnt_fsname);
1082
/* udisks_debug ("device %d:%d for entry %s", major (sb.st_rdev), minor (sb.st_rdev), m->mnt_fsname); */
1084
if (udisks_block_get_device_number (block) == sb.st_rdev)
1087
if (out_mount_point != NULL)
1088
*out_mount_point = g_strdup (m->mnt_dir);
1089
if (out_mount_options != NULL)
1090
*out_mount_options = g_strdup (m->mnt_opts);
1103
/* returns TRUE if, and only if, device is referenced in e.g. /etc/fstab
1105
* TODO: check all files in /etc/fstab.d (it's a non-standard Linux extension)
1106
* TODO: check if systemd has a specific "unit" for the device
1109
is_system_managed (UDisksBlock *block,
1110
gchar **out_mount_point,
1111
gchar **out_mount_options)
1117
/* First, check /etc/fstab */
1118
if (is_in_fstab (block, "/etc/fstab", out_mount_point, out_mount_options))
1127
/* ---------------------------------------------------------------------------------------------------- */
1129
/* runs in thread dedicated to handling @invocation */
1131
handle_mount (UDisksFilesystem *filesystem,
1132
GDBusMethodInvocation *invocation,
1135
UDisksObject *object;
1137
UDisksDaemon *daemon;
1142
const gchar * const *existing_mount_points;
1143
const gchar *probed_fs_usage;
1144
gchar *fs_type_to_use;
1145
gchar *mount_options_to_use;
1146
gchar *mount_point_to_use;
1147
gchar *fstab_mount_options;
1148
gchar *escaped_fs_type_to_use;
1149
gchar *escaped_mount_options_to_use;
1150
gchar *escaped_mount_point_to_use;
1151
gchar *error_message;
1152
gchar *caller_user_name;
1154
const gchar *action_id;
1155
const gchar *message;
1156
gboolean system_managed;
1157
gchar *escaped_device = NULL;
1160
error_message = NULL;
1161
fs_type_to_use = NULL;
1162
mount_options_to_use = NULL;
1163
mount_point_to_use = NULL;
1164
fstab_mount_options = NULL;
1165
escaped_fs_type_to_use = NULL;
1166
escaped_mount_options_to_use = NULL;
1167
escaped_mount_point_to_use = NULL;
1168
caller_user_name = NULL;
1169
system_managed = FALSE;
1171
/* only allow a single call at a time */
1172
g_mutex_lock (&UDISKS_LINUX_FILESYSTEM (filesystem)->lock);
1175
object = udisks_daemon_util_dup_object (filesystem, &error);
1178
g_dbus_method_invocation_take_error (invocation, error);
1182
block = udisks_object_peek_block (object);
1183
daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
1184
state = udisks_daemon_get_state (daemon);
1186
/* check if mount point is managed by e.g. /etc/fstab or similar */
1187
if (is_system_managed (block, &mount_point_to_use, &fstab_mount_options))
1189
system_managed = TRUE;
1192
/* First, fail if the device is already mounted */
1193
existing_mount_points = udisks_filesystem_get_mount_points (filesystem);
1194
if (existing_mount_points != NULL && g_strv_length ((gchar **) existing_mount_points) > 0)
1198
str = g_string_new (NULL);
1199
for (n = 0; existing_mount_points[n] != NULL; n++)
1202
g_string_append (str, ", ");
1203
g_string_append_printf (str, "`%s'", existing_mount_points[n]);
1205
g_dbus_method_invocation_return_error (invocation,
1207
UDISKS_ERROR_ALREADY_MOUNTED,
1208
"Device %s is already mounted at %s.\n",
1209
udisks_block_get_device (block),
1211
g_string_free (str, TRUE);
1216
if (!udisks_daemon_util_get_caller_uid_sync (daemon,
1218
NULL /* GCancellable */,
1224
g_dbus_method_invocation_return_gerror (invocation, error);
1225
g_error_free (error);
1230
if (!udisks_daemon_util_get_caller_pid_sync (daemon,
1232
NULL /* GCancellable */,
1236
g_dbus_method_invocation_return_gerror (invocation, error);
1237
g_error_free (error);
1244
gboolean mount_fstab_as_root = FALSE;
1246
if (!has_option (fstab_mount_options, "x-udisks-auth"))
1248
action_id = "org.freedesktop.udisks2.filesystem-mount";
1249
/* Translators: Shown in authentication dialog when the user
1250
* requests mounting a filesystem.
1252
* Do not translate $(drive), it's a placeholder and
1253
* will be replaced by the name of the drive/device in question
1255
message = N_("Authentication is required to mount $(drive)");
1256
if (!udisks_daemon_util_setup_by_user (daemon, object, caller_uid))
1258
if (udisks_block_get_hint_system (block))
1260
action_id = "org.freedesktop.udisks2.filesystem-mount-system";
1262
else if (!udisks_daemon_util_on_same_seat (daemon, object, caller_pid))
1264
action_id = "org.freedesktop.udisks2.filesystem-mount-other-seat";
1268
if (!udisks_daemon_util_check_authorization_sync (daemon,
1275
mount_fstab_as_root = TRUE;
1278
if (!g_file_test (mount_point_to_use, G_FILE_TEST_IS_DIR))
1280
if (g_mkdir_with_parents (mount_point_to_use, 0755) != 0)
1282
g_dbus_method_invocation_return_error (invocation,
1284
UDISKS_ERROR_FAILED,
1285
"Error creating directory `%s' to be used for mounting %s: %m",
1287
udisks_block_get_device (block));
1292
escaped_mount_point_to_use = udisks_daemon_util_escape_and_quote (mount_point_to_use);
1294
if (!udisks_daemon_launch_spawned_job_sync (daemon,
1296
"filesystem-mount", caller_uid,
1297
NULL, /* GCancellable */
1298
mount_fstab_as_root ? 0 : caller_uid, /* uid_t run_as_uid */
1299
mount_fstab_as_root ? 0 : caller_uid, /* uid_t run_as_euid */
1302
NULL, /* input_string */
1304
escaped_mount_point_to_use))
1306
/* mount(8) exits with status 1 on "incorrect invocation or permissions" - if this is
1307
* is so, try as as root */
1308
if (!mount_fstab_as_root && WIFEXITED (status) && WEXITSTATUS (status) == 1)
1310
if (!udisks_daemon_util_check_authorization_sync (daemon,
1312
"org.freedesktop.udisks2.filesystem-fstab",
1314
/* Translators: Shown in authentication dialog when the
1315
* user requests mounting a filesystem that is in
1316
* /etc/fstab file with the x-udisks-auth option.
1318
* Do not translate $(drive), it's a
1319
* placeholder and will be replaced by the name of
1320
* the drive/device in question
1322
* Do not translate /etc/fstab
1324
N_("Authentication is required to mount $(drive) referenced in the /etc/fstab file"),
1327
mount_fstab_as_root = TRUE;
1328
goto mount_fstab_again;
1331
g_dbus_method_invocation_return_error (invocation,
1333
UDISKS_ERROR_FAILED,
1334
"Error mounting system-managed device %s: %s",
1335
udisks_block_get_device (block),
1339
udisks_notice ("Mounted %s (system) at %s on behalf of uid %d",
1340
udisks_block_get_device (block),
1344
/* update the mounted-fs file */
1345
udisks_state_add_mounted_fs (state,
1347
udisks_block_get_device_number (block),
1349
TRUE); /* fstab_mounted */
1351
udisks_filesystem_complete_mount (filesystem, invocation, mount_point_to_use);
1355
/* Then fail if the device is not mountable - we actually allow mounting
1356
* devices that are not probed since since it could be that we just
1357
* don't have the data in the udev database but the device has a
1358
* filesystem *anyway*...
1360
* For example, this applies to PC floppy devices - automatically
1361
* probing for media them creates annoying noise. So they won't
1362
* appear in the udev database.
1364
probed_fs_usage = NULL;
1366
probed_fs_usage = udisks_block_get_id_usage (block);
1367
if (probed_fs_usage != NULL && strlen (probed_fs_usage) > 0 &&
1368
g_strcmp0 (probed_fs_usage, "filesystem") != 0)
1370
g_dbus_method_invocation_return_error (invocation,
1372
UDISKS_ERROR_FAILED,
1373
"Cannot mount block device %s with probed usage `%s' - expected `filesystem'",
1374
udisks_block_get_device (block),
1379
/* calculate filesystem type (guaranteed to be valid UTF-8) */
1381
fs_type_to_use = calculate_fs_type (block,
1384
if (fs_type_to_use == NULL)
1386
g_dbus_method_invocation_return_gerror (invocation, error);
1387
g_error_free (error);
1391
/* calculate mount options (guaranteed to be valid UTF-8) */
1393
mount_options_to_use = calculate_mount_options (daemon,
1399
if (mount_options_to_use == NULL)
1401
g_dbus_method_invocation_return_gerror (invocation, error);
1402
g_error_free (error);
1406
/* Now, check that the user is actually authorized to mount the
1407
* device. Need to do this before calculating a mount point since we
1408
* may be racing with other threads...
1410
action_id = "org.freedesktop.udisks2.filesystem-mount";
1411
/* Translators: Shown in authentication dialog when the user
1412
* requests mounting a filesystem.
1414
* Do not translate $(drive), it's a placeholder and
1415
* will be replaced by the name of the drive/device in question
1417
message = N_("Authentication is required to mount $(drive)");
1418
if (!udisks_daemon_util_setup_by_user (daemon, object, caller_uid))
1420
if (udisks_block_get_hint_system (block))
1422
action_id = "org.freedesktop.udisks2.filesystem-mount-system";
1424
else if (!udisks_daemon_util_on_same_seat (daemon, object, caller_pid))
1426
action_id = "org.freedesktop.udisks2.filesystem-mount-other-seat";
1430
if (!udisks_daemon_util_check_authorization_sync (daemon,
1438
/* calculate mount point (guaranteed to be valid UTF-8) */
1440
mount_point_to_use = calculate_mount_point (daemon,
1447
if (mount_point_to_use == NULL)
1449
g_dbus_method_invocation_return_gerror (invocation, error);
1450
g_error_free (error);
1454
/* create the mount point */
1455
if (g_mkdir (mount_point_to_use, 0700) != 0)
1457
g_dbus_method_invocation_return_error (invocation,
1459
UDISKS_ERROR_FAILED,
1460
"Error creating mount point `%s': %m",
1461
mount_point_to_use);
1465
escaped_fs_type_to_use = udisks_daemon_util_escape_and_quote (fs_type_to_use);
1466
escaped_mount_options_to_use = udisks_daemon_util_escape_and_quote (mount_options_to_use);
1467
escaped_mount_point_to_use = udisks_daemon_util_escape_and_quote (mount_point_to_use);
1468
escaped_device = udisks_daemon_util_escape_and_quote (udisks_block_get_device (block));
1471
if (!udisks_daemon_launch_spawned_job_sync (daemon,
1473
"filesystem-mount", caller_uid,
1474
NULL, /* GCancellable */
1475
0, /* uid_t run_as_uid */
1476
0, /* uid_t run_as_euid */
1477
NULL, /* gint *out_status */
1479
NULL, /* input_string */
1480
"mount -t %s -o %s %s %s",
1481
escaped_fs_type_to_use,
1482
escaped_mount_options_to_use,
1484
escaped_mount_point_to_use))
1486
/* ugh, something went wrong.. we need to clean up the created mount point */
1487
if (g_rmdir (mount_point_to_use) != 0)
1488
udisks_warning ("Error removing directory %s: %m", mount_point_to_use);
1489
g_dbus_method_invocation_return_error (invocation,
1491
UDISKS_ERROR_FAILED,
1492
"Error mounting %s at %s: %s",
1493
udisks_block_get_device (block),
1499
/* update the mounted-fs file */
1500
udisks_state_add_mounted_fs (state,
1502
udisks_block_get_device_number (block),
1504
FALSE); /* fstab_mounted */
1506
udisks_notice ("Mounted %s at %s on behalf of uid %d",
1507
udisks_block_get_device (block),
1511
udisks_filesystem_complete_mount (filesystem, invocation, mount_point_to_use);
1514
g_free (escaped_device);
1515
g_free (error_message);
1516
g_free (escaped_fs_type_to_use);
1517
g_free (escaped_mount_options_to_use);
1518
g_free (escaped_mount_point_to_use);
1519
g_free (fs_type_to_use);
1520
g_free (mount_options_to_use);
1521
g_free (mount_point_to_use);
1522
g_free (fstab_mount_options);
1523
g_free (caller_user_name);
1524
g_clear_object (&object);
1526
/* only allow a single call at a time */
1527
g_mutex_unlock (&UDISKS_LINUX_FILESYSTEM (filesystem)->lock);
1529
return TRUE; /* returning TRUE means that we handled the method invocation */
1532
/* ---------------------------------------------------------------------------------------------------- */
1535
get_error_code_for_umount (gint exit_status,
1536
const gchar *error_message)
1538
if (strstr (error_message, "device is busy") != NULL ||
1539
strstr (error_message, "target is busy") != NULL)
1540
return UDISKS_ERROR_DEVICE_BUSY;
1542
return UDISKS_ERROR_FAILED;
1545
/* runs in thread dedicated to handling @invocation */
1547
handle_unmount (UDisksFilesystem *filesystem,
1548
GDBusMethodInvocation *invocation,
1551
UDisksObject *object;
1553
UDisksDaemon *daemon;
1556
gchar *fstab_mount_options;
1557
gchar *escaped_mount_point;
1559
uid_t mounted_by_uid;
1562
gchar *error_message;
1563
const gchar *const *mount_points;
1566
gboolean system_managed;
1567
gboolean fstab_mounted;
1568
gchar *escaped_device = NULL;
1571
fstab_mount_options = NULL;
1572
escaped_mount_point = NULL;
1573
error_message = NULL;
1576
/* only allow a single call at a time */
1577
g_mutex_lock (&UDISKS_LINUX_FILESYSTEM (filesystem)->lock);
1580
object = udisks_daemon_util_dup_object (filesystem, &error);
1583
g_dbus_method_invocation_take_error (invocation, error);
1587
block = udisks_object_peek_block (object);
1588
daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
1589
state = udisks_daemon_get_state (daemon);
1590
system_managed = FALSE;
1592
if (options != NULL)
1594
g_variant_lookup (options,
1600
mount_points = udisks_filesystem_get_mount_points (filesystem);
1601
if (mount_points == NULL || g_strv_length ((gchar **) mount_points) == 0)
1603
g_dbus_method_invocation_return_error (invocation,
1605
UDISKS_ERROR_NOT_MOUNTED,
1606
"Device `%s' is not mounted",
1607
udisks_block_get_device (block));
1612
if (!udisks_daemon_util_get_caller_uid_sync (daemon, invocation, NULL, &caller_uid, NULL, NULL, &error))
1614
g_dbus_method_invocation_return_gerror (invocation, error);
1615
g_error_free (error);
1619
/* check if mount point is managed by e.g. /etc/fstab or similar */
1620
if (is_system_managed (block, &mount_point, &fstab_mount_options))
1622
system_managed = TRUE;
1625
/* if system-managed (e.g. referenced in /etc/fstab or similar) and
1626
* with the option x-udisks-auth, just run umount(8) as the
1629
if (system_managed && has_option (fstab_mount_options, "x-udisks-auth"))
1631
gboolean unmount_fstab_as_root;
1633
unmount_fstab_as_root = FALSE;
1634
unmount_fstab_again:
1635
escaped_mount_point = udisks_daemon_util_escape_and_quote (mount_point);
1636
/* right now -l is the only way to "force unmount" file systems... */
1637
if (!udisks_daemon_launch_spawned_job_sync (daemon,
1639
"filesystem-unmount", caller_uid,
1640
NULL, /* GCancellable */
1641
unmount_fstab_as_root ? 0 : caller_uid, /* uid_t run_as_uid */
1642
unmount_fstab_as_root ? 0 : caller_uid, /* uid_t run_as_euid */
1645
NULL, /* input_string */
1647
opt_force ? "-l" : "",
1648
escaped_mount_point))
1650
/* umount(8) does not (yet) have a specific exits status for
1651
* "insufficient permissions" so just try again as root
1653
* TODO: file bug asking for such an exit status
1655
if (!unmount_fstab_as_root && WIFEXITED (status) && WEXITSTATUS (status) != 0)
1657
if (!udisks_daemon_util_check_authorization_sync (daemon,
1659
"org.freedesktop.udisks2.filesystem-fstab",
1661
/* Translators: Shown in authentication dialog when the
1662
* user requests unmounting a filesystem that is in
1663
* /etc/fstab file with the x-udisks-auth option.
1665
* Do not translate $(drive), it's a
1666
* placeholder and will be replaced by the name of
1667
* the drive/device in question
1669
* Do not translate /etc/fstab
1671
N_("Authentication is required to unmount $(drive) referenced in the /etc/fstab file"),
1674
unmount_fstab_as_root = TRUE;
1675
goto unmount_fstab_again;
1678
g_dbus_method_invocation_return_error (invocation,
1680
get_error_code_for_umount (status, error_message),
1681
"Error unmounting system-managed device %s: %s",
1682
udisks_block_get_device (block),
1686
udisks_notice ("Unmounted %s (system) from %s on behalf of uid %d",
1687
udisks_block_get_device (block),
1690
udisks_filesystem_complete_unmount (filesystem, invocation);
1695
mount_point = udisks_state_find_mounted_fs (state,
1696
udisks_block_get_device_number (block),
1699
if (mount_point == NULL)
1701
/* allow unmounting stuff not mentioned in mounted-fs, but treat it like root mounted it */
1705
if (caller_uid != 0 && (caller_uid != mounted_by_uid))
1707
const gchar *action_id;
1708
const gchar *message;
1710
action_id = "org.freedesktop.udisks2.filesystem-unmount-others";
1711
/* Translators: Shown in authentication dialog when the user
1712
* requests unmounting a filesystem previously mounted by
1715
* Do not translate $(drive), it's a placeholder and
1716
* will be replaced by the name of the drive/device in question
1718
message = N_("Authentication is required to unmount $(drive) mounted by another user");
1720
if (!udisks_daemon_util_check_authorization_sync (daemon,
1729
escaped_device = udisks_daemon_util_escape_and_quote (udisks_block_get_device (block));
1731
/* otherwise go ahead and unmount the filesystem */
1732
if (mount_point != NULL)
1734
escaped_mount_point = udisks_daemon_util_escape_and_quote (mount_point);
1735
rc = udisks_daemon_launch_spawned_job_sync (daemon,
1737
"filesystem-unmount", caller_uid,
1738
NULL, /* GCancellable */
1739
0, /* uid_t run_as_uid */
1740
0, /* uid_t run_as_euid */
1741
NULL, /* gint *out_status */
1743
NULL, /* input_string */
1745
opt_force ? "-l" : "",
1746
escaped_mount_point);
1750
/* mount_point == NULL */
1751
rc = udisks_daemon_launch_spawned_job_sync (daemon,
1753
"filesystem-unmount", caller_uid,
1754
NULL, /* GCancellable */
1755
0, /* uid_t run_as_uid */
1756
0, /* uid_t run_as_euid */
1759
NULL, /* input_string */
1761
opt_force ? "-l" : "",
1767
g_dbus_method_invocation_return_error (invocation,
1769
get_error_code_for_umount (status, error_message),
1770
"Error unmounting %s: %s",
1771
udisks_block_get_device (block),
1776
/* OK, filesystem unmounted.. the state/cleanup routines will remove the mountpoint for us */
1778
udisks_notice ("Unmounted %s on behalf of uid %d",
1779
udisks_block_get_device (block),
1782
udisks_filesystem_complete_unmount (filesystem, invocation);
1785
g_free (escaped_device);
1786
g_free (error_message);
1787
g_free (escaped_mount_point);
1788
g_free (mount_point);
1789
g_free (fstab_mount_options);
1790
g_clear_object (&object);
1792
g_mutex_unlock (&UDISKS_LINUX_FILESYSTEM (filesystem)->lock);
1797
/* ---------------------------------------------------------------------------------------------------- */
1800
on_set_label_job_completed (UDisksJob *job,
1802
const gchar *message,
1805
GDBusMethodInvocation *invocation = G_DBUS_METHOD_INVOCATION (user_data);
1806
UDisksFilesystem *filesystem;
1808
filesystem = UDISKS_FILESYSTEM (g_dbus_method_invocation_get_user_data (invocation));
1811
udisks_filesystem_complete_set_label (filesystem, invocation);
1813
g_dbus_method_invocation_return_error (invocation,
1815
UDISKS_ERROR_FAILED,
1816
"Error setting label: %s",
1820
/* runs in thread dedicated to handling method call */
1822
handle_set_label (UDisksFilesystem *filesystem,
1823
GDBusMethodInvocation *invocation,
1828
UDisksObject *object;
1829
UDisksDaemon *daemon;
1830
const gchar *probed_fs_usage;
1831
const gchar *probed_fs_type;
1832
const FSInfo *fs_info;
1834
const gchar *action_id;
1835
const gchar *message;
1836
gchar *real_label = NULL;
1849
object = udisks_daemon_util_dup_object (filesystem, &error);
1852
g_dbus_method_invocation_take_error (invocation, error);
1856
daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
1857
block = udisks_object_peek_block (object);
1860
if (!udisks_daemon_util_get_caller_pid_sync (daemon,
1862
NULL /* GCancellable */,
1866
g_dbus_method_invocation_return_gerror (invocation, error);
1867
g_error_free (error);
1872
if (!udisks_daemon_util_get_caller_uid_sync (daemon,
1874
NULL /* GCancellable */,
1880
g_dbus_method_invocation_return_gerror (invocation, error);
1881
g_error_free (error);
1885
probed_fs_usage = udisks_block_get_id_usage (block);
1886
probed_fs_type = udisks_block_get_id_type (block);
1888
if (g_strcmp0 (probed_fs_usage, "filesystem") != 0)
1890
g_dbus_method_invocation_return_error (invocation,
1892
UDISKS_ERROR_NOT_SUPPORTED,
1893
"Cannot change label on device of type %s",
1898
fs_info = get_fs_info (probed_fs_type);
1900
if (fs_info == NULL || fs_info->command_change_label == NULL)
1902
g_dbus_method_invocation_return_error (invocation,
1904
UDISKS_ERROR_NOT_SUPPORTED,
1905
"Don't know how to change label on device of type %s:%s",
1911
/* VFAT does not allow some characters; as dosfslabel does not enforce this,
1912
* check in advance; also, VFAT only knows upper-case characters, dosfslabel
1914
if (g_strcmp0 (probed_fs_type, "vfat") == 0)
1916
const gchar *forbidden = "\"*/:<>?\\|";
1918
for (n = 0; forbidden[n] != 0; n++)
1920
if (strchr (label, forbidden[n]) != NULL)
1922
g_dbus_method_invocation_return_error (invocation,
1924
UDISKS_ERROR_NOT_SUPPORTED,
1925
"character '%c' not supported in VFAT labels",
1931
/* we need to remember that we make a copy, so assign it to a new
1933
real_label = g_ascii_strup (label, -1);
1937
/* Fail if the device is already mounted and the tools/drivers doesn't
1938
* support changing the label in that case
1940
if (filesystem != NULL && !fs_info->supports_online_label_rename)
1942
const gchar * const *existing_mount_points;
1943
existing_mount_points = udisks_filesystem_get_mount_points (filesystem);
1944
if (existing_mount_points != NULL && g_strv_length ((gchar **) existing_mount_points) > 0)
1946
g_dbus_method_invocation_return_error (invocation,
1948
UDISKS_ERROR_NOT_SUPPORTED,
1949
"Cannot change label on mounted device of type %s:%s.\n",
1956
action_id = "org.freedesktop.udisks2.modify-device";
1957
/* Translators: Shown in authentication dialog when the user
1958
* requests changing the filesystem label.
1960
* Do not translate $(drive), it's a placeholder and
1961
* will be replaced by the name of the drive/device in question
1963
message = N_("Authentication is required to change the filesystem label on $(drive)");
1964
if (!udisks_daemon_util_setup_by_user (daemon, object, caller_uid))
1966
if (udisks_block_get_hint_system (block))
1968
action_id = "org.freedesktop.udisks2.modify-device-system";
1970
else if (!udisks_daemon_util_on_same_seat (daemon, UDISKS_OBJECT (object), caller_pid))
1972
action_id = "org.freedesktop.udisks2.modify-device-other-seat";
1976
/* Check that the user is actually authorized to change the
1979
if (!udisks_daemon_util_check_authorization_sync (daemon,
1987
if (fs_info->command_clear_label != NULL && strlen (label) == 0)
1989
command = subst_str_and_escape (fs_info->command_clear_label, "$DEVICE", udisks_block_get_device (block));
1993
tmp = subst_str_and_escape (fs_info->command_change_label, "$DEVICE", udisks_block_get_device (block));
1994
command = subst_str_and_escape (tmp, "$LABEL", label);
1998
job = udisks_daemon_launch_spawned_job (daemon,
2000
"filesystem-modify", caller_uid,
2001
NULL, /* cancellable */
2002
0, /* uid_t run_as_uid */
2003
0, /* uid_t run_as_euid */
2004
NULL, /* input_string */
2006
g_signal_connect (job,
2008
G_CALLBACK (on_set_label_job_completed),
2012
/* for some FSes we need to copy and modify label; free our copy */
2013
g_free (real_label);
2015
g_clear_object (&object);
2016
return TRUE; /* returning TRUE means that we handled the method invocation */
2019
/* ---------------------------------------------------------------------------------------------------- */
2022
filesystem_iface_init (UDisksFilesystemIface *iface)
2024
iface->handle_mount = handle_mount;
2025
iface->handle_unmount = handle_unmount;
2026
iface->handle_set_label = handle_set_label;