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