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