1 /***************************************************************************
4 * hal-storage-mount.c : Mount wrapper
6 * Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 **************************************************************************/
33 #include <glib/gstdio.h>
36 #include <sys/param.h>
37 #include <sys/ucred.h>
38 #include <sys/mount.h>
42 #include <sys/mnttab.h>
43 #include <sys/vfstab.h>
48 #include <sys/types.h>
54 #include <libhal-storage.h>
56 #include <libpolkit.h>
59 #include "hal-storage-shared.h"
62 #define MOUNT "/sbin/mount"
63 #define MOUNT_OPTIONS "noexec,nosuid"
64 #define MOUNT_TYPE_OPT "-t"
66 #define MOUNT "/sbin/mount"
67 #define MOUNT_OPTIONS "nosuid"
68 #define MOUNT_TYPE_OPT "-F"
70 #define MOUNT "/bin/mount"
71 #define MOUNT_OPTIONS "noexec,nosuid,nodev"
72 #define MOUNT_TYPE_OPT "-t"
78 fprintf (stderr
, "This program should only be started by hald.\n");
83 permission_denied_volume_ignore (const char *device
)
85 fprintf (stderr
, "org.freedesktop.Hal.Device.Volume.PermissionDenied\n");
86 fprintf (stderr
, "Device has %s volume.ignore set to TRUE. Refusing to mount.\n", device
);
91 permission_denied_etc_fstab (const char *device
)
93 fprintf (stderr
, "org.freedesktop.Hal.Device.Volume.PermissionDenied\n");
94 fprintf (stderr
, "Device %s is listed in /etc/fstab. Refusing to mount.\n", device
);
99 already_mounted (const char *device
)
101 fprintf (stderr
, "org.freedesktop.Hal.Device.Volume.AlreadyMounted\n");
102 fprintf (stderr
, "Device %s is already mounted.\n", device
);
107 invalid_mount_option (const char *option
, const char *uid
)
109 fprintf (stderr
, "org.freedesktop.Hal.Device.Volume.InvalidMountOption\n");
110 fprintf (stderr
, "The option '%s' is not allowed for uid=%s\n", option
, uid
);
115 unknown_filesystem (const char *filesystem
)
117 fprintf (stderr
, "org.freedesktop.Hal.Device.Volume.UnknownFilesystemType\n");
118 fprintf (stderr
, "Unknown file system '%s'\n", filesystem
);
123 invalid_mount_point (const char *mount_point
)
125 fprintf (stderr
, "org.freedesktop.Hal.Device.Volume.InvalidMountpoint\n");
126 fprintf (stderr
, "The mount point '%s' is invalid\n", mount_point
);
131 mount_point_not_available (const char *mount_point
)
133 fprintf (stderr
, "org.freedesktop.Hal.Device.Volume.MountPointNotAvailable\n");
134 fprintf (stderr
, "The mount point '%s' is already occupied\n", mount_point
);
140 cannot_remount (const char *device
)
142 fprintf (stderr
, "org.freedesktop.Hal.Device.Volume.CannotRemount\n");
143 fprintf (stderr
, "%s not mounted already\n", device
);
149 permission_denied_privilege (const char *privilege
, const char *uid
)
151 fprintf (stderr
, "org.freedesktop.Hal.Device.PermissionDeniedByPolicy\n");
152 fprintf (stderr
, "%s refused uid %s\n", privilege
, uid
);
158 /* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */
160 canonicalize_filename (gchar
*filename
)
163 gboolean last_was_slash
= FALSE
;
170 if (*p
== G_DIR_SEPARATOR
)
173 *q
++ = G_DIR_SEPARATOR
;
175 last_was_slash
= TRUE
;
179 if (last_was_slash
&& *p
== '.')
181 if (*(p
+ 1) == G_DIR_SEPARATOR
||
184 if (*(p
+ 1) == '\0')
189 else if (*(p
+ 1) == '.' &&
190 (*(p
+ 2) == G_DIR_SEPARATOR
||
193 if (q
> filename
+ 1)
196 while (q
> filename
+ 1 &&
197 *(q
- 1) != G_DIR_SEPARATOR
)
201 if (*(p
+ 2) == '\0')
209 last_was_slash
= FALSE
;
215 last_was_slash
= FALSE
;
222 if (q
> filename
+ 1 && *(q
- 1) == G_DIR_SEPARATOR
)
229 resolve_symlink (const char *file
)
239 while (g_file_test (f
, G_FILE_TEST_IS_SYMLINK
)) {
240 link
= g_file_read_link (f
, &error
);
242 g_warning ("Cannot resolve symlink %s: %s", f
, error
->message
);
243 g_error_free (error
);
249 dir
= g_path_get_dirname (f
);
250 f1
= g_strdup_printf ("%s/%s", dir
, link
);
259 canonicalize_filename (f
);
263 static LibHalVolume
*
264 volume_findby (LibHalContext
*hal_ctx
, const char *property
, const char *value
)
269 LibHalVolume
*result
= NULL
;
270 char *found_udi
= NULL
;
273 dbus_error_init (&error
);
274 if ((hal_udis
= libhal_manager_find_device_string_match (hal_ctx
, property
,
275 value
, &num_hal_udis
, &error
)) == NULL
) {
276 LIBHAL_FREE_DBUS_ERROR (&error
);
279 for (i
= 0; i
< num_hal_udis
; i
++) {
282 if (libhal_device_query_capability (hal_ctx
, udi
, "volume", &error
)) {
283 found_udi
= strdup (udi
);
288 libhal_free_string_array (hal_udis
);
290 if (found_udi
!= NULL
)
291 result
= libhal_volume_from_udi (hal_ctx
, found_udi
);
299 bailout_if_in_fstab (LibHalContext
*hal_ctx
, const char *device
, const char *label
, const char *uuid
)
305 printf (" label '%s' uuid '%s'\n", label
? label
: "" , uuid
? uuid
: "");
307 /* check if /etc/fstab mentions this device... (with symlinks etc) */
308 if (! fstab_open (&handle
)) {
309 printf ("cannot open /etc/fstab\n");
310 unknown_error ("Cannot open /etc/fstab");
312 while ((entry
= fstab_next (handle
, &_mount_point
)) != NULL
) {
316 printf ("Looking at /etc/fstab entry '%s'\n", entry
);
318 if (label
!= NULL
&& g_str_has_prefix (entry
, "LABEL=")) {
319 if (strcmp (entry
+ 6, label
) == 0) {
320 gboolean skip_fstab_entry
;
322 skip_fstab_entry
= FALSE
;
324 /* (heck, we also do the stuff below in gnome-mount) */
326 /* OK, so what's if someone attaches an external disk with the label '/' and
329 * LABEL=/ / ext3 defaults 1 1
331 * in /etc/fstab as most Red Hat systems do? Bugger, this is a very common use
332 * case; suppose that you take the disk from your Fedora server and attaches it
333 * to your laptop. Bingo, you now have two disks with the label '/'. One must
334 * seriously wonder if using things like LABEL=/ for / is a good idea; just
335 * what happens if you boot in this configuration? (answer: the initrd gets
336 * it wrong most of the time.. sigh)
338 * To work around this, check if the listed entry in /etc/fstab is already mounted,
339 * if it is, then check if it's the same device_file as the given one...
342 /* see if a volume is mounted at this mount point */
343 if (_mount_point
!= NULL
) {
344 LibHalVolume
*mounted_vol
;
346 mounted_vol
= volume_findby (hal_ctx
, "volume.mount_point", _mount_point
);
347 if (mounted_vol
!= NULL
) {
348 const char *mounted_vol_device_file
;
350 mounted_vol_device_file
= libhal_volume_get_device_file (mounted_vol
);
351 /* no need to resolve symlinks, hal uses the canonical device file */
352 if (mounted_vol_device_file
!= NULL
&&
353 strcmp (mounted_vol_device_file
, device
) !=0) {
355 printf ("Wanting to mount %s that has label %s, but /etc/fstab says LABEL=%s is to be mounted at mount point '%s'. However %s (that also has label %s), is already mounted at said mount point. So, skipping said /etc/fstab entry.\n",
356 device
, label
, label
, _mount_point
, mounted_vol_device_file
, _mount_point
);
358 skip_fstab_entry
= TRUE
;
360 libhal_volume_free (mounted_vol
);
364 if (!skip_fstab_entry
) {
365 printf ("%s found in /etc/fstab. Not mounting.\n", entry
);
366 permission_denied_etc_fstab (device
);
369 } else if (uuid
!= NULL
&& g_str_has_prefix (entry
, "UUID=")) {
370 if (strcmp (entry
+ 5, uuid
) == 0) {
371 printf ("%s found in /etc/fstab. Not mounting.\n", entry
);
372 permission_denied_etc_fstab (device
);
376 resolved
= resolve_symlink (entry
);
378 printf ("/etc/fstab: device %s -> %s \n", entry
, resolved
);
380 if (strcmp (device
, resolved
) == 0) {
381 printf ("%s (-> %s) found in /etc/fstab. Not mounting.\n", entry
, resolved
);
382 permission_denied_etc_fstab (device
);
388 fstab_close (handle
);
392 device_is_mounted (const char *device
, char **mount_point
)
400 /* check if /proc/mounts mentions this device... (with symlinks etc) */
401 if (! mtab_open (&handle
)) {
402 printf ("cannot open mount list\n");
403 unknown_error ("Cannot open /etc/mtab or equivalent");
405 while (((entry
= mtab_next (handle
, mount_point
)) != NULL
) && (ret
== FALSE
)) {
408 resolved
= resolve_symlink (entry
);
410 printf ("/proc/mounts: device %s -> %s \n", entry
, resolved
);
412 if (strcmp (device
, resolved
) == 0) {
413 printf ("%s (-> %s) found in mount list. Not mounting.\n", entry
, resolved
);
423 /* maps volume_id fs types to the appropriate -t mount option */
425 map_fstype (const char *fstype
)
428 if (! strcmp (fstype
, "iso9660"))
430 else if (! strcmp (fstype
, "ext2"))
432 else if (! strcmp (fstype
, "vfat"))
435 if (! strcmp (fstype
, "iso9660"))
437 else if (! strcmp (fstype
, "vfat"))
445 handle_mount (LibHalContext
*hal_ctx
,
447 LibPolKitContext
*pol_ctx
,
450 LibHalVolume
*volume
, LibHalDrive
*drive
, const char *device
,
451 const char *invoked_by_uid
, const char *invoked_by_syscon_name
,
452 DBusConnection
*system_bus
)
456 char mount_point
[256];
457 char mount_fstype
[256];
458 char mount_options
[1024];
459 char **allowed_options
;
460 char **given_options
;
461 gboolean wants_to_change_uid
;
469 GString
*mount_option_str
;
470 gboolean pol_is_fixed
;
471 gboolean pol_change_uid
;
475 gboolean allowed_by_privilege
;
476 gboolean is_temporary_privilege
;
478 gboolean explicit_mount_point_given
;
488 const char *drive_type
;
490 adt_export_data_t
*adt_data
;
491 size_t adt_data_size
;
492 gboolean append_ro
= FALSE
;
493 gboolean is_abs_path
= FALSE
;
496 calling_uid
= atol (invoked_by_uid
);
500 printf ("device = %s\n", device
);
501 printf ("invoked by uid = %s\n", invoked_by_uid
);
502 printf ("invoked by system bus connection = %s\n", invoked_by_syscon_name
);
505 if (volume
!= NULL
) {
506 dbus_error_init (&error
);
507 if (libhal_device_get_property_bool (hal_ctx
, udi
, "volume.ignore", &error
) ||
508 dbus_error_is_set (&error
)) {
509 if (dbus_error_is_set (&error
)) {
510 LIBHAL_FREE_DBUS_ERROR (&error
);
513 * When device allocation is enabled (bsmconv or TX), we
514 * set volume.ignore on all volumes, but still want
515 * Mount() to succeed when called from the euid=0
516 * device allocation program.
518 if (atol (invoked_by_uid
) != 0) {
519 permission_denied_volume_ignore (device
);
523 label
= libhal_volume_get_label (volume
);
524 uuid
= libhal_volume_get_uuid (volume
);
530 bailout_if_in_fstab (hal_ctx
, device
, label
, uuid
);
532 /* TODO: sanity check that what hal exports is correct (cf. Martin Pitt's email) */
534 /* read from stdin */
535 if (strlen (fgets (mount_point
, sizeof (mount_point
), stdin
)) > 0)
536 mount_point
[strlen (mount_point
) - 1] = '\0';
537 if (strlen (fgets (mount_fstype
, sizeof (mount_fstype
), stdin
)) > 0)
538 mount_fstype
[strlen (mount_fstype
) - 1] = '\0';
539 if (strlen (fgets (mount_options
, sizeof (mount_options
), stdin
)) > 0)
540 mount_options
[strlen (mount_options
) - 1] = '\0';
541 /* validate that input from stdin is UTF-8 */
542 if (!g_utf8_validate (mount_point
, -1, &end
))
543 unknown_error ("Error validating mount_point as UTF-8");
544 if (!g_utf8_validate (mount_fstype
, -1, &end
))
545 unknown_error ("Error validating mount_fstype as UTF-8");
546 if (!g_utf8_validate (mount_options
, -1, &end
))
547 unknown_error ("Error validating mount_options as UTF-8");
550 if (calling_uid
!= 0) {
552 for (i
= 0; mount_point
[i
] != '\0'; i
++) {
553 if (mount_point
[i
] == '\n' ||
554 mount_point
[i
] == G_DIR_SEPARATOR
) {
555 unknown_error ("mount_point cannot contain the following characters: newline, G_DIR_SEPARATOR (usually /)");
560 is_abs_path
= (mount_point
[0] == G_DIR_SEPARATOR
);
564 printf ("mount_point = '%s'\n", mount_point
);
565 printf ("mount_fstype = '%s'\n", mount_fstype
);
566 printf ("mount_options = '%s'\n", mount_options
);
569 /* delete any trailing whitespace options from splitting the string */
570 given_options
= g_strsplit (mount_options
, "\t", 0);
571 for (i
= g_strv_length (given_options
) - 1; i
>= 0; --i
) {
572 if (strlen (given_options
[i
]) > 0)
574 given_options
[i
] = NULL
;
578 /* for read-only media append 'ro' option if not already */
579 append_ro
= libhal_device_get_property_bool (hal_ctx
, libhal_drive_get_udi(drive
),
580 "storage.removable.solaris.read_only", NULL
);
583 for (i
= 0; i
< (int) g_strv_length (given_options
); i
++) {
584 if (strcmp (given_options
[i
], "ro") == 0) {
591 /* is option 'remount' included? */
593 for (i
= 0; i
< (int) g_strv_length (given_options
); i
++) {
594 if (strcmp (given_options
[i
], "remount") == 0) {
601 if (volume
!= NULL
) {
602 if (!libhal_volume_is_mounted (volume
)) {
603 cannot_remount (device
);
605 mount_dir
= g_strdup (libhal_volume_get_mount_point (volume
));
607 if (!device_is_mounted (device
, &mount_dir
)) {
608 cannot_remount (device
);
612 if (mount_dir
== NULL
) {
613 unknown_error ("Cannot get mount_dir for remount even though volume is mounted!");
617 if (volume
!= NULL
) {
618 if (libhal_volume_is_mounted (volume
)) {
619 already_mounted (device
);
622 if (device_is_mounted (device
, NULL
)) {
623 already_mounted (device
);
629 /* figure out mount point if no mount point is given... */
630 explicit_mount_point_given
= FALSE
;
631 if (strlen (mount_point
) == 0) {
636 label
= libhal_volume_get_label (volume
);
640 model
= libhal_drive_get_model (drive
);
641 drive_type
= libhal_drive_get_type_textual (drive
);
644 /* best - use label */
645 g_strlcpy (mount_point
, label
, sizeof (mount_point
));
647 } else if ((model
!= NULL
) && (strlen (model
) > 0)) {
648 g_strlcpy (mount_point
, model
, sizeof (mount_point
));
649 } else if ((drive_type
!= NULL
) && (strlen (drive_type
) > 0)) {
650 g_strlcpy (mount_point
, drive_type
, sizeof (mount_point
));
652 /* fallback - use "disk" */
653 g_snprintf (mount_point
, sizeof (mount_point
), "disk");
656 /* sanitize computed mount point name, e.g. replace invalid chars with '-' */
659 p
= g_utf8_strchr (mount_point
, -1, G_DIR_SEPARATOR
);
666 explicit_mount_point_given
= TRUE
;
669 /* check mount point name - only forbid separators */
671 if (calling_uid
!= 0) {
673 if (g_utf8_strchr (mount_point
, -1, G_DIR_SEPARATOR
) != NULL
) {
674 printf ("'%s' is an invalid mount point\n", mount_point
);
675 invalid_mount_point (mount_point
);
681 /* check if mount point is available - append number to mount point */
688 mount_dir
= g_strdup (mount_point
);
692 mount_dir
= g_strdup_printf ("/media/%s", mount_point
);
694 mount_dir
= g_strdup_printf ("/media/%s-%d", mount_point
, i
);
697 printf ("trying dir %s\n", mount_dir
);
700 /* XXX should test for being a mount point */
701 if (!g_file_test (mount_dir
, G_FILE_TEST_EXISTS
)) {
705 if (explicit_mount_point_given
) {
706 mount_point_not_available (mount_dir
);
713 dbus_error_init (&error
);
714 allowed_options
= libhal_device_get_property_strlist (hal_ctx
, udi
, "volume.mount.valid_options", &error
);
715 if (dbus_error_is_set (&error
)) {
716 unknown_error ("Cannot get volume.mount.valid_options");
717 dbus_error_free (&error
);
721 for (i
= 0; given_options
[i
] != NULL
; i
++)
722 printf ("given_options[%d] = '%s'\n", i
, given_options
[i
]);
723 for (i
= 0; allowed_options
[i
] != NULL
; i
++)
724 printf ("allowed_options[%d] = '%s'\n", i
, allowed_options
[i
]);
727 wants_to_change_uid
= FALSE
;
729 /* check mount options */
730 for (i
= 0; given_options
[i
] != NULL
; i
++) {
731 char *given
= given_options
[i
];
733 for (j
= 0; allowed_options
[j
] != NULL
; j
++) {
734 char *allow
= allowed_options
[j
];
735 int allow_len
= strlen (allow
);
737 if (strcmp (given
, allow
) == 0) {
741 if ((allow
[allow_len
- 1] == '=') &&
742 (strncmp (given
, allow
, allow_len
) == 0) &&
743 (int) strlen (given
) > allow_len
) {
745 /* option matched allowed ending in '=', e.g.
746 * given == "umask=foobar" and allowed == "umask="
748 if (strcmp (allow
, "uid=") == 0) {
751 /* check for uid=, it requires special handling */
752 uid
= (uid_t
) strtol (given
+ allow_len
, &endp
, 10);
754 printf ("'%s' is not a number?\n", given
);
755 unknown_error ("option uid is malformed");
758 printf ("%s with uid %d\n", allow
, uid
);
760 wants_to_change_uid
= TRUE
;
770 /* apparently option was not ok */
771 invalid_mount_option (given
, invoked_by_uid
);
777 /* Check privilege */
779 if (libhal_drive_is_hotpluggable (drive
) || libhal_drive_uses_removable_media (drive
))
780 pol_is_fixed
= FALSE
;
782 pol_change_uid
= FALSE
;
783 /* don't consider uid= on non-pollable drives for the purpose of policy
784 * (since these drives normally use vfat)
786 if (volume
!= NULL
) {
787 /* don't consider uid= on vfat, iso9660, udf change-uid for the purpose of policy
788 * (since these doesn't contain uid/gid bits)
790 if (strcmp (libhal_volume_get_fstype (volume
), "vfat") != 0 &&
791 strcmp (libhal_volume_get_fstype (volume
), "iso9660") != 0 &&
792 strcmp (libhal_volume_get_fstype (volume
), "udf") != 0) {
793 pol_change_uid
= wants_to_change_uid
;
798 if (pol_change_uid
) {
799 privilege
= "hal-storage-fixed-mount-all-options";
801 privilege
= "hal-storage-fixed-mount";
804 if (pol_change_uid
) {
805 privilege
= "hal-storage-removable-mount-all-options";
807 privilege
= "hal-storage-removable-mount";
812 printf ("using privilege %s for uid %s, system_bus_connection %s\n", privilege
, invoked_by_uid
,
813 invoked_by_syscon_name
);
817 if (libpolkit_is_uid_allowed_for_privilege (pol_ctx
,
818 invoked_by_syscon_name
,
822 &allowed_by_privilege
,
823 &is_temporary_privilege
,
824 NULL
) != LIBPOLKIT_RESULT_OK
) {
825 printf ("cannot lookup privilege\n");
826 unknown_error ("Cannot lookup privilege from PolicyKit");
829 if (!allowed_by_privilege
) {
830 printf ("caller don't possess privilege\n");
831 permission_denied_privilege (privilege
, invoked_by_uid
);
836 printf ("passed privilege\n");
840 /* create directory */
842 if (!g_file_test (mount_dir
, G_FILE_TEST_EXISTS
) &&
843 (g_mkdir (mount_dir
, 0755) != 0)) {
845 if (g_mkdir (mount_dir
, 0700) != 0) {
847 printf ("Cannot create '%s'\n", mount_dir
);
848 unknown_error ("Cannot create mount directory");
852 calling_uid
= (uid_t
) strtol (invoked_by_uid
, (char **) NULL
, 10);
853 pw
= getpwuid (calling_uid
);
855 calling_gid
= pw
->pw_gid
;
859 if (chown (mount_dir
, calling_uid
, calling_gid
) != 0) {
860 printf ("Cannot chown '%s' to uid: %d, gid: %d\n", mount_dir
,
861 calling_uid
, calling_gid
);
868 char *mount_option_commasep
= NULL
;
869 char *mount_do_fstype
= "auto";
871 /* construct arguments to mount */
874 if (strlen (mount_fstype
) > 0) {
875 mount_do_fstype
= (char *) map_fstype (mount_fstype
);
876 } else if (volume
== NULL
) {
877 /* non-pollable drive; force auto */
878 mount_do_fstype
= "auto";
879 } else if (libhal_volume_get_fstype (volume
) != NULL
&& strlen (libhal_volume_get_fstype (volume
)) > 0) {
880 mount_do_fstype
= (char *) map_fstype (libhal_volume_get_fstype (volume
));
882 args
[na
++] = MOUNT_TYPE_OPT
;
883 args
[na
++] = mount_do_fstype
;
886 mount_option_str
= g_string_new (MOUNT_OPTIONS
);
887 for (i
= 0; given_options
[i
] != NULL
; i
++) {
888 g_string_append (mount_option_str
, ",");
889 g_string_append (mount_option_str
, given_options
[i
]);
893 g_string_append (mount_option_str
, ",ro");
896 mount_option_commasep
= g_string_free (mount_option_str
, FALSE
); /* leak! */
897 args
[na
++] = mount_option_commasep
;
898 args
[na
++] = (char *) device
;
899 args
[na
++] = mount_dir
;
902 /* TODO FIXME XXX HACK: OK, so we should rewrite the options in /media/.hal-mtab ..
903 * but it doesn't really matter much at this point */
906 char *mount_dir_escaped
;
908 int hal_mtab_orig_len
;
911 char *hal_mtab_buf_old
;
913 /* Maintain a list in /media/.hal-mtab with entries of the following format
915 * <device_file>\t<uid>\t<session-id>\t<fstype>\t<options_sep_by_comma>\t<mount point>\n
917 * where session-id currently is unused and thus set to 0.
921 * /dev/sda2 500 0 hfsplus noexec,nosuid,nodev /media/Macintosh HD
922 * /dev/sda4 500 0 ntfs noexec,nosuid,nodev,umask=222 /media/Windows
923 * /dev/sdb1 500 0 vfat noexec,nosuid,nodev,shortname=winnt,uid=500 /media/davidz
927 if (g_file_test ("/media/.hal-mtab", G_FILE_TEST_EXISTS
)) {
928 hal_mtab_orig
= fopen ("/media/.hal-mtab", "r");
929 if (hal_mtab_orig
== NULL
) {
930 unknown_error ("Cannot open /media/.hal-mtab");
932 if (fseek (hal_mtab_orig
, 0L, SEEK_END
) != 0) {
933 unknown_error ("Cannot seek to end of /media/.hal-mtab");
935 hal_mtab_orig_len
= ftell (hal_mtab_orig
);
936 if (hal_mtab_orig_len
< 0) {
937 unknown_error ("Cannot determine size of /media/.hal-mtab");
939 rewind (hal_mtab_orig
);
940 hal_mtab_buf
= g_new0 (char, hal_mtab_orig_len
+ 1);
941 num_read
= fread (hal_mtab_buf
, 1, hal_mtab_orig_len
, hal_mtab_orig
);
942 if (num_read
!= hal_mtab_orig_len
) {
943 unknown_error ("Cannot read from /media/.hal-mtab");
945 fclose (hal_mtab_orig
);
947 hal_mtab_buf
= g_strdup ("");
950 mount_dir_escaped
= g_strescape (mount_dir
, NULL
);
952 printf ("%d: XYA creating /media/.hal-mtab~\n", getpid ());
954 hal_mtab
= fopen ("/media/.hal-mtab~", "w");
955 if (hal_mtab
== NULL
) {
956 unknown_error ("Cannot create /media/.hal-mtab~");
958 hal_mtab_buf_old
= hal_mtab_buf
;
959 hal_mtab_buf
= g_strdup_printf ("%s%s\t%s\t0\t%s\t%s\t%s\n",
961 device
, invoked_by_uid
, mount_do_fstype
,
962 mount_option_commasep
, mount_dir_escaped
);
963 g_free (hal_mtab_buf_old
);
964 if (hal_mtab_buf_old
== NULL
) {
965 unknown_error ("Out of memory appending to /media/.hal-mtab~");
967 if (fwrite (hal_mtab_buf
, 1, strlen (hal_mtab_buf
), hal_mtab
) != strlen (hal_mtab_buf
)) {
968 unknown_error ("Cannot write to /media/.hal-mtab~");
971 g_free (hal_mtab_buf
);
972 g_free (mount_dir_escaped
);
974 printf ("%d: XYA closing /media/.hal-mtab~\n", getpid ());
978 /* now try to mount */
979 if (!g_spawn_sync ("/",
989 printf ("Cannot execute %s\n", MOUNT
);
991 unlink ("/media/.hal-mtab~");
992 unknown_error ("Cannot spawn " MOUNT
);
996 if (exit_status
!= 0) {
997 char errstr
[] = "mount: unknown filesystem type";
999 printf ("%s error %d, stdout='%s', stderr='%s'\n", MOUNT
, exit_status
, sout
, serr
);
1002 g_rmdir (mount_dir
);
1003 unlink ("/media/.hal-mtab~");
1006 if (strncmp (errstr
, serr
, sizeof (errstr
) - 1) == 0) {
1007 unknown_filesystem (strlen (mount_fstype
) > 0 ?
1009 (volume
!= NULL
? libhal_volume_get_fstype (volume
) : "") );
1012 for (n
= 0; serr
[n
] != '\0'; n
++) {
1013 if (serr
[n
] == '\n') {
1017 unknown_error (serr
);
1022 if (rename ("/media/.hal-mtab~", "/media/.hal-mtab") != 0) {
1023 printf ("rename(2) failed, errno=%d -> '%s'\n", errno
, strerror (errno
));
1024 unlink ("/media/.hal-mtab~");
1026 printf ("%d: XYA failed renaming /media/.hal-mtab~ to /media/.hal-mtab\n", getpid ());
1028 unknown_error ("Cannot rename /media/.hal-mtab~ to /media/.hal-mtab");
1031 printf ("%d: XYA done renaming /media/.hal-mtab~ to /media/.hal-mtab\n", getpid ());
1035 openlog ("hald", 0, LOG_DAEMON
);
1037 syslog (LOG_INFO
, "remounted %s at '%s' on behalf of uid %s", device
, mount_dir
, invoked_by_uid
);
1039 syslog (LOG_INFO
, "mounted %s on behalf of uid %s", device
, invoked_by_uid
);
1044 if ((adt_data
= get_audit_export_data (system_bus
,
1045 invoked_by_syscon_name
, &adt_data_size
)) != NULL
) {
1046 audit_volume (adt_data
, ADT_attach
,
1047 WEXITSTATUS(exit_status
), auth_from_privilege(privilege
),
1048 mount_dir
, device
, mount_option_commasep
);
1056 libhal_free_string_array (allowed_options
);
1057 g_strfreev (given_options
);
1062 main (int argc
, char *argv
[])
1066 LibHalVolume
*volume
;
1068 LibHalContext
*hal_ctx
= NULL
;
1069 DBusConnection
*system_bus
= NULL
;
1071 LibPolKitContext
*pol_ctx
= NULL
;
1073 char *invoked_by_uid
;
1074 char *invoked_by_syscon_name
;
1076 if (!lock_hal_mtab ()) {
1077 unknown_error ("Cannot obtain lock on /media/.hal-mtab");
1080 device
= getenv ("HAL_PROP_BLOCK_DEVICE");
1084 udi
= getenv ("HAL_PROP_INFO_UDI");
1088 invoked_by_uid
= getenv ("HAL_METHOD_INVOKED_BY_UID");
1090 invoked_by_syscon_name
= getenv ("HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME");
1092 dbus_error_init (&error
);
1093 if ((hal_ctx
= libhal_ctx_init_direct (&error
)) == NULL
) {
1094 printf ("Cannot connect to hald\n");
1095 LIBHAL_FREE_DBUS_ERROR (&error
);
1099 dbus_error_init (&error
);
1100 system_bus
= dbus_bus_get (DBUS_BUS_SYSTEM
, &error
);
1101 if (system_bus
== NULL
) {
1102 printf ("Cannot connect to the system bus\n");
1103 LIBHAL_FREE_DBUS_ERROR (&error
);
1107 pol_ctx
= libpolkit_new_context (system_bus
);
1108 if (pol_ctx
== NULL
) {
1109 printf ("Cannot get libpolkit context\n");
1110 unknown_error ("Cannot get libpolkit context");
1114 volume
= libhal_volume_from_udi (hal_ctx
, udi
);
1115 if (volume
== NULL
) {
1118 drive
= libhal_drive_from_udi (hal_ctx
, udi
);
1119 if (drive
== NULL
) {
1122 handle_mount (hal_ctx
,
1126 udi
, NULL
, drive
, device
, invoked_by_uid
,
1127 invoked_by_syscon_name
, system_bus
);
1131 const char *drive_udi
;
1134 drive_udi
= libhal_volume_get_storage_device_udi (volume
);
1136 if (drive_udi
== NULL
)
1137 unknown_error ("Cannot get drive_udi from volume");
1138 drive
= libhal_drive_from_udi (hal_ctx
, drive_udi
);
1140 unknown_error ("Cannot get drive from hal");
1142 handle_mount (hal_ctx
,
1146 udi
, volume
, drive
, device
, invoked_by_uid
,
1147 invoked_by_syscon_name
, system_bus
);