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