hal: Branch 'origin' - 12 commits

Kay Sievers kay at kemper.freedesktop.org
Wed Oct 11 02:05:11 PDT 2006


 hald/device.c         |    5 
 hald/device_info.c    | 1869 +++++++++++++++++++++-----------------------------
 hald/device_info.h    |    4 
 hald/hald.c           |    8 
 hald/hald_runner.c    |   68 -
 hald/ids.c            |  151 +---
 hald/util.c           |    6 
 hald/valgrind-hald.sh |    3 
 8 files changed, 899 insertions(+), 1215 deletions(-)

New commits:
diff-tree b105ec345ad12fc4eff158c9aeaab78caebe9a71 (from 5e33459557cf9d4680f894392a834b7752acd60a)
Author: David Zeuthen <davidz at redhat.com>
Date:   Wed Oct 11 00:43:32 2006 -0400

    make pnp.ids static to save writable memory
    
    Goodbye another 8KB!

diff --git a/hald/ids.c b/hald/ids.c
index aa23e1c..223c8d4 100644
--- a/hald/ids.c
+++ b/hald/ids.c
@@ -527,9 +527,9 @@ ids_init (void)
  * Keep this sorted!
  */
 struct pnp_id {
-	char *id;
-   	char *desc;
-} static  pnp_ids_list[] = {
+	const char *id;
+   	const char *desc;
+} static const pnp_ids_list[] = {
 	/* Crystal Semiconductor devices */
 	{"CSC0000", "Crystal Semiconductor CS423x sound -- SB/WSS/OPL3 emulation"},
 	{"CSC0001", "Crystal Semiconductor CS423x sound -- joystick"},
@@ -948,22 +948,14 @@ ids_comp_pnp(const void *id1, const void
 void
 ids_find_pnp (const char *pnp_id, char **pnp_description)
 {
-	static gboolean sorted = FALSE;
 	struct pnp_id search, *res;
-        
-	if (!sorted) {
-		/* sort the list, to be sure that all is in correc order */
-		qsort(pnp_ids_list, sizeof(pnp_ids_list)/sizeof(pnp_ids_list[0]), 
-		      sizeof(struct pnp_id), ids_comp_pnp);
-		sorted = TRUE;
-	}
 
         search.id = (char *) pnp_id;
         res = bsearch(&search, pnp_ids_list, sizeof(pnp_ids_list)/sizeof(pnp_ids_list[0]), 
 		      sizeof(struct pnp_id), ids_comp_pnp);
 
         if (res != NULL)
-        	*pnp_description = res->desc;
+        	*pnp_description = (char *) res->desc;
 	else
         	*pnp_description = NULL; 
         return;
diff-tree 5e33459557cf9d4680f894392a834b7752acd60a (from e6b0bd21ae250d6d589e2584fd624b7bd2fa6835)
Author: David Zeuthen <davidz at redhat.com>
Date:   Wed Oct 11 00:17:34 2006 -0400

    use mmap to access pci.ids and usb.ids
    
    Goodbye 580KB of writable memory! :-)

diff --git a/hald/ids.c b/hald/ids.c
index 5d2fe62..aa23e1c 100644
--- a/hald/ids.c
+++ b/hald/ids.c
@@ -31,6 +31,11 @@
 #include <stdint.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <errno.h>
 
 #include <dbus/dbus.h>
 #include <dbus/dbus-glib.h>
@@ -43,10 +48,10 @@
 static char *pci_ids = NULL;
 
 /** Length of data store at at pci_ids */
-static unsigned int pci_ids_len;
+static size_t pci_ids_len;
 
 /** Iterator position into pci_ids */
-static unsigned int pci_ids_iter_pos;
+static size_t pci_ids_iter_pos;
 
 /** Initialize the pci.ids line iterator to the beginning of the file */
 static void
@@ -258,20 +263,6 @@ ids_find_pci (int vendor_id, int product
 	}
 }
 
-/** Free resources used by to store the PCI database
- *
- *  @param                      #FALSE if the PCI database wasn't loaded
- */
-static dbus_bool_t
-pci_ids_free ()
-{
-	if (pci_ids != NULL) {
-		free (pci_ids);
-		pci_ids = NULL;
-		return TRUE;
-	}
-	return FALSE;
-}
 
 /** Load the PCI database used for mapping vendor, product, subsys_vendor
  *  and subsys_product numbers into names.
@@ -283,35 +274,36 @@ pci_ids_free ()
 static dbus_bool_t
 pci_ids_load (const char *path)
 {
-	FILE *fp;
-	unsigned int num_read;
+	int fd;
+	struct stat statbuf;
+	gboolean ret;
 
-	fp = fopen (path, "r");
-	if (fp == NULL) {
-		HAL_ERROR (("couldn't open PCI database at %s,", path));
-		return FALSE;
-	}
+	ret = FALSE;
 
-	fseek (fp, 0, SEEK_END);
-	pci_ids_len = ftell (fp);
-	fseek (fp, 0, SEEK_SET);
+	if (stat (path, &statbuf) != 0) {
+		HAL_WARNING (("Couldn't stat pci.ids file '%s', errno=%d: %s", path, errno, strerror (errno)));
+		goto out;
+	}
+	pci_ids_len = statbuf.st_size;
 
-	pci_ids = malloc (pci_ids_len);
-	if (pci_ids == NULL) {
-		DIE (("Couldn't allocate %d bytes for PCI database file\n",
-		      pci_ids_len));
+	fd = open (path, O_RDONLY);
+	if (fd < 0) {
+		HAL_WARNING (("Couldn't open pci.ids file '%s', errno=%d: %s", path, errno, strerror (errno)));
+		goto out;
 	}
 
-	num_read = fread (pci_ids, sizeof (char), pci_ids_len, fp);
-	if (pci_ids_len != num_read) {
-		HAL_ERROR (("Error loading PCI database file"));
-		pci_ids_free();
-		fclose(fp);
-		return FALSE;
+	pci_ids = mmap (NULL, pci_ids_len, PROT_READ, MAP_SHARED, fd, 0);
+	if (pci_ids == MAP_FAILED) {
+		HAL_WARNING (("Couldn't mmap pci.ids file '%s', errno=%d: %s", path, errno, strerror (errno)));
+		close (fd);
+		goto out;
 	}
 
-	fclose(fp);
-	return TRUE;
+	ret = TRUE;
+
+	close (fd);
+out:
+	return ret;
 }
 
 /*==========================================================================*/
@@ -320,10 +312,10 @@ pci_ids_load (const char *path)
 static char *usb_ids = NULL;
 
 /** Length of data store at at usb_ids */
-static unsigned int usb_ids_len;
+static size_t usb_ids_len;
 
 /** Iterator position into usb_ids */
-static unsigned int usb_ids_iter_pos;
+static size_t usb_ids_iter_pos;
 
 /** Initialize the usb.ids line iterator to the beginning of the file */
 static void
@@ -475,21 +467,6 @@ ids_find_usb (int vendor_id, int product
 	}
 }
 
-/** Free resources used by to store the USB database
- *
- *  @param                      #FALSE if the USB database wasn't loaded
- */
-static dbus_bool_t
-usb_ids_free ()
-{
-	if (usb_ids != NULL) {
-		free (usb_ids);
-		usb_ids = NULL;
-		return TRUE;
-	}
-	return FALSE;
-}
-
 /** Load the USB database used for mapping vendor, product, subsys_vendor
  *  and subsys_product numbers into names.
  *
@@ -500,38 +477,36 @@ usb_ids_free ()
 static dbus_bool_t
 usb_ids_load (const char *path)
 {
-	FILE *fp;
-	unsigned int num_read;
+	int fd;
+	struct stat statbuf;
+	gboolean ret;
+
+	ret = FALSE;
 
-	fp = fopen (path, "r");
-	if (fp == NULL) {
-		printf ("couldn't open USB database at %s,", path);
-		return FALSE;
-	}
-
-	fseek (fp, 0, SEEK_END);
-	usb_ids_len = ftell (fp);
-	fseek (fp, 0, SEEK_SET);
-
-	usb_ids = malloc (usb_ids_len);
-	if (usb_ids == NULL) {
-		printf
-		    ("Couldn't allocate %d bytes for USB database file\n",
-		     usb_ids_len);
-		fclose(fp);
-		return FALSE;
-	}
-
-	num_read = fread (usb_ids, sizeof (char), usb_ids_len, fp);
-	if (usb_ids_len != num_read) {
-		printf ("Error loading USB database file\n");
-		usb_ids_free ();
-		fclose(fp);
-		return FALSE;
+	if (stat (path, &statbuf) != 0) {
+		HAL_WARNING (("Couldn't stat usb.ids file '%s', errno=%d: %s", path, errno, strerror (errno)));
+		goto out;
 	}
+	usb_ids_len = statbuf.st_size;
+
+	fd = open (path, O_RDONLY);
+	if (fd < 0) {
+		HAL_WARNING (("Couldn't open usb.ids file '%s', errno=%d: %s", path, errno, strerror (errno)));
+		goto out;
+	}
+
+	usb_ids = mmap (NULL, usb_ids_len, PROT_READ, MAP_SHARED, fd, 0);
+	if (usb_ids == MAP_FAILED) {
+		HAL_WARNING (("Couldn't mmap usb.ids file '%s', errno=%d: %s", path, errno, strerror (errno)));
+		close (fd);
+		goto out;
+	}
+
+	ret = TRUE;
 
-	fclose(fp);
-	return TRUE;
+	close (fd);
+out:
+	return ret;
 }
 
 
diff-tree e6b0bd21ae250d6d589e2584fd624b7bd2fa6835 (from 9aa082592ee8fa3c33539bda2e0226c12880d30a)
Author: David Zeuthen <davidz at redhat.com>
Date:   Tue Oct 10 21:11:39 2006 -0400

    comment out some debugging spew from fdi matching
    
    We really need a modularized logging system Real Soon Now(tm).

diff --git a/hald/device_info.c b/hald/device_info.c
index fe5ac98..9ff8ba8 100644
--- a/hald/device_info.c
+++ b/hald/device_info.c
@@ -153,6 +153,7 @@ rule_type get_rule_type (const char *str
 	return RULE_UNKNOWN;
 }
 
+/*
 static char *
 get_rule_type_str (enum rule_type type)
 {
@@ -178,6 +179,7 @@ get_rule_type_str (enum rule_type type)
 	}
 	return "invalid rule type";
 }
+*/
 
 static enum
 merge_type get_merge_type (const char *str)
@@ -201,6 +203,7 @@ merge_type get_merge_type (const char *s
 	return MERGE_UNKNOWN;
 }
 
+/*
 static char *
 get_merge_type_str (enum merge_type type)
 {
@@ -226,6 +229,7 @@ get_merge_type_str (enum merge_type type
 	}
 	return "invalid merge type";
 }
+*/
 
 static enum
 match_type get_match_type(const char *str)
@@ -261,6 +265,7 @@ match_type get_match_type(const char *st
 	return MATCH_UNKNOWN;
 }
 
+/*
 static char *
 get_match_type_str (enum match_type type)
 {
@@ -298,6 +303,7 @@ get_match_type_str (enum match_type type
 	}
 	return "invalid match type";
 }
+*/
 
 /** Resolve a udi-property path as used in .fdi files.
  *
@@ -1296,9 +1302,9 @@ rules_match_and_merge_device (GSList *fd
 		switch (rule->rtype) {
 		case RULE_MATCH:
 			/* skip non-matching rules block */
-			HAL_INFO(("%p match '%s' at %s", rule, rule->key, hal_device_get_udi (d)));
+			/*HAL_INFO(("%p match '%s' at %s", rule, rule->key, hal_device_get_udi (d)));*/
 			if (!handle_match (rule, d)) {
-				HAL_INFO(("no match, skip to rule %s (%p)", get_rule_type_str (rule->next_rule->rtype), rule->next_rule));
+				/*HAL_INFO(("no match, skip to rule %s (%p)", get_rule_type_str (rule->next_rule->rtype), rule->next_rule));*/
 				elem = g_slist_find (elem, rule->next_rule);
 				continue;
 			}
@@ -1310,12 +1316,12 @@ rules_match_and_merge_device (GSList *fd
 		case RULE_CLEAR:
 		case RULE_SPAWN:
 		case RULE_MERGE:
-			HAL_INFO(("%p merge '%s' at %s", rule, rule->key, hal_device_get_udi (d)));
+			/*HAL_INFO(("%p merge '%s' at %s", rule, rule->key, hal_device_get_udi (d)));*/
 			handle_merge (rule, d);
 			break;
 
 		case RULE_EOF:
-			HAL_INFO(("%p fdi file '%s' finished", rule, rule->key));
+			/*HAL_INFO(("%p fdi file '%s' finished", rule, rule->key));*/
 			break;
 
 		default:
@@ -1332,17 +1338,17 @@ di_search_and_merge (HalDevice *d, Devic
 {
 	switch (type) {
 	case DEVICE_INFO_TYPE_PREPROBE:
-		HAL_INFO(("apply fdi preprobe to device %p", d));
+		/*HAL_INFO(("apply fdi preprobe to device %p", d));*/
 		rules_match_and_merge_device (fdi_rules_preprobe, d);
 		break;
 
 	case DEVICE_INFO_TYPE_INFORMATION:
-		HAL_INFO(("apply fdi info to device %p", d));
+		/*HAL_INFO(("apply fdi info to device %p", d));*/
 		rules_match_and_merge_device (fdi_rules_information, d);
 		break;
 
 	case DEVICE_INFO_TYPE_POLICY:
-		HAL_INFO(("apply fdi policy to device %p", d));
+		/*HAL_INFO(("apply fdi policy to device %p", d));*/
 		rules_match_and_merge_device (fdi_rules_policy, d);
 		break;
 
diff-tree 9aa082592ee8fa3c33539bda2e0226c12880d30a (from 8ee20db66713838d7b4bede2ba2162082b66165b)
Author: David Zeuthen <davidz at redhat.com>
Date:   Tue Oct 10 20:47:55 2006 -0400

    report how much memory the rules use

diff --git a/hald/device_info.c b/hald/device_info.c
index fd54e7a..fe5ac98 100644
--- a/hald/device_info.c
+++ b/hald/device_info.c
@@ -127,6 +127,8 @@ struct fdi_context {
 	/* current rule */
 	struct rule *rule;
 
+	int fdi_rule_size;
+
 	/* all rules */
 	GSList* rules;
 };
@@ -1058,6 +1060,13 @@ end (void *data, const char *el)
 	if (fdi_ctx->rule->value == NULL)
 		fdi_ctx->rule->value = g_strdup ("");
 
+	if (fdi_ctx->fdi_rule_size >= 0) {
+		fdi_ctx->fdi_rule_size += 
+			sizeof (struct rule) + 
+			strlen (fdi_ctx->rule->key) + 
+			fdi_ctx->rule->value_len;
+	}
+
 	/* insert merge rule into list and get new rule */
 	fdi_ctx->rules = g_slist_append (fdi_ctx->rules, fdi_ctx->rule);
 	fdi_ctx->rule = g_new0 (struct rule, 1);
@@ -1065,12 +1074,13 @@ end (void *data, const char *el)
 
 /* decompile an fdi file into a list of rules as this is quicker than opening then each time we want to search */
 static int
-rules_add_fdi_file (GSList **fdi_rules, const char *filename)
+rules_add_fdi_file (GSList **fdi_rules, const char *filename, gboolean compute_rule_size)
 {
 	struct fdi_context *fdi_ctx;
 	char *buf;
 	gsize buflen;
 	int rc;
+	int fdi_rule_size;
 
 	if (!g_file_get_contents (filename, &buf, &buflen, NULL))
 		return -1;
@@ -1078,6 +1088,7 @@ rules_add_fdi_file (GSList **fdi_rules, 
 	/* get context and first rule */
 	fdi_ctx = g_new0 (struct fdi_context ,1);
 	fdi_ctx->rule = g_new0 (struct rule ,1);
+	fdi_ctx->fdi_rule_size = compute_rule_size ? 0 : -1;
 
 	XML_Parser parser = XML_ParserCreate (NULL);
 	if (parser == NULL) {
@@ -1106,35 +1117,14 @@ rules_add_fdi_file (GSList **fdi_rules, 
 	else
 		*fdi_rules = g_slist_concat (*fdi_rules, fdi_ctx->rules);
 
+	fdi_rule_size = (gint64) fdi_ctx->fdi_rule_size;
+
 	g_free (fdi_ctx);
 
 	if (rc == 0)
 		return -1;
-	return 0;
-}
-
-/* print the rules to screen, mainly useful for debugging */
-static void
-rules_dump (GSList *fdi_rules)
-{
-	GSList *elem;
-
-	for (elem = fdi_rules; elem != NULL; elem = g_slist_next (elem)) {
-		struct rule *rule = elem->data;
 
-		if (rule->rtype == RULE_EOF) {
-			printf ("%p: eof %s\n", rule, rule->key);
-		} else if (rule->rtype == RULE_MATCH) {
-			printf ("\n");
-			printf ("%p: match '%s' (%s) '%s' (skip to %p)\n",
-				rule, rule->key, get_match_type_str (rule->type_match),
-				rule->value, rule->next_rule);
-		} else {
-			printf ("%p: %s '%s' (%s) '%s'\n",
-				rule, get_rule_type_str (rule->rtype), rule->key,
-				get_merge_type_str (rule->type_merge), rule->value);
-		}
-	}
+	return compute_rule_size ? fdi_rule_size : 0;
 }
 
 /* modified alphasort to count downwards */
@@ -1150,7 +1140,7 @@ _alphasort(const struct dirent **a, cons
 
 /* recurse a directory tree, searching and adding fdi files */
 static int
-rules_search_and_add_fdi_files (GSList **fdi_rules, const char *dir)
+rules_search_and_add_fdi_files (GSList **fdi_rules, const char *dir, int *rules_size)
 {
 	int i;
 	int num_entries;
@@ -1169,8 +1159,19 @@ rules_search_and_add_fdi_files (GSList *
 		len = strlen (filename);
 		full_path = g_strdup_printf ("%s/%s", dir, filename);
 		if (g_file_test (full_path, (G_FILE_TEST_IS_REGULAR))) {
-			if (len >= 5 && strcmp(&filename[len - 4], ".fdi") == 0)
-				rules_add_fdi_file (fdi_rules, full_path);
+			if (len >= 5 && strcmp(&filename[len - 4], ".fdi") == 0) {
+				int fdi_rules_size;
+				fdi_rules_size = rules_add_fdi_file (fdi_rules, full_path, rules_size != NULL);
+				if (fdi_rules_size >= 0) {
+					if (rules_size != NULL) {
+						*rules_size += fdi_rules_size;
+						HAL_INFO (("fdi file '%s' -> %d bytes of rules", 
+							   full_path, fdi_rules_size));
+					}
+				} else {
+					HAL_WARNING (("error processing fdi file '%s'", full_path));
+				}
+			}
 		} else if (g_file_test (full_path, (G_FILE_TEST_IS_DIR)) && filename[0] != '.') {
 			int num_bytes;
 			char *dirname;
@@ -1181,7 +1182,7 @@ rules_search_and_add_fdi_files (GSList *
 				break;
 
 			snprintf (dirname, num_bytes, "%s/%s", dir, filename);
-			rules_search_and_add_fdi_files (fdi_rules, dirname);
+			rules_search_and_add_fdi_files (fdi_rules, dirname, rules_size);
 			free (dirname);
 		}
 		g_free (full_path);
@@ -1196,45 +1197,73 @@ rules_search_and_add_fdi_files (GSList *
 	return 0;
 }
 
+/* print the rules to screen, mainly useful for debugging */
+#if 0
+static void
+rules_dump (GSList *fdi_rules)
+{
+	GSList *elem;
+
+	for (elem = fdi_rules; elem != NULL; elem = g_slist_next (elem)) {
+		struct rule *rule = elem->data;
+
+		if (rule->rtype == RULE_EOF) {
+			printf ("%p: eof %s\n", rule, rule->key);
+		} else if (rule->rtype == RULE_MATCH) {
+			printf ("\n");
+			printf ("%p: match '%s' (%s) '%s' (skip to %p)\n",
+				rule, rule->key, get_match_type_str (rule->type_match),
+				rule->value, rule->next_rule);
+		} else {
+			printf ("%p: %s '%s' (%s) '%s'\n",
+				rule, get_rule_type_str (rule->rtype), rule->key,
+				get_merge_type_str (rule->type_merge), rule->value);
+		}
+	}
+}
+#endif
+
 /* setup the location of the rules */
 void
 di_rules_init (void)
 {
+	int size;
 	char *hal_fdi_source_preprobe = getenv ("HAL_FDI_SOURCE_PREPROBE");
 	char *hal_fdi_source_information = getenv ("HAL_FDI_SOURCE_INFORMATION");
 	char *hal_fdi_source_policy = getenv ("HAL_FDI_SOURCE_POLICY");
 
 	HAL_INFO (("Loading rules"));
 
+	size = 0;
+
 	if (hal_fdi_source_preprobe != NULL)
-		rules_search_and_add_fdi_files (&fdi_rules_preprobe, hal_fdi_source_preprobe);
+		rules_search_and_add_fdi_files (&fdi_rules_preprobe, hal_fdi_source_preprobe, &size);
 	else {
-		rules_search_and_add_fdi_files (&fdi_rules_preprobe, PACKAGE_DATA_DIR "/hal/fdi/preprobe");
-		rules_search_and_add_fdi_files (&fdi_rules_preprobe, PACKAGE_SYSCONF_DIR "/hal/fdi/preprobe");
+		rules_search_and_add_fdi_files (&fdi_rules_preprobe, PACKAGE_DATA_DIR "/hal/fdi/preprobe", &size);
+		rules_search_and_add_fdi_files (&fdi_rules_preprobe, PACKAGE_SYSCONF_DIR "/hal/fdi/preprobe", &size);
 	}
 
 	if (hal_fdi_source_information != NULL)
-		rules_search_and_add_fdi_files (&fdi_rules_information, hal_fdi_source_information);
+		rules_search_and_add_fdi_files (&fdi_rules_information, hal_fdi_source_information, &size);
 	else {
-		rules_search_and_add_fdi_files (&fdi_rules_information, PACKAGE_DATA_DIR "/hal/fdi/information");
-		rules_search_and_add_fdi_files (&fdi_rules_information, PACKAGE_SYSCONF_DIR "/hal/fdi/information");
+		rules_search_and_add_fdi_files (&fdi_rules_information, PACKAGE_DATA_DIR "/hal/fdi/information", &size);
+		rules_search_and_add_fdi_files (&fdi_rules_information, PACKAGE_SYSCONF_DIR "/hal/fdi/information", &size);
 	}
 
 	if (hal_fdi_source_policy != NULL)
-		rules_search_and_add_fdi_files (&fdi_rules_policy, hal_fdi_source_policy);
+		rules_search_and_add_fdi_files (&fdi_rules_policy, hal_fdi_source_policy, &size);
 	else {
-		rules_search_and_add_fdi_files (&fdi_rules_policy, PACKAGE_DATA_DIR "/hal/fdi/policy");
-		rules_search_and_add_fdi_files (&fdi_rules_policy, PACKAGE_SYSCONF_DIR "/hal/fdi/policy");
+		rules_search_and_add_fdi_files (&fdi_rules_policy, PACKAGE_DATA_DIR "/hal/fdi/policy", &size);
+		rules_search_and_add_fdi_files (&fdi_rules_policy, PACKAGE_SYSCONF_DIR "/hal/fdi/policy", &size);
 	}
 
-	/* only dump the rules if we are being verbose as this is expensive */
-	if (getenv ("HALD_VERBOSE") != NULL) {
-		rules_dump (fdi_rules_preprobe);
-		rules_dump (fdi_rules_information);
-		rules_dump (fdi_rules_policy);
-	}
+	/* dump the rules (commented out as this is expensive) */
+	/*rules_dump (fdi_rules_preprobe);
+	  rules_dump (fdi_rules_information);
+	  rules_dump (fdi_rules_policy);
+	*/
 
-	HAL_INFO (("Loading rules done"));
+	HAL_INFO (("Loading rules done (occupying %d bytes)", size));
 }
 
 /* cleanup the rules */
diff-tree 8ee20db66713838d7b4bede2ba2162082b66165b (from 9cdc896239875e778682a5fc8f25a823c015761d)
Author: David Zeuthen <davidz at redhat.com>
Date:   Tue Oct 10 19:57:48 2006 -0400

    fix segfault on cleaning up rules

diff --git a/hald/device_info.c b/hald/device_info.c
index e96ee15..fd54e7a 100644
--- a/hald/device_info.c
+++ b/hald/device_info.c
@@ -1056,7 +1056,7 @@ end (void *data, const char *el)
 
 	/* set empty value to empty string */
 	if (fdi_ctx->rule->value == NULL)
-		fdi_ctx->rule->value = "";
+		fdi_ctx->rule->value = g_strdup ("");
 
 	/* insert merge rule into list and get new rule */
 	fdi_ctx->rules = g_slist_append (fdi_ctx->rules, fdi_ctx->rule);
@@ -1204,6 +1204,8 @@ di_rules_init (void)
 	char *hal_fdi_source_information = getenv ("HAL_FDI_SOURCE_INFORMATION");
 	char *hal_fdi_source_policy = getenv ("HAL_FDI_SOURCE_POLICY");
 
+	HAL_INFO (("Loading rules"));
+
 	if (hal_fdi_source_preprobe != NULL)
 		rules_search_and_add_fdi_files (&fdi_rules_preprobe, hal_fdi_source_preprobe);
 	else {
@@ -1231,6 +1233,8 @@ di_rules_init (void)
 		rules_dump (fdi_rules_information);
 		rules_dump (fdi_rules_policy);
 	}
+
+	HAL_INFO (("Loading rules done"));
 }
 
 /* cleanup the rules */
diff-tree 9cdc896239875e778682a5fc8f25a823c015761d (from 1ffd76385cebb2be97a3c474f9a92e0a64602c1b)
Author: David Zeuthen <davidz at redhat.com>
Date:   Tue Oct 10 19:44:05 2006 -0400

    forward port changes made to hald/device_info.c since June 2006

diff --git a/hald/device_info.c b/hald/device_info.c
index f1b1061..e96ee15 100644
--- a/hald/device_info.c
+++ b/hald/device_info.c
@@ -640,12 +640,11 @@ handle_match (struct rule *rule, HalDevi
 					contains = TRUE;
 			}
 		} else if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRLIST && value != NULL) {
-			GSList *list;
-			GSList *i;
-
-			list = hal_device_property_get_strlist (d, prop_to_check);
-			for (i = list; i != NULL; i = g_slist_next (i)) {
-				const char *str = i->data;
+			HalDeviceStrListIter iter;
+			for (hal_device_property_strlist_iter_init (d, prop_to_check, &iter);
+			     hal_device_property_strlist_iter_is_valid (&iter);
+			     hal_device_property_strlist_iter_next (&iter)) {
+				const char *str = hal_device_property_strlist_iter_get_value (&iter);
 				if (strcmp (str, value) == 0) {
 					contains = TRUE;
 					break;
@@ -677,12 +676,11 @@ handle_match (struct rule *rule, HalDevi
 				g_free (haystack_lowercase);
 			}
 		} else if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRLIST && value != NULL) {
-			GSList *list;
-			GSList *i;
-
-			list = hal_device_property_get_strlist (d, prop_to_check);
-			for (i = list; i != NULL; i = g_slist_next (i)) {
-				const char *str = i->data;
+			HalDeviceStrListIter iter;
+			for (hal_device_property_strlist_iter_init (d, prop_to_check, &iter);
+			     hal_device_property_strlist_iter_is_valid (&iter);
+			     hal_device_property_strlist_iter_next (&iter)) {
+				const char *str = hal_device_property_strlist_iter_get_value (&iter);
 				if (g_ascii_strcasecmp (str, value) == 0) {
 					contains_ncase = TRUE;
 					break;
@@ -745,7 +743,7 @@ handle_match (struct rule *rule, HalDevi
 static void
 spawned_device_callouts_add_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
 {
-	HAL_INFO (("Add callouts completed udi=%s", d->udi));
+	HAL_INFO (("Add callouts completed udi=%s", hal_device_get_udi (d)));
 
 	/* Move from temporary to global device store */
 	hal_device_store_remove (hald_get_tdl (), d);
@@ -909,11 +907,11 @@ handle_merge (struct rule *rule, HalDevi
 
 		if (spawned == NULL) {
 			HAL_INFO (("Spawning new device object '%s' caused by <spawn> on udi '%s'",
-				   key, d->udi));
+				   key, hal_device_get_udi (d)));
 			spawned = hal_device_new ();
 			hal_device_property_set_string (spawned, "info.bus", "unknown");
 			hal_device_property_set_string (spawned, "info.udi", key);
-			hal_device_property_set_string (spawned, "info.parent", d->udi);
+			hal_device_property_set_string (spawned, "info.parent", hal_device_get_udi (d));
 			hal_device_set_udi (spawned, key);
 
 			hal_device_store_add (hald_get_tdl (), spawned);
@@ -1141,7 +1139,11 @@ rules_dump (GSList *fdi_rules)
 
 /* modified alphasort to count downwards */
 static int
+#ifdef __GLIBC__
 _alphasort(const void *a, const void *b)
+#else
+_alphasort(const struct dirent **a, const struct dirent **b)
+#endif
 {
 	return -alphasort (a, b);
 }
diff-tree 1ffd76385cebb2be97a3c474f9a92e0a64602c1b (from 195222c1b1115e62a55b3a21898176c8d01c8da8)
Author: Kay Sievers <kay.sievers at vrfy.org>
Date:   Tue Oct 10 19:32:40 2006 -0400

    store fdi files as rules object
    
    Some work by Richard Hughes <richard at hughsie.com> to implement
    the <spawn> rules.

diff --git a/hald/device_info.c b/hald/device_info.c
index 17751d3..f1b1061 100644
--- a/hald/device_info.c
+++ b/hald/device_info.c
@@ -1,9 +1,11 @@
 /***************************************************************************
  * CVSID: $Id$
  *
- * device_store.c : Search for .fdi files and merge on match
+ * device_store.c : Parse .fdi files and match/merge device properties.
  *
  * Copyright (C) 2003 David Zeuthen, <david at fubar.dk>
+ * Copyright (C) 2006 Kay Sievers, <kay.sievers at vrfy.org>
+ * Copyright (C) 2006 Richard Hughes <richard at hughsie.com>
  *
  * Licensed under the Academic Free License version 2.1
  *
@@ -31,10 +33,12 @@
 #include <stdlib.h>
 #include <string.h>
 #include <dirent.h>
+#include <unistd.h>
 #include <expat.h>
 #include <assert.h>
 #include <dbus/dbus.h>
 #include <dbus/dbus-glib.h>
+#include <sys/stat.h>
 #include <math.h>
 
 #include "hald.h"
@@ -43,122 +47,257 @@
 #include "device_store.h"
 #include "util.h"
 
-/**
- * @defgroup DeviceInfo Device Info File Parsing
- * @ingroup HalDaemon
- * @brief Parsing of device info files
- * @{
- */
-
-
-/** Maximum nesting depth */
-#define MAX_DEPTH 32
-
-/** Maximum amount of CDATA */
-#define CDATA_BUF_SIZE  1024
-
-/** Max length of property key */
-#define MAX_KEY_SIZE 128
-
-/** Possible elements the parser can process */
-enum {
-	/** Not processing a known tag */
-	CURELEM_UNKNOWN = -1,
-
-	/** Processing a deviceinfo element */
-	CURELEM_DEVICE_INFO = 0,
-
-	/** Processing a device element */
-	CURELEM_DEVICE = 1,
-
-	/** Processing a match element */
-	CURELEM_MATCH = 2,
-
-	/** Processing a merge element */
-	CURELEM_MERGE = 3,
-
-	/** Processing an append element */
-	CURELEM_APPEND = 4,
-
-	/** Processing a prepend element */
-	CURELEM_PREPEND = 5,
-
-	/** Processing a remove element */
-	CURELEM_REMOVE = 6,
-
-	/** Processing a clear element */
-	CURELEM_CLEAR = 7,
+#define MAX_INDENT_DEPTH		64
 
-	/** Processing a spawn element */
-	CURELEM_SPAWN = 8
+/* pre-parsed rules to keep in memory */
+static GSList *fdi_rules_preprobe;
+static GSList *fdi_rules_information;
+static GSList *fdi_rules_policy;
+
+/* rule type to process */
+enum rule_type {
+	RULE_UNKNOWN,
+	RULE_MATCH,
+	RULE_MERGE,
+	RULE_APPEND,
+	RULE_PREPEND,
+	RULE_REMOVE,
+	RULE_CLEAR,
+	RULE_SPAWN,
+	RULE_EOF,
 };
 
-/** What and how to merge */
-enum {
-	MERGE_TYPE_UNKNOWN       = 0,
-	MERGE_TYPE_STRING        = 1,
-	MERGE_TYPE_BOOLEAN       = 2,
-	MERGE_TYPE_INT32         = 3,
-	MERGE_TYPE_UINT64        = 4,
-	MERGE_TYPE_DOUBLE        = 5,
-	MERGE_TYPE_COPY_PROPERTY = 6,
-	MERGE_TYPE_STRLIST       = 7,
-	MERGE_TYPE_REMOVE        = 8,
-	MERGE_TYPE_CLEAR         = 9,
-	MERGE_TYPE_SPAWN         = 10
+/* type of merge command */
+enum merge_type {
+	MERGE_UNKNOWN,
+	MERGE_STRING,
+	MERGE_BOOLEAN,
+	MERGE_INT32,
+	MERGE_UINT64,
+	MERGE_DOUBLE,
+	MERGE_COPY_PROPERTY,
+	MERGE_STRLIST,
+	MERGE_REMOVE,
 };
 
-/** Parsing Context
- */
-typedef struct {
-	/** Name of file being parsed */
-	char *file;
-
-	/** Parser object */
-	XML_Parser parser;
-
-	/** Device we are trying to match*/
-	HalDevice *device;
-
-	/** Buffer to put CDATA in */
-	char cdata_buf[CDATA_BUF_SIZE];
-
-	/** Current length of CDATA buffer */
-	int cdata_buf_len;
-	
-	/** Current depth we are parsing at */
-	int depth;
+/* type of match command */
+enum
+match_type {
+	MATCH_UNKNOWN,
+	MATCH_STRING,
+	MATCH_INT,
+	MATCH_UINT64,
+	MATCH_BOOL,
+	MATCH_EXISTS,
+	MATCH_EMPTY,
+	MATCH_ISASCII,
+	MATCH_IS_ABS_PATH,
+	MATCH_CONTAINS,
+	MATCH_CONTAINS_NCASE,
+	MATCH_COMPARE_LT,
+	MATCH_COMPARE_LE,
+	MATCH_COMPARE_GT,
+	MATCH_COMPARE_GE,
+};
 
-	/** Element currently being processed */
-	int curelem;
+/* a "rule" structure that is a generic node of the fdi file */
+struct rule {
+	/* typ of tule in the list */
+	enum rule_type rtype;
+
+	/* all rules have a key */
+	char *key;
+
+	/* "match" or "merge" rule */
+	enum match_type type_match;
+	enum merge_type type_merge;
 
-	/** Stack of elements being processed */
-	int curelem_stack[MAX_DEPTH];
+	char *value;
+	int value_len;
 
-	/** #TRUE if parsing of document have been aborted */
-	dbus_bool_t aborted;
+	/* if rule does not match, skip to this rule */
+	struct rule *next_rule;
+};
 
+/* ctx of the current fdi file used for parsing */
+struct fdi_context {
+	int depth;
+	struct rule *match_at_depth[MAX_INDENT_DEPTH];
 
-	/** Depth of match-fail */
-	int match_depth_first_fail;
+	/* current rule */
+	struct rule *rule;
 
-	/** #TRUE if all matches on prior depths have been OK */
-	dbus_bool_t match_ok;
+	/* all rules */
+	GSList* rules;
+};
 
+static enum
+rule_type get_rule_type (const char *str)
+{
+	if (strcmp (str, "match") == 0)
+		return RULE_MATCH;
+	if (strcmp (str, "merge") == 0)
+		return RULE_MERGE;
+	if (strcmp (str, "append") == 0)
+		return RULE_APPEND;
+	if (strcmp (str, "prepend") == 0)
+		return RULE_PREPEND;
+	if (strcmp (str, "remove") == 0)
+		return RULE_REMOVE;
+	if (strcmp (str, "clear") == 0)
+		return RULE_CLEAR;
+	if (strcmp (str, "spawn") == 0)
+		return RULE_SPAWN;
+	return RULE_UNKNOWN;
+}
 
+static char *
+get_rule_type_str (enum rule_type type)
+{
+	switch (type) {
+	case RULE_MATCH:
+		return "match";
+	case RULE_MERGE:
+		return "merge";
+	case RULE_APPEND:
+		return "append";
+	case RULE_PREPEND:
+		return "prepend";
+	case RULE_REMOVE:
+		return "remove";
+	case RULE_CLEAR:
+		return "clear";
+	case RULE_SPAWN:
+		return "spawn";
+	case RULE_EOF:
+		return "eof";
+	case RULE_UNKNOWN:
+		return "unknown rule type";
+	}
+	return "invalid rule type";
+}
 
-	/** When merging, the key to store the value in */
-	char merge_key[MAX_KEY_SIZE];
+static enum
+merge_type get_merge_type (const char *str)
+{
+	if (strcmp (str, "string") == 0)
+		return MERGE_STRING;
+	if (strcmp (str, "bool") == 0)
+		return MERGE_BOOLEAN;
+	if (strcmp (str, "int") == 0)
+		return MERGE_INT32;
+	if (strcmp (str, "unint64") == 0)
+		return MERGE_UINT64;
+	if (strcmp (str, "double") == 0)
+		return MERGE_DOUBLE;
+	if (strcmp (str, "strlist") == 0)
+		return MERGE_STRLIST;
+	if (strcmp (str, "copy_property") == 0)
+		return MERGE_COPY_PROPERTY;
+	if (strcmp (str, "remove") == 0)
+		return MERGE_REMOVE;
+	return MERGE_UNKNOWN;
+}
 
-	/** Type to merge*/
-	int merge_type;
+static char *
+get_merge_type_str (enum merge_type type)
+{
+	switch (type) {
+	case MERGE_STRING:
+		return "string";
+	case MERGE_BOOLEAN:
+		return "bool";
+	case MERGE_INT32:
+		return "int";
+	case MERGE_UINT64:
+		return "unint64";
+	case MERGE_DOUBLE:
+		return "double";
+	case MERGE_STRLIST:
+		return "strlist";
+	case MERGE_COPY_PROPERTY:
+		return "copy_property";
+	case MERGE_REMOVE:
+		return "remove";
+	case MERGE_UNKNOWN:
+		return "unknown merge type";
+	}
+	return "invalid merge type";
+}
 
-	/** Set to #TRUE if a device is matched */
-	dbus_bool_t device_matched;
+static enum
+match_type get_match_type(const char *str)
+{
+	if (strcmp (str, "string") == 0)
+		return MATCH_STRING;
+	if (strcmp (str, "int") == 0)
+		return MATCH_INT;
+	if (strcmp (str, "uint64") == 0)
+		return MATCH_UINT64;
+	if (strcmp (str, "bool") == 0)
+		return MATCH_BOOL;
+	if (strcmp (str, "exists") == 0)
+		return MATCH_EXISTS;
+	if (strcmp (str, "empty") == 0)
+		return MATCH_EMPTY;
+	if (strcmp (str, "is_ascii") == 0)
+		return MATCH_ISASCII;
+	if (strcmp (str, "is_absolute_path") == 0)
+		return MATCH_IS_ABS_PATH;
+	if (strcmp (str, "contains") == 0)
+		return MATCH_CONTAINS;
+	if (strcmp (str, "contains_ncase") == 0)
+		return MATCH_CONTAINS_NCASE;
+	if (strcmp (str, "compare_lt") == 0)
+		return MATCH_COMPARE_LT;
+	if (strcmp (str, "compare_le") == 0)
+		return MATCH_COMPARE_LE;
+	if (strcmp (str, "compare_gt") == 0)
+		return MATCH_COMPARE_GT;
+	if (strcmp (str, "compare_ge") == 0)
+		return MATCH_COMPARE_GE;
+	return MATCH_UNKNOWN;
+}
 
-} ParsingContext;
+static char *
+get_match_type_str (enum match_type type)
+{
+	switch (type) {
+	case MATCH_STRING:
+		return "string";
+	case MATCH_INT:
+		return "int";
+	case MATCH_UINT64:
+		return "uint64";
+	case MATCH_BOOL:
+		return "bool";
+	case MATCH_EXISTS:
+		return "exists";
+	case MATCH_EMPTY:
+		return "empty";
+	case MATCH_ISASCII:
+		return "is_ascii";
+	case MATCH_IS_ABS_PATH:
+		return "is_absolute_path";
+	case MATCH_CONTAINS:
+		return "contains";
+	case MATCH_CONTAINS_NCASE:
+		return "contains_ncase";
+	case MATCH_COMPARE_LT:
+		return "compare_lt";
+	case MATCH_COMPARE_LE:
+		return "compare_le";
+	case MATCH_COMPARE_GT:
+		return "compare_gt";
+	case MATCH_COMPARE_GE:
+		return "compare_ge";
+	case MATCH_UNKNOWN:
+		return "unknown match type";
+	}
+	return "invalid match type";
+}
 
-/** Resolve a udi-property path as used in .fdi files. 
+/** Resolve a udi-property path as used in .fdi files.
  *
  *  Examples of udi-property paths:
  *
@@ -177,16 +316,12 @@ typedef struct {
  */
 static gboolean
 resolve_udiprop_path (const char *path, const char *source_udi,
-		      char *udi_result, size_t udi_result_size, 
+		      char *udi_result, size_t udi_result_size,
 		      char *prop_result, size_t prop_result_size)
 {
 	int i;
 	gchar **tokens = NULL;
-	gboolean rc;
-
-	rc = FALSE;
-
-	/*HAL_INFO (("Looking at '%s' for udi='%s'", path, source_udi));*/
+	gboolean rc = FALSE;
 
 	/* Split up path into ':' tokens */
 	tokens = g_strsplit (path, ":", 64);
@@ -235,26 +370,15 @@ resolve_udiprop_path (const char *path, 
 			if (newudi == NULL)
 				goto out;
 
-			/*HAL_INFO (("new_udi = '%s' (from indirection)", newudi));*/
-
 			strncpy (udi_result, newudi, udi_result_size);
 		} else {
-			/*HAL_INFO (("new_udi = '%s'", curtoken));*/
 			strncpy (udi_result, curtoken, udi_result_size);
 		}
 
 	}
 
 out:
-
-/*
-	HAL_INFO (("success     = '%s'", rc ? "yes" : "no"));
-	HAL_INFO (("udi_result  = '%s'", udi_result));
-	HAL_INFO (("prop_result = '%s'", prop_result));
-*/
-
 	g_strfreev (tokens);
-
 	return rc;
 }
 
@@ -317,135 +441,86 @@ out:
 	return rc;
 }
 
-/** Called when the match element begins.
- *
- *  @param  pc                  Parsing context
- *  @param  attr                Attribute key/value pairs
- *  @return                     #FALSE if the device in question didn't
- *                              match the data in the attributes
- */
-static dbus_bool_t
-handle_match (ParsingContext * pc, const char **attr)
+static gboolean
+handle_match (struct rule *rule, HalDevice *d)
 {
-	char udi_to_check[256];
-	char prop_to_check[256];
-	const char *key;
-	int num_attrib;
-	HalDevice *d;
-
-	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++);
-
-	if (num_attrib != 4)
-		return FALSE;
-
-	if (strcmp (attr[0], "key") != 0)
-		return FALSE;
-	key = attr[1];
+	char udi_to_check[HAL_PATH_MAX];
+	char prop_to_check[HAL_PATH_MAX];
+	const char *key = rule->key;
+	const char *value = rule->value;
 
 	/* Resolve key paths like 'someudi/foo/bar/baz:prop.name' '@prop.here.is.an.udi:with.prop.name' */
 	if (!resolve_udiprop_path (key,
-				   pc->device->udi,
+				   hal_device_get_udi (d),
 				   udi_to_check, sizeof (udi_to_check),
 				   prop_to_check, sizeof (prop_to_check))) {
-		HAL_ERROR (("Could not resolve keypath '%s' on udi '%s'", key, pc->device->udi));
+		HAL_ERROR (("Could not resolve keypath '%s' on udi '%s'", key, value));
 		return FALSE;
 	}
 
 	d = hal_device_store_find (hald_get_gdl (), udi_to_check);
-	if (d == NULL) {
+	if (d == NULL)
 		d = hal_device_store_find (hald_get_tdl (), udi_to_check);
-	}
 	if (d == NULL) {
 		HAL_ERROR (("Could not find device with udi '%s'", udi_to_check));
 		return FALSE;
 	}
-	
-
-	if (strcmp (attr[2], "string") == 0) {
-		const char *value;
-
-		/* match string property */
-
-		value = attr[3];
-
-		/*HAL_INFO(("Checking that key='%s' is a string that "
-		  "equals '%s'", key, value)); */
 
+	switch (rule->type_match) {
+	case MATCH_STRING:
+	{
 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_STRING)
 			return FALSE;
-
-		if (strcmp (hal_device_property_get_string (d, prop_to_check),
-			    value) != 0)
+		if (strcmp (hal_device_property_get_string (d, prop_to_check), value) != 0)
 			return FALSE;
-
-		/*HAL_INFO (("*** string match for key %s", key));*/
 		return TRUE;
-	} else if (strcmp (attr[2], "int") == 0) {
-		dbus_int32_t value;
-
-		/* match integer property */
-		value = strtol (attr[3], NULL, 0);
-		
-		/** @todo Check error condition */
+	}
 
-		/*HAL_INFO (("Checking that key='%s' is a int that equals %d", 
-		  key, value));*/
+	case MATCH_INT:
+	{
+		int val = strtol (value, NULL, 0);
 
 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_INT32)
 			return FALSE;
-
-		if (hal_device_property_get_int (d, prop_to_check) != value) {
+		if (hal_device_property_get_int (d, prop_to_check) != val)
 			return FALSE;
-		}
-
 		return TRUE;
-	} else if (strcmp (attr[2], "uint64") == 0) {
-		dbus_uint64_t value;
-
-		/* match integer property */
-		value = strtoull (attr[3], NULL, 0);
-		
-		/** @todo Check error condition */
+	}
 
-		/*HAL_INFO (("Checking that key='%s' is a int that equals %d", 
-		  key, value));*/
+	case MATCH_UINT64:
+	{
+		dbus_uint64_t val = strtol (value, NULL, 0);
 
 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_UINT64)
 			return FALSE;
-
-		if (hal_device_property_get_uint64 (d, prop_to_check) != value) {
+		if (hal_device_property_get_uint64 (d, prop_to_check) != val)
 			return FALSE;
-		}
-
 		return TRUE;
-	} else if (strcmp (attr[2], "bool") == 0) {
-		dbus_bool_t value;
-
-		/* match string property */
+	}
 
-		if (strcmp (attr[3], "false") == 0)
-			value = FALSE;
-		else if (strcmp (attr[3], "true") == 0)
-			value = TRUE;
+	case MATCH_BOOL:
+	{
+		dbus_bool_t val;
+
+		if (strcmp (value, "false") == 0)
+			val = FALSE;
+		else if (strcmp (value, "true") == 0)
+			val = TRUE;
 		else
 			return FALSE;
 
-		/*HAL_INFO (("Checking that key='%s' is a bool that equals %s", 
-		  key, value ? "TRUE" : "FALSE"));*/
-
-		if (hal_device_property_get_type (d, prop_to_check) != 
-		    HAL_PROPERTY_TYPE_BOOLEAN)
+		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_BOOLEAN)
 			return FALSE;
-
-		if (hal_device_property_get_bool (d, prop_to_check) != value)
+		if (hal_device_property_get_bool (d, prop_to_check) != val)
 			return FALSE;
-
-		/*HAL_INFO (("*** bool match for key %s", key));*/
 		return TRUE;
-	} else if (strcmp (attr[2], "exists") == 0) {
+	}
+
+	case MATCH_EXISTS:
+	{
 		dbus_bool_t should_exist = TRUE;
 
-		if (strcmp (attr[3], "false") == 0)
+		if (strcmp (value, "false") == 0)
 			should_exist = FALSE;
 
 		if (should_exist) {
@@ -459,16 +534,17 @@ handle_match (ParsingContext * pc, const
 			else
 				return TRUE;
 		}
-	} else if (strcmp (attr[2], "empty") == 0) {
+	}
+
+	case MATCH_EMPTY:
+	{
 		dbus_bool_t is_empty = TRUE;
 		dbus_bool_t should_be_empty = TRUE;
 
-		if (strcmp (attr[3], "false") == 0)
+		if (strcmp (value, "false") == 0)
 			should_be_empty = FALSE;
-
 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_STRING)
 			return FALSE;
-
 		if (hal_device_has_property (d, prop_to_check))
 			if (strlen (hal_device_property_get_string (d, prop_to_check)) > 0)
 				is_empty = FALSE;
@@ -484,13 +560,16 @@ handle_match (ParsingContext * pc, const
 			else
 				return TRUE;
 		}
-	} else if (strcmp (attr[2], "is_ascii") == 0) {
+	}
+
+	case MATCH_ISASCII:
+	{
 		dbus_bool_t is_ascii = TRUE;
 		dbus_bool_t should_be_ascii = TRUE;
 		unsigned int i;
 		const char *str;
 
-		if (strcmp (attr[3], "false") == 0)
+		if (strcmp (value, "false") == 0)
 			should_be_ascii = FALSE;
 
 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_STRING)
@@ -515,16 +594,17 @@ handle_match (ParsingContext * pc, const
 			else
 				return TRUE;
 		}
-	} else if (strcmp (attr[2], "is_absolute_path") == 0) {
+	}
+
+	case MATCH_IS_ABS_PATH:
+	{
 		const char *path = NULL;
 		dbus_bool_t is_absolute_path = FALSE;
 		dbus_bool_t should_be_absolute_path = TRUE;
 
-		if (strcmp (attr[3], "false") == 0)
+		if (strcmp (value, "false") == 0)
 			should_be_absolute_path = FALSE;
 
-		/*HAL_INFO (("d->udi='%s', prop_to_check='%s'", d->udi, prop_to_check));*/
-
 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_STRING)
 			return FALSE;
 
@@ -534,8 +614,6 @@ handle_match (ParsingContext * pc, const
 				is_absolute_path = TRUE;
 		}
 
-		/*HAL_INFO (("is_absolute=%d, should_be=%d, path='%s'", is_absolute_path, should_be_absolute_path, path));*/
-
 		if (should_be_absolute_path) {
 			if (is_absolute_path)
 				return TRUE;
@@ -547,31 +625,28 @@ handle_match (ParsingContext * pc, const
 			else
 				return TRUE;
 		}
-	} else if (strcmp (attr[2], "contains") == 0) {
-		const char *needle;
-		dbus_bool_t contains = FALSE;
+	}
 
-		needle = attr[3];
+	case MATCH_CONTAINS:
+	{
+		dbus_bool_t contains = FALSE;
 
 		if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRING) {
 			if (hal_device_has_property (d, prop_to_check)) {
 				const char *haystack;
-				
+
 				haystack = hal_device_property_get_string (d, prop_to_check);
-				if (needle != NULL && haystack != NULL && strstr (haystack, needle)) {
+				if (value != NULL && haystack != NULL && strstr (haystack, value))
 					contains = TRUE;
-				}
-				
 			}
-		} else if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRLIST && 
-			   needle != NULL) {
+		} else if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRLIST && value != NULL) {
+			GSList *list;
 			GSList *i;
-			GSList *value;
 
-			value = hal_device_property_get_strlist (d, prop_to_check);
-			for (i = value; i != NULL; i = g_slist_next (i)) {
+			list = hal_device_property_get_strlist (d, prop_to_check);
+			for (i = list; i != NULL; i = g_slist_next (i)) {
 				const char *str = i->data;
-				if (strcmp (str, needle) == 0) {
+				if (strcmp (str, value) == 0) {
 					contains = TRUE;
 					break;
 				}
@@ -581,482 +656,93 @@ handle_match (ParsingContext * pc, const
 		}
 
 		return contains;
-	} else if (strcmp (attr[2], "contains_ncase") == 0) {
-		const char *needle;
-		dbus_bool_t contains_ncase = FALSE;
+	}
 
-		needle = attr[3];
+	case MATCH_CONTAINS_NCASE:
+	{
+		dbus_bool_t contains_ncase = FALSE;
 
 		if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRING) {
 			if (hal_device_has_property (d, prop_to_check)) {
-				char *needle_lowercase;
+				char *value_lowercase;
 				char *haystack_lowercase;
-				
-				needle_lowercase   = g_utf8_strdown (needle, -1);
+
+				value_lowercase   = g_utf8_strdown (value, -1);
 				haystack_lowercase = g_utf8_strdown (hal_device_property_get_string (d, prop_to_check), -1);
-				if (needle_lowercase != NULL && haystack_lowercase != NULL && strstr (haystack_lowercase, needle_lowercase)) {
+				if (value_lowercase != NULL && haystack_lowercase != NULL &&
+				    strstr (haystack_lowercase, value_lowercase))
 					contains_ncase = TRUE;
-				}
-				
-				g_free (needle_lowercase);
+
+				g_free (value_lowercase);
 				g_free (haystack_lowercase);
 			}
-		} else if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRLIST && 
-			   needle != NULL) {
+		} else if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRLIST && value != NULL) {
+			GSList *list;
 			GSList *i;
-			GSList *value;
 
-			value = hal_device_property_get_strlist (d, prop_to_check);
-			for (i = value; i != NULL; i = g_slist_next (i)) {
+			list = hal_device_property_get_strlist (d, prop_to_check);
+			for (i = list; i != NULL; i = g_slist_next (i)) {
 				const char *str = i->data;
-				if (g_ascii_strcasecmp (str, needle) == 0) {
+				if (g_ascii_strcasecmp (str, value) == 0) {
 					contains_ncase = TRUE;
 					break;
 				}
 			}
-		} else {
+		} else
 			return FALSE;
-		}
-
 		return contains_ncase;
-	} else if (strcmp (attr[2], "compare_lt") == 0) {
+	}
+
+	case MATCH_COMPARE_LT:
+	{
 		dbus_int64_t result;
-		if (!match_compare_property (d, prop_to_check, attr[3], &result)) {
+
+		if (!match_compare_property (d, prop_to_check, value, &result))
 			return FALSE;
-		} else {
+		else
 			return result < 0;
-		}
-	} else if (strcmp (attr[2], "compare_le") == 0) {
+	}
+
+	case MATCH_COMPARE_LE:
+	{
 		dbus_int64_t result;
-		if (!match_compare_property (d, prop_to_check, attr[3], &result))
+
+		if (!match_compare_property (d, prop_to_check, value, &result))
 			return FALSE;
 		else
 			return result <= 0;
-	} else if (strcmp (attr[2], "compare_gt") == 0) {
+	}
+
+	case MATCH_COMPARE_GT:
+	{
 		dbus_int64_t result;
-		if (!match_compare_property (d, prop_to_check, attr[3], &result))
+
+		if (!match_compare_property (d, prop_to_check, value, &result))
 			return FALSE;
 		else
 			return result > 0;
-	} else if (strcmp (attr[2], "compare_ge") == 0) {
+	}
+
+	case MATCH_COMPARE_GE:
+	{
 		dbus_int64_t result;
-		if (!match_compare_property (d, prop_to_check, attr[3], &result))
+
+		if (!match_compare_property (d, prop_to_check, value, &result))
 			return FALSE;
 		else
 			return result >= 0;
 	}
-	
-	return FALSE;
-}
-
-
-/** Called when the merge element begins.
- *
- *  @param  pc                  Parsing context
- *  @param  attr                Attribute key/value pairs
- */
-static void
-handle_merge (ParsingContext * pc, const char **attr)
-{
-	int num_attrib;
-
-	pc->merge_type = MERGE_TYPE_UNKNOWN;
-
-
-	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++) {
-		;
-	}
-
-	if (num_attrib != 4)
-		return;
-
-	if (strcmp (attr[0], "key") != 0)
-		return;
-	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
-
-	if (strcmp (attr[2], "type") != 0)
-		return;
-
-	if (strcmp (attr[3], "string") == 0) {
-		/* match string property */
-		pc->merge_type = MERGE_TYPE_STRING;
-		return;
-	} else if (strcmp (attr[3], "bool") == 0) {
-		/* match string property */
-		pc->merge_type = MERGE_TYPE_BOOLEAN;
-		return;
-	} else if (strcmp (attr[3], "int") == 0) {
-		/* match string property */
-		pc->merge_type = MERGE_TYPE_INT32;
-		return;
-	} else if (strcmp (attr[3], "uint64") == 0) {
-		/* match string property */
-		pc->merge_type = MERGE_TYPE_UINT64;
-		return;
-	} else if (strcmp (attr[3], "double") == 0) {
-		/* match string property */
-		pc->merge_type = MERGE_TYPE_DOUBLE;
-		return;
-	} else if (strcmp (attr[3], "strlist") == 0) {
-		/* match string property */
-		pc->merge_type = MERGE_TYPE_STRLIST;
-		return;
-	} else if (strcmp (attr[3], "copy_property") == 0) {
-		/* copy another property */
-		pc->merge_type = MERGE_TYPE_COPY_PROPERTY;
-		return;
-	}
-
-	return;
-}
-
-/** Called when the append or prepend element begins.
- *
- *  @param  pc                  Parsing context
- *  @param  attr                Attribute key/value pairs
- */
-static void
-handle_append_prepend (ParsingContext * pc, const char **attr)
-{
-	int num_attrib;
-
-	pc->merge_type = MERGE_TYPE_UNKNOWN;
-
-	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++) {
-		;
-	}
-
-	if (num_attrib != 4)
-		return;
-
-	if (strcmp (attr[0], "key") != 0)
-		return;
-	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
-
-	if (strcmp (attr[2], "type") != 0)
-		return;
-
-	if (strcmp (attr[3], "string") == 0) {
-		/* append to a string */
-		pc->merge_type = MERGE_TYPE_STRING;
-		return;
-	} else if (strcmp (attr[3], "strlist") == 0) {
-		/* append to a string list*/
-		pc->merge_type = MERGE_TYPE_STRLIST;
-		return;
-	} else if (strcmp (attr[3], "copy_property") == 0) {
-		/* copy another property */
-		pc->merge_type = MERGE_TYPE_COPY_PROPERTY;
-		return;
-	}
-
-	return;
-}
-
-
-/** Called when the spawn element begins.
- *
- *  @param  pc                  Parsing context
- *  @param  attr                Attribute key/value pairs
- */
-static void
-handle_spawn (ParsingContext * pc, const char **attr)
-{
-	int num_attrib;
-
-	pc->merge_type = MERGE_TYPE_UNKNOWN;
-
-	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++) {
-		;
-	}
-
-	if (num_attrib != 2)
-		return;
-
-	if (strcmp (attr[0], "udi") != 0)
-		return;
-
-	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
-
-	pc->merge_type = MERGE_TYPE_SPAWN;
-
-	return;
-}
-
-/** Called when the remove element begins.
- *
- *  @param  pc                  Parsing context
- *  @param  attr                Attribute key/value pairs
- */
-static void
-handle_remove (ParsingContext * pc, const char **attr)
-{
-	int num_attrib;
-
-	pc->merge_type = MERGE_TYPE_UNKNOWN;
-
-	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++) {
-		;
-	}
-
-	if (num_attrib != 2 && num_attrib != 4)
-		return;
-
-	if (strcmp (attr[0], "key") != 0)
-		return;
-	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
-
-	if (num_attrib == 4) {
-		if (strcmp (attr[2], "type") != 0)
-			return;
-
-		if (strcmp (attr[3], "strlist") == 0) {
-			/* remove from strlist */
-			pc->merge_type = MERGE_TYPE_STRLIST;
-			return;
-		} else {
-			pc->merge_type = MERGE_TYPE_UNKNOWN;
-			return;
-		}
-	} else {
-		pc->merge_type = MERGE_TYPE_REMOVE;
-	}
-
-	return;
-}
-
-/** Called when the clear element begins.
- *
- *  @param  pc                  Parsing context
- *  @param  attr                Attribute key/value pairs
- */
-static void
-handle_clear (ParsingContext * pc, const char **attr)
-{
-	int num_attrib;
-
-	pc->merge_type = MERGE_TYPE_UNKNOWN;
 
-	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++) {
-		;
+	default:
+		HAL_INFO(("match ERROR"));
+		return FALSE;
 	}
 
-	if (num_attrib != 4)
-		return;
-	
-	if (strcmp (attr[0], "key") != 0)
-		return;
-
-
-	if (strcmp (attr[3], "strlist") != 0)
-		return;
-	
-	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
-	
-	pc->merge_type = MERGE_TYPE_CLEAR;
-
-	return;
-}
-
-/** Abort parsing of document
- *
- *  @param  pc                  Parsing context
- */
-static void
-parsing_abort (ParsingContext * pc)
-{
-	/* Grr, expat can't abort parsing */
-	HAL_ERROR (("Aborting parsing of document"));
-	pc->aborted = TRUE;
+	return FALSE;
 }
 
-/** Called by expat when an element begins.
- *
- *  @param  pc                  Parsing context
- *  @param  el                  Element name
- *  @param  attr                Attribute key/value pairs
- */
+/* we have finished the callouts for a device, now add it to the gdl */
 static void
-start (ParsingContext * pc, const char *el, const char **attr)
-{
-	if (pc->aborted)
-		return;
-
-	pc->cdata_buf_len = 0;
-
-/*
-    for (i = 0; i < pc->depth; i++)
-        printf("  ");
-    
-    printf("%s", el);
-    
-    for (i = 0; attr[i]; i += 2) {
-        printf(" %s='%s'", attr[i], attr[i + 1]);
-    }
-
-    printf("   curelem=%d\n", pc->curelem);
-*/
-
-	if (strcmp (el, "match") == 0) {
-		if (pc->curelem != CURELEM_DEVICE
-		    && pc->curelem != CURELEM_MATCH) {
-			HAL_ERROR (("%s:%d:%d: Element <match> can only be "
-				    "inside <device> and <match>", 
-				    pc->file, 
-				    XML_GetCurrentLineNumber (pc->parser), 
-				    XML_GetCurrentColumnNumber (pc->parser)));
-			parsing_abort (pc);
-		}
-
-		pc->curelem = CURELEM_MATCH;
-
-		/* don't bother checking if matching at lower depths failed */
-		if (pc->match_ok) {
-			if (!handle_match (pc, attr)) {
-				/* No match */
-				pc->match_depth_first_fail = pc->depth;
-				pc->match_ok = FALSE;
-			}
-		}
-	} else if (strcmp (el, "merge") == 0) {
-		if (pc->curelem != CURELEM_DEVICE
-		    && pc->curelem != CURELEM_MATCH) {
-			HAL_ERROR (("%s:%d:%d: Element <merge> can only be "
-				    "inside <device> and <match>", 
-				    pc->file, 
-				    XML_GetCurrentLineNumber (pc->parser), 
-				    XML_GetCurrentColumnNumber (pc->parser)));
-			parsing_abort (pc);
-		}
-
-		pc->curelem = CURELEM_MERGE;
-		if (pc->match_ok) {
-			handle_merge (pc, attr);
-		} else {
-			/*HAL_INFO(("No merge!")); */
-		}
-	} else if (strcmp (el, "append") == 0) {
-		if (pc->curelem != CURELEM_DEVICE
-		    && pc->curelem != CURELEM_MATCH) {
-			HAL_ERROR (("%s:%d:%d: Element <append> can only be "
-				    "inside <device> and <match>", 
-				    pc->file, 
-				    XML_GetCurrentLineNumber (pc->parser), 
-				    XML_GetCurrentColumnNumber (pc->parser)));
-			parsing_abort (pc);
-		}
-
-		pc->curelem = CURELEM_APPEND;
-		if (pc->match_ok) {
-			handle_append_prepend (pc, attr);
-		} else {
-			/*HAL_INFO(("No merge!")); */
-		}
-	} else if (strcmp (el, "prepend") == 0) {
-		if (pc->curelem != CURELEM_DEVICE
-		    && pc->curelem != CURELEM_MATCH) {
-			HAL_ERROR (("%s:%d:%d: Element <prepend> can only be "
-				    "inside <device> and <match>", 
-				    pc->file, 
-				    XML_GetCurrentLineNumber (pc->parser), 
-				    XML_GetCurrentColumnNumber (pc->parser)));
-			parsing_abort (pc);
-		}
-
-		pc->curelem = CURELEM_PREPEND;
-		if (pc->match_ok) {
-			handle_append_prepend (pc, attr);
-		} else {
-			/*HAL_INFO(("No merge!")); */
-		}
-	} else if (strcmp (el, "remove") == 0) {
-		if (pc->curelem != CURELEM_DEVICE
-		    && pc->curelem != CURELEM_MATCH) {
-			HAL_ERROR (("%s:%d:%d: Element <remove> can only be "
-				    "inside <device> and <match>", 
-				    pc->file, 
-				    XML_GetCurrentLineNumber (pc->parser), 
-				    XML_GetCurrentColumnNumber (pc->parser)));
-			parsing_abort (pc);
-		}
-
-		pc->curelem = CURELEM_REMOVE;
-		if (pc->match_ok) {
-			handle_remove (pc, attr);
-		} else {
-			/*HAL_INFO(("No merge!")); */
-		}
-	} else if (strcmp (el, "clear") == 0) {
-		if (pc->curelem != CURELEM_DEVICE
-		    && pc->curelem != CURELEM_MATCH) {
-			HAL_ERROR (("%s:%d:%d: Element <remove> can only be "
-				    "inside <device> and <match>", 
-				    pc->file, 
-				    XML_GetCurrentLineNumber (pc->parser), 
-				    XML_GetCurrentColumnNumber (pc->parser)));
-			parsing_abort (pc);
-		}
-
-		pc->curelem = CURELEM_CLEAR;
-		if (pc->match_ok) {
-			handle_clear (pc, attr);
-		} else {
-			/*HAL_INFO(("No merge!")); */
-		}
-	} else if (strcmp (el, "device") == 0) {
-		if (pc->curelem != CURELEM_DEVICE_INFO) {
-			HAL_ERROR (("%s:%d:%d: Element <device> can only be "
-				    "inside <deviceinfo>", 
-				    pc->file, 
-				    XML_GetCurrentLineNumber (pc->parser), 
-				    XML_GetCurrentColumnNumber (pc->parser)));
-			parsing_abort (pc);
-		}
-		pc->curelem = CURELEM_DEVICE;
-	} else if (strcmp (el, "deviceinfo") == 0) {
-		if (pc->curelem != CURELEM_UNKNOWN) {
-			HAL_ERROR (("%s:%d:%d: Element <deviceinfo> must be "
-				    "a top-level element", 
-				    pc->file, 
-				    XML_GetCurrentLineNumber (pc->parser), 
-				    XML_GetCurrentColumnNumber (pc->parser)));
-			parsing_abort (pc);
-		}
-		pc->curelem = CURELEM_DEVICE_INFO;
-	} else if (strcmp (el, "spawn") == 0) {
-		if (pc->curelem != CURELEM_MATCH) {
-			HAL_ERROR (("%s:%d:%d: Element <spawn> can only be "
-				    "inside <match>", 
-				    pc->file, 
-				    XML_GetCurrentLineNumber (pc->parser), 
-				    XML_GetCurrentColumnNumber (pc->parser)));
-			parsing_abort (pc);
-		}
-
-		pc->curelem = CURELEM_SPAWN;
-		if (pc->match_ok) {
-			handle_spawn (pc, attr);
-		} 
-
-	} else {
-		HAL_ERROR (("%s:%d:%d: Unknown element <%s>",
-			    pc->file,
-			    XML_GetCurrentLineNumber (pc->parser),
-			    XML_GetCurrentColumnNumber (pc->parser), el));
-		parsing_abort (pc);
-	}
-
-	/* Nasty hack */
-	assert (pc->depth < MAX_DEPTH);
-
-	pc->depth++;
-
-	/* store depth */
-	pc->curelem_stack[pc->depth] = pc->curelem;
-
-}
-
-static void 
 spawned_device_callouts_add_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
 {
 	HAL_INFO (("Add callouts completed udi=%s", d->udi));
@@ -1064,96 +750,55 @@ spawned_device_callouts_add_done (HalDev
 	/* Move from temporary to global device store */
 	hal_device_store_remove (hald_get_tdl (), d);
 	hal_device_store_add (hald_get_gdl (), d);
-
 }
 
-/** Called by expat when an element ends.
- *
- *  @param  pc                  Parsing context
- *  @param  el                  Element name
- */
-static void
-end (ParsingContext * pc, const char *el)
+/* for this device, process the rule */
+static gboolean
+handle_merge (struct rule *rule, HalDevice *d)
 {
-	if (pc->aborted)
-		return;
-
-	pc->cdata_buf[pc->cdata_buf_len] = '\0';
+	const char *key = rule->key;
+	const char *value = rule->value;
 
-/*    printf("   curelem=%d\n", pc->curelem);*/
+	if (rule->rtype == RULE_MERGE) {
 
-	if (pc->curelem == CURELEM_MERGE && pc->match_ok) {
-		/* As soon as we are merging, we have matched the device... */
-		pc->device_matched = TRUE;
+		if (rule->type_merge == MERGE_STRING) {
+			hal_device_property_set_string (d, key, value);
 
-		switch (pc->merge_type) {
-		case MERGE_TYPE_STRING:
-			hal_device_property_set_string (pc->device, pc->merge_key, pc->cdata_buf);
-			break;
+		} else if (rule->type_merge == MERGE_STRLIST) {
+			int type = hal_device_property_get_type (d, key);
 
-		case MERGE_TYPE_STRLIST:
-		{
-			int type = hal_device_property_get_type (pc->device, pc->merge_key);
 			if (type == HAL_PROPERTY_TYPE_STRLIST || type == HAL_PROPERTY_TYPE_INVALID) {
-				hal_device_property_remove (pc->device, pc->merge_key);
-				hal_device_property_strlist_append (pc->device, pc->merge_key, pc->cdata_buf);
+				hal_device_property_remove (d, key);
+				hal_device_property_strlist_append (d, key, value);
 			}
-			break;
-		}
 
-		case MERGE_TYPE_INT32:
-			{
-				dbus_int32_t value;
+		} else if (rule->type_merge == MERGE_INT32) {
+			dbus_int32_t val = strtol (value, NULL, 0);
+			hal_device_property_set_int (d, key, val);
 
-				/* match integer property */
-				value = strtol (pc->cdata_buf, NULL, 0);
+		} else if (rule->type_merge == MERGE_UINT64) {
+			dbus_uint64_t val = strtoull (value, NULL, 0);
+			hal_device_property_set_uint64 (d, key, val);
 
-				/** @todo FIXME: Check error condition */
+		} else if (rule->type_merge == MERGE_BOOLEAN) {
+			hal_device_property_set_bool (d, key, (strcmp (value, "true") == 0) ? TRUE : FALSE);
 
-				hal_device_property_set_int (pc->device,
-						     pc->merge_key, value);
-				break;
-			}
-
-		case MERGE_TYPE_UINT64:
-			{
-				dbus_uint64_t value;
-
-				/* match integer property */
-				value = strtoull (pc->cdata_buf, NULL, 0);
-
-				/** @todo FIXME: Check error condition */
-
-				hal_device_property_set_uint64 (pc->device,
-						     pc->merge_key, value);
-				break;
-			}
-
-		case MERGE_TYPE_BOOLEAN:
-			hal_device_property_set_bool (pc->device, pc->merge_key,
-					      (strcmp (pc->cdata_buf,
-						       "true") == 0) 
-					      ? TRUE : FALSE);
-			break;
+		} else if (rule->type_merge == MERGE_DOUBLE) {
+			hal_device_property_set_double (d, key, atof (value));
 
-		case MERGE_TYPE_DOUBLE:
-			hal_device_property_set_double (pc->device, pc->merge_key,
-						atof (pc->cdata_buf));
-			break;
+		} else if (rule->type_merge == MERGE_COPY_PROPERTY) {
 
-		case MERGE_TYPE_COPY_PROPERTY:
-		{
-			char udi_to_merge_from[256];
-			char prop_to_merge[256];
+			char udi_to_merge_from[HAL_PATH_MAX];
+			char prop_to_merge[HAL_PATH_MAX];
 
-			/* Resolve key paths like 'someudi/foo/bar/baz:prop.name' 
+			/* Resolve key paths like 'someudi/foo/bar/baz:prop.name'
 			 * '@prop.here.is.an.udi:with.prop.name'
 			 */
-			if (!resolve_udiprop_path (pc->cdata_buf,
-						   pc->device->udi,
+			if (!resolve_udiprop_path (value,
+						   hal_device_get_udi (d),
 						   udi_to_merge_from, sizeof (udi_to_merge_from),
 						   prop_to_merge, sizeof (prop_to_merge))) {
-				HAL_ERROR (("Could not resolve keypath '%s' on udi '%s'", pc->cdata_buf, pc->device->udi));
+				HAL_ERROR (("Could not resolve keypath '%s' on udi '%s'", value, hal_device_get_udi (d)));
 			} else {
 				HalDevice *d;
 
@@ -1164,386 +809,380 @@ end (ParsingContext * pc, const char *el
 				if (d == NULL) {
 					HAL_ERROR (("Could not find device with udi '%s'", udi_to_merge_from));
 				} else {
-					hal_device_copy_property (d, prop_to_merge, pc->device, pc->merge_key);
+					hal_device_copy_property (d, prop_to_merge, d, key);
 				}
 			}
-			break;
-		}
 
-		default:
-			HAL_ERROR (("Unknown merge_type=%d='%c'",
-				    pc->merge_type, pc->merge_type));
-			break;
+		} else {
+			HAL_ERROR (("unknown merge type (%u)", rule->type_merge));
 		}
-	} else if (pc->curelem == CURELEM_APPEND && pc->match_ok && 
-		   (hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_STRING ||
-		    hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_STRLIST ||
-		    hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_INVALID)) {
-		char buf[256];
-		char buf2[256];
 
-		/* As soon as we are appending, we have matched the device... */
-		pc->device_matched = TRUE;
+	} else if (rule->rtype == RULE_APPEND) {
+		char buf[HAL_PATH_MAX];
+		char buf2[HAL_PATH_MAX];
 
-		if (pc->merge_type == MERGE_TYPE_STRLIST) {
-			hal_device_property_strlist_append (pc->device, pc->merge_key, pc->cdata_buf);
+		if (hal_device_property_get_type (d, key) != HAL_PROPERTY_TYPE_STRING &&
+		    hal_device_property_get_type (d, key) != HAL_PROPERTY_TYPE_STRLIST &&
+		    hal_device_property_get_type (d, key) != HAL_PROPERTY_TYPE_INVALID) {
+			HAL_ERROR (("invalid key type"));
+			return FALSE;
+		}
+
+		if (rule->type_merge == MERGE_STRLIST) {
+			hal_device_property_strlist_append (d, key, value);
 		} else {
 			const char *existing_string;
-			
-			switch (pc->merge_type) {
-			case MERGE_TYPE_STRING:
-				strncpy (buf, pc->cdata_buf, sizeof (buf));
+
+			switch (rule->type_merge) {
+			case MERGE_STRING:
+				strncpy (buf, value, sizeof (buf));
 				break;
-				
-			case MERGE_TYPE_COPY_PROPERTY:
-				hal_device_property_get_as_string (pc->device, pc->cdata_buf, buf, sizeof (buf));
+
+			case MERGE_COPY_PROPERTY:
+				hal_device_property_get_as_string (d, value, buf, sizeof (buf));
 				break;
-				
+
 			default:
-				HAL_ERROR (("Unknown merge_type=%d='%c'", pc->merge_type, pc->merge_type));
 				break;
 			}
-			
-			existing_string = hal_device_property_get_string (pc->device, pc->merge_key);
+
+			existing_string = hal_device_property_get_string (d, key);
 			if (existing_string != NULL) {
 				strncpy (buf2, existing_string, sizeof (buf2));
 				strncat (buf2, buf, sizeof (buf2) - strlen(buf2));
-			} else {
+			} else
 				strncpy (buf2, buf, sizeof (buf2));
-			}
-			hal_device_property_set_string (pc->device, pc->merge_key, buf2);
+			hal_device_property_set_string (d, key, buf2);
 		}
-	} else if (pc->curelem == CURELEM_PREPEND && pc->match_ok && 
-		   (hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_STRING ||
-		    hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_STRLIST ||
-		    hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_INVALID)) {
-		char buf[256];
-		char buf2[256];
 
-		/* As soon as we are prepending, we have matched the device... */
-		pc->device_matched = TRUE;
+	} else if (rule->rtype == RULE_PREPEND) {
+		char buf[HAL_PATH_MAX];
+		char buf2[HAL_PATH_MAX];
 
-		if (pc->merge_type == MERGE_TYPE_STRLIST) {
-			hal_device_property_strlist_prepend (pc->device, pc->merge_key, pc->cdata_buf);
+		if (hal_device_property_get_type (d, key) != HAL_PROPERTY_TYPE_STRING &&
+		    hal_device_property_get_type (d, key) != HAL_PROPERTY_TYPE_STRLIST &&
+		    hal_device_property_get_type (d, key) != HAL_PROPERTY_TYPE_INVALID) {
+			HAL_ERROR (("invalid key type"));
+			return FALSE;
+		}
+
+		if (rule->type_merge == MERGE_STRLIST) {
+			hal_device_property_strlist_prepend (d, key, value);
 		} else {
 			const char *existing_string;
-			
-			switch (pc->merge_type) {
-			case MERGE_TYPE_STRING:
-				strncpy (buf, pc->cdata_buf, sizeof (buf));
-				break;
-				
-			case MERGE_TYPE_COPY_PROPERTY:
-				hal_device_property_get_as_string (pc->device, pc->cdata_buf, buf, sizeof (buf));
-				break;
-				
-			default:
-				HAL_ERROR (("Unknown merge_type=%d='%c'", pc->merge_type, pc->merge_type));
-				break;
+
+			if (rule->type_merge == MERGE_STRING) {
+				strncpy (buf, value, sizeof (buf));
+
+			} else if (rule->type_merge == MERGE_COPY_PROPERTY) {
+				hal_device_property_get_as_string (d, value, buf, sizeof (buf));
+
 			}
-			
-			existing_string = hal_device_property_get_string (pc->device, pc->merge_key);
+
+			existing_string = hal_device_property_get_string (d, key);
 			if (existing_string != NULL) {
 				strncpy (buf2, buf, sizeof (buf2));
 				strncat (buf2, existing_string, sizeof (buf2) - strlen(buf2));
 			} else {
 				strncpy (buf2, buf, sizeof (buf2));
 			}
-			hal_device_property_set_string (pc->device, pc->merge_key, buf2);
+			hal_device_property_set_string (d, key, buf2);
 		}
-	} else if (pc->curelem == CURELEM_REMOVE && pc->match_ok) {
 
-		if (pc->merge_type == MERGE_TYPE_STRLIST) {
+	} else if (rule->rtype == RULE_REMOVE) {
+
+		if (rule->type_merge == MERGE_STRLIST) {
 			/* covers <remove key="foobar" type="strlist">blah</remove> */
-			hal_device_property_strlist_remove (pc->device, pc->merge_key, pc->cdata_buf);
+			hal_device_property_strlist_remove (d, key, value);
+
 		} else {
 			/* only allow <remove key="foobar"/>, not <remove key="foobar">blah</remove> */
-			if (strlen (pc->cdata_buf) == 0) {
-				hal_device_property_remove (pc->device, pc->merge_key);
-			}
+			if (strlen (value) == 0)
+				hal_device_property_remove (d, key);
 		}
-	} else if (pc->merge_type == MERGE_TYPE_SPAWN) {
-		HalDevice *spawned;
 
-		spawned = hal_device_store_find (hald_get_gdl (), pc->merge_key);
+	} else if (rule->rtype == RULE_SPAWN) {
+		HalDevice *spawned;
+		spawned = hal_device_store_find (hald_get_gdl (), key);
 		if (spawned == NULL)
-			spawned = hal_device_store_find (hald_get_tdl (), pc->merge_key);
+			spawned = hal_device_store_find (hald_get_tdl (), key);
 
 		if (spawned == NULL) {
-			HAL_INFO (("Spawning new device object '%s' caused by <spawn> on udi '%s'", 
-				   pc->merge_key, pc->device->udi));
-
+			HAL_INFO (("Spawning new device object '%s' caused by <spawn> on udi '%s'",
+				   key, d->udi));
 			spawned = hal_device_new ();
 			hal_device_property_set_string (spawned, "info.bus", "unknown");
-			hal_device_property_set_string (spawned, "info.udi", pc->merge_key);
-			hal_device_property_set_string (spawned, "info.parent", pc->device->udi);
-			hal_device_set_udi (spawned, pc->merge_key);
-			
+			hal_device_property_set_string (spawned, "info.udi", key);
+			hal_device_property_set_string (spawned, "info.parent", d->udi);
+			hal_device_set_udi (spawned, key);
+
 			hal_device_store_add (hald_get_tdl (), spawned);
-			
+
 			di_search_and_merge (spawned, DEVICE_INFO_TYPE_INFORMATION);
 			di_search_and_merge (spawned, DEVICE_INFO_TYPE_POLICY);
-			
+
 			hal_util_callout_device_add (spawned, spawned_device_callouts_add_done, NULL, NULL);
 		}
 
-	} else if (pc->curelem == CURELEM_CLEAR && pc->match_ok) {
-		if (pc->merge_type == MERGE_TYPE_CLEAR) {
-			hal_device_property_strlist_clear (pc->device, pc->merge_key);
+	} else {
+		HAL_ERROR (("Unknown rule type (%u)", rule->rtype));
+		return FALSE;
+	}
+	return TRUE;
+}
+
+/* for each node, free memory and it's own list of nodes */
+static void
+rules_cleanup_list (GSList *fdi_rules)
+{
+	GSList *elem;
+
+	for (elem = fdi_rules; elem != NULL; elem = g_slist_next (elem)) {
+		struct rule *rule = elem->data;
+
+		g_free (rule->key);
+		g_free (rule->value);
+		g_free (rule);
+	}
+	g_slist_free (fdi_rules);
+	fdi_rules = NULL;
+}
+
+/* expat cb for start, e.g. <match foo=bar */
+static void
+start (void *data, const char *el, const char **attr)
+{
+	struct fdi_context *fdi_ctx = data;
+	enum rule_type rtype = get_rule_type (el);
+	int i;
+
+	if (rtype == RULE_UNKNOWN)
+		return;
+
+	if (fdi_ctx->rule == NULL)
+		return;
+
+	/* get key and attribute for current rule */
+	for (i = 0; attr[i] != NULL; i+=2) {
+		if (strcmp (attr[i], "key") == 0) {
+			fdi_ctx->rule->key = g_strdup (attr[1]);
+			continue;
+		}
+		if (rtype == RULE_SPAWN) {
+			if (strcmp (attr[i], "udi") == 0) {
+				fdi_ctx->rule->key = g_strdup (attr[1]);
+				continue;
+			}
+		} else if (rtype == RULE_MATCH) {
+			fdi_ctx->rule->type_match = get_match_type (attr[i]);
+			if (fdi_ctx->rule->type_match == MATCH_UNKNOWN)
+				continue;
+			fdi_ctx->rule->value = g_strdup (attr[i+1]);
+		} else {
+			if (strcmp (attr[i], "type") != 0)
+				continue;
+			fdi_ctx->rule->type_merge = get_merge_type (attr[i+1]);
+			if (fdi_ctx->rule->type_merge == MERGE_UNKNOWN)
+				return;
 		}
 	}
 
+	if (fdi_ctx->rule->key[0] == '\0')
+		return;
+
+	fdi_ctx->rule->rtype = rtype;
 
-	pc->cdata_buf_len = 0;
-	pc->depth--;
+	/* match rules remember the current nesting and the label to jump to if not matching */
+	if (rtype == RULE_MATCH) {
+		/* remember current nesting */
+		fdi_ctx->depth++;
 
-	/* maintain curelem */
-	pc->curelem = pc->curelem_stack[pc->depth];
+		/* remember rule at nesting level nesting */
+		fdi_ctx->match_at_depth[fdi_ctx->depth] = fdi_ctx->rule;
 
-	/* maintain pc->match_ok */
-	if (pc->depth <= pc->match_depth_first_fail)
-		pc->match_ok = TRUE;
+		/* insert match rule into list and get new rule */
+		fdi_ctx->rules = g_slist_append (fdi_ctx->rules, fdi_ctx->rule);
+		fdi_ctx->rule = g_new0 (struct rule ,1);
+	}
 }
 
-/** Called when there is CDATA 
- *
- *  @param  pc                  Parsing context
- *  @param  s                   Pointer to data
- *  @param  len                 Length of data
- */
+/* expat cb for character data, i.e. the text data in between tags */
+static void
+cdata (void *data, const char *s, int len)
+{
+	struct fdi_context *fdi_ctx = data;
+
+	if (fdi_ctx->rule == NULL)
+		return;
+
+	if (fdi_ctx->rule->rtype != RULE_MERGE &&
+	    fdi_ctx->rule->rtype != RULE_PREPEND &&
+	    fdi_ctx->rule->rtype != RULE_APPEND &&
+	    fdi_ctx->rule->rtype != RULE_REMOVE &&
+	    fdi_ctx->rule->rtype != RULE_SPAWN)
+		return;
+
+	if (len < 1)
+		return;
+
+	/* copy cdata in current context */
+	fdi_ctx->rule->value = g_realloc (fdi_ctx->rule->value, fdi_ctx->rule->value_len + len+1);
+	memcpy (&fdi_ctx->rule->value[fdi_ctx->rule->value_len], s, len);
+	fdi_ctx->rule->value_len += len;
+	fdi_ctx->rule->value[fdi_ctx->rule->value_len] = '\0';
+}
+
+/* expat cb for end, e.g. </device> */
 static void
-cdata (ParsingContext * pc, const char *s, int len)
+end (void *data, const char *el)
 {
-	int bytes_left;
-	int bytes_to_copy;
+	struct fdi_context *fdi_ctx = data;
+	enum rule_type rtype = get_rule_type (el);
 
-	if (pc->aborted)
+	if (rtype == RULE_UNKNOWN)
 		return;
 
-	bytes_left = CDATA_BUF_SIZE - pc->cdata_buf_len;
-	if (len > bytes_left) {
-		HAL_ERROR (("CDATA in element larger than %d",
-			    CDATA_BUF_SIZE));
+	if (rtype == RULE_MATCH) {
+		if (fdi_ctx->depth <= 0)
+			return;
+
+		/* get corresponding match rule and set the rule to skip to */
+		fdi_ctx->match_at_depth[fdi_ctx->depth]->next_rule = fdi_ctx->rule;
+		fdi_ctx->depth--;
+		return;
 	}
 
-	bytes_to_copy = len;
-	if (bytes_to_copy > bytes_left)
-		bytes_to_copy = bytes_left;
+	/* only valid if element is in the current context */
+	if (fdi_ctx->rule->rtype != rtype)
+		return;
 
-	if (bytes_to_copy > 0)
-		memcpy (pc->cdata_buf + pc->cdata_buf_len, s,
-			bytes_to_copy);
+	/* set empty value to empty string */
+	if (fdi_ctx->rule->value == NULL)
+		fdi_ctx->rule->value = "";
 
-	pc->cdata_buf_len += bytes_to_copy;
+	/* insert merge rule into list and get new rule */
+	fdi_ctx->rules = g_slist_append (fdi_ctx->rules, fdi_ctx->rule);
+	fdi_ctx->rule = g_new0 (struct rule, 1);
 }
 
-
-/** Process a device information info file.
- *
- *  @param  dir                 Directory file resides in
- *  @param  filename            File name
- *  @param  device              Device to match on
- *  @return                     #TRUE if file matched device and information
- *                              was merged
- */
-static dbus_bool_t
-process_fdi_file (const char *dir, const char *filename,
-		  HalDevice * device)
+/* decompile an fdi file into a list of rules as this is quicker than opening then each time we want to search */
+static int
+rules_add_fdi_file (GSList **fdi_rules, const char *filename)
 {
+	struct fdi_context *fdi_ctx;
+	char *buf;
+	gsize buflen;
 	int rc;
-	char buf[512];
-	FILE *file;
-	int filesize;
-	size_t read;
-	char *filebuf;
-	dbus_bool_t device_matched;
-	XML_Parser parser;
-	ParsingContext *parsing_context;
-
-	file = NULL;
-	filebuf = NULL;
-	parser = NULL;
-	parsing_context = NULL;
-
-	device_matched = FALSE;
-
-	snprintf (buf, sizeof (buf), "%s/%s", dir, filename);
-
-	/*HAL_INFO(("analyzing file %s", buf));*/
-
-	/* open file and read it into a buffer; it's a small file... */
-	file = fopen (buf, "r");
-	if (file == NULL) {
-		HAL_ERROR (("Could not open file %s", buf));
-		goto out;
-	}
 
-	fseek (file, 0L, SEEK_END);
-	filesize = (int) ftell (file);
-	rewind (file);
-	filebuf = (char *) malloc (filesize);
-	if (filebuf == NULL) {
-		HAL_ERROR (("Could not allocate %d bytes for file %s", filesize, buf));
-		goto out;
-	}
-	read = fread (filebuf, sizeof (char), filesize, file);
+	if (!g_file_get_contents (filename, &buf, &buflen, NULL))
+		return -1;
 
-	/* initialize parsing context */
-	parsing_context =
-	    (ParsingContext *) malloc (sizeof (ParsingContext));
-	if (parsing_context == NULL) {
-		HAL_ERROR (("Could not allocate parsing context"));
-		goto out;
-	}
+	/* get context and first rule */
+	fdi_ctx = g_new0 (struct fdi_context ,1);
+	fdi_ctx->rule = g_new0 (struct rule ,1);
 
-	/* TODO: reuse parser
-	 */
-	parser = XML_ParserCreate (NULL);
+	XML_Parser parser = XML_ParserCreate (NULL);
 	if (parser == NULL) {
-		HAL_ERROR (("Could not allocate XML parser"));
-		goto out;
+		fprintf (stderr, "Couldn't allocate memory for parser\n");
+		return -1;
 	}
+	XML_SetUserData (parser, fdi_ctx);
+	XML_SetElementHandler (parser, start, end);
+	XML_SetCharacterDataHandler (parser, cdata);
+	rc = XML_Parse (parser, buf, buflen, 1);
+	if (rc == 0)
+		fprintf (stderr, "Parse error at line %i:\n%s\n",
+			(int) XML_GetCurrentLineNumber (parser),
+			XML_ErrorString (XML_GetErrorCode (parser)));
+	XML_ParserFree (parser);
+	g_free (buf);
+
+	/* insert last dummy rule into list */
+	fdi_ctx->rule->rtype = RULE_EOF;
+	fdi_ctx->rule->key = g_strdup (filename);
+	fdi_ctx->rules = g_slist_append (fdi_ctx->rules, fdi_ctx->rule);
+
+	/* add rules to external list */
+	if (rc == 0)
+		rules_cleanup_list (fdi_ctx->rules);
+	else
+		*fdi_rules = g_slist_concat (*fdi_rules, fdi_ctx->rules);
+
+	g_free (fdi_ctx);
+
+	if (rc == 0)
+		return -1;
+	return 0;
+}
 
-	parsing_context->depth = 0;
-	parsing_context->device_matched = FALSE;
-	parsing_context->match_ok = TRUE;
-	parsing_context->curelem = CURELEM_UNKNOWN;
-	parsing_context->aborted = FALSE;
-	parsing_context->file = buf;
-	parsing_context->parser = parser;
-	parsing_context->device = device;
-	parsing_context->match_depth_first_fail = -1;
-
-	XML_SetElementHandler (parser,
-			       (XML_StartElementHandler) start,
-			       (XML_EndElementHandler) end);
-	XML_SetCharacterDataHandler (parser,
-				     (XML_CharacterDataHandler) cdata);
-	XML_SetUserData (parser, parsing_context);
-
-	rc = XML_Parse (parser, filebuf, filesize, 1);
-	/*printf("XML_Parse rc=%d\r\n", rc); */
-
-	if (rc == 0) {
-		/* error parsing document */
-		HAL_ERROR (("Error parsing XML document %s at line %d, "
-			    "column %d : %s", 
-			    buf, 
-			    XML_GetCurrentLineNumber (parser), 
-			    XML_GetCurrentColumnNumber (parser), 
-			    XML_ErrorString (XML_GetErrorCode (parser))));
-		device_matched = FALSE;
-	} else {
-		/* document parsed ok */
-		device_matched = parsing_context->device_matched;
-	}
+/* print the rules to screen, mainly useful for debugging */
+static void
+rules_dump (GSList *fdi_rules)
+{
+	GSList *elem;
 
-out:
-	if (filebuf != NULL)
-		free (filebuf);
-	if (file != NULL)
-		fclose (file);
-	if (parser != NULL)
-		XML_ParserFree (parser);
-	if (parsing_context != NULL)
-		free (parsing_context);
+	for (elem = fdi_rules; elem != NULL; elem = g_slist_next (elem)) {
+		struct rule *rule = elem->data;
 
-	return device_matched;
+		if (rule->rtype == RULE_EOF) {
+			printf ("%p: eof %s\n", rule, rule->key);
+		} else if (rule->rtype == RULE_MATCH) {
+			printf ("\n");
+			printf ("%p: match '%s' (%s) '%s' (skip to %p)\n",
+				rule, rule->key, get_match_type_str (rule->type_match),
+				rule->value, rule->next_rule);
+		} else {
+			printf ("%p: %s '%s' (%s) '%s'\n",
+				rule, get_rule_type_str (rule->rtype), rule->key,
+				get_merge_type_str (rule->type_merge), rule->value);
+		}
+	}
 }
 
-
-
-static int 
-my_alphasort(const void *a, const void *b)
+/* modified alphasort to count downwards */
+static int
+_alphasort(const void *a, const void *b)
 {
 	return -alphasort (a, b);
 }
 
-
-/** Scan all directories and subdirectories in the given directory and
- *  process each *.fdi file
- *
- *  @param  d                   Device to merge information into
- *  @return                     #TRUE if information was merged
- */
-static dbus_bool_t
-scan_fdi_files (const char *dir, HalDevice * d)
+/* recurse a directory tree, searching and adding fdi files */
+static int
+rules_search_and_add_fdi_files (GSList **fdi_rules, const char *dir)
 {
 	int i;
 	int num_entries;
-	dbus_bool_t found_fdi_file;
 	struct dirent **name_list;
 
-	found_fdi_file = 0;
-
-	/*HAL_INFO(("scan_fdi_files: Processing dir '%s'", dir));*/
-
-	num_entries = scandir (dir, &name_list, 0, my_alphasort);
-	if (num_entries == -1) {
-		perror ("scandir");
-		return FALSE;
-	}
+	num_entries = scandir (dir, &name_list, 0, _alphasort);
+	if (num_entries == -1)
+		return -1;
 
 	for (i = num_entries - 1; i >= 0; i--) {
 		int len;
 		char *filename;
-		gchar *full_path;					     
+		gchar *full_path;
 
 		filename = name_list[i]->d_name;
 		len = strlen (filename);
-
 		full_path = g_strdup_printf ("%s/%s", dir, filename);
-		/*HAL_INFO (("Full path = %s", full_path));*/
-
-		/* Mmm, d_type can be DT_UNKNOWN, use glib to determine
-		 * the type
-		 */
 		if (g_file_test (full_path, (G_FILE_TEST_IS_REGULAR))) {
-			/* regular file */
-
-			if (len >= 5 &&
-			    filename[len - 4] == '.' &&
-			    filename[len - 3] == 'f' &&
-			    filename[len - 2] == 'd' &&
-			    filename[len - 1] == 'i') {
-				/*HAL_INFO (("scan_fdi_files: Processing file '%s'", filename));*/
-				found_fdi_file = process_fdi_file (dir, filename, d);
-				if (found_fdi_file) {
-					HAL_INFO (("*** Matched file %s/%s", dir, filename));
-					/*break;*/
-				}
-			}
-
-		} else if (g_file_test (full_path, (G_FILE_TEST_IS_DIR)) 
-			   && strcmp (filename, ".") != 0
-			   && strcmp (filename, "..") != 0) {
+			if (len >= 5 && strcmp(&filename[len - 4], ".fdi") == 0)
+				rules_add_fdi_file (fdi_rules, full_path);
+		} else if (g_file_test (full_path, (G_FILE_TEST_IS_DIR)) && filename[0] != '.') {
 			int num_bytes;
 			char *dirname;
 
-			/* Directory; do the recursion thingy but not 
-			 * for . and ..
-			 */
-
 			num_bytes = len + strlen (dir) + 1 + 1;
 			dirname = (char *) malloc (num_bytes);
-			if (dirname == NULL) {
-				HAL_ERROR (("couldn't allocated %d bytes",
-					    num_bytes));
+			if (dirname == NULL)
 				break;
-			}
 
-			snprintf (dirname, num_bytes, "%s/%s", dir,
-				  filename);
-			found_fdi_file = scan_fdi_files (dirname, d);
+			snprintf (dirname, num_bytes, "%s/%s", dir, filename);
+			rules_search_and_add_fdi_files (fdi_rules, dirname);
 			free (dirname);
-			/*
-			if (found_fdi_file)
-				break;
-			*/
 		}
-
 		g_free (full_path);
-
 		free (name_list[i]);
 	}
 
@@ -1552,80 +1191,129 @@ scan_fdi_files (const char *dir, HalDevi
 	}
 
 	free (name_list);
+	return 0;
+}
 
-	return found_fdi_file;
+/* setup the location of the rules */
+void
+di_rules_init (void)
+{
+	char *hal_fdi_source_preprobe = getenv ("HAL_FDI_SOURCE_PREPROBE");
+	char *hal_fdi_source_information = getenv ("HAL_FDI_SOURCE_INFORMATION");
+	char *hal_fdi_source_policy = getenv ("HAL_FDI_SOURCE_POLICY");
+
+	if (hal_fdi_source_preprobe != NULL)
+		rules_search_and_add_fdi_files (&fdi_rules_preprobe, hal_fdi_source_preprobe);
+	else {
+		rules_search_and_add_fdi_files (&fdi_rules_preprobe, PACKAGE_DATA_DIR "/hal/fdi/preprobe");
+		rules_search_and_add_fdi_files (&fdi_rules_preprobe, PACKAGE_SYSCONF_DIR "/hal/fdi/preprobe");
+	}
+
+	if (hal_fdi_source_information != NULL)
+		rules_search_and_add_fdi_files (&fdi_rules_information, hal_fdi_source_information);
+	else {
+		rules_search_and_add_fdi_files (&fdi_rules_information, PACKAGE_DATA_DIR "/hal/fdi/information");
+		rules_search_and_add_fdi_files (&fdi_rules_information, PACKAGE_SYSCONF_DIR "/hal/fdi/information");
+	}
+
+	if (hal_fdi_source_policy != NULL)
+		rules_search_and_add_fdi_files (&fdi_rules_policy, hal_fdi_source_policy);
+	else {
+		rules_search_and_add_fdi_files (&fdi_rules_policy, PACKAGE_DATA_DIR "/hal/fdi/policy");
+		rules_search_and_add_fdi_files (&fdi_rules_policy, PACKAGE_SYSCONF_DIR "/hal/fdi/policy");
+	}
+
+	/* only dump the rules if we are being verbose as this is expensive */
+	if (getenv ("HALD_VERBOSE") != NULL) {
+		rules_dump (fdi_rules_preprobe);
+		rules_dump (fdi_rules_information);
+		rules_dump (fdi_rules_policy);
+	}
 }
 
-/** Search the device info file repository for a .fdi file to merge
- *  more information into the device object.
- *
- *  @param  d                   Device to merge information into
- *  @return                     #TRUE if information was merged
- */
-dbus_bool_t
-di_search_and_merge (HalDevice *d, DeviceInfoType type)
+/* cleanup the rules */
+void
+di_rules_cleanup (void)
 {
-	static gboolean have_checked_hal_fdi_source = FALSE;
-	static char *hal_fdi_source_preprobe = NULL;
-	static char *hal_fdi_source_information = NULL;
-	static char *hal_fdi_source_policy = NULL;
-	dbus_bool_t ret;
-	char *s1;
-	char *s2;
-
-	ret = FALSE;
-
-	if (!have_checked_hal_fdi_source) {
-		hal_fdi_source_preprobe    = getenv ("HAL_FDI_SOURCE_PREPROBE");
-		hal_fdi_source_information = getenv ("HAL_FDI_SOURCE_INFORMATION");
-		hal_fdi_source_policy      = getenv ("HAL_FDI_SOURCE_POLICY");
-		have_checked_hal_fdi_source = TRUE;
+	rules_cleanup_list (fdi_rules_preprobe);
+	rules_cleanup_list (fdi_rules_information);
+	rules_cleanup_list (fdi_rules_policy);
+	fdi_rules_preprobe = NULL;
+	fdi_rules_information = NULL;
+	fdi_rules_policy = NULL;
+}
+
+/* process a match and merge comand for a device */
+static void
+rules_match_and_merge_device (GSList *fdi_rules, HalDevice *d)
+{
+	GSList *elem;
+
+	if (fdi_rules == NULL) {
+		di_rules_cleanup ();
+		di_rules_init ();
+	}
+
+	elem = fdi_rules;
+	while (elem != NULL) {
+		struct rule *rule = elem->data;
+
+		switch (rule->rtype) {
+		case RULE_MATCH:
+			/* skip non-matching rules block */
+			HAL_INFO(("%p match '%s' at %s", rule, rule->key, hal_device_get_udi (d)));
+			if (!handle_match (rule, d)) {
+				HAL_INFO(("no match, skip to rule %s (%p)", get_rule_type_str (rule->next_rule->rtype), rule->next_rule));
+				elem = g_slist_find (elem, rule->next_rule);
+				continue;
+			}
+			break;
+
+		case RULE_APPEND:
+		case RULE_PREPEND:
+		case RULE_REMOVE:
+		case RULE_CLEAR:
+		case RULE_SPAWN:
+		case RULE_MERGE:
+			HAL_INFO(("%p merge '%s' at %s", rule, rule->key, hal_device_get_udi (d)));
+			handle_merge (rule, d);
+			break;
+
+		case RULE_EOF:
+			HAL_INFO(("%p fdi file '%s' finished", rule, rule->key));
+			break;
+
+		default:
+			HAL_WARNING(("Unhandled rule (%i)!", rule->rtype));
+			break;
+		}
+		elem = g_slist_next (elem);
 	}
+}
 
+/* merge the device info type, either preprobe, info or policy */
+gboolean
+di_search_and_merge (HalDevice *d, DeviceInfoType type)
+{
 	switch (type) {
 	case DEVICE_INFO_TYPE_PREPROBE:
-		if (hal_fdi_source_preprobe != NULL) {
-			s1 = hal_fdi_source_preprobe;
-			s2 = NULL;
-		} else {
-			s1 = PACKAGE_DATA_DIR "/hal/fdi/preprobe";
-			s2 = PACKAGE_SYSCONF_DIR "/hal/fdi/preprobe";
-		}
+		HAL_INFO(("apply fdi preprobe to device %p", d));
+		rules_match_and_merge_device (fdi_rules_preprobe, d);
 		break;
 
 	case DEVICE_INFO_TYPE_INFORMATION:
-		if (hal_fdi_source_information != NULL) {
-			s1 = hal_fdi_source_information;
-			s2 = NULL;
-		} else {
-			s1 = PACKAGE_DATA_DIR "/hal/fdi/information";
-			s2 = PACKAGE_SYSCONF_DIR "/hal/fdi/information";
-		}
+		HAL_INFO(("apply fdi info to device %p", d));
+		rules_match_and_merge_device (fdi_rules_information, d);
 		break;
 
 	case DEVICE_INFO_TYPE_POLICY:
-		if (hal_fdi_source_policy != NULL) {
-			s1 = hal_fdi_source_policy;
-			s2 = NULL;
-		} else {
-			s1 = PACKAGE_DATA_DIR "/hal/fdi/policy";
-			s2 = PACKAGE_SYSCONF_DIR "/hal/fdi/policy";
-		}
+		HAL_INFO(("apply fdi policy to device %p", d));
+		rules_match_and_merge_device (fdi_rules_policy, d);
 		break;
 
 	default:
-		s1 = NULL;
-		s2 = NULL;
-		HAL_ERROR (("Bogus device information type %d", type));
 		break;
 	}
 
-	if (s1 != NULL)
-		ret = scan_fdi_files (s1, d) || ret;
-	if (s2 != NULL)
-		ret = scan_fdi_files (s2, d) || ret;
-
-	return ret;
+	return TRUE;
 }
-
-/** @} */
diff --git a/hald/device_info.h b/hald/device_info.h
index e37973f..24b1567 100644
--- a/hald/device_info.h
+++ b/hald/device_info.h
@@ -38,6 +38,8 @@ typedef enum {
 	DEVICE_INFO_TYPE_POLICY
 } DeviceInfoType;
 
-dbus_bool_t di_search_and_merge (HalDevice *d, DeviceInfoType type);
+extern void di_rules_init (void);
+extern void di_rules_cleanup (void);
+extern gboolean di_search_and_merge (HalDevice *d, DeviceInfoType type);
 
 #endif				/* DEVICE_INFO_H */
diff-tree 195222c1b1115e62a55b3a21898176c8d01c8da8 (from ec7b3fc5f01a75dd749d05c70ba2a842c16d3c66)
Author: David Zeuthen <davidz at redhat.com>
Date:   Tue Oct 10 19:30:38 2006 -0400

    revert hald/device_info.c back to state from June 2006

diff --git a/hald/device_info.c b/hald/device_info.c
index 78ba7cf..17751d3 100644
--- a/hald/device_info.c
+++ b/hald/device_info.c
@@ -36,7 +36,6 @@
 #include <dbus/dbus.h>
 #include <dbus/dbus-glib.h>
 #include <math.h>
-#include <errno.h>
 
 #include "hald.h"
 #include "logger.h"
@@ -345,10 +344,10 @@ handle_match (ParsingContext * pc, const
 
 	/* Resolve key paths like 'someudi/foo/bar/baz:prop.name' '@prop.here.is.an.udi:with.prop.name' */
 	if (!resolve_udiprop_path (key,
-				   hal_device_get_udi (pc->device),
+				   pc->device->udi,
 				   udi_to_check, sizeof (udi_to_check),
 				   prop_to_check, sizeof (prop_to_check))) {
-		HAL_ERROR (("Could not resolve keypath '%s' on udi '%s'", key, hal_device_get_udi (pc->device)));
+		HAL_ERROR (("Could not resolve keypath '%s' on udi '%s'", key, pc->device->udi));
 		return FALSE;
 	}
 
@@ -461,32 +460,19 @@ handle_match (ParsingContext * pc, const
 				return TRUE;
 		}
 	} else if (strcmp (attr[2], "empty") == 0) {
-		int type;
 		dbus_bool_t is_empty = TRUE;
 		dbus_bool_t should_be_empty = TRUE;
 
-
 		if (strcmp (attr[3], "false") == 0)
 			should_be_empty = FALSE;
 
-		type = hal_device_property_get_type (d, prop_to_check);
-		switch (type) {
-		case HAL_PROPERTY_TYPE_STRING: 
-			if (hal_device_has_property (d, prop_to_check))
-				if (strlen (hal_device_property_get_string (d, prop_to_check)) > 0)
-					is_empty = FALSE;
-			break;
-		case HAL_PROPERTY_TYPE_STRLIST:
-			if (hal_device_has_property (d, prop_to_check))
-				if (!hal_device_property_strlist_is_empty(d, prop_to_check))
-					is_empty = FALSE;
-			break;
-		default:
-			/* explicit fallthrough */
+		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_STRING)
 			return FALSE;
-			break;
-		} 
-	
+
+		if (hal_device_has_property (d, prop_to_check))
+			if (strlen (hal_device_property_get_string (d, prop_to_check)) > 0)
+				is_empty = FALSE;
+
 		if (should_be_empty) {
 			if (is_empty)
 				return TRUE;
@@ -537,7 +523,7 @@ handle_match (ParsingContext * pc, const
 		if (strcmp (attr[3], "false") == 0)
 			should_be_absolute_path = FALSE;
 
-		/*HAL_INFO (("hal_device_get_udi (d)='%s', prop_to_check='%s'", hal_device_get_udi (d), prop_to_check));*/
+		/*HAL_INFO (("d->udi='%s', prop_to_check='%s'", d->udi, prop_to_check));*/
 
 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_STRING)
 			return FALSE;
@@ -579,12 +565,12 @@ handle_match (ParsingContext * pc, const
 			}
 		} else if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRLIST && 
 			   needle != NULL) {
-			HalDeviceStrListIter iter;
+			GSList *i;
+			GSList *value;
 
-			for (hal_device_property_strlist_iter_init (d, prop_to_check, &iter);
-			     hal_device_property_strlist_iter_is_valid (&iter);
-			     hal_device_property_strlist_iter_next (&iter)) {
-				const char *str = hal_device_property_strlist_iter_get_value (&iter);
+			value = hal_device_property_get_strlist (d, prop_to_check);
+			for (i = value; i != NULL; i = g_slist_next (i)) {
+				const char *str = i->data;
 				if (strcmp (str, needle) == 0) {
 					contains = TRUE;
 					break;
@@ -617,12 +603,12 @@ handle_match (ParsingContext * pc, const
 			}
 		} else if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRLIST && 
 			   needle != NULL) {
-			HalDeviceStrListIter iter;
+			GSList *i;
+			GSList *value;
 
-			for (hal_device_property_strlist_iter_init (d, prop_to_check, &iter);
-			     hal_device_property_strlist_iter_is_valid (&iter);
-			     hal_device_property_strlist_iter_next (&iter)) {
-				const char *str = hal_device_property_strlist_iter_get_value (&iter);
+			value = hal_device_property_get_strlist (d, prop_to_check);
+			for (i = value; i != NULL; i = g_slist_next (i)) {
+				const char *str = i->data;
 				if (g_ascii_strcasecmp (str, needle) == 0) {
 					contains_ncase = TRUE;
 					break;
@@ -793,6 +779,7 @@ handle_spawn (ParsingContext * pc, const
 	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
 
 	pc->merge_type = MERGE_TYPE_SPAWN;
+
 	return;
 }
 
@@ -897,8 +884,6 @@ start (ParsingContext * pc, const char *
 
 	pc->cdata_buf_len = 0;
 
-	pc->merge_type = MERGE_TYPE_UNKNOWN;
-
 /*
     for (i = 0; i < pc->depth; i++)
         printf("  ");
@@ -1074,7 +1059,7 @@ start (ParsingContext * pc, const char *
 static void 
 spawned_device_callouts_add_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
 {
-	HAL_INFO (("Add callouts completed udi=%s", hal_device_get_udi (d)));
+	HAL_INFO (("Add callouts completed udi=%s", d->udi));
 
 	/* Move from temporary to global device store */
 	hal_device_store_remove (hald_get_tdl (), d);
@@ -1165,11 +1150,10 @@ end (ParsingContext * pc, const char *el
 			 * '@prop.here.is.an.udi:with.prop.name'
 			 */
 			if (!resolve_udiprop_path (pc->cdata_buf,
-						   hal_device_get_udi (pc->device),
+						   pc->device->udi,
 						   udi_to_merge_from, sizeof (udi_to_merge_from),
 						   prop_to_merge, sizeof (prop_to_merge))) {
-				HAL_ERROR (("Could not resolve keypath '%s' on udi '%s'", pc->cdata_buf, 
-					    hal_device_get_udi (pc->device)));
+				HAL_ERROR (("Could not resolve keypath '%s' on udi '%s'", pc->cdata_buf, pc->device->udi));
 			} else {
 				HalDevice *d;
 
@@ -1287,12 +1271,12 @@ end (ParsingContext * pc, const char *el
 
 		if (spawned == NULL) {
 			HAL_INFO (("Spawning new device object '%s' caused by <spawn> on udi '%s'", 
-				   pc->merge_key, hal_device_get_udi (pc->device)));
+				   pc->merge_key, pc->device->udi));
 
 			spawned = hal_device_new ();
 			hal_device_property_set_string (spawned, "info.bus", "unknown");
 			hal_device_property_set_string (spawned, "info.udi", pc->merge_key);
-			hal_device_property_set_string (spawned, "info.parent", hal_device_get_udi (pc->device));
+			hal_device_property_set_string (spawned, "info.parent", pc->device->udi);
 			hal_device_set_udi (spawned, pc->merge_key);
 			
 			hal_device_store_add (hald_get_tdl (), spawned);
@@ -1469,12 +1453,8 @@ out:
 
 
 
-static int
-#ifdef __GLIBC__
+static int 
 my_alphasort(const void *a, const void *b)
-#else
-my_alphasort(const struct dirent **a, const struct dirent **b)
-#endif
 {
 	return -alphasort (a, b);
 }
@@ -1500,7 +1480,7 @@ scan_fdi_files (const char *dir, HalDevi
 
 	num_entries = scandir (dir, &name_list, 0, my_alphasort);
 	if (num_entries == -1) {
-		HAL_ERROR (("scandir failed for '%s' (errno=%d '%s')", dir, errno, strerror (errno)));
+		perror ("scandir");
 		return FALSE;
 	}
 
diff-tree ec7b3fc5f01a75dd749d05c70ba2a842c16d3c66 (from parents)
Merge: 74720d88576d7cf19947ec3fbe4b15e9d0e373a4 1a077e580cf552b09445c06e088bdb1982f3f052
Author: David Zeuthen <davidz at redhat.com>
Date:   Tue Oct 10 17:45:12 2006 -0400

    Merge branch 'master' of ssh://david@git.freedesktop.org/git/hal

diff-tree 74720d88576d7cf19947ec3fbe4b15e9d0e373a4 (from cf9f235164570bb6f6667822ccfca0e4c36b5580)
Author: David Zeuthen <davidz at redhat.com>
Date:   Tue Oct 10 17:45:02 2006 -0400

    switch running_processes to using a list + fix a few memory leaks

diff --git a/hald/hald.c b/hald/hald.c
index 71e73bd..c30ff76 100644
--- a/hald/hald.c
+++ b/hald/hald.c
@@ -371,7 +371,7 @@ main (int argc, char *argv[])
 	openlog ("hald", LOG_PID, LOG_DAEMON);
 
 #ifdef HALD_MEMLEAK_DBG
-	g_mem_set_vtable (glib_mem_profiler_table);
+	/*g_mem_set_vtable (glib_mem_profiler_table);*/
 #endif
 
 	g_type_init ();
@@ -601,9 +601,9 @@ extern int dbg_hal_device_object_delta;
 static gboolean
 my_shutdown2 (gpointer data)
 {
-	g_mem_profile ();
-	sleep (10000);
-	/*exit (1);*/
+	/*g_mem_profile ();*/
+	/*sleep (10000);*/
+	exit (1);
 	return FALSE;
 }
 
diff --git a/hald/hald_runner.c b/hald/hald_runner.c
index 7940065..32abd9c 100644
--- a/hald/hald_runner.c
+++ b/hald/hald_runner.c
@@ -64,31 +64,26 @@ typedef struct
 	gpointer data2;
 } RunningProcess;
 
-/* mapping from PID to RunningProcess */
-static GHashTable *running_processes = NULL;
-
-static gboolean
-rprd_foreach (gpointer key,
-	      gpointer value,
-	      gpointer user_data)
-{
-	gboolean remove;
-	RunningProcess *rp = value;
-	HalDevice *device = user_data;
-
-	if (device == NULL || rp->device == device) {
-		remove = TRUE;
-		g_free (rp);
-	}
-
-	return remove;
-}
+/* list of RunningProcess */
+static GSList *running_processes = NULL;
 
 static void
 running_processes_remove_device (HalDevice *device)
 {
-	if (running_processes != NULL) {
-		g_hash_table_foreach_remove (running_processes, rprd_foreach, device);
+	GSList *i;
+	GSList *j;
+
+	for (i = running_processes; i != NULL; i = j) {
+		RunningProcess *rp;
+
+		j = g_slist_next (i);
+		rp = i->data;
+
+		if (rp->device == device) {
+			g_free (rp);
+			running_processes = g_slist_delete_link (running_processes, i);
+		}
+
 	}
 }
 
@@ -119,18 +114,23 @@ runner_server_message_handler (DBusConne
 		if (dbus_message_get_args (message, &error,
 					   DBUS_TYPE_INT64, &dpid,
 					   DBUS_TYPE_INVALID)) {
-			RunningProcess *rp;
+			GSList *i;
 			GPid pid;
 
 			pid = (GPid) dpid;
 
-			if (running_processes != NULL) {
-				/*HAL_INFO (("Previously started process with pid %d exited", pid));*/
-				rp = g_hash_table_lookup (running_processes, (gpointer) pid);
-				if (rp != NULL) {
+			HAL_INFO (("Previously started process with pid %d exited", pid));
+
+			for (i = running_processes; i != NULL; i = g_slist_next (i)) {
+				RunningProcess *rp;
+
+				rp = i->data;
+
+				if (rp->pid == pid) {
 					rp->cb (rp->device, 0, 0, NULL, rp->data1, rp->data2);
-					g_hash_table_remove (running_processes, (gpointer) pid);
 					g_free (rp);
+					running_processes = g_slist_delete_link (running_processes, i);
+					break;
 				}
 			}
 		}
@@ -200,8 +200,11 @@ hald_runner_stop_runner (void)
 		DBusMessage *msg;
 
 		/* Don't care about running processes anymore */
-		g_hash_table_foreach_remove (running_processes, rprd_foreach, NULL);
-		g_hash_table_destroy (running_processes);
+		
+		HAL_INFO (("running_processes %p, num = %d", running_processes, g_slist_length (running_processes)));
+
+		g_slist_foreach (running_processes, (GFunc) g_free, NULL);
+		g_slist_free (running_processes);
 		running_processes = NULL;
 
 		HAL_INFO (("Killing runner with pid %d", runner_pid));
@@ -235,7 +238,7 @@ hald_runner_start_runner(void)
   const char *hald_runner_path;
   char *server_address;
 
-  running_processes = g_hash_table_new (g_direct_hash, g_direct_equal);
+  running_processes = NULL;
 
   dbus_error_init(&err);
   runner_server = dbus_server_listen(DBUS_SERVER_ADDRESS, &err);
@@ -446,7 +449,7 @@ hald_runner_start (HalDevice *device, co
 	if (dbus_message_get_args (reply, &err,
 				   DBUS_TYPE_INT64, &pid_from_runner,
 				   DBUS_TYPE_INVALID)) {
-		if (cb != NULL && running_processes != NULL) {
+		if (cb != NULL) {
 			RunningProcess *rp;
 			rp = g_new0 (RunningProcess, 1);
 			rp->pid = (GPid) pid_from_runner;
@@ -455,7 +458,8 @@ hald_runner_start (HalDevice *device, co
 			rp->data1 = data1;
 			rp->data2 = data2;
 
-			g_hash_table_insert (running_processes, (gpointer) rp->pid, rp);
+			running_processes = g_slist_prepend (running_processes, rp);
+			HAL_INFO (("running_processes %p, num = %d", running_processes, g_slist_length (running_processes)));
 		}
 	} else {
 	  HAL_ERROR (("Error extracting out_pid from runner's Start()"));
diff --git a/hald/util.c b/hald/util.c
index 405cc23..a1e8197 100644
--- a/hald/util.c
+++ b/hald/util.c
@@ -932,10 +932,12 @@ hal_util_strdup_valid_utf8 (const char *
 		count++;
 	}
 	
-	if (strlen(newstr) == count)
+	if (strlen(newstr) == count) {
+		g_free (newstr);
 		return NULL;
-	else
+	} else {
 		return newstr;
+	}
 }
 
 void
diff --git a/hald/valgrind-hald.sh b/hald/valgrind-hald.sh
index d9f3fec..2b6a8fe 100755
--- a/hald/valgrind-hald.sh
+++ b/hald/valgrind-hald.sh
@@ -13,4 +13,5 @@ export HAL_FDI_SOURCE_PREPROBE=.local-fd
 export HAL_FDI_SOURCE_INFORMATION=.local-fdi/share/hal/fdi/information
 export HAL_FDI_SOURCE_POLICY=.local-fdi/share/hal/fdi/policy
 
-valgrind --num-callers=20 --show-reachable=yes --leak-check=yes --tool=memcheck ./hald --daemon=no --verbose=yes $@
+#valgrind --num-callers=20 --show-reachable=yes --leak-check=yes --tool=memcheck ./hald --daemon=no --verbose=yes $@
+valgrind --show-reachable=yes --tool=memcheck --leak-check=full ./hald --daemon=no --verbose=yes $@
diff-tree cf9f235164570bb6f6667822ccfca0e4c36b5580 (from parents)
Merge: ef8985ccb67b0876156742d46d687f7f2174ec68 4e6f2c6c565374ad22cc9e0ba1d44479d020a86b
Author: David Zeuthen <davidz at redhat.com>
Date:   Tue Oct 10 13:54:58 2006 -0400

    Merge branch 'master' of ssh://david@git.freedesktop.org/git/hal

diff-tree ef8985ccb67b0876156742d46d687f7f2174ec68 (from dbffafacbf7b9143d82547b9eabe61d1a5b8fffc)
Author: David Zeuthen <davidz at redhat.com>
Date:   Tue Oct 10 01:22:18 2006 -0400

    free hash table before the private object to prevent segfault

diff --git a/hald/device.c b/hald/device.c
index 15b0d8f..e0b8a7b 100644
--- a/hald/device.c
+++ b/hald/device.c
@@ -37,7 +37,6 @@
 #include "logger.h"
 #include "hald_runner.h"
 
-
 struct _HalProperty {
 	int type;
 	union {
@@ -382,10 +381,10 @@ hal_device_finalize (GObject *obj)
 
 	g_free (device->private->udi);
 
-	g_free (device->private);
-
 	g_hash_table_destroy (device->private->props);
 
+	g_free (device->private);
+
 	if (parent_class->finalize)
 		parent_class->finalize (obj);
 }


More information about the hal-commit mailing list