/******************************************************************************* * XXX: I'm really not sure this is completely reliable for getting a relative * XXX: path. *******************************************************************************/ void printKextExecutable( OSKextRef theKext, PathSpec pathSpec, char lineEnd) { CFStringRef executablePath = NULL; // must release char * executablePathCString = NULL; // must free executablePath = copyKextExecutablePath(theKext, pathSpec); if (!executablePath) { OSKextLogMemError(); goto finish; } executablePathCString = createUTF8CStringForCFString(executablePath); if (!executablePathCString) { OSKextLogMemError(); goto finish; } printf("%s%c", executablePathCString, lineEnd); finish: SAFE_FREE(executablePathCString); SAFE_RELEASE(executablePath); return; }
void printKextInfoDictionary( OSKextRef theKext, PathSpec pathSpec, char lineEnd) { CFStringRef infoDictPath = NULL; // must release char * infoDictPathCString = NULL; // must free infoDictPath = copyKextInfoDictionaryPath(theKext, pathSpec); if (!infoDictPath) { OSKextLogMemError(); goto finish; } infoDictPathCString = createUTF8CStringForCFString(infoDictPath); if (!infoDictPathCString) { OSKextLogMemError(); goto finish; } printf("%s%c", infoDictPathCString, lineEnd); finish: SAFE_FREE(infoDictPathCString); SAFE_RELEASE(infoDictPath); return; }
void printKext( OSKextRef theKext, PathSpec pathSpec, Boolean extra_info, char lineEnd) { CFStringRef bundleID = NULL; // do NOT release CFStringRef bundleVersion = NULL; // do NOT release CFStringRef kextPath = NULL; // must release char * kext_path = NULL; // must free char * bundle_id = NULL; // must free char * bundle_version = NULL; // must free kextPath = copyPathForKext(theKext, pathSpec); if (!kextPath) { OSKextLogMemError(); goto finish; } kext_path = createUTF8CStringForCFString(kextPath); if (!kext_path) { OSKextLogMemError(); goto finish; } if (extra_info) { bundleID = OSKextGetIdentifier(theKext); bundleVersion = OSKextGetValueForInfoDictionaryKey(theKext, kCFBundleVersionKey); bundle_id = createUTF8CStringForCFString(bundleID); bundle_version = createUTF8CStringForCFString(bundleVersion); if (!bundle_id || !bundle_version) { OSKextLogMemError(); goto finish; } fprintf(stdout, "%s\t%s\t%s%c", kext_path, bundle_id, bundle_version, lineEnd); } else { fprintf(stdout, "%s%c", kext_path, lineEnd); } finish: SAFE_RELEASE(kextPath); SAFE_FREE(kext_path); SAFE_FREE(bundle_id); SAFE_FREE(bundle_version); return; }
/******************************************************************************* * XXX: I'm really not sure this is completely reliable for getting a relative * XXX: path. *******************************************************************************/ CFStringRef copyKextInfoDictionaryPath( OSKextRef theKext, PathSpec pathSpec) { CFStringRef result = NULL; CFURLRef kextURL = NULL; // do not release CFURLRef kextAbsURL = NULL; // must release CFBundleRef kextBundle = NULL; // must release CFURLRef infoDictURL = NULL; // must release kextURL = OSKextGetURL(theKext); if (!kextURL) { OSKextLog(theKext, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "Kext has no URL!"); goto finish; } kextAbsURL = CFURLCopyAbsoluteURL(kextURL); if (!kextAbsURL) { OSKextLogMemError(); goto finish; } kextBundle = CFBundleCreate(kCFAllocatorDefault, kextAbsURL); if (!kextBundle) { OSKextLogMemError(); goto finish; } infoDictURL = _CFBundleCopyInfoPlistURL(kextBundle); if (!infoDictURL) { // not able to determine error here, bundle might have no plist // (well, we should never have gotten here if that were the case) result = CFStringCreateWithCString(kCFAllocatorDefault, "", kCFStringEncodingUTF8); goto finish; } result = copyAdjustedPathForURL(theKext, infoDictURL, pathSpec); finish: SAFE_RELEASE(infoDictURL); SAFE_RELEASE(kextBundle); SAFE_RELEASE(kextAbsURL); return result; }
ExitStatus setPrelinkedKernelArgs( KcgenArgs * toolArgs, char * filename) { ExitStatus result = EX_USAGE; if (toolArgs->prelinkedKernelPath) { OSKextLog(/* kext */ NULL, kOSKextLogWarningLevel | kOSKextLogGeneralFlag, "Warning - prelinked kernel already specified; using last."); } else { toolArgs->prelinkedKernelPath = malloc(PATH_MAX); if (!toolArgs->prelinkedKernelPath) { OSKextLogMemError(); result = EX_OSERR; goto finish; } } /* If we don't have a filename we construct a default one, automatically * add the system extensions folders, and note that we're using default * info. */ if (!filename) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "Error - prelinked kernel filename required"); goto finish; } else { size_t len = strlcpy(toolArgs->prelinkedKernelPath, filename, PATH_MAX); if (len >= PATH_MAX) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "Error - prelinked kernel filename length exceeds PATH_MAX"); goto finish; } } result = EX_OK; finish: return result; }
/******************************************************************************* * XXX: I'm really not sure this is completely reliable for getting a relative * XXX: path. *******************************************************************************/ CFStringRef copyKextExecutablePath( OSKextRef theKext, PathSpec pathSpec) { CFStringRef result = NULL; CFURLRef kextURL = NULL; // do not release CFURLRef kextAbsURL = NULL; // must release CFURLRef executableURL = NULL; // must release kextURL = OSKextGetURL(theKext); if (!kextURL) { OSKextLog(theKext, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "Kext has no URL!"); goto finish; } kextAbsURL = CFURLCopyAbsoluteURL(kextURL); if (!kextAbsURL) { OSKextLogMemError(); goto finish; } executableURL = _CFBundleCopyExecutableURLInDirectory(kextAbsURL); if (!executableURL) { // not able to determine error here, bundle might have no executable result = CFStringCreateWithCString(kCFAllocatorDefault, "", kCFStringEncodingUTF8); goto finish; } result = copyAdjustedPathForURL(theKext, executableURL, pathSpec); finish: SAFE_RELEASE(executableURL); SAFE_RELEASE(kextAbsURL); return result; }
CFDataRef createMkext1ForArch(const NXArchInfo * arch, CFArrayRef archiveKexts, boolean_t compress) { CFMutableDataRef result = NULL; CFMutableDictionaryRef kextsByIdentifier = NULL; Mkext1Context context; mkext1_header * mkextHeader = NULL; // do not free const uint8_t * adler_point = 0; CFIndex count, i; result = CFDataCreateMutable(kCFAllocatorDefault, /* capaacity */ 0); if (!result || !createCFMutableDictionary(&kextsByIdentifier)) { OSKextLogMemError(); goto finish; } /* mkext1 can only contain 1 kext for a given bundle identifier, so we * have to pick out the most recent versions. */ count = CFArrayGetCount(archiveKexts); for (i = 0; i < count; i++) { OSKextRef theKext = (OSKextRef)CFArrayGetValueAtIndex(archiveKexts, i); CFStringRef bundleIdentifier = OSKextGetIdentifier(theKext); OSKextRef savedKext = (OSKextRef)CFDictionaryGetValue(kextsByIdentifier, bundleIdentifier); OSKextVersion thisVersion, savedVersion; if (!OSKextSupportsArchitecture(theKext, arch)) { continue; } if (!savedKext) { CFDictionarySetValue(kextsByIdentifier, bundleIdentifier, theKext); continue; } thisVersion = OSKextGetVersion(theKext); savedVersion = OSKextGetVersion(savedKext); if (thisVersion > savedVersion) { CFDictionarySetValue(kextsByIdentifier, bundleIdentifier, theKext); } } /* Add room for the mkext header and kext descriptors. */ CFDataSetLength(result, sizeof(mkext1_header) + CFDictionaryGetCount(kextsByIdentifier) * sizeof(mkext_kext)); context.mkext = result; context.kextIndex = 0; context.compressOffset = (uint32_t)CFDataGetLength(result); context.arch = arch; context.fatal = false; context.compress = compress; CFDictionaryApplyFunction(kextsByIdentifier, addToMkext1, &context); if (context.fatal) { SAFE_RELEASE_NULL(result); goto finish; } mkextHeader = (mkext1_header *)CFDataGetBytePtr(result); mkextHeader->magic = OSSwapHostToBigInt32(MKEXT_MAGIC); mkextHeader->signature = OSSwapHostToBigInt32(MKEXT_SIGN); mkextHeader->version = OSSwapHostToBigInt32(0x01008000); // 'vers' 1.0.0 mkextHeader->numkexts = OSSwapHostToBigInt32((__uint32_t)CFDictionaryGetCount(kextsByIdentifier)); mkextHeader->cputype = OSSwapHostToBigInt32(arch->cputype); mkextHeader->cpusubtype = OSSwapHostToBigInt32(arch->cpusubtype); mkextHeader->length = OSSwapHostToBigInt32((__uint32_t)CFDataGetLength(result)); adler_point = (UInt8 *)&mkextHeader->version; mkextHeader->adler32 = OSSwapHostToBigInt32(local_adler32( (UInt8 *)&mkextHeader->version, (int)(CFDataGetLength(result) - (adler_point - (uint8_t *)mkextHeader)))); OSKextLog(/* kext */ NULL, kOSKextLogProgressLevel | kOSKextLogArchiveFlag, "Created mkext for %s containing %lu kexts.", arch->name, CFDictionaryGetCount(kextsByIdentifier)); finish: SAFE_RELEASE(kextsByIdentifier); return result; }
ExitStatus readArgs( int * argc, char * const ** argv, KctoolArgs * toolArgs) { ExitStatus result = EX_USAGE; ExitStatus scratchResult = EX_USAGE; int optchar = 0; int longindex = -1; bzero(toolArgs, sizeof(*toolArgs)); /***** * Process command line arguments. */ while ((optchar = getopt_long_only(*argc, *argv, kOptChars, sOptInfo, &longindex)) != -1) { switch (optchar) { case kOptArch: toolArgs->archInfo = NXGetArchInfoFromName(optarg); if (!toolArgs->archInfo) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "Unknown architecture %s.", optarg); goto finish; } break; case kOptHelp: usage(kUsageLevelFull); result = kKctoolExitHelp; goto finish; default: OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "unrecognized option %s", (*argv)[optind-1]); goto finish; break; } /* Reset longindex, because getopt_long_only() is stupid and doesn't. */ longindex = -1; } /* Update the argc & argv seen by main() so that boot<>root calls * handle remaining args. */ *argc -= optind; *argv += optind; if (*argc != 4) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "incorrect number of arguments"); goto finish; } /***** * Record remaining args from the command line. */ toolArgs->kernelcachePath = (*argv)[0]; toolArgs->kextID = CFStringCreateWithCString(kCFAllocatorDefault, (*argv)[1], kCFStringEncodingUTF8); if (!toolArgs->kextID) { OSKextLogMemError(); result = EX_OSERR; goto finish; } toolArgs->segmentName = (*argv)[2]; toolArgs->sectionName = (*argv)[3]; result = EX_OK; finish: if (result == EX_USAGE) { usage(kUsageLevelBrief); } return result; }
/******************************************************************************* * copyAdjustedPathForURL() * * This function takes an URL with a given kext, and adjusts it to be absolute * or relative to the kext's containing repository, properly handling plugin * kexts to include the repository-path of the containing kext as well. *******************************************************************************/ CFStringRef copyAdjustedPathForURL( OSKextRef theKext, CFURLRef urlToAdjust, PathSpec pathSpec) { CFStringRef result = NULL; CFURLRef absURL = NULL; // must release CFStringRef absPath = NULL; // must release CFStringRef kextAbsPath = NULL; // must release CFStringRef kextRelPath = NULL; // must release CFStringRef pathInKext = NULL; // must release CFRange scratchRange; if (pathSpec != kPathsFull && pathSpec != kPathsRelative) { OSKextLog(theKext, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "Invalid argument to copyAdjustedPathForURL()."); } absURL = CFURLCopyAbsoluteURL(urlToAdjust); if (!absURL) { OSKextLogMemError(); goto finish; } if (pathSpec == kPathsFull) { result = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle); goto finish; } /***** * Okay, we are doing repository-relative paths here. Here's how! * We are strip the matching part of the kext's absolute path * from the URL/path handed in, which gives us the path in the kext. * Then we tack that back onto the kext's repository-relative path. Got it? */ kextAbsPath = copyPathForKext(theKext, kPathsFull); kextRelPath = copyPathForKext(theKext, kPathsRelative); absPath = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle); if (!kextAbsPath || !kextRelPath || !absPath) { goto finish; } scratchRange = CFRangeMake(CFStringGetLength(kextAbsPath), CFStringGetLength(absPath) - CFStringGetLength(kextAbsPath)); pathInKext = CFStringCreateWithSubstring(kCFAllocatorDefault, absPath, scratchRange); if (!pathInKext) { OSKextLogMemError(); } result = CFStringCreateWithFormat(kCFAllocatorDefault, /* options */ 0, CFSTR("%@%@"), kextRelPath, pathInKext); finish: SAFE_RELEASE(absURL); SAFE_RELEASE(absPath); SAFE_RELEASE(kextAbsPath); SAFE_RELEASE(kextRelPath); SAFE_RELEASE(pathInKext); return result; }
CFStringRef copyPathForKext( OSKextRef theKext, PathSpec pathSpec) { CFStringRef result = CFSTR("(can't determine kext path)"); CFURLRef kextURL = OSKextGetURL(theKext); // do not release CFURLRef absURL = NULL; // must release OSKextRef containerKext = NULL; // must release CFURLRef containerURL = NULL; // do not release CFURLRef containerAbsURL = NULL; // must release CFURLRef repositoryURL = NULL; // must release CFStringRef repositoryPath = NULL; // must release CFStringRef kextPath = NULL; // must release if (!kextURL) { OSKextLog(theKext, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "Kext has no URL!"); goto finish; } if (pathSpec == kPathsNone) { result = CFURLCopyLastPathComponent(kextURL); } else if (pathSpec == kPathsFull) { absURL = CFURLCopyAbsoluteURL(kextURL); if (!absURL) { OSKextLogMemError(); goto finish; } result = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle); } else if (pathSpec == kPathsRelative) { CFRange relativeRange; absURL = CFURLCopyAbsoluteURL(kextURL); if (!absURL) { OSKextLogMemError(); goto finish; } containerKext = OSKextCopyContainerForPluginKext(theKext); if (containerKext) { containerURL = OSKextGetURL(containerKext); if (!containerURL) { OSKextLog(containerKext, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "Container kext has no URL!"); goto finish; } containerAbsURL = CFURLCopyAbsoluteURL(containerURL); if (!containerAbsURL) { OSKextLogMemError(); goto finish; } repositoryURL = CFURLCreateCopyDeletingLastPathComponent( kCFAllocatorDefault, containerAbsURL); if (!repositoryURL) { OSKextLogMemError(); goto finish; } } else { repositoryURL = CFURLCreateCopyDeletingLastPathComponent( kCFAllocatorDefault, absURL); if (!repositoryURL) { OSKextLogMemError(); goto finish; } } repositoryPath = CFURLCopyFileSystemPath(repositoryURL, kCFURLPOSIXPathStyle); kextPath = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle); if (!repositoryPath || !kextPath) { OSKextLogMemError(); goto finish; } /* We add 1 to the length of the repositoryPath to handle the * intermediate '/' character. */ relativeRange = CFRangeMake(1+CFStringGetLength(repositoryPath), CFStringGetLength(kextPath) - (1+CFStringGetLength(repositoryPath))); result = CFStringCreateWithSubstring(kCFAllocatorDefault, kextPath, relativeRange); } else { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "Internal error."); goto finish; } finish: SAFE_RELEASE(absURL); SAFE_RELEASE(containerKext); SAFE_RELEASE(containerAbsURL); SAFE_RELEASE(repositoryURL); SAFE_RELEASE(repositoryPath); SAFE_RELEASE(kextPath); return result; }
ExitStatus main(int argc, char * const * argv) { ExitStatus result = EX_OK; KextstatArgs toolArgs; CFDictionaryRef * kextInfoList = NULL; // must free CFIndex count, i; if (argv[0]) { progname = argv[0]; } /* Set the OSKext log callback right away. */ OSKextSetLogOutputFunction(&tool_log); result = readArgs(argc, argv, &toolArgs); if (result != EX_OK) { if (result == kKextstatExitHelp) { result = EX_OK; } goto finish; } toolArgs.runningKernelArch = OSKextGetRunningKernelArchitecture(); if (!toolArgs.runningKernelArch) { result = EX_OSERR; goto finish; } toolArgs.loadedKextInfo = OSKextCopyLoadedKextInfo(toolArgs.bundleIDs, NULL /* all info */); if (!toolArgs.loadedKextInfo) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogIPCFlag, "Couldn't get list of loaded kexts from kernel."); result = EX_OSERR; goto finish; } if (!toolArgs.flagListOnly) { printf("Index Refs Address "); if (toolArgs.runningKernelArch->cputype & CPU_ARCH_ABI64) { printf(" "); } printf("Size Wired "); if (toolArgs.flagShowArchitecture) { printf("Architecture "); } printf("Name (Version) <Linked Against>\n"); } count = CFDictionaryGetCount(toolArgs.loadedKextInfo); if (!count) { goto finish; } kextInfoList = (CFDictionaryRef *)malloc(count * sizeof(CFDictionaryRef)); if (!kextInfoList) { OSKextLogMemError(); result = EX_OSERR; goto finish; } CFDictionaryGetKeysAndValues(toolArgs.loadedKextInfo, /* keys */ NULL, (const void **)kextInfoList); qsort(kextInfoList, count, sizeof(CFDictionaryRef), &compareKextInfo); for (i = 0; i < count; i++) { printKextInfo(kextInfoList[i], &toolArgs); } finish: exit(result); SAFE_FREE(kextInfoList); return result; }
void printKextInfo(CFDictionaryRef kextInfo, KextstatArgs * toolArgs) { CFBooleanRef isKernelComponent = NULL; // do not release CFNumberRef loadTag = NULL; // do not release CFNumberRef retainCount = NULL; // do not release CFNumberRef loadAddress = NULL; // do not release CFNumberRef loadSize = NULL; // do not release CFNumberRef wiredSize = NULL; // do not release CFStringRef bundleID = NULL; // do not release CFStringRef bundleVersion = NULL; // do not release CFArrayRef dependencyLoadTags = NULL; // do not release CFMutableArrayRef sortedLoadTags = NULL; // must release uint32_t loadTagValue = kOSKextInvalidLoadTag; uint32_t retainCountValue = (uint32_t)-1; uint64_t loadAddressValue = (uint64_t)-1; uint32_t loadSizeValue = (uint32_t)-1; uint32_t wiredSizeValue = (uint32_t)-1; uint32_t cpuTypeValue = (uint32_t)-1; uint32_t cpuSubTypeValue = (uint32_t)-1; char * bundleIDCString = NULL; // must free char * bundleVersionCString = NULL; // must free CFIndex count, i; loadTag = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleLoadTagKey)); retainCount = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleRetainCountKey)); loadAddress = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleLoadAddressKey)); loadSize = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleLoadSizeKey)); wiredSize = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleWiredSizeKey)); bundleID = (CFStringRef)CFDictionaryGetValue(kextInfo, kCFBundleIdentifierKey); bundleVersion = (CFStringRef)CFDictionaryGetValue(kextInfo, kCFBundleVersionKey); dependencyLoadTags = (CFArrayRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleDependenciesKey)); /* If the -k flag was given, skip any kernel components unless * they are explicitly requested. */ if (toolArgs->flagNoKernelComponents) { isKernelComponent = (CFBooleanRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSKernelResourceKey)); if (isKernelComponent && CFBooleanGetValue(isKernelComponent)) { if (bundleID && kCFNotFound == CFArrayGetFirstIndexOfValue(toolArgs->bundleIDs, RANGE_ALL(toolArgs->bundleIDs), bundleID)) { goto finish; } } } if (!getNumValue(loadTag, kCFNumberSInt32Type, &loadTagValue)) { loadTagValue = kOSKextInvalidLoadTag; } /* Never print the info for the kernel (loadTag 0, id __kernel__). */ if (loadTagValue == 0) { goto finish; } if (!getNumValue(retainCount, kCFNumberSInt32Type, &retainCountValue)) { retainCountValue = (uint32_t)-1; } if (!getNumValue(loadAddress, kCFNumberSInt64Type, &loadAddressValue)) { loadAddressValue = (uint64_t)-1; } if (!getNumValue(loadSize, kCFNumberSInt32Type, &loadSizeValue)) { loadSizeValue = (uint32_t)-1; } if (!getNumValue(wiredSize, kCFNumberSInt32Type, &wiredSizeValue)) { wiredSizeValue = (uint32_t)-1; } if (!getNumValue(((CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleCPUTypeKey))), kCFNumberSInt32Type, &cpuTypeValue)) { cpuTypeValue = (uint32_t)-1; } if (!getNumValue(((CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleCPUSubtypeKey))), kCFNumberSInt32Type, &cpuSubTypeValue)) { cpuSubTypeValue = (uint32_t)-1; } bundleIDCString = createUTF8CStringForCFString(bundleID); bundleVersionCString = createUTF8CStringForCFString(bundleVersion); /* First column has no leading space. * * These field widths are from the old kextstat, may want to change them. */ if (loadTagValue == kOSKextInvalidLoadTag) { fprintf(stdout, "%5s", kStringInvalidShort); } else { fprintf(stdout, "%5d", loadTagValue); } if (retainCountValue == (uint32_t)-1) { fprintf(stdout, " %4s", kStringInvalidShort); } else { fprintf(stdout, " %4d", retainCountValue); } if (toolArgs->runningKernelArch->cputype & CPU_ARCH_ABI64) { if (loadAddressValue == (uint64_t)-1) { fprintf(stdout, " %-18s", kStringInvalidLong); } else { fprintf(stdout, " %#-18llx", (uint64_t)loadAddressValue); } } else { if (loadAddressValue == (uint64_t)-1) { fprintf(stdout, " %-10s", kStringInvalidLong); } else { fprintf(stdout, " %#-10x", (uint32_t)loadAddressValue); } } if (loadSizeValue == (uint32_t)-1) { fprintf(stdout, " %-10s", kStringInvalidLong); } else { fprintf(stdout, " %#-10x", loadSizeValue); } if (wiredSizeValue == (uint32_t)-1) { fprintf(stdout, " %-10s", kStringInvalidLong); } else { fprintf(stdout, " %#-10x", wiredSizeValue); } if (toolArgs->flagShowArchitecture) { // include kext cputype/cpusubtype info if (cpuTypeValue == (uint32_t) -1) { fprintf(stdout, " %10s/%-7s", kStringInvalidLong, kStringInvalidLong); } else { const NXArchInfo * archName = NXGetArchInfoFromCpuType(cpuTypeValue, cpuSubTypeValue); if (archName != NULL) { fprintf(stdout, " %-18s", archName->name); } else { fprintf(stdout, " %#010x/%#-7x", cpuTypeValue, cpuSubTypeValue); } } } fprintf(stdout, " %s", bundleIDCString ? bundleIDCString : kStringInvalidLong); fprintf(stdout, " (%s)", bundleVersionCString ? bundleVersionCString : kStringInvalidLong); if (dependencyLoadTags && CFArrayGetCount(dependencyLoadTags)) { sortedLoadTags = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, dependencyLoadTags); if (!sortedLoadTags) { OSKextLogMemError(); goto finish; } CFArraySortValues(sortedLoadTags, RANGE_ALL(sortedLoadTags), &compareNumbers, /* context */ NULL); fprintf(stdout, " <"); count = CFArrayGetCount(sortedLoadTags); for (i = 0; i < count; i++) { loadTag = (CFNumberRef)CFArrayGetValueAtIndex(sortedLoadTags, i); if (!getNumValue(loadTag, kCFNumberSInt32Type, &loadTagValue)) { loadTagValue = kOSKextInvalidLoadTag; } if (loadTagValue == kOSKextInvalidLoadTag) { fprintf(stdout, "%s%s", i == 0 ? "" : " ", kStringInvalidShort); } else { fprintf(stdout, "%s%d", i == 0 ? "" : " ", loadTagValue); } } fprintf(stdout, ">"); } fprintf(stdout, "\n"); finish: SAFE_RELEASE(sortedLoadTags); SAFE_FREE(bundleIDCString); SAFE_FREE(bundleVersionCString); return; }
ExitStatus readArgs(int argc, char * const * argv, KextstatArgs * toolArgs) { ExitStatus result = EX_USAGE; CFStringRef scratchString = NULL; // must release int optChar = 0; bzero(toolArgs, sizeof(*toolArgs)); /***** * Allocate collection objects needed for command line argument processing. */ if (!createCFMutableArray(&toolArgs->bundleIDs, &kCFTypeArrayCallBacks)) { goto finish; } /***** * Process command-line arguments. */ result = EX_USAGE; while ((optChar = getopt_long_only(argc, argv, kOptChars, sOptInfo, NULL)) != -1) { SAFE_RELEASE_NULL(scratchString); switch (optChar) { case kOptHelp: usage(kUsageLevelFull); result = kKextstatExitHelp; goto finish; break; case kOptNoKernelComponents: toolArgs->flagNoKernelComponents = true; break; case kOptListOnly: toolArgs->flagListOnly = true; break; case kOptBundleIdentifier: scratchString = CFStringCreateWithCString(kCFAllocatorDefault, optarg, kCFStringEncodingUTF8); if (!scratchString) { OSKextLogMemError(); result = EX_OSERR; goto finish; } CFArrayAppendValue(toolArgs->bundleIDs, scratchString); break; case kOptArchitecture: toolArgs->flagShowArchitecture = true; break; } } argc -= optind; argv += optind; if (argc) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "Extra arguments starting at %s....", argv[0]); usage(kUsageLevelBrief); goto finish; } result = EX_OK; finish: SAFE_RELEASE_NULL(scratchString); if (result == EX_USAGE) { usage(kUsageLevelBrief); } return result; }
ExitStatus readArgs( int * argc, char * const ** argv, KcgenArgs * toolArgs) { ExitStatus result = EX_USAGE; ExitStatus scratchResult = EX_USAGE; CFStringRef scratchString = NULL; // must release CFNumberRef scratchNumber = NULL; // must release CFURLRef scratchURL = NULL; // must release size_t len = 0; int32_t i = 0; int optchar = 0; int longindex = -1; bzero(toolArgs, sizeof(*toolArgs)); /***** * Allocate collection objects. */ if (!createCFMutableSet(&toolArgs->kextIDs, &kCFTypeSetCallBacks) || !createCFMutableSet(&toolArgs->optionalKextIDs, &kCFTypeSetCallBacks) || !createCFMutableArray(&toolArgs->argURLs, &kCFTypeArrayCallBacks) || !createCFMutableArray(&toolArgs->repositoryURLs, &kCFTypeArrayCallBacks) || !createCFMutableArray(&toolArgs->namedKextURLs, &kCFTypeArrayCallBacks) || !createCFMutableArray(&toolArgs->targetArchs, NULL)) { OSKextLogMemError(); result = EX_OSERR; exit(result); } /***** * Process command line arguments. */ while ((optchar = getopt_long_only(*argc, *argv, kOptChars, sOptInfo, &longindex)) != -1) { SAFE_RELEASE_NULL(scratchString); SAFE_RELEASE_NULL(scratchNumber); SAFE_RELEASE_NULL(scratchURL); /* When processing short (single-char) options, there is no way to * express optional arguments. Instead, we suppress missing option * argument errors by adding a leading ':' to the option string. * When getopt detects a missing argument, it will return a ':' so that * we can screen for options that are not required to have an argument. */ if (optchar == ':') { switch (optopt) { case kOptPrelinkedKernel: optchar = optopt; break; default: OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "Error - option requires an argument -- -%c.", optopt); break; } } switch (optchar) { case kOptArch: if (!addArchForName(toolArgs, optarg)) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "Error - unknown architecture %s.", optarg); goto finish; } break; case kOptBundleIdentifier: scratchString = CFStringCreateWithCString(kCFAllocatorDefault, optarg, kCFStringEncodingUTF8); if (!scratchString) { OSKextLogMemError(); result = EX_OSERR; goto finish; } CFSetAddValue(toolArgs->kextIDs, scratchString); break; case kOptPrelinkedKernel: scratchResult = readPrelinkedKernelArgs(toolArgs, *argc, *argv, /* isLongopt */ longindex != -1); if (scratchResult != EX_OK) { result = scratchResult; goto finish; } break; case kOptHelp: usage(kUsageLevelFull); result = kKcgenExitHelp; goto finish; case kOptKernel: if (toolArgs->kernelPath) { OSKextLog(/* kext */ NULL, kOSKextLogWarningLevel | kOSKextLogGeneralFlag, "Warning - kernel file already specified; using last."); } else { toolArgs->kernelPath = malloc(PATH_MAX); if (!toolArgs->kernelPath) { OSKextLogMemError(); result = EX_OSERR; goto finish; } } len = strlcpy(toolArgs->kernelPath, optarg, PATH_MAX); if (len >= PATH_MAX) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "Error - kernel filename length exceeds PATH_MAX"); goto finish; } break; case kOptTests: toolArgs->printTestResults = true; break; case kOptQuiet: beQuiet(); break; case kOptVerbose: scratchResult = setLogFilterForOpt(*argc, *argv, /* forceOnFlags */ kOSKextLogKextOrGlobalMask); if (scratchResult != EX_OK) { result = scratchResult; goto finish; } break; case kOptNoAuthentication: OSKextLog(/* kext */ NULL, kOSKextLogWarningLevel | kOSKextLogGeneralFlag, "Note: -%s is implicitly set for %s.", kOptNameNoAuthentication, progname); break; case 0: switch (longopt) { case kLongOptOptionalBundleIdentifier: scratchString = CFStringCreateWithCString(kCFAllocatorDefault, optarg, kCFStringEncodingUTF8); if (!scratchString) { OSKextLogMemError(); result = EX_OSERR; goto finish; } CFSetAddValue(toolArgs->optionalKextIDs, scratchString); break; case kLongOptCompressed: toolArgs->compress = true; break; case kLongOptUncompressed: toolArgs->uncompress = true; break; case kLongOptSymbols: if (toolArgs->symbolDirURL) { OSKextLog(/* kext */ NULL, kOSKextLogWarningLevel | kOSKextLogGeneralFlag, "Warning - symbol directory already specified; using last."); SAFE_RELEASE_NULL(toolArgs->symbolDirURL); } scratchURL = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, (const UInt8 *)optarg, strlen(optarg), true); if (!scratchURL) { OSKextLogStringError(/* kext */ NULL); result = EX_OSERR; goto finish; } toolArgs->symbolDirURL = CFRetain(scratchURL); toolArgs->generatePrelinkedSymbols = true; break; case kLongOptVolumeRoot: if (toolArgs->volumeRootURL) { OSKextLog(/* kext */ NULL, kOSKextLogWarningLevel | kOSKextLogGeneralFlag, "Warning: volume root already specified; using last."); SAFE_RELEASE_NULL(toolArgs->volumeRootURL); } scratchURL = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, (const UInt8 *)optarg, strlen(optarg), true); if (!scratchURL) { OSKextLogStringError(/* kext */ NULL); result = EX_OSERR; goto finish; } toolArgs->volumeRootURL = CFRetain(scratchURL); break; case kLongOptAllPersonalities: OSKextLog(/* kext */ NULL, kOSKextLogWarningLevel | kOSKextLogGeneralFlag, "Note: -%s is implicitly set for %s.", kOptNameAllPersonalities, progname); break; case kLongOptNoLinkFailures: OSKextLog(/* kext */ NULL, kOSKextLogWarningLevel | kOSKextLogGeneralFlag, "Note: -%s is implicitly set for %s.", kOptNameNoLinkFailures, progname); break; case kLongOptStripSymbols: toolArgs->stripSymbols = true; break; case kLongOptMaxSliceSize: toolArgs->maxSliceSize = atol(optarg); break; default: /* Because we use ':', getopt_long doesn't print an error message. */ OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "Error - unrecognized option %s", (*argv)[optind-1]); goto finish; break; } break; default: /* Because we use ':', getopt_long doesn't print an error message. */ OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "Error - unrecognized option %s", (*argv)[optind-1]); goto finish; break; } /* Reset longindex, because getopt_long_only() is stupid and doesn't. */ longindex = -1; } /* Update the argc & argv seen by main(). */ *argc -= optind; *argv += optind; /* * Record the kext & directory names from the command line. */ for (i = 0; i < *argc; i++) { SAFE_RELEASE_NULL(scratchURL); SAFE_RELEASE_NULL(scratchString); scratchURL = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, (const UInt8 *)(*argv)[i], strlen((*argv)[i]), true); if (!scratchURL) { OSKextLogMemError(); result = EX_OSERR; goto finish; } CFArrayAppendValue(toolArgs->argURLs, scratchURL); scratchString = CFURLCopyPathExtension(scratchURL); if (scratchString && CFEqual(scratchString, CFSTR("kext"))) { CFArrayAppendValue(toolArgs->namedKextURLs, scratchURL); } else { CFArrayAppendValue(toolArgs->repositoryURLs, scratchURL); } } result = EX_OK; finish: SAFE_RELEASE(scratchString); SAFE_RELEASE(scratchNumber); SAFE_RELEASE(scratchURL); if (result == EX_USAGE) { usage(kUsageLevelBrief); } return result; }