xref: /illumos-gate/usr/src/cmd/hal/hald/device_info.c (revision 55fea89dcaa64928bed4327112404dcb3e07b79f)
118c2aff7Sartem /***************************************************************************
218c2aff7Sartem  * CVSID: $Id$
318c2aff7Sartem  *
418c2aff7Sartem  * device_store.c : Search for .fdi files and merge on match
518c2aff7Sartem  *
618c2aff7Sartem  * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
718c2aff7Sartem  *
818c2aff7Sartem  * Licensed under the Academic Free License version 2.1
918c2aff7Sartem  *
1018c2aff7Sartem  * This program is free software; you can redistribute it and/or modify
1118c2aff7Sartem  * it under the terms of the GNU General Public License as published by
1218c2aff7Sartem  * the Free Software Foundation; either version 2 of the License, or
1318c2aff7Sartem  * (at your option) any later version.
1418c2aff7Sartem  *
1518c2aff7Sartem  * This program is distributed in the hope that it will be useful,
1618c2aff7Sartem  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1718c2aff7Sartem  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1818c2aff7Sartem  * GNU General Public License for more details.
1918c2aff7Sartem  *
2018c2aff7Sartem  * You should have received a copy of the GNU General Public License
2118c2aff7Sartem  * along with this program; if not, write to the Free Software
2218c2aff7Sartem  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
2318c2aff7Sartem  *
2418c2aff7Sartem  **************************************************************************/
2518c2aff7Sartem 
2618c2aff7Sartem #ifdef HAVE_CONFIG_H
2718c2aff7Sartem #  include <config.h>
2818c2aff7Sartem #endif
2918c2aff7Sartem 
3018c2aff7Sartem #include <stdio.h>
3118c2aff7Sartem #include <stdlib.h>
3218c2aff7Sartem #include <string.h>
3318c2aff7Sartem #include <dirent.h>
3418c2aff7Sartem #include <expat.h>
3518c2aff7Sartem #include <assert.h>
3618c2aff7Sartem #include <dbus/dbus.h>
3718c2aff7Sartem #include <dbus/dbus-glib.h>
3818c2aff7Sartem #include <math.h>
3918c2aff7Sartem 
4018c2aff7Sartem #include "hald.h"
4118c2aff7Sartem #include "logger.h"
4218c2aff7Sartem #include "device_info.h"
4318c2aff7Sartem #include "device_store.h"
4418c2aff7Sartem #include "util.h"
4518c2aff7Sartem 
4618c2aff7Sartem /**
4718c2aff7Sartem  * @defgroup DeviceInfo Device Info File Parsing
4818c2aff7Sartem  * @ingroup HalDaemon
4918c2aff7Sartem  * @brief Parsing of device info files
5018c2aff7Sartem  * @{
5118c2aff7Sartem  */
5218c2aff7Sartem 
5318c2aff7Sartem 
5418c2aff7Sartem /** Maximum nesting depth */
5518c2aff7Sartem #define MAX_DEPTH 32
5618c2aff7Sartem 
5718c2aff7Sartem /** Maximum amount of CDATA */
5818c2aff7Sartem #define CDATA_BUF_SIZE  1024
5918c2aff7Sartem 
6018c2aff7Sartem /** Max length of property key */
6118c2aff7Sartem #define MAX_KEY_SIZE 128
6218c2aff7Sartem 
6318c2aff7Sartem /** Possible elements the parser can process */
6418c2aff7Sartem enum {
6518c2aff7Sartem 	/** Not processing a known tag */
6618c2aff7Sartem 	CURELEM_UNKNOWN = -1,
6718c2aff7Sartem 
6818c2aff7Sartem 	/** Processing a deviceinfo element */
6918c2aff7Sartem 	CURELEM_DEVICE_INFO = 0,
7018c2aff7Sartem 
7118c2aff7Sartem 	/** Processing a device element */
7218c2aff7Sartem 	CURELEM_DEVICE = 1,
7318c2aff7Sartem 
7418c2aff7Sartem 	/** Processing a match element */
7518c2aff7Sartem 	CURELEM_MATCH = 2,
7618c2aff7Sartem 
7718c2aff7Sartem 	/** Processing a merge element */
7818c2aff7Sartem 	CURELEM_MERGE = 3,
7918c2aff7Sartem 
8018c2aff7Sartem 	/** Processing an append element */
8118c2aff7Sartem 	CURELEM_APPEND = 4,
8218c2aff7Sartem 
8318c2aff7Sartem 	/** Processing a prepend element */
8418c2aff7Sartem 	CURELEM_PREPEND = 5,
8518c2aff7Sartem 
8618c2aff7Sartem 	/** Processing a remove element */
8718c2aff7Sartem 	CURELEM_REMOVE = 6,
8818c2aff7Sartem 
8918c2aff7Sartem 	/** Processing a clear element */
9018c2aff7Sartem 	CURELEM_CLEAR = 7,
9118c2aff7Sartem 
9218c2aff7Sartem 	/** Processing a spawn element */
9318c2aff7Sartem 	CURELEM_SPAWN = 8
9418c2aff7Sartem };
9518c2aff7Sartem 
9618c2aff7Sartem /** What and how to merge */
9718c2aff7Sartem enum {
9818c2aff7Sartem 	MERGE_TYPE_UNKNOWN       = 0,
9918c2aff7Sartem 	MERGE_TYPE_STRING        = 1,
10018c2aff7Sartem 	MERGE_TYPE_BOOLEAN       = 2,
10118c2aff7Sartem 	MERGE_TYPE_INT32         = 3,
10218c2aff7Sartem 	MERGE_TYPE_UINT64        = 4,
10318c2aff7Sartem 	MERGE_TYPE_DOUBLE        = 5,
10418c2aff7Sartem 	MERGE_TYPE_COPY_PROPERTY = 6,
10518c2aff7Sartem 	MERGE_TYPE_STRLIST       = 7,
10618c2aff7Sartem 	MERGE_TYPE_REMOVE        = 8,
10718c2aff7Sartem 	MERGE_TYPE_CLEAR         = 9,
10818c2aff7Sartem 	MERGE_TYPE_SPAWN         = 10
10918c2aff7Sartem };
11018c2aff7Sartem 
11118c2aff7Sartem /** Parsing Context
11218c2aff7Sartem  */
11318c2aff7Sartem typedef struct {
11418c2aff7Sartem 	/** Name of file being parsed */
11518c2aff7Sartem 	char *file;
11618c2aff7Sartem 
11718c2aff7Sartem 	/** Parser object */
11818c2aff7Sartem 	XML_Parser parser;
11918c2aff7Sartem 
12018c2aff7Sartem 	/** Device we are trying to match*/
12118c2aff7Sartem 	HalDevice *device;
12218c2aff7Sartem 
12318c2aff7Sartem 	/** Buffer to put CDATA in */
12418c2aff7Sartem 	char cdata_buf[CDATA_BUF_SIZE];
12518c2aff7Sartem 
12618c2aff7Sartem 	/** Current length of CDATA buffer */
12718c2aff7Sartem 	int cdata_buf_len;
12818c2aff7Sartem 
12918c2aff7Sartem 	/** Current depth we are parsing at */
13018c2aff7Sartem 	int depth;
13118c2aff7Sartem 
13218c2aff7Sartem 	/** Element currently being processed */
13318c2aff7Sartem 	int curelem;
13418c2aff7Sartem 
13518c2aff7Sartem 	/** Stack of elements being processed */
13618c2aff7Sartem 	int curelem_stack[MAX_DEPTH];
13718c2aff7Sartem 
13818c2aff7Sartem 	/** #TRUE if parsing of document have been aborted */
13918c2aff7Sartem 	dbus_bool_t aborted;
14018c2aff7Sartem 
14118c2aff7Sartem 
14218c2aff7Sartem 	/** Depth of match-fail */
14318c2aff7Sartem 	int match_depth_first_fail;
14418c2aff7Sartem 
14518c2aff7Sartem 	/** #TRUE if all matches on prior depths have been OK */
14618c2aff7Sartem 	dbus_bool_t match_ok;
14718c2aff7Sartem 
14818c2aff7Sartem 
14918c2aff7Sartem 
15018c2aff7Sartem 	/** When merging, the key to store the value in */
15118c2aff7Sartem 	char merge_key[MAX_KEY_SIZE];
15218c2aff7Sartem 
15318c2aff7Sartem 	/** Type to merge*/
15418c2aff7Sartem 	int merge_type;
15518c2aff7Sartem 
15618c2aff7Sartem 	/** Set to #TRUE if a device is matched */
15718c2aff7Sartem 	dbus_bool_t device_matched;
15818c2aff7Sartem 
15918c2aff7Sartem } ParsingContext;
16018c2aff7Sartem 
16118c2aff7Sartem /** Resolve a udi-property path as used in .fdi files.
16218c2aff7Sartem  *
16318c2aff7Sartem  *  Examples of udi-property paths:
16418c2aff7Sartem  *
16518c2aff7Sartem  *   info.udi
16618c2aff7Sartem  *   /org/freedesktop/Hal/devices/computer:kernel.name
16718c2aff7Sartem  *   @block.storage_device:storage.bus
16818c2aff7Sartem  *   @block.storage_device:@storage.physical_device:ide.channel
16918c2aff7Sartem  *
17018c2aff7Sartem  *  @param  source_udi          UDI of source device
17118c2aff7Sartem  *  @param  path                The given path
17218c2aff7Sartem  *  @param  udi_result          Where to store the resulting UDI
17318c2aff7Sartem  *  @param  udi_result_size     Size of UDI string
17418c2aff7Sartem  *  @param  prop_result         Where to store the resulting property name
17518c2aff7Sartem  *  @param  prop_result_size    Size of property string
17618c2aff7Sartem  *  @return                     TRUE if and only if the path resolved.
17718c2aff7Sartem  */
17818c2aff7Sartem static gboolean
resolve_udiprop_path(const char * path,const char * source_udi,char * udi_result,size_t udi_result_size,char * prop_result,size_t prop_result_size)17918c2aff7Sartem resolve_udiprop_path (const char *path, const char *source_udi,
18018c2aff7Sartem 		      char *udi_result, size_t udi_result_size,
18118c2aff7Sartem 		      char *prop_result, size_t prop_result_size)
18218c2aff7Sartem {
18318c2aff7Sartem 	int i;
18418c2aff7Sartem 	gchar **tokens = NULL;
18518c2aff7Sartem 	gboolean rc;
18618c2aff7Sartem 
18718c2aff7Sartem 	rc = FALSE;
18818c2aff7Sartem 
18918c2aff7Sartem 	/*HAL_INFO (("Looking at '%s' for udi='%s'", path, source_udi));*/
19018c2aff7Sartem 
19118c2aff7Sartem 	/* Split up path into ':' tokens */
19218c2aff7Sartem 	tokens = g_strsplit (path, ":", 64);
19318c2aff7Sartem 
19418c2aff7Sartem 	/* Detect trivial property access, e.g. path='foo.bar'   */
19518c2aff7Sartem 	if (tokens == NULL || tokens[0] == NULL || tokens[1] == NULL) {
19618c2aff7Sartem 		strncpy (udi_result, source_udi, udi_result_size);
19718c2aff7Sartem 		strncpy (prop_result, path, prop_result_size);
19818c2aff7Sartem 		rc = TRUE;
19918c2aff7Sartem 		goto out;
20018c2aff7Sartem 	}
20118c2aff7Sartem 
20218c2aff7Sartem 	/* Start with the source udi */
20318c2aff7Sartem 	strncpy (udi_result, source_udi, udi_result_size);
20418c2aff7Sartem 
20518c2aff7Sartem 	for (i = 0; tokens[i] != NULL; i++) {
20618c2aff7Sartem 		HalDevice *d;
20718c2aff7Sartem 		gchar *curtoken;
20818c2aff7Sartem 
20918c2aff7Sartem 		/*HAL_INFO (("tokens[%d] = '%s'", i, tokens[i]));*/
21018c2aff7Sartem 
21118c2aff7Sartem 		d = hal_device_store_find (hald_get_gdl (), udi_result);
21218c2aff7Sartem 		if (d == NULL)
21318c2aff7Sartem 			d = hal_device_store_find (hald_get_tdl (), udi_result);
21418c2aff7Sartem 		if (d == NULL)
21518c2aff7Sartem 			goto out;
21618c2aff7Sartem 
21718c2aff7Sartem 		curtoken = tokens[i];
21818c2aff7Sartem 
21918c2aff7Sartem 		/* process all but the last tokens as UDI paths */
22018c2aff7Sartem 		if (tokens[i+1] == NULL) {
22118c2aff7Sartem 			strncpy (prop_result, curtoken, prop_result_size);
22218c2aff7Sartem 			rc = TRUE;
22318c2aff7Sartem 			goto out;
22418c2aff7Sartem 		}
22518c2aff7Sartem 
22618c2aff7Sartem 
22718c2aff7Sartem 		/* Check for indirection */
22818c2aff7Sartem 		if (curtoken[0] == '@') {
22918c2aff7Sartem 			const char *udiprop;
23018c2aff7Sartem 			const char *newudi;
23118c2aff7Sartem 
23218c2aff7Sartem 			udiprop = curtoken + 1;
23318c2aff7Sartem 
23418c2aff7Sartem 			newudi = hal_device_property_get_string (d, udiprop);
23518c2aff7Sartem 			if (newudi == NULL)
23618c2aff7Sartem 				goto out;
23718c2aff7Sartem 
23818c2aff7Sartem 			/*HAL_INFO (("new_udi = '%s' (from indirection)", newudi));*/
23918c2aff7Sartem 
24018c2aff7Sartem 			strncpy (udi_result, newudi, udi_result_size);
24118c2aff7Sartem 		} else {
24218c2aff7Sartem 			/*HAL_INFO (("new_udi = '%s'", curtoken));*/
24318c2aff7Sartem 			strncpy (udi_result, curtoken, udi_result_size);
24418c2aff7Sartem 		}
24518c2aff7Sartem 
24618c2aff7Sartem 	}
24718c2aff7Sartem 
24818c2aff7Sartem out:
24918c2aff7Sartem 
25018c2aff7Sartem /*
25118c2aff7Sartem 	HAL_INFO (("success     = '%s'", rc ? "yes" : "no"));
25218c2aff7Sartem 	HAL_INFO (("udi_result  = '%s'", udi_result));
25318c2aff7Sartem 	HAL_INFO (("prop_result = '%s'", prop_result));
25418c2aff7Sartem */
25518c2aff7Sartem 
25618c2aff7Sartem 	g_strfreev (tokens);
25718c2aff7Sartem 
25818c2aff7Sartem 	return rc;
25918c2aff7Sartem }
26018c2aff7Sartem 
26118c2aff7Sartem /* Compare the value of a property on a hal device object against a string value
26218c2aff7Sartem  * and return the result. Note that this works for several types, e.g. both strings
26318c2aff7Sartem  * and integers - in the latter case the given right side string will be interpreted
26418c2aff7Sartem  * as a number.
26518c2aff7Sartem  *
26618c2aff7Sartem  * The comparison might not make sense if you are comparing a property which is an integer
26718c2aff7Sartem  * against a string in which case this function returns FALSE. Also, if the property doesn't
26818c2aff7Sartem  * exist this function will also return FALSE.
26918c2aff7Sartem  *
27018c2aff7Sartem  * @param  d                    hal device object
27118c2aff7Sartem  * @param  key                  Key of the property to compare
27218c2aff7Sartem  * @param  right_side           Value to compare against
27318c2aff7Sartem  * @param  result               Pointer to where to store result
27418c2aff7Sartem  * @return                      TRUE if, and only if, the comparison could take place
27518c2aff7Sartem  */
27618c2aff7Sartem static gboolean
match_compare_property(HalDevice * d,const char * key,const char * right_side,dbus_int64_t * result)27718c2aff7Sartem match_compare_property (HalDevice *d, const char *key, const char *right_side, dbus_int64_t *result)
27818c2aff7Sartem {
27918c2aff7Sartem 	gboolean rc;
28018c2aff7Sartem 	int proptype;
28118c2aff7Sartem 
28218c2aff7Sartem 	rc = FALSE;
28318c2aff7Sartem 
28418c2aff7Sartem 	if (!hal_device_has_property (d, key))
28518c2aff7Sartem 		goto out;
28618c2aff7Sartem 
28718c2aff7Sartem 	proptype = hal_device_property_get_type (d, key);
28818c2aff7Sartem 	switch (proptype) {
28918c2aff7Sartem 	case HAL_PROPERTY_TYPE_STRING:
29018c2aff7Sartem 		*result = (dbus_int64_t) strcmp (hal_device_property_get_string (d, key), right_side);
29118c2aff7Sartem 		rc = TRUE;
29218c2aff7Sartem 		break;
29318c2aff7Sartem 
29418c2aff7Sartem 	case HAL_PROPERTY_TYPE_INT32:
29518c2aff7Sartem 		*result = ((dbus_int64_t) hal_device_property_get_int (d, key)) - strtoll (right_side, NULL, 0);
29618c2aff7Sartem 		rc = TRUE;
29718c2aff7Sartem 		break;
29818c2aff7Sartem 
29918c2aff7Sartem 	case HAL_PROPERTY_TYPE_UINT64:
30018c2aff7Sartem 		*result = ((dbus_int64_t) hal_device_property_get_uint64 (d, key)) - ((dbus_int64_t) strtoll (right_side, NULL, 0));
30118c2aff7Sartem 		rc = TRUE;
30218c2aff7Sartem 		break;
30318c2aff7Sartem 
30418c2aff7Sartem 	case HAL_PROPERTY_TYPE_DOUBLE:
30518c2aff7Sartem 		*result = (dbus_int64_t) ceil (hal_device_property_get_double (d, key) - atof (right_side));
30618c2aff7Sartem 		rc = TRUE;
30718c2aff7Sartem 		break;
30818c2aff7Sartem 
30918c2aff7Sartem 	default:
31018c2aff7Sartem 		/* explicit fallthrough */
31118c2aff7Sartem 	case HAL_PROPERTY_TYPE_BOOLEAN:
31218c2aff7Sartem 		/* explicit blank since this doesn't make sense */
31318c2aff7Sartem 		break;
31418c2aff7Sartem 	}
31518c2aff7Sartem 
31618c2aff7Sartem out:
31718c2aff7Sartem 	return rc;
31818c2aff7Sartem }
31918c2aff7Sartem 
32018c2aff7Sartem /** Called when the match element begins.
32118c2aff7Sartem  *
32218c2aff7Sartem  *  @param  pc                  Parsing context
32318c2aff7Sartem  *  @param  attr                Attribute key/value pairs
32418c2aff7Sartem  *  @return                     #FALSE if the device in question didn't
32518c2aff7Sartem  *                              match the data in the attributes
32618c2aff7Sartem  */
32718c2aff7Sartem static dbus_bool_t
handle_match(ParsingContext * pc,const char ** attr)32818c2aff7Sartem handle_match (ParsingContext * pc, const char **attr)
32918c2aff7Sartem {
33018c2aff7Sartem 	char udi_to_check[256];
33118c2aff7Sartem 	char prop_to_check[256];
33218c2aff7Sartem 	const char *key;
33318c2aff7Sartem 	int num_attrib;
33418c2aff7Sartem 	HalDevice *d;
33518c2aff7Sartem 
33618c2aff7Sartem 	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++);
33718c2aff7Sartem 
33818c2aff7Sartem 	if (num_attrib != 4)
33918c2aff7Sartem 		return FALSE;
34018c2aff7Sartem 
34118c2aff7Sartem 	if (strcmp (attr[0], "key") != 0)
34218c2aff7Sartem 		return FALSE;
34318c2aff7Sartem 	key = attr[1];
34418c2aff7Sartem 
34518c2aff7Sartem 	/* Resolve key paths like 'someudi/foo/bar/baz:prop.name' '@prop.here.is.an.udi:with.prop.name' */
34618c2aff7Sartem 	if (!resolve_udiprop_path (key,
34718c2aff7Sartem 				   pc->device->udi,
34818c2aff7Sartem 				   udi_to_check, sizeof (udi_to_check),
34918c2aff7Sartem 				   prop_to_check, sizeof (prop_to_check))) {
35018c2aff7Sartem 		HAL_ERROR (("Could not resolve keypath '%s' on udi '%s'", key, pc->device->udi));
35118c2aff7Sartem 		return FALSE;
35218c2aff7Sartem 	}
35318c2aff7Sartem 
35418c2aff7Sartem 	d = hal_device_store_find (hald_get_gdl (), udi_to_check);
35518c2aff7Sartem 	if (d == NULL) {
35618c2aff7Sartem 		d = hal_device_store_find (hald_get_tdl (), udi_to_check);
35718c2aff7Sartem 	}
35818c2aff7Sartem 	if (d == NULL) {
35918c2aff7Sartem 		HAL_ERROR (("Could not find device with udi '%s'", udi_to_check));
36018c2aff7Sartem 		return FALSE;
36118c2aff7Sartem 	}
36218c2aff7Sartem 
36318c2aff7Sartem 
36418c2aff7Sartem 	if (strcmp (attr[2], "string") == 0) {
36518c2aff7Sartem 		const char *value;
36618c2aff7Sartem 
36718c2aff7Sartem 		/* match string property */
36818c2aff7Sartem 
36918c2aff7Sartem 		value = attr[3];
37018c2aff7Sartem 
37118c2aff7Sartem 		/*HAL_INFO(("Checking that key='%s' is a string that "
37218c2aff7Sartem 		  "equals '%s'", key, value)); */
37318c2aff7Sartem 
37418c2aff7Sartem 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_STRING)
37518c2aff7Sartem 			return FALSE;
37618c2aff7Sartem 
37718c2aff7Sartem 		if (strcmp (hal_device_property_get_string (d, prop_to_check),
37818c2aff7Sartem 			    value) != 0)
37918c2aff7Sartem 			return FALSE;
38018c2aff7Sartem 
38118c2aff7Sartem 		/*HAL_INFO (("*** string match for key %s", key));*/
38218c2aff7Sartem 		return TRUE;
38318c2aff7Sartem 	} else if (strcmp (attr[2], "int") == 0) {
38418c2aff7Sartem 		dbus_int32_t value;
38518c2aff7Sartem 
38618c2aff7Sartem 		/* match integer property */
38718c2aff7Sartem 		value = strtol (attr[3], NULL, 0);
38818c2aff7Sartem 
38918c2aff7Sartem 		/** @todo Check error condition */
39018c2aff7Sartem 
39118c2aff7Sartem 		/*HAL_INFO (("Checking that key='%s' is a int that equals %d",
39218c2aff7Sartem 		  key, value));*/
39318c2aff7Sartem 
39418c2aff7Sartem 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_INT32)
39518c2aff7Sartem 			return FALSE;
39618c2aff7Sartem 
39718c2aff7Sartem 		if (hal_device_property_get_int (d, prop_to_check) != value) {
39818c2aff7Sartem 			return FALSE;
39918c2aff7Sartem 		}
40018c2aff7Sartem 
40118c2aff7Sartem 		return TRUE;
40218c2aff7Sartem 	} else if (strcmp (attr[2], "uint64") == 0) {
40318c2aff7Sartem 		dbus_uint64_t value;
40418c2aff7Sartem 
40518c2aff7Sartem 		/* match integer property */
40618c2aff7Sartem 		value = strtoull (attr[3], NULL, 0);
40718c2aff7Sartem 
40818c2aff7Sartem 		/** @todo Check error condition */
40918c2aff7Sartem 
41018c2aff7Sartem 		/*HAL_INFO (("Checking that key='%s' is a int that equals %d",
41118c2aff7Sartem 		  key, value));*/
41218c2aff7Sartem 
41318c2aff7Sartem 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_UINT64)
41418c2aff7Sartem 			return FALSE;
41518c2aff7Sartem 
41618c2aff7Sartem 		if (hal_device_property_get_uint64 (d, prop_to_check) != value) {
41718c2aff7Sartem 			return FALSE;
41818c2aff7Sartem 		}
41918c2aff7Sartem 
42018c2aff7Sartem 		return TRUE;
42118c2aff7Sartem 	} else if (strcmp (attr[2], "bool") == 0) {
42218c2aff7Sartem 		dbus_bool_t value;
42318c2aff7Sartem 
42418c2aff7Sartem 		/* match string property */
42518c2aff7Sartem 
42618c2aff7Sartem 		if (strcmp (attr[3], "false") == 0)
42718c2aff7Sartem 			value = FALSE;
42818c2aff7Sartem 		else if (strcmp (attr[3], "true") == 0)
42918c2aff7Sartem 			value = TRUE;
43018c2aff7Sartem 		else
43118c2aff7Sartem 			return FALSE;
43218c2aff7Sartem 
43318c2aff7Sartem 		/*HAL_INFO (("Checking that key='%s' is a bool that equals %s",
43418c2aff7Sartem 		  key, value ? "TRUE" : "FALSE"));*/
43518c2aff7Sartem 
43618c2aff7Sartem 		if (hal_device_property_get_type (d, prop_to_check) !=
43718c2aff7Sartem 		    HAL_PROPERTY_TYPE_BOOLEAN)
43818c2aff7Sartem 			return FALSE;
43918c2aff7Sartem 
44018c2aff7Sartem 		if (hal_device_property_get_bool (d, prop_to_check) != value)
44118c2aff7Sartem 			return FALSE;
44218c2aff7Sartem 
44318c2aff7Sartem 		/*HAL_INFO (("*** bool match for key %s", key));*/
44418c2aff7Sartem 		return TRUE;
44518c2aff7Sartem 	} else if (strcmp (attr[2], "exists") == 0) {
44618c2aff7Sartem 		dbus_bool_t should_exist = TRUE;
44718c2aff7Sartem 
44818c2aff7Sartem 		if (strcmp (attr[3], "false") == 0)
44918c2aff7Sartem 			should_exist = FALSE;
45018c2aff7Sartem 
45118c2aff7Sartem 		if (should_exist) {
45218c2aff7Sartem 			if (hal_device_has_property (d, prop_to_check))
45318c2aff7Sartem 				return TRUE;
45418c2aff7Sartem 			else
45518c2aff7Sartem 				return FALSE;
45618c2aff7Sartem 		} else {
45718c2aff7Sartem 			if (hal_device_has_property (d, prop_to_check))
45818c2aff7Sartem 				return FALSE;
45918c2aff7Sartem 			else
46018c2aff7Sartem 				return TRUE;
46118c2aff7Sartem 		}
46218c2aff7Sartem 	} else if (strcmp (attr[2], "empty") == 0) {
46318c2aff7Sartem 		int type;
46418c2aff7Sartem 		dbus_bool_t is_empty = TRUE;
46518c2aff7Sartem 		dbus_bool_t should_be_empty = TRUE;
46618c2aff7Sartem 
46718c2aff7Sartem 
46818c2aff7Sartem 		if (strcmp (attr[3], "false") == 0)
46918c2aff7Sartem 			should_be_empty = FALSE;
47018c2aff7Sartem 
47118c2aff7Sartem 		type = hal_device_property_get_type (d, prop_to_check);
47218c2aff7Sartem 		switch (type) {
47318c2aff7Sartem 		case HAL_PROPERTY_TYPE_STRING:
47418c2aff7Sartem 			if (hal_device_has_property (d, prop_to_check))
47518c2aff7Sartem 				if (strlen (hal_device_property_get_string (d, prop_to_check)) > 0)
47618c2aff7Sartem 					is_empty = FALSE;
47718c2aff7Sartem 			break;
47818c2aff7Sartem 		case HAL_PROPERTY_TYPE_STRLIST:
47918c2aff7Sartem 			if (hal_device_has_property (d, prop_to_check))
48018c2aff7Sartem 				if (!hal_device_property_strlist_is_empty(d, prop_to_check))
48118c2aff7Sartem 					is_empty = FALSE;
48218c2aff7Sartem 			break;
48318c2aff7Sartem 		default:
48418c2aff7Sartem 			/* explicit fallthrough */
48518c2aff7Sartem 			return FALSE;
48618c2aff7Sartem 			break;
48718c2aff7Sartem 		}
48818c2aff7Sartem 
48918c2aff7Sartem 		if (should_be_empty) {
49018c2aff7Sartem 			if (is_empty)
49118c2aff7Sartem 				return TRUE;
49218c2aff7Sartem 			else
49318c2aff7Sartem 				return FALSE;
49418c2aff7Sartem 		} else {
49518c2aff7Sartem 			if (is_empty)
49618c2aff7Sartem 				return FALSE;
49718c2aff7Sartem 			else
49818c2aff7Sartem 				return TRUE;
49918c2aff7Sartem 		}
50018c2aff7Sartem 	} else if (strcmp (attr[2], "is_ascii") == 0) {
50118c2aff7Sartem 		dbus_bool_t is_ascii = TRUE;
50218c2aff7Sartem 		dbus_bool_t should_be_ascii = TRUE;
50318c2aff7Sartem 		unsigned int i;
50418c2aff7Sartem 		const char *str;
50518c2aff7Sartem 
50618c2aff7Sartem 		if (strcmp (attr[3], "false") == 0)
50718c2aff7Sartem 			should_be_ascii = FALSE;
50818c2aff7Sartem 
50918c2aff7Sartem 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_STRING)
51018c2aff7Sartem 			return FALSE;
51118c2aff7Sartem 
51218c2aff7Sartem 		is_ascii = TRUE;
51318c2aff7Sartem 
51418c2aff7Sartem 		str = hal_device_property_get_string (d, prop_to_check);
51518c2aff7Sartem 		for (i = 0; str[i] != '\0'; i++) {
51618c2aff7Sartem 			if (((unsigned char) str[i]) > 0x7f)
51718c2aff7Sartem 				is_ascii = FALSE;
51818c2aff7Sartem 		}
51918c2aff7Sartem 
52018c2aff7Sartem 		if (should_be_ascii) {
52118c2aff7Sartem 			if (is_ascii)
52218c2aff7Sartem 				return TRUE;
52318c2aff7Sartem 			else
52418c2aff7Sartem 				return FALSE;
52518c2aff7Sartem 		} else {
52618c2aff7Sartem 			if (is_ascii)
52718c2aff7Sartem 				return FALSE;
52818c2aff7Sartem 			else
52918c2aff7Sartem 				return TRUE;
53018c2aff7Sartem 		}
53118c2aff7Sartem 	} else if (strcmp (attr[2], "is_absolute_path") == 0) {
53218c2aff7Sartem 		const char *path = NULL;
53318c2aff7Sartem 		dbus_bool_t is_absolute_path = FALSE;
53418c2aff7Sartem 		dbus_bool_t should_be_absolute_path = TRUE;
53518c2aff7Sartem 
53618c2aff7Sartem 		if (strcmp (attr[3], "false") == 0)
53718c2aff7Sartem 			should_be_absolute_path = FALSE;
53818c2aff7Sartem 
53918c2aff7Sartem 		/*HAL_INFO (("d->udi='%s', prop_to_check='%s'", d->udi, prop_to_check));*/
54018c2aff7Sartem 
54118c2aff7Sartem 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_STRING)
54218c2aff7Sartem 			return FALSE;
54318c2aff7Sartem 
54418c2aff7Sartem 		if (hal_device_has_property (d, prop_to_check)) {
54518c2aff7Sartem 			path = hal_device_property_get_string (d, prop_to_check);
54618c2aff7Sartem 			if (g_path_is_absolute (path))
54718c2aff7Sartem 				is_absolute_path = TRUE;
54818c2aff7Sartem 		}
54918c2aff7Sartem 
55018c2aff7Sartem 		/*HAL_INFO (("is_absolute=%d, should_be=%d, path='%s'", is_absolute_path, should_be_absolute_path, path));*/
55118c2aff7Sartem 
55218c2aff7Sartem 		if (should_be_absolute_path) {
55318c2aff7Sartem 			if (is_absolute_path)
55418c2aff7Sartem 				return TRUE;
55518c2aff7Sartem 			else
55618c2aff7Sartem 				return FALSE;
55718c2aff7Sartem 		} else {
55818c2aff7Sartem 			if (is_absolute_path)
55918c2aff7Sartem 				return FALSE;
56018c2aff7Sartem 			else
56118c2aff7Sartem 				return TRUE;
56218c2aff7Sartem 		}
56318c2aff7Sartem 	} else if (strcmp (attr[2], "contains") == 0) {
56418c2aff7Sartem 		const char *needle;
56518c2aff7Sartem 		dbus_bool_t contains = FALSE;
56618c2aff7Sartem 
56718c2aff7Sartem 		needle = attr[3];
56818c2aff7Sartem 
56918c2aff7Sartem 		if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRING) {
57018c2aff7Sartem 			if (hal_device_has_property (d, prop_to_check)) {
57118c2aff7Sartem 				const char *haystack;
57218c2aff7Sartem 
57318c2aff7Sartem 				haystack = hal_device_property_get_string (d, prop_to_check);
57418c2aff7Sartem 				if (needle != NULL && haystack != NULL && strstr (haystack, needle)) {
57518c2aff7Sartem 					contains = TRUE;
57618c2aff7Sartem 				}
57718c2aff7Sartem 
57818c2aff7Sartem 			}
57918c2aff7Sartem 		} else if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRLIST &&
58018c2aff7Sartem 			   needle != NULL) {
58118c2aff7Sartem 			GSList *i;
58218c2aff7Sartem 			GSList *value;
58318c2aff7Sartem 
58418c2aff7Sartem 			value = hal_device_property_get_strlist (d, prop_to_check);
58518c2aff7Sartem 			for (i = value; i != NULL; i = g_slist_next (i)) {
58618c2aff7Sartem 				const char *str = i->data;
58718c2aff7Sartem 				if (strcmp (str, needle) == 0) {
58818c2aff7Sartem 					contains = TRUE;
58918c2aff7Sartem 					break;
59018c2aff7Sartem 				}
59118c2aff7Sartem 			}
59218c2aff7Sartem 		} else {
59318c2aff7Sartem 			return FALSE;
59418c2aff7Sartem 		}
59518c2aff7Sartem 
59618c2aff7Sartem 		return contains;
59718c2aff7Sartem 	} else if (strcmp (attr[2], "contains_ncase") == 0) {
59818c2aff7Sartem 		const char *needle;
59918c2aff7Sartem 		dbus_bool_t contains_ncase = FALSE;
60018c2aff7Sartem 
60118c2aff7Sartem 		needle = attr[3];
60218c2aff7Sartem 
60318c2aff7Sartem 		if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRING) {
60418c2aff7Sartem 			if (hal_device_has_property (d, prop_to_check)) {
60518c2aff7Sartem 				char *needle_lowercase;
60618c2aff7Sartem 				char *haystack_lowercase;
60718c2aff7Sartem 
60818c2aff7Sartem 				needle_lowercase   = g_utf8_strdown (needle, -1);
60918c2aff7Sartem 				haystack_lowercase = g_utf8_strdown (hal_device_property_get_string (d, prop_to_check), -1);
61018c2aff7Sartem 				if (needle_lowercase != NULL && haystack_lowercase != NULL && strstr (haystack_lowercase, needle_lowercase)) {
61118c2aff7Sartem 					contains_ncase = TRUE;
61218c2aff7Sartem 				}
61318c2aff7Sartem 
61418c2aff7Sartem 				g_free (needle_lowercase);
61518c2aff7Sartem 				g_free (haystack_lowercase);
61618c2aff7Sartem 			}
61718c2aff7Sartem 		} else if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRLIST &&
61818c2aff7Sartem 			   needle != NULL) {
61918c2aff7Sartem 			GSList *i;
62018c2aff7Sartem 			GSList *value;
62118c2aff7Sartem 
62218c2aff7Sartem 			value = hal_device_property_get_strlist (d, prop_to_check);
62318c2aff7Sartem 			for (i = value; i != NULL; i = g_slist_next (i)) {
62418c2aff7Sartem 				const char *str = i->data;
62518c2aff7Sartem 				if (g_ascii_strcasecmp (str, needle) == 0) {
62618c2aff7Sartem 					contains_ncase = TRUE;
62718c2aff7Sartem 					break;
62818c2aff7Sartem 				}
62918c2aff7Sartem 			}
63018c2aff7Sartem 		} else {
63118c2aff7Sartem 			return FALSE;
63218c2aff7Sartem 		}
63318c2aff7Sartem 
63418c2aff7Sartem 		return contains_ncase;
63518c2aff7Sartem 	} else if (strcmp (attr[2], "compare_lt") == 0) {
63618c2aff7Sartem 		dbus_int64_t result;
63718c2aff7Sartem 		if (!match_compare_property (d, prop_to_check, attr[3], &result)) {
63818c2aff7Sartem 			return FALSE;
63918c2aff7Sartem 		} else {
64018c2aff7Sartem 			return result < 0;
64118c2aff7Sartem 		}
64218c2aff7Sartem 	} else if (strcmp (attr[2], "compare_le") == 0) {
64318c2aff7Sartem 		dbus_int64_t result;
64418c2aff7Sartem 		if (!match_compare_property (d, prop_to_check, attr[3], &result))
64518c2aff7Sartem 			return FALSE;
64618c2aff7Sartem 		else
64718c2aff7Sartem 			return result <= 0;
64818c2aff7Sartem 	} else if (strcmp (attr[2], "compare_gt") == 0) {
64918c2aff7Sartem 		dbus_int64_t result;
65018c2aff7Sartem 		if (!match_compare_property (d, prop_to_check, attr[3], &result))
65118c2aff7Sartem 			return FALSE;
65218c2aff7Sartem 		else
65318c2aff7Sartem 			return result > 0;
65418c2aff7Sartem 	} else if (strcmp (attr[2], "compare_ge") == 0) {
65518c2aff7Sartem 		dbus_int64_t result;
65618c2aff7Sartem 		if (!match_compare_property (d, prop_to_check, attr[3], &result))
65718c2aff7Sartem 			return FALSE;
65818c2aff7Sartem 		else
65918c2aff7Sartem 			return result >= 0;
66018c2aff7Sartem 	}
66118c2aff7Sartem 
66218c2aff7Sartem 	return FALSE;
66318c2aff7Sartem }
66418c2aff7Sartem 
66518c2aff7Sartem 
66618c2aff7Sartem /** Called when the merge element begins.
66718c2aff7Sartem  *
66818c2aff7Sartem  *  @param  pc                  Parsing context
66918c2aff7Sartem  *  @param  attr                Attribute key/value pairs
67018c2aff7Sartem  */
67118c2aff7Sartem static void
handle_merge(ParsingContext * pc,const char ** attr)67218c2aff7Sartem handle_merge (ParsingContext * pc, const char **attr)
67318c2aff7Sartem {
67418c2aff7Sartem 	int num_attrib;
67518c2aff7Sartem 
67618c2aff7Sartem 	pc->merge_type = MERGE_TYPE_UNKNOWN;
67718c2aff7Sartem 
67818c2aff7Sartem 
67918c2aff7Sartem 	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++) {
68018c2aff7Sartem 		;
68118c2aff7Sartem 	}
68218c2aff7Sartem 
68318c2aff7Sartem 	if (num_attrib != 4)
68418c2aff7Sartem 		return;
68518c2aff7Sartem 
68618c2aff7Sartem 	if (strcmp (attr[0], "key") != 0)
68718c2aff7Sartem 		return;
68818c2aff7Sartem 	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
68918c2aff7Sartem 
69018c2aff7Sartem 	if (strcmp (attr[2], "type") != 0)
69118c2aff7Sartem 		return;
69218c2aff7Sartem 
69318c2aff7Sartem 	if (strcmp (attr[3], "string") == 0) {
69418c2aff7Sartem 		/* match string property */
69518c2aff7Sartem 		pc->merge_type = MERGE_TYPE_STRING;
69618c2aff7Sartem 		return;
69718c2aff7Sartem 	} else if (strcmp (attr[3], "bool") == 0) {
69818c2aff7Sartem 		/* match string property */
69918c2aff7Sartem 		pc->merge_type = MERGE_TYPE_BOOLEAN;
70018c2aff7Sartem 		return;
70118c2aff7Sartem 	} else if (strcmp (attr[3], "int") == 0) {
70218c2aff7Sartem 		/* match string property */
70318c2aff7Sartem 		pc->merge_type = MERGE_TYPE_INT32;
70418c2aff7Sartem 		return;
70518c2aff7Sartem 	} else if (strcmp (attr[3], "uint64") == 0) {
70618c2aff7Sartem 		/* match string property */
70718c2aff7Sartem 		pc->merge_type = MERGE_TYPE_UINT64;
70818c2aff7Sartem 		return;
70918c2aff7Sartem 	} else if (strcmp (attr[3], "double") == 0) {
71018c2aff7Sartem 		/* match string property */
71118c2aff7Sartem 		pc->merge_type = MERGE_TYPE_DOUBLE;
71218c2aff7Sartem 		return;
71318c2aff7Sartem 	} else if (strcmp (attr[3], "strlist") == 0) {
71418c2aff7Sartem 		/* match string property */
71518c2aff7Sartem 		pc->merge_type = MERGE_TYPE_STRLIST;
71618c2aff7Sartem 		return;
71718c2aff7Sartem 	} else if (strcmp (attr[3], "copy_property") == 0) {
71818c2aff7Sartem 		/* copy another property */
71918c2aff7Sartem 		pc->merge_type = MERGE_TYPE_COPY_PROPERTY;
72018c2aff7Sartem 		return;
72118c2aff7Sartem 	}
72218c2aff7Sartem 
72318c2aff7Sartem 	return;
72418c2aff7Sartem }
72518c2aff7Sartem 
72618c2aff7Sartem /** Called when the append or prepend element begins.
72718c2aff7Sartem  *
72818c2aff7Sartem  *  @param  pc                  Parsing context
72918c2aff7Sartem  *  @param  attr                Attribute key/value pairs
73018c2aff7Sartem  */
73118c2aff7Sartem static void
handle_append_prepend(ParsingContext * pc,const char ** attr)73218c2aff7Sartem handle_append_prepend (ParsingContext * pc, const char **attr)
73318c2aff7Sartem {
73418c2aff7Sartem 	int num_attrib;
73518c2aff7Sartem 
73618c2aff7Sartem 	pc->merge_type = MERGE_TYPE_UNKNOWN;
73718c2aff7Sartem 
73818c2aff7Sartem 	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++) {
73918c2aff7Sartem 		;
74018c2aff7Sartem 	}
74118c2aff7Sartem 
74218c2aff7Sartem 	if (num_attrib != 4)
74318c2aff7Sartem 		return;
74418c2aff7Sartem 
74518c2aff7Sartem 	if (strcmp (attr[0], "key") != 0)
74618c2aff7Sartem 		return;
74718c2aff7Sartem 	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
74818c2aff7Sartem 
74918c2aff7Sartem 	if (strcmp (attr[2], "type") != 0)
75018c2aff7Sartem 		return;
75118c2aff7Sartem 
75218c2aff7Sartem 	if (strcmp (attr[3], "string") == 0) {
75318c2aff7Sartem 		/* append to a string */
75418c2aff7Sartem 		pc->merge_type = MERGE_TYPE_STRING;
75518c2aff7Sartem 		return;
75618c2aff7Sartem 	} else if (strcmp (attr[3], "strlist") == 0) {
75718c2aff7Sartem 		/* append to a string list*/
75818c2aff7Sartem 		pc->merge_type = MERGE_TYPE_STRLIST;
75918c2aff7Sartem 		return;
76018c2aff7Sartem 	} else if (strcmp (attr[3], "copy_property") == 0) {
76118c2aff7Sartem 		/* copy another property */
76218c2aff7Sartem 		pc->merge_type = MERGE_TYPE_COPY_PROPERTY;
76318c2aff7Sartem 		return;
76418c2aff7Sartem 	}
76518c2aff7Sartem 
76618c2aff7Sartem 	return;
76718c2aff7Sartem }
76818c2aff7Sartem 
76918c2aff7Sartem 
77018c2aff7Sartem /** Called when the spawn element begins.
77118c2aff7Sartem  *
77218c2aff7Sartem  *  @param  pc                  Parsing context
77318c2aff7Sartem  *  @param  attr                Attribute key/value pairs
77418c2aff7Sartem  */
77518c2aff7Sartem static void
handle_spawn(ParsingContext * pc,const char ** attr)77618c2aff7Sartem handle_spawn (ParsingContext * pc, const char **attr)
77718c2aff7Sartem {
77818c2aff7Sartem 	int num_attrib;
77918c2aff7Sartem 
78018c2aff7Sartem 	pc->merge_type = MERGE_TYPE_UNKNOWN;
78118c2aff7Sartem 
78218c2aff7Sartem 	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++) {
78318c2aff7Sartem 		;
78418c2aff7Sartem 	}
78518c2aff7Sartem 
78618c2aff7Sartem 	if (num_attrib != 2)
78718c2aff7Sartem 		return;
78818c2aff7Sartem 
78918c2aff7Sartem 	if (strcmp (attr[0], "udi") != 0)
79018c2aff7Sartem 		return;
79118c2aff7Sartem 
79218c2aff7Sartem 	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
79318c2aff7Sartem 
79418c2aff7Sartem 	pc->merge_type = MERGE_TYPE_SPAWN;
79518c2aff7Sartem 	return;
79618c2aff7Sartem }
79718c2aff7Sartem 
79818c2aff7Sartem /** Called when the remove element begins.
79918c2aff7Sartem  *
80018c2aff7Sartem  *  @param  pc                  Parsing context
80118c2aff7Sartem  *  @param  attr                Attribute key/value pairs
80218c2aff7Sartem  */
80318c2aff7Sartem static void
handle_remove(ParsingContext * pc,const char ** attr)80418c2aff7Sartem handle_remove (ParsingContext * pc, const char **attr)
80518c2aff7Sartem {
80618c2aff7Sartem 	int num_attrib;
80718c2aff7Sartem 
80818c2aff7Sartem 	pc->merge_type = MERGE_TYPE_UNKNOWN;
80918c2aff7Sartem 
81018c2aff7Sartem 	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++) {
81118c2aff7Sartem 		;
81218c2aff7Sartem 	}
81318c2aff7Sartem 
81418c2aff7Sartem 	if (num_attrib != 2 && num_attrib != 4)
81518c2aff7Sartem 		return;
81618c2aff7Sartem 
81718c2aff7Sartem 	if (strcmp (attr[0], "key") != 0)
81818c2aff7Sartem 		return;
81918c2aff7Sartem 	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
82018c2aff7Sartem 
82118c2aff7Sartem 	if (num_attrib == 4) {
82218c2aff7Sartem 		if (strcmp (attr[2], "type") != 0)
82318c2aff7Sartem 			return;
82418c2aff7Sartem 
82518c2aff7Sartem 		if (strcmp (attr[3], "strlist") == 0) {
82618c2aff7Sartem 			/* remove from strlist */
82718c2aff7Sartem 			pc->merge_type = MERGE_TYPE_STRLIST;
82818c2aff7Sartem 			return;
82918c2aff7Sartem 		} else {
83018c2aff7Sartem 			pc->merge_type = MERGE_TYPE_UNKNOWN;
83118c2aff7Sartem 			return;
83218c2aff7Sartem 		}
83318c2aff7Sartem 	} else {
83418c2aff7Sartem 		pc->merge_type = MERGE_TYPE_REMOVE;
83518c2aff7Sartem 	}
83618c2aff7Sartem 
83718c2aff7Sartem 	return;
83818c2aff7Sartem }
83918c2aff7Sartem 
84018c2aff7Sartem /** Called when the clear element begins.
84118c2aff7Sartem  *
84218c2aff7Sartem  *  @param  pc                  Parsing context
84318c2aff7Sartem  *  @param  attr                Attribute key/value pairs
84418c2aff7Sartem  */
84518c2aff7Sartem static void
handle_clear(ParsingContext * pc,const char ** attr)84618c2aff7Sartem handle_clear (ParsingContext * pc, const char **attr)
84718c2aff7Sartem {
84818c2aff7Sartem 	int num_attrib;
84918c2aff7Sartem 
85018c2aff7Sartem 	pc->merge_type = MERGE_TYPE_UNKNOWN;
85118c2aff7Sartem 
85218c2aff7Sartem 	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++) {
85318c2aff7Sartem 		;
85418c2aff7Sartem 	}
85518c2aff7Sartem 
85618c2aff7Sartem 	if (num_attrib != 4)
85718c2aff7Sartem 		return;
85818c2aff7Sartem 
85918c2aff7Sartem 	if (strcmp (attr[0], "key") != 0)
86018c2aff7Sartem 		return;
86118c2aff7Sartem 
86218c2aff7Sartem 
86318c2aff7Sartem 	if (strcmp (attr[3], "strlist") != 0)
86418c2aff7Sartem 		return;
86518c2aff7Sartem 
86618c2aff7Sartem 	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
86718c2aff7Sartem 
86818c2aff7Sartem 	pc->merge_type = MERGE_TYPE_CLEAR;
86918c2aff7Sartem 
87018c2aff7Sartem 	return;
87118c2aff7Sartem }
87218c2aff7Sartem 
87318c2aff7Sartem /** Abort parsing of document
87418c2aff7Sartem  *
87518c2aff7Sartem  *  @param  pc                  Parsing context
87618c2aff7Sartem  */
87718c2aff7Sartem static void
parsing_abort(ParsingContext * pc)87818c2aff7Sartem parsing_abort (ParsingContext * pc)
87918c2aff7Sartem {
88018c2aff7Sartem 	/* Grr, expat can't abort parsing */
88118c2aff7Sartem 	HAL_ERROR (("Aborting parsing of document"));
88218c2aff7Sartem 	pc->aborted = TRUE;
88318c2aff7Sartem }
88418c2aff7Sartem 
88518c2aff7Sartem /** Called by expat when an element begins.
88618c2aff7Sartem  *
88718c2aff7Sartem  *  @param  pc                  Parsing context
88818c2aff7Sartem  *  @param  el                  Element name
88918c2aff7Sartem  *  @param  attr                Attribute key/value pairs
89018c2aff7Sartem  */
89118c2aff7Sartem static void
start(ParsingContext * pc,const char * el,const char ** attr)89218c2aff7Sartem start (ParsingContext * pc, const char *el, const char **attr)
89318c2aff7Sartem {
89418c2aff7Sartem 	if (pc->aborted)
89518c2aff7Sartem 		return;
89618c2aff7Sartem 
89718c2aff7Sartem 	pc->cdata_buf_len = 0;
89818c2aff7Sartem 
89918c2aff7Sartem 	pc->merge_type = MERGE_TYPE_UNKNOWN;
90018c2aff7Sartem 
90118c2aff7Sartem /*
90218c2aff7Sartem     for (i = 0; i < pc->depth; i++)
90318c2aff7Sartem         printf("  ");
90418c2aff7Sartem 
90518c2aff7Sartem     printf("%s", el);
90618c2aff7Sartem 
90718c2aff7Sartem     for (i = 0; attr[i]; i += 2) {
90818c2aff7Sartem         printf(" %s='%s'", attr[i], attr[i + 1]);
90918c2aff7Sartem     }
91018c2aff7Sartem 
91118c2aff7Sartem     printf("   curelem=%d\n", pc->curelem);
91218c2aff7Sartem */
91318c2aff7Sartem 
91418c2aff7Sartem 	if (strcmp (el, "match") == 0) {
91518c2aff7Sartem 		if (pc->curelem != CURELEM_DEVICE
91618c2aff7Sartem 		    && pc->curelem != CURELEM_MATCH) {
91718c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <match> can only be "
91818c2aff7Sartem 				    "inside <device> and <match>",
91918c2aff7Sartem 				    pc->file,
92018c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
92118c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
92218c2aff7Sartem 			parsing_abort (pc);
92318c2aff7Sartem 		}
92418c2aff7Sartem 
92518c2aff7Sartem 		pc->curelem = CURELEM_MATCH;
92618c2aff7Sartem 
92718c2aff7Sartem 		/* don't bother checking if matching at lower depths failed */
92818c2aff7Sartem 		if (pc->match_ok) {
92918c2aff7Sartem 			if (!handle_match (pc, attr)) {
93018c2aff7Sartem 				/* No match */
93118c2aff7Sartem 				pc->match_depth_first_fail = pc->depth;
93218c2aff7Sartem 				pc->match_ok = FALSE;
93318c2aff7Sartem 			}
93418c2aff7Sartem 		}
93518c2aff7Sartem 	} else if (strcmp (el, "merge") == 0) {
93618c2aff7Sartem 		if (pc->curelem != CURELEM_DEVICE
93718c2aff7Sartem 		    && pc->curelem != CURELEM_MATCH) {
93818c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <merge> can only be "
93918c2aff7Sartem 				    "inside <device> and <match>",
94018c2aff7Sartem 				    pc->file,
94118c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
94218c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
94318c2aff7Sartem 			parsing_abort (pc);
94418c2aff7Sartem 		}
94518c2aff7Sartem 
94618c2aff7Sartem 		pc->curelem = CURELEM_MERGE;
94718c2aff7Sartem 		if (pc->match_ok) {
94818c2aff7Sartem 			handle_merge (pc, attr);
94918c2aff7Sartem 		} else {
95018c2aff7Sartem 			/*HAL_INFO(("No merge!")); */
95118c2aff7Sartem 		}
95218c2aff7Sartem 	} else if (strcmp (el, "append") == 0) {
95318c2aff7Sartem 		if (pc->curelem != CURELEM_DEVICE
95418c2aff7Sartem 		    && pc->curelem != CURELEM_MATCH) {
95518c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <append> can only be "
95618c2aff7Sartem 				    "inside <device> and <match>",
95718c2aff7Sartem 				    pc->file,
95818c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
95918c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
96018c2aff7Sartem 			parsing_abort (pc);
96118c2aff7Sartem 		}
96218c2aff7Sartem 
96318c2aff7Sartem 		pc->curelem = CURELEM_APPEND;
96418c2aff7Sartem 		if (pc->match_ok) {
96518c2aff7Sartem 			handle_append_prepend (pc, attr);
96618c2aff7Sartem 		} else {
96718c2aff7Sartem 			/*HAL_INFO(("No merge!")); */
96818c2aff7Sartem 		}
96918c2aff7Sartem 	} else if (strcmp (el, "prepend") == 0) {
97018c2aff7Sartem 		if (pc->curelem != CURELEM_DEVICE
97118c2aff7Sartem 		    && pc->curelem != CURELEM_MATCH) {
97218c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <prepend> can only be "
97318c2aff7Sartem 				    "inside <device> and <match>",
97418c2aff7Sartem 				    pc->file,
97518c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
97618c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
97718c2aff7Sartem 			parsing_abort (pc);
97818c2aff7Sartem 		}
97918c2aff7Sartem 
98018c2aff7Sartem 		pc->curelem = CURELEM_PREPEND;
98118c2aff7Sartem 		if (pc->match_ok) {
98218c2aff7Sartem 			handle_append_prepend (pc, attr);
98318c2aff7Sartem 		} else {
98418c2aff7Sartem 			/*HAL_INFO(("No merge!")); */
98518c2aff7Sartem 		}
98618c2aff7Sartem 	} else if (strcmp (el, "remove") == 0) {
98718c2aff7Sartem 		if (pc->curelem != CURELEM_DEVICE
98818c2aff7Sartem 		    && pc->curelem != CURELEM_MATCH) {
98918c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <remove> can only be "
99018c2aff7Sartem 				    "inside <device> and <match>",
99118c2aff7Sartem 				    pc->file,
99218c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
99318c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
99418c2aff7Sartem 			parsing_abort (pc);
99518c2aff7Sartem 		}
99618c2aff7Sartem 
99718c2aff7Sartem 		pc->curelem = CURELEM_REMOVE;
99818c2aff7Sartem 		if (pc->match_ok) {
99918c2aff7Sartem 			handle_remove (pc, attr);
100018c2aff7Sartem 		} else {
100118c2aff7Sartem 			/*HAL_INFO(("No merge!")); */
100218c2aff7Sartem 		}
100318c2aff7Sartem 	} else if (strcmp (el, "clear") == 0) {
100418c2aff7Sartem 		if (pc->curelem != CURELEM_DEVICE
100518c2aff7Sartem 		    && pc->curelem != CURELEM_MATCH) {
100618c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <remove> can only be "
100718c2aff7Sartem 				    "inside <device> and <match>",
100818c2aff7Sartem 				    pc->file,
100918c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
101018c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
101118c2aff7Sartem 			parsing_abort (pc);
101218c2aff7Sartem 		}
101318c2aff7Sartem 
101418c2aff7Sartem 		pc->curelem = CURELEM_CLEAR;
101518c2aff7Sartem 		if (pc->match_ok) {
101618c2aff7Sartem 			handle_clear (pc, attr);
101718c2aff7Sartem 		} else {
101818c2aff7Sartem 			/*HAL_INFO(("No merge!")); */
101918c2aff7Sartem 		}
102018c2aff7Sartem 	} else if (strcmp (el, "device") == 0) {
102118c2aff7Sartem 		if (pc->curelem != CURELEM_DEVICE_INFO) {
102218c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <device> can only be "
102318c2aff7Sartem 				    "inside <deviceinfo>",
102418c2aff7Sartem 				    pc->file,
102518c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
102618c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
102718c2aff7Sartem 			parsing_abort (pc);
102818c2aff7Sartem 		}
102918c2aff7Sartem 		pc->curelem = CURELEM_DEVICE;
103018c2aff7Sartem 	} else if (strcmp (el, "deviceinfo") == 0) {
103118c2aff7Sartem 		if (pc->curelem != CURELEM_UNKNOWN) {
103218c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <deviceinfo> must be "
103318c2aff7Sartem 				    "a top-level element",
103418c2aff7Sartem 				    pc->file,
103518c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
103618c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
103718c2aff7Sartem 			parsing_abort (pc);
103818c2aff7Sartem 		}
103918c2aff7Sartem 		pc->curelem = CURELEM_DEVICE_INFO;
104018c2aff7Sartem 	} else if (strcmp (el, "spawn") == 0) {
104118c2aff7Sartem 		if (pc->curelem != CURELEM_MATCH) {
104218c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <spawn> can only be "
104318c2aff7Sartem 				    "inside <match>",
104418c2aff7Sartem 				    pc->file,
104518c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
104618c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
104718c2aff7Sartem 			parsing_abort (pc);
104818c2aff7Sartem 		}
104918c2aff7Sartem 
105018c2aff7Sartem 		pc->curelem = CURELEM_SPAWN;
105118c2aff7Sartem 		if (pc->match_ok) {
105218c2aff7Sartem 			handle_spawn (pc, attr);
105318c2aff7Sartem 		}
105418c2aff7Sartem 
105518c2aff7Sartem 	} else {
105618c2aff7Sartem 		HAL_ERROR (("%s:%d:%d: Unknown element <%s>",
105718c2aff7Sartem 			    pc->file,
105818c2aff7Sartem 			    XML_GetCurrentLineNumber (pc->parser),
105918c2aff7Sartem 			    XML_GetCurrentColumnNumber (pc->parser), el));
106018c2aff7Sartem 		parsing_abort (pc);
106118c2aff7Sartem 	}
106218c2aff7Sartem 
106318c2aff7Sartem 	/* Nasty hack */
106418c2aff7Sartem 	assert (pc->depth < MAX_DEPTH);
106518c2aff7Sartem 
106618c2aff7Sartem 	pc->depth++;
106718c2aff7Sartem 
106818c2aff7Sartem 	/* store depth */
106918c2aff7Sartem 	pc->curelem_stack[pc->depth] = pc->curelem;
107018c2aff7Sartem 
107118c2aff7Sartem }
107218c2aff7Sartem 
107318c2aff7Sartem static void
spawned_device_callouts_add_done(HalDevice * d,gpointer userdata1,gpointer userdata2)107418c2aff7Sartem spawned_device_callouts_add_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
107518c2aff7Sartem {
107618c2aff7Sartem 	HAL_INFO (("Add callouts completed udi=%s", d->udi));
107718c2aff7Sartem 
107818c2aff7Sartem 	/* Move from temporary to global device store */
107918c2aff7Sartem 	hal_device_store_remove (hald_get_tdl (), d);
108018c2aff7Sartem 	hal_device_store_add (hald_get_gdl (), d);
108118c2aff7Sartem 
108218c2aff7Sartem }
108318c2aff7Sartem 
108418c2aff7Sartem /** Called by expat when an element ends.
108518c2aff7Sartem  *
108618c2aff7Sartem  *  @param  pc                  Parsing context
108718c2aff7Sartem  *  @param  el                  Element name
108818c2aff7Sartem  */
108918c2aff7Sartem static void
end(ParsingContext * pc,const char * el)109018c2aff7Sartem end (ParsingContext * pc, const char *el)
109118c2aff7Sartem {
109218c2aff7Sartem 	if (pc->aborted)
109318c2aff7Sartem 		return;
109418c2aff7Sartem 
109518c2aff7Sartem 	pc->cdata_buf[pc->cdata_buf_len] = '\0';
109618c2aff7Sartem 
109718c2aff7Sartem /*    printf("   curelem=%d\n", pc->curelem);*/
109818c2aff7Sartem 
109918c2aff7Sartem 	if (pc->curelem == CURELEM_MERGE && pc->match_ok) {
110018c2aff7Sartem 		/* As soon as we are merging, we have matched the device... */
110118c2aff7Sartem 		pc->device_matched = TRUE;
110218c2aff7Sartem 
110318c2aff7Sartem 		switch (pc->merge_type) {
110418c2aff7Sartem 		case MERGE_TYPE_STRING:
110518c2aff7Sartem 			hal_device_property_set_string (pc->device, pc->merge_key, pc->cdata_buf);
110618c2aff7Sartem 			break;
110718c2aff7Sartem 
110818c2aff7Sartem 		case MERGE_TYPE_STRLIST:
110918c2aff7Sartem 		{
111018c2aff7Sartem 			int type = hal_device_property_get_type (pc->device, pc->merge_key);
111118c2aff7Sartem 			if (type == HAL_PROPERTY_TYPE_STRLIST || type == HAL_PROPERTY_TYPE_INVALID) {
111218c2aff7Sartem 				hal_device_property_remove (pc->device, pc->merge_key);
111318c2aff7Sartem 				hal_device_property_strlist_append (pc->device, pc->merge_key, pc->cdata_buf);
111418c2aff7Sartem 			}
111518c2aff7Sartem 			break;
111618c2aff7Sartem 		}
111718c2aff7Sartem 
111818c2aff7Sartem 		case MERGE_TYPE_INT32:
111918c2aff7Sartem 			{
112018c2aff7Sartem 				dbus_int32_t value;
112118c2aff7Sartem 
112218c2aff7Sartem 				/* match integer property */
112318c2aff7Sartem 				value = strtol (pc->cdata_buf, NULL, 0);
112418c2aff7Sartem 
112518c2aff7Sartem 				/** @todo FIXME: Check error condition */
112618c2aff7Sartem 
112718c2aff7Sartem 				hal_device_property_set_int (pc->device,
112818c2aff7Sartem 						     pc->merge_key, value);
112918c2aff7Sartem 				break;
113018c2aff7Sartem 			}
113118c2aff7Sartem 
113218c2aff7Sartem 		case MERGE_TYPE_UINT64:
113318c2aff7Sartem 			{
113418c2aff7Sartem 				dbus_uint64_t value;
113518c2aff7Sartem 
113618c2aff7Sartem 				/* match integer property */
113718c2aff7Sartem 				value = strtoull (pc->cdata_buf, NULL, 0);
113818c2aff7Sartem 
113918c2aff7Sartem 				/** @todo FIXME: Check error condition */
114018c2aff7Sartem 
114118c2aff7Sartem 				hal_device_property_set_uint64 (pc->device,
114218c2aff7Sartem 						     pc->merge_key, value);
114318c2aff7Sartem 				break;
114418c2aff7Sartem 			}
114518c2aff7Sartem 
114618c2aff7Sartem 		case MERGE_TYPE_BOOLEAN:
114718c2aff7Sartem 			hal_device_property_set_bool (pc->device, pc->merge_key,
114818c2aff7Sartem 					      (strcmp (pc->cdata_buf,
114918c2aff7Sartem 						       "true") == 0)
115018c2aff7Sartem 					      ? TRUE : FALSE);
115118c2aff7Sartem 			break;
115218c2aff7Sartem 
115318c2aff7Sartem 		case MERGE_TYPE_DOUBLE:
115418c2aff7Sartem 			hal_device_property_set_double (pc->device, pc->merge_key,
115518c2aff7Sartem 						atof (pc->cdata_buf));
115618c2aff7Sartem 			break;
115718c2aff7Sartem 
115818c2aff7Sartem 		case MERGE_TYPE_COPY_PROPERTY:
115918c2aff7Sartem 		{
116018c2aff7Sartem 			char udi_to_merge_from[256];
116118c2aff7Sartem 			char prop_to_merge[256];
116218c2aff7Sartem 
116318c2aff7Sartem 			/* Resolve key paths like 'someudi/foo/bar/baz:prop.name'
116418c2aff7Sartem 			 * '@prop.here.is.an.udi:with.prop.name'
116518c2aff7Sartem 			 */
116618c2aff7Sartem 			if (!resolve_udiprop_path (pc->cdata_buf,
116718c2aff7Sartem 						   pc->device->udi,
116818c2aff7Sartem 						   udi_to_merge_from, sizeof (udi_to_merge_from),
116918c2aff7Sartem 						   prop_to_merge, sizeof (prop_to_merge))) {
117018c2aff7Sartem 				HAL_ERROR (("Could not resolve keypath '%s' on udi '%s'", pc->cdata_buf, pc->device->udi));
117118c2aff7Sartem 			} else {
117218c2aff7Sartem 				HalDevice *d;
117318c2aff7Sartem 
117418c2aff7Sartem 				d = hal_device_store_find (hald_get_gdl (), udi_to_merge_from);
117518c2aff7Sartem 				if (d == NULL) {
117618c2aff7Sartem 					d = hal_device_store_find (hald_get_tdl (), udi_to_merge_from);
117718c2aff7Sartem 				}
117818c2aff7Sartem 				if (d == NULL) {
117918c2aff7Sartem 					HAL_ERROR (("Could not find device with udi '%s'", udi_to_merge_from));
118018c2aff7Sartem 				} else {
118118c2aff7Sartem 					hal_device_copy_property (d, prop_to_merge, pc->device, pc->merge_key);
118218c2aff7Sartem 				}
118318c2aff7Sartem 			}
118418c2aff7Sartem 			break;
118518c2aff7Sartem 		}
118618c2aff7Sartem 
118718c2aff7Sartem 		default:
118818c2aff7Sartem 			HAL_ERROR (("Unknown merge_type=%d='%c'",
118918c2aff7Sartem 				    pc->merge_type, pc->merge_type));
119018c2aff7Sartem 			break;
119118c2aff7Sartem 		}
119218c2aff7Sartem 	} else if (pc->curelem == CURELEM_APPEND && pc->match_ok &&
119318c2aff7Sartem 		   (hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_STRING ||
119418c2aff7Sartem 		    hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_STRLIST ||
119518c2aff7Sartem 		    hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_INVALID)) {
119618c2aff7Sartem 		char buf[256];
119718c2aff7Sartem 		char buf2[256];
119818c2aff7Sartem 
119918c2aff7Sartem 		/* As soon as we are appending, we have matched the device... */
120018c2aff7Sartem 		pc->device_matched = TRUE;
120118c2aff7Sartem 
120218c2aff7Sartem 		if (pc->merge_type == MERGE_TYPE_STRLIST) {
120318c2aff7Sartem 			hal_device_property_strlist_append (pc->device, pc->merge_key, pc->cdata_buf);
120418c2aff7Sartem 		} else {
120518c2aff7Sartem 			const char *existing_string;
120618c2aff7Sartem 
120718c2aff7Sartem 			switch (pc->merge_type) {
120818c2aff7Sartem 			case MERGE_TYPE_STRING:
120918c2aff7Sartem 				strncpy (buf, pc->cdata_buf, sizeof (buf));
121018c2aff7Sartem 				break;
121118c2aff7Sartem 
121218c2aff7Sartem 			case MERGE_TYPE_COPY_PROPERTY:
121318c2aff7Sartem 				hal_device_property_get_as_string (pc->device, pc->cdata_buf, buf, sizeof (buf));
121418c2aff7Sartem 				break;
121518c2aff7Sartem 
121618c2aff7Sartem 			default:
121718c2aff7Sartem 				HAL_ERROR (("Unknown merge_type=%d='%c'", pc->merge_type, pc->merge_type));
121818c2aff7Sartem 				break;
121918c2aff7Sartem 			}
122018c2aff7Sartem 
122118c2aff7Sartem 			existing_string = hal_device_property_get_string (pc->device, pc->merge_key);
122218c2aff7Sartem 			if (existing_string != NULL) {
122318c2aff7Sartem 				strncpy (buf2, existing_string, sizeof (buf2));
122418c2aff7Sartem 				strncat (buf2, buf, sizeof (buf2) - strlen(buf2));
122518c2aff7Sartem 			} else {
122618c2aff7Sartem 				strncpy (buf2, buf, sizeof (buf2));
122718c2aff7Sartem 			}
122818c2aff7Sartem 			hal_device_property_set_string (pc->device, pc->merge_key, buf2);
122918c2aff7Sartem 		}
123018c2aff7Sartem 	} else if (pc->curelem == CURELEM_PREPEND && pc->match_ok &&
123118c2aff7Sartem 		   (hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_STRING ||
123218c2aff7Sartem 		    hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_STRLIST ||
123318c2aff7Sartem 		    hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_INVALID)) {
123418c2aff7Sartem 		char buf[256];
123518c2aff7Sartem 		char buf2[256];
123618c2aff7Sartem 
123718c2aff7Sartem 		/* As soon as we are prepending, we have matched the device... */
123818c2aff7Sartem 		pc->device_matched = TRUE;
123918c2aff7Sartem 
124018c2aff7Sartem 		if (pc->merge_type == MERGE_TYPE_STRLIST) {
124118c2aff7Sartem 			hal_device_property_strlist_prepend (pc->device, pc->merge_key, pc->cdata_buf);
124218c2aff7Sartem 		} else {
124318c2aff7Sartem 			const char *existing_string;
124418c2aff7Sartem 
124518c2aff7Sartem 			switch (pc->merge_type) {
124618c2aff7Sartem 			case MERGE_TYPE_STRING:
124718c2aff7Sartem 				strncpy (buf, pc->cdata_buf, sizeof (buf));
124818c2aff7Sartem 				break;
124918c2aff7Sartem 
125018c2aff7Sartem 			case MERGE_TYPE_COPY_PROPERTY:
125118c2aff7Sartem 				hal_device_property_get_as_string (pc->device, pc->cdata_buf, buf, sizeof (buf));
125218c2aff7Sartem 				break;
125318c2aff7Sartem 
125418c2aff7Sartem 			default:
125518c2aff7Sartem 				HAL_ERROR (("Unknown merge_type=%d='%c'", pc->merge_type, pc->merge_type));
125618c2aff7Sartem 				break;
125718c2aff7Sartem 			}
125818c2aff7Sartem 
125918c2aff7Sartem 			existing_string = hal_device_property_get_string (pc->device, pc->merge_key);
126018c2aff7Sartem 			if (existing_string != NULL) {
126118c2aff7Sartem 				strncpy (buf2, buf, sizeof (buf2));
126218c2aff7Sartem 				strncat (buf2, existing_string, sizeof (buf2) - strlen(buf2));
126318c2aff7Sartem 			} else {
126418c2aff7Sartem 				strncpy (buf2, buf, sizeof (buf2));
126518c2aff7Sartem 			}
126618c2aff7Sartem 			hal_device_property_set_string (pc->device, pc->merge_key, buf2);
126718c2aff7Sartem 		}
126818c2aff7Sartem 	} else if (pc->curelem == CURELEM_REMOVE && pc->match_ok) {
126918c2aff7Sartem 
127018c2aff7Sartem 		if (pc->merge_type == MERGE_TYPE_STRLIST) {
127118c2aff7Sartem 			/* covers <remove key="foobar" type="strlist">blah</remove> */
127218c2aff7Sartem 			hal_device_property_strlist_remove (pc->device, pc->merge_key, pc->cdata_buf);
127318c2aff7Sartem 		} else {
127418c2aff7Sartem 			/* only allow <remove key="foobar"/>, not <remove key="foobar">blah</remove> */
127518c2aff7Sartem 			if (strlen (pc->cdata_buf) == 0) {
127618c2aff7Sartem 				hal_device_property_remove (pc->device, pc->merge_key);
127718c2aff7Sartem 			}
127818c2aff7Sartem 		}
127918c2aff7Sartem 	} else if (pc->merge_type == MERGE_TYPE_SPAWN) {
128018c2aff7Sartem 		HalDevice *spawned;
128118c2aff7Sartem 
128218c2aff7Sartem 		spawned = hal_device_store_find (hald_get_gdl (), pc->merge_key);
128318c2aff7Sartem 		if (spawned == NULL)
128418c2aff7Sartem 			spawned = hal_device_store_find (hald_get_tdl (), pc->merge_key);
128518c2aff7Sartem 
128618c2aff7Sartem 		if (spawned == NULL) {
128718c2aff7Sartem 			HAL_INFO (("Spawning new device object '%s' caused by <spawn> on udi '%s'",
128818c2aff7Sartem 				   pc->merge_key, pc->device->udi));
128918c2aff7Sartem 
129018c2aff7Sartem 			spawned = hal_device_new ();
129118c2aff7Sartem 			hal_device_property_set_string (spawned, "info.bus", "unknown");
129218c2aff7Sartem 			hal_device_property_set_string (spawned, "info.udi", pc->merge_key);
129318c2aff7Sartem 			hal_device_property_set_string (spawned, "info.parent", pc->device->udi);
129418c2aff7Sartem 			hal_device_set_udi (spawned, pc->merge_key);
129518c2aff7Sartem 
129618c2aff7Sartem 			hal_device_store_add (hald_get_tdl (), spawned);
129718c2aff7Sartem 
129818c2aff7Sartem 			di_search_and_merge (spawned, DEVICE_INFO_TYPE_INFORMATION);
129918c2aff7Sartem 			di_search_and_merge (spawned, DEVICE_INFO_TYPE_POLICY);
130018c2aff7Sartem 
130118c2aff7Sartem 			hal_util_callout_device_add (spawned, spawned_device_callouts_add_done, NULL, NULL);
130218c2aff7Sartem 		}
130318c2aff7Sartem 
130418c2aff7Sartem 	} else if (pc->curelem == CURELEM_CLEAR && pc->match_ok) {
130518c2aff7Sartem 		if (pc->merge_type == MERGE_TYPE_CLEAR) {
130618c2aff7Sartem 			hal_device_property_strlist_clear (pc->device, pc->merge_key);
130718c2aff7Sartem 		}
130818c2aff7Sartem 	}
130918c2aff7Sartem 
131018c2aff7Sartem 
131118c2aff7Sartem 	pc->cdata_buf_len = 0;
131218c2aff7Sartem 	pc->depth--;
131318c2aff7Sartem 
131418c2aff7Sartem 	/* maintain curelem */
131518c2aff7Sartem 	pc->curelem = pc->curelem_stack[pc->depth];
131618c2aff7Sartem 
131718c2aff7Sartem 	/* maintain pc->match_ok */
131818c2aff7Sartem 	if (pc->depth <= pc->match_depth_first_fail)
131918c2aff7Sartem 		pc->match_ok = TRUE;
132018c2aff7Sartem }
132118c2aff7Sartem 
132218c2aff7Sartem /** Called when there is CDATA
132318c2aff7Sartem  *
132418c2aff7Sartem  *  @param  pc                  Parsing context
132518c2aff7Sartem  *  @param  s                   Pointer to data
132618c2aff7Sartem  *  @param  len                 Length of data
132718c2aff7Sartem  */
132818c2aff7Sartem static void
cdata(ParsingContext * pc,const char * s,int len)132918c2aff7Sartem cdata (ParsingContext * pc, const char *s, int len)
133018c2aff7Sartem {
133118c2aff7Sartem 	int bytes_left;
133218c2aff7Sartem 	int bytes_to_copy;
133318c2aff7Sartem 
133418c2aff7Sartem 	if (pc->aborted)
133518c2aff7Sartem 		return;
133618c2aff7Sartem 
133718c2aff7Sartem 	bytes_left = CDATA_BUF_SIZE - pc->cdata_buf_len;
133818c2aff7Sartem 	if (len > bytes_left) {
133918c2aff7Sartem 		HAL_ERROR (("CDATA in element larger than %d",
134018c2aff7Sartem 			    CDATA_BUF_SIZE));
134118c2aff7Sartem 	}
134218c2aff7Sartem 
134318c2aff7Sartem 	bytes_to_copy = len;
134418c2aff7Sartem 	if (bytes_to_copy > bytes_left)
134518c2aff7Sartem 		bytes_to_copy = bytes_left;
134618c2aff7Sartem 
134718c2aff7Sartem 	if (bytes_to_copy > 0)
134818c2aff7Sartem 		memcpy (pc->cdata_buf + pc->cdata_buf_len, s,
134918c2aff7Sartem 			bytes_to_copy);
135018c2aff7Sartem 
135118c2aff7Sartem 	pc->cdata_buf_len += bytes_to_copy;
135218c2aff7Sartem }
135318c2aff7Sartem 
135418c2aff7Sartem 
135518c2aff7Sartem /** Process a device information info file.
135618c2aff7Sartem  *
135718c2aff7Sartem  *  @param  dir                 Directory file resides in
135818c2aff7Sartem  *  @param  filename            File name
135918c2aff7Sartem  *  @param  device              Device to match on
136018c2aff7Sartem  *  @return                     #TRUE if file matched device and information
136118c2aff7Sartem  *                              was merged
136218c2aff7Sartem  */
136318c2aff7Sartem static dbus_bool_t
process_fdi_file(const char * dir,const char * filename,HalDevice * device)136418c2aff7Sartem process_fdi_file (const char *dir, const char *filename,
136518c2aff7Sartem 		  HalDevice * device)
136618c2aff7Sartem {
136718c2aff7Sartem 	int rc;
136818c2aff7Sartem 	char buf[512];
136918c2aff7Sartem 	FILE *file;
137018c2aff7Sartem 	int filesize;
137118c2aff7Sartem 	char *filebuf;
137218c2aff7Sartem 	dbus_bool_t device_matched;
137318c2aff7Sartem 	XML_Parser parser;
137418c2aff7Sartem 	ParsingContext *parsing_context;
137518c2aff7Sartem 
137618c2aff7Sartem 	file = NULL;
137718c2aff7Sartem 	filebuf = NULL;
137818c2aff7Sartem 	parser = NULL;
137918c2aff7Sartem 	parsing_context = NULL;
138018c2aff7Sartem 
138118c2aff7Sartem 	device_matched = FALSE;
138218c2aff7Sartem 
138318c2aff7Sartem 	snprintf (buf, sizeof (buf), "%s/%s", dir, filename);
138418c2aff7Sartem 
138518c2aff7Sartem 	/*HAL_INFO(("analyzing file %s", buf));*/
138618c2aff7Sartem 
138718c2aff7Sartem 	/* open file and read it into a buffer; it's a small file... */
138818c2aff7Sartem 	file = fopen (buf, "r");
138918c2aff7Sartem 	if (file == NULL) {
139018c2aff7Sartem 		HAL_ERROR (("Could not open file %s", buf));
139118c2aff7Sartem 		goto out;
139218c2aff7Sartem 	}
139318c2aff7Sartem 
139418c2aff7Sartem 	fseek (file, 0L, SEEK_END);
139518c2aff7Sartem 	filesize = (int) ftell (file);
139618c2aff7Sartem 	rewind (file);
139718c2aff7Sartem 	filebuf = (char *) malloc (filesize);
139818c2aff7Sartem 	if (filebuf == NULL) {
139918c2aff7Sartem 		HAL_ERROR (("Could not allocate %d bytes for file %s", filesize, buf));
140018c2aff7Sartem 		goto out;
140118c2aff7Sartem 	}
1402*d9e525a8SToomas Soome 	(void) fread (filebuf, sizeof (char), filesize, file);
140318c2aff7Sartem 
140418c2aff7Sartem 	/* initialize parsing context */
140518c2aff7Sartem 	parsing_context =
140618c2aff7Sartem 	    (ParsingContext *) malloc (sizeof (ParsingContext));
140718c2aff7Sartem 	if (parsing_context == NULL) {
140818c2aff7Sartem 		HAL_ERROR (("Could not allocate parsing context"));
140918c2aff7Sartem 		goto out;
141018c2aff7Sartem 	}
141118c2aff7Sartem 
141218c2aff7Sartem 	/* TODO: reuse parser
141318c2aff7Sartem 	 */
141418c2aff7Sartem 	parser = XML_ParserCreate (NULL);
141518c2aff7Sartem 	if (parser == NULL) {
141618c2aff7Sartem 		HAL_ERROR (("Could not allocate XML parser"));
141718c2aff7Sartem 		goto out;
141818c2aff7Sartem 	}
141918c2aff7Sartem 
142018c2aff7Sartem 	parsing_context->depth = 0;
142118c2aff7Sartem 	parsing_context->device_matched = FALSE;
142218c2aff7Sartem 	parsing_context->match_ok = TRUE;
142318c2aff7Sartem 	parsing_context->curelem = CURELEM_UNKNOWN;
142418c2aff7Sartem 	parsing_context->aborted = FALSE;
142518c2aff7Sartem 	parsing_context->file = buf;
142618c2aff7Sartem 	parsing_context->parser = parser;
142718c2aff7Sartem 	parsing_context->device = device;
142818c2aff7Sartem 	parsing_context->match_depth_first_fail = -1;
142918c2aff7Sartem 
143018c2aff7Sartem 	XML_SetElementHandler (parser,
143118c2aff7Sartem 			       (XML_StartElementHandler) start,
143218c2aff7Sartem 			       (XML_EndElementHandler) end);
143318c2aff7Sartem 	XML_SetCharacterDataHandler (parser,
143418c2aff7Sartem 				     (XML_CharacterDataHandler) cdata);
143518c2aff7Sartem 	XML_SetUserData (parser, parsing_context);
143618c2aff7Sartem 
143718c2aff7Sartem 	rc = XML_Parse (parser, filebuf, filesize, 1);
143818c2aff7Sartem 	/*printf("XML_Parse rc=%d\r\n", rc); */
143918c2aff7Sartem 
144018c2aff7Sartem 	if (rc == 0) {
144118c2aff7Sartem 		/* error parsing document */
144218c2aff7Sartem 		HAL_ERROR (("Error parsing XML document %s at line %d, "
144318c2aff7Sartem 			    "column %d : %s",
144418c2aff7Sartem 			    buf,
144518c2aff7Sartem 			    XML_GetCurrentLineNumber (parser),
144618c2aff7Sartem 			    XML_GetCurrentColumnNumber (parser),
144718c2aff7Sartem 			    XML_ErrorString (XML_GetErrorCode (parser))));
144818c2aff7Sartem 		device_matched = FALSE;
144918c2aff7Sartem 	} else {
145018c2aff7Sartem 		/* document parsed ok */
145118c2aff7Sartem 		device_matched = parsing_context->device_matched;
145218c2aff7Sartem 	}
145318c2aff7Sartem 
145418c2aff7Sartem out:
145518c2aff7Sartem 	if (filebuf != NULL)
145618c2aff7Sartem 		free (filebuf);
145718c2aff7Sartem 	if (file != NULL)
145818c2aff7Sartem 		fclose (file);
145918c2aff7Sartem 	if (parser != NULL)
146018c2aff7Sartem 		XML_ParserFree (parser);
146118c2aff7Sartem 	if (parsing_context != NULL)
146218c2aff7Sartem 		free (parsing_context);
146318c2aff7Sartem 
146418c2aff7Sartem 	return device_matched;
146518c2aff7Sartem }
146618c2aff7Sartem 
146718c2aff7Sartem 
146818c2aff7Sartem 
146918c2aff7Sartem static int
147018c2aff7Sartem #ifdef __GLIBC__
my_alphasort(const void * a,const void * b)147118c2aff7Sartem my_alphasort(const void *a, const void *b)
147218c2aff7Sartem #else
147318c2aff7Sartem my_alphasort(const struct dirent **a, const struct dirent **b)
147418c2aff7Sartem #endif
147518c2aff7Sartem {
147618c2aff7Sartem 	return -alphasort (a, b);
147718c2aff7Sartem }
147818c2aff7Sartem 
147918c2aff7Sartem 
148018c2aff7Sartem /** Scan all directories and subdirectories in the given directory and
148118c2aff7Sartem  *  process each *.fdi file
148218c2aff7Sartem  *
148318c2aff7Sartem  *  @param  d                   Device to merge information into
148418c2aff7Sartem  *  @return                     #TRUE if information was merged
148518c2aff7Sartem  */
148618c2aff7Sartem static dbus_bool_t
scan_fdi_files(const char * dir,HalDevice * d)148718c2aff7Sartem scan_fdi_files (const char *dir, HalDevice * d)
148818c2aff7Sartem {
148918c2aff7Sartem 	int i;
149018c2aff7Sartem 	int num_entries;
149118c2aff7Sartem 	dbus_bool_t found_fdi_file;
149218c2aff7Sartem 	struct dirent **name_list;
149318c2aff7Sartem 
149418c2aff7Sartem 	found_fdi_file = 0;
149518c2aff7Sartem 
149618c2aff7Sartem 	/*HAL_INFO(("scan_fdi_files: Processing dir '%s'", dir));*/
149718c2aff7Sartem 
149818c2aff7Sartem 	num_entries = scandir (dir, &name_list, 0, my_alphasort);
149918c2aff7Sartem 	if (num_entries == -1) {
150018c2aff7Sartem 		return FALSE;
150118c2aff7Sartem 	}
150218c2aff7Sartem 
150318c2aff7Sartem 	for (i = num_entries - 1; i >= 0; i--) {
150418c2aff7Sartem 		int len;
150518c2aff7Sartem 		char *filename;
150618c2aff7Sartem 		gchar *full_path;
150718c2aff7Sartem 
150818c2aff7Sartem 		filename = name_list[i]->d_name;
150918c2aff7Sartem 		len = strlen (filename);
151018c2aff7Sartem 
151118c2aff7Sartem 		full_path = g_strdup_printf ("%s/%s", dir, filename);
151218c2aff7Sartem 		/*HAL_INFO (("Full path = %s", full_path));*/
151318c2aff7Sartem 
151418c2aff7Sartem 		/* Mmm, d_type can be DT_UNKNOWN, use glib to determine
151518c2aff7Sartem 		 * the type
151618c2aff7Sartem 		 */
151718c2aff7Sartem 		if (g_file_test (full_path, (G_FILE_TEST_IS_REGULAR))) {
151818c2aff7Sartem 			/* regular file */
151918c2aff7Sartem 
152018c2aff7Sartem 			if (len >= 5 &&
152118c2aff7Sartem 			    filename[len - 4] == '.' &&
152218c2aff7Sartem 			    filename[len - 3] == 'f' &&
152318c2aff7Sartem 			    filename[len - 2] == 'd' &&
152418c2aff7Sartem 			    filename[len - 1] == 'i') {
152518c2aff7Sartem 				/*HAL_INFO (("scan_fdi_files: Processing file '%s'", filename));*/
152618c2aff7Sartem 				found_fdi_file = process_fdi_file (dir, filename, d);
152718c2aff7Sartem 				if (found_fdi_file) {
152818c2aff7Sartem 					HAL_INFO (("*** Matched file %s/%s", dir, filename));
152918c2aff7Sartem 					/*break;*/
153018c2aff7Sartem 				}
153118c2aff7Sartem 			}
153218c2aff7Sartem 
153318c2aff7Sartem 		} else if (g_file_test (full_path, (G_FILE_TEST_IS_DIR))
153418c2aff7Sartem 			   && strcmp (filename, ".") != 0
153518c2aff7Sartem 			   && strcmp (filename, "..") != 0) {
153618c2aff7Sartem 			int num_bytes;
153718c2aff7Sartem 			char *dirname;
153818c2aff7Sartem 
153918c2aff7Sartem 			/* Directory; do the recursion thingy but not
154018c2aff7Sartem 			 * for . and ..
154118c2aff7Sartem 			 */
154218c2aff7Sartem 
154318c2aff7Sartem 			num_bytes = len + strlen (dir) + 1 + 1;
154418c2aff7Sartem 			dirname = (char *) malloc (num_bytes);
154518c2aff7Sartem 			if (dirname == NULL) {
154618c2aff7Sartem 				HAL_ERROR (("couldn't allocated %d bytes",
154718c2aff7Sartem 					    num_bytes));
154818c2aff7Sartem 				break;
154918c2aff7Sartem 			}
155018c2aff7Sartem 
155118c2aff7Sartem 			snprintf (dirname, num_bytes, "%s/%s", dir,
155218c2aff7Sartem 				  filename);
155318c2aff7Sartem 			found_fdi_file = scan_fdi_files (dirname, d);
155418c2aff7Sartem 			free (dirname);
155518c2aff7Sartem 			/*
155618c2aff7Sartem 			if (found_fdi_file)
155718c2aff7Sartem 				break;
155818c2aff7Sartem 			*/
155918c2aff7Sartem 		}
156018c2aff7Sartem 
156118c2aff7Sartem 		g_free (full_path);
156218c2aff7Sartem 
156318c2aff7Sartem 		free (name_list[i]);
156418c2aff7Sartem 	}
156518c2aff7Sartem 
156618c2aff7Sartem 	for (; i >= 0; i--) {
156718c2aff7Sartem 		free (name_list[i]);
156818c2aff7Sartem 	}
156918c2aff7Sartem 
157018c2aff7Sartem 	free (name_list);
157118c2aff7Sartem 
157218c2aff7Sartem 	return found_fdi_file;
157318c2aff7Sartem }
157418c2aff7Sartem 
157518c2aff7Sartem /** Search the device info file repository for a .fdi file to merge
157618c2aff7Sartem  *  more information into the device object.
157718c2aff7Sartem  *
157818c2aff7Sartem  *  @param  d                   Device to merge information into
157918c2aff7Sartem  *  @return                     #TRUE if information was merged
158018c2aff7Sartem  */
158118c2aff7Sartem dbus_bool_t
di_search_and_merge(HalDevice * d,DeviceInfoType type)158218c2aff7Sartem di_search_and_merge (HalDevice *d, DeviceInfoType type)
158318c2aff7Sartem {
158418c2aff7Sartem 	static gboolean have_checked_hal_fdi_source = FALSE;
158518c2aff7Sartem 	static char *hal_fdi_source_preprobe = NULL;
158618c2aff7Sartem 	static char *hal_fdi_source_information = NULL;
158718c2aff7Sartem 	static char *hal_fdi_source_policy = NULL;
158818c2aff7Sartem 	dbus_bool_t ret;
158918c2aff7Sartem 	char *s1;
159018c2aff7Sartem 	char *s2;
15911c755acbSAlexander Pyhalov 	char *s3;
159218c2aff7Sartem 
159318c2aff7Sartem 	ret = FALSE;
159418c2aff7Sartem 
159518c2aff7Sartem 	if (!have_checked_hal_fdi_source) {
159618c2aff7Sartem 		hal_fdi_source_preprobe    = getenv ("HAL_FDI_SOURCE_PREPROBE");
159718c2aff7Sartem 		hal_fdi_source_information = getenv ("HAL_FDI_SOURCE_INFORMATION");
159818c2aff7Sartem 		hal_fdi_source_policy      = getenv ("HAL_FDI_SOURCE_POLICY");
159918c2aff7Sartem 		have_checked_hal_fdi_source = TRUE;
160018c2aff7Sartem 	}
160118c2aff7Sartem 
160218c2aff7Sartem 	switch (type) {
160318c2aff7Sartem 	case DEVICE_INFO_TYPE_PREPROBE:
160418c2aff7Sartem 		if (hal_fdi_source_preprobe != NULL) {
160518c2aff7Sartem 			s1 = hal_fdi_source_preprobe;
160618c2aff7Sartem 			s2 = NULL;
16071c755acbSAlexander Pyhalov 			s3 = NULL;
160818c2aff7Sartem 		} else {
16091c755acbSAlexander Pyhalov 			s1 = PACKAGE_OLD_DATA_DIR "/hal/fdi/preprobe";
16101c755acbSAlexander Pyhalov 			s2 = PACKAGE_DATA_DIR "/hal/fdi/preprobe";
16111c755acbSAlexander Pyhalov 			s3 = PACKAGE_SYSCONF_DIR "/hal/fdi/preprobe";
161218c2aff7Sartem 		}
161318c2aff7Sartem 		break;
161418c2aff7Sartem 
161518c2aff7Sartem 	case DEVICE_INFO_TYPE_INFORMATION:
161618c2aff7Sartem 		if (hal_fdi_source_information != NULL) {
161718c2aff7Sartem 			s1 = hal_fdi_source_information;
161818c2aff7Sartem 			s2 = NULL;
16191c755acbSAlexander Pyhalov 			s3 = NULL;
162018c2aff7Sartem 		} else {
16211c755acbSAlexander Pyhalov 			s1 = PACKAGE_OLD_DATA_DIR "/hal/fdi/information";
16221c755acbSAlexander Pyhalov 			s2 = PACKAGE_DATA_DIR "/hal/fdi/information";
16231c755acbSAlexander Pyhalov 			s3 = PACKAGE_SYSCONF_DIR "/hal/fdi/information";
162418c2aff7Sartem 		}
162518c2aff7Sartem 		break;
162618c2aff7Sartem 
162718c2aff7Sartem 	case DEVICE_INFO_TYPE_POLICY:
162818c2aff7Sartem 		if (hal_fdi_source_policy != NULL) {
162918c2aff7Sartem 			s1 = hal_fdi_source_policy;
163018c2aff7Sartem 			s2 = NULL;
16311c755acbSAlexander Pyhalov 			s3 = NULL;
163218c2aff7Sartem 		} else {
16331c755acbSAlexander Pyhalov 			s1 = PACKAGE_OLD_DATA_DIR "/hal/fdi/policy";
16341c755acbSAlexander Pyhalov 			s2 = PACKAGE_DATA_DIR "/hal/fdi/policy";
16351c755acbSAlexander Pyhalov 			s3 = PACKAGE_SYSCONF_DIR "/hal/fdi/policy";
163618c2aff7Sartem 		}
163718c2aff7Sartem 		break;
163818c2aff7Sartem 
163918c2aff7Sartem 	default:
164018c2aff7Sartem 		s1 = NULL;
164118c2aff7Sartem 		s2 = NULL;
16421c755acbSAlexander Pyhalov 		s3 = NULL;
164318c2aff7Sartem 		HAL_ERROR (("Bogus device information type %d", type));
164418c2aff7Sartem 		break;
164518c2aff7Sartem 	}
164618c2aff7Sartem 
164718c2aff7Sartem 	if (s1 != NULL)
164818c2aff7Sartem 		ret = scan_fdi_files (s1, d) || ret;
164918c2aff7Sartem 	if (s2 != NULL)
165018c2aff7Sartem 		ret = scan_fdi_files (s2, d) || ret;
16511c755acbSAlexander Pyhalov 	if (s3 != NULL)
16521c755acbSAlexander Pyhalov 		ret = scan_fdi_files (s3, d) || ret;
165318c2aff7Sartem 
165418c2aff7Sartem 	return ret;
165518c2aff7Sartem }
165618c2aff7Sartem 
165718c2aff7Sartem /** @} */
1658