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