1/* 2 * kextload_main.c 3 * kext_tools 4 * 5 * Created by Nik Gervae on 11/08/08. 6 * Copyright 2008 Apple Inc. All rights reserved. 7 * 8 */ 9#include "kextload_main.h" 10#include "kext_tools_util.h" 11#include "security.h" 12 13#include <libc.h> 14#include <servers/bootstrap.h> 15#include <sysexits.h> 16#include <Security/SecKeychainPriv.h> 17 18#include <IOKit/kext/KextManager.h> 19#include <IOKit/kext/KextManagerPriv.h> 20#include <IOKit/kext/kextmanager_types.h> 21#include <IOKit/kext/OSKextPrivate.h> 22 23#pragma mark Constants 24/******************************************************************************* 25* Constants 26*******************************************************************************/ 27 28#pragma mark Global/Static Variables 29/******************************************************************************* 30* Global/Static Variables 31*******************************************************************************/ 32const char * progname = "(unknown)"; 33static Boolean sKextdActive = FALSE; 34 35#pragma mark Main Routine 36/******************************************************************************* 37* Global variables. 38*******************************************************************************/ 39ExitStatus 40main(int argc, char * const * argv) 41{ 42 ExitStatus result = EX_SOFTWARE; 43 KextloadArgs toolArgs; 44 45 /***** 46 * Find out what the program was invoked as. 47 */ 48 progname = rindex(argv[0], '/'); 49 if (progname) { 50 progname++; // go past the '/' 51 } else { 52 progname = (char *)argv[0]; 53 } 54 55 /* Set the OSKext log callback right away. 56 */ 57 OSKextSetLogOutputFunction(&tool_log); 58 59 /***** 60 * Process args & check for permission to load. 61 */ 62 result = readArgs(argc, argv, &toolArgs); 63 if (result != EX_OK) { 64 if (result == kKextloadExitHelp) { 65 result = EX_OK; 66 } 67 goto finish; 68 } 69 70 result = checkArgs(&toolArgs); 71 if (result != EX_OK) { 72 goto finish; 73 } 74 75 result = checkAccess(); 76 if (result != EX_OK) { 77 goto finish; 78 } 79 80 /***** 81 * Assemble the list of URLs to scan, in this order (the OSKext lib inverts it 82 * for last-opened-wins semantics): 83 * 1. System repository directories (if not asking kextd to load). 84 * 2. Named kexts (always given after -repository & -dependency on command line). 85 * 3. Named repository directories (-repository/-r). 86 * 4. Named dependencies get priority (-dependency/-d). 87 * 88 * #2 is necessary since one might try to run kextload on two kexts, 89 * one of which depends on the other. 90 */ 91 if (!sKextdActive) { 92 CFArrayRef sysExtFolders = OSKextGetSystemExtensionsFolderURLs(); 93 if (!sysExtFolders) { 94 OSKextLog(/* kext */ NULL, 95 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 96 "Can't get system extensions folders."); 97 result = EX_OSERR; 98 goto finish; 99 } 100 CFArrayAppendArray(toolArgs.scanURLs, 101 sysExtFolders, RANGE_ALL(sysExtFolders)); 102 } 103 CFArrayAppendArray(toolArgs.scanURLs, toolArgs.kextURLs, 104 RANGE_ALL(toolArgs.kextURLs)); 105 CFArrayAppendArray(toolArgs.scanURLs, toolArgs.repositoryURLs, 106 RANGE_ALL(toolArgs.repositoryURLs)); 107 CFArrayAppendArray(toolArgs.scanURLs, toolArgs.dependencyURLs, 108 RANGE_ALL(toolArgs.dependencyURLs)); 109 110 if (sKextdActive) { 111 result = loadKextsViaKextd(&toolArgs); 112 } else { 113 result = loadKextsIntoKernel(&toolArgs); 114 } 115 116finish: 117 118 /* We're actually not going to free anything else because we're exiting! 119 */ 120 exit(result); 121 122 SAFE_RELEASE(toolArgs.kextIDs); 123 SAFE_RELEASE(toolArgs.dependencyURLs); 124 SAFE_RELEASE(toolArgs.repositoryURLs); 125 SAFE_RELEASE(toolArgs.kextURLs); 126 SAFE_RELEASE(toolArgs.scanURLs); 127 SAFE_RELEASE(toolArgs.allKexts); 128 129 return result; 130} 131 132#pragma mark Major Subroutines 133 134/******************************************************************************* 135* Major Subroutines 136*******************************************************************************/ 137ExitStatus 138readArgs( 139 int argc, 140 char * const * argv, 141 KextloadArgs * toolArgs) 142{ 143 ExitStatus result = EX_USAGE; 144 ExitStatus scratchResult = EX_USAGE; 145 int optchar; 146 int longindex; 147 CFStringRef scratchString = NULL; // must release 148 CFURLRef scratchURL = NULL; // must release 149 uint32_t i; 150 151 /* Set up default arg values. 152 */ 153 bzero(toolArgs, sizeof(*toolArgs)); 154 155 /***** 156 * Allocate collection objects needed for reading args. 157 */ 158 if (!createCFMutableArray(&toolArgs->kextIDs, &kCFTypeArrayCallBacks) || 159 !createCFMutableArray(&toolArgs->dependencyURLs, &kCFTypeArrayCallBacks) || 160 !createCFMutableArray(&toolArgs->repositoryURLs, &kCFTypeArrayCallBacks) || 161 !createCFMutableArray(&toolArgs->kextURLs, &kCFTypeArrayCallBacks) || 162 !createCFMutableArray(&toolArgs->scanURLs, &kCFTypeArrayCallBacks)) { 163 164 result = EX_OSERR; 165 OSKextLogMemError(); 166 exit(result); 167 } 168 169 while ((optchar = getopt_long_only(argc, (char * const *)argv, 170 kOptChars, sOptInfo, &longindex)) != -1) { 171 172 SAFE_RELEASE_NULL(scratchString); 173 SAFE_RELEASE_NULL(scratchURL); 174 175 switch (optchar) { 176 case kOptHelp: 177 usage(kUsageLevelFull); 178 result = kKextloadExitHelp; 179 goto finish; 180 break; 181 182 case kOptBundleIdentifier: 183 scratchString = CFStringCreateWithCString(kCFAllocatorDefault, 184 optarg, kCFStringEncodingUTF8); 185 if (!scratchString) { 186 OSKextLogMemError(); 187 result = EX_OSERR; 188 goto finish; 189 } 190 CFArrayAppendValue(toolArgs->kextIDs, scratchString); 191 break; 192 193 case kOptDependency: 194 case kOptRepository: 195 scratchURL = CFURLCreateFromFileSystemRepresentation( 196 kCFAllocatorDefault, 197 (const UInt8 *)optarg, strlen(optarg), true); 198 if (!scratchURL) { 199 OSKextLogStringError(/* kext */ NULL); 200 result = EX_OSERR; 201 goto finish; 202 } 203 CFArrayAppendValue((optchar == kOptDependency) ? 204 toolArgs->dependencyURLs : toolArgs->repositoryURLs, 205 scratchURL); 206 break; 207 208 case kOptQuiet: 209 beQuiet(); 210 break; 211 212 case kOptVerbose: 213 scratchResult = setLogFilterForOpt(argc, argv, /* forceOnFlags */ 0); 214 if (scratchResult != EX_OK) { 215 result = scratchResult; 216 goto finish; 217 } 218 break; 219 220 case kOptNoCaches: 221 OSKextLog(/* kext */ NULL, 222 kOSKextLogWarningLevel | kOSKextLogGeneralFlag, 223 "Notice: -%s (-%c) ignored; use kextutil(8) to test kexts.", 224 kOptNameNoCaches, kOptNoCaches); 225 break; 226 227 case kOptNoLoadedCheck: 228 OSKextLog(/* kext */ NULL, 229 kOSKextLogWarningLevel | kOSKextLogGeneralFlag, 230 "Notice: -%s (-%c) ignored.", 231 kOptNameNoLoadedCheck, kOptNoLoadedCheck); 232 break; 233 234 case kOptTests: 235 OSKextLog(/* kext */ NULL, 236 kOSKextLogWarningLevel | kOSKextLogGeneralFlag, 237 "Notice: -%s (-%c) ignored; use kextutil(8) to test kexts.", 238 kOptNameTests, kOptTests); 239 break; 240 241 case 0: 242 switch (longopt) { 243 default: 244 OSKextLog(/* kext */ NULL, 245 kOSKextLogWarningLevel | kOSKextLogGeneralFlag, 246 "Use kextutil(8) for development loading of kexts."); 247 goto finish; 248 break; 249 } 250 break; 251 252 default: 253 OSKextLog(/* kext */ NULL, 254 kOSKextLogWarningLevel | kOSKextLogGeneralFlag, 255 "Use kextutil(8) for development loading of kexts."); 256 goto finish; 257 break; 258 259 } /* switch (optchar) */ 260 } /* while (optchar = getopt_long_only(...) */ 261 262 /***** 263 * Record the kext names from the command line. 264 */ 265 for (i = optind; (int)i < argc; i++) { 266 SAFE_RELEASE_NULL(scratchURL); 267 scratchURL = CFURLCreateFromFileSystemRepresentation( 268 kCFAllocatorDefault, 269 (const UInt8 *)argv[i], strlen(argv[i]), true); 270 if (!scratchURL) { 271 result = EX_OSERR; 272 OSKextLogMemError(); 273 goto finish; 274 } 275 CFArrayAppendValue(toolArgs->kextURLs, scratchURL); 276 } 277 278 result = EX_OK; 279 280finish: 281 SAFE_RELEASE(scratchString); 282 SAFE_RELEASE(scratchURL); 283 284 if (result == EX_USAGE) { 285 usage(kUsageLevelBrief); 286 } 287 return result; 288} 289 290/******************************************************************************* 291*******************************************************************************/ 292ExitStatus 293checkArgs(KextloadArgs * toolArgs) 294{ 295 ExitStatus result = EX_USAGE; 296 297 if (!CFArrayGetCount(toolArgs->kextURLs) && 298 !CFArrayGetCount(toolArgs->kextIDs)) { 299 300 OSKextLog(/* kext */ NULL, 301 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 302 "No kernel extensions specified; name kernel extension bundles\n" 303 " following options, or use -%s (-%c).", 304 kOptNameBundleIdentifier, kOptBundleIdentifier); 305 goto finish; 306 } 307 308 result = EX_OK; 309 310finish: 311 if (result == EX_USAGE) { 312 usage(kUsageLevelBrief); 313 } 314 return result; 315} 316 317/******************************************************************************* 318*******************************************************************************/ 319ExitStatus checkAccess(void) 320{ 321 ExitStatus result = EX_OK; 322#if !TARGET_OS_EMBEDDED 323 kern_return_t kern_result = kOSReturnError; 324 mach_port_t kextd_port = MACH_PORT_NULL; 325 326 kern_result = bootstrap_look_up(bootstrap_port, 327 (char *)KEXTD_SERVER_NAME, &kextd_port); 328 329 if (kern_result == kOSReturnSuccess) { 330 sKextdActive = TRUE; 331 } else { 332 if (geteuid() == 0) { 333 OSKextLog(/* kext */ NULL, 334 kOSKextLogBasicLevel | kOSKextLogGeneralFlag | 335 kOSKextLogLoadFlag | kOSKextLogIPCFlag, 336 "Can't contact kextd; attempting to load directly into kernel."); 337 } else { 338 OSKextLog(/* kext */ NULL, 339 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | 340 kOSKextLogLoadFlag | kOSKextLogIPCFlag, 341 "Can't contact kextd; must run as root to load kexts."); 342 result = EX_NOPERM; 343 goto finish; 344 } 345 } 346 347#else 348 349 if (geteuid() != 0) { 350 OSKextLog(/* kext */ NULL, 351 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | 352 kOSKextLogLoadFlag | kOSKextLogIPCFlag, 353 "You must be running as root to load kexts."); 354 result = EX_NOPERM; 355 goto finish; 356 } 357 358#endif /* !TARGET_OS_EMBEDDED */ 359 360finish: 361 362#if !TARGET_OS_EMBEDDED 363 if (kextd_port != MACH_PORT_NULL) { 364 mach_port_deallocate(mach_task_self(), kextd_port); 365 } 366#endif /* !TARGET_OS_EMBEDDED */ 367 368 return result; 369} 370 371/******************************************************************************* 372*******************************************************************************/ 373ExitStatus loadKextsViaKextd(KextloadArgs * toolArgs) 374{ 375 ExitStatus result = EX_OK; 376 OSReturn loadResult = kOSReturnError; 377 char scratchCString[PATH_MAX]; 378 CFIndex count, index; 379 380 count = CFArrayGetCount(toolArgs->kextIDs); 381 for (index = 0; index < count; index++) { 382 CFStringRef kextID = CFArrayGetValueAtIndex(toolArgs->kextIDs, index); 383 384 if (!CFStringGetCString(kextID, scratchCString, sizeof(scratchCString), 385 kCFStringEncodingUTF8)) { 386 387 strlcpy(scratchCString, "unknown", sizeof(scratchCString)); 388 } 389 390 OSKextLog(/* kext */ NULL, 391 kOSKextLogBasicLevel | kOSKextLogGeneralFlag | 392 kOSKextLogLoadFlag | kOSKextLogIPCFlag, 393 "Requesting load of %s.", 394 scratchCString); 395 396 loadResult = KextManagerLoadKextWithIdentifier(kextID, 397 toolArgs->scanURLs); 398 if (loadResult != kOSReturnSuccess) { 399 OSKextLog(/* kext */ NULL, 400 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 401 "%s failed to load - %s; " 402 "check the system/kernel logs for errors or try kextutil(8).", 403 scratchCString, safe_mach_error_string(loadResult)); 404 if (result == EX_OK) { 405 result = exitStatusForOSReturn(loadResult); 406 // keep trying other kexts though 407 } 408 } else { 409 OSKextLog(/* kext */ NULL, 410 kOSKextLogBasicLevel | kOSKextLogGeneralFlag | kOSKextLogLoadFlag, 411 "%s loaded successfully (or already loaded).", 412 scratchCString); 413 } 414 } 415 416 count = CFArrayGetCount(toolArgs->kextURLs); 417 for (index = 0; index < count; index++) { 418 CFURLRef kextURL = CFArrayGetValueAtIndex(toolArgs->kextURLs, index); 419 if (!CFURLGetFileSystemRepresentation(kextURL, /* resolveToBase */ true, 420 (UInt8 *)scratchCString, sizeof(scratchCString))) { 421 422 strlcpy(scratchCString, "unknown", sizeof(scratchCString)); 423 } 424 425 OSKextLog(/* kext */ NULL, 426 kOSKextLogBasicLevel | kOSKextLogGeneralFlag | 427 kOSKextLogLoadFlag | kOSKextLogIPCFlag, 428 "Requesting load of %s.", 429 scratchCString); 430 431 loadResult = KextManagerLoadKextWithURL(kextURL, 432 toolArgs->scanURLs); 433 if (loadResult != kOSReturnSuccess) { 434 OSKextLog(/* kext */ NULL, 435 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 436 "%s failed to load - %s; " 437 "check the system/kernel logs for errors or try kextutil(8).", 438 scratchCString, safe_mach_error_string(loadResult)); 439 if (result == EX_OK) { 440 result = exitStatusForOSReturn(loadResult); 441 // keep trying other kexts though 442 } 443 } else { 444 OSKextLog(/* kext */ NULL, 445 kOSKextLogBasicLevel | kOSKextLogGeneralFlag | kOSKextLogLoadFlag, 446 "%s loaded successfully (or already loaded).", 447 scratchCString); 448 } 449 } 450 451 return result; 452} 453 454/******************************************************************************* 455*******************************************************************************/ 456ExitStatus loadKextsIntoKernel(KextloadArgs * toolArgs) 457{ 458 ExitStatus result = EX_OK; 459 OSReturn loadResult = kOSReturnError; 460 char scratchCString[PATH_MAX]; 461 CFIndex count, index; 462#if !TARGET_OS_EMBEDDED 463 Boolean earlyBoot = false; 464 Boolean readOnly = false; 465#endif 466 467 OSKextLog(/* kext */ NULL, 468 kOSKextLogProgressLevel | kOSKextLogGeneralFlag, 469 "Reading extensions."); 470 toolArgs->allKexts = OSKextCreateKextsFromURLs(kCFAllocatorDefault, 471 toolArgs->scanURLs); 472 if (!toolArgs->allKexts) { 473 OSKextLog(/* kext */ NULL, 474 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 475 "Can't read kexts from disk."); 476 result = EX_OSERR; 477 goto finish; 478 } 479#if !TARGET_OS_EMBEDDED 480 // not perfect, but we check to see if kextd is running to determine 481 // if we are in early boot. 482 int skc_result; 483 484 earlyBoot = (isKextdRunning() == false); 485 skc_result = callSecKeychainMDSInstall(); 486 if (skc_result != 0) { 487 // SecKeychainMDSInstall should never fail, except on read only FS. 488 // We get -67674 when SecKeychainMDSInstall can't write to its DB. 489 // see 18367703 490 if (earlyBoot && skc_result == -67674) { 491 struct statfs statfsBuffer; 492 if (statfs("/System/Library", &statfsBuffer) == 0) { 493 if (statfsBuffer.f_flags & MNT_RDONLY) { 494 readOnly = true; 495 } 496 } 497 } 498 else { 499 goto finish; 500 } 501 } 502#endif 503 count = CFArrayGetCount(toolArgs->kextIDs); 504 for (index = 0; index < count; index++) { 505 OSKextRef theKext = NULL; // do not release 506 CFStringRef kextID = CFArrayGetValueAtIndex( 507 toolArgs->kextIDs, 508 index); 509 510 if (!CFStringGetCString(kextID, scratchCString, sizeof(scratchCString), 511 kCFStringEncodingUTF8)) { 512 513 strlcpy(scratchCString, "unknown", sizeof(scratchCString)); 514 } 515 516 OSKextLog(/* kext */ NULL, 517 kOSKextLogBasicLevel | kOSKextLogGeneralFlag | 518 kOSKextLogLoadFlag | kOSKextLogIPCFlag, 519 "Loading %s.", 520 scratchCString); 521 522 theKext = OSKextGetKextWithIdentifier(kextID); 523 if (!theKext) { 524 OSKextLog(/* kext */ NULL, 525 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 526 "Error: Kext %s - not found/unable to create.", scratchCString); 527 result = kOSKextReturnNotFound; 528 goto finish; 529 } 530 531#if !TARGET_OS_EMBEDDED 532 // temp change for 18367703 533 if (readOnly && 534 (CFStringCompare(kextID, CFSTR("com.apple.nke.asp-tcp"), 0) == kCFCompareEqualTo 535 || 536 CFStringCompare(kextID, CFSTR("com.apple.filesystems.afpfs"), 0) == kCFCompareEqualTo)) { 537 OSKextLogCFString(NULL, 538 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 539 CFSTR("Netboot, loading '%@'"), 540 kextID); 541 } 542 else { 543 OSStatus sigResult = checkKextSignature(theKext, true, earlyBoot); 544 if ( sigResult != 0 ) { 545 if ( isInvalidSignatureAllowed() ) { 546 OSKextLogCFString(NULL, 547 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 548 CFSTR("kext-dev-mode allowing invalid signature %ld 0x%02lX for kext '%s'"), 549 (long)sigResult, (long)sigResult, 550 scratchCString); 551 } 552 else { 553 OSKextLogCFString(NULL, 554 kOSKextLogErrorLevel | 555 kOSKextLogLoadFlag | kOSKextLogIPCFlag, 556 CFSTR("ERROR: invalid signature for '%s', will not load"), 557 scratchCString); 558 result = sigResult; 559 goto finish; 560 } 561 } 562 } 563#endif // not TARGET_OS_EMBEDDED 564 565 /* The codepath from this function will do any error logging 566 * and cleanup needed. 567 */ 568 loadResult = OSKextLoadWithOptions(theKext, 569 /* statExclusion */ kOSKextExcludeNone, 570 /* addPersonalitiesExclusion */ kOSKextExcludeNone, 571 /* personalityNames */ NULL, 572 /* delayAutounloadFlag */ false); 573 574 if (loadResult != kOSReturnSuccess) { 575 OSKextLog(/* kext */ NULL, 576 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 577 "%s failed to load - %s.", 578 scratchCString, safe_mach_error_string(loadResult)); 579 if (result == EX_OK) { 580 result = exitStatusForOSReturn(loadResult); 581 // keep trying other kexts though 582 } 583 } else { 584 OSKextLog(/* kext */ NULL, 585 kOSKextLogBasicLevel | kOSKextLogGeneralFlag | kOSKextLogLoadFlag, 586 "%s loaded successfully (or already loaded).", 587 scratchCString); 588 } 589 } 590 591 count = CFArrayGetCount(toolArgs->kextURLs); 592 for (index = 0; index < count; index++) { 593 CFURLRef kextURL = CFArrayGetValueAtIndex( 594 toolArgs->kextURLs, 595 index); 596 if (!CFURLGetFileSystemRepresentation(kextURL, /* resolveToBase */ true, 597 (UInt8 *)scratchCString, sizeof(scratchCString))) { 598 599 strlcpy(scratchCString, "unknown", sizeof(scratchCString)); 600 } 601 602 OSKextLog(/* kext */ NULL, 603 kOSKextLogBasicLevel | kOSKextLogGeneralFlag | 604 kOSKextLogLoadFlag | kOSKextLogIPCFlag, 605 "Loading %s.", 606 scratchCString); 607 608 OSKextRef theKext = NULL; // do not release 609 610 /* Use OSKextGetKextWithURL() to avoid double open error messages, 611 * because we already tried to open all kexts above. 612 * That means we don't log here if we don't find the kext. 613 */ 614 loadResult = kOSKextReturnNotFound; 615 theKext = OSKextGetKextWithURL(kextURL); 616 if (theKext) { 617 /* The codepath from OSKextLoadWithOptions will do any error logging 618 * and cleanup needed. 619 */ 620#if !TARGET_OS_EMBEDDED 621 OSStatus sigResult = 0; 622 CFStringRef myBundleID = NULL; // do not release 623 624 myBundleID = OSKextGetIdentifier(theKext); 625 626 // temp change for 18367703 627 if (readOnly && myBundleID && 628 (CFStringCompare(myBundleID, CFSTR("com.apple.nke.asp-tcp"), 0) == kCFCompareEqualTo 629 || 630 CFStringCompare(myBundleID, CFSTR("com.apple.filesystems.afpfs"), 0) == kCFCompareEqualTo)) { 631 OSKextLogCFString(NULL, 632 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 633 CFSTR("Netboot, loading '%@'"), 634 myBundleID); 635 } 636 else { 637 sigResult = checkKextSignature(theKext, true, earlyBoot); 638 if ( sigResult != 0 ) { 639 if ( isInvalidSignatureAllowed() ) { 640 OSKextLogCFString(NULL, 641 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 642 CFSTR("kext-dev-mode allowing invalid signature %ld 0x%02lX for kext '%s'"), 643 (long)sigResult, (long)sigResult, 644 scratchCString); 645 sigResult = 0; 646 } 647 else { 648 OSKextLogCFString(NULL, 649 kOSKextLogErrorLevel | 650 kOSKextLogLoadFlag | kOSKextLogIPCFlag, 651 CFSTR("ERROR: invalid signature for '%s', will not load"), 652 scratchCString); 653 loadResult = sigResult; 654 } 655 } 656 } 657 658 659 if (sigResult == 0) { 660 loadResult = OSKextLoadWithOptions(theKext, 661 kOSKextExcludeNone, 662 kOSKextExcludeNone, 663 NULL, 664 false); 665 } 666#else 667 loadResult = OSKextLoadWithOptions(theKext, 668 kOSKextExcludeNone, 669 kOSKextExcludeNone, 670 NULL, 671 false); 672#endif // not TARGET_OS_EMBEDDED 673 } 674 if (loadResult != kOSReturnSuccess) { 675 OSKextLog(/* kext */ NULL, 676 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 677 "%s failed to load - %s.", 678 scratchCString, safe_mach_error_string(loadResult)); 679 if (result == EX_OK) { 680 result = exitStatusForOSReturn(loadResult); 681 // keep trying other kexts though 682 } 683 } else { 684 OSKextLog(/* kext */ NULL, 685 kOSKextLogBasicLevel | kOSKextLogGeneralFlag | kOSKextLogLoadFlag, 686 "%s loaded successfully (or already loaded).", 687 scratchCString); 688 } 689 } 690 691finish: 692 return result; 693} 694 695/******************************************************************************* 696*******************************************************************************/ 697ExitStatus exitStatusForOSReturn(OSReturn osReturn) 698{ 699 ExitStatus result = EX_OSERR; 700 701 switch (osReturn) { 702 case kOSKextReturnNotPrivileged: 703 result = EX_NOPERM; 704 break; 705 default: 706 result = EX_OSERR; 707 break; 708 } 709 return result; 710} 711 712/******************************************************************************* 713* usage() 714*******************************************************************************/ 715void usage(UsageLevel usageLevel) 716{ 717 fprintf(stderr, "usage: %s [options] [--] [kext] ...\n" 718 "\n", progname); 719 720 if (usageLevel == kUsageLevelBrief) { 721 fprintf(stderr, "use %s -%s for an explanation of each option\n", 722 progname, kOptNameHelp); 723 return; 724 } 725 726 fprintf(stderr, "kext: a kext bundle to load or examine\n"); 727 fprintf(stderr, "\n"); 728 729 fprintf(stderr, "-%s <bundle_id> (-%c):\n" 730 " load/use the kext whose CFBundleIdentifier is <bundle_id>\n", 731 kOptNameBundleIdentifier, kOptBundleIdentifier); 732 fprintf(stderr, "-%s <kext> (-%c):\n" 733 " consider <kext> as a candidate dependency\n", 734 kOptNameDependency, kOptDependency); 735 fprintf(stderr, "-%s <directory> (-%c):\n" 736 " look in <directory> for kexts\n", 737 kOptNameRepository, kOptRepository); 738 fprintf(stderr, "\n"); 739 740 fprintf(stderr, "-%s (-%c):\n" 741 " quiet mode: print no informational or error messages\n", 742 kOptNameQuiet, kOptQuiet); 743 fprintf(stderr, "-%s [ 0-6 | 0x<flags> ] (-%c):\n" 744 " verbose mode; print info about analysis & loading\n", 745 kOptNameVerbose, kOptVerbose); 746 fprintf(stderr, "\n"); 747 748 fprintf(stderr, "-%s (-%c): print this message and exit\n", 749 kOptNameHelp, kOptHelp); 750 fprintf(stderr, "\n"); 751 752 fprintf(stderr, "--: end of options\n"); 753 return; 754} 755