1 /** 2 * Copyright(c) 2011 Trusted Logic. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name Trusted Logic nor the names of its 15 * contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <stdlib.h> 32 #include <assert.h> 33 #include <stdio.h> 34 #include <ctype.h> 35 #include <string.h> 36 37 #if defined(_WIN32_WCE) 38 #include "os_wm.h" 39 #else 40 #include <errno.h> 41 #endif 42 43 #include "smc_properties_parser.h" 44 #include "lib_manifest2.h" 45 #include "s_error.h" 46 47 /* --------------------------------------------------------------------------------- 48 Defines 49 ---------------------------------------------------------------------------------*/ 50 51 #define STRUE "true" 52 #define SFALSE "false" 53 54 #if defined(_WIN32_WCE) 55 #define GET_LAST_ERR GetLastError() 56 #else 57 #define GET_LAST_ERR errno 58 #endif 59 60 #if defined (LINUX) || defined (__SYMBIAN32__) || defined (__ANDROID32__) 61 #define STRICMP strcasecmp 62 #elif defined(_WIN32_WCE) 63 #define STRICMP _stricmp 64 #else 65 #define STRICMP stricmp 66 #endif 67 68 69 /* --------------------------------------------------------------------------------- 70 Logs and Traces. 71 ---------------------------------------------------------------------------------*/ 72 #ifdef __SYMBIAN32__ 73 #include "os_symbian.h" 74 #elif NDEBUG 75 /* Compile-out the traces */ 76 #define TRACE_ERROR(...) 77 #define TRACE_WARNING(...) 78 #define TRACE_INFO(...) 79 #else 80 #include <stdarg.h> 81 static void TRACE_ERROR(const char* format, ...) 82 { 83 va_list ap; 84 va_start(ap, format); 85 fprintf(stderr, "TRACE: ERROR: "); 86 vfprintf(stderr, format, ap); 87 fprintf(stderr, "\n"); 88 va_end(ap); 89 } 90 91 static void TRACE_WARNING(const char* format, ...) 92 { 93 va_list ap; 94 va_start(ap, format); 95 fprintf(stderr, "TRACE: WARNING: "); 96 vfprintf(stderr, format, ap); 97 fprintf(stderr, "\n"); 98 va_end(ap); 99 } 100 101 static void TRACE_INFO(const char* format, ...) 102 { 103 va_list ap; 104 va_start(ap, format); 105 fprintf(stderr, "TRACE: "); 106 vfprintf(stderr, format, ap); 107 fprintf(stderr, "\n"); 108 va_end(ap); 109 } 110 #endif /* NDEBUG */ 111 112 /* --------------------------------------------------------------------------------- 113 private functions. 114 ---------------------------------------------------------------------------------*/ 115 116 static NODE* static_listFindNodeElement(NODE* pList,char* pName,bool bIsCaseSensitive) 117 { 118 int32_t nCmp; 119 120 assert(pName!=NULL); 121 122 while (pList!=NULL) 123 { 124 if (bIsCaseSensitive) 125 { 126 nCmp=strcmp(pName,pList->pName); 127 } 128 else 129 { 130 nCmp=STRICMP(pName,pList->pName); 131 } 132 if (nCmp>0) 133 { 134 pList=pList->pRight; 135 } 136 else if (nCmp<0) 137 { 138 pList=pList->pLeft; 139 } 140 else 141 { 142 break; 143 } 144 } 145 return pList; 146 } 147 148 149 static S_RESULT static_listSortedAddNode(NODE* pList,NODE* pNode) 150 { 151 int32_t nCmp; 152 153 do { 154 nCmp=strcmp(pNode->pName,pList->pName); 155 if (nCmp>0) 156 { 157 if (pList->pRight!=NULL) 158 { 159 pList=pList->pRight; 160 } 161 else 162 { 163 pList->pRight=pNode; 164 /* update linked list */ 165 pNode->pPrevious=pList; 166 pNode->pNext=pList->pNext; 167 if (pList->pNext!=NULL) 168 { 169 pList->pNext->pPrevious=pNode; 170 } 171 pList->pNext=pNode; 172 return S_SUCCESS; 173 } 174 } 175 else if (nCmp<0) 176 { 177 if (pList->pLeft!=NULL) 178 { 179 pList=pList->pLeft; 180 } 181 else 182 { 183 pList->pLeft=pNode; 184 /* update linked list */ 185 pNode->pNext=pList; 186 pNode->pPrevious=pList->pPrevious; 187 if (pList->pPrevious!=NULL) 188 { 189 pList->pPrevious->pNext=pNode; 190 } 191 pList->pPrevious=pNode; 192 return S_SUCCESS; 193 } 194 } 195 } while (nCmp!=0); 196 197 TRACE_ERROR("%s already exist !\n",pNode->pName); 198 return S_ERROR_ITEM_EXISTS; 199 } 200 201 202 static S_RESULT SMCPropListSortedAdd(LIST* pList,NODE* pNode) 203 { 204 S_RESULT nResult; 205 206 assert(pList!=NULL && pNode!=NULL); 207 208 if (pNode->pName==NULL) 209 { 210 TRACE_ERROR("Trying to insert a NULL node name !\n"); 211 return S_ERROR_BAD_PARAMETERS; 212 } 213 214 if (pList->pRoot==NULL) 215 { 216 pList->pRoot=pNode; 217 pList->pFirst=pNode; 218 return S_SUCCESS; 219 } 220 else 221 { 222 nResult=static_listSortedAddNode(pList->pRoot,pNode); 223 /* update the first node of the linked list */ 224 if (nResult==S_SUCCESS && pNode->pPrevious==NULL) 225 { 226 pList->pFirst=pNode; 227 } 228 } 229 return nResult; 230 } 231 232 233 static NODE* SMCPropListFindElement(LIST* pList,char* pName,bool bIsCaseSensitive) 234 { 235 if (pList->pRoot!=NULL) 236 { 237 return static_listFindNodeElement(pList->pRoot,pName,bIsCaseSensitive); 238 } 239 return NULL; 240 } 241 242 243 static S_RESULT SMCPropYacc(uint8_t* pBuffer, uint32_t nBufferLength, 244 CONF_FILE* pConfFile) 245 { 246 S_RESULT nError=S_SUCCESS; 247 LIST *pPublicPropertyList=NULL; 248 LIST *pPrivatePropertyList=NULL; 249 PROPERTY* pProperty=NULL; 250 SERVICE_SECTION* pServSection; 251 SERVICE_SECTION* pPreviousService=NULL; 252 253 uint8_t* pName; 254 uint32_t nNameLength; 255 uint8_t* pValue; 256 uint32_t nValueLength; 257 char* pNameZ = NULL; 258 char* pValueZ = NULL; 259 LIB_MANIFEST2_CONTEXT sParserContext; 260 char serviceManifestName[1024]; 261 262 sParserContext.pManifestName = "Configuration File"; 263 sParserContext.pManifestContent = pBuffer; 264 sParserContext.nManifestLength = nBufferLength; 265 sParserContext.nType = LIB_MANIFEST2_TYPE_SOURCE_WITH_SECTIONS; 266 267 libManifest2InitContext(&sParserContext); 268 269 while (true) 270 { 271 nError = libManifest2GetNextItem( 272 &sParserContext, 273 &pName, 274 &nNameLength, 275 &pValue, 276 &nValueLength); 277 if (nError == S_ERROR_ITEM_NOT_FOUND) 278 { 279 /* End of parsing */ 280 nError = S_SUCCESS; 281 break; 282 } 283 else if (nError != S_SUCCESS) 284 { 285 /* Error */ 286 goto error; 287 } 288 289 /* Duplicate name and value in as zero-terminated strings */ 290 /* Unclean: those strings are not going to be deallocated 291 This is not a problem because this code is run in a tool 292 */ 293 pNameZ = malloc(nNameLength+1); 294 if (pNameZ == NULL) 295 { 296 nError = S_ERROR_OUT_OF_MEMORY; 297 goto error; 298 } 299 memcpy(pNameZ, pName, nNameLength); 300 pNameZ[nNameLength] = 0; 301 302 if (pValue == NULL) 303 { 304 /* It's a section */ 305 if (STRICMP(pNameZ, SYSTEM_SECTION_NAME) == 0) 306 { 307 free(pNameZ); 308 pPublicPropertyList=&pConfFile->sSystemSectionPropertyList; 309 } 310 else 311 { 312 pServSection=(SERVICE_SECTION*)SMCPropListFindElement( 313 &pConfFile->sDriverSectionList, 314 pNameZ, 315 false); 316 if (pServSection==NULL) 317 { 318 pServSection=(SERVICE_SECTION*)SMCPropListFindElement( 319 &pConfFile->sPreinstalledSectionList, 320 pNameZ, 321 false); 322 } 323 if (pServSection==NULL) 324 { 325 pServSection=(SERVICE_SECTION*)SMCPropListFindElement( 326 &pConfFile->sSectionList, 327 pNameZ, 328 false); 329 if (pServSection==NULL) 330 { 331 nError=S_ERROR_ITEM_NOT_FOUND; 332 goto error; 333 } 334 } 335 free(pNameZ); 336 337 pServSection->inSCF=true; 338 if (pPreviousService!=NULL) 339 { 340 pPreviousService->pNextInSCF=pServSection; 341 } 342 else 343 { 344 pConfFile->pFirstSectionInSCF=pServSection; 345 } 346 pPreviousService=pServSection; 347 348 pPublicPropertyList=&pServSection->sPublicPropertyList; 349 pPrivatePropertyList=&pServSection->sPrivatePropertyList; 350 } 351 } 352 else 353 { 354 /* It's a property definition */ 355 pValueZ = malloc(nValueLength+1); 356 if (pValueZ == NULL) 357 { 358 nError = S_ERROR_OUT_OF_MEMORY; 359 goto error; 360 } 361 memcpy(pValueZ, pValue, nValueLength); 362 pValueZ[nValueLength] = 0; 363 364 pProperty=(PROPERTY*)malloc(sizeof(PROPERTY)); 365 if (pProperty==NULL) 366 { 367 nError=S_ERROR_OUT_OF_MEMORY; 368 goto error; 369 } 370 memset(pProperty, 0x00, sizeof(PROPERTY)); 371 pProperty->sNode.pName=pNameZ; 372 373 pProperty->pValue=pValueZ; 374 375 if (pPrivatePropertyList==NULL) 376 { 377 nError=SMCPropListSortedAdd(pPublicPropertyList,(NODE*)pProperty); 378 if (nError!=S_SUCCESS) 379 { 380 goto error; 381 } 382 } 383 else 384 { 385 if ((nValueLength > strlen(CONFIG_PROPERTY_NAME)) && 386 (memcmp(pProperty->sNode.pName, CONFIG_PROPERTY_NAME, strlen(CONFIG_PROPERTY_NAME)) == 0)) 387 { 388 nError=SMCPropListSortedAdd(pPrivatePropertyList,(NODE*)pProperty); 389 } 390 else 391 { 392 nError=SMCPropListSortedAdd(pPublicPropertyList,(NODE*)pProperty); 393 } 394 if (nError!=S_SUCCESS) 395 { 396 goto error; 397 } 398 } 399 } 400 } 401 402 error: 403 if (nError!=S_SUCCESS) 404 { 405 switch (nError) 406 { 407 case S_ERROR_BAD_FORMAT: 408 /* Error message already output */ 409 break; 410 case S_ERROR_WRONG_SIGNATURE: 411 TRACE_ERROR("Configuration file: wrong service UUID: %s\n", pValueZ); 412 break; 413 case S_ERROR_OUT_OF_MEMORY: 414 TRACE_ERROR("Out of memory\n"); 415 break; 416 case S_ERROR_ITEM_NOT_FOUND: 417 TRACE_ERROR("Configuration file: service \"%s\" not found\n", pNameZ); 418 break; 419 } 420 } 421 return nError; 422 } 423 424 425 S_RESULT static_readFile(const char* pFilename, void** ppFile, uint32_t* pnFileLength) 426 { 427 S_RESULT nResult = S_SUCCESS; 428 long nFilesize; 429 FILE* pFile = NULL; 430 void *pBuff = NULL; 431 432 // open file and get its size... 433 if ((pFile = fopen(pFilename, "rb")) == NULL) 434 { 435 TRACE_ERROR("static_readFile: fopen(%s) failed [%d]", pFilename, GET_LAST_ERR); 436 nResult = S_ERROR_ITEM_NOT_FOUND; 437 return nResult; 438 } 439 if (fseek(pFile, 0, SEEK_END) != 0) 440 { 441 TRACE_ERROR("static_readFile: fseek(%s) failed [%d]", pFilename, GET_LAST_ERR); 442 nResult = S_ERROR_UNDERLYING_OS; 443 goto error; 444 } 445 nFilesize = ftell(pFile); 446 if (nFilesize < 0) 447 { 448 TRACE_ERROR("static_readFile: ftell(%s) failed [%d]", pFilename, GET_LAST_ERR); 449 nResult = S_ERROR_UNDERLYING_OS; 450 goto error; 451 } 452 rewind(pFile); 453 454 // allocate the buffer 455 pBuff = malloc(nFilesize + 1); 456 if (pBuff == NULL) 457 { 458 TRACE_ERROR("static_readFile: out of memory"); 459 nResult = S_ERROR_OUT_OF_MEMORY; 460 goto error; 461 } 462 463 // read the file 464 if (fread(pBuff, sizeof(uint8_t), (size_t)nFilesize, pFile) != (size_t)nFilesize) 465 { 466 TRACE_ERROR("static_readFile: fread failed [%d]", GET_LAST_ERR); 467 nResult = S_ERROR_UNDERLYING_OS; 468 goto error; 469 } 470 ((char*)pBuff)[nFilesize] = 0; 471 472 *ppFile = pBuff; 473 *pnFileLength = nFilesize; 474 return S_SUCCESS; 475 476 error: 477 if (pBuff != NULL) 478 free(pBuff); 479 fclose(pFile); 480 481 *ppFile = NULL; 482 *pnFileLength = 0; 483 return nResult; 484 } 485 486 487 488 489 490 /* --------------------------------------------------------------------------------- 491 API functions. 492 ---------------------------------------------------------------------------------*/ 493 494 char* SMCPropGetSystemProperty(CONF_FILE* pConfFile, char* pPropertyName) 495 { 496 PROPERTY* pProperty; 497 498 pProperty=(PROPERTY*)SMCPropListFindElement( 499 &pConfFile->sSystemSectionPropertyList, 500 pPropertyName, 501 true); 502 if (pProperty!=NULL) 503 { 504 return pProperty->pValue; 505 } 506 return NULL; 507 } 508 509 uint32_t SMCPropGetSystemPropertyAsInt(CONF_FILE* pConfFile, char* pPropertyName) 510 { 511 uint32_t nValue; 512 char* pValue=SMCPropGetSystemProperty(pConfFile,pPropertyName); 513 514 if (libString2GetStringAsInt(pValue, &nValue) == S_SUCCESS) 515 { 516 return nValue; 517 } 518 return 0; 519 } 520 521 522 S_RESULT SMCPropParseConfigFile(char* pConfigFilename,CONF_FILE* pConfFile) 523 { 524 S_RESULT nError=S_SUCCESS; 525 void* pFile; 526 uint32_t nFileLength; 527 bool bReuseManifest; 528 529 assert(pConfFile!=NULL); 530 531 TRACE_INFO("Processing configuration file '%s'", pConfigFilename); 532 533 if(pConfigFilename != NULL) 534 { 535 nError=static_readFile(pConfigFilename,&pFile,&nFileLength); 536 if (nError!=S_SUCCESS) 537 { 538 goto error; 539 } 540 bReuseManifest = true; 541 } 542 else 543 { 544 assert(0); 545 } 546 547 nError=SMCPropYacc(pFile,nFileLength,pConfFile); 548 549 if(pConfigFilename != NULL) 550 { 551 free(pFile); 552 } 553 554 error: 555 return nError; 556 } 557