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 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 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 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 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 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 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 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 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 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 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 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 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 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 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__ 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 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 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