xref: /onnv-gate/usr/src/cmd/hal/tools/hal-storage-mount.c (revision 12395:50bdcae3feb5)
12912Sartem /***************************************************************************
22912Sartem  * CVSID: $Id$
32912Sartem  *
42912Sartem  * hal-storage-mount.c : Mount wrapper
52912Sartem  *
62912Sartem  * Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
72912Sartem  *
82912Sartem  * This program is free software; you can redistribute it and/or modify
92912Sartem  * it under the terms of the GNU General Public License as published by
102912Sartem  * the Free Software Foundation; either version 2 of the License, or
112912Sartem  * (at your option) any later version.
122912Sartem  *
132912Sartem  * This program is distributed in the hope that it will be useful,
142912Sartem  * but WITHOUT ANY WARRANTY; without even the implied warranty of
152912Sartem  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
162912Sartem  * GNU General Public License for more details.
172912Sartem  *
182912Sartem  * You should have received a copy of the GNU General Public License
192912Sartem  * along with this program; if not, write to the Free Software
202912Sartem  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
212912Sartem  *
222912Sartem  **************************************************************************/
232912Sartem 
242912Sartem 
252912Sartem #ifdef HAVE_CONFIG_H
262912Sartem #  include <config.h>
272912Sartem #endif
282912Sartem 
292912Sartem #include <stdio.h>
302912Sartem #include <stdlib.h>
312912Sartem #include <string.h>
322912Sartem #include <glib.h>
332912Sartem #include <glib/gstdio.h>
342912Sartem #ifdef __FreeBSD__
352912Sartem #include <fstab.h>
362912Sartem #include <sys/param.h>
372912Sartem #include <sys/ucred.h>
382912Sartem #include <sys/mount.h>
392912Sartem #include <limits.h>
402912Sartem #include <pwd.h>
412912Sartem #elif sun
422912Sartem #include <sys/mnttab.h>
432912Sartem #include <sys/vfstab.h>
442912Sartem #include <sys/wait.h>
452912Sartem #else
462912Sartem #include <mntent.h>
472912Sartem #endif
482912Sartem #include <sys/types.h>
492912Sartem #include <unistd.h>
502912Sartem #include <errno.h>
512912Sartem #include <syslog.h>
522912Sartem 
532912Sartem #include <libhal.h>
542912Sartem #include <libhal-storage.h>
552912Sartem #ifdef HAVE_POLKIT
562912Sartem #include <libpolkit.h>
572912Sartem #endif
582912Sartem 
592912Sartem #include "hal-storage-shared.h"
602912Sartem 
612912Sartem #ifdef __FreeBSD__
622912Sartem #define MOUNT		"/sbin/mount"
632912Sartem #define MOUNT_OPTIONS	"noexec,nosuid"
642912Sartem #define MOUNT_TYPE_OPT	"-t"
652912Sartem #elif sun
662912Sartem #define MOUNT		"/sbin/mount"
673020Sartem #define MOUNT_OPTIONS	"nosuid"
682912Sartem #define MOUNT_TYPE_OPT	"-F"
692912Sartem #else
702912Sartem #define MOUNT		"/bin/mount"
712912Sartem #define MOUNT_OPTIONS	"noexec,nosuid,nodev"
722912Sartem #define MOUNT_TYPE_OPT	"-t"
732912Sartem #endif
742912Sartem 
752912Sartem static void
usage(void)762912Sartem usage (void)
772912Sartem {
782912Sartem 	fprintf (stderr, "This program should only be started by hald.\n");
792912Sartem 	exit (1);
802912Sartem }
812912Sartem 
822912Sartem static void
permission_denied_volume_ignore(const char * device)832912Sartem permission_denied_volume_ignore (const char *device)
842912Sartem {
852912Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.PermissionDenied\n");
862912Sartem 	fprintf (stderr, "Device has %s volume.ignore set to TRUE. Refusing to mount.\n", device);
872912Sartem 	exit (1);
882912Sartem }
892912Sartem 
902912Sartem static void
permission_denied_etc_fstab(const char * device)912912Sartem permission_denied_etc_fstab (const char *device)
922912Sartem {
932912Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.PermissionDenied\n");
942912Sartem 	fprintf (stderr, "Device %s is listed in /etc/fstab. Refusing to mount.\n", device);
952912Sartem 	exit (1);
962912Sartem }
972912Sartem 
982912Sartem static void
already_mounted(const char * device)992912Sartem already_mounted (const char *device)
1002912Sartem {
1012912Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.AlreadyMounted\n");
1022912Sartem 	fprintf (stderr, "Device %s is already mounted.\n", device);
1032912Sartem 	exit (1);
1042912Sartem }
1052912Sartem 
1062912Sartem static void
invalid_mount_option(const char * option,const char * uid)1072912Sartem invalid_mount_option (const char *option, const char *uid)
1082912Sartem {
1092912Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.InvalidMountOption\n");
1102912Sartem 	fprintf (stderr, "The option '%s' is not allowed for uid=%s\n", option, uid);
1112912Sartem 	exit (1);
1122912Sartem }
1132912Sartem 
1142912Sartem static void
unknown_filesystem(const char * filesystem)1152912Sartem unknown_filesystem (const char *filesystem)
1162912Sartem {
1172912Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.UnknownFilesystemType\n");
1182912Sartem 	fprintf (stderr, "Unknown file system '%s'\n", filesystem);
1192912Sartem 	exit (1);
1202912Sartem }
1212912Sartem 
1222912Sartem static void
invalid_mount_point(const char * mount_point)1232912Sartem invalid_mount_point (const char *mount_point)
1242912Sartem {
1252912Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.InvalidMountpoint\n");
1262912Sartem 	fprintf (stderr, "The mount point '%s' is invalid\n", mount_point);
1272912Sartem 	exit (1);
1282912Sartem }
1292912Sartem 
1302912Sartem static void
mount_point_not_available(const char * mount_point)1312912Sartem mount_point_not_available (const char *mount_point)
1322912Sartem {
1332912Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.MountPointNotAvailable\n");
1342912Sartem 	fprintf (stderr, "The mount point '%s' is already occupied\n", mount_point);
1352912Sartem 	exit (1);
1362912Sartem }
1372912Sartem 
1382912Sartem 
1392912Sartem static void
cannot_remount(const char * device)1402912Sartem cannot_remount (const char *device)
1412912Sartem {
1422912Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.CannotRemount\n");
1432912Sartem 	fprintf (stderr, "%s not mounted already\n", device);
1442912Sartem 	exit (1);
1452912Sartem }
1462912Sartem 
1472912Sartem #ifdef HAVE_POLKIT
1482912Sartem static void
permission_denied_privilege(const char * privilege,const char * uid)1492912Sartem permission_denied_privilege (const char *privilege, const char *uid)
1502912Sartem {
1512912Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.PermissionDeniedByPolicy\n");
1522912Sartem 	fprintf (stderr, "%s refused uid %s\n", privilege, uid);
1532912Sartem 	exit (1);
1542912Sartem }
1552912Sartem #endif
1562912Sartem 
1572912Sartem 
1582912Sartem /* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */
1592912Sartem static void
canonicalize_filename(gchar * filename)1602912Sartem canonicalize_filename (gchar *filename)
1612912Sartem {
1622912Sartem 	gchar *p, *q;
1632912Sartem 	gboolean last_was_slash = FALSE;
1642912Sartem 
1652912Sartem 	p = filename;
1662912Sartem 	q = filename;
1672912Sartem 
1682912Sartem 	while (*p)
1692912Sartem 	{
1702912Sartem 		if (*p == G_DIR_SEPARATOR)
1712912Sartem 		{
1722912Sartem 			if (!last_was_slash)
1732912Sartem 				*q++ = G_DIR_SEPARATOR;
1742912Sartem 
1752912Sartem 			last_was_slash = TRUE;
1762912Sartem 		}
1772912Sartem 		else
1782912Sartem 		{
1792912Sartem 			if (last_was_slash && *p == '.')
1802912Sartem 			{
1812912Sartem 				if (*(p + 1) == G_DIR_SEPARATOR ||
1822912Sartem 				    *(p + 1) == '\0')
1832912Sartem 				{
1842912Sartem 					if (*(p + 1) == '\0')
1852912Sartem 						break;
1862912Sartem 
1872912Sartem 					p += 1;
1882912Sartem 				}
1892912Sartem 				else if (*(p + 1) == '.' &&
1902912Sartem 					 (*(p + 2) == G_DIR_SEPARATOR ||
1912912Sartem 					  *(p + 2) == '\0'))
1922912Sartem 				{
1932912Sartem 					if (q > filename + 1)
1942912Sartem 					{
1952912Sartem 						q--;
1962912Sartem 						while (q > filename + 1 &&
1972912Sartem 						       *(q - 1) != G_DIR_SEPARATOR)
1982912Sartem 							q--;
1992912Sartem 					}
2002912Sartem 
2012912Sartem 					if (*(p + 2) == '\0')
2022912Sartem 						break;
2032912Sartem 
2042912Sartem 					p += 2;
2052912Sartem 				}
2062912Sartem 				else
2072912Sartem 				{
2082912Sartem 					*q++ = *p;
2092912Sartem 					last_was_slash = FALSE;
2102912Sartem 				}
2112912Sartem 			}
2122912Sartem 			else
2132912Sartem 			{
2142912Sartem 				*q++ = *p;
2152912Sartem 				last_was_slash = FALSE;
2162912Sartem 			}
2172912Sartem 		}
2182912Sartem 
2192912Sartem 		p++;
2202912Sartem 	}
2212912Sartem 
2222912Sartem 	if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
2232912Sartem 		q--;
2242912Sartem 
2252912Sartem 	*q = '\0';
2262912Sartem }
2272912Sartem 
2282912Sartem static char *
resolve_symlink(const char * file)2292912Sartem resolve_symlink (const char *file)
2302912Sartem {
2312912Sartem 	GError *error;
2322912Sartem 	char *dir;
2332912Sartem 	char *link;
2342912Sartem 	char *f;
2352912Sartem 	char *f1;
2362912Sartem 
2372912Sartem 	f = g_strdup (file);
2382912Sartem 
2392912Sartem 	while (g_file_test (f, G_FILE_TEST_IS_SYMLINK)) {
2402912Sartem 		link = g_file_read_link (f, &error);
2412912Sartem 		if (link == NULL) {
2422912Sartem 			g_warning ("Cannot resolve symlink %s: %s", f, error->message);
2432912Sartem 			g_error_free (error);
2442912Sartem 			g_free (f);
2452912Sartem 			f = NULL;
2462912Sartem 			goto out;
2472912Sartem 		}
2482912Sartem 
2492912Sartem 		dir = g_path_get_dirname (f);
2502912Sartem 		f1 = g_strdup_printf ("%s/%s", dir, link);
2512912Sartem 		g_free (dir);
2522912Sartem 		g_free (link);
2532912Sartem 		g_free (f);
2542912Sartem 		f = f1;
2552912Sartem 	}
2562912Sartem 
2572912Sartem out:
2582912Sartem 	if (f != NULL)
2592912Sartem 		canonicalize_filename (f);
2602912Sartem 	return f;
2612912Sartem }
2622912Sartem 
2632912Sartem static LibHalVolume *
volume_findby(LibHalContext * hal_ctx,const char * property,const char * value)2642912Sartem volume_findby (LibHalContext *hal_ctx, const char *property, const char *value)
2652912Sartem {
2662912Sartem 	int i;
2672912Sartem 	char **hal_udis;
2682912Sartem 	int num_hal_udis;
2692912Sartem 	LibHalVolume *result = NULL;
2702912Sartem 	char *found_udi = NULL;
2712912Sartem 	DBusError error;
2722912Sartem 
2732912Sartem 	dbus_error_init (&error);
2742912Sartem 	if ((hal_udis = libhal_manager_find_device_string_match (hal_ctx, property,
2752912Sartem 								 value, &num_hal_udis, &error)) == NULL) {
2762912Sartem 		LIBHAL_FREE_DBUS_ERROR (&error);
2772912Sartem 		goto out;
2782912Sartem 	}
2792912Sartem 	for (i = 0; i < num_hal_udis; i++) {
2802912Sartem 		char *udi;
2812912Sartem 		udi = hal_udis[i];
2822912Sartem 		if (libhal_device_query_capability (hal_ctx, udi, "volume", &error)) {
2832912Sartem 			found_udi = strdup (udi);
2842912Sartem 			break;
2852912Sartem 		}
2862912Sartem 	}
2872912Sartem 
2882912Sartem 	libhal_free_string_array (hal_udis);
2892912Sartem 
2902912Sartem 	if (found_udi != NULL)
2912912Sartem 		result = libhal_volume_from_udi (hal_ctx, found_udi);
2922912Sartem 
2932912Sartem 	free (found_udi);
2942912Sartem out:
2952912Sartem 	return result;
2962912Sartem }
2972912Sartem 
2982912Sartem static void
bailout_if_in_fstab(LibHalContext * hal_ctx,const char * device,const char * label,const char * uuid)2992912Sartem bailout_if_in_fstab (LibHalContext *hal_ctx, const char *device, const char *label, const char *uuid)
3002912Sartem {
3012912Sartem 	gpointer handle;
3022912Sartem 	char *entry;
3032912Sartem 	char *_mount_point;
3042912Sartem 
3052912Sartem 	printf (" label '%s'  uuid '%s'\n", label ? label : "" , uuid ? uuid : "");
3062912Sartem 
3072912Sartem 	/* check if /etc/fstab mentions this device... (with symlinks etc) */
3082912Sartem 	if (! fstab_open (&handle)) {
3092912Sartem 		printf ("cannot open /etc/fstab\n");
3102912Sartem 		unknown_error ("Cannot open /etc/fstab");
3112912Sartem 	}
3122912Sartem 	while ((entry = fstab_next (handle, &_mount_point)) != NULL) {
3132912Sartem 		char *resolved;
3142912Sartem 
3152912Sartem #ifdef DEBUG
3162912Sartem 		printf ("Looking at /etc/fstab entry '%s'\n", entry);
3172912Sartem #endif
3182912Sartem 		if (label != NULL && g_str_has_prefix (entry, "LABEL=")) {
3192912Sartem 			if (strcmp (entry + 6, label) == 0) {
3202912Sartem 				gboolean skip_fstab_entry;
3212912Sartem 
3222912Sartem 				skip_fstab_entry = FALSE;
3232912Sartem 
3242912Sartem 				/* (heck, we also do the stuff below in gnome-mount) */
3252912Sartem 
3262912Sartem 				/* OK, so what's if someone attaches an external disk with the label '/' and
3272912Sartem 				 * /etc/fstab has
3282912Sartem 				 *
3292912Sartem 				 *    LABEL=/    /    ext3    defaults    1 1
3302912Sartem 				 *
3312912Sartem 				 * in /etc/fstab as most Red Hat systems do? Bugger, this is a very common use
3322912Sartem 				 * case; suppose that you take the disk from your Fedora server and attaches it
3332912Sartem 				 * to your laptop. Bingo, you now have two disks with the label '/'. One must
3342912Sartem 				 * seriously wonder if using things like LABEL=/ for / is a good idea; just
3352912Sartem 				 * what happens if you boot in this configuration? (answer: the initrd gets
3362912Sartem 				 * it wrong most of the time.. sigh)
3372912Sartem 				 *
3382912Sartem 				 * To work around this, check if the listed entry in /etc/fstab is already mounted,
3392912Sartem 				 * if it is, then check if it's the same device_file as the given one...
3402912Sartem 				 */
3412912Sartem 
3422912Sartem 				/* see if a volume is mounted at this mount point  */
3432912Sartem 				if (_mount_point != NULL) {
3442912Sartem 					LibHalVolume *mounted_vol;
3452912Sartem 
3462912Sartem 					mounted_vol = volume_findby (hal_ctx, "volume.mount_point", _mount_point);
3472912Sartem 					if (mounted_vol != NULL) {
3482912Sartem 						const char *mounted_vol_device_file;
3492912Sartem 
3502912Sartem 						mounted_vol_device_file = libhal_volume_get_device_file (mounted_vol);
3512912Sartem 						/* no need to resolve symlinks, hal uses the canonical device file */
3522912Sartem 						if (mounted_vol_device_file != NULL &&
3532912Sartem 						    strcmp (mounted_vol_device_file, device) !=0) {
3542912Sartem #ifdef DEBUG
3552912Sartem 							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",
3562912Sartem 								   device, label, label, _mount_point, mounted_vol_device_file, _mount_point);
3572912Sartem #endif
3582912Sartem 							skip_fstab_entry = TRUE;
3592912Sartem 						}
3602912Sartem 						libhal_volume_free (mounted_vol);
3612912Sartem 					}
3622912Sartem 				}
3632912Sartem 
3642912Sartem 				if (!skip_fstab_entry) {
3652912Sartem 					printf ("%s found in /etc/fstab. Not mounting.\n", entry);
3662912Sartem 					permission_denied_etc_fstab (device);
3672912Sartem 				}
3682912Sartem 			}
3692912Sartem 		} else if (uuid != NULL && g_str_has_prefix (entry, "UUID=")) {
3702912Sartem 			if (strcmp (entry + 5, uuid) == 0) {
3712912Sartem 				printf ("%s found in /etc/fstab. Not mounting.\n", entry);
3722912Sartem 				permission_denied_etc_fstab (device);
3732912Sartem 			}
3742912Sartem 		} else {
3752912Sartem 
3762912Sartem 			resolved = resolve_symlink (entry);
3772912Sartem #ifdef DEBUG
3782912Sartem 			printf ("/etc/fstab: device %s -> %s \n", entry, resolved);
3792912Sartem #endif
3802912Sartem 			if (strcmp (device, resolved) == 0) {
3812912Sartem 				printf ("%s (-> %s) found in /etc/fstab. Not mounting.\n", entry, resolved);
3822912Sartem 				permission_denied_etc_fstab (device);
3832912Sartem 			}
3842912Sartem 
3852912Sartem 			g_free (resolved);
3862912Sartem 		}
3872912Sartem 	}
3882912Sartem 	fstab_close (handle);
3892912Sartem }
3902912Sartem 
3912912Sartem static gboolean
device_is_mounted(const char * device,char ** mount_point)3922912Sartem device_is_mounted (const char *device, char **mount_point)
3932912Sartem {
3942912Sartem 	gpointer handle;
3952912Sartem 	char *entry;
3962912Sartem 	gboolean ret;
3972912Sartem 
3982912Sartem 	ret = FALSE;
3992912Sartem 
4002912Sartem 	/* check if /proc/mounts mentions this device... (with symlinks etc) */
4012912Sartem 	if (! mtab_open (&handle)) {
4022912Sartem 		printf ("cannot open mount list\n");
4032912Sartem 		unknown_error ("Cannot open /etc/mtab or equivalent");
4042912Sartem 	}
4052912Sartem 	while (((entry = mtab_next (handle, mount_point)) != NULL) && (ret == FALSE)) {
4062912Sartem 		char *resolved;
4072912Sartem 
4082912Sartem 		resolved = resolve_symlink (entry);
4092912Sartem #ifdef DEBUG
4102912Sartem 		printf ("/proc/mounts: device %s -> %s \n", entry, resolved);
4112912Sartem #endif
4122912Sartem 		if (strcmp (device, resolved) == 0) {
4132912Sartem 			printf ("%s (-> %s) found in mount list. Not mounting.\n", entry, resolved);
4142912Sartem 			ret = TRUE;
4152912Sartem 		}
4162912Sartem 
4172912Sartem 		g_free (resolved);
4182912Sartem 	}
4192912Sartem 	mtab_close (handle);
4202912Sartem 	return ret;
4212912Sartem }
4222912Sartem 
4232912Sartem /* maps volume_id fs types to the appropriate -t mount option */
4242912Sartem static const char *
map_fstype(const char * fstype)4252912Sartem map_fstype (const char *fstype)
4262912Sartem {
4272912Sartem #ifdef __FreeBSD__
4282912Sartem 	if (! strcmp (fstype, "iso9660"))
4292912Sartem 		return "cd9660";
4302912Sartem 	else if (! strcmp (fstype, "ext2"))
4312912Sartem 		return "ext2fs";
4322912Sartem 	else if (! strcmp (fstype, "vfat"))
4332912Sartem 		return "msdosfs";
4342912Sartem #elif sun
4352912Sartem 	if (! strcmp (fstype, "iso9660"))
4362912Sartem 		return "hsfs";
4372912Sartem 	else if (! strcmp (fstype, "vfat"))
4382912Sartem 		return "pcfs";
4392912Sartem #endif
4402912Sartem 
4412912Sartem 	return fstype;
4422912Sartem }
4432912Sartem 
4442912Sartem static void
handle_mount(LibHalContext * hal_ctx,LibPolKitContext * pol_ctx,const char * udi,LibHalVolume * volume,LibHalDrive * drive,const char * device,const char * invoked_by_uid,const char * invoked_by_syscon_name,DBusConnection * system_bus)4452912Sartem handle_mount (LibHalContext *hal_ctx,
4462912Sartem #ifdef HAVE_POLKIT
4472912Sartem 	      LibPolKitContext *pol_ctx,
4482912Sartem #endif
4492912Sartem 	      const char *udi,
4502912Sartem 	      LibHalVolume *volume, LibHalDrive *drive, const char *device,
4512912Sartem 	      const char *invoked_by_uid, const char *invoked_by_syscon_name,
4522912Sartem 	      DBusConnection *system_bus)
4532912Sartem {
4542912Sartem 	int i, j;
4552912Sartem 	DBusError error;
4562912Sartem 	char mount_point[256];
4572912Sartem 	char mount_fstype[256];
4582912Sartem 	char mount_options[1024];
4592912Sartem 	char **allowed_options;
4602912Sartem 	char **given_options;
4612912Sartem 	gboolean wants_to_change_uid;
4622912Sartem 	char *mount_dir;
4632912Sartem 	GError *err = NULL;
4642912Sartem 	char *sout = NULL;
4652912Sartem 	char *serr = NULL;
4662912Sartem 	int exit_status;
4672912Sartem 	char *args[10];
4682912Sartem 	int na;
4692912Sartem 	GString *mount_option_str;
4702912Sartem 	gboolean pol_is_fixed;
4712912Sartem 	gboolean pol_change_uid;
4722912Sartem 	char *privilege;
4732912Sartem 	gboolean is_remount;
4742912Sartem #ifdef HAVE_POLKIT
4752912Sartem 	gboolean allowed_by_privilege;
4762912Sartem 	gboolean is_temporary_privilege;
4772912Sartem #endif
4782912Sartem 	gboolean explicit_mount_point_given;
4792912Sartem 	const char *end;
4802912Sartem #ifdef __FreeBSD__
4812912Sartem 	struct passwd *pw;
4822912Sartem 	uid_t calling_uid;
4832912Sartem 	gid_t calling_gid;
4842912Sartem #endif
4852912Sartem 	const char *label;
4862912Sartem 	const char *uuid;
4872912Sartem 	const char *model;
4882912Sartem 	const char *drive_type;
4892912Sartem #ifdef sun
4902912Sartem 	adt_export_data_t *adt_data;
4912912Sartem 	size_t adt_data_size;
4922912Sartem 	gboolean append_ro = FALSE;
4932912Sartem 	gboolean is_abs_path = FALSE;
4942912Sartem 	uid_t calling_uid;
4952912Sartem 
4962912Sartem 	calling_uid = atol (invoked_by_uid);
4972912Sartem #endif
4982912Sartem 
4992912Sartem #ifdef DEBUG
5002912Sartem 	printf ("device                           = %s\n", device);
5012912Sartem 	printf ("invoked by uid                   = %s\n", invoked_by_uid);
5022912Sartem 	printf ("invoked by system bus connection = %s\n", invoked_by_syscon_name);
5032912Sartem #endif
5042912Sartem 
5052912Sartem 	if (volume != NULL) {
5062912Sartem 		dbus_error_init (&error);
5072912Sartem 		if (libhal_device_get_property_bool (hal_ctx, udi, "volume.ignore", &error) ||
5082912Sartem 		    dbus_error_is_set (&error)) {
5092912Sartem 			if (dbus_error_is_set (&error)) {
5102912Sartem 				LIBHAL_FREE_DBUS_ERROR (&error);
5112912Sartem 			}
5122912Sartem 			/*
5132912Sartem 			 * When device allocation is enabled (bsmconv or TX), we
5142912Sartem 			 * set volume.ignore on all volumes, but still want
5152912Sartem 			 * Mount() to succeed when called from the euid=0
5162912Sartem 			 * device allocation program.
5172912Sartem 			 */
5182912Sartem 			if (atol (invoked_by_uid) != 0) {
5192912Sartem 				permission_denied_volume_ignore (device);
5202912Sartem 			}
5212912Sartem 		}
5222912Sartem 
5232912Sartem 		label = libhal_volume_get_label (volume);
5242912Sartem 		uuid = libhal_volume_get_uuid (volume);
5252912Sartem 	} else {
5262912Sartem 		label = NULL;
5272912Sartem 		uuid = NULL;
5282912Sartem 	}
5292912Sartem 
5302912Sartem 	bailout_if_in_fstab (hal_ctx, device, label, uuid);
5312912Sartem 
5322912Sartem 	/* TODO: sanity check that what hal exports is correct (cf. Martin Pitt's email) */
5332912Sartem 
5342912Sartem 	/* read from stdin */
5352912Sartem 	if (strlen (fgets (mount_point, sizeof (mount_point), stdin)) > 0)
5362912Sartem 		mount_point   [strlen (mount_point)   - 1] = '\0';
5372912Sartem 	if (strlen (fgets (mount_fstype, sizeof (mount_fstype), stdin)) > 0)
5382912Sartem 		mount_fstype  [strlen (mount_fstype)  - 1] = '\0';
5392912Sartem 	if (strlen (fgets (mount_options, sizeof (mount_options), stdin)) > 0)
5402912Sartem 		mount_options [strlen (mount_options) - 1] = '\0';
5412912Sartem 	/* validate that input from stdin is UTF-8 */
5422912Sartem 	if (!g_utf8_validate (mount_point, -1, &end))
5432912Sartem 		unknown_error ("Error validating mount_point as UTF-8");
5442912Sartem 	if (!g_utf8_validate (mount_fstype, -1, &end))
5452912Sartem 		unknown_error ("Error validating mount_fstype as UTF-8");
5462912Sartem 	if (!g_utf8_validate (mount_options, -1, &end))
5472912Sartem 		unknown_error ("Error validating mount_options as UTF-8");
5482912Sartem 
5492912Sartem #ifdef sun
5502912Sartem 	if (calling_uid != 0) {
5512912Sartem #endif
5522912Sartem 	for (i = 0; mount_point[i] != '\0'; i++) {
5532912Sartem 		if (mount_point[i] == '\n' ||
5542912Sartem 		    mount_point[i] == G_DIR_SEPARATOR) {
5552912Sartem 			unknown_error ("mount_point cannot contain the following characters: newline, G_DIR_SEPARATOR (usually /)");
5562912Sartem 		}
5572912Sartem 	}
5582912Sartem #ifdef sun
5592912Sartem 	}
5602912Sartem 	is_abs_path = (mount_point[0] == G_DIR_SEPARATOR);
5612912Sartem #endif
5622912Sartem 
5632912Sartem #ifdef DEBUG
5642912Sartem 	printf ("mount_point    = '%s'\n", mount_point);
5652912Sartem 	printf ("mount_fstype   = '%s'\n", mount_fstype);
5662912Sartem 	printf ("mount_options  = '%s'\n", mount_options);
5672912Sartem #endif
5682912Sartem 
5692912Sartem 	/* delete any trailing whitespace options from splitting the string */
5702912Sartem 	given_options = g_strsplit (mount_options, "\t", 0);
5712912Sartem 	for (i = g_strv_length (given_options) - 1; i >= 0; --i) {
5722912Sartem 		if (strlen (given_options[i]) > 0)
5732912Sartem 			break;
5742912Sartem 		given_options[i] = NULL;
5752912Sartem 	}
5762912Sartem 
5772912Sartem #ifdef sun
5782912Sartem 	/* for read-only media append 'ro' option if not already */
5792912Sartem 	append_ro = libhal_device_get_property_bool (hal_ctx, libhal_drive_get_udi(drive),
5802912Sartem 	    "storage.removable.solaris.read_only", NULL);
5812912Sartem 
5822912Sartem 	if (append_ro) {
5832912Sartem 		for (i = 0; i < (int) g_strv_length (given_options); i++) {
5842912Sartem 			if (strcmp (given_options[i], "ro") == 0) {
5852912Sartem 				append_ro = FALSE;
5862912Sartem 			}
5872912Sartem 		}
5882912Sartem 	}
5892912Sartem #endif /* sun */
5902912Sartem 
5912912Sartem 	/* is option 'remount' included? */
5922912Sartem 	is_remount = FALSE;
5932912Sartem 	for (i = 0; i < (int) g_strv_length (given_options); i++) {
5942912Sartem 		if (strcmp (given_options[i], "remount") == 0) {
5952912Sartem 			is_remount = TRUE;
5962912Sartem 		}
5972912Sartem 	}
5982912Sartem 
5992912Sartem 	mount_dir = NULL;
6002912Sartem 	if (is_remount) {
6012912Sartem 		if (volume != NULL) {
6022912Sartem 			if (!libhal_volume_is_mounted (volume)) {
6032912Sartem 				cannot_remount (device);
6042912Sartem 			}
6052912Sartem 			mount_dir = g_strdup (libhal_volume_get_mount_point (volume));
6062912Sartem 		} else {
6072912Sartem 			if (!device_is_mounted (device, &mount_dir)) {
6082912Sartem 				cannot_remount (device);
6092912Sartem 			}
6102912Sartem 		}
6112912Sartem 
6122912Sartem 		if (mount_dir == NULL) {
6132912Sartem 			unknown_error ("Cannot get mount_dir for remount even though volume is mounted!");
6142912Sartem 		}
6152912Sartem 
6162912Sartem 	} else {
6172912Sartem 		if (volume != NULL) {
6182912Sartem 			if (libhal_volume_is_mounted (volume)) {
6192912Sartem 				already_mounted (device);
6202912Sartem 			}
6212912Sartem 		} else {
6222912Sartem 			if (device_is_mounted (device, NULL)) {
6232912Sartem 				already_mounted (device);
6242912Sartem 			}
6252912Sartem 		}
6262912Sartem 	}
6272912Sartem 
6282912Sartem 	if (!is_remount) {
6292912Sartem 		/* figure out mount point if no mount point is given... */
6302912Sartem 		explicit_mount_point_given = FALSE;
6312912Sartem 		if (strlen (mount_point) == 0) {
6322912Sartem 			char *p;
6332912Sartem 			const char *label;
6342912Sartem 
6352912Sartem 			if (volume != NULL)
6362912Sartem 				label = libhal_volume_get_label (volume);
6372912Sartem 			else
6382912Sartem 				label = NULL;
6392912Sartem 
6402912Sartem 			model = libhal_drive_get_model (drive);
6412912Sartem 			drive_type = libhal_drive_get_type_textual (drive);
6422912Sartem 
6432912Sartem 			if (label != NULL) {
6442912Sartem 				/* best - use label */
6452912Sartem 				g_strlcpy (mount_point, label, sizeof (mount_point));
6462912Sartem 
6472912Sartem 			} else if ((model != NULL) && (strlen (model) > 0)) {
6482912Sartem 				g_strlcpy (mount_point, model, sizeof (mount_point));
6492912Sartem 			} else if ((drive_type != NULL) && (strlen (drive_type) > 0)) {
6502912Sartem 				g_strlcpy (mount_point, drive_type, sizeof (mount_point));
6512912Sartem 			} else {
6522912Sartem 				/* fallback - use "disk" */
6532912Sartem 				g_snprintf (mount_point, sizeof (mount_point), "disk");
6542912Sartem 			}
6552912Sartem 
6562912Sartem 			/* sanitize computed mount point name, e.g. replace invalid chars with '-' */
6572912Sartem 			p = mount_point;
6582912Sartem 			while (TRUE) {
6592912Sartem 				p = g_utf8_strchr (mount_point, -1, G_DIR_SEPARATOR);
6602912Sartem 				if (p == NULL)
6612912Sartem 					break;
6622912Sartem 				*p = '-';
6632912Sartem 			};
6642912Sartem 
6652912Sartem 		} else {
6662912Sartem 			explicit_mount_point_given = TRUE;
6672912Sartem 		}
6682912Sartem 
6692912Sartem 		/* check mount point name - only forbid separators */
6702912Sartem #ifdef sun
6712912Sartem 		if (calling_uid != 0) {
6722912Sartem #endif
6732912Sartem 		if (g_utf8_strchr (mount_point, -1, G_DIR_SEPARATOR) != NULL) {
6742912Sartem 			printf ("'%s' is an invalid mount point\n", mount_point);
6752912Sartem 			invalid_mount_point (mount_point);
6762912Sartem 		}
6772912Sartem #ifdef sun
6782912Sartem 		}
6792912Sartem #endif
6802912Sartem 
6812912Sartem 		/* check if mount point is available - append number to mount point */
6822912Sartem 		i = 0;
6832912Sartem 		mount_dir = NULL;
6842912Sartem 		while (TRUE) {
6852912Sartem 			g_free (mount_dir);
6862912Sartem #ifdef sun
6872912Sartem 			if (is_abs_path)
6882912Sartem 				mount_dir = g_strdup (mount_point);
6892912Sartem 			else
6902912Sartem #endif
6912912Sartem 			if (i == 0)
6922912Sartem 				mount_dir = g_strdup_printf ("/media/%s", mount_point);
6932912Sartem 			else
6942912Sartem 				mount_dir = g_strdup_printf ("/media/%s-%d", mount_point, i);
6952912Sartem 
6962912Sartem #ifdef DEBUG
6972912Sartem 			printf ("trying dir %s\n", mount_dir);
6982912Sartem #endif
6992912Sartem 
7002912Sartem 			/* XXX should test for being a mount point */
7012912Sartem 			if (!g_file_test (mount_dir, G_FILE_TEST_EXISTS)) {
7022912Sartem 				break;
7032912Sartem 			}
704*12395SLin.Guo@Sun.COM 
7052912Sartem 			if (explicit_mount_point_given) {
7062912Sartem 				mount_point_not_available (mount_dir);
7072912Sartem 			}
7082912Sartem 
7092912Sartem 			i++;
7102912Sartem 		}
7112912Sartem 	}
7122912Sartem 
7132912Sartem 	dbus_error_init (&error);
7142912Sartem 	allowed_options = libhal_device_get_property_strlist (hal_ctx, udi, "volume.mount.valid_options", &error);
7152912Sartem 	if (dbus_error_is_set (&error)) {
7162912Sartem 		unknown_error ("Cannot get volume.mount.valid_options");
7172912Sartem 		dbus_error_free (&error);
7182912Sartem 	}
7192912Sartem 
7202912Sartem #ifdef DEBUG
7212912Sartem 	for (i = 0; given_options[i] != NULL; i++)
7222912Sartem 		printf ("given_options[%d] = '%s'\n", i, given_options[i]);
7232912Sartem 	for (i = 0; allowed_options[i] != NULL; i++)
7242912Sartem 		printf ("allowed_options[%d] = '%s'\n", i, allowed_options[i]);
7252912Sartem #endif
7262912Sartem 
7272912Sartem 	wants_to_change_uid = FALSE;
7282912Sartem 
7292912Sartem 	/* check mount options */
7302912Sartem 	for (i = 0; given_options[i] != NULL; i++) {
7312912Sartem 		char *given = given_options[i];
7322912Sartem 
7332912Sartem 		for (j = 0; allowed_options[j] != NULL; j++) {
7342912Sartem 			char *allow = allowed_options[j];
7352912Sartem 			int allow_len = strlen (allow);
7362912Sartem 
7372912Sartem 			if (strcmp (given, allow) == 0) {
7382912Sartem 				goto option_ok;
7392912Sartem 			}
7402912Sartem 
7412912Sartem 			if ((allow[allow_len - 1] == '=') &&
7422912Sartem 			    (strncmp (given, allow, allow_len) == 0) &&
7432912Sartem 			    (int) strlen (given) > allow_len) {
7442912Sartem 
7452912Sartem 				/* option matched allowed ending in '=', e.g.
7462912Sartem 				 * given == "umask=foobar" and allowed == "umask="
7472912Sartem 				 */
7482912Sartem 				if (strcmp (allow, "uid=") == 0) {
7492912Sartem 					uid_t uid;
7502912Sartem 					char *endp;
7512912Sartem 					/* check for uid=, it requires special handling */
7522912Sartem 					uid = (uid_t) strtol (given + allow_len, &endp, 10);
7532912Sartem 					if (*endp != '\0') {
7542912Sartem 						printf ("'%s' is not a number?\n", given);
7552912Sartem 						unknown_error ("option uid is malformed");
7562912Sartem 					}
7572912Sartem #ifdef DEBUG
7582912Sartem 					printf ("%s with uid %d\n", allow, uid);
7592912Sartem #endif
7602912Sartem 					wants_to_change_uid = TRUE;
7612912Sartem 
7622912Sartem 					goto option_ok;
7632912Sartem 				} else {
7642912Sartem 
7652912Sartem 					goto option_ok;
7662912Sartem 				}
7672912Sartem 			}
7682912Sartem 		}
7692912Sartem 
7702912Sartem 		/* apparently option was not ok */
7712912Sartem 		invalid_mount_option (given, invoked_by_uid);
7722912Sartem 
7732912Sartem 	option_ok:
7742912Sartem 		;
7752912Sartem 	}
7762912Sartem 
7772912Sartem 	/* Check privilege */
7782912Sartem 	pol_is_fixed = TRUE;
7792912Sartem 	if (libhal_drive_is_hotpluggable (drive) || libhal_drive_uses_removable_media (drive))
7802912Sartem 		pol_is_fixed = FALSE;
7812912Sartem 
7822912Sartem 	pol_change_uid = FALSE;
7832912Sartem 	/* don't consider uid= on non-pollable drives for the purpose of policy
7842912Sartem 	 * (since these drives normally use vfat)
7852912Sartem 	 */
7862912Sartem 	if (volume != NULL) {
7872912Sartem 		/* don't consider uid= on vfat, iso9660, udf change-uid for the purpose of policy
7882912Sartem 		 * (since these doesn't contain uid/gid bits)
7892912Sartem 		 */
7902912Sartem 		if (strcmp (libhal_volume_get_fstype (volume), "vfat") != 0 &&
7912912Sartem 		    strcmp (libhal_volume_get_fstype (volume), "iso9660") != 0 &&
7922912Sartem 		    strcmp (libhal_volume_get_fstype (volume), "udf") != 0) {
7932912Sartem 			pol_change_uid = wants_to_change_uid;
7942912Sartem 		}
7952912Sartem 	}
7962912Sartem 
7972912Sartem 	if (pol_is_fixed) {
7982912Sartem 		if (pol_change_uid) {
7992912Sartem 			privilege = "hal-storage-fixed-mount-all-options";
8002912Sartem 		} else {
8012912Sartem 			privilege = "hal-storage-fixed-mount";
8022912Sartem 		}
8032912Sartem 	} else {
8042912Sartem 		if (pol_change_uid) {
8052912Sartem 			privilege = "hal-storage-removable-mount-all-options";
8062912Sartem 		} else {
8072912Sartem 			privilege = "hal-storage-removable-mount";
8082912Sartem 		}
8092912Sartem 	}
8102912Sartem 
8112912Sartem #ifdef DEBUG
8122912Sartem 	printf ("using privilege %s for uid %s, system_bus_connection %s\n", privilege, invoked_by_uid,
8132912Sartem 		invoked_by_syscon_name);
8142912Sartem #endif
8152912Sartem 
8162912Sartem #ifdef HAVE_POLKIT
8172912Sartem 	if (libpolkit_is_uid_allowed_for_privilege (pol_ctx,
8182912Sartem 						    invoked_by_syscon_name,
8192912Sartem 						    invoked_by_uid,
8202912Sartem 						    privilege,
8212912Sartem 						    udi,
8222912Sartem 						    &allowed_by_privilege,
8232912Sartem 						    &is_temporary_privilege,
8242912Sartem 						    NULL) != LIBPOLKIT_RESULT_OK) {
8252912Sartem 		printf ("cannot lookup privilege\n");
8262912Sartem 		unknown_error ("Cannot lookup privilege from PolicyKit");
8272912Sartem 	}
8282912Sartem 
8292912Sartem 	if (!allowed_by_privilege) {
8302912Sartem 		printf ("caller don't possess privilege\n");
8312912Sartem 		permission_denied_privilege (privilege, invoked_by_uid);
8322912Sartem 	}
8332912Sartem #endif
8342912Sartem 
8352912Sartem #ifdef DEBUG
8362912Sartem 	printf ("passed privilege\n");
8372912Sartem #endif
8382912Sartem 
8392912Sartem 	if (!is_remount) {
8402912Sartem 		/* create directory */
8412912Sartem #ifdef sun
8423502Sartem 		if (!g_file_test (mount_dir, G_FILE_TEST_EXISTS) &&
8433502Sartem 		    (g_mkdir (mount_dir, 0755) != 0)) {
8443502Sartem #else
8453502Sartem 		if (g_mkdir (mount_dir, 0700) != 0) {
8462912Sartem #endif
8472912Sartem 			printf ("Cannot create '%s'\n", mount_dir);
8482912Sartem 			unknown_error ("Cannot create mount directory");
8492912Sartem 		}
8502912Sartem 
8512912Sartem #ifdef __FreeBSD__
8522912Sartem 		calling_uid = (uid_t) strtol (invoked_by_uid, (char **) NULL, 10);
8532912Sartem 		pw = getpwuid (calling_uid);
8542912Sartem 		if (pw != NULL) {
8552912Sartem 			calling_gid = pw->pw_gid;
8562912Sartem 		} else {
8572912Sartem 			calling_gid = 0;
8582912Sartem 		}
8592912Sartem 		if (chown (mount_dir, calling_uid, calling_gid) != 0) {
8602912Sartem 			printf ("Cannot chown '%s' to uid: %d, gid: %d\n", mount_dir,
8612912Sartem 				calling_uid, calling_gid);
8622912Sartem 			g_rmdir (mount_dir);
8632912Sartem 			unknown_error ();
8642912Sartem 		}
8652912Sartem #endif
8662912Sartem 	}
8672912Sartem 
8682912Sartem 	char *mount_option_commasep = NULL;
8692912Sartem 	char *mount_do_fstype = "auto";
8702912Sartem 
8712912Sartem 	/* construct arguments to mount */
8722912Sartem 	na = 0;
8732912Sartem 	args[na++] = MOUNT;
8742912Sartem 	if (strlen (mount_fstype) > 0) {
8752912Sartem 		mount_do_fstype = (char *) map_fstype (mount_fstype);
8762912Sartem 	} else if (volume == NULL) {
8772912Sartem 		/* non-pollable drive; force auto */
8782912Sartem 		mount_do_fstype = "auto";
8792912Sartem 	} else if (libhal_volume_get_fstype (volume) != NULL && strlen (libhal_volume_get_fstype (volume)) > 0) {
8802912Sartem 		mount_do_fstype = (char *) map_fstype (libhal_volume_get_fstype (volume));
8812912Sartem 	}
8822912Sartem 	args[na++] = MOUNT_TYPE_OPT;
8832912Sartem 	args[na++] = mount_do_fstype;
8842912Sartem 
8852912Sartem 	args[na++] = "-o";
8862912Sartem 	mount_option_str = g_string_new (MOUNT_OPTIONS);
8872912Sartem 	for (i = 0; given_options[i] != NULL; i++) {
8882912Sartem 		g_string_append (mount_option_str, ",");
8892912Sartem 		g_string_append (mount_option_str, given_options[i]);
8902912Sartem 	}
8912912Sartem #ifdef sun
8922912Sartem 	if (append_ro) {
8932912Sartem 		g_string_append (mount_option_str, ",ro");
8942912Sartem 	}
8952912Sartem #endif
8962912Sartem 	mount_option_commasep = g_string_free (mount_option_str, FALSE); /* leak! */
8972912Sartem 	args[na++] = mount_option_commasep;
8982912Sartem 	args[na++] = (char *) device;
8992912Sartem 	args[na++] = mount_dir;
9002912Sartem 	args[na++] = NULL;
9012912Sartem 
9022912Sartem 	/* TODO FIXME XXX HACK: OK, so we should rewrite the options in /media/.hal-mtab ..
9032912Sartem 	 *                      but it doesn't really matter much at this point */
9042912Sartem 	if (!is_remount) {
9052912Sartem 		FILE *hal_mtab;
9062912Sartem 		char *mount_dir_escaped;
9072912Sartem 		FILE *hal_mtab_orig;
9082912Sartem 		int hal_mtab_orig_len;
9092912Sartem 		int num_read;
9102912Sartem 		char *hal_mtab_buf;
9112912Sartem 		char *hal_mtab_buf_old;
9122912Sartem 
9132912Sartem 		/* Maintain a list in /media/.hal-mtab with entries of the following format
9142912Sartem 		 *
9152912Sartem 		 *  <device_file>\t<uid>\t<session-id>\t<fstype>\t<options_sep_by_comma>\t<mount point>\n
9162912Sartem 		 *
9172912Sartem 		 * where session-id currently is unused and thus set to 0.
9182912Sartem 		 *
9192912Sartem 		 * Example:
9202912Sartem 		 *
9212912Sartem 		 *  /dev/sda2	500	0	hfsplus	noexec,nosuid,nodev	/media/Macintosh HD
9222912Sartem 		 *  /dev/sda4	500	0	ntfs	noexec,nosuid,nodev,umask=222	/media/Windows
9232912Sartem 		 *  /dev/sdb1	500	0	vfat	noexec,nosuid,nodev,shortname=winnt,uid=500	/media/davidz
9242912Sartem 		 */
9252912Sartem 
9262912Sartem 
9272912Sartem 		if (g_file_test ("/media/.hal-mtab", G_FILE_TEST_EXISTS)) {
9282912Sartem 			hal_mtab_orig = fopen ("/media/.hal-mtab", "r");
9292912Sartem 			if (hal_mtab_orig == NULL) {
9302912Sartem 				unknown_error ("Cannot open /media/.hal-mtab");
9312912Sartem 			}
9322912Sartem 			if (fseek (hal_mtab_orig, 0L, SEEK_END) != 0) {
9332912Sartem 				unknown_error ("Cannot seek to end of /media/.hal-mtab");
9342912Sartem 			}
9352912Sartem 			hal_mtab_orig_len = ftell (hal_mtab_orig);
9362912Sartem 			if (hal_mtab_orig_len < 0) {
9372912Sartem 				unknown_error ("Cannot determine size of /media/.hal-mtab");
9382912Sartem 			}
9392912Sartem 			rewind (hal_mtab_orig);
9402912Sartem 			hal_mtab_buf = g_new0 (char, hal_mtab_orig_len + 1);
9412912Sartem 			num_read = fread (hal_mtab_buf, 1, hal_mtab_orig_len, hal_mtab_orig);
9422912Sartem 			if (num_read != hal_mtab_orig_len) {
9432912Sartem 				unknown_error ("Cannot read from /media/.hal-mtab");
9442912Sartem 			}
9452912Sartem 			fclose (hal_mtab_orig);
9462912Sartem 		} else {
9472912Sartem 			hal_mtab_buf = g_strdup ("");
9482912Sartem 		}
9492912Sartem 
9502912Sartem 		mount_dir_escaped = g_strescape (mount_dir, NULL);
9512912Sartem #ifdef DEBUG
9522912Sartem 		printf ("%d: XYA creating /media/.hal-mtab~\n", getpid ());
9532912Sartem #endif
9542912Sartem 		hal_mtab = fopen ("/media/.hal-mtab~", "w");
9552912Sartem 		if (hal_mtab == NULL) {
9562912Sartem 			unknown_error ("Cannot create /media/.hal-mtab~");
9572912Sartem 		}
9582912Sartem 		hal_mtab_buf_old = hal_mtab_buf;
9592912Sartem 		hal_mtab_buf = g_strdup_printf ("%s%s\t%s\t0\t%s\t%s\t%s\n",
9602912Sartem 						hal_mtab_buf_old,
9612912Sartem 						device, invoked_by_uid, mount_do_fstype,
9622912Sartem 						mount_option_commasep, mount_dir_escaped);
9632912Sartem 		g_free (hal_mtab_buf_old);
9642912Sartem 		if (hal_mtab_buf_old == NULL) {
9652912Sartem 			unknown_error ("Out of memory appending to /media/.hal-mtab~");
9662912Sartem 		}
9672912Sartem 		if (fwrite (hal_mtab_buf, 1, strlen (hal_mtab_buf), hal_mtab) != strlen (hal_mtab_buf)) {
9682912Sartem 			unknown_error ("Cannot write to /media/.hal-mtab~");
9692912Sartem 		}
9702912Sartem 		fclose (hal_mtab);
9712912Sartem 		g_free (hal_mtab_buf);
9722912Sartem 		g_free (mount_dir_escaped);
9732912Sartem #ifdef DEBUG
9742912Sartem 		printf ("%d: XYA closing /media/.hal-mtab~\n", getpid ());
9752912Sartem #endif
9762912Sartem 	} /* !is_remount */
9772912Sartem 
9782912Sartem 	/* now try to mount */
9792912Sartem 	if (!g_spawn_sync ("/",
9802912Sartem 			   args,
9812912Sartem 			   NULL,
9822912Sartem 			   0,
9832912Sartem 			   NULL,
9842912Sartem 			   NULL,
9852912Sartem 			   &sout,
9862912Sartem 			   &serr,
9872912Sartem 			   &exit_status,
9882912Sartem 			   &err)) {
9892912Sartem 		printf ("Cannot execute %s\n", MOUNT);
9902912Sartem 		g_rmdir (mount_dir);
9912912Sartem 		unlink ("/media/.hal-mtab~");
9922912Sartem 		unknown_error ("Cannot spawn " MOUNT);
9932912Sartem 	}
9942912Sartem 
9952912Sartem 
9962912Sartem 	if (exit_status != 0) {
9972912Sartem 		char errstr[]  = "mount: unknown filesystem type";
9982912Sartem 
9992912Sartem 		printf ("%s error %d, stdout='%s', stderr='%s'\n", MOUNT, exit_status, sout, serr);
10002912Sartem 
10012912Sartem 		if (!is_remount) {
10022912Sartem 			g_rmdir (mount_dir);
10032912Sartem 			unlink ("/media/.hal-mtab~");
10042912Sartem 		}
10052912Sartem 
10062912Sartem 		if (strncmp (errstr, serr, sizeof (errstr) - 1) == 0) {
10072912Sartem 			unknown_filesystem (strlen (mount_fstype) > 0 ?
10082912Sartem 					    mount_fstype :
10092912Sartem 					    (volume != NULL ? libhal_volume_get_fstype (volume) : "") );
10102912Sartem 		} else {
10112912Sartem 			int n;
10122912Sartem 			for (n = 0; serr[n] != '\0'; n++) {
10132912Sartem 				if (serr[n] == '\n') {
10142912Sartem 					serr[n] = ' ';
10152912Sartem 				}
10162912Sartem 			}
10172912Sartem 			unknown_error (serr);
10182912Sartem 		}
10192912Sartem 	}
10202912Sartem 
10212912Sartem 	if (!is_remount) {
10222912Sartem 		if (rename ("/media/.hal-mtab~", "/media/.hal-mtab") != 0) {
10232912Sartem 			printf ("rename(2) failed, errno=%d -> '%s'\n", errno, strerror (errno));
10242912Sartem 			unlink ("/media/.hal-mtab~");
10252912Sartem #ifdef DEBUG
10262912Sartem 			printf ("%d: XYA failed renaming /media/.hal-mtab~ to /media/.hal-mtab\n", getpid ());
10272912Sartem #endif
10282912Sartem 			unknown_error ("Cannot rename /media/.hal-mtab~ to /media/.hal-mtab");
10292912Sartem 		}
10302912Sartem #ifdef DEBUG
10312912Sartem 		printf ("%d: XYA done renaming /media/.hal-mtab~ to /media/.hal-mtab\n", getpid ());
10322912Sartem #endif
10332912Sartem 	}
10342912Sartem 
10352912Sartem 	openlog ("hald", 0, LOG_DAEMON);
10362912Sartem 	if (is_remount) {
10372912Sartem 		syslog (LOG_INFO, "remounted %s at '%s' on behalf of uid %s", device, mount_dir, invoked_by_uid);
10382912Sartem 	} else {
10392912Sartem 		syslog (LOG_INFO, "mounted %s on behalf of uid %s", device, invoked_by_uid);
10402912Sartem 	}
10412912Sartem 	closelog ();
10422912Sartem 
10432912Sartem #ifdef sun
10442912Sartem 	if ((adt_data = get_audit_export_data (system_bus,
10452912Sartem 	    invoked_by_syscon_name, &adt_data_size)) != NULL) {
10462912Sartem 		audit_volume (adt_data, ADT_attach,
10472912Sartem 		    WEXITSTATUS(exit_status), auth_from_privilege(privilege),
10482912Sartem 		    mount_dir, device, mount_option_commasep);
10492912Sartem 		free (adt_data);
10502912Sartem 	}
10512912Sartem #endif
10522912Sartem 
10532912Sartem 	g_free (sout);
10542912Sartem 	g_free (serr);
10552912Sartem 	g_free (mount_dir);
10562912Sartem 	libhal_free_string_array (allowed_options);
10572912Sartem 	g_strfreev (given_options);
10582912Sartem }
10592912Sartem 
10602912Sartem 
10612912Sartem int
10622912Sartem main (int argc, char *argv[])
10632912Sartem {
10642912Sartem 	char *udi;
10652912Sartem 	char *device;
10662912Sartem 	LibHalVolume *volume;
10672912Sartem 	DBusError error;
10682912Sartem 	LibHalContext *hal_ctx = NULL;
10692912Sartem 	DBusConnection *system_bus = NULL;
10702912Sartem #ifdef HAVE_POLKIT
10712912Sartem 	LibPolKitContext *pol_ctx = NULL;
10722912Sartem #endif
10732912Sartem 	char *invoked_by_uid;
10742912Sartem 	char *invoked_by_syscon_name;
10752912Sartem 
10762912Sartem 	if (!lock_hal_mtab ()) {
10772912Sartem 		unknown_error ("Cannot obtain lock on /media/.hal-mtab");
10782912Sartem 	}
10792912Sartem 
10802912Sartem 	device = getenv ("HAL_PROP_BLOCK_DEVICE");
10812912Sartem 	if (device == NULL)
10822912Sartem 		usage ();
10832912Sartem 
10842912Sartem 	udi = getenv ("HAL_PROP_INFO_UDI");
10852912Sartem 	if (udi == NULL)
10862912Sartem 		usage ();
10872912Sartem 
10882912Sartem 	invoked_by_uid = getenv ("HAL_METHOD_INVOKED_BY_UID");
10892912Sartem 
10902912Sartem 	invoked_by_syscon_name = getenv ("HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME");
10912912Sartem 
10922912Sartem 	dbus_error_init (&error);
10932912Sartem 	if ((hal_ctx = libhal_ctx_init_direct (&error)) == NULL) {
10942912Sartem 		printf ("Cannot connect to hald\n");
10952912Sartem 		LIBHAL_FREE_DBUS_ERROR (&error);
10962912Sartem 		usage ();
10972912Sartem 	}
10982912Sartem 
10992912Sartem 	dbus_error_init (&error);
11002912Sartem 	system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
11012912Sartem 	if (system_bus == NULL) {
11022912Sartem 		printf ("Cannot connect to the system bus\n");
11032912Sartem 		LIBHAL_FREE_DBUS_ERROR (&error);
11042912Sartem 		usage ();
11052912Sartem 	}
11062912Sartem #ifdef HAVE_POLKIT
11072912Sartem 	pol_ctx = libpolkit_new_context (system_bus);
11082912Sartem 	if (pol_ctx == NULL) {
11092912Sartem 		printf ("Cannot get libpolkit context\n");
11102912Sartem 		unknown_error ("Cannot get libpolkit context");
11112912Sartem 	}
11122912Sartem #endif
11132912Sartem 
11142912Sartem 	volume = libhal_volume_from_udi (hal_ctx, udi);
11152912Sartem 	if (volume == NULL) {
11162912Sartem 		LibHalDrive *drive;
11172912Sartem 
11182912Sartem 		drive = libhal_drive_from_udi (hal_ctx, udi);
11192912Sartem 		if (drive == NULL) {
11202912Sartem 			usage ();
11212912Sartem 		} else {
11222912Sartem 			handle_mount (hal_ctx,
11232912Sartem #ifdef HAVE_POLKIT
11242912Sartem 				      pol_ctx,
11252912Sartem #endif
11262912Sartem 				      udi, NULL, drive, device, invoked_by_uid,
11272912Sartem 				      invoked_by_syscon_name, system_bus);
11282912Sartem 		}
11292912Sartem 
11302912Sartem 	} else {
11312912Sartem 		const char *drive_udi;
11322912Sartem 		LibHalDrive *drive;
11332912Sartem 
11342912Sartem 		drive_udi = libhal_volume_get_storage_device_udi (volume);
11352912Sartem 
11362912Sartem 		if (drive_udi == NULL)
11372912Sartem 			unknown_error ("Cannot get drive_udi from volume");
11382912Sartem 		drive = libhal_drive_from_udi (hal_ctx, drive_udi);
11392912Sartem 		if (drive == NULL)
11402912Sartem 			unknown_error ("Cannot get drive from hal");
11412912Sartem 
11422912Sartem 		handle_mount (hal_ctx,
11432912Sartem #ifdef HAVE_POLKIT
11442912Sartem 			      pol_ctx,
11452912Sartem #endif
11462912Sartem 			      udi, volume, drive, device, invoked_by_uid,
11472912Sartem 			      invoked_by_syscon_name, system_bus);
11482912Sartem 
11492912Sartem 	}
11502912Sartem 
11512912Sartem 	unlock_hal_mtab ();
11522912Sartem 
11532912Sartem 	return 0;
11542912Sartem }
1155