xref: /titanic_50/usr/src/cmd/hal/hald/device_info.c (revision 18c2aff776a775d34a4c9893a4c72e0434d68e36)
1*18c2aff7Sartem /***************************************************************************
2*18c2aff7Sartem  * CVSID: $Id$
3*18c2aff7Sartem  *
4*18c2aff7Sartem  * device_store.c : Search for .fdi files and merge on match
5*18c2aff7Sartem  *
6*18c2aff7Sartem  * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
7*18c2aff7Sartem  *
8*18c2aff7Sartem  * Licensed under the Academic Free License version 2.1
9*18c2aff7Sartem  *
10*18c2aff7Sartem  * This program is free software; you can redistribute it and/or modify
11*18c2aff7Sartem  * it under the terms of the GNU General Public License as published by
12*18c2aff7Sartem  * the Free Software Foundation; either version 2 of the License, or
13*18c2aff7Sartem  * (at your option) any later version.
14*18c2aff7Sartem  *
15*18c2aff7Sartem  * This program is distributed in the hope that it will be useful,
16*18c2aff7Sartem  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*18c2aff7Sartem  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*18c2aff7Sartem  * GNU General Public License for more details.
19*18c2aff7Sartem  *
20*18c2aff7Sartem  * You should have received a copy of the GNU General Public License
21*18c2aff7Sartem  * along with this program; if not, write to the Free Software
22*18c2aff7Sartem  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
23*18c2aff7Sartem  *
24*18c2aff7Sartem  **************************************************************************/
25*18c2aff7Sartem 
26*18c2aff7Sartem #ifdef HAVE_CONFIG_H
27*18c2aff7Sartem #  include <config.h>
28*18c2aff7Sartem #endif
29*18c2aff7Sartem 
30*18c2aff7Sartem #include <stdio.h>
31*18c2aff7Sartem #include <stdlib.h>
32*18c2aff7Sartem #include <string.h>
33*18c2aff7Sartem #include <dirent.h>
34*18c2aff7Sartem #include <expat.h>
35*18c2aff7Sartem #include <assert.h>
36*18c2aff7Sartem #include <dbus/dbus.h>
37*18c2aff7Sartem #include <dbus/dbus-glib.h>
38*18c2aff7Sartem #include <math.h>
39*18c2aff7Sartem 
40*18c2aff7Sartem #include "hald.h"
41*18c2aff7Sartem #include "logger.h"
42*18c2aff7Sartem #include "device_info.h"
43*18c2aff7Sartem #include "device_store.h"
44*18c2aff7Sartem #include "util.h"
45*18c2aff7Sartem 
46*18c2aff7Sartem /**
47*18c2aff7Sartem  * @defgroup DeviceInfo Device Info File Parsing
48*18c2aff7Sartem  * @ingroup HalDaemon
49*18c2aff7Sartem  * @brief Parsing of device info files
50*18c2aff7Sartem  * @{
51*18c2aff7Sartem  */
52*18c2aff7Sartem 
53*18c2aff7Sartem 
54*18c2aff7Sartem /** Maximum nesting depth */
55*18c2aff7Sartem #define MAX_DEPTH 32
56*18c2aff7Sartem 
57*18c2aff7Sartem /** Maximum amount of CDATA */
58*18c2aff7Sartem #define CDATA_BUF_SIZE  1024
59*18c2aff7Sartem 
60*18c2aff7Sartem /** Max length of property key */
61*18c2aff7Sartem #define MAX_KEY_SIZE 128
62*18c2aff7Sartem 
63*18c2aff7Sartem /** Possible elements the parser can process */
64*18c2aff7Sartem enum {
65*18c2aff7Sartem 	/** Not processing a known tag */
66*18c2aff7Sartem 	CURELEM_UNKNOWN = -1,
67*18c2aff7Sartem 
68*18c2aff7Sartem 	/** Processing a deviceinfo element */
69*18c2aff7Sartem 	CURELEM_DEVICE_INFO = 0,
70*18c2aff7Sartem 
71*18c2aff7Sartem 	/** Processing a device element */
72*18c2aff7Sartem 	CURELEM_DEVICE = 1,
73*18c2aff7Sartem 
74*18c2aff7Sartem 	/** Processing a match element */
75*18c2aff7Sartem 	CURELEM_MATCH = 2,
76*18c2aff7Sartem 
77*18c2aff7Sartem 	/** Processing a merge element */
78*18c2aff7Sartem 	CURELEM_MERGE = 3,
79*18c2aff7Sartem 
80*18c2aff7Sartem 	/** Processing an append element */
81*18c2aff7Sartem 	CURELEM_APPEND = 4,
82*18c2aff7Sartem 
83*18c2aff7Sartem 	/** Processing a prepend element */
84*18c2aff7Sartem 	CURELEM_PREPEND = 5,
85*18c2aff7Sartem 
86*18c2aff7Sartem 	/** Processing a remove element */
87*18c2aff7Sartem 	CURELEM_REMOVE = 6,
88*18c2aff7Sartem 
89*18c2aff7Sartem 	/** Processing a clear element */
90*18c2aff7Sartem 	CURELEM_CLEAR = 7,
91*18c2aff7Sartem 
92*18c2aff7Sartem 	/** Processing a spawn element */
93*18c2aff7Sartem 	CURELEM_SPAWN = 8
94*18c2aff7Sartem };
95*18c2aff7Sartem 
96*18c2aff7Sartem /** What and how to merge */
97*18c2aff7Sartem enum {
98*18c2aff7Sartem 	MERGE_TYPE_UNKNOWN       = 0,
99*18c2aff7Sartem 	MERGE_TYPE_STRING        = 1,
100*18c2aff7Sartem 	MERGE_TYPE_BOOLEAN       = 2,
101*18c2aff7Sartem 	MERGE_TYPE_INT32         = 3,
102*18c2aff7Sartem 	MERGE_TYPE_UINT64        = 4,
103*18c2aff7Sartem 	MERGE_TYPE_DOUBLE        = 5,
104*18c2aff7Sartem 	MERGE_TYPE_COPY_PROPERTY = 6,
105*18c2aff7Sartem 	MERGE_TYPE_STRLIST       = 7,
106*18c2aff7Sartem 	MERGE_TYPE_REMOVE        = 8,
107*18c2aff7Sartem 	MERGE_TYPE_CLEAR         = 9,
108*18c2aff7Sartem 	MERGE_TYPE_SPAWN         = 10
109*18c2aff7Sartem };
110*18c2aff7Sartem 
111*18c2aff7Sartem /** Parsing Context
112*18c2aff7Sartem  */
113*18c2aff7Sartem typedef struct {
114*18c2aff7Sartem 	/** Name of file being parsed */
115*18c2aff7Sartem 	char *file;
116*18c2aff7Sartem 
117*18c2aff7Sartem 	/** Parser object */
118*18c2aff7Sartem 	XML_Parser parser;
119*18c2aff7Sartem 
120*18c2aff7Sartem 	/** Device we are trying to match*/
121*18c2aff7Sartem 	HalDevice *device;
122*18c2aff7Sartem 
123*18c2aff7Sartem 	/** Buffer to put CDATA in */
124*18c2aff7Sartem 	char cdata_buf[CDATA_BUF_SIZE];
125*18c2aff7Sartem 
126*18c2aff7Sartem 	/** Current length of CDATA buffer */
127*18c2aff7Sartem 	int cdata_buf_len;
128*18c2aff7Sartem 
129*18c2aff7Sartem 	/** Current depth we are parsing at */
130*18c2aff7Sartem 	int depth;
131*18c2aff7Sartem 
132*18c2aff7Sartem 	/** Element currently being processed */
133*18c2aff7Sartem 	int curelem;
134*18c2aff7Sartem 
135*18c2aff7Sartem 	/** Stack of elements being processed */
136*18c2aff7Sartem 	int curelem_stack[MAX_DEPTH];
137*18c2aff7Sartem 
138*18c2aff7Sartem 	/** #TRUE if parsing of document have been aborted */
139*18c2aff7Sartem 	dbus_bool_t aborted;
140*18c2aff7Sartem 
141*18c2aff7Sartem 
142*18c2aff7Sartem 	/** Depth of match-fail */
143*18c2aff7Sartem 	int match_depth_first_fail;
144*18c2aff7Sartem 
145*18c2aff7Sartem 	/** #TRUE if all matches on prior depths have been OK */
146*18c2aff7Sartem 	dbus_bool_t match_ok;
147*18c2aff7Sartem 
148*18c2aff7Sartem 
149*18c2aff7Sartem 
150*18c2aff7Sartem 	/** When merging, the key to store the value in */
151*18c2aff7Sartem 	char merge_key[MAX_KEY_SIZE];
152*18c2aff7Sartem 
153*18c2aff7Sartem 	/** Type to merge*/
154*18c2aff7Sartem 	int merge_type;
155*18c2aff7Sartem 
156*18c2aff7Sartem 	/** Set to #TRUE if a device is matched */
157*18c2aff7Sartem 	dbus_bool_t device_matched;
158*18c2aff7Sartem 
159*18c2aff7Sartem } ParsingContext;
160*18c2aff7Sartem 
161*18c2aff7Sartem /** Resolve a udi-property path as used in .fdi files.
162*18c2aff7Sartem  *
163*18c2aff7Sartem  *  Examples of udi-property paths:
164*18c2aff7Sartem  *
165*18c2aff7Sartem  *   info.udi
166*18c2aff7Sartem  *   /org/freedesktop/Hal/devices/computer:kernel.name
167*18c2aff7Sartem  *   @block.storage_device:storage.bus
168*18c2aff7Sartem  *   @block.storage_device:@storage.physical_device:ide.channel
169*18c2aff7Sartem  *
170*18c2aff7Sartem  *  @param  source_udi          UDI of source device
171*18c2aff7Sartem  *  @param  path                The given path
172*18c2aff7Sartem  *  @param  udi_result          Where to store the resulting UDI
173*18c2aff7Sartem  *  @param  udi_result_size     Size of UDI string
174*18c2aff7Sartem  *  @param  prop_result         Where to store the resulting property name
175*18c2aff7Sartem  *  @param  prop_result_size    Size of property string
176*18c2aff7Sartem  *  @return                     TRUE if and only if the path resolved.
177*18c2aff7Sartem  */
178*18c2aff7Sartem 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)179*18c2aff7Sartem resolve_udiprop_path (const char *path, const char *source_udi,
180*18c2aff7Sartem 		      char *udi_result, size_t udi_result_size,
181*18c2aff7Sartem 		      char *prop_result, size_t prop_result_size)
182*18c2aff7Sartem {
183*18c2aff7Sartem 	int i;
184*18c2aff7Sartem 	gchar **tokens = NULL;
185*18c2aff7Sartem 	gboolean rc;
186*18c2aff7Sartem 
187*18c2aff7Sartem 	rc = FALSE;
188*18c2aff7Sartem 
189*18c2aff7Sartem 	/*HAL_INFO (("Looking at '%s' for udi='%s'", path, source_udi));*/
190*18c2aff7Sartem 
191*18c2aff7Sartem 	/* Split up path into ':' tokens */
192*18c2aff7Sartem 	tokens = g_strsplit (path, ":", 64);
193*18c2aff7Sartem 
194*18c2aff7Sartem 	/* Detect trivial property access, e.g. path='foo.bar'   */
195*18c2aff7Sartem 	if (tokens == NULL || tokens[0] == NULL || tokens[1] == NULL) {
196*18c2aff7Sartem 		strncpy (udi_result, source_udi, udi_result_size);
197*18c2aff7Sartem 		strncpy (prop_result, path, prop_result_size);
198*18c2aff7Sartem 		rc = TRUE;
199*18c2aff7Sartem 		goto out;
200*18c2aff7Sartem 	}
201*18c2aff7Sartem 
202*18c2aff7Sartem 	/* Start with the source udi */
203*18c2aff7Sartem 	strncpy (udi_result, source_udi, udi_result_size);
204*18c2aff7Sartem 
205*18c2aff7Sartem 	for (i = 0; tokens[i] != NULL; i++) {
206*18c2aff7Sartem 		HalDevice *d;
207*18c2aff7Sartem 		gchar *curtoken;
208*18c2aff7Sartem 
209*18c2aff7Sartem 		/*HAL_INFO (("tokens[%d] = '%s'", i, tokens[i]));*/
210*18c2aff7Sartem 
211*18c2aff7Sartem 		d = hal_device_store_find (hald_get_gdl (), udi_result);
212*18c2aff7Sartem 		if (d == NULL)
213*18c2aff7Sartem 			d = hal_device_store_find (hald_get_tdl (), udi_result);
214*18c2aff7Sartem 		if (d == NULL)
215*18c2aff7Sartem 			goto out;
216*18c2aff7Sartem 
217*18c2aff7Sartem 		curtoken = tokens[i];
218*18c2aff7Sartem 
219*18c2aff7Sartem 		/* process all but the last tokens as UDI paths */
220*18c2aff7Sartem 		if (tokens[i+1] == NULL) {
221*18c2aff7Sartem 			strncpy (prop_result, curtoken, prop_result_size);
222*18c2aff7Sartem 			rc = TRUE;
223*18c2aff7Sartem 			goto out;
224*18c2aff7Sartem 		}
225*18c2aff7Sartem 
226*18c2aff7Sartem 
227*18c2aff7Sartem 		/* Check for indirection */
228*18c2aff7Sartem 		if (curtoken[0] == '@') {
229*18c2aff7Sartem 			const char *udiprop;
230*18c2aff7Sartem 			const char *newudi;
231*18c2aff7Sartem 
232*18c2aff7Sartem 			udiprop = curtoken + 1;
233*18c2aff7Sartem 
234*18c2aff7Sartem 			newudi = hal_device_property_get_string (d, udiprop);
235*18c2aff7Sartem 			if (newudi == NULL)
236*18c2aff7Sartem 				goto out;
237*18c2aff7Sartem 
238*18c2aff7Sartem 			/*HAL_INFO (("new_udi = '%s' (from indirection)", newudi));*/
239*18c2aff7Sartem 
240*18c2aff7Sartem 			strncpy (udi_result, newudi, udi_result_size);
241*18c2aff7Sartem 		} else {
242*18c2aff7Sartem 			/*HAL_INFO (("new_udi = '%s'", curtoken));*/
243*18c2aff7Sartem 			strncpy (udi_result, curtoken, udi_result_size);
244*18c2aff7Sartem 		}
245*18c2aff7Sartem 
246*18c2aff7Sartem 	}
247*18c2aff7Sartem 
248*18c2aff7Sartem out:
249*18c2aff7Sartem 
250*18c2aff7Sartem /*
251*18c2aff7Sartem 	HAL_INFO (("success     = '%s'", rc ? "yes" : "no"));
252*18c2aff7Sartem 	HAL_INFO (("udi_result  = '%s'", udi_result));
253*18c2aff7Sartem 	HAL_INFO (("prop_result = '%s'", prop_result));
254*18c2aff7Sartem */
255*18c2aff7Sartem 
256*18c2aff7Sartem 	g_strfreev (tokens);
257*18c2aff7Sartem 
258*18c2aff7Sartem 	return rc;
259*18c2aff7Sartem }
260*18c2aff7Sartem 
261*18c2aff7Sartem /* Compare the value of a property on a hal device object against a string value
262*18c2aff7Sartem  * and return the result. Note that this works for several types, e.g. both strings
263*18c2aff7Sartem  * and integers - in the latter case the given right side string will be interpreted
264*18c2aff7Sartem  * as a number.
265*18c2aff7Sartem  *
266*18c2aff7Sartem  * The comparison might not make sense if you are comparing a property which is an integer
267*18c2aff7Sartem  * against a string in which case this function returns FALSE. Also, if the property doesn't
268*18c2aff7Sartem  * exist this function will also return FALSE.
269*18c2aff7Sartem  *
270*18c2aff7Sartem  * @param  d                    hal device object
271*18c2aff7Sartem  * @param  key                  Key of the property to compare
272*18c2aff7Sartem  * @param  right_side           Value to compare against
273*18c2aff7Sartem  * @param  result               Pointer to where to store result
274*18c2aff7Sartem  * @return                      TRUE if, and only if, the comparison could take place
275*18c2aff7Sartem  */
276*18c2aff7Sartem static gboolean
match_compare_property(HalDevice * d,const char * key,const char * right_side,dbus_int64_t * result)277*18c2aff7Sartem match_compare_property (HalDevice *d, const char *key, const char *right_side, dbus_int64_t *result)
278*18c2aff7Sartem {
279*18c2aff7Sartem 	gboolean rc;
280*18c2aff7Sartem 	int proptype;
281*18c2aff7Sartem 
282*18c2aff7Sartem 	rc = FALSE;
283*18c2aff7Sartem 
284*18c2aff7Sartem 	if (!hal_device_has_property (d, key))
285*18c2aff7Sartem 		goto out;
286*18c2aff7Sartem 
287*18c2aff7Sartem 	proptype = hal_device_property_get_type (d, key);
288*18c2aff7Sartem 	switch (proptype) {
289*18c2aff7Sartem 	case HAL_PROPERTY_TYPE_STRING:
290*18c2aff7Sartem 		*result = (dbus_int64_t) strcmp (hal_device_property_get_string (d, key), right_side);
291*18c2aff7Sartem 		rc = TRUE;
292*18c2aff7Sartem 		break;
293*18c2aff7Sartem 
294*18c2aff7Sartem 	case HAL_PROPERTY_TYPE_INT32:
295*18c2aff7Sartem 		*result = ((dbus_int64_t) hal_device_property_get_int (d, key)) - strtoll (right_side, NULL, 0);
296*18c2aff7Sartem 		rc = TRUE;
297*18c2aff7Sartem 		break;
298*18c2aff7Sartem 
299*18c2aff7Sartem 	case HAL_PROPERTY_TYPE_UINT64:
300*18c2aff7Sartem 		*result = ((dbus_int64_t) hal_device_property_get_uint64 (d, key)) - ((dbus_int64_t) strtoll (right_side, NULL, 0));
301*18c2aff7Sartem 		rc = TRUE;
302*18c2aff7Sartem 		break;
303*18c2aff7Sartem 
304*18c2aff7Sartem 	case HAL_PROPERTY_TYPE_DOUBLE:
305*18c2aff7Sartem 		*result = (dbus_int64_t) ceil (hal_device_property_get_double (d, key) - atof (right_side));
306*18c2aff7Sartem 		rc = TRUE;
307*18c2aff7Sartem 		break;
308*18c2aff7Sartem 
309*18c2aff7Sartem 	default:
310*18c2aff7Sartem 		/* explicit fallthrough */
311*18c2aff7Sartem 	case HAL_PROPERTY_TYPE_BOOLEAN:
312*18c2aff7Sartem 		/* explicit blank since this doesn't make sense */
313*18c2aff7Sartem 		break;
314*18c2aff7Sartem 	}
315*18c2aff7Sartem 
316*18c2aff7Sartem out:
317*18c2aff7Sartem 	return rc;
318*18c2aff7Sartem }
319*18c2aff7Sartem 
320*18c2aff7Sartem /** Called when the match element begins.
321*18c2aff7Sartem  *
322*18c2aff7Sartem  *  @param  pc                  Parsing context
323*18c2aff7Sartem  *  @param  attr                Attribute key/value pairs
324*18c2aff7Sartem  *  @return                     #FALSE if the device in question didn't
325*18c2aff7Sartem  *                              match the data in the attributes
326*18c2aff7Sartem  */
327*18c2aff7Sartem static dbus_bool_t
handle_match(ParsingContext * pc,const char ** attr)328*18c2aff7Sartem handle_match (ParsingContext * pc, const char **attr)
329*18c2aff7Sartem {
330*18c2aff7Sartem 	char udi_to_check[256];
331*18c2aff7Sartem 	char prop_to_check[256];
332*18c2aff7Sartem 	const char *key;
333*18c2aff7Sartem 	int num_attrib;
334*18c2aff7Sartem 	HalDevice *d;
335*18c2aff7Sartem 
336*18c2aff7Sartem 	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++);
337*18c2aff7Sartem 
338*18c2aff7Sartem 	if (num_attrib != 4)
339*18c2aff7Sartem 		return FALSE;
340*18c2aff7Sartem 
341*18c2aff7Sartem 	if (strcmp (attr[0], "key") != 0)
342*18c2aff7Sartem 		return FALSE;
343*18c2aff7Sartem 	key = attr[1];
344*18c2aff7Sartem 
345*18c2aff7Sartem 	/* Resolve key paths like 'someudi/foo/bar/baz:prop.name' '@prop.here.is.an.udi:with.prop.name' */
346*18c2aff7Sartem 	if (!resolve_udiprop_path (key,
347*18c2aff7Sartem 				   pc->device->udi,
348*18c2aff7Sartem 				   udi_to_check, sizeof (udi_to_check),
349*18c2aff7Sartem 				   prop_to_check, sizeof (prop_to_check))) {
350*18c2aff7Sartem 		HAL_ERROR (("Could not resolve keypath '%s' on udi '%s'", key, pc->device->udi));
351*18c2aff7Sartem 		return FALSE;
352*18c2aff7Sartem 	}
353*18c2aff7Sartem 
354*18c2aff7Sartem 	d = hal_device_store_find (hald_get_gdl (), udi_to_check);
355*18c2aff7Sartem 	if (d == NULL) {
356*18c2aff7Sartem 		d = hal_device_store_find (hald_get_tdl (), udi_to_check);
357*18c2aff7Sartem 	}
358*18c2aff7Sartem 	if (d == NULL) {
359*18c2aff7Sartem 		HAL_ERROR (("Could not find device with udi '%s'", udi_to_check));
360*18c2aff7Sartem 		return FALSE;
361*18c2aff7Sartem 	}
362*18c2aff7Sartem 
363*18c2aff7Sartem 
364*18c2aff7Sartem 	if (strcmp (attr[2], "string") == 0) {
365*18c2aff7Sartem 		const char *value;
366*18c2aff7Sartem 
367*18c2aff7Sartem 		/* match string property */
368*18c2aff7Sartem 
369*18c2aff7Sartem 		value = attr[3];
370*18c2aff7Sartem 
371*18c2aff7Sartem 		/*HAL_INFO(("Checking that key='%s' is a string that "
372*18c2aff7Sartem 		  "equals '%s'", key, value)); */
373*18c2aff7Sartem 
374*18c2aff7Sartem 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_STRING)
375*18c2aff7Sartem 			return FALSE;
376*18c2aff7Sartem 
377*18c2aff7Sartem 		if (strcmp (hal_device_property_get_string (d, prop_to_check),
378*18c2aff7Sartem 			    value) != 0)
379*18c2aff7Sartem 			return FALSE;
380*18c2aff7Sartem 
381*18c2aff7Sartem 		/*HAL_INFO (("*** string match for key %s", key));*/
382*18c2aff7Sartem 		return TRUE;
383*18c2aff7Sartem 	} else if (strcmp (attr[2], "int") == 0) {
384*18c2aff7Sartem 		dbus_int32_t value;
385*18c2aff7Sartem 
386*18c2aff7Sartem 		/* match integer property */
387*18c2aff7Sartem 		value = strtol (attr[3], NULL, 0);
388*18c2aff7Sartem 
389*18c2aff7Sartem 		/** @todo Check error condition */
390*18c2aff7Sartem 
391*18c2aff7Sartem 		/*HAL_INFO (("Checking that key='%s' is a int that equals %d",
392*18c2aff7Sartem 		  key, value));*/
393*18c2aff7Sartem 
394*18c2aff7Sartem 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_INT32)
395*18c2aff7Sartem 			return FALSE;
396*18c2aff7Sartem 
397*18c2aff7Sartem 		if (hal_device_property_get_int (d, prop_to_check) != value) {
398*18c2aff7Sartem 			return FALSE;
399*18c2aff7Sartem 		}
400*18c2aff7Sartem 
401*18c2aff7Sartem 		return TRUE;
402*18c2aff7Sartem 	} else if (strcmp (attr[2], "uint64") == 0) {
403*18c2aff7Sartem 		dbus_uint64_t value;
404*18c2aff7Sartem 
405*18c2aff7Sartem 		/* match integer property */
406*18c2aff7Sartem 		value = strtoull (attr[3], NULL, 0);
407*18c2aff7Sartem 
408*18c2aff7Sartem 		/** @todo Check error condition */
409*18c2aff7Sartem 
410*18c2aff7Sartem 		/*HAL_INFO (("Checking that key='%s' is a int that equals %d",
411*18c2aff7Sartem 		  key, value));*/
412*18c2aff7Sartem 
413*18c2aff7Sartem 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_UINT64)
414*18c2aff7Sartem 			return FALSE;
415*18c2aff7Sartem 
416*18c2aff7Sartem 		if (hal_device_property_get_uint64 (d, prop_to_check) != value) {
417*18c2aff7Sartem 			return FALSE;
418*18c2aff7Sartem 		}
419*18c2aff7Sartem 
420*18c2aff7Sartem 		return TRUE;
421*18c2aff7Sartem 	} else if (strcmp (attr[2], "bool") == 0) {
422*18c2aff7Sartem 		dbus_bool_t value;
423*18c2aff7Sartem 
424*18c2aff7Sartem 		/* match string property */
425*18c2aff7Sartem 
426*18c2aff7Sartem 		if (strcmp (attr[3], "false") == 0)
427*18c2aff7Sartem 			value = FALSE;
428*18c2aff7Sartem 		else if (strcmp (attr[3], "true") == 0)
429*18c2aff7Sartem 			value = TRUE;
430*18c2aff7Sartem 		else
431*18c2aff7Sartem 			return FALSE;
432*18c2aff7Sartem 
433*18c2aff7Sartem 		/*HAL_INFO (("Checking that key='%s' is a bool that equals %s",
434*18c2aff7Sartem 		  key, value ? "TRUE" : "FALSE"));*/
435*18c2aff7Sartem 
436*18c2aff7Sartem 		if (hal_device_property_get_type (d, prop_to_check) !=
437*18c2aff7Sartem 		    HAL_PROPERTY_TYPE_BOOLEAN)
438*18c2aff7Sartem 			return FALSE;
439*18c2aff7Sartem 
440*18c2aff7Sartem 		if (hal_device_property_get_bool (d, prop_to_check) != value)
441*18c2aff7Sartem 			return FALSE;
442*18c2aff7Sartem 
443*18c2aff7Sartem 		/*HAL_INFO (("*** bool match for key %s", key));*/
444*18c2aff7Sartem 		return TRUE;
445*18c2aff7Sartem 	} else if (strcmp (attr[2], "exists") == 0) {
446*18c2aff7Sartem 		dbus_bool_t should_exist = TRUE;
447*18c2aff7Sartem 
448*18c2aff7Sartem 		if (strcmp (attr[3], "false") == 0)
449*18c2aff7Sartem 			should_exist = FALSE;
450*18c2aff7Sartem 
451*18c2aff7Sartem 		if (should_exist) {
452*18c2aff7Sartem 			if (hal_device_has_property (d, prop_to_check))
453*18c2aff7Sartem 				return TRUE;
454*18c2aff7Sartem 			else
455*18c2aff7Sartem 				return FALSE;
456*18c2aff7Sartem 		} else {
457*18c2aff7Sartem 			if (hal_device_has_property (d, prop_to_check))
458*18c2aff7Sartem 				return FALSE;
459*18c2aff7Sartem 			else
460*18c2aff7Sartem 				return TRUE;
461*18c2aff7Sartem 		}
462*18c2aff7Sartem 	} else if (strcmp (attr[2], "empty") == 0) {
463*18c2aff7Sartem 		int type;
464*18c2aff7Sartem 		dbus_bool_t is_empty = TRUE;
465*18c2aff7Sartem 		dbus_bool_t should_be_empty = TRUE;
466*18c2aff7Sartem 
467*18c2aff7Sartem 
468*18c2aff7Sartem 		if (strcmp (attr[3], "false") == 0)
469*18c2aff7Sartem 			should_be_empty = FALSE;
470*18c2aff7Sartem 
471*18c2aff7Sartem 		type = hal_device_property_get_type (d, prop_to_check);
472*18c2aff7Sartem 		switch (type) {
473*18c2aff7Sartem 		case HAL_PROPERTY_TYPE_STRING:
474*18c2aff7Sartem 			if (hal_device_has_property (d, prop_to_check))
475*18c2aff7Sartem 				if (strlen (hal_device_property_get_string (d, prop_to_check)) > 0)
476*18c2aff7Sartem 					is_empty = FALSE;
477*18c2aff7Sartem 			break;
478*18c2aff7Sartem 		case HAL_PROPERTY_TYPE_STRLIST:
479*18c2aff7Sartem 			if (hal_device_has_property (d, prop_to_check))
480*18c2aff7Sartem 				if (!hal_device_property_strlist_is_empty(d, prop_to_check))
481*18c2aff7Sartem 					is_empty = FALSE;
482*18c2aff7Sartem 			break;
483*18c2aff7Sartem 		default:
484*18c2aff7Sartem 			/* explicit fallthrough */
485*18c2aff7Sartem 			return FALSE;
486*18c2aff7Sartem 			break;
487*18c2aff7Sartem 		}
488*18c2aff7Sartem 
489*18c2aff7Sartem 		if (should_be_empty) {
490*18c2aff7Sartem 			if (is_empty)
491*18c2aff7Sartem 				return TRUE;
492*18c2aff7Sartem 			else
493*18c2aff7Sartem 				return FALSE;
494*18c2aff7Sartem 		} else {
495*18c2aff7Sartem 			if (is_empty)
496*18c2aff7Sartem 				return FALSE;
497*18c2aff7Sartem 			else
498*18c2aff7Sartem 				return TRUE;
499*18c2aff7Sartem 		}
500*18c2aff7Sartem 	} else if (strcmp (attr[2], "is_ascii") == 0) {
501*18c2aff7Sartem 		dbus_bool_t is_ascii = TRUE;
502*18c2aff7Sartem 		dbus_bool_t should_be_ascii = TRUE;
503*18c2aff7Sartem 		unsigned int i;
504*18c2aff7Sartem 		const char *str;
505*18c2aff7Sartem 
506*18c2aff7Sartem 		if (strcmp (attr[3], "false") == 0)
507*18c2aff7Sartem 			should_be_ascii = FALSE;
508*18c2aff7Sartem 
509*18c2aff7Sartem 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_STRING)
510*18c2aff7Sartem 			return FALSE;
511*18c2aff7Sartem 
512*18c2aff7Sartem 		is_ascii = TRUE;
513*18c2aff7Sartem 
514*18c2aff7Sartem 		str = hal_device_property_get_string (d, prop_to_check);
515*18c2aff7Sartem 		for (i = 0; str[i] != '\0'; i++) {
516*18c2aff7Sartem 			if (((unsigned char) str[i]) > 0x7f)
517*18c2aff7Sartem 				is_ascii = FALSE;
518*18c2aff7Sartem 		}
519*18c2aff7Sartem 
520*18c2aff7Sartem 		if (should_be_ascii) {
521*18c2aff7Sartem 			if (is_ascii)
522*18c2aff7Sartem 				return TRUE;
523*18c2aff7Sartem 			else
524*18c2aff7Sartem 				return FALSE;
525*18c2aff7Sartem 		} else {
526*18c2aff7Sartem 			if (is_ascii)
527*18c2aff7Sartem 				return FALSE;
528*18c2aff7Sartem 			else
529*18c2aff7Sartem 				return TRUE;
530*18c2aff7Sartem 		}
531*18c2aff7Sartem 	} else if (strcmp (attr[2], "is_absolute_path") == 0) {
532*18c2aff7Sartem 		const char *path = NULL;
533*18c2aff7Sartem 		dbus_bool_t is_absolute_path = FALSE;
534*18c2aff7Sartem 		dbus_bool_t should_be_absolute_path = TRUE;
535*18c2aff7Sartem 
536*18c2aff7Sartem 		if (strcmp (attr[3], "false") == 0)
537*18c2aff7Sartem 			should_be_absolute_path = FALSE;
538*18c2aff7Sartem 
539*18c2aff7Sartem 		/*HAL_INFO (("d->udi='%s', prop_to_check='%s'", d->udi, prop_to_check));*/
540*18c2aff7Sartem 
541*18c2aff7Sartem 		if (hal_device_property_get_type (d, prop_to_check) != HAL_PROPERTY_TYPE_STRING)
542*18c2aff7Sartem 			return FALSE;
543*18c2aff7Sartem 
544*18c2aff7Sartem 		if (hal_device_has_property (d, prop_to_check)) {
545*18c2aff7Sartem 			path = hal_device_property_get_string (d, prop_to_check);
546*18c2aff7Sartem 			if (g_path_is_absolute (path))
547*18c2aff7Sartem 				is_absolute_path = TRUE;
548*18c2aff7Sartem 		}
549*18c2aff7Sartem 
550*18c2aff7Sartem 		/*HAL_INFO (("is_absolute=%d, should_be=%d, path='%s'", is_absolute_path, should_be_absolute_path, path));*/
551*18c2aff7Sartem 
552*18c2aff7Sartem 		if (should_be_absolute_path) {
553*18c2aff7Sartem 			if (is_absolute_path)
554*18c2aff7Sartem 				return TRUE;
555*18c2aff7Sartem 			else
556*18c2aff7Sartem 				return FALSE;
557*18c2aff7Sartem 		} else {
558*18c2aff7Sartem 			if (is_absolute_path)
559*18c2aff7Sartem 				return FALSE;
560*18c2aff7Sartem 			else
561*18c2aff7Sartem 				return TRUE;
562*18c2aff7Sartem 		}
563*18c2aff7Sartem 	} else if (strcmp (attr[2], "contains") == 0) {
564*18c2aff7Sartem 		const char *needle;
565*18c2aff7Sartem 		dbus_bool_t contains = FALSE;
566*18c2aff7Sartem 
567*18c2aff7Sartem 		needle = attr[3];
568*18c2aff7Sartem 
569*18c2aff7Sartem 		if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRING) {
570*18c2aff7Sartem 			if (hal_device_has_property (d, prop_to_check)) {
571*18c2aff7Sartem 				const char *haystack;
572*18c2aff7Sartem 
573*18c2aff7Sartem 				haystack = hal_device_property_get_string (d, prop_to_check);
574*18c2aff7Sartem 				if (needle != NULL && haystack != NULL && strstr (haystack, needle)) {
575*18c2aff7Sartem 					contains = TRUE;
576*18c2aff7Sartem 				}
577*18c2aff7Sartem 
578*18c2aff7Sartem 			}
579*18c2aff7Sartem 		} else if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRLIST &&
580*18c2aff7Sartem 			   needle != NULL) {
581*18c2aff7Sartem 			GSList *i;
582*18c2aff7Sartem 			GSList *value;
583*18c2aff7Sartem 
584*18c2aff7Sartem 			value = hal_device_property_get_strlist (d, prop_to_check);
585*18c2aff7Sartem 			for (i = value; i != NULL; i = g_slist_next (i)) {
586*18c2aff7Sartem 				const char *str = i->data;
587*18c2aff7Sartem 				if (strcmp (str, needle) == 0) {
588*18c2aff7Sartem 					contains = TRUE;
589*18c2aff7Sartem 					break;
590*18c2aff7Sartem 				}
591*18c2aff7Sartem 			}
592*18c2aff7Sartem 		} else {
593*18c2aff7Sartem 			return FALSE;
594*18c2aff7Sartem 		}
595*18c2aff7Sartem 
596*18c2aff7Sartem 		return contains;
597*18c2aff7Sartem 	} else if (strcmp (attr[2], "contains_ncase") == 0) {
598*18c2aff7Sartem 		const char *needle;
599*18c2aff7Sartem 		dbus_bool_t contains_ncase = FALSE;
600*18c2aff7Sartem 
601*18c2aff7Sartem 		needle = attr[3];
602*18c2aff7Sartem 
603*18c2aff7Sartem 		if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRING) {
604*18c2aff7Sartem 			if (hal_device_has_property (d, prop_to_check)) {
605*18c2aff7Sartem 				char *needle_lowercase;
606*18c2aff7Sartem 				char *haystack_lowercase;
607*18c2aff7Sartem 
608*18c2aff7Sartem 				needle_lowercase   = g_utf8_strdown (needle, -1);
609*18c2aff7Sartem 				haystack_lowercase = g_utf8_strdown (hal_device_property_get_string (d, prop_to_check), -1);
610*18c2aff7Sartem 				if (needle_lowercase != NULL && haystack_lowercase != NULL && strstr (haystack_lowercase, needle_lowercase)) {
611*18c2aff7Sartem 					contains_ncase = TRUE;
612*18c2aff7Sartem 				}
613*18c2aff7Sartem 
614*18c2aff7Sartem 				g_free (needle_lowercase);
615*18c2aff7Sartem 				g_free (haystack_lowercase);
616*18c2aff7Sartem 			}
617*18c2aff7Sartem 		} else if (hal_device_property_get_type (d, prop_to_check) == HAL_PROPERTY_TYPE_STRLIST &&
618*18c2aff7Sartem 			   needle != NULL) {
619*18c2aff7Sartem 			GSList *i;
620*18c2aff7Sartem 			GSList *value;
621*18c2aff7Sartem 
622*18c2aff7Sartem 			value = hal_device_property_get_strlist (d, prop_to_check);
623*18c2aff7Sartem 			for (i = value; i != NULL; i = g_slist_next (i)) {
624*18c2aff7Sartem 				const char *str = i->data;
625*18c2aff7Sartem 				if (g_ascii_strcasecmp (str, needle) == 0) {
626*18c2aff7Sartem 					contains_ncase = TRUE;
627*18c2aff7Sartem 					break;
628*18c2aff7Sartem 				}
629*18c2aff7Sartem 			}
630*18c2aff7Sartem 		} else {
631*18c2aff7Sartem 			return FALSE;
632*18c2aff7Sartem 		}
633*18c2aff7Sartem 
634*18c2aff7Sartem 		return contains_ncase;
635*18c2aff7Sartem 	} else if (strcmp (attr[2], "compare_lt") == 0) {
636*18c2aff7Sartem 		dbus_int64_t result;
637*18c2aff7Sartem 		if (!match_compare_property (d, prop_to_check, attr[3], &result)) {
638*18c2aff7Sartem 			return FALSE;
639*18c2aff7Sartem 		} else {
640*18c2aff7Sartem 			return result < 0;
641*18c2aff7Sartem 		}
642*18c2aff7Sartem 	} else if (strcmp (attr[2], "compare_le") == 0) {
643*18c2aff7Sartem 		dbus_int64_t result;
644*18c2aff7Sartem 		if (!match_compare_property (d, prop_to_check, attr[3], &result))
645*18c2aff7Sartem 			return FALSE;
646*18c2aff7Sartem 		else
647*18c2aff7Sartem 			return result <= 0;
648*18c2aff7Sartem 	} else if (strcmp (attr[2], "compare_gt") == 0) {
649*18c2aff7Sartem 		dbus_int64_t result;
650*18c2aff7Sartem 		if (!match_compare_property (d, prop_to_check, attr[3], &result))
651*18c2aff7Sartem 			return FALSE;
652*18c2aff7Sartem 		else
653*18c2aff7Sartem 			return result > 0;
654*18c2aff7Sartem 	} else if (strcmp (attr[2], "compare_ge") == 0) {
655*18c2aff7Sartem 		dbus_int64_t result;
656*18c2aff7Sartem 		if (!match_compare_property (d, prop_to_check, attr[3], &result))
657*18c2aff7Sartem 			return FALSE;
658*18c2aff7Sartem 		else
659*18c2aff7Sartem 			return result >= 0;
660*18c2aff7Sartem 	}
661*18c2aff7Sartem 
662*18c2aff7Sartem 	return FALSE;
663*18c2aff7Sartem }
664*18c2aff7Sartem 
665*18c2aff7Sartem 
666*18c2aff7Sartem /** Called when the merge element begins.
667*18c2aff7Sartem  *
668*18c2aff7Sartem  *  @param  pc                  Parsing context
669*18c2aff7Sartem  *  @param  attr                Attribute key/value pairs
670*18c2aff7Sartem  */
671*18c2aff7Sartem static void
handle_merge(ParsingContext * pc,const char ** attr)672*18c2aff7Sartem handle_merge (ParsingContext * pc, const char **attr)
673*18c2aff7Sartem {
674*18c2aff7Sartem 	int num_attrib;
675*18c2aff7Sartem 
676*18c2aff7Sartem 	pc->merge_type = MERGE_TYPE_UNKNOWN;
677*18c2aff7Sartem 
678*18c2aff7Sartem 
679*18c2aff7Sartem 	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++) {
680*18c2aff7Sartem 		;
681*18c2aff7Sartem 	}
682*18c2aff7Sartem 
683*18c2aff7Sartem 	if (num_attrib != 4)
684*18c2aff7Sartem 		return;
685*18c2aff7Sartem 
686*18c2aff7Sartem 	if (strcmp (attr[0], "key") != 0)
687*18c2aff7Sartem 		return;
688*18c2aff7Sartem 	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
689*18c2aff7Sartem 
690*18c2aff7Sartem 	if (strcmp (attr[2], "type") != 0)
691*18c2aff7Sartem 		return;
692*18c2aff7Sartem 
693*18c2aff7Sartem 	if (strcmp (attr[3], "string") == 0) {
694*18c2aff7Sartem 		/* match string property */
695*18c2aff7Sartem 		pc->merge_type = MERGE_TYPE_STRING;
696*18c2aff7Sartem 		return;
697*18c2aff7Sartem 	} else if (strcmp (attr[3], "bool") == 0) {
698*18c2aff7Sartem 		/* match string property */
699*18c2aff7Sartem 		pc->merge_type = MERGE_TYPE_BOOLEAN;
700*18c2aff7Sartem 		return;
701*18c2aff7Sartem 	} else if (strcmp (attr[3], "int") == 0) {
702*18c2aff7Sartem 		/* match string property */
703*18c2aff7Sartem 		pc->merge_type = MERGE_TYPE_INT32;
704*18c2aff7Sartem 		return;
705*18c2aff7Sartem 	} else if (strcmp (attr[3], "uint64") == 0) {
706*18c2aff7Sartem 		/* match string property */
707*18c2aff7Sartem 		pc->merge_type = MERGE_TYPE_UINT64;
708*18c2aff7Sartem 		return;
709*18c2aff7Sartem 	} else if (strcmp (attr[3], "double") == 0) {
710*18c2aff7Sartem 		/* match string property */
711*18c2aff7Sartem 		pc->merge_type = MERGE_TYPE_DOUBLE;
712*18c2aff7Sartem 		return;
713*18c2aff7Sartem 	} else if (strcmp (attr[3], "strlist") == 0) {
714*18c2aff7Sartem 		/* match string property */
715*18c2aff7Sartem 		pc->merge_type = MERGE_TYPE_STRLIST;
716*18c2aff7Sartem 		return;
717*18c2aff7Sartem 	} else if (strcmp (attr[3], "copy_property") == 0) {
718*18c2aff7Sartem 		/* copy another property */
719*18c2aff7Sartem 		pc->merge_type = MERGE_TYPE_COPY_PROPERTY;
720*18c2aff7Sartem 		return;
721*18c2aff7Sartem 	}
722*18c2aff7Sartem 
723*18c2aff7Sartem 	return;
724*18c2aff7Sartem }
725*18c2aff7Sartem 
726*18c2aff7Sartem /** Called when the append or prepend element begins.
727*18c2aff7Sartem  *
728*18c2aff7Sartem  *  @param  pc                  Parsing context
729*18c2aff7Sartem  *  @param  attr                Attribute key/value pairs
730*18c2aff7Sartem  */
731*18c2aff7Sartem static void
handle_append_prepend(ParsingContext * pc,const char ** attr)732*18c2aff7Sartem handle_append_prepend (ParsingContext * pc, const char **attr)
733*18c2aff7Sartem {
734*18c2aff7Sartem 	int num_attrib;
735*18c2aff7Sartem 
736*18c2aff7Sartem 	pc->merge_type = MERGE_TYPE_UNKNOWN;
737*18c2aff7Sartem 
738*18c2aff7Sartem 	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++) {
739*18c2aff7Sartem 		;
740*18c2aff7Sartem 	}
741*18c2aff7Sartem 
742*18c2aff7Sartem 	if (num_attrib != 4)
743*18c2aff7Sartem 		return;
744*18c2aff7Sartem 
745*18c2aff7Sartem 	if (strcmp (attr[0], "key") != 0)
746*18c2aff7Sartem 		return;
747*18c2aff7Sartem 	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
748*18c2aff7Sartem 
749*18c2aff7Sartem 	if (strcmp (attr[2], "type") != 0)
750*18c2aff7Sartem 		return;
751*18c2aff7Sartem 
752*18c2aff7Sartem 	if (strcmp (attr[3], "string") == 0) {
753*18c2aff7Sartem 		/* append to a string */
754*18c2aff7Sartem 		pc->merge_type = MERGE_TYPE_STRING;
755*18c2aff7Sartem 		return;
756*18c2aff7Sartem 	} else if (strcmp (attr[3], "strlist") == 0) {
757*18c2aff7Sartem 		/* append to a string list*/
758*18c2aff7Sartem 		pc->merge_type = MERGE_TYPE_STRLIST;
759*18c2aff7Sartem 		return;
760*18c2aff7Sartem 	} else if (strcmp (attr[3], "copy_property") == 0) {
761*18c2aff7Sartem 		/* copy another property */
762*18c2aff7Sartem 		pc->merge_type = MERGE_TYPE_COPY_PROPERTY;
763*18c2aff7Sartem 		return;
764*18c2aff7Sartem 	}
765*18c2aff7Sartem 
766*18c2aff7Sartem 	return;
767*18c2aff7Sartem }
768*18c2aff7Sartem 
769*18c2aff7Sartem 
770*18c2aff7Sartem /** Called when the spawn element begins.
771*18c2aff7Sartem  *
772*18c2aff7Sartem  *  @param  pc                  Parsing context
773*18c2aff7Sartem  *  @param  attr                Attribute key/value pairs
774*18c2aff7Sartem  */
775*18c2aff7Sartem static void
handle_spawn(ParsingContext * pc,const char ** attr)776*18c2aff7Sartem handle_spawn (ParsingContext * pc, const char **attr)
777*18c2aff7Sartem {
778*18c2aff7Sartem 	int num_attrib;
779*18c2aff7Sartem 
780*18c2aff7Sartem 	pc->merge_type = MERGE_TYPE_UNKNOWN;
781*18c2aff7Sartem 
782*18c2aff7Sartem 	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++) {
783*18c2aff7Sartem 		;
784*18c2aff7Sartem 	}
785*18c2aff7Sartem 
786*18c2aff7Sartem 	if (num_attrib != 2)
787*18c2aff7Sartem 		return;
788*18c2aff7Sartem 
789*18c2aff7Sartem 	if (strcmp (attr[0], "udi") != 0)
790*18c2aff7Sartem 		return;
791*18c2aff7Sartem 
792*18c2aff7Sartem 	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
793*18c2aff7Sartem 
794*18c2aff7Sartem 	pc->merge_type = MERGE_TYPE_SPAWN;
795*18c2aff7Sartem 	return;
796*18c2aff7Sartem }
797*18c2aff7Sartem 
798*18c2aff7Sartem /** Called when the remove element begins.
799*18c2aff7Sartem  *
800*18c2aff7Sartem  *  @param  pc                  Parsing context
801*18c2aff7Sartem  *  @param  attr                Attribute key/value pairs
802*18c2aff7Sartem  */
803*18c2aff7Sartem static void
handle_remove(ParsingContext * pc,const char ** attr)804*18c2aff7Sartem handle_remove (ParsingContext * pc, const char **attr)
805*18c2aff7Sartem {
806*18c2aff7Sartem 	int num_attrib;
807*18c2aff7Sartem 
808*18c2aff7Sartem 	pc->merge_type = MERGE_TYPE_UNKNOWN;
809*18c2aff7Sartem 
810*18c2aff7Sartem 	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++) {
811*18c2aff7Sartem 		;
812*18c2aff7Sartem 	}
813*18c2aff7Sartem 
814*18c2aff7Sartem 	if (num_attrib != 2 && num_attrib != 4)
815*18c2aff7Sartem 		return;
816*18c2aff7Sartem 
817*18c2aff7Sartem 	if (strcmp (attr[0], "key") != 0)
818*18c2aff7Sartem 		return;
819*18c2aff7Sartem 	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
820*18c2aff7Sartem 
821*18c2aff7Sartem 	if (num_attrib == 4) {
822*18c2aff7Sartem 		if (strcmp (attr[2], "type") != 0)
823*18c2aff7Sartem 			return;
824*18c2aff7Sartem 
825*18c2aff7Sartem 		if (strcmp (attr[3], "strlist") == 0) {
826*18c2aff7Sartem 			/* remove from strlist */
827*18c2aff7Sartem 			pc->merge_type = MERGE_TYPE_STRLIST;
828*18c2aff7Sartem 			return;
829*18c2aff7Sartem 		} else {
830*18c2aff7Sartem 			pc->merge_type = MERGE_TYPE_UNKNOWN;
831*18c2aff7Sartem 			return;
832*18c2aff7Sartem 		}
833*18c2aff7Sartem 	} else {
834*18c2aff7Sartem 		pc->merge_type = MERGE_TYPE_REMOVE;
835*18c2aff7Sartem 	}
836*18c2aff7Sartem 
837*18c2aff7Sartem 	return;
838*18c2aff7Sartem }
839*18c2aff7Sartem 
840*18c2aff7Sartem /** Called when the clear element begins.
841*18c2aff7Sartem  *
842*18c2aff7Sartem  *  @param  pc                  Parsing context
843*18c2aff7Sartem  *  @param  attr                Attribute key/value pairs
844*18c2aff7Sartem  */
845*18c2aff7Sartem static void
handle_clear(ParsingContext * pc,const char ** attr)846*18c2aff7Sartem handle_clear (ParsingContext * pc, const char **attr)
847*18c2aff7Sartem {
848*18c2aff7Sartem 	int num_attrib;
849*18c2aff7Sartem 
850*18c2aff7Sartem 	pc->merge_type = MERGE_TYPE_UNKNOWN;
851*18c2aff7Sartem 
852*18c2aff7Sartem 	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++) {
853*18c2aff7Sartem 		;
854*18c2aff7Sartem 	}
855*18c2aff7Sartem 
856*18c2aff7Sartem 	if (num_attrib != 4)
857*18c2aff7Sartem 		return;
858*18c2aff7Sartem 
859*18c2aff7Sartem 	if (strcmp (attr[0], "key") != 0)
860*18c2aff7Sartem 		return;
861*18c2aff7Sartem 
862*18c2aff7Sartem 
863*18c2aff7Sartem 	if (strcmp (attr[3], "strlist") != 0)
864*18c2aff7Sartem 		return;
865*18c2aff7Sartem 
866*18c2aff7Sartem 	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
867*18c2aff7Sartem 
868*18c2aff7Sartem 	pc->merge_type = MERGE_TYPE_CLEAR;
869*18c2aff7Sartem 
870*18c2aff7Sartem 	return;
871*18c2aff7Sartem }
872*18c2aff7Sartem 
873*18c2aff7Sartem /** Abort parsing of document
874*18c2aff7Sartem  *
875*18c2aff7Sartem  *  @param  pc                  Parsing context
876*18c2aff7Sartem  */
877*18c2aff7Sartem static void
parsing_abort(ParsingContext * pc)878*18c2aff7Sartem parsing_abort (ParsingContext * pc)
879*18c2aff7Sartem {
880*18c2aff7Sartem 	/* Grr, expat can't abort parsing */
881*18c2aff7Sartem 	HAL_ERROR (("Aborting parsing of document"));
882*18c2aff7Sartem 	pc->aborted = TRUE;
883*18c2aff7Sartem }
884*18c2aff7Sartem 
885*18c2aff7Sartem /** Called by expat when an element begins.
886*18c2aff7Sartem  *
887*18c2aff7Sartem  *  @param  pc                  Parsing context
888*18c2aff7Sartem  *  @param  el                  Element name
889*18c2aff7Sartem  *  @param  attr                Attribute key/value pairs
890*18c2aff7Sartem  */
891*18c2aff7Sartem static void
start(ParsingContext * pc,const char * el,const char ** attr)892*18c2aff7Sartem start (ParsingContext * pc, const char *el, const char **attr)
893*18c2aff7Sartem {
894*18c2aff7Sartem 	if (pc->aborted)
895*18c2aff7Sartem 		return;
896*18c2aff7Sartem 
897*18c2aff7Sartem 	pc->cdata_buf_len = 0;
898*18c2aff7Sartem 
899*18c2aff7Sartem 	pc->merge_type = MERGE_TYPE_UNKNOWN;
900*18c2aff7Sartem 
901*18c2aff7Sartem /*
902*18c2aff7Sartem     for (i = 0; i < pc->depth; i++)
903*18c2aff7Sartem         printf("  ");
904*18c2aff7Sartem 
905*18c2aff7Sartem     printf("%s", el);
906*18c2aff7Sartem 
907*18c2aff7Sartem     for (i = 0; attr[i]; i += 2) {
908*18c2aff7Sartem         printf(" %s='%s'", attr[i], attr[i + 1]);
909*18c2aff7Sartem     }
910*18c2aff7Sartem 
911*18c2aff7Sartem     printf("   curelem=%d\n", pc->curelem);
912*18c2aff7Sartem */
913*18c2aff7Sartem 
914*18c2aff7Sartem 	if (strcmp (el, "match") == 0) {
915*18c2aff7Sartem 		if (pc->curelem != CURELEM_DEVICE
916*18c2aff7Sartem 		    && pc->curelem != CURELEM_MATCH) {
917*18c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <match> can only be "
918*18c2aff7Sartem 				    "inside <device> and <match>",
919*18c2aff7Sartem 				    pc->file,
920*18c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
921*18c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
922*18c2aff7Sartem 			parsing_abort (pc);
923*18c2aff7Sartem 		}
924*18c2aff7Sartem 
925*18c2aff7Sartem 		pc->curelem = CURELEM_MATCH;
926*18c2aff7Sartem 
927*18c2aff7Sartem 		/* don't bother checking if matching at lower depths failed */
928*18c2aff7Sartem 		if (pc->match_ok) {
929*18c2aff7Sartem 			if (!handle_match (pc, attr)) {
930*18c2aff7Sartem 				/* No match */
931*18c2aff7Sartem 				pc->match_depth_first_fail = pc->depth;
932*18c2aff7Sartem 				pc->match_ok = FALSE;
933*18c2aff7Sartem 			}
934*18c2aff7Sartem 		}
935*18c2aff7Sartem 	} else if (strcmp (el, "merge") == 0) {
936*18c2aff7Sartem 		if (pc->curelem != CURELEM_DEVICE
937*18c2aff7Sartem 		    && pc->curelem != CURELEM_MATCH) {
938*18c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <merge> can only be "
939*18c2aff7Sartem 				    "inside <device> and <match>",
940*18c2aff7Sartem 				    pc->file,
941*18c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
942*18c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
943*18c2aff7Sartem 			parsing_abort (pc);
944*18c2aff7Sartem 		}
945*18c2aff7Sartem 
946*18c2aff7Sartem 		pc->curelem = CURELEM_MERGE;
947*18c2aff7Sartem 		if (pc->match_ok) {
948*18c2aff7Sartem 			handle_merge (pc, attr);
949*18c2aff7Sartem 		} else {
950*18c2aff7Sartem 			/*HAL_INFO(("No merge!")); */
951*18c2aff7Sartem 		}
952*18c2aff7Sartem 	} else if (strcmp (el, "append") == 0) {
953*18c2aff7Sartem 		if (pc->curelem != CURELEM_DEVICE
954*18c2aff7Sartem 		    && pc->curelem != CURELEM_MATCH) {
955*18c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <append> can only be "
956*18c2aff7Sartem 				    "inside <device> and <match>",
957*18c2aff7Sartem 				    pc->file,
958*18c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
959*18c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
960*18c2aff7Sartem 			parsing_abort (pc);
961*18c2aff7Sartem 		}
962*18c2aff7Sartem 
963*18c2aff7Sartem 		pc->curelem = CURELEM_APPEND;
964*18c2aff7Sartem 		if (pc->match_ok) {
965*18c2aff7Sartem 			handle_append_prepend (pc, attr);
966*18c2aff7Sartem 		} else {
967*18c2aff7Sartem 			/*HAL_INFO(("No merge!")); */
968*18c2aff7Sartem 		}
969*18c2aff7Sartem 	} else if (strcmp (el, "prepend") == 0) {
970*18c2aff7Sartem 		if (pc->curelem != CURELEM_DEVICE
971*18c2aff7Sartem 		    && pc->curelem != CURELEM_MATCH) {
972*18c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <prepend> can only be "
973*18c2aff7Sartem 				    "inside <device> and <match>",
974*18c2aff7Sartem 				    pc->file,
975*18c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
976*18c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
977*18c2aff7Sartem 			parsing_abort (pc);
978*18c2aff7Sartem 		}
979*18c2aff7Sartem 
980*18c2aff7Sartem 		pc->curelem = CURELEM_PREPEND;
981*18c2aff7Sartem 		if (pc->match_ok) {
982*18c2aff7Sartem 			handle_append_prepend (pc, attr);
983*18c2aff7Sartem 		} else {
984*18c2aff7Sartem 			/*HAL_INFO(("No merge!")); */
985*18c2aff7Sartem 		}
986*18c2aff7Sartem 	} else if (strcmp (el, "remove") == 0) {
987*18c2aff7Sartem 		if (pc->curelem != CURELEM_DEVICE
988*18c2aff7Sartem 		    && pc->curelem != CURELEM_MATCH) {
989*18c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <remove> can only be "
990*18c2aff7Sartem 				    "inside <device> and <match>",
991*18c2aff7Sartem 				    pc->file,
992*18c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
993*18c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
994*18c2aff7Sartem 			parsing_abort (pc);
995*18c2aff7Sartem 		}
996*18c2aff7Sartem 
997*18c2aff7Sartem 		pc->curelem = CURELEM_REMOVE;
998*18c2aff7Sartem 		if (pc->match_ok) {
999*18c2aff7Sartem 			handle_remove (pc, attr);
1000*18c2aff7Sartem 		} else {
1001*18c2aff7Sartem 			/*HAL_INFO(("No merge!")); */
1002*18c2aff7Sartem 		}
1003*18c2aff7Sartem 	} else if (strcmp (el, "clear") == 0) {
1004*18c2aff7Sartem 		if (pc->curelem != CURELEM_DEVICE
1005*18c2aff7Sartem 		    && pc->curelem != CURELEM_MATCH) {
1006*18c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <remove> can only be "
1007*18c2aff7Sartem 				    "inside <device> and <match>",
1008*18c2aff7Sartem 				    pc->file,
1009*18c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
1010*18c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
1011*18c2aff7Sartem 			parsing_abort (pc);
1012*18c2aff7Sartem 		}
1013*18c2aff7Sartem 
1014*18c2aff7Sartem 		pc->curelem = CURELEM_CLEAR;
1015*18c2aff7Sartem 		if (pc->match_ok) {
1016*18c2aff7Sartem 			handle_clear (pc, attr);
1017*18c2aff7Sartem 		} else {
1018*18c2aff7Sartem 			/*HAL_INFO(("No merge!")); */
1019*18c2aff7Sartem 		}
1020*18c2aff7Sartem 	} else if (strcmp (el, "device") == 0) {
1021*18c2aff7Sartem 		if (pc->curelem != CURELEM_DEVICE_INFO) {
1022*18c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <device> can only be "
1023*18c2aff7Sartem 				    "inside <deviceinfo>",
1024*18c2aff7Sartem 				    pc->file,
1025*18c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
1026*18c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
1027*18c2aff7Sartem 			parsing_abort (pc);
1028*18c2aff7Sartem 		}
1029*18c2aff7Sartem 		pc->curelem = CURELEM_DEVICE;
1030*18c2aff7Sartem 	} else if (strcmp (el, "deviceinfo") == 0) {
1031*18c2aff7Sartem 		if (pc->curelem != CURELEM_UNKNOWN) {
1032*18c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <deviceinfo> must be "
1033*18c2aff7Sartem 				    "a top-level element",
1034*18c2aff7Sartem 				    pc->file,
1035*18c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
1036*18c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
1037*18c2aff7Sartem 			parsing_abort (pc);
1038*18c2aff7Sartem 		}
1039*18c2aff7Sartem 		pc->curelem = CURELEM_DEVICE_INFO;
1040*18c2aff7Sartem 	} else if (strcmp (el, "spawn") == 0) {
1041*18c2aff7Sartem 		if (pc->curelem != CURELEM_MATCH) {
1042*18c2aff7Sartem 			HAL_ERROR (("%s:%d:%d: Element <spawn> can only be "
1043*18c2aff7Sartem 				    "inside <match>",
1044*18c2aff7Sartem 				    pc->file,
1045*18c2aff7Sartem 				    XML_GetCurrentLineNumber (pc->parser),
1046*18c2aff7Sartem 				    XML_GetCurrentColumnNumber (pc->parser)));
1047*18c2aff7Sartem 			parsing_abort (pc);
1048*18c2aff7Sartem 		}
1049*18c2aff7Sartem 
1050*18c2aff7Sartem 		pc->curelem = CURELEM_SPAWN;
1051*18c2aff7Sartem 		if (pc->match_ok) {
1052*18c2aff7Sartem 			handle_spawn (pc, attr);
1053*18c2aff7Sartem 		}
1054*18c2aff7Sartem 
1055*18c2aff7Sartem 	} else {
1056*18c2aff7Sartem 		HAL_ERROR (("%s:%d:%d: Unknown element <%s>",
1057*18c2aff7Sartem 			    pc->file,
1058*18c2aff7Sartem 			    XML_GetCurrentLineNumber (pc->parser),
1059*18c2aff7Sartem 			    XML_GetCurrentColumnNumber (pc->parser), el));
1060*18c2aff7Sartem 		parsing_abort (pc);
1061*18c2aff7Sartem 	}
1062*18c2aff7Sartem 
1063*18c2aff7Sartem 	/* Nasty hack */
1064*18c2aff7Sartem 	assert (pc->depth < MAX_DEPTH);
1065*18c2aff7Sartem 
1066*18c2aff7Sartem 	pc->depth++;
1067*18c2aff7Sartem 
1068*18c2aff7Sartem 	/* store depth */
1069*18c2aff7Sartem 	pc->curelem_stack[pc->depth] = pc->curelem;
1070*18c2aff7Sartem 
1071*18c2aff7Sartem }
1072*18c2aff7Sartem 
1073*18c2aff7Sartem static void
spawned_device_callouts_add_done(HalDevice * d,gpointer userdata1,gpointer userdata2)1074*18c2aff7Sartem spawned_device_callouts_add_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
1075*18c2aff7Sartem {
1076*18c2aff7Sartem 	HAL_INFO (("Add callouts completed udi=%s", d->udi));
1077*18c2aff7Sartem 
1078*18c2aff7Sartem 	/* Move from temporary to global device store */
1079*18c2aff7Sartem 	hal_device_store_remove (hald_get_tdl (), d);
1080*18c2aff7Sartem 	hal_device_store_add (hald_get_gdl (), d);
1081*18c2aff7Sartem 
1082*18c2aff7Sartem }
1083*18c2aff7Sartem 
1084*18c2aff7Sartem /** Called by expat when an element ends.
1085*18c2aff7Sartem  *
1086*18c2aff7Sartem  *  @param  pc                  Parsing context
1087*18c2aff7Sartem  *  @param  el                  Element name
1088*18c2aff7Sartem  */
1089*18c2aff7Sartem static void
end(ParsingContext * pc,const char * el)1090*18c2aff7Sartem end (ParsingContext * pc, const char *el)
1091*18c2aff7Sartem {
1092*18c2aff7Sartem 	if (pc->aborted)
1093*18c2aff7Sartem 		return;
1094*18c2aff7Sartem 
1095*18c2aff7Sartem 	pc->cdata_buf[pc->cdata_buf_len] = '\0';
1096*18c2aff7Sartem 
1097*18c2aff7Sartem /*    printf("   curelem=%d\n", pc->curelem);*/
1098*18c2aff7Sartem 
1099*18c2aff7Sartem 	if (pc->curelem == CURELEM_MERGE && pc->match_ok) {
1100*18c2aff7Sartem 		/* As soon as we are merging, we have matched the device... */
1101*18c2aff7Sartem 		pc->device_matched = TRUE;
1102*18c2aff7Sartem 
1103*18c2aff7Sartem 		switch (pc->merge_type) {
1104*18c2aff7Sartem 		case MERGE_TYPE_STRING:
1105*18c2aff7Sartem 			hal_device_property_set_string (pc->device, pc->merge_key, pc->cdata_buf);
1106*18c2aff7Sartem 			break;
1107*18c2aff7Sartem 
1108*18c2aff7Sartem 		case MERGE_TYPE_STRLIST:
1109*18c2aff7Sartem 		{
1110*18c2aff7Sartem 			int type = hal_device_property_get_type (pc->device, pc->merge_key);
1111*18c2aff7Sartem 			if (type == HAL_PROPERTY_TYPE_STRLIST || type == HAL_PROPERTY_TYPE_INVALID) {
1112*18c2aff7Sartem 				hal_device_property_remove (pc->device, pc->merge_key);
1113*18c2aff7Sartem 				hal_device_property_strlist_append (pc->device, pc->merge_key, pc->cdata_buf);
1114*18c2aff7Sartem 			}
1115*18c2aff7Sartem 			break;
1116*18c2aff7Sartem 		}
1117*18c2aff7Sartem 
1118*18c2aff7Sartem 		case MERGE_TYPE_INT32:
1119*18c2aff7Sartem 			{
1120*18c2aff7Sartem 				dbus_int32_t value;
1121*18c2aff7Sartem 
1122*18c2aff7Sartem 				/* match integer property */
1123*18c2aff7Sartem 				value = strtol (pc->cdata_buf, NULL, 0);
1124*18c2aff7Sartem 
1125*18c2aff7Sartem 				/** @todo FIXME: Check error condition */
1126*18c2aff7Sartem 
1127*18c2aff7Sartem 				hal_device_property_set_int (pc->device,
1128*18c2aff7Sartem 						     pc->merge_key, value);
1129*18c2aff7Sartem 				break;
1130*18c2aff7Sartem 			}
1131*18c2aff7Sartem 
1132*18c2aff7Sartem 		case MERGE_TYPE_UINT64:
1133*18c2aff7Sartem 			{
1134*18c2aff7Sartem 				dbus_uint64_t value;
1135*18c2aff7Sartem 
1136*18c2aff7Sartem 				/* match integer property */
1137*18c2aff7Sartem 				value = strtoull (pc->cdata_buf, NULL, 0);
1138*18c2aff7Sartem 
1139*18c2aff7Sartem 				/** @todo FIXME: Check error condition */
1140*18c2aff7Sartem 
1141*18c2aff7Sartem 				hal_device_property_set_uint64 (pc->device,
1142*18c2aff7Sartem 						     pc->merge_key, value);
1143*18c2aff7Sartem 				break;
1144*18c2aff7Sartem 			}
1145*18c2aff7Sartem 
1146*18c2aff7Sartem 		case MERGE_TYPE_BOOLEAN:
1147*18c2aff7Sartem 			hal_device_property_set_bool (pc->device, pc->merge_key,
1148*18c2aff7Sartem 					      (strcmp (pc->cdata_buf,
1149*18c2aff7Sartem 						       "true") == 0)
1150*18c2aff7Sartem 					      ? TRUE : FALSE);
1151*18c2aff7Sartem 			break;
1152*18c2aff7Sartem 
1153*18c2aff7Sartem 		case MERGE_TYPE_DOUBLE:
1154*18c2aff7Sartem 			hal_device_property_set_double (pc->device, pc->merge_key,
1155*18c2aff7Sartem 						atof (pc->cdata_buf));
1156*18c2aff7Sartem 			break;
1157*18c2aff7Sartem 
1158*18c2aff7Sartem 		case MERGE_TYPE_COPY_PROPERTY:
1159*18c2aff7Sartem 		{
1160*18c2aff7Sartem 			char udi_to_merge_from[256];
1161*18c2aff7Sartem 			char prop_to_merge[256];
1162*18c2aff7Sartem 
1163*18c2aff7Sartem 			/* Resolve key paths like 'someudi/foo/bar/baz:prop.name'
1164*18c2aff7Sartem 			 * '@prop.here.is.an.udi:with.prop.name'
1165*18c2aff7Sartem 			 */
1166*18c2aff7Sartem 			if (!resolve_udiprop_path (pc->cdata_buf,
1167*18c2aff7Sartem 						   pc->device->udi,
1168*18c2aff7Sartem 						   udi_to_merge_from, sizeof (udi_to_merge_from),
1169*18c2aff7Sartem 						   prop_to_merge, sizeof (prop_to_merge))) {
1170*18c2aff7Sartem 				HAL_ERROR (("Could not resolve keypath '%s' on udi '%s'", pc->cdata_buf, pc->device->udi));
1171*18c2aff7Sartem 			} else {
1172*18c2aff7Sartem 				HalDevice *d;
1173*18c2aff7Sartem 
1174*18c2aff7Sartem 				d = hal_device_store_find (hald_get_gdl (), udi_to_merge_from);
1175*18c2aff7Sartem 				if (d == NULL) {
1176*18c2aff7Sartem 					d = hal_device_store_find (hald_get_tdl (), udi_to_merge_from);
1177*18c2aff7Sartem 				}
1178*18c2aff7Sartem 				if (d == NULL) {
1179*18c2aff7Sartem 					HAL_ERROR (("Could not find device with udi '%s'", udi_to_merge_from));
1180*18c2aff7Sartem 				} else {
1181*18c2aff7Sartem 					hal_device_copy_property (d, prop_to_merge, pc->device, pc->merge_key);
1182*18c2aff7Sartem 				}
1183*18c2aff7Sartem 			}
1184*18c2aff7Sartem 			break;
1185*18c2aff7Sartem 		}
1186*18c2aff7Sartem 
1187*18c2aff7Sartem 		default:
1188*18c2aff7Sartem 			HAL_ERROR (("Unknown merge_type=%d='%c'",
1189*18c2aff7Sartem 				    pc->merge_type, pc->merge_type));
1190*18c2aff7Sartem 			break;
1191*18c2aff7Sartem 		}
1192*18c2aff7Sartem 	} else if (pc->curelem == CURELEM_APPEND && pc->match_ok &&
1193*18c2aff7Sartem 		   (hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_STRING ||
1194*18c2aff7Sartem 		    hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_STRLIST ||
1195*18c2aff7Sartem 		    hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_INVALID)) {
1196*18c2aff7Sartem 		char buf[256];
1197*18c2aff7Sartem 		char buf2[256];
1198*18c2aff7Sartem 
1199*18c2aff7Sartem 		/* As soon as we are appending, we have matched the device... */
1200*18c2aff7Sartem 		pc->device_matched = TRUE;
1201*18c2aff7Sartem 
1202*18c2aff7Sartem 		if (pc->merge_type == MERGE_TYPE_STRLIST) {
1203*18c2aff7Sartem 			hal_device_property_strlist_append (pc->device, pc->merge_key, pc->cdata_buf);
1204*18c2aff7Sartem 		} else {
1205*18c2aff7Sartem 			const char *existing_string;
1206*18c2aff7Sartem 
1207*18c2aff7Sartem 			switch (pc->merge_type) {
1208*18c2aff7Sartem 			case MERGE_TYPE_STRING:
1209*18c2aff7Sartem 				strncpy (buf, pc->cdata_buf, sizeof (buf));
1210*18c2aff7Sartem 				break;
1211*18c2aff7Sartem 
1212*18c2aff7Sartem 			case MERGE_TYPE_COPY_PROPERTY:
1213*18c2aff7Sartem 				hal_device_property_get_as_string (pc->device, pc->cdata_buf, buf, sizeof (buf));
1214*18c2aff7Sartem 				break;
1215*18c2aff7Sartem 
1216*18c2aff7Sartem 			default:
1217*18c2aff7Sartem 				HAL_ERROR (("Unknown merge_type=%d='%c'", pc->merge_type, pc->merge_type));
1218*18c2aff7Sartem 				break;
1219*18c2aff7Sartem 			}
1220*18c2aff7Sartem 
1221*18c2aff7Sartem 			existing_string = hal_device_property_get_string (pc->device, pc->merge_key);
1222*18c2aff7Sartem 			if (existing_string != NULL) {
1223*18c2aff7Sartem 				strncpy (buf2, existing_string, sizeof (buf2));
1224*18c2aff7Sartem 				strncat (buf2, buf, sizeof (buf2) - strlen(buf2));
1225*18c2aff7Sartem 			} else {
1226*18c2aff7Sartem 				strncpy (buf2, buf, sizeof (buf2));
1227*18c2aff7Sartem 			}
1228*18c2aff7Sartem 			hal_device_property_set_string (pc->device, pc->merge_key, buf2);
1229*18c2aff7Sartem 		}
1230*18c2aff7Sartem 	} else if (pc->curelem == CURELEM_PREPEND && pc->match_ok &&
1231*18c2aff7Sartem 		   (hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_STRING ||
1232*18c2aff7Sartem 		    hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_STRLIST ||
1233*18c2aff7Sartem 		    hal_device_property_get_type (pc->device, pc->merge_key) == HAL_PROPERTY_TYPE_INVALID)) {
1234*18c2aff7Sartem 		char buf[256];
1235*18c2aff7Sartem 		char buf2[256];
1236*18c2aff7Sartem 
1237*18c2aff7Sartem 		/* As soon as we are prepending, we have matched the device... */
1238*18c2aff7Sartem 		pc->device_matched = TRUE;
1239*18c2aff7Sartem 
1240*18c2aff7Sartem 		if (pc->merge_type == MERGE_TYPE_STRLIST) {
1241*18c2aff7Sartem 			hal_device_property_strlist_prepend (pc->device, pc->merge_key, pc->cdata_buf);
1242*18c2aff7Sartem 		} else {
1243*18c2aff7Sartem 			const char *existing_string;
1244*18c2aff7Sartem 
1245*18c2aff7Sartem 			switch (pc->merge_type) {
1246*18c2aff7Sartem 			case MERGE_TYPE_STRING:
1247*18c2aff7Sartem 				strncpy (buf, pc->cdata_buf, sizeof (buf));
1248*18c2aff7Sartem 				break;
1249*18c2aff7Sartem 
1250*18c2aff7Sartem 			case MERGE_TYPE_COPY_PROPERTY:
1251*18c2aff7Sartem 				hal_device_property_get_as_string (pc->device, pc->cdata_buf, buf, sizeof (buf));
1252*18c2aff7Sartem 				break;
1253*18c2aff7Sartem 
1254*18c2aff7Sartem 			default:
1255*18c2aff7Sartem 				HAL_ERROR (("Unknown merge_type=%d='%c'", pc->merge_type, pc->merge_type));
1256*18c2aff7Sartem 				break;
1257*18c2aff7Sartem 			}
1258*18c2aff7Sartem 
1259*18c2aff7Sartem 			existing_string = hal_device_property_get_string (pc->device, pc->merge_key);
1260*18c2aff7Sartem 			if (existing_string != NULL) {
1261*18c2aff7Sartem 				strncpy (buf2, buf, sizeof (buf2));
1262*18c2aff7Sartem 				strncat (buf2, existing_string, sizeof (buf2) - strlen(buf2));
1263*18c2aff7Sartem 			} else {
1264*18c2aff7Sartem 				strncpy (buf2, buf, sizeof (buf2));
1265*18c2aff7Sartem 			}
1266*18c2aff7Sartem 			hal_device_property_set_string (pc->device, pc->merge_key, buf2);
1267*18c2aff7Sartem 		}
1268*18c2aff7Sartem 	} else if (pc->curelem == CURELEM_REMOVE && pc->match_ok) {
1269*18c2aff7Sartem 
1270*18c2aff7Sartem 		if (pc->merge_type == MERGE_TYPE_STRLIST) {
1271*18c2aff7Sartem 			/* covers <remove key="foobar" type="strlist">blah</remove> */
1272*18c2aff7Sartem 			hal_device_property_strlist_remove (pc->device, pc->merge_key, pc->cdata_buf);
1273*18c2aff7Sartem 		} else {
1274*18c2aff7Sartem 			/* only allow <remove key="foobar"/>, not <remove key="foobar">blah</remove> */
1275*18c2aff7Sartem 			if (strlen (pc->cdata_buf) == 0) {
1276*18c2aff7Sartem 				hal_device_property_remove (pc->device, pc->merge_key);
1277*18c2aff7Sartem 			}
1278*18c2aff7Sartem 		}
1279*18c2aff7Sartem 	} else if (pc->merge_type == MERGE_TYPE_SPAWN) {
1280*18c2aff7Sartem 		HalDevice *spawned;
1281*18c2aff7Sartem 
1282*18c2aff7Sartem 		spawned = hal_device_store_find (hald_get_gdl (), pc->merge_key);
1283*18c2aff7Sartem 		if (spawned == NULL)
1284*18c2aff7Sartem 			spawned = hal_device_store_find (hald_get_tdl (), pc->merge_key);
1285*18c2aff7Sartem 
1286*18c2aff7Sartem 		if (spawned == NULL) {
1287*18c2aff7Sartem 			HAL_INFO (("Spawning new device object '%s' caused by <spawn> on udi '%s'",
1288*18c2aff7Sartem 				   pc->merge_key, pc->device->udi));
1289*18c2aff7Sartem 
1290*18c2aff7Sartem 			spawned = hal_device_new ();
1291*18c2aff7Sartem 			hal_device_property_set_string (spawned, "info.bus", "unknown");
1292*18c2aff7Sartem 			hal_device_property_set_string (spawned, "info.udi", pc->merge_key);
1293*18c2aff7Sartem 			hal_device_property_set_string (spawned, "info.parent", pc->device->udi);
1294*18c2aff7Sartem 			hal_device_set_udi (spawned, pc->merge_key);
1295*18c2aff7Sartem 
1296*18c2aff7Sartem 			hal_device_store_add (hald_get_tdl (), spawned);
1297*18c2aff7Sartem 
1298*18c2aff7Sartem 			di_search_and_merge (spawned, DEVICE_INFO_TYPE_INFORMATION);
1299*18c2aff7Sartem 			di_search_and_merge (spawned, DEVICE_INFO_TYPE_POLICY);
1300*18c2aff7Sartem 
1301*18c2aff7Sartem 			hal_util_callout_device_add (spawned, spawned_device_callouts_add_done, NULL, NULL);
1302*18c2aff7Sartem 		}
1303*18c2aff7Sartem 
1304*18c2aff7Sartem 	} else if (pc->curelem == CURELEM_CLEAR && pc->match_ok) {
1305*18c2aff7Sartem 		if (pc->merge_type == MERGE_TYPE_CLEAR) {
1306*18c2aff7Sartem 			hal_device_property_strlist_clear (pc->device, pc->merge_key);
1307*18c2aff7Sartem 		}
1308*18c2aff7Sartem 	}
1309*18c2aff7Sartem 
1310*18c2aff7Sartem 
1311*18c2aff7Sartem 	pc->cdata_buf_len = 0;
1312*18c2aff7Sartem 	pc->depth--;
1313*18c2aff7Sartem 
1314*18c2aff7Sartem 	/* maintain curelem */
1315*18c2aff7Sartem 	pc->curelem = pc->curelem_stack[pc->depth];
1316*18c2aff7Sartem 
1317*18c2aff7Sartem 	/* maintain pc->match_ok */
1318*18c2aff7Sartem 	if (pc->depth <= pc->match_depth_first_fail)
1319*18c2aff7Sartem 		pc->match_ok = TRUE;
1320*18c2aff7Sartem }
1321*18c2aff7Sartem 
1322*18c2aff7Sartem /** Called when there is CDATA
1323*18c2aff7Sartem  *
1324*18c2aff7Sartem  *  @param  pc                  Parsing context
1325*18c2aff7Sartem  *  @param  s                   Pointer to data
1326*18c2aff7Sartem  *  @param  len                 Length of data
1327*18c2aff7Sartem  */
1328*18c2aff7Sartem static void
cdata(ParsingContext * pc,const char * s,int len)1329*18c2aff7Sartem cdata (ParsingContext * pc, const char *s, int len)
1330*18c2aff7Sartem {
1331*18c2aff7Sartem 	int bytes_left;
1332*18c2aff7Sartem 	int bytes_to_copy;
1333*18c2aff7Sartem 
1334*18c2aff7Sartem 	if (pc->aborted)
1335*18c2aff7Sartem 		return;
1336*18c2aff7Sartem 
1337*18c2aff7Sartem 	bytes_left = CDATA_BUF_SIZE - pc->cdata_buf_len;
1338*18c2aff7Sartem 	if (len > bytes_left) {
1339*18c2aff7Sartem 		HAL_ERROR (("CDATA in element larger than %d",
1340*18c2aff7Sartem 			    CDATA_BUF_SIZE));
1341*18c2aff7Sartem 	}
1342*18c2aff7Sartem 
1343*18c2aff7Sartem 	bytes_to_copy = len;
1344*18c2aff7Sartem 	if (bytes_to_copy > bytes_left)
1345*18c2aff7Sartem 		bytes_to_copy = bytes_left;
1346*18c2aff7Sartem 
1347*18c2aff7Sartem 	if (bytes_to_copy > 0)
1348*18c2aff7Sartem 		memcpy (pc->cdata_buf + pc->cdata_buf_len, s,
1349*18c2aff7Sartem 			bytes_to_copy);
1350*18c2aff7Sartem 
1351*18c2aff7Sartem 	pc->cdata_buf_len += bytes_to_copy;
1352*18c2aff7Sartem }
1353*18c2aff7Sartem 
1354*18c2aff7Sartem 
1355*18c2aff7Sartem /** Process a device information info file.
1356*18c2aff7Sartem  *
1357*18c2aff7Sartem  *  @param  dir                 Directory file resides in
1358*18c2aff7Sartem  *  @param  filename            File name
1359*18c2aff7Sartem  *  @param  device              Device to match on
1360*18c2aff7Sartem  *  @return                     #TRUE if file matched device and information
1361*18c2aff7Sartem  *                              was merged
1362*18c2aff7Sartem  */
1363*18c2aff7Sartem static dbus_bool_t
process_fdi_file(const char * dir,const char * filename,HalDevice * device)1364*18c2aff7Sartem process_fdi_file (const char *dir, const char *filename,
1365*18c2aff7Sartem 		  HalDevice * device)
1366*18c2aff7Sartem {
1367*18c2aff7Sartem 	int rc;
1368*18c2aff7Sartem 	char buf[512];
1369*18c2aff7Sartem 	FILE *file;
1370*18c2aff7Sartem 	int filesize;
1371*18c2aff7Sartem 	size_t read;
1372*18c2aff7Sartem 	char *filebuf;
1373*18c2aff7Sartem 	dbus_bool_t device_matched;
1374*18c2aff7Sartem 	XML_Parser parser;
1375*18c2aff7Sartem 	ParsingContext *parsing_context;
1376*18c2aff7Sartem 
1377*18c2aff7Sartem 	file = NULL;
1378*18c2aff7Sartem 	filebuf = NULL;
1379*18c2aff7Sartem 	parser = NULL;
1380*18c2aff7Sartem 	parsing_context = NULL;
1381*18c2aff7Sartem 
1382*18c2aff7Sartem 	device_matched = FALSE;
1383*18c2aff7Sartem 
1384*18c2aff7Sartem 	snprintf (buf, sizeof (buf), "%s/%s", dir, filename);
1385*18c2aff7Sartem 
1386*18c2aff7Sartem 	/*HAL_INFO(("analyzing file %s", buf));*/
1387*18c2aff7Sartem 
1388*18c2aff7Sartem 	/* open file and read it into a buffer; it's a small file... */
1389*18c2aff7Sartem 	file = fopen (buf, "r");
1390*18c2aff7Sartem 	if (file == NULL) {
1391*18c2aff7Sartem 		HAL_ERROR (("Could not open file %s", buf));
1392*18c2aff7Sartem 		goto out;
1393*18c2aff7Sartem 	}
1394*18c2aff7Sartem 
1395*18c2aff7Sartem 	fseek (file, 0L, SEEK_END);
1396*18c2aff7Sartem 	filesize = (int) ftell (file);
1397*18c2aff7Sartem 	rewind (file);
1398*18c2aff7Sartem 	filebuf = (char *) malloc (filesize);
1399*18c2aff7Sartem 	if (filebuf == NULL) {
1400*18c2aff7Sartem 		HAL_ERROR (("Could not allocate %d bytes for file %s", filesize, buf));
1401*18c2aff7Sartem 		goto out;
1402*18c2aff7Sartem 	}
1403*18c2aff7Sartem 	read = fread (filebuf, sizeof (char), filesize, file);
1404*18c2aff7Sartem 
1405*18c2aff7Sartem 	/* initialize parsing context */
1406*18c2aff7Sartem 	parsing_context =
1407*18c2aff7Sartem 	    (ParsingContext *) malloc (sizeof (ParsingContext));
1408*18c2aff7Sartem 	if (parsing_context == NULL) {
1409*18c2aff7Sartem 		HAL_ERROR (("Could not allocate parsing context"));
1410*18c2aff7Sartem 		goto out;
1411*18c2aff7Sartem 	}
1412*18c2aff7Sartem 
1413*18c2aff7Sartem 	/* TODO: reuse parser
1414*18c2aff7Sartem 	 */
1415*18c2aff7Sartem 	parser = XML_ParserCreate (NULL);
1416*18c2aff7Sartem 	if (parser == NULL) {
1417*18c2aff7Sartem 		HAL_ERROR (("Could not allocate XML parser"));
1418*18c2aff7Sartem 		goto out;
1419*18c2aff7Sartem 	}
1420*18c2aff7Sartem 
1421*18c2aff7Sartem 	parsing_context->depth = 0;
1422*18c2aff7Sartem 	parsing_context->device_matched = FALSE;
1423*18c2aff7Sartem 	parsing_context->match_ok = TRUE;
1424*18c2aff7Sartem 	parsing_context->curelem = CURELEM_UNKNOWN;
1425*18c2aff7Sartem 	parsing_context->aborted = FALSE;
1426*18c2aff7Sartem 	parsing_context->file = buf;
1427*18c2aff7Sartem 	parsing_context->parser = parser;
1428*18c2aff7Sartem 	parsing_context->device = device;
1429*18c2aff7Sartem 	parsing_context->match_depth_first_fail = -1;
1430*18c2aff7Sartem 
1431*18c2aff7Sartem 	XML_SetElementHandler (parser,
1432*18c2aff7Sartem 			       (XML_StartElementHandler) start,
1433*18c2aff7Sartem 			       (XML_EndElementHandler) end);
1434*18c2aff7Sartem 	XML_SetCharacterDataHandler (parser,
1435*18c2aff7Sartem 				     (XML_CharacterDataHandler) cdata);
1436*18c2aff7Sartem 	XML_SetUserData (parser, parsing_context);
1437*18c2aff7Sartem 
1438*18c2aff7Sartem 	rc = XML_Parse (parser, filebuf, filesize, 1);
1439*18c2aff7Sartem 	/*printf("XML_Parse rc=%d\r\n", rc); */
1440*18c2aff7Sartem 
1441*18c2aff7Sartem 	if (rc == 0) {
1442*18c2aff7Sartem 		/* error parsing document */
1443*18c2aff7Sartem 		HAL_ERROR (("Error parsing XML document %s at line %d, "
1444*18c2aff7Sartem 			    "column %d : %s",
1445*18c2aff7Sartem 			    buf,
1446*18c2aff7Sartem 			    XML_GetCurrentLineNumber (parser),
1447*18c2aff7Sartem 			    XML_GetCurrentColumnNumber (parser),
1448*18c2aff7Sartem 			    XML_ErrorString (XML_GetErrorCode (parser))));
1449*18c2aff7Sartem 		device_matched = FALSE;
1450*18c2aff7Sartem 	} else {
1451*18c2aff7Sartem 		/* document parsed ok */
1452*18c2aff7Sartem 		device_matched = parsing_context->device_matched;
1453*18c2aff7Sartem 	}
1454*18c2aff7Sartem 
1455*18c2aff7Sartem out:
1456*18c2aff7Sartem 	if (filebuf != NULL)
1457*18c2aff7Sartem 		free (filebuf);
1458*18c2aff7Sartem 	if (file != NULL)
1459*18c2aff7Sartem 		fclose (file);
1460*18c2aff7Sartem 	if (parser != NULL)
1461*18c2aff7Sartem 		XML_ParserFree (parser);
1462*18c2aff7Sartem 	if (parsing_context != NULL)
1463*18c2aff7Sartem 		free (parsing_context);
1464*18c2aff7Sartem 
1465*18c2aff7Sartem 	return device_matched;
1466*18c2aff7Sartem }
1467*18c2aff7Sartem 
1468*18c2aff7Sartem 
1469*18c2aff7Sartem 
1470*18c2aff7Sartem static int
1471*18c2aff7Sartem #ifdef __GLIBC__
my_alphasort(const void * a,const void * b)1472*18c2aff7Sartem my_alphasort(const void *a, const void *b)
1473*18c2aff7Sartem #else
1474*18c2aff7Sartem my_alphasort(const struct dirent **a, const struct dirent **b)
1475*18c2aff7Sartem #endif
1476*18c2aff7Sartem {
1477*18c2aff7Sartem 	return -alphasort (a, b);
1478*18c2aff7Sartem }
1479*18c2aff7Sartem 
1480*18c2aff7Sartem 
1481*18c2aff7Sartem /** Scan all directories and subdirectories in the given directory and
1482*18c2aff7Sartem  *  process each *.fdi file
1483*18c2aff7Sartem  *
1484*18c2aff7Sartem  *  @param  d                   Device to merge information into
1485*18c2aff7Sartem  *  @return                     #TRUE if information was merged
1486*18c2aff7Sartem  */
1487*18c2aff7Sartem static dbus_bool_t
scan_fdi_files(const char * dir,HalDevice * d)1488*18c2aff7Sartem scan_fdi_files (const char *dir, HalDevice * d)
1489*18c2aff7Sartem {
1490*18c2aff7Sartem 	int i;
1491*18c2aff7Sartem 	int num_entries;
1492*18c2aff7Sartem 	dbus_bool_t found_fdi_file;
1493*18c2aff7Sartem 	struct dirent **name_list;
1494*18c2aff7Sartem 
1495*18c2aff7Sartem 	found_fdi_file = 0;
1496*18c2aff7Sartem 
1497*18c2aff7Sartem 	/*HAL_INFO(("scan_fdi_files: Processing dir '%s'", dir));*/
1498*18c2aff7Sartem 
1499*18c2aff7Sartem 	num_entries = scandir (dir, &name_list, 0, my_alphasort);
1500*18c2aff7Sartem 	if (num_entries == -1) {
1501*18c2aff7Sartem 		return FALSE;
1502*18c2aff7Sartem 	}
1503*18c2aff7Sartem 
1504*18c2aff7Sartem 	for (i = num_entries - 1; i >= 0; i--) {
1505*18c2aff7Sartem 		int len;
1506*18c2aff7Sartem 		char *filename;
1507*18c2aff7Sartem 		gchar *full_path;
1508*18c2aff7Sartem 
1509*18c2aff7Sartem 		filename = name_list[i]->d_name;
1510*18c2aff7Sartem 		len = strlen (filename);
1511*18c2aff7Sartem 
1512*18c2aff7Sartem 		full_path = g_strdup_printf ("%s/%s", dir, filename);
1513*18c2aff7Sartem 		/*HAL_INFO (("Full path = %s", full_path));*/
1514*18c2aff7Sartem 
1515*18c2aff7Sartem 		/* Mmm, d_type can be DT_UNKNOWN, use glib to determine
1516*18c2aff7Sartem 		 * the type
1517*18c2aff7Sartem 		 */
1518*18c2aff7Sartem 		if (g_file_test (full_path, (G_FILE_TEST_IS_REGULAR))) {
1519*18c2aff7Sartem 			/* regular file */
1520*18c2aff7Sartem 
1521*18c2aff7Sartem 			if (len >= 5 &&
1522*18c2aff7Sartem 			    filename[len - 4] == '.' &&
1523*18c2aff7Sartem 			    filename[len - 3] == 'f' &&
1524*18c2aff7Sartem 			    filename[len - 2] == 'd' &&
1525*18c2aff7Sartem 			    filename[len - 1] == 'i') {
1526*18c2aff7Sartem 				/*HAL_INFO (("scan_fdi_files: Processing file '%s'", filename));*/
1527*18c2aff7Sartem 				found_fdi_file = process_fdi_file (dir, filename, d);
1528*18c2aff7Sartem 				if (found_fdi_file) {
1529*18c2aff7Sartem 					HAL_INFO (("*** Matched file %s/%s", dir, filename));
1530*18c2aff7Sartem 					/*break;*/
1531*18c2aff7Sartem 				}
1532*18c2aff7Sartem 			}
1533*18c2aff7Sartem 
1534*18c2aff7Sartem 		} else if (g_file_test (full_path, (G_FILE_TEST_IS_DIR))
1535*18c2aff7Sartem 			   && strcmp (filename, ".") != 0
1536*18c2aff7Sartem 			   && strcmp (filename, "..") != 0) {
1537*18c2aff7Sartem 			int num_bytes;
1538*18c2aff7Sartem 			char *dirname;
1539*18c2aff7Sartem 
1540*18c2aff7Sartem 			/* Directory; do the recursion thingy but not
1541*18c2aff7Sartem 			 * for . and ..
1542*18c2aff7Sartem 			 */
1543*18c2aff7Sartem 
1544*18c2aff7Sartem 			num_bytes = len + strlen (dir) + 1 + 1;
1545*18c2aff7Sartem 			dirname = (char *) malloc (num_bytes);
1546*18c2aff7Sartem 			if (dirname == NULL) {
1547*18c2aff7Sartem 				HAL_ERROR (("couldn't allocated %d bytes",
1548*18c2aff7Sartem 					    num_bytes));
1549*18c2aff7Sartem 				break;
1550*18c2aff7Sartem 			}
1551*18c2aff7Sartem 
1552*18c2aff7Sartem 			snprintf (dirname, num_bytes, "%s/%s", dir,
1553*18c2aff7Sartem 				  filename);
1554*18c2aff7Sartem 			found_fdi_file = scan_fdi_files (dirname, d);
1555*18c2aff7Sartem 			free (dirname);
1556*18c2aff7Sartem 			/*
1557*18c2aff7Sartem 			if (found_fdi_file)
1558*18c2aff7Sartem 				break;
1559*18c2aff7Sartem 			*/
1560*18c2aff7Sartem 		}
1561*18c2aff7Sartem 
1562*18c2aff7Sartem 		g_free (full_path);
1563*18c2aff7Sartem 
1564*18c2aff7Sartem 		free (name_list[i]);
1565*18c2aff7Sartem 	}
1566*18c2aff7Sartem 
1567*18c2aff7Sartem 	for (; i >= 0; i--) {
1568*18c2aff7Sartem 		free (name_list[i]);
1569*18c2aff7Sartem 	}
1570*18c2aff7Sartem 
1571*18c2aff7Sartem 	free (name_list);
1572*18c2aff7Sartem 
1573*18c2aff7Sartem 	return found_fdi_file;
1574*18c2aff7Sartem }
1575*18c2aff7Sartem 
1576*18c2aff7Sartem /** Search the device info file repository for a .fdi file to merge
1577*18c2aff7Sartem  *  more information into the device object.
1578*18c2aff7Sartem  *
1579*18c2aff7Sartem  *  @param  d                   Device to merge information into
1580*18c2aff7Sartem  *  @return                     #TRUE if information was merged
1581*18c2aff7Sartem  */
1582*18c2aff7Sartem dbus_bool_t
di_search_and_merge(HalDevice * d,DeviceInfoType type)1583*18c2aff7Sartem di_search_and_merge (HalDevice *d, DeviceInfoType type)
1584*18c2aff7Sartem {
1585*18c2aff7Sartem 	static gboolean have_checked_hal_fdi_source = FALSE;
1586*18c2aff7Sartem 	static char *hal_fdi_source_preprobe = NULL;
1587*18c2aff7Sartem 	static char *hal_fdi_source_information = NULL;
1588*18c2aff7Sartem 	static char *hal_fdi_source_policy = NULL;
1589*18c2aff7Sartem 	dbus_bool_t ret;
1590*18c2aff7Sartem 	char *s1;
1591*18c2aff7Sartem 	char *s2;
1592*18c2aff7Sartem 
1593*18c2aff7Sartem 	ret = FALSE;
1594*18c2aff7Sartem 
1595*18c2aff7Sartem 	if (!have_checked_hal_fdi_source) {
1596*18c2aff7Sartem 		hal_fdi_source_preprobe    = getenv ("HAL_FDI_SOURCE_PREPROBE");
1597*18c2aff7Sartem 		hal_fdi_source_information = getenv ("HAL_FDI_SOURCE_INFORMATION");
1598*18c2aff7Sartem 		hal_fdi_source_policy      = getenv ("HAL_FDI_SOURCE_POLICY");
1599*18c2aff7Sartem 		have_checked_hal_fdi_source = TRUE;
1600*18c2aff7Sartem 	}
1601*18c2aff7Sartem 
1602*18c2aff7Sartem 	switch (type) {
1603*18c2aff7Sartem 	case DEVICE_INFO_TYPE_PREPROBE:
1604*18c2aff7Sartem 		if (hal_fdi_source_preprobe != NULL) {
1605*18c2aff7Sartem 			s1 = hal_fdi_source_preprobe;
1606*18c2aff7Sartem 			s2 = NULL;
1607*18c2aff7Sartem 		} else {
1608*18c2aff7Sartem 			s1 = PACKAGE_DATA_DIR "/hal/fdi/preprobe";
1609*18c2aff7Sartem 			s2 = PACKAGE_SYSCONF_DIR "/hal/fdi/preprobe";
1610*18c2aff7Sartem 		}
1611*18c2aff7Sartem 		break;
1612*18c2aff7Sartem 
1613*18c2aff7Sartem 	case DEVICE_INFO_TYPE_INFORMATION:
1614*18c2aff7Sartem 		if (hal_fdi_source_information != NULL) {
1615*18c2aff7Sartem 			s1 = hal_fdi_source_information;
1616*18c2aff7Sartem 			s2 = NULL;
1617*18c2aff7Sartem 		} else {
1618*18c2aff7Sartem 			s1 = PACKAGE_DATA_DIR "/hal/fdi/information";
1619*18c2aff7Sartem 			s2 = PACKAGE_SYSCONF_DIR "/hal/fdi/information";
1620*18c2aff7Sartem 		}
1621*18c2aff7Sartem 		break;
1622*18c2aff7Sartem 
1623*18c2aff7Sartem 	case DEVICE_INFO_TYPE_POLICY:
1624*18c2aff7Sartem 		if (hal_fdi_source_policy != NULL) {
1625*18c2aff7Sartem 			s1 = hal_fdi_source_policy;
1626*18c2aff7Sartem 			s2 = NULL;
1627*18c2aff7Sartem 		} else {
1628*18c2aff7Sartem 			s1 = PACKAGE_DATA_DIR "/hal/fdi/policy";
1629*18c2aff7Sartem 			s2 = PACKAGE_SYSCONF_DIR "/hal/fdi/policy";
1630*18c2aff7Sartem 		}
1631*18c2aff7Sartem 		break;
1632*18c2aff7Sartem 
1633*18c2aff7Sartem 	default:
1634*18c2aff7Sartem 		s1 = NULL;
1635*18c2aff7Sartem 		s2 = NULL;
1636*18c2aff7Sartem 		HAL_ERROR (("Bogus device information type %d", type));
1637*18c2aff7Sartem 		break;
1638*18c2aff7Sartem 	}
1639*18c2aff7Sartem 
1640*18c2aff7Sartem 	if (s1 != NULL)
1641*18c2aff7Sartem 		ret = scan_fdi_files (s1, d) || ret;
1642*18c2aff7Sartem 	if (s2 != NULL)
1643*18c2aff7Sartem 		ret = scan_fdi_files (s2, d) || ret;
1644*18c2aff7Sartem 
1645*18c2aff7Sartem 	return ret;
1646*18c2aff7Sartem }
1647*18c2aff7Sartem 
1648*18c2aff7Sartem /** @} */
1649