[patch] progress with autofs.

Luke Kenneth Casson Leighton lkcl at lkcl.net
Fri Sep 24 08:05:37 PDT 2004


okay, here y'go.

btw, about the size of the modifications to fsync-fstab.c?  ... i lied :)

... well, not exactly.  most of them are very obviously trivial:
g/s/r _FSTAB_PATH with fstab_path local variable accounts for
a good hundred patch lines.

comments account for a lot more.

review:

- added new config option "autofs_in_use" to hald.conf please think of a
  better name!

- added some cru-joze (viz, "nasty", "yuk") commented-out code that
  kills all processes stone dead on a umount.

- added a comment about the ioctl reread partition failing.

- in detect_media, set the volume.automount_point from the _parent_'s
  block.automount_point [kindly set up by fstab-sync in autofs mode]

- corrected spelling mistake "unfortunately".

- do the same as in detect_media, but for a first-time create.
  also, send a VolumeMount notification via dbus.

- find_mtab_index and delete_mtab_index irreverant functions i was
  going to mess about with mtab.  i like these functions so can't
  bring myself to delete them.  sentimental, one 2 3 ahh..

- get_parent_automount_point does the searching of the parent
  automount point from a child's "info.parent" udi if you happen
  not to have the parent structure hanging about.

- in mtab_handle_volume, stop a VolumeUmount signal from being sent
  if running in autofs mode.

  ... you know, i'm not so sure this is necessary [to stop
  this], esp. in light of examining KVM, which doesn't actually
  use these signals at all.

  what KVM does is use "a" notify to _re-read_ the entire HAL list
  *gibber* and it seems to react from changes _it_ detects rather than
  relying on dbus notifications.

  anyway, KVM could detect the volume.automount_point string and react
  accordingly (i.e. to ignore the spurious VolumeMount and VolumeUnmount
  signals).

- in hald_helper_hotplug, corrected spelling mistake "couldn't".

- large amounts of usage comments that should probably go in a README.

- added index table of fstab_fields and autofs_fields - this is part
  of the reuse of the /etc/fstab reading code to read /etc/auto.hal.

  i added in a means to "prefix" fields with "," ":" and "-fstype="
  as appropriate, and modified the parsing code to look for these
  tokens in the right places.

  i don't claim this code to be perfect: if someone puts an autofs
  line of "-ro" which is perfectly acceptable (an implicit -fstype=
  option) then the code will break.

  tough.

- set_hal_automount_point: this function is responsible for putting
  the FULL path to the automount point into the hal database for the
  block udi.
  
  yes, the block, no, not the child volume.
  
  no, fstab-sync doesn't get called for volumes, it gets called
  for block devices.

- reshuffled fs_table_has_volume() because if there's one thing
  about code that DRIVES ME UP THE WALL it's functions that have seven
  layers of indents and are so bloody big they have to have their own
  traffic cops (a la if { ... } /* ends if numbered 192 point 6 */)

  diff got a bit confused and started weaving the three new
  functions i split fs_table_has_volume() into in and out of
  each other.  so i "massaged" the location of those until the
  problem went away.

- split fs_table_has_volume() into check_block_field_device() and
  commented that it has side-effects - namely it can update the
  automount point back into hal and also update the block device
  into hal if it discovers that the block device (e.g. /dev/cdrom)
  is a symlink.
 
- split fs_table_has_volume() into check_mount_by_label() and
  commented that autofs could do with some integration with it,
  i think the label idea is cool.
 
- stopped create_mount_point_for_volume() from doing a mkdir
  in an autofs-managed area!  this is really important!

  also stopped a stat from occuring (it's all Bad for autofs).

- changed semantics of creation of mountpoint name for autofs:
  /etc/auto.master stores the prefix of the mountpoint, and
  the child "/etc/auto.hal" config file stores the relative directory
  name of the mountpoint(s).

 
that's mostly it.  bored now.  wanna do the next challenge.

happy hacking.

l.

-- 
--
Truth, honesty and respect are rare commodities that all spring from
the same well: Love.  If you love yourself and everyone and everything
around you, funnily and coincidentally enough, life gets a lot better.
--
<a href="http://lkcl.net">      lkcl.net      </a> <br />
<a href="mailto:lkcl at lkcl.net"> lkcl at lkcl.net </a> <br />

-------------- next part --------------
diff -udpr --exclude='config*' ../tmp/hal-0.2.97+cvs20040907/README ./README
--- ../tmp/hal-0.2.97+cvs20040907/README	2003-12-24 00:55:38.000000000 +0000
+++ ./README	2004-09-23 22:20:29.000000000 +0100
@@ -1,8 +1,6 @@
 
 HAL is a hardware abstraction layer
 
-See also the file HACKING for notes of interest to developers working on HAL.
-
 See http://www.freedesktop.org/Software/hal for lots of documentation, 
 mailing lists, etc.
 
diff -udpr --exclude='config*' ../tmp/hal-0.2.97+cvs20040907/hal.conf ./hal.conf
--- ../tmp/hal-0.2.97+cvs20040907/hal.conf	2004-09-07 21:00:50.000000000 +0100
+++ ./hal.conf	2004-09-23 22:20:48.000000000 +0100
@@ -7,9 +7,9 @@
   <!-- This configuration file specifies the required security policies
        for the HAL to work. -->
 
-  <!-- Only user haldaemon can own the HAL service and be an agent -->
-  <!-- policy user="haldaemon" We require root to sniff mii registers -->
-  <policy user="haldaemon">
+  <!-- Only user root can own the HAL service and be an agent -->
+  <!-- policy user="root" We require root to sniff mii registers -->
+  <policy user="root">
     <allow own="org.freedesktop.Hal"/>
 
     <allow send_interface="org.freedesktop.Hal.AgentManager"
@@ -28,7 +28,7 @@
 
   <!-- Any user in the haldaemon group can use the AgentManager interface -->
   <!-- policy group="haldaemon" Doesn't work on dbus 0.20. Works in CVS -->
-  <policy user="haldaemon">
+  <policy user="root">
     <allow send_interface="org.freedesktop.Hal.AgentManager"
            send_destination="org.freedesktop.Hal"/>
     <allow receive_interface="org.freedesktop.Hal.AgentManager"
diff -udpr --exclude='config*' ../tmp/hal-0.2.97+cvs20040907/hald/hald_conf.c ./hald/hald_conf.c
--- ../tmp/hal-0.2.97+cvs20040907/hald/hald_conf.c	2004-08-12 20:54:03.000000000 +0100
+++ ./hald/hald_conf.c	2004-09-22 23:07:24.000000000 +0100
@@ -43,7 +43,8 @@
 static HaldConf hald_conf = {
 	TRUE,  /* storage.media_check_enabled */
 	TRUE,  /* storage.automount_enabled_hint */
-	FALSE  /* persistent_device_list */
+	FALSE, /* persistent_device_list */
+	FALSE  /* autofs_in_use */
 };
 
 HaldConf *
@@ -115,9 +116,11 @@ end (ParsingContext * pc, const char *el
 	} else if ((strcmp (key, "persistent_device_list") == 0) &&
 		   (strcmp (value, "true") == 0)) {
 		hald_conf.persistent_device_list = TRUE;
+	} else if ((strcmp (key, "autofs_in_use") == 0) &&
+		   (strcmp (value, "true") == 0)) {
+		hald_conf.autofs_in_use = TRUE;
 	}
 
-
 	pc->elem[0] = '\0';
 	pc->cdata_buf[0] = '\0';
 	pc->cdata_buf_len = 0;
diff -udpr --exclude='config*' ../tmp/hal-0.2.97+cvs20040907/hald/hald_conf.h ./hald/hald_conf.h
--- ../tmp/hal-0.2.97+cvs20040907/hald/hald_conf.h	2004-08-12 20:54:03.000000000 +0100
+++ ./hald/hald_conf.h	2004-09-22 23:06:42.000000000 +0100
@@ -71,6 +71,18 @@ struct _HaldConf {
          *  properties are kept between invocations of hald.
 	 */
 	dbus_bool_t persistent_device_list;
+
+	/** If true, then the behaviour of hald matches the use of
+	 *  autofs (automount - /etc/auto.hal) instead of a static
+	 *  fstab expectations.
+	 *
+	 *  Basically it doesn't keep on generating mount notifications
+	 *  just because autofs automatically unmounts a volume, which
+	 *  would get _excruciatingly_ boring for users when the autofs
+	 *  timeout is set to oh, say, two seconds.
+     *  
+	 */
+	dbus_bool_t autofs_in_use;
 };
 
 HaldConf *hald_get_conf (void);
diff -udpr --exclude='config*' ../tmp/hal-0.2.97+cvs20040907/hald/linux/block_class_device.c ./hald/linux/block_class_device.c
--- ../tmp/hal-0.2.97+cvs20040907/hald/linux/block_class_device.c	2004-09-04 09:51:13.000000000 +0100
+++ ./hald/linux/block_class_device.c	2004-09-24 15:06:46.000000000 +0100
@@ -369,6 +369,21 @@ force_unmount (HalDevice * d)
 	    strlen (device_mount_point) > 0) {
 		HAL_INFO (("attempting /bin/umount -l %s", device_file));
 
+#ifdef HA_HA_ONLY_IF_TOTALLY_DESPERATE_BUT_IT_WORKS_IT_REALLY_DOES
+		    {
+				/* forced kill -TERM of all programs using this mount point! */
+				/* has to be done _before_ the umount because otherwise
+				 * you find there's apparently nothing using it...
+				 *
+				 * all because of a bug in linux 2.6 kernel where
+				 * BLKRREAD ioctl (partition reread) on a block device
+				 * doesn't work ("Device or Resource busy").
+				 */
+				char cmd[512];
+				 sprintf(cmd, "lsof %s | cut -f2 -d' '| sort | uniq | xargs kill -TERM", device_mount_point);
+				 system(cmd);
+			}
+#endif
 		/* invoke umount */
 		if (g_spawn_sync ("/",
 				  (char **) umount_argv,
@@ -418,6 +433,7 @@ force_unmount (HalDevice * d)
 					      FALSE);
 			device_property_atomic_update_end ();
 */
+
 		}
 	}
 }
@@ -457,7 +473,9 @@ force_unmount_of_all_childs (HalDevice *
 			   device_file));
 		fd = open (device_file, O_RDONLY | O_NONBLOCK);
 		if (fd != -1) {
-			ioctl (fd, BLKRRPART);
+			if (ioctl (fd, BLKRRPART) != 0)
+			HAL_INFO (("Ioctl BLK re-read partition for %s failed: %s",
+				   device_file, strerror(errno)));
 		}
 		close (fd);
 
@@ -948,6 +966,18 @@ detect_media (HalDevice * d, dbus_bool_t
 		hal_device_property_set_bool (child, "volume.is_mounted", FALSE);
 		hal_device_property_set_bool (child, "volume.is_disc", is_cdrom);
 
+		if (hald_get_conf()->autofs_in_use)
+		{
+			/* get parent's block automount_point (kindly set by fstab-sync
+			 * for us) and set the volume child's automount point.
+			 */
+			const char *mp = hal_device_property_get_string (d,
+									  "block.automount_point");
+			hal_device_property_set_string (child, "volume.automount_point",
+					                    mp ? mp : "");
+						  
+		}
+
 		/* set the size */
 		volume_set_size (child, force_poll);
 
@@ -983,7 +1013,7 @@ detect_media (HalDevice * d, dbus_bool_t
 			}
 		}
 
-		/* Unfortunally, linux doesn't scan optical discs for partition
+		/* Unfortunately, linux doesn't scan optical discs for partition
 		 * tables. We only get the main device, the kernel doesn't
 		 * create childs for us.
 		 */
@@ -1033,8 +1063,46 @@ detect_media (HalDevice * d, dbus_bool_t
 			G_CALLBACK (class_device_move_from_tdl_to_gdl), cad);
 		hal_callout_device (child, TRUE);
 
+		/* When using AutoFS instead of manual mount, we _do not_
+		 * want VolumeMount and VolumeUnmounts to be triggered via
+		 * changes in /etc/mtab.
+		 * instead, we notify here ONCE per volume (and notify again
+		 * when the volume is deleted obviously).
+		 *
+		 * I AM COUNTING ON hal_callout_device() above to have updated
+		 * the block.automount_point, by fstab-sync (in autofs mode) setting
+		 * it.  ha ha.
+		 *
+		 * the behaviour is different because of course autofs doesn't
+		 * actually let you see the directory, so it is _essential_ that
+		 * this notify be done (and not be removed until the volume is
+		 * removed by the user).
+		 */
+		if (hald_get_conf()->autofs_in_use)
+		{
+			const char *mount_point = hal_device_property_get_string ( child,
+						"block.automount_point");
+			const char *block_device = hal_device_property_get_string ( child,
+						"block.device");
+
+			if (mount_point != NULL && block_device != NULL)
+			{
+				HAL_INFO (("%s is auto-mounted at %s, udi=%s",
+						block_device, mount_point, child->udi));
+
+				device_send_signal_condition (
+					child,
+					"VolumeMount",
+					DBUS_TYPE_STRING,
+					block_device,
+					DBUS_TYPE_STRING,
+					mount_point,
+					DBUS_TYPE_INVALID);
+			}
+		}
 		volume_id_close (vid);
 		close (fd);
+
 		return TRUE;
 	}
 
@@ -1754,6 +1822,40 @@ static int num_mount_points;
 
 static int etc_fd = -1;
 
+static int find_mtab_index(char *device)
+{
+	int idx;
+	for (idx = 0; idx < num_mount_points; idx++)
+	{
+		if (strcmp(mount_points->device, device) == 0)
+			return idx;
+	}
+	return -1;
+}
+
+/* deletes an entry if it exists, shuffles entries... */
+static void delete_mtab_entry(char *device)
+{
+	int locate = find_mtab_index(device);
+	int idx;
+
+	if (locate == -1)
+		return;
+
+	/* move'em'all down, yee-haah */
+	for (idx = locate; idx < num_mount_points-1; idx++)
+	{
+		memmove(&mount_points[idx+1], &mount_points[idx],
+				 sizeof(struct mount_point_s));
+	}
+	num_mount_points--;
+	if (num_mount_points != MOUNT_POINT_MAX-1)
+	{
+		mount_points[num_mount_points].device[0] = '\0';
+		mount_points[num_mount_points].mount_point[0] = '\0';
+		mount_points[num_mount_points].fs_type[0] = '\0';
+	}
+}
 
 /** Process a line in /etc/mtab. The given string will be modifed by
  *  this function.
@@ -1957,6 +2059,25 @@ mtab_handle_storage (HalDevice *d)
 	return TRUE;
 }
 
+char *get_parent_automount_point(HalDevice *d)
+{
+	const char *ps;
+	HalDevice *p = NULL;
+	char *mp = "";
+	if (hald_get_conf()->autofs_in_use)
+		return mp;
+	ps = hal_device_property_get_string (d, "info.parent");
+	if (ps == NULL)
+		return mp;
+	p = hal_device_store_find (hald_get_gdl (), ps);
+	if (p == NULL)
+		return mp;
+	mp = hal_device_property_get_string (p, "block.automount_point");
+	if (mp == NULL)
+		mp = "";
+	return mp;
+}
+
 static gboolean
 mtab_handle_volume (HalDevice *d)
 {
@@ -2007,6 +2128,12 @@ mtab_handle_volume (HalDevice *d)
 						      "volume.is_mounted",
 						      TRUE);
 
+			if (hald_get_conf()->autofs_in_use)
+			{
+				hal_device_property_set_string (d,
+								"volume.automount_point",
+				              get_parent_automount_point(d));
+			}
 			/* only overwrite block.device if it's not set */
 			if (existing_block_device == NULL ||
 			    (existing_block_device != NULL &&
@@ -2054,22 +2181,27 @@ mtab_handle_volume (HalDevice *d)
 
 		hal_device_property_set_bool (d, "volume.is_mounted",
 					      FALSE);
-		hal_device_property_set_string (d, "volume.mount_point",
-						"");
+		hal_device_property_set_string (d, "volume.mount_point", "");
 
 		device_property_atomic_update_end ();
 
 		if (was_mounted) {
-			device_send_signal_condition (
-				d, "VolumeUnmount",
-				DBUS_TYPE_STRING,
-				hal_device_property_get_string (
-					d,
-					"block.device"),
-				DBUS_TYPE_STRING,
-				device_mount_point,
-				DBUS_TYPE_INVALID);
-
+			if (hald_get_conf()->autofs_in_use)
+			{
+				/* only send an umount notification when we are in
+				 * fstab-sync "standard" mode as opposed to using
+				 * "autofs".
+				 */
+				device_send_signal_condition (
+					d, "VolumeUnmount",
+					DBUS_TYPE_STRING,
+					hal_device_property_get_string (
+						d,
+						"block.device"),
+					DBUS_TYPE_STRING,
+					device_mount_point,
+					DBUS_TYPE_INVALID);
+			}
 			/* Alrighty, we were unmounted and we are some media without
 			 * partition tables and we don't like to be polled. So now
 			 * the user could actually remove the media and insert some
diff -udpr --exclude='config*' ../tmp/hal-0.2.97+cvs20040907/hald/linux/osspec.c ./hald/linux/osspec.c
--- ../tmp/hal-0.2.97+cvs20040907/hald/linux/osspec.c	2004-09-07 21:36:45.000000000 +0100
+++ ./hald/linux/osspec.c	2004-09-16 18:58:21.000000000 +0100
@@ -854,7 +854,7 @@ add_device (const char *sysfs_path, cons
 
 			class_device = sysfs_open_class_device_path (sysfs_path);
 			if (class_device == NULL) {
-				HAL_WARNING (("Coulnd't get sysfs class device object at "
+				HAL_WARNING (("Couldn't get sysfs class device object at "
 					      "path %s", sysfs_path));
 				return NULL;
 			}
diff -udpr --exclude='config*' ../tmp/hal-0.2.97+cvs20040907/tools/fstab-sync.c ./tools/fstab-sync.c
--- ../tmp/hal-0.2.97+cvs20040907/tools/fstab-sync.c	2004-09-01 17:47:06.000000000 +0100
+++ ./tools/fstab-sync.c	2004-09-24 15:38:10.000000000 +0100
@@ -1,6 +1,8 @@
 /* -*- mode: C; c-file-style: "gnu" -*- */
 /* Copyright 2004 Red Hat, Inc.
  *
+ * Copyright (C) 2004 Luke Kenneth Casson Leighton <lkcl at lkcl.net>
+ *
  * This software may be freely redistributed under the terms of the GNU
  * Lesser General Public license.
  *
@@ -35,6 +37,51 @@
  * /etc/fstab being on a tmpfs or ramfs)
  */
 
+/* 24sep2004 lkcl: added support for autofs.
+ 
+   set two entries in /etc/fstab-sync.conf:
+
+       EXTRA_MOUNT_OPTS=uid=consoleusername,noauto,user,exec
+       AUTOFS_HAL_ROOT=/media
+
+   all of the EXTRA_MOUNT_OPTS are optional.
+
+   the defaults are:
+   
+       EXTRA_MOUNT_OPTS=noauto,user,exec
+       AUTOFS_HAL_ROOT=/media
+
+   AUTOFS_HAL_ROOT is not optional, however its location doesn't
+   _have_ to match the /etc/auto.master location: i am using
+   fusexmp [google for "fuse linux"] to proxy-redirect the entire
+   filesystem onto /mnt/home, setting auto.master to /media
+   and then setting AUTOFS_HAL_ROOT=/mnt/home/media.
+   
+   (the reason for doing this is because as of linux kernel 2.6.8,
+    open file or directory handles _still_ cause devices to return
+    "Device Busy" signals, which stops them from being unmounted
+    correctly: not even hotplug events can be generated: see
+    http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=273055)
+
+   by "cheating" and using a proxy view of the filesystem (via
+   fusexmp), programs keep filehandles open on the proxy view
+   (not on the real filesystem), thereby giving HAL and autofs a
+   chance to actually unmount the real filesystem with impunity.
+
+   p.s. remember to look in your kernel's fs/autofs4/autofs4_i.h
+   file and change the damn "negative" timeout from a minute to
+   something more respectable like 5 seconds.
+
+   TODO: make it a configuration option to determine the username
+         from who is logged in at the console.
+	 for example, usb-mount [google for "usbmount"] does this:
+           user="$(ls -l /dev/console | awk '{print $3}')"
+
+   TODO: add in "exclusion" option in fstab-sync.conf to make
+         sure certain entries don't go into /etc/auto.hal e.g.
+	 persistent hard disks.
+
+ */
 #ifdef HAVE_CONFIG_H
 #  include <config.h>
 #endif
@@ -68,7 +115,7 @@
 
 typedef int boolean;
 
-static boolean verbose = FALSE;
+static boolean verbose = TRUE;
 
 #define _(a) (a)
 #define N_(a) a
@@ -77,6 +124,21 @@ static boolean verbose = FALSE;
 #define TEMP_FSTAB_PREFIX ".fstab.hal."
 #define TEMP_FSTAB_MAX_LENGTH 64
 
+/* default file for fstab-sync in autofs mode to write and manage
+ * autofs configuration.
+ * 
+ * it's worth noting that the autofs config file *doesn't* contain
+ * the root of the mount point - that's specified in /etc/auto.master.
+ *
+ * remember to place an entry similar to this
+ * in /etc/auto.master:
+ *
+ * /media                 /etc/auto.hal --timeout 2
+ */
+#ifndef AUTOFS_SYNC_MOUNT_FILE
+#  define AUTOFS_SYNC_MOUNT_FILE "/etc/auto.hal"
+#endif
+
 #ifndef FSTAB_SYNC_MOUNT_ROOT
 #  define FSTAB_SYNC_MOUNT_ROOT "/media"
 #endif
@@ -127,9 +189,30 @@ typedef enum 
   FS_TABLE_NUM_FIELD_TYPES
 } FSTableFieldType;
 
+static FSTableFieldType fstab_fields[] =
+{
+  FS_TABLE_FIELD_TYPE_BLOCK_DEVICE,
+  FS_TABLE_FIELD_TYPE_MOUNT_POINT,
+  FS_TABLE_FIELD_TYPE_FILE_SYSTEM_TYPE,
+  FS_TABLE_FIELD_TYPE_MOUNT_OPTIONS,
+  FS_TABLE_FIELD_TYPE_DUMP_FREQUENCY,
+  FS_TABLE_FIELD_TYPE_PASS_NUMBER,
+  FS_TABLE_FIELD_TYPE_WHITE_SPACE
+};
+
+static FSTableFieldType autofs_fields[] =
+{
+  FS_TABLE_FIELD_TYPE_MOUNT_POINT,
+  FS_TABLE_FIELD_TYPE_FILE_SYSTEM_TYPE,
+  FS_TABLE_FIELD_TYPE_MOUNT_OPTIONS,
+  FS_TABLE_FIELD_TYPE_BLOCK_DEVICE,
+  FS_TABLE_FIELD_TYPE_WHITE_SPACE
+};
+
 typedef struct FSTableField
 {
   FSTableFieldType type;
+  char *prefix;
   char *value;
   struct FSTableField *next;
 } FSTableField;
@@ -160,6 +243,13 @@ typedef struct
 static LibHalContext *hal_context = NULL;
 static pid_t pid;
 
+static boolean automount = FALSE;
+static char *fstab_path;
+static char extra_mount_opts[80];
+static char autofs_root[80];
+
+static FSTableFieldType *fs_fields;
+
 static void fs_table_line_add_field (FSTableLine *line, FSTableField *field);
 static boolean fs_table_line_is_generated (FSTableLine *line);
 static void fs_table_line_update_pointer (FSTableLine *line, FSTableField *field);
@@ -283,19 +373,26 @@ static int restore_selinux_context(char 
 #endif /* HAVE_SELINUX */
 
 static FSTableField *
-fs_table_field_new (FSTableFieldType type, const char *value)
+autofs_table_field_new (FSTableFieldType type, const char *value, const char *prefix)
 {
   FSTableField *field;
 
   field = malloc (sizeof (FSTableLine));
 
   field->type = type;
+  field->prefix = prefix ? strdup(prefix) : NULL;
   field->value = strdup (value);
   field->next = NULL;
 
   return field;
 }
 
+static FSTableField *
+fs_table_field_new (FSTableFieldType type, const char *value)
+{
+  return autofs_table_field_new(type, value, NULL);
+}
+
 static void
 fs_table_field_free (FSTableField *field)
 {
@@ -305,6 +402,11 @@ fs_table_field_free (FSTableField *field
 
   field->type = FS_TABLE_FIELD_TYPE_WHITE_SPACE;
 
+  if (field->prefix != NULL)
+    {
+      free (field->prefix);
+      field->prefix = NULL;
+    }
   if (field->value != NULL)
     {
       free (field->value);
@@ -341,6 +443,44 @@ get_whitespace (const char *field, int p
 }
 
 static FSTableLine *
+autofs_table_line_new_from_field_values (const char *block_device,
+                                     const char *mount_point,
+                                     const char *fs_type,
+                                     const char *mount_options,
+                                     int dump_frequency,
+                                     int pass_number)
+{
+  FSTableLine *line;
+  FSTableField *field;
+
+  line = fs_table_line_new ();
+
+  field = autofs_table_field_new (FS_TABLE_FIELD_TYPE_MOUNT_POINT, mount_point, NULL); 
+  fs_table_line_add_field (line, field);
+  
+  field = fs_table_field_new (FS_TABLE_FIELD_TYPE_WHITE_SPACE, 
+                              get_whitespace (mount_point, 24)); 
+  fs_table_line_add_field (line, field);
+
+  field = autofs_table_field_new (FS_TABLE_FIELD_TYPE_FILE_SYSTEM_TYPE, fs_type, "-fstype="); 
+  fs_table_line_add_field (line, field);
+
+  field = autofs_table_field_new (FS_TABLE_FIELD_TYPE_MOUNT_OPTIONS, mount_options,
+	          mount_options && mount_options[0] ? "," : NULL);
+  fs_table_line_add_field (line, field);
+
+  field = fs_table_field_new (FS_TABLE_FIELD_TYPE_WHITE_SPACE, 
+                              get_whitespace (mount_options, 24)); 
+  fs_table_line_add_field (line, field);
+
+  field = autofs_table_field_new (FS_TABLE_FIELD_TYPE_BLOCK_DEVICE, block_device,
+  			block_device && block_device[0] ?  ":" : NULL);
+  fs_table_line_add_field (line, field);
+
+  return line;
+}
+
+static FSTableLine *
 fs_table_line_new_from_field_values (const char *block_device,
                                      const char *mount_point,
                                      const char *fs_type,
@@ -416,6 +556,8 @@ fs_table_line_add_field (FSTableLine *li
 
 static boolean fs_table_line_is_generated (FSTableLine *line)
 {
+	if (automount)
+		return TRUE;
 
 #ifdef FSTAB_SYNC_USE_NOOP_MOUNT_OPTION
   if (!fs_table_line_has_mount_option (line, FSTAB_SYNC_MOUNT_MANAGED_KEYWORD))
@@ -468,6 +610,24 @@ fs_table_add_line (FSTable *table, FSTab
     }
 }
 
+static void blat_output(size_t *output_string_length,
+		size_t *output_string_capacity,
+		char **output_string,
+		const char *val)
+{
+	  size_t field_length = strlen (val);
+
+	  if ((*output_string_length) + field_length >= (*output_string_capacity) - 1)
+		{
+		  (*output_string_capacity) *= 2;
+
+		  (*output_string) = realloc ((*output_string), (*output_string_capacity));
+		}
+
+	  strcpy ((*output_string) + (*output_string_length), val);
+	  (*output_string_length) += field_length; 
+}
+
 static char *
 fs_table_to_string (FSTable *table, size_t *length)
 {
@@ -488,19 +648,12 @@ fs_table_to_string (FSTable *table, size
       field = line->fields;
       while (field != NULL)
         {
-          size_t field_length;
-
-          field_length = strlen (field->value);
-
-          if (output_string_length + field_length >= output_string_capacity - 1)
-            {
-              output_string_capacity *= 2;
-
-              output_string = realloc (output_string, output_string_capacity);
-            }
-
-          strcpy (output_string + output_string_length, field->value);
-          output_string_length += field_length; 
+			if (field->prefix != NULL)
+				blat_output(&output_string_length, &output_string_capacity,
+					     &output_string, field->prefix);
+			if (field->value != NULL)
+				blat_output(&output_string_length, &output_string_capacity,
+					     &output_string, field->value);
 
           field = field->next;
         }
@@ -670,13 +823,16 @@ fs_table_parse_line (FSTable *table, con
 {
   FSTableLine *table_line;
   FSTableField *field;
-  char *field_value, *p;
+  char *field_value, *p, *prefix;
+  int fld_idx = 0;
   FSTableFieldType current_field;
   size_t i;
 
+  fstab_update_debug (_("%d: starting fs_table_parse_line: %s\n"), pid, line);
+
   table_line = fs_table_line_new ();
 
-  current_field = FS_TABLE_FIELD_TYPE_BLOCK_DEVICE;
+  current_field = fs_fields[fld_idx];
   p = (char *) line;
   i = 0;
   while (*p != '\0' && current_field <= FS_TABLE_FIELD_TYPE_WHITE_SPACE)
@@ -724,8 +880,17 @@ fs_table_parse_line (FSTable *table, con
           break;
         }
 
-      while (line[i] != '\0' && !isspace (line[i]) && i < length)
-        i++;
+	  if (automount && current_field == FS_TABLE_FIELD_TYPE_FILE_SYSTEM_TYPE)
+	  {
+		  while (line[i] != '\0' && !isspace (line[i]) && line[i] != ',' &&
+				  i < length)
+			i++;
+	  }
+	  else
+	  {
+		  while (line[i] != '\0' && !isspace (line[i]) && i < length)
+			i++;
+	  }
 
       if (i > length || (line[i] == '\0' && i < length))
         {
@@ -740,10 +905,33 @@ fs_table_parse_line (FSTable *table, con
         }
 
       assert (line + i != p);
+	  prefix = NULL;
 
-      field_value = strndup (p, line + i - p);
-      field = fs_table_field_new (current_field, field_value);
-      current_field++;
+	  if (automount && current_field == FS_TABLE_FIELD_TYPE_FILE_SYSTEM_TYPE)
+	  {
+		  /* assume it starts with -fstype= */
+		  field_value = strndup (p+8, line + i - p-8);
+		  prefix = "-fstype=";
+	  }
+	  else if (automount && current_field == FS_TABLE_FIELD_TYPE_MOUNT_OPTIONS)
+	  {
+		  field_value = strndup (p+1, line + i - p-1);
+		  if (field_value[0])
+			  prefix=",";
+	  }
+	  else if (automount && current_field == FS_TABLE_FIELD_TYPE_BLOCK_DEVICE)
+	  {
+		  field_value = strndup (p+1, line + i - p-1);
+		  prefix=":";
+	  }
+	  else
+		  field_value = strndup (p, line + i - p);
+
+	  fprintf(stderr, "%d %s ", current_field, field_value);
+
+      field = autofs_table_field_new (current_field, field_value, prefix);
+      fld_idx++;
+	  current_field = fs_fields[fld_idx];
       free (field_value);
 
       fs_table_line_add_field (table_line, field);
@@ -751,6 +939,8 @@ fs_table_parse_line (FSTable *table, con
       p = (char *) line + i;
     }
 
+  fprintf(stderr, "\n");
+
   fs_table_add_line (table, table_line);
 
   return TRUE;
@@ -983,6 +1173,144 @@ device_type_normalize (const char *devic
   return new_device_type;
 }
 
+void set_hal_automount_point(const char *udi, const char *mount_point)
+{
+  /* in automount mode, the volume.automount_point isn't going to be set
+   * up / triggered by a VolumeMount because we don't _know_ where
+   * the VolumeMount is going to end up oh dearie me.
+   *
+   * so we need to set volume.automount_point _here_ so that, in autofs
+   * mode, a VolumeMount notification can be sent (to anyone listening)
+   * and then KVM (or GDM) can access that mountpoint.
+   *
+   * well, if fstab-sync can change the block device with HAL, then,
+   * darn it, i can set up an automount point.  nyur, so there.
+   */
+    char amp[80];
+    strncpy(amp, autofs_root, sizeof(amp));
+    strncat(amp, "/", sizeof(amp));
+    strncat(amp, mount_point, sizeof(amp));
+
+    hal_device_set_property_string (hal_context, udi,
+			                        "block.automount_point", amp);
+  }
+
+/*
+ * check whether the block device already exists (also searching
+ * down a symlink location e.g. /dev/bus/ide... or /dev/cdrom)
+ *
+ * as a side-effect, update hal to tell it both the automount point
+ * and also the actual block device (if the recorded one was a symlink).
+ */
+static boolean check_block_field_device(FSTable *table, Volume *volume,
+	const char *block_dev, const char *mount_point)
+{
+	char buf[256];
+	struct stat statbuf;
+
+	/* Easy, the device file is a match */
+	if (strcmp (block_dev, volume->block_device) == 0)
+	{
+	  set_hal_automount_point(volume->udi, mount_point);
+	  return TRUE;
+	}
+	/* Check if it's a symlink */
+	if (lstat (block_dev, &statbuf) != 0)
+		return FALSE;
+
+	if (!S_ISLNK(statbuf.st_mode))
+	  return FALSE;
+
+	memset (buf, '\0', sizeof (buf));
+
+	if (readlink (block_dev, buf, sizeof (buf)) > 0) {
+
+	  /* check if link is fully qualified  */
+	  if (buf[0] != '/') {
+		char buf1[256];
+		char *p;
+
+		strncpy (buf1, buf, sizeof (buf1));
+		strncpy (buf, block_dev, sizeof(buf));
+		p = strrchr (buf, '/');
+		strncpy (p+1, buf1, buf+sizeof(buf)-p-1);
+	  }
+	}
+	if (strcmp (volume->block_device, buf) != 0)
+	  return FALSE;
+
+	  /* update block.device with new value */
+	fstab_update_debug (_("%d: Found %s pointing to %s in %s"), pid, block_dev, buf, fstab_path);
+	hal_device_set_property_string (hal_context, volume->udi,
+			"block.device", block_dev);
+	set_hal_automount_point(volume->udi, mount_point);
+	return TRUE;
+}
+
+/* not sure what this one's all about but it appears to be
+ * checking by the volume label (cool!).
+ *
+ * it also double-checks that the mount point is correct in
+ * /etc/mtab.
+ *
+ * TODO: integrate this somehow with autofs.
+ */
+static boolean check_mount_by_label(FSTable *table, Volume *volume, 
+	const char *block_dev, const char *mount_point)
+{
+	FILE *f;
+	struct mntent mnt;
+	struct mntent *mnte;
+	char buf[512];
+	char *device_file_from_mount_point;
+
+	/* Mount by label, more tricky, see below... */
+	if (!(strncmp (block_dev, "LABEL=", 6) == 0 &&
+		strlen (block_dev) > 6 &&
+		strcmp (block_dev + 6, volume->label) == 0))
+		return FALSE;
+
+	/* OK, so this new volume has a label that is matched
+	 * in the fstab.. Check, via /etc/mtab, whether the
+	 * device file for the entry in mtab matches the mount
+	 * point 
+	 *
+	 * (If it's mounted at all, which we assume it
+	 * is since no hotpluggable drives should be listed
+	 * in /etc/fstab by LABEL. And note that if it's 
+	 * not mounted then now we have TWO volumes with
+	 * the same label and then everything is FUBAR anyway) 
+	 */
+
+	if (mount_point == NULL)
+	return FALSE;
+
+	  /* good, now lookup in /etc/mtab */
+	  device_file_from_mount_point = NULL;
+	  if ((f = setmntent ("/etc/mtab", "r")) != NULL) {
+
+		  while ((mnte = getmntent_r (f, &mnt, buf, sizeof(buf))) != NULL) {
+			if (strcmp (mnt.mnt_dir, mount_point) == 0) {
+			  device_file_from_mount_point = mnt.mnt_fsname;
+			  break;
+			}
+		  }
+
+	  endmntent (f);
+	}
+
+	/* now see if it's the same device_file as our volume */
+	if (device_file_from_mount_point != NULL &&
+			strcmp (device_file_from_mount_point, 
+					volume->block_device) == 0)
+	{
+	  /* Yah it is.. So we're already listed in the fstab */
+	  return TRUE;
+	}
+	
+	return FALSE;
+}
+
 
 static char *
 compute_cdrom_name (const char *drive_udi)
@@ -1164,6 +1492,14 @@ volume_free (Volume *volume)
 static boolean
 create_mount_point_for_volume (Volume *volume)
 {
+	if (automount)
+	{
+		/* noooooo! if you try to create a directory on an automount
+		 * location, autofs it thinks you want to access the mountpoint!
+		 * plus the mkdir will fail anyway.
+		 */
+		return TRUE;
+	}
 
   /* FIXME: Should only mkdir if we need to and should do so
    * recursively for each component of the mount root.
@@ -1173,124 +1509,44 @@ create_mount_point_for_volume (Volume *v
   return (mkdir (volume->mount_point, 0775) != -1) || errno == EEXIST;
 }
 
-
-static boolean
-fs_table_has_volume (FSTable *table, Volume *volume)
+/*
+ * check for a volume and incidentally as a side-effect notify
+ * hal of any changes in /etc/mtab to the block device, and
+ * also notify hal of the automount point (if in autofs mode)
+ */
+static boolean fs_table_has_volume (FSTable *table, Volume *volume)
 {
   FSTableLine *line;
-  struct stat statbuf;
 
   line = table->lines;
   while (line != NULL)
     {
       FSTableField *field;
+	  const char *mount_point = NULL;
+	  const char *block_dev = NULL;
 
-      field = line->fields;
-      while (field != NULL)
-        {
-
-          if (field->type == FS_TABLE_FIELD_TYPE_BLOCK_DEVICE)
-            {
-
-	      /* Easy, the device file is a match */
-              if (strcmp (field->value, volume->block_device) == 0)
-                return TRUE;
-
-	      /* Check if it's a symlink */
-	      if (lstat (field->value, &statbuf) == 0) {
-
-		if (S_ISLNK(statbuf.st_mode)) {
-		  char buf[256];
-
-		  memset (buf, '\0', sizeof (buf));
-
-		  if (readlink (field->value, buf, sizeof (buf)) > 0) {
-
-		    /* check if link is fully qualified  */
-		    if (buf[0] != '/') {
-		      char buf1[256];
-		      char *p;
-
-		      strncpy (buf1, buf, sizeof (buf1));
-		      strncpy (buf, field->value, sizeof(buf));
-		      p = strrchr (buf, '/');
-		      strncpy (p+1, buf1, buf+sizeof(buf)-p-1);
-		    }
-
-		    if (strcmp (volume->block_device, buf) == 0) {
-		      /* update block.device with new value */
-		      fstab_update_debug (_("%d: Found %s pointing to %s in" _PATH_FSTAB), pid, field->value, buf);
-		      hal_device_set_property_string (hal_context, volume->udi, "block.device", field->value);
-		      return TRUE;
-		    }
-
-		  }
-		} 
-	      }
-
-	      /* Mount by label, more tricky, see below... */
-	      if (strncmp (field->value, "LABEL=", 6) == 0 &&
-		  strlen (field->value) > 6 &&
-		  strcmp (field->value + 6, volume->label) == 0) {
-		FSTableField *i;
-		char *mount_point;
-      
-		/* OK, so this new volume has a label that is matched
-		 * in the fstab.. Check, via /etc/mtab, whether the
-		 * device file for the entry in mtab matches the mount
-		 * point 
-		 *
-		 * (If it's mounted at all, which we assume it
-		 * is since no hotpluggable drives should be listed
-		 * in /etc/fstab by LABEL. And note that if it's 
-		 * not mounted then now we have TWO volumes with
-		 * the same label and then everything is FUBAR anyway) 
-		 */
-
-		/* first, find the mountpoint from fstab */
-		mount_point = NULL;
-		for (i = line->fields; i != NULL; i = i->next) {
-		  if (i->type == FS_TABLE_FIELD_TYPE_MOUNT_POINT) {
-		    mount_point = i->value;
-		    break;
-		  }
-		}
-
-		if (mount_point != NULL) {
-		  FILE *f;
-		  struct mntent mnt;
-		  struct mntent *mnte;
-		  char buf[512];
-		  char *device_file_from_mount_point;
-
-		  /* good, now lookup in /etc/mtab */
-		  device_file_from_mount_point = NULL;
-		  if ((f = setmntent ("/etc/mtab", "r")) != NULL) {
-
-		    while ((mnte = getmntent_r (f, &mnt, buf, sizeof(buf))) != NULL) {
-		      if (strcmp (mnt.mnt_dir, mount_point) == 0) {
-			device_file_from_mount_point = mnt.mnt_fsname;
-			break;
-		      }
-		    }
-
-		    endmntent (f);
-		  }
+	  /* first, find the mountpoint from fstab */
+	  for (field = line->fields; field != NULL; field = field->next)
+	  {
+		  if (field->type == FS_TABLE_FIELD_TYPE_MOUNT_POINT)
+		  {
+		  mount_point = field->value;
+		  break;
+          }
+		  else if (field->type == FS_TABLE_FIELD_TYPE_BLOCK_DEVICE)
+          {
+		  block_dev = field->value;
+		  break;
+          }
+      }
 
-		  /* now see if it's the same device_file as our volume */
-		  if (device_file_from_mount_point != NULL &&
-		      strcmp (device_file_from_mount_point, 
-			      volume->block_device) == 0) {
-		    /* Yah it is.. So we're already listed in the fstab */
-		    return TRUE;
-		  }
-		}
-	      } /* entry is LABEL= */
+	  if (block_dev == NULL)
+		  continue;
 
-            }
+	  if (check_block_field_device(table, volume, block_dev, mount_point) ||
+		  check_mount_by_label(table, volume, block_dev, mount_point))
+		  return TRUE;
 
-          field = field->next;
-        }
       line = line->next;
     }
 
@@ -1320,7 +1576,11 @@ fs_table_add_volume (FSTable *table, Vol
 
   options[0] = '\0';
 
-  strcat_len (options, "noauto,user,exec");
+  strcat_len (options, "noauto,user");
+
+  if (extra_mount_opts[0])
+	  strcat_len (options, ",");
+	  strcat_len (options, extra_mount_opts);
 
 #ifdef FSTAB_SYNC_USE_NOOP_MOUNT_OPTION
   strcat_len (options, "," FSTAB_SYNC_MOUNT_MANAGED_KEYWORD);
@@ -1336,7 +1596,13 @@ fs_table_add_volume (FSTable *table, Vol
     strcat_len (options, ",noatime,sync");
   }
 
-  line = fs_table_line_new_from_field_values (volume->block_device,
+  if (automount)
+	  line = autofs_table_line_new_from_field_values (volume->block_device,
+                                              volume->mount_point,
+                                              volume->fs_type,
+                                              strdup (options), 0, 0); 
+  else
+	  line = fs_table_line_new_from_field_values (volume->block_device,
                                               volume->mount_point,
                                               volume->fs_type,
                                               strdup (options), 0, 0); 
@@ -1436,10 +1702,20 @@ tryagain:
     return FALSE;
   }
 
-  if (dev_number == 0)
-    snprintf (desired_name, sizeof (desired_name), FSTAB_SYNC_MOUNT_ROOT "/%s", volume->type);
+  if (automount)
+  {
+	  if (dev_number == 0)
+		snprintf (desired_name, sizeof (desired_name), "%s", volume->type);
+	  else
+		snprintf (desired_name, sizeof (desired_name), "%s%d", volume->type, dev_number);
+	}
   else
-    snprintf (desired_name, sizeof (desired_name), FSTAB_SYNC_MOUNT_ROOT "/%s%d", volume->type, dev_number);
+  {
+	  if (dev_number == 0)
+		snprintf (desired_name, sizeof (desired_name), FSTAB_SYNC_MOUNT_ROOT "/%s", volume->type);
+	  else
+		snprintf (desired_name, sizeof (desired_name), FSTAB_SYNC_MOUNT_ROOT "/%s%d", volume->type, dev_number);
+  }
 
   /* see if it's in fstab */
   for (line = table->lines; line != NULL; line = line->next) {
@@ -1449,10 +1725,13 @@ tryagain:
     }
   }
 
-  /* see if the mount point physically exists */
-  if (stat (desired_name, &statbuf) == 0 || errno != ENOENT) {
-    dev_number++;
-    goto tryagain;
+  if (!automount)
+  {
+	  /* see if the mount point physically exists */
+	  if (stat (desired_name, &statbuf) == 0 || errno != ENOENT) {
+		dev_number++;
+		goto tryagain;
+	  }
   }
 
   volume->mount_point = strdup (desired_name);
@@ -1482,12 +1761,12 @@ add_udi (const char *udi)
   if (volume == NULL)
     return FALSE;
 
-  dir = strdup (_PATH_FSTAB); 	 
+  dir = strdup (fstab_path); 	 
   last_slash = strrchr (dir, '/'); 	 
   if (last_slash) 
     *last_slash = '\0';
 
-  fs_table = fs_table_new (_PATH_FSTAB);
+  fs_table = fs_table_new (fstab_path);
 
   if (fs_table == NULL)
     goto error;
@@ -1497,7 +1776,7 @@ add_udi (const char *udi)
   if (fd < 0)
     goto error;
 
-  fstab_modification_time = get_file_modification_time (_PATH_FSTAB);
+  fstab_modification_time = get_file_modification_time (fstab_path);
 
   if (fstab_modification_time == 0)
     goto error;
@@ -1513,7 +1792,7 @@ add_udi (const char *udi)
 
   /* Someone changed the fs table under us, better start over.
    */
-  if (get_file_modification_time (_PATH_FSTAB) != fstab_modification_time)
+  if (get_file_modification_time (fstab_path) != fstab_modification_time)
     {
       close (fd);
       unlink (temp_filename);
@@ -1521,16 +1800,18 @@ add_udi (const char *udi)
       return add_udi (udi);
     }
 
-  if (rename (temp_filename, _PATH_FSTAB) < 0)
+  if (rename (temp_filename, fstab_path) < 0)
     {
       fstab_update_debug (_("%d: Failed to rename '%s' to '%s': %s\n"),
-                          pid, temp_filename, _PATH_FSTAB, strerror (errno));
+                          pid, temp_filename, fstab_path, strerror (errno));
       goto error;
     }
 
   if (!create_mount_point_for_volume (volume))
     goto error;
 
+  set_hal_automount_point(volume->udi, volume->mount_point);
+
   fstab_update_debug (_("%d: added mount point '%s' for device '%s'\n"),
 		      pid, volume->mount_point, volume->block_device);
   syslog (LOG_INFO, _("added mount point %s for %s"), volume->mount_point, volume->block_device);
@@ -1539,7 +1820,7 @@ add_udi (const char *udi)
   volume_free (volume);
 
 #ifdef HAVE_SELINUX
-  restore_selinux_context(_PATH_FSTAB);
+  restore_selinux_context(fstab_path);
 #endif
 
   return TRUE;
@@ -1563,7 +1844,7 @@ remove_udi (const char *udi)
   FSTableLine *line = NULL;
   char *temp_filename = NULL;
   time_t fstab_modification_time;
-  int fd;
+  int fd = -1;
   boolean is_volume;
   char *dir = NULL;
   char *last_slash;
@@ -1580,19 +1861,31 @@ remove_udi (const char *udi)
 
   block_device = hal_device_get_property_string (hal_context, udi, "block.device");
 
-  dir = strdup (_PATH_FSTAB); 	 
+  if (block_device == NULL)
+	  goto error;
+
+  /* in automount mode, the volume.mount_point is managed by fstab-sync.
+   * so we need to clear volume.mount_point, here.
+   */
+  if (is_volume && automount)
+  {
+    hal_device_set_property_string (hal_context, udi,
+			                        "volume.mount_point", "");
+  }
+
+  dir = strdup (fstab_path); 	 
   last_slash = strrchr (dir, '/'); 	 
   if (last_slash) 
     *last_slash = '\0';
 
-  fs_table = fs_table_new (_PATH_FSTAB);
+  fs_table = fs_table_new (fstab_path);
 
   fd = open_temp_fstab_file (dir, &temp_filename);
 
   if (fd < 0)
     goto error;
 
-  fstab_modification_time = get_file_modification_time (_PATH_FSTAB);
+  fstab_modification_time = get_file_modification_time (fstab_path);
 
   if (fstab_modification_time == 0)
     goto error;
@@ -1609,7 +1902,7 @@ remove_udi (const char *udi)
 
   assert (line->mount_point != NULL);
 
-  if (rmdir (line->mount_point) < 0)
+  if (!automount && rmdir (line->mount_point) < 0)
     {
       fstab_update_debug (_("%d: Failed to remove mount point '%s': %s\n"),
                           pid, line->mount_point, strerror (errno));
@@ -1622,7 +1915,7 @@ remove_udi (const char *udi)
 
   /* Someone changed the fs table under us, better start over.
    */
-  if (get_file_modification_time (_PATH_FSTAB) != fstab_modification_time)
+  if (get_file_modification_time (fstab_path) != fstab_modification_time)
     {
       close (fd);
       unlink (temp_filename);
@@ -1630,10 +1923,10 @@ remove_udi (const char *udi)
       return remove_udi (udi);
     }
 
-  if (rename (temp_filename, _PATH_FSTAB) < 0)
+  if (rename (temp_filename, fstab_path) < 0)
     {
       fstab_update_debug (_("%d: Failed to rename '%s' to '%s': %s\n"),
-                          pid, temp_filename, _PATH_FSTAB, strerror (errno));
+                          pid, temp_filename, fstab_path, strerror (errno));
       goto error;
     }
 
@@ -1646,7 +1939,7 @@ remove_udi (const char *udi)
   fs_table_line_free (line);
 
 #ifdef HAVE_SELINUX
-  restore_selinux_context(_PATH_FSTAB);
+  restore_selinux_context(fstab_path);
 #endif
 
   return TRUE;
@@ -1655,7 +1948,8 @@ error:
   if (fd >= 0)
     close (fd);
 
-  free (block_device);
+  if (block_device != NULL)
+	  free (block_device);
 
   if (temp_filename != NULL)
     unlink (temp_filename);
@@ -1746,19 +2040,19 @@ clean (void)
   char *dir = NULL;
   char *last_slash;
 
-  dir = strdup (_PATH_FSTAB); 	 
+  dir = strdup (fstab_path); 	 
   last_slash = strrchr (dir, '/'); 	 
   if (last_slash) 
     *last_slash = '\0';
 
-  fs_table = fs_table_new (_PATH_FSTAB);
+  fs_table = fs_table_new (fstab_path);
 
   fd = open_temp_fstab_file (dir, &temp_filename);
 
   if (fd < 0)
     goto error;
 
-  fstab_modification_time = get_file_modification_time (_PATH_FSTAB);
+  fstab_modification_time = get_file_modification_time (fstab_path);
 
   if (fstab_modification_time == 0)
     goto error;
@@ -1770,24 +2064,24 @@ clean (void)
 
   /* Someone changed the fs table under us, better start over.
    */
-  if (get_file_modification_time (_PATH_FSTAB) != fstab_modification_time)
+  if (get_file_modification_time (fstab_path) != fstab_modification_time)
     {
       close (fd);
       unlink (temp_filename);
       return clean ();
     }
 
-  if (rename (temp_filename, _PATH_FSTAB) < 0)
+  if (rename (temp_filename, fstab_path) < 0)
     {
       fstab_update_debug (_("%d: Failed to rename '%s' to '%s': %s\n"),
-                          pid, temp_filename, _PATH_FSTAB, strerror (errno));
+                          pid, temp_filename, fstab_path, strerror (errno));
       goto error;
     }
 
   close (fd);
 
 #ifdef HAVE_SELINUX
-  restore_selinux_context(_PATH_FSTAB);
+  restore_selinux_context(fstab_path);
 #endif
 
   syslog (LOG_INFO, _("removed all generated mount points"));
@@ -1804,6 +2098,45 @@ error:
   return FALSE;
 }
 
+/* hacked-up function to read some additional mount options
+ * to be tacked onto all entries put into /etc/fstab (or /etc/auto.hal).
+ * e.g. you might want to specify "sync,dirsync" or "uid=fred".  or noexec.
+ * uid=fred is essential for autofs because otherwise the file system
+ * can get mounted as root...
+ */
+static void read_fstab_conf_options(void)
+{
+	FILE *f = fopen("/etc/fstab-sync.conf", "r");
+	if (f == NULL)
+		return;
+	char line[80];
+	while (fgets(line, sizeof(line), f))
+	{
+		size_t len = strlen(line);
+		char *p;
+		if (line[len-1] == '\n')
+				line[len-1] = '\0';
+		p = strchr(line, '=');
+		if (p == NULL)
+			continue;
+		*p = 0;
+		if (strcmp(line, "EXTRA_MOUNT_OPTS") == 0)
+		{
+			strncpy(extra_mount_opts, p+1, sizeof(extra_mount_opts));
+		}
+		else if (strcmp(line, "AUTOFS_HAL_ROOT") == 0)
+		{
+			size_t len;
+			strncpy(autofs_root, p+1, sizeof(autofs_root));
+			len = strlen(autofs_root);
+			if (autofs_root[len-1] == '/')
+				autofs_root[len-1] = '\0';
+		}
+	}
+
+	fclose(f);
+}
+
 int
 main (int argc, const char *argv[])
 {
@@ -1814,6 +2147,30 @@ main (int argc, const char *argv[])
   const char **left_over_args = NULL;
   int lockfd = -1;
 
+  /* default for mount opts, and default for autofs root mount point.
+   * fstab root mount point is still defined via hard-coded #define
+   */
+  strncpy(extra_mount_opts,"noauto,user,exec", sizeof(extra_mount_opts));
+  strncpy(autofs_root, FSTAB_SYNC_MOUNT_ROOT, sizeof(autofs_root));
+  read_fstab_conf_options();
+
+  /* choose between autofs and fstab based on last part of name of program
+   * so we can do /etc/hal/devices.d/50-autofs.hal and expect it to work,
+   * or /etc/hal/devices.d/50-fstab-sync.hal and expect that to work
+   */
+
+    /* *** fstab mode *** */
+    fstab_path = _PATH_FSTAB;
+    fs_fields = fstab_fields;
+
+    if (strcmp(&(argv[0][strlen(argv[0])-10]), "autofs.hal") == 0)
+    {
+	/* *** autofs mode *** */
+	automount = TRUE;
+	fstab_path = AUTOFS_SYNC_MOUNT_FILE;
+	fs_fields = autofs_fields;
+    }
+
   pid = getpid ();
 
   openlog (PROGRAM_NAME, LOG_PID, LOG_USER);
@@ -1895,23 +2252,23 @@ main (int argc, const char *argv[])
       fstab_update_debug (_("%d: ###################################\n"), pid);
       fstab_update_debug (_("%d: %s entering; %s udi=%s\n"), 
 			  pid, PROGRAM_NAME, argv[1], hal_device_udi);
-      fstab_update_debug (("%d: mount_root=" FSTAB_SYNC_MOUNT_ROOT 
+	  if (!automount)
+		  fstab_update_debug (("%d: mount_root=" FSTAB_SYNC_MOUNT_ROOT 
 #ifdef FSTAB_SYNC_USE_NOOP_MOUNT_OPTION
 			   " use_managed=yes"
 #else
 			   " use_managed=no"
 #endif
 			   " managed_keyword=" FSTAB_SYNC_MOUNT_MANAGED_KEYWORD "\n"), pid);
-      
-      lockfd = open (_PATH_FSTAB, O_RDONLY);
+      lockfd = open (fstab_path, O_RDONLY);
       if (lockfd < 0) {
 	fstab_update_debug (_("%d: couldn't open %s O_RDONLY; bailing out\n"), 
-			    pid, _PATH_FSTAB);
+			    pid, fstab_path);
 	retval = 1;
 	goto out;
       }
-      fstab_update_debug (_("%d: Acquiring advisory lock on " 
-			    _PATH_FSTAB "\n"), pid);
+      fstab_update_debug (_("%d: Acquiring advisory lock on %s\n"),
+			  pid, fstab_path);
       if (flock (lockfd, LOCK_EX) != 0) {
 	fstab_update_debug (_("%d: Error acquiring lock '%s'; bailing out\n"),
 			    pid, strerror(errno));
@@ -1964,7 +2321,7 @@ main (int argc, const char *argv[])
   if (hal_device_udi != NULL) {
 
     fstab_update_debug (_("%d: Releasing advisory lock on %s\n"), 
-			pid, _PATH_FSTAB);
+			pid, fstab_path);
     if (flock (lockfd, LOCK_EX) != 0) {
       fstab_update_debug (_("%d: Error releasing lock '%s'\n"), pid, 
 	      strerror(errno));
-------------- next part --------------
_______________________________________________
hal mailing list
hal at freedesktop.org
http://freedesktop.org/mailman/listinfo/hal


More information about the Hal mailing list