1/* 2 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23#include "kextfind_main.h" 24#include "kextfind_report.h" 25#include "kextfind_query.h" 26#include "kextfind_commands.h" 27#include "kext_tools_util.h" 28 29#include <IOKit/kext/OSKext.h> 30#include <IOKit/kext/OSKextPrivate.h> 31#include <IOKit/kext/fat_util.h> 32#include <IOKit/kext/macho_util.h> 33 34 35/******************************************************************************* 36* 37*******************************************************************************/ 38Boolean reportParseProperty( 39 CFMutableDictionaryRef element, 40 int argc __unused, 41 char * const argv[], 42 uint32_t * num_used, 43 void * user_data, 44 QEQueryError * error) 45{ 46 Boolean result = false; 47 uint32_t index = 1; 48 49 /* Fudge the predicate so we can use one eval callback. 50 */ 51 QEQueryElementSetPredicate(element, CFSTR(kPredNameProperty)); 52 53 /* Parse the property name to retrieve. 54 */ 55 if (!parseArgument(element, &argv[index], &index, user_data, error)) { 56 goto finish; 57 } 58 59 result = true; 60finish: 61 *num_used += index; 62 return result; 63} 64 65/******************************************************************************* 66* 67*******************************************************************************/ 68Boolean reportParseShorthand( 69 CFMutableDictionaryRef element, 70 int argc __unused, 71 char * const argv[] __unused, 72 uint32_t * num_used, 73 void * user_data __unused, 74 QEQueryError * error __unused) 75{ 76 Boolean result = false; 77 CFStringRef predicate = QEQueryElementGetPredicate(element); 78 uint32_t index = 1; 79 80 if (CFEqual(predicate, CFSTR(kPredNameBundleID))) { 81 QEQueryElementAppendArgument(element, kCFBundleIdentifierKey); 82 } else if (CFEqual(predicate, CFSTR(kPredNameBundleName))) { 83 QEQueryElementAppendArgument(element, kCFBundleNameKey); 84 } else if (CFEqual(predicate, CFSTR(kPredNameVersion))) { 85 QEQueryElementAppendArgument(element, kCFBundleVersionKey); 86 } else { 87 goto finish; 88 } 89 90 QEQueryElementSetPredicate(element, CFSTR(kPredNameProperty)); 91 92 result = true; 93finish: 94 *num_used += index; 95 return result; 96} 97 98/******************************************************************************* 99* 100*******************************************************************************/ 101char * cStringForCFValue(CFTypeRef value) 102{ 103 CFTypeID valueType; 104 CFIndex count; 105 char buffer[80]; // more than big enough for a number 106 107 if (!value) { 108 return strdup("<null>"); 109 } 110 111 valueType = CFGetTypeID(value); 112 113 if (CFStringGetTypeID() == valueType) { 114 return createUTF8CStringForCFString(value); 115 } else if (CFBooleanGetTypeID() == valueType) { 116 return CFBooleanGetValue(value) ? strdup(kWordTrue) : strdup(kWordFalse); 117 } else if (CFNumberGetTypeID() == valueType) { 118 } else if (CFArrayGetTypeID() == valueType) { 119 count = CFArrayGetCount(value); 120 snprintf(buffer, (sizeof(buffer)/sizeof(char)), "<array of %ld>", count); 121 return strdup(buffer); 122 } else if (CFDictionaryGetTypeID() == valueType) { 123 count = CFDictionaryGetCount(value); 124 snprintf(buffer, (sizeof(buffer)/sizeof(char)), "<dict of %ld>", count); 125 return strdup(buffer); 126 } else if (CFDataGetTypeID() == valueType) { 127 count = CFDataGetLength(value); 128 snprintf(buffer, (sizeof(buffer)/sizeof(char)), "<data of %ld>", count); 129 return strdup(buffer); 130 } else { 131 return strdup("<unknown CF type>"); 132 } 133 return NULL; 134} 135 136/******************************************************************************* 137* Note: reportEvalCommand() calls this. 138*******************************************************************************/ 139Boolean reportEvalProperty( 140 CFDictionaryRef element, 141 void * object, 142 void * user_data, 143 QEQueryError * error) 144{ 145 Boolean result = false; 146 OSKextRef theKext = (OSKextRef)object; 147 QueryContext * context = (QueryContext *)user_data; 148 CFStringRef propKey = NULL; // don't release 149 CFTypeRef propVal = NULL; // don't release 150 char * cString = NULL; // must free 151 152 propKey = QEQueryElementGetArgumentAtIndex(element, 0); 153 if (!propKey) { 154 *error = kQEQueryErrorEvaluationCallbackFailed; 155 goto finish; 156 } 157 158 if (!context->reportStarted) { 159 cString = createUTF8CStringForCFString(propKey); 160 if (!cString) { 161 *error = kQEQueryErrorEvaluationCallbackFailed; 162 goto finish; 163 } 164 printf("%s%s", context->reportRowStarted ? "\t" : "", 165 cString); 166 } else { 167 // This is allowed to be null 168 propVal = OSKextGetValueForInfoDictionaryKey(theKext, propKey); 169 cString = cStringForCFValue(propVal); 170 if (!cString) { 171 *error = kQEQueryErrorEvaluationCallbackFailed; 172 goto finish; 173 } 174 printf("%s%s", context->reportRowStarted ? "\t" : "", 175 cString); 176 } 177 178 context->reportRowStarted = true; 179 180 result = true; 181finish: 182 if (cString) free(cString); 183 return result; 184} 185 186/******************************************************************************* 187* 188*******************************************************************************/ 189Boolean reportParseFlag( 190 CFMutableDictionaryRef element, 191 int argc __unused, 192 char * const argv[] __unused, 193 uint32_t * num_used, 194 void * user_data, 195 QEQueryError * error __unused) 196{ 197 Boolean result = false; 198 CFStringRef flag = QEQueryElementGetPredicate(element); 199 QueryContext * context = (QueryContext *)user_data; 200 uint32_t index = 1; 201 202 QEQueryElementSetPredicate(element, CFSTR(kPredNameFlag)); 203 CFDictionarySetValue(element, CFSTR(kKeywordFlag), flag); 204 205 if (CFEqual(flag, CFSTR(kPredNameLoaded))) { 206 context->checkLoaded = true; 207 } else if (CFEqual(flag, CFSTR(kPredNameIntegrity))) { 208 /* Kext integrity is no longer used on SnowLeopard. We read the 209 * flags but no kext will ever match them now. 210 */ 211 context->checkIntegrity = true; 212 } 213 214 result = true; 215 216 *num_used += index; 217 return result; 218} 219 220/******************************************************************************* 221* 222*******************************************************************************/ 223Boolean reportEvalFlag( 224 CFDictionaryRef element, 225 void * object, 226 void * user_data, 227 QEQueryError * error) 228{ 229 Boolean result = false; 230 OSKextRef theKext = (OSKextRef)object; 231 CFStringRef flag = CFDictionaryGetValue(element, CFSTR(kKeywordFlag)); 232 QueryContext * context = (QueryContext *)user_data; 233 char * cString = NULL; // don't free! 234 Boolean print = true; 235 236 if (!context->reportStarted) { 237 if (CFEqual(flag, CFSTR(kPredNameLoaded))) { 238 cString = "Loaded"; 239 } else if (CFEqual(flag, CFSTR(kPredNameValid))) { 240 cString = "Valid"; 241 } else if (CFEqual(flag, CFSTR(kPredNameAuthentic))) { 242 cString = "Authentic"; 243 } else if (CFEqual(flag, CFSTR(kPredNameDependenciesMet))) { 244 cString = "Dependencies Met"; 245 } else if (CFEqual(flag, CFSTR(kPredNameLoadable))) { 246 cString = "Loadable"; 247 } else if (CFEqual(flag, CFSTR(kPredNameWarnings))) { 248 cString = "Warnings"; 249 } else if (CFEqual(flag, CFSTR(kPredNameIsLibrary))) { 250 cString = "Library"; 251 } else if (CFEqual(flag, CFSTR(kPredNameHasPlugins))) { 252 cString = "Plugins"; 253 } else if (CFEqual(flag, CFSTR(kPredNameIsPlugin))) { 254 cString = "Is Plugin"; 255 } else if (CFEqual(flag, CFSTR(kPredNameHasDebugProperties))) { 256 cString = "Debug"; 257 } else if (CFEqual(flag, CFSTR(kPredNameIsKernelResource))) { 258 cString = "Kernel Resource"; 259 } else if (CFEqual(flag, CFSTR(kPredNameIntegrity))) { 260 cString = "Integrity"; 261 } else if (CFEqual(flag, CFSTR(kPredNameExecutable))) { 262 cString = "Has Executable"; 263 } else if (CFEqual(flag, CFSTR(kPredNameDuplicate))) { 264 cString = "Has Duplicates"; 265 } else { 266 *error = kQEQueryErrorEvaluationCallbackFailed; 267 goto finish; 268 } 269 270 printf("%s%s", context->reportRowStarted ? "\t" : "", cString); 271 } else { 272 273 if (CFEqual(flag, CFSTR(kPredNameLoaded))) { 274 cString = OSKextIsLoaded(theKext) ? kWordYes : kWordNo; 275 } else if (CFEqual(flag, CFSTR(kPredNameValid))) { 276 cString = OSKextIsValid(theKext) ? kWordYes : kWordNo; 277 } else if (CFEqual(flag, CFSTR(kPredNameAuthentic))) { 278 cString = OSKextIsAuthentic(theKext) ? kWordYes : kWordNo; 279 } else if (CFEqual(flag, CFSTR(kPredNameDependenciesMet))) { 280 cString = OSKextResolveDependencies(theKext) ? kWordYes : kWordNo; 281 } else if (CFEqual(flag, CFSTR(kPredNameLoadable))) { 282 cString = OSKextIsLoadable(theKext) ? 283 kWordYes : kWordNo; 284 } else if (CFEqual(flag, CFSTR(kPredNameWarnings))) { 285 CFDictionaryRef warnings = OSKextCopyDiagnostics(theKext, 286 kOSKextDiagnosticsFlagWarnings); 287 cString = (warnings && CFDictionaryGetCount(warnings)) ? 288 kWordYes : kWordNo; 289 SAFE_RELEASE(warnings); 290 } else if (CFEqual(flag, CFSTR(kPredNameIsLibrary))) { 291 cString = (OSKextGetCompatibleVersion(theKext) > 0) ? 292 kWordYes : kWordNo; 293 } else if (CFEqual(flag, CFSTR(kPredNameHasPlugins))) { 294 CFArrayRef plugins = OSKextCopyPlugins(theKext); 295 cString = (plugins && CFArrayGetCount(plugins)) ? 296 kWordYes : kWordNo; 297 SAFE_RELEASE(plugins); 298 } else if (CFEqual(flag, CFSTR(kPredNameIsPlugin))) { 299 cString = OSKextIsPlugin(theKext) ? kWordYes : kWordNo; 300 } else if (CFEqual(flag, CFSTR(kPredNameHasDebugProperties))) { 301 cString = OSKextHasLogOrDebugFlags(theKext) ? kWordYes : kWordNo; 302 } else if (CFEqual(flag, CFSTR(kPredNameIsKernelResource))) { 303 cString = OSKextIsKernelComponent(theKext) ? kWordYes : kWordNo; 304 } else if (CFEqual(flag, CFSTR(kPredNameIntegrity))) { 305 /* Note: As of SnowLeopard, integrity is no longer used. 306 */ 307 printf("%s%s", context->reportRowStarted ? "\t" : "", 308 "n/a"); 309 print = false; 310 } else if (CFEqual(flag, CFSTR(kPredNameExecutable))) { 311 cString = OSKextDeclaresExecutable(theKext) ? kWordYes : kWordNo; 312 } else if (CFEqual(flag, CFSTR(kPredNameDuplicate))) { 313 CFStringRef kextIdentifier = OSKextGetIdentifier(theKext); 314 if (kextIdentifier) { 315 if (kextIdentifier) { 316 CFArrayRef kexts = OSKextCopyKextsWithIdentifier(kextIdentifier); 317 if (!kexts) { 318 OSKextLogMemError(); 319 goto finish; 320 } 321 cString = (CFArrayGetCount(kexts) > 1) ? kWordYes : kWordNo; 322 SAFE_RELEASE(kexts); 323 } 324 } 325 } else { 326 *error = kQEQueryErrorEvaluationCallbackFailed; 327 goto finish; 328 } 329 330 if (print) { 331 if (!cString) { 332 *error = kQEQueryErrorEvaluationCallbackFailed; 333 goto finish; 334 } 335 printf("%s%s", context->reportRowStarted ? "\t" : "", 336 cString); 337 } 338 } 339 340 context->reportRowStarted = true; 341 342 result = true; 343finish: 344 return result; 345} 346 347/******************************************************************************* 348* 349*******************************************************************************/ 350Boolean reportParseArch( 351 CFMutableDictionaryRef element, 352 int argc, 353 char * const argv[], 354 uint32_t * num_used, 355 void * user_data, 356 QEQueryError * error) 357{ 358 Boolean result = false; 359 CFStringRef scratchString = NULL; 360 361 if (!argv[(*num_used) + 1]) { 362 goto finish; 363 } 364 365 scratchString = CFStringCreateWithCString(kCFAllocatorDefault, 366 argv[(*num_used) + 1], kCFStringEncodingUTF8); 367 368 CFDictionarySetValue(element, CFSTR("label"), scratchString); 369 370 result = parseArch(element, argc, argv, num_used, user_data, error); 371 if (!result) { 372 goto finish; 373 } 374 375 result = true; 376finish: 377 SAFE_RELEASE(scratchString); 378 return result; 379} 380 381/******************************************************************************* 382* 383*******************************************************************************/ 384Boolean reportEvalArch( 385 CFDictionaryRef element, 386 void * object, 387 void * user_data, 388 QEQueryError * error) 389{ 390 Boolean result = false; 391 QueryContext * context = (QueryContext *)user_data; 392 CFStringRef string = NULL; // don't release 393 char * cString = NULL; // must free 394 395 396 if (!context->reportStarted) { 397 string = CFDictionaryGetValue(element, CFSTR("label")); 398 if (!string) { 399 *error = kQEQueryErrorEvaluationCallbackFailed; 400 goto finish; 401 } 402 cString = createUTF8CStringForCFString(string); 403 if (!cString) { 404 *error = kQEQueryErrorEvaluationCallbackFailed; 405 goto finish; 406 } 407 printf("%s%s", context->reportRowStarted ? "\t" : "", 408 cString); 409 } else { 410 Boolean match = evalArch(element, object, user_data, error); 411 if (*error != kQEQueryErrorNone) { 412 goto finish; 413 } 414 printf("%s%s", context->reportRowStarted ? "\t" : "", 415 match ? kWordYes : kWordNo); 416 } 417 418 context->reportRowStarted = true; 419 420 result = true; 421finish: 422 if (cString) free(cString); 423 return result; 424} 425 426/******************************************************************************* 427* 428*******************************************************************************/ 429Boolean reportEvalArchExact( 430 CFDictionaryRef element, 431 void * object, 432 void * user_data, 433 QEQueryError * error) 434{ 435 Boolean result = false; 436 QueryContext * context = (QueryContext *)user_data; 437 CFStringRef string = NULL; // don't release 438 char * cString = NULL; // must free 439 440 441 if (!context->reportStarted) { 442 string = CFDictionaryGetValue(element, CFSTR("label")); 443 if (!string) { 444 *error = kQEQueryErrorEvaluationCallbackFailed; 445 goto finish; 446 } 447 cString = createUTF8CStringForCFString(string); 448 if (!cString) { 449 *error = kQEQueryErrorEvaluationCallbackFailed; 450 goto finish; 451 } 452 printf("%s%s (only)", context->reportRowStarted ? "\t" : "", 453 cString); 454 } else { 455 Boolean match = evalArchExact(element, object, user_data, error); 456 if (*error != kQEQueryErrorNone) { 457 goto finish; 458 } 459 printf("%s%s", context->reportRowStarted ? "\t" : "", 460 match ? kWordYes : kWordNo); 461 } 462 463 context->reportRowStarted = true; 464 465 result = true; 466finish: 467 if (cString) free(cString); 468 return result; 469} 470 471/******************************************************************************* 472* 473*******************************************************************************/ 474Boolean reportParseDefinesOrReferencesSymbol( 475 CFMutableDictionaryRef element, 476 int argc, 477 char * const argv[], 478 uint32_t * num_used, 479 void * user_data, 480 QEQueryError * error) 481{ 482 return parseDefinesOrReferencesSymbol(element, argc, argv, num_used, 483 user_data, error); 484} 485 486/******************************************************************************* 487* xxx - if arches were specified on the command line, this should perhaps only 488* xxx - check those arches 489*******************************************************************************/ 490Boolean reportEvalDefinesOrReferencesSymbol( 491 CFDictionaryRef element, 492 void * object, 493 void * user_data, 494 QEQueryError * error) 495{ 496 Boolean result = false; 497 OSKextRef theKext = (OSKextRef)object; 498 QueryContext * context = (QueryContext *)user_data; 499 CFStringRef symbol = QEQueryElementGetArgumentAtIndex(element, 0); 500 char * cSymbol = NULL; // must free 501 const char * value = ""; // don't free 502 fat_iterator fiter = NULL; // must close 503 struct mach_header * farch = NULL; 504 void * farch_end = NULL; 505 uint8_t nlist_type; 506 507 if (!symbol) { 508 *error = kQEQueryErrorEvaluationCallbackFailed; 509 goto finish; 510 } 511 cSymbol = createUTF8CStringForCFString(symbol); 512 if (!cSymbol) { 513 *error = kQEQueryErrorEvaluationCallbackFailed; 514 goto finish; 515 } 516 517 if (!context->reportStarted) { 518 printf("%ssymbol %s", context->reportRowStarted ? "\t" : "", 519 cSymbol); 520 } else { 521 522 fiter = createFatIteratorForKext(theKext); 523 if (!fiter) { 524 goto finish; 525 } 526 527 while ((farch = fat_iterator_next_arch(fiter, &farch_end))) { 528 macho_seek_result seek_result = macho_find_symbol( 529 farch, farch_end, cSymbol, &nlist_type, NULL); 530 531 if (seek_result == macho_seek_result_found_no_value || 532 seek_result == macho_seek_result_found) { 533 534 if ((N_TYPE & nlist_type) == N_UNDF) { 535 value = OSKextIsKernelComponent(theKext) ? 536 "defines" : "references"; 537 } else { 538 value = "defines"; 539 } 540 break; 541 } 542 } 543 } 544 545 printf("%s%s", context->reportRowStarted ? "\t" : "", value); 546 context->reportRowStarted = true; 547 548 result = true; 549finish: 550 if (cSymbol) free(cSymbol); 551 return result; 552} 553 554/******************************************************************************* 555* 556*******************************************************************************/ 557Boolean reportParseCommand( 558 CFMutableDictionaryRef element, 559 int argc __unused, 560 char * const argv[], 561 uint32_t * num_used, 562 void * user_data, 563 QEQueryError * error) 564{ 565 Boolean result = false; 566 QueryContext * context = (QueryContext *)user_data; 567 CFStringRef command = QEQueryElementGetPredicate(element); 568 uint32_t index = 1; 569 570 if (CFEqual(command, CFSTR(kPredNamePrintProperty))) { 571 572 /* Fudge the predicate so we can use one eval callback. 573 */ 574 QEQueryElementSetPredicate(element, CFSTR(kPredNameProperty)); 575 if (!parseArgument(element, &argv[index], &index, user_data, error)) { 576 goto finish; 577 } 578 } else if (CFEqual(command, CFSTR(kPredNamePrintIntegrity))) { 579 /* Kext integrity is no longer used on SnowLeopard. We read the 580 * flags but no kext will ever match them now. 581 */ 582 context->checkIntegrity = true; 583 } 584 585 CFDictionarySetValue(element, CFSTR(kKeywordCommand), command); 586 QEQueryElementSetPredicate(element, CFSTR(kPredNameCommand)); 587 588 result = true; 589finish: 590 *num_used += index; 591 return result; 592} 593 594/******************************************************************************* 595* 596*******************************************************************************/ 597Boolean reportEvalCommand( 598 CFDictionaryRef element, 599 void * object, 600 void * user_data, 601 QEQueryError * error) 602{ 603 Boolean result = false; 604 CFStringRef command = CFDictionaryGetValue(element, CFSTR(kKeywordCommand)); 605 OSKextRef theKext = (OSKextRef)object; 606 QueryContext * context = (QueryContext *)user_data; 607 CFStringRef scratchString = NULL; // must release 608 char * cString = NULL; // must free 609 610 // if we do arches, easier to print than generate a string 611 Boolean print = true; 612 613 CFArrayRef dependencies = NULL; // must release 614 CFArrayRef dependents = NULL; // must release 615 CFArrayRef plugins = NULL; // do NOT release 616 CFIndex count; 617 char buffer[80]; // more than enough for an int 618 619 if (!context->reportStarted) { 620 if (CFEqual(command, CFSTR(kPredNamePrint)) || 621 CFEqual(command, CFSTR(kPredNameBundleName))) { 622 cString = strdup("Bundle"); 623 } else if (CFEqual(command, CFSTR(kPredNamePrintProperty))) { 624 result = reportEvalProperty(element, object, user_data, error); 625 goto finish; 626 } else if (CFEqual(command, CFSTR(kPredNamePrintArches))) { 627 cString = strdup("Arches"); 628 } else if (CFEqual(command, CFSTR(kPredNamePrintDependencies))) { 629 cString = strdup("# Dependencies"); 630 } else if (CFEqual(command, CFSTR(kPredNamePrintDependents))) { 631 cString = strdup("# Dependents"); 632 } else if (CFEqual(command, CFSTR(kPredNamePrintPlugins))) { 633 cString = strdup("# Plugins"); 634 } else if (CFEqual(command, CFSTR(kPredNamePrintIntegrity))) { 635 cString = strdup("Integrity"); 636 } else if (CFEqual(command, CFSTR(kPredNamePrintInfoDictionary))) { 637 cString = strdup("Info Dictionary"); 638 } else if (CFEqual(command, CFSTR(kPredNamePrintExecutable))) { 639 cString = strdup("Executable"); 640 } else { 641 *error = kQEQueryErrorEvaluationCallbackFailed; 642 goto finish; 643 } 644 645 printf("%s%s", context->reportRowStarted ? "\t" : "", cString); 646 } else { 647 if (CFEqual(command, CFSTR(kPredNamePrint))) { 648 scratchString = copyPathForKext(theKext, context->pathSpec); 649 if (!scratchString) { 650 OSKextLogMemError(); 651 goto finish; 652 } 653 cString = createUTF8CStringForCFString(scratchString); 654 } else if (CFEqual(command, CFSTR(kPredNameBundleName))) { 655 scratchString = copyPathForKext(theKext, kPathsNone); 656 if (!scratchString) { 657 OSKextLogMemError(); 658 goto finish; 659 } 660 cString = createUTF8CStringForCFString(scratchString); 661 } else if (CFEqual(command, CFSTR(kPredNamePrintProperty))) { 662 result = reportEvalProperty(element, object, user_data, error); 663 goto finish; 664 } else if (CFEqual(command, CFSTR(kPredNamePrintArches))) { 665 printf("%s", context->reportRowStarted ? "\t" : ""); 666 printKextArches(theKext, 0, false /* print line end */); 667 print = false; 668 } else if (CFEqual(command, CFSTR(kPredNamePrintDependencies))) { 669 dependencies = OSKextCopyAllDependencies(theKext, 670 /* needAll? */ false); 671 count = dependencies ? CFArrayGetCount(dependencies) : 0; 672 snprintf(buffer, (sizeof(buffer)/sizeof(char)), "%ld", count); 673 cString = strdup(buffer); 674 } else if (CFEqual(command, CFSTR(kPredNamePrintDependents))) { 675 dependencies = OSKextCopyDependents(theKext, /* direct? */ false); 676 count = dependencies ? CFArrayGetCount(dependencies) : 0; 677 snprintf(buffer, (sizeof(buffer)/sizeof(char)), "%ld", count); 678 cString = strdup(buffer); 679 } else if (CFEqual(command, CFSTR(kPredNamePrintPlugins))) { 680 plugins = OSKextCopyPlugins(theKext); 681 count = plugins ? CFArrayGetCount(plugins) : 0; 682 snprintf(buffer, (sizeof(buffer)/sizeof(char)), "%ld", count); 683 cString = strdup(buffer); 684 SAFE_RELEASE(plugins); 685 } else if (CFEqual(command, CFSTR(kPredNamePrintIntegrity))) { 686 /* Note: As of SnowLeopard, integrity is no longer used. 687 */ 688 printf("%s%s", context->reportRowStarted ? "\t" : "", 689 "n/a"); 690 print = false; 691 } else if (CFEqual(command, CFSTR(kPredNamePrintInfoDictionary))) { 692 scratchString = copyKextInfoDictionaryPath(theKext, context->pathSpec); 693 if (!scratchString) { 694 OSKextLogMemError(); 695 goto finish; 696 } 697 cString = createUTF8CStringForCFString(scratchString); 698 } else if (CFEqual(command, CFSTR(kPredNamePrintExecutable))) { 699 scratchString = copyKextExecutablePath(theKext, context->pathSpec); 700 if (!scratchString) { 701 OSKextLogMemError(); 702 goto finish; 703 } 704 cString = createUTF8CStringForCFString(scratchString); 705 } else { 706 *error = kQEQueryErrorEvaluationCallbackFailed; 707 goto finish; 708 } 709 710 if (print) { 711 if (!cString) { 712 *error = kQEQueryErrorEvaluationCallbackFailed; 713 goto finish; 714 } 715 printf("%s%s", context->reportRowStarted ? "\t" : "", 716 cString); 717 } 718 } 719 720 context->reportRowStarted = true; 721 result = true; 722finish: 723 SAFE_RELEASE(scratchString); 724 SAFE_FREE(cString); 725 SAFE_RELEASE(dependencies); 726 SAFE_RELEASE(dependents); 727 return result; 728} 729