#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFBundlePriv.h>
#include <IOKit/kext/OSKext.h>
#include <IOKit/kext/OSKextPrivate.h>
#include <IOKit/kext/fat_util.h>
#include <IOKit/kext/macho_util.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "QEQuery.h"
#include "kextfind_main.h"
#include "kextfind_query.h"
#include "kextfind_commands.h"
typedef enum {
kVersionNone,
kVersionEqual,
kVersionNotEqual,
kVersionGreaterThan,
kVersionGreaterOrEqual,
kVersionLessThan,
kVersionLessOrEqual,
kVersionRange
} VersionOperator;
struct option echo_opt_info[] = {
{ kPredOptNameNoNewline, no_argument, NULL, kPredOptNoNewline },
{ kOptNameNulTerminate, no_argument, NULL, kOptNulTerminate },
QUERY_PREDICATES
QUERY_COMMANDS
{ NULL, 0, NULL, 0 } };
#define ECHO_OPTS "0n"
struct option property_opt_info[] = {
{ kPredOptNameCaseInsensitive, no_argument, NULL, kPredOptCaseInsensitive },
{ kPredOptNameSubstring, no_argument, NULL, kPredOptSubstring },
QUERY_PREDICATES
QUERY_COMMANDS
{ NULL, 0, NULL, 0 } };
#define PROPERTY_OPTS "is"
struct option print_opt_info[] = {
{ kOptNameNulTerminate, no_argument, NULL, kOptNulTerminate },
QUERY_PREDICATES
QUERY_COMMANDS
{ NULL, 0, NULL, 0 } };
#define PRINT_OPTS "0"
static int parseVersionArg(const char * string,
VersionOperator * versionOperator,
OSKextVersion * version1,
OSKextVersion * version2,
uint32_t * error);
Boolean parseStringElementOptions(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * index,
QueryContext * context,
QEQueryError * error);
Boolean parseEchoOptions(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * index,
QueryContext * context,
QEQueryError * error);
Boolean parsePrintOptions(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * index,
QueryContext * context,
QEQueryError * error);
Boolean handleNonOption(int opt_char,
char * const argv[],
QueryContext * context,
QEQueryError * error);
Boolean parseArgument(
CFMutableDictionaryRef element,
char * const argv[],
uint32_t * num_used,
void * user_data __unused,
QEQueryError * error)
{
Boolean result = false;
uint32_t index = 0; CFStringRef arg = NULL;
if (!argv[index]) {
*error = kQEQueryErrorInvalidOrMissingArgument;
goto finish;
}
arg = CFStringCreateWithCString(kCFAllocatorDefault, argv[index],
kCFStringEncodingUTF8);
index++;
*num_used += index;
QEQueryElementAppendArgument(element, arg);
result = true;
finish:
if (arg) CFRelease(arg);
return result;
}
Boolean parseProperty(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * num_used,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
QueryContext * context = (QueryContext *)user_data;
CFStringRef predicate = NULL; Boolean needValue = true;
uint32_t index = 1;
predicate = QEQueryElementGetPredicate(element);
if (CFEqual(predicate, CFSTR(kPredNamePropertyExists))) {
CFDictionarySetValue(element, CFSTR(kSearchStyleKeyExists), kCFBooleanTrue);
needValue = false;
} else if (!parseStringElementOptions(element, argc, argv, &index,
context, error)) {
goto finish;
}
QEQueryElementSetPredicate(element, CFSTR(kPredNameProperty));
if (!parseArgument(element, &argv[index], &index, user_data, error)) {
goto finish;
}
if (needValue) {
if (!parseArgument(element, &argv[index], &index, user_data, error)) {
goto finish;
}
}
result = true;
finish:
*num_used += index;
return result;
}
Boolean parseBundleName(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * num_used,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
QueryContext * context = (QueryContext *)user_data;
uint32_t index = 1;
if (!parseStringElementOptions(element, argc, argv, &index,
context, error)) {
goto finish;
}
if (!parseArgument(element, &argv[index], &index, user_data, error)) {
goto finish;
}
QEQueryElementSetPredicate(element, CFSTR(kPredNameBundleName));
result = true;
finish:
*num_used += index;
return result;
}
Boolean evalBundleName(
CFDictionaryRef element,
void * object,
void * user_data,
QEQueryError * error __unused)
{
Boolean result = false;
QueryContext * context = (QueryContext *)user_data;
OSKextRef theKext = (OSKextRef)object;
CFStringRef queryName = QEQueryElementGetArgumentAtIndex(element, 0);
CFURLRef kextURL = NULL; CFStringRef bundleName = NULL;
kextURL = OSKextGetURL(theKext);
if (!kextURL) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
"Kext has no URL!");
goto finish;
}
bundleName = CFURLCopyLastPathComponent(kextURL);
if (!bundleName) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
"Kext has bad URL.");
goto finish;
}
CFOptionFlags searchOptions = 0;
if (context->caseInsensitive ||
CFDictionaryGetValue(element,
CFSTR(kSearchStyleCaseInsensitive))) {
searchOptions |= kCFCompareCaseInsensitive;
}
if (context->substrings ||
CFDictionaryGetValue(element, CFSTR(kSearchStyleSubstring))) {
CFRange findResult = CFStringFind(bundleName,
queryName, searchOptions);
if (findResult.location != kCFNotFound) {
result = true;
}
} else {
CFComparisonResult compareResult = CFStringCompareWithOptions(
bundleName, queryName,
CFRangeMake(0, CFStringGetLength(bundleName)),
searchOptions);
if (compareResult == kCFCompareEqualTo) {
result = true;
}
}
finish:
SAFE_RELEASE(bundleName);
return result;
}
Boolean parseShorthand(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * num_used,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
QueryContext * context = (QueryContext *)user_data;
CFStringRef predicate = QEQueryElementGetPredicate(element);
uint32_t index = 1;
if (CFEqual(predicate, CFSTR(kPredNameBundleID))) {
if (!parseStringElementOptions(element, argc, argv, &index,
context, error)) {
goto finish;
}
QEQueryElementAppendArgument(element, kCFBundleIdentifierKey);
if (!parseArgument(element, &argv[index], &index, user_data, error)) {
goto finish;
}
} else {
if (CFEqual(predicate, CFSTR(kPredNameRoot))) {
QEQueryElementAppendArgument(element, CFSTR(kOSBundleRequired));
QEQueryElementAppendArgument(element, CFSTR(kOSBundleRequiredRoot));
CFDictionarySetValue(element, CFSTR(kSearchStyleExact), kCFBooleanTrue);
} else if (CFEqual(predicate, CFSTR(kPredNameConsole))) {
QEQueryElementAppendArgument(element, CFSTR(kOSBundleRequired));
QEQueryElementAppendArgument(element, CFSTR(kOSBundleRequiredConsole));
CFDictionarySetValue(element, CFSTR(kSearchStyleExact), kCFBooleanTrue);
} else if (CFEqual(predicate, CFSTR(kPredNameLocalRoot))) {
QEQueryElementAppendArgument(element, CFSTR(kOSBundleRequired));
QEQueryElementAppendArgument(element, CFSTR(kOSBundleRequiredLocalRoot));
CFDictionarySetValue(element, CFSTR(kSearchStyleExact), kCFBooleanTrue);
} else if (CFEqual(predicate, CFSTR(kPredNameNetworkRoot))) {
QEQueryElementAppendArgument(element, CFSTR(kOSBundleRequired));
QEQueryElementAppendArgument(element, CFSTR(kOSBundleRequiredNetworkRoot));
CFDictionarySetValue(element, CFSTR(kSearchStyleExact), kCFBooleanTrue);
} else if (CFEqual(predicate, CFSTR(kPredNameSafeBoot))) {
QEQueryElementAppendArgument(element, CFSTR(kOSBundleRequired));
QEQueryElementAppendArgument(element, CFSTR(kOSBundleRequiredSafeBoot));
CFDictionarySetValue(element, CFSTR(kSearchStyleExact), kCFBooleanTrue);
} else {
goto finish;
}
}
QEQueryElementSetPredicate(element, CFSTR(kPredNameProperty));
result = true;
finish:
*num_used += index;
return result;
}
Boolean _evalPropertyInDict(
CFDictionaryRef element,
void * object,
CFDictionaryRef searchDict,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
OSKextRef theKext = (OSKextRef)object;
QueryContext * context = (QueryContext *)user_data;
CFStringRef propName = NULL;
CFStringRef queryValue = NULL;
CFTypeRef foundValue = NULL;
CFTypeID foundType = 0;
CFLocaleRef locale = NULL; CFNumberFormatterRef formatter = NULL; CFNumberRef searchNumber = NULL; char * scratchCString = NULL;
propName = QEQueryElementGetArgumentAtIndex(element, 0);
if (searchDict) {
foundValue = CFDictionaryGetValue(searchDict, propName);
} else {
foundValue = OSKextGetValueForInfoDictionaryKey(theKext, propName);
}
if (!foundValue) {
goto finish;
}
foundType = CFGetTypeID(foundValue);
if (CFDictionaryGetValue(element, CFSTR(kSearchStyleKeyExists))) {
if (foundValue) {
result = true;
}
goto finish;
}
queryValue = QEQueryElementGetArgumentAtIndex(element, 1);
if (foundType == CFStringGetTypeID()) {
if (CFDictionaryGetValue(element, CFSTR(kSearchStyleExact))) {
result = CFEqual(foundValue, queryValue);
goto finish;
} else {
CFOptionFlags searchOptions = 0;
if (context->caseInsensitive ||
CFDictionaryGetValue(element,
CFSTR(kSearchStyleCaseInsensitive))) {
searchOptions |= kCFCompareCaseInsensitive;
}
if (context->substrings ||
CFDictionaryGetValue(element, CFSTR(kSearchStyleSubstring))) {
CFRange findResult = CFStringFind(foundValue,
queryValue, searchOptions);
if (findResult.location != kCFNotFound) {
result = true;
}
} else {
CFComparisonResult compareResult = CFStringCompareWithOptions(
foundValue, queryValue,
CFRangeMake(0, CFStringGetLength(foundValue)),
searchOptions);
if (compareResult == kCFCompareEqualTo) {
result = true;
}
}
goto finish;
}
} else if (foundType == CFNumberGetTypeID()) {
if (CFDictionaryGetValue(element, CFSTR(kSearchStyleSubstring))) {
goto finish;
} else {
CFNumberRef foundNumber = NULL; CFRange stringRange;
foundNumber = (CFNumberRef)foundValue;
locale = CFLocaleCopyCurrent();
if (!locale) {
*error = kQEQueryErrorEvaluationCallbackFailed;
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
"Can't get current locale.");
goto finish;
}
formatter = CFNumberFormatterCreate(kCFAllocatorDefault, locale,
kCFNumberFormatterNoStyle);
if (!formatter) {
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
stringRange = CFRangeMake(0, CFStringGetLength(queryValue));
searchNumber = CFNumberFormatterCreateNumberFromString(
kCFAllocatorDefault, formatter, queryValue,
&stringRange, 0);
if (!formatter) {
*error = kQEQueryErrorEvaluationCallbackFailed;
scratchCString = createUTF8CStringForCFString(queryValue);
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
"Failed to parse number string '%s'.",
scratchCString);
SAFE_FREE_NULL(scratchCString);
goto finish;
}
if (CFEqual(foundNumber, searchNumber)) {
result = true;
goto finish;
}
}
} else if (foundType == CFBooleanGetTypeID()) {
if (CFDictionaryGetValue(element, CFSTR(kSearchStyleSubstring))) {
goto finish;
} else {
CFBooleanRef foundBoolean = (CFBooleanRef)foundValue;
if (CFBooleanGetValue(foundBoolean) == true) {
if (CFEqual(queryValue, CFSTR(kWordTrue)) ||
CFEqual(queryValue, CFSTR(kWordYes)) ||
CFEqual(queryValue, CFSTR(kWord1))) {
result = true;
goto finish;
}
} else {
if (CFEqual(queryValue, CFSTR(kWordFalse)) ||
CFEqual(queryValue, CFSTR(kWordNo)) ||
CFEqual(queryValue, CFSTR(kWord0))) {
result = true;
goto finish;
}
}
}
}
finish:
SAFE_RELEASE(locale);
SAFE_RELEASE(formatter);
SAFE_RELEASE(searchNumber);
SAFE_FREE(scratchCString);
return result;
}
Boolean evalProperty(
CFDictionaryRef element,
void * object,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
result = _evalPropertyInDict(element, object, NULL,
user_data, error);
return result;
}
Boolean parseMatchProperty(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * num_used,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
QueryContext * context = (QueryContext *)user_data;
CFStringRef predicate = NULL; Boolean needValue = true;
uint32_t index = 1;
predicate = QEQueryElementGetPredicate(element);
if (CFEqual(predicate, CFSTR(kPredNameMatchPropertyExists))) {
CFDictionarySetValue(element, CFSTR(kSearchStyleKeyExists), kCFBooleanTrue);
needValue = false;
} else {
if (!parseStringElementOptions(element, argc, argv, &index,
context, error)) {
goto finish;
}
}
QEQueryElementSetPredicate(element, CFSTR(kPredNameMatchProperty));
if (!parseArgument(element, &argv[index], &index, user_data, error)) {
goto finish;
}
if (needValue) {
if (!parseArgument(element, &argv[index], &index, user_data, error)) {
goto finish;
}
}
result = true;
finish:
*num_used += index;
return result;
}
Boolean evalMatchProperty(
CFDictionaryRef element,
void * object,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
OSKextRef theKext = (OSKextRef)object;
CFArrayRef personalities = OSKextCopyPersonalitiesArray(theKext);
CFIndex count, i;
if (!personalities) {
goto finish;
}
count = CFArrayGetCount(personalities);
for (i = 0; i < count; i++) {
CFDictionaryRef personality = CFArrayGetValueAtIndex(personalities, i);
if (_evalPropertyInDict(element, object, personality,
user_data, error)) {
result = true;
goto finish;
}
}
finish:
if (personalities) CFRelease(personalities);
return result;
}
Boolean parseIntegrity(
CFMutableDictionaryRef element,
int argc __unused,
char * const argv[],
uint32_t * num_used,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
QueryContext * context = (QueryContext *)user_data;
uint32_t index = 1; CFStringRef name = NULL; CFStringRef value = NULL;
if (!argv[index]) {
*error = kQEQueryErrorInvalidOrMissingArgument;
goto finish;
}
if (strcmp(argv[index], kIntegrityCorrect) &&
strcmp(argv[index], kIntegrityUnknown) &&
strcmp(argv[index], kIntegrityNotApple) &&
strcmp(argv[index], kIntegrityNoReceipt) &&
strcmp(argv[index], kIntegrityModified)) {
*error = kQEQueryErrorInvalidOrMissingArgument;
goto finish;
}
value = CFStringCreateWithCString(kCFAllocatorDefault, argv[index],
kCFStringEncodingUTF8);
index++;
*num_used += index;
QEQueryElementAppendArgument(element, value);
context->checkIntegrity = true;
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
"Integrity states are no longer used; no kexts will match.");
result = true;
finish:
if (name) CFRelease(name);
if (value) CFRelease(value);
return result;
}
Boolean evalIntegrity(
CFDictionaryRef element __unused,
void * object __unused,
void * user_data __unused,
QEQueryError * error __unused)
{
Boolean result = false;
return result;
}
Boolean parseFlag(
CFMutableDictionaryRef element,
int argc __unused,
char * const argv[] __unused,
uint32_t * num_used,
void * user_data,
QEQueryError * error __unused)
{
CFStringRef flag = QEQueryElementGetPredicate(element);
QueryContext * context = (QueryContext *)user_data;
QEQueryElementSetPredicate(element, CFSTR(kPredNameFlag));
CFDictionarySetValue(element, CFSTR(kKeywordFlag), flag);
if (CFEqual(flag, CFSTR(kPredNameLoaded))) {
context->checkLoaded = true;
}
*num_used += 1;
return true;
}
Boolean evalFlag(
CFDictionaryRef element,
void * object,
void * user_data __unused,
QEQueryError * error __unused)
{
Boolean result = false;
OSKextRef theKext = (OSKextRef)object;
CFStringRef flag = CFDictionaryGetValue(element, CFSTR(kKeywordFlag));
if (CFEqual(flag, CFSTR(kPredNameLoaded))) {
return OSKextIsLoaded(theKext);
} else if (CFEqual(flag, CFSTR(kPredNameDuplicate))) {
CFStringRef kextIdentifier = OSKextGetIdentifier(theKext);
if (kextIdentifier) {
CFArrayRef kexts = OSKextCopyKextsWithIdentifier(kextIdentifier);
if (kexts && CFArrayGetCount(kexts) > 1) {
result = true;
}
SAFE_RELEASE(kexts);
}
} else if (CFEqual(flag, CFSTR(kPredNameValid))) {
return OSKextIsValid(theKext);
} if (CFEqual(flag, CFSTR(kPredNameInvalid))) {
return !OSKextIsValid(theKext);
} else if (CFEqual(flag, CFSTR(kPredNameAuthentic))) {
return OSKextIsAuthentic(theKext);
} else if (CFEqual(flag, CFSTR(kPredNameInauthentic))) {
return !OSKextIsAuthentic(theKext);
} else if (CFEqual(flag, CFSTR(kPredNameDependenciesMet))) {
return OSKextResolveDependencies(theKext);
} else if (CFEqual(flag, CFSTR(kPredNameDependenciesMissing))) {
return !OSKextResolveDependencies(theKext);
} else if (CFEqual(flag, CFSTR(kPredNameLoadable))) {
return OSKextIsLoadable(theKext);
} else if (CFEqual(flag, CFSTR(kPredNameNonloadable))) {
return !OSKextIsLoadable(theKext);
} else if (CFEqual(flag, CFSTR(kPredNameWarnings))) {
CFDictionaryRef warnings = OSKextCopyDiagnostics(theKext,
kOSKextDiagnosticsFlagWarnings);
if (warnings && CFDictionaryGetCount(warnings)) {
result = true;
}
SAFE_RELEASE(warnings);
} else if (CFEqual(flag, CFSTR(kPredNameIsLibrary))) {
if (OSKextGetCompatibleVersion(theKext) > 0) {
result = true;
}
} else if (CFEqual(flag, CFSTR(kPredNameHasPlugins))) {
CFArrayRef plugins = OSKextCopyPlugins(theKext);
if (plugins && CFArrayGetCount(plugins)) {
result = true;
}
SAFE_RELEASE(plugins);
} else if (CFEqual(flag, CFSTR(kPredNameIsPlugin))) {
return OSKextIsPlugin(theKext);
} else if (CFEqual(flag, CFSTR(kPredNameHasDebugProperties))) {
return OSKextHasLogOrDebugFlags(theKext);
} else if (CFEqual(flag, CFSTR(kPredNameIsKernelResource))) {
return OSKextIsKernelComponent(theKext);
} else if (CFEqual(flag, CFSTR(kPredNameExecutable))) {
return OSKextDeclaresExecutable(theKext);
} else if (CFEqual(flag, CFSTR(kPredNameNoExecutable))) {
return !OSKextDeclaresExecutable(theKext);
}
return result;
}
Boolean parseVersion(
CFMutableDictionaryRef element,
int argc __unused,
char * const argv[],
uint32_t * num_used,
void * user_data __unused,
QEQueryError * error)
{
Boolean result = false;
uint32_t index = 1; VersionOperator versionOperator;
OSKextVersion version1 = 0;
OSKextVersion version2 = 0;
CFNumberRef vOpNum = NULL; CFDataRef version1Data = NULL; CFDataRef version2Data = NULL;
if (!argv[index]) {
*error = kQEQueryErrorInvalidOrMissingArgument;
goto finish;
}
if (!parseVersionArg(argv[index], &versionOperator, &version1, &version2, error)) {
goto finish;
}
index++;
vOpNum = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type,
&versionOperator);
if (!vOpNum) {
*error = kQEQueryErrorNoMemory;
goto finish;
}
version1Data = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&version1, sizeof(version1));
if (!version1Data) {
*error = kQEQueryErrorNoMemory;
goto finish;
}
version2Data = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&version2, sizeof(version2));
if (!version2Data) {
*error = kQEQueryErrorNoMemory;
goto finish;
}
QEQueryElementAppendArgument(element, vOpNum);
QEQueryElementAppendArgument(element, version1Data);
QEQueryElementAppendArgument(element, version2Data);
result = true;
finish:
*num_used += index;
if (vOpNum) CFRelease(vOpNum);
if (version1Data) CFRelease(version1Data);
if (version2Data) CFRelease(version2Data);
return result;
}
Boolean evalVersion(
CFDictionaryRef element,
void * object,
void * user_data __unused,
QEQueryError * error)
{
Boolean result = false;
OSKextRef theKext = (OSKextRef)object;
OSKextVersion kextVers = OSKextGetVersion(theKext);
CFNumberRef vOpNum = NULL; CFDataRef version1Data = NULL; CFDataRef version2Data = NULL; VersionOperator versionOperator;
OSKextVersion version1;
OSKextVersion version2;
vOpNum = QEQueryElementGetArgumentAtIndex(element, 0);
version1Data = QEQueryElementGetArgumentAtIndex(element, 1);
version2Data = QEQueryElementGetArgumentAtIndex(element, 2);
if (!CFNumberGetValue(vOpNum,kCFNumberSInt32Type,&versionOperator)) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
"Internal error getting version operator.");
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
version1 = *(OSKextVersion *)CFDataGetBytePtr(version1Data);
version2 = *(OSKextVersion *)CFDataGetBytePtr(version2Data);
switch (versionOperator) {
case kVersionEqual:
if (kextVers == version1) {
result = true;
}
break;
case kVersionNotEqual:
if (kextVers != version1) {
result = true;
}
break;
case kVersionGreaterThan:
if (kextVers > version1) {
result = true;
}
break;
case kVersionGreaterOrEqual:
if (kextVers >= version1) {
result = true;
}
break;
case kVersionLessThan:
if (kextVers < version1) {
result = true;
}
break;
case kVersionLessOrEqual:
if (kextVers <= version1) {
result = true;
}
break;
case kVersionRange:
if ((kextVers >= version1) && (kextVers <= version2)) {
result = true;
}
break;
default:
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
"Internal evaluation error.");
*error = kQEQueryErrorEvaluationCallbackFailed;
break;
}
finish:
return result;
}
Boolean parseCompatibleWithVersion(
CFMutableDictionaryRef element,
int argc __unused,
char * const argv[],
uint32_t * num_used,
void * user_data __unused,
QEQueryError * error)
{
Boolean result = false;
uint32_t index = 1; OSKextVersion compatible_version = 0;
CFDataRef versionData = NULL;
if (!argv[index]) {
*error = kQEQueryErrorInvalidOrMissingArgument;
goto finish;
}
compatible_version = OSKextParseVersionString(argv[index]);
if (compatible_version == -1) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
"Invalid version string '%s'.", argv[index]);
goto finish;
}
index++;
versionData = CFDataCreate(kCFAllocatorDefault,
(UInt8 *)&compatible_version, sizeof(compatible_version));
if (!versionData) {
*error = kQEQueryErrorNoMemory;
goto finish;
}
QEQueryElementAppendArgument(element, versionData);
result = true;
finish:
*num_used += index;
if (versionData) CFRelease(versionData);
return result;
}
Boolean evalCompatibleWithVersion(
CFDictionaryRef element,
void * object,
void * user_data __unused,
QEQueryError * error __unused)
{
Boolean result = false;
OSKextRef theKext = (OSKextRef)object;
CFDataRef versionData = NULL; OSKextVersion compatible_version = 0;
versionData = QEQueryElementGetArgumentAtIndex(element, 0);
compatible_version = *(OSKextVersion *)CFDataGetBytePtr(versionData);
if (OSKextIsCompatibleWithVersion(theKext, compatible_version)) {
result = true;
}
return result;
}
static int parseVersionArg(const char * string,
VersionOperator * versionOperator,
OSKextVersion * version1,
OSKextVersion * version2,
uint32_t * error)
{
int result = -1; char * scratch = NULL; char * v1string = NULL; char * hyphen = NULL; char * v2string = NULL;
scratch = strdup(string);
if (!scratch) {
OSKextLogMemError();
result = 0;
goto finish;
}
v1string = scratch;
*versionOperator = kVersionNone;
switch (scratch[0]) {
case 'e':
*versionOperator = kVersionEqual;
v1string = &scratch[1];
break;
case 'n':
if (scratch[1] != 'e') {
goto finish;
}
*versionOperator = kVersionNotEqual;
v1string = &scratch[2];
break;
case 'g':
if (scratch[1] == 'e') {
*versionOperator = kVersionGreaterOrEqual;
} else if (scratch[1] == 't') {
*versionOperator = kVersionGreaterThan;
} else {
goto finish;
}
v1string = &scratch[2];
break;
case 'l':
if (scratch[1] == 'e') {
*versionOperator = kVersionLessOrEqual;
} else if (scratch[1] == 't') {
result = kVersionLessThan;
} else {
goto finish;
}
v1string = &scratch[2];
break;
}
hyphen = index(v1string, '-');
if (hyphen) {
if (*versionOperator != kVersionNone) {
goto finish;
}
*versionOperator = kVersionRange;
v2string = hyphen + 1;
*hyphen = '\0';
}
*version1 = OSKextParseVersionString(v1string);
if (*version1 == -1) {
goto finish;
}
if (hyphen) {
*version2 = OSKextParseVersionString(v2string);
if (*version2 == -1) {
goto finish;
}
}
if (*versionOperator == kVersionNone) {
*versionOperator = kVersionEqual;
}
result = 1;
finish:
if (scratch) {
free(scratch);
scratch = NULL;
}
if (result == -1) {
*error = kQEQueryErrorInvalidOrMissingArgument;
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
"Invalid version string '%s'.", string);
result = 0;
}
return result;
}
Boolean parseArch(
CFMutableDictionaryRef element,
int argc __unused,
char * const argv[],
uint32_t * num_used,
void * user_data __unused,
QEQueryError * error)
{
Boolean result = false;
uint32_t index = 1; CFStringRef archString = NULL; CFArrayRef arches = NULL; CFIndex count, i;
char * arch = NULL;
if (!argv[index]) {
*error = kQEQueryErrorInvalidOrMissingArgument;
goto finish;
}
archString = CFStringCreateWithCString(kCFAllocatorDefault,
argv[index], kCFStringEncodingUTF8);
if (!archString) {
*error = kQEQueryErrorNoMemory;
goto finish;
}
index++;
arches = CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault,archString, CFSTR(","));
if (!arches) {
goto finish;
}
count = CFArrayGetCount(arches);
for (i = 0; i < count; i++) {
CFStringRef archString = NULL;
const NXArchInfo * archinfo = NULL;
archString = CFArrayGetValueAtIndex(arches, i);
arch = createUTF8CStringForCFString(archString);
if (!arch) {
OSKextLogStringError( NULL);
goto finish;
}
archinfo = NXGetArchInfoFromName(arch);
if (!archinfo) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
"Unknown architecture %s.", arch);
*error = kQEQueryErrorInvalidOrMissingArgument;
goto finish;
}
free(arch);
arch = NULL;
}
QEQueryElementSetArgumentsArray(element, arches);
result = true;
finish:
*num_used += index;
if (archString) CFRelease(archString);
if (arches) CFRelease(arches);
if (arch) free(arch);
return result;
}
Boolean _checkArches(
OSKextRef theKext,
CFArrayRef arches)
{
Boolean result = false;
CFIndex count, i;
char * arch = NULL;
count = CFArrayGetCount(arches);
for (i = 0; i < count; i++) {
CFStringRef archString = NULL;
const NXArchInfo * archinfo = NULL;
archString = CFArrayGetValueAtIndex(arches, i);
arch = createUTF8CStringForCFString(archString);
if (!arch) {
OSKextLogStringError(theKext);
goto finish;
}
archinfo = NXGetArchInfoFromName(arch);
if (!archinfo) {
goto finish;
}
free(arch);
arch = NULL;
if (!OSKextSupportsArchitecture(theKext, archinfo)) {
goto finish;
}
}
result = true;
finish:
SAFE_FREE(arch);
return result;
}
Boolean evalArch(
CFDictionaryRef element,
void * object,
void * user_data __unused,
QEQueryError * error __unused)
{
OSKextRef theKext = (OSKextRef)object;
CFArrayRef arches = NULL;
arches = QEQueryElementGetArguments(element);
if (!arches) {
return false;
}
return _checkArches(theKext, arches);
}
typedef struct {
struct fat_header fat_hdr;
struct fat_arch fat_arch;
} FakeFatHeader;
Boolean evalArchExact(
CFDictionaryRef element,
void * object,
void * user_data __unused,
QEQueryError * error __unused)
{
Boolean result = false;
OSKextRef theKext = (OSKextRef)object;
CFArrayRef arches = NULL; CFIndex count, i;
fat_iterator fiter = NULL; char * arch = NULL; struct mach_header * farch;
const NXArchInfo * archinfo = NULL;
fiter = createFatIteratorForKext(theKext);
if (!fiter) {
goto finish;
}
arches = QEQueryElementGetArguments(element);
if (!arches) {
goto finish;
}
count = CFArrayGetCount(arches);
if (!_checkArches(theKext, arches)) {
goto finish;
}
while ((farch = (struct mach_header *)fat_iterator_next_arch(fiter, NULL))) {
int swap = 0;
struct fat_arch fakeFatArch;
Boolean thisArchFound = false;
#if DEBUG
const NXArchInfo * info;
#endif
if (farch->magic == MH_CIGAM || farch->magic == MH_CIGAM_64) {
swap = 1;
}
fakeFatArch.cputype = CondSwapInt32(swap, farch->cputype);
fakeFatArch.cpusubtype = CondSwapInt32(swap, farch->cpusubtype);
#if DEBUG
info = NXGetArchInfoFromCpuType(fakeFatArch.cputype, fakeFatArch.cpusubtype);
fprintf(stderr, " checking architecture %s\n", info->name);
#endif
for (i = 0; i < count; i++) {
CFStringRef archString = CFArrayGetValueAtIndex(arches, i);
arch = createUTF8CStringForCFString(archString);
if (!arch) {
OSKextLogStringError(theKext);
goto finish;
}
archinfo = NXGetArchInfoFromName(arch);
if (!archinfo) {
goto finish;
}
free(arch);
arch = NULL;
#if DEBUG
fprintf(stderr, " %s? ", archinfo->name);
#endif
if (NXFindBestFatArch(archinfo->cputype, archinfo->cpusubtype,
&fakeFatArch, 1)) {
thisArchFound = true;
break;
#if DEBUG
fprintf(stderr, "yes\n");
#endif
} else {
#if DEBUG
fprintf(stderr, "no\n");
#endif
}
}
if (!thisArchFound) {
goto finish;
}
}
result = true;
finish:
if (arch) free(arch);
if (fiter) fat_iterator_close(fiter);
return result;
}
Boolean parseDefinesOrReferencesSymbol(
CFMutableDictionaryRef element,
int argc __unused,
char * const argv[],
uint32_t * num_used,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
uint32_t index = 1;
if (!parseArgument(element, &argv[index], &index, user_data, error)) {
goto finish;
}
result = true;
finish:
*num_used += index;
return result;
}
Boolean evalDefinesOrReferencesSymbol(
CFDictionaryRef element,
void * object,
void * user_data __unused,
QEQueryError * error __unused)
{
Boolean result = false;
OSKextRef theKext = (OSKextRef)object;
CFStringRef predicate = NULL; Boolean seekingReference = false;
char * symbol = NULL; fat_iterator fiter = NULL; struct mach_header * farch = NULL;
void * farch_end = NULL;
Boolean isKernelComponent;
uint8_t nlist_type;
predicate = QEQueryElementGetPredicate(element);
if (CFEqual(predicate, CFSTR(kPredNameReferencesSymbol))) {
seekingReference = true;
}
symbol = createUTF8CStringForCFString(
QEQueryElementGetArgumentAtIndex(element, 0));
if (!symbol) {
goto finish;
}
fiter = createFatIteratorForKext(theKext);
if (!fiter) {
goto finish;
}
isKernelComponent = OSKextIsKernelComponent(theKext);
if (isKernelComponent && seekingReference) {
goto finish;
}
while ((farch = fat_iterator_next_arch(fiter, &farch_end))) {
macho_seek_result seek_result = macho_find_symbol(
farch, farch_end, symbol, &nlist_type, NULL);
if (seek_result == macho_seek_result_found_no_value ||
seek_result == macho_seek_result_found) {
uint8_t n_type = N_TYPE & nlist_type;
if (!isKernelComponent) {
if ((seekingReference && (n_type == N_UNDF)) ||
(!seekingReference && (n_type != N_UNDF))) {
result = true;
}
} else {
if ((!seekingReference && (n_type == N_UNDF || n_type == N_INDR))) {
result = true;
}
}
if (result) {
goto finish;
}
if ((seekingReference && (n_type == N_UNDF || n_type == N_INDR)) ||
(!seekingReference && (n_type != N_UNDF))) {
result = true;
goto finish;
}
}
}
finish:
if (fiter) fat_iterator_close(fiter);
if (symbol) free(symbol);
return result;
}
Boolean parseCommand(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * num_used,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
QueryContext * context = (QueryContext *)user_data;
CFStringRef predicate = QEQueryElementGetPredicate(element);
uint32_t index = 1;
CFDictionarySetValue(element, CFSTR(kKeywordCommand), predicate);
QEQueryElementSetPredicate(element, CFSTR(kPredNameCommand));
if (CFEqual(predicate, CFSTR(kPredNameEcho))) {
if (!parseEchoOptions(element, argc, argv, &index,
context, error)) {
goto finish;
}
} else if (CFStringHasPrefix(predicate, CFSTR(kPredPrefixPrint)) &&
!CFEqual(predicate, CFSTR(kPredNamePrint0)) &&
!CFEqual(predicate, CFSTR(kPredNamePrintDiagnostics))) {
if (!parsePrintOptions(element, argc, argv, &index,
context, error)) {
goto finish;
}
} else if (CFEqual(predicate, CFSTR(kPredNamePrint0))) {
CFDictionarySetValue(element, CFSTR(kKeywordCommand),
CFSTR(kPredNamePrint));
CFDictionarySetValue(element, CFSTR(kOptNameNulTerminate),
kCFBooleanTrue);
}
if (CFEqual(predicate, CFSTR(kPredNameEcho)) ||
CFEqual(predicate, CFSTR(kPredNamePrintProperty)) ||
CFEqual(predicate, CFSTR(kPredNamePrintMatchProperty))) {
if (!parseArgument(element, &argv[index], &index, user_data, error)) {
goto finish;
}
}
context->commandSpecified = true;
result = true;
finish:
*num_used += index;
return result;
}
char terminatorForElement(CFDictionaryRef element)
{
if (CFDictionaryGetValue(element, CFSTR(kOptNameNulTerminate))) {
return '\0';
}
return '\n';
}
Boolean evalCommand(
CFDictionaryRef element,
void * object,
void * user_data,
QEQueryError * error)
{
OSKextRef theKext = (OSKextRef)object;
QueryContext * context = (QueryContext *)user_data;
CFStringRef command = CFDictionaryGetValue(element, CFSTR(kKeywordCommand));
CFArrayRef arguments = NULL;
CFStringRef arg = NULL;
char * string = NULL;
if (CFEqual(command, CFSTR(kPredNameEcho))) {
arguments = QEQueryElementGetArguments(element);
arg = CFArrayGetValueAtIndex(arguments, 0);
string = createUTF8CStringForCFString(arg);
printf("%s", string);
if (!CFDictionaryGetValue(element, CFSTR(kPredOptNameNoNewline))) {
printf("%c", terminatorForElement(element));
}
goto finish;
} else if (CFEqual(command, CFSTR(kPredNamePrint))) {
printKext(theKext, context->pathSpec, context->extraInfo,
terminatorForElement(element));
} else if (CFEqual(command, CFSTR(kPredNameBundleName))) {
printKext(theKext, kPathsNone, context->extraInfo,
terminatorForElement(element));
} else if (CFEqual(command, CFSTR(kPredNamePrintDiagnostics))) {
g_log_stream = stdout;
OSKextLogDiagnostics(theKext, kOSKextDiagnosticsFlagAll);
g_log_stream = stderr;
} else if (CFEqual(command, CFSTR(kPredNamePrintProperty))) {
arguments = QEQueryElementGetArguments(element);
arg = CFArrayGetValueAtIndex(arguments, 0);
printKextProperty(theKext, arg, terminatorForElement(element));
} else if (CFEqual(command, CFSTR(kPredNamePrintMatchProperty))) {
arguments = QEQueryElementGetArguments(element);
arg = CFArrayGetValueAtIndex(arguments, 1);
printKextMatchProperty(theKext, arg, terminatorForElement(element));
} else if (CFEqual(command, CFSTR(kPredNamePrintArches))) {
printKextArches(theKext, terminatorForElement(element), true);
} else if (CFEqual(command, CFSTR(kPredNamePrintDependencies))) {
printKextDependencies(theKext, context->pathSpec,
context->extraInfo, terminatorForElement(element));
} else if (CFEqual(command, CFSTR(kPredNamePrintDependents))) {
printKextDependents(theKext, context->pathSpec,
context->extraInfo, terminatorForElement(element));
} else if (CFEqual(command, CFSTR(kPredNamePrintPlugins))) {
printKextPlugins(theKext, context->pathSpec, context->extraInfo,
terminatorForElement(element));
} else if (CFEqual(command, CFSTR(kPredNamePrintIntegrity))) {
printf("%s%c", "n/a", terminatorForElement(element));
} else if (CFEqual(command, CFSTR(kPredNamePrintInfoDictionary))) {
printKextInfoDictionary(theKext, context->pathSpec,
terminatorForElement(element));
} else if (CFEqual(command, CFSTR(kPredNamePrintExecutable))) {
printKextExecutable(theKext, context->pathSpec,
terminatorForElement(element));
} else {
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
finish:
if (string) free(string);
return true;
}
Boolean parseExec(
CFMutableDictionaryRef element,
int argc __unused,
char * const argv[],
uint32_t * num_used,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
QueryContext * context = (QueryContext *)user_data;
uint32_t index = 1; CFStringRef arg = NULL;
context->commandSpecified = true;
while (argv[index]) {
if (!strcmp(argv[index], kExecTerminator)) {
result = true;
index++;
goto finish;
}
SAFE_RELEASE_NULL(arg);
arg = CFStringCreateWithCString(kCFAllocatorDefault,
argv[index], kCFStringEncodingUTF8);
if (!arg) {
*error = kQEQueryErrorNoMemory;
goto finish;
}
QEQueryElementAppendArgument(element, arg);
index++;
}
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
"No terminating ; for %s.", kPredNameExec);
*error = kQEQueryErrorInvalidOrMissingArgument;
finish:
SAFE_RELEASE(arg);
*num_used += index;
return result;
}
Boolean evalExec(
CFDictionaryRef element,
void * object,
void * user_data __unused,
QEQueryError * error)
{
Boolean result = false;
pid_t pid;
int status;
OSKextRef theKext = (OSKextRef)object;
CFURLRef kextURL = NULL; CFStringRef kextPath = NULL; CFBundleRef kextBundle = NULL; CFURLRef infoDictURL = NULL; CFStringRef infoDictPath = NULL; CFURLRef executableURL = NULL; CFStringRef executablePath = NULL; char ** command_argv = NULL; CFArrayRef arguments = QEQueryElementGetArguments(element);
CFMutableStringRef scratch = NULL; char kextPathBuffer[PATH_MAX];
CFIndex count, i;
*error = kQEQueryErrorEvaluationCallbackFailed;
if (!arguments) {
goto finish;
}
count = CFArrayGetCount(arguments);
kextURL = OSKextGetURL(theKext);
if (!kextURL) {
OSKextLog(theKext,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
"Kext has no URL!");
*error = kQEQueryErrorUnspecified;
goto finish;
}
if (!CFURLGetFileSystemRepresentation(kextURL, false,
(UInt8 *)kextPathBuffer, sizeof(kextPathBuffer))) {
OSKextLogStringError(theKext);
*error = kQEQueryErrorUnspecified;
goto finish;
}
kextPath = CFURLCopyFileSystemPath(kextURL, kCFURLPOSIXPathStyle);
if (!kextPath) {
OSKextLogMemError();
*error = kQEQueryErrorNoMemory;
goto finish;
}
kextBundle = CFBundleCreate(kCFAllocatorDefault, kextURL);
if (!kextBundle) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
"Can't create bundle for %s.", kextPathBuffer);
*error = kQEQueryErrorNoMemory;
goto finish;
}
infoDictURL = _CFBundleCopyInfoPlistURL(kextBundle);
if (infoDictURL) {
infoDictPath = CFURLCopyFileSystemPath(infoDictURL, kCFURLPOSIXPathStyle);
}
executableURL = CFBundleCopyExecutableURL(kextBundle);
if (executableURL) {
executablePath = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
}
if (!kextPath || !infoDictPath) {
goto finish;
}
command_argv = (char **)malloc((1 + count) * sizeof(char *));
if (!command_argv) {
goto finish;
}
bzero(&command_argv, sizeof((1 + count) * sizeof(char *)));
for (i = 0; i < count; i++) {
scratch = CFStringCreateMutableCopy(kCFAllocatorDefault,
0, CFArrayGetValueAtIndex(arguments, i));
if (!scratch) {
goto finish;
}
CFStringFindAndReplace(scratch, CFSTR(kExecInfoDictionaryReplace),
infoDictPath, CFRangeMake(0, CFStringGetLength(scratch)), 0);
if (executablePath) {
CFStringFindAndReplace(scratch, CFSTR(kExecExecutableReplace),
executablePath, CFRangeMake(0, CFStringGetLength(scratch)), 0);
}
CFStringFindAndReplace(scratch, CFSTR(kExecBundlePathReplace),
kextPath, CFRangeMake(0, CFStringGetLength(scratch)), 0);
command_argv[i] = createUTF8CStringForCFString(scratch);
if (!command_argv[i]) {
goto finish;
}
CFRelease(scratch);
scratch = NULL;
}
command_argv[i] = NULL;
pid = fork();
switch (pid) {
case 0: execvp(command_argv[0], command_argv);
break;
case -1: perror("error forking for -exec");
goto finish;
break;
default: waitpid(-1, &status, 0);
if (WIFEXITED(status)) {
result = WEXITSTATUS(status) ? false : true;
}
break;
}
*error = kQEQueryErrorNone;
finish:
SAFE_RELEASE(scratch);
SAFE_RELEASE(kextPath);
SAFE_RELEASE(kextBundle);
SAFE_RELEASE(infoDictURL);
SAFE_RELEASE(infoDictPath);
SAFE_RELEASE(executableURL);
SAFE_RELEASE(executablePath);
if (command_argv) {
char ** arg = command_argv;
while (*arg) {
free(*arg);
arg++;
}
free(command_argv);
}
return result;
}
static int last_optind;
void reset_getopt(void)
{
optreset = 1;
opterr = 0;
optind = 1;
last_optind = optind;
return;
}
Boolean
parseStringElementOptions(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * index,
QueryContext * context,
QEQueryError * error)
{
Boolean result = true; int opt_char;
reset_getopt();
while ((opt_char = getopt_long_only(argc, argv, PROPERTY_OPTS,
property_opt_info, NULL)) != -1) {
switch (opt_char) {
case kPredOptCaseInsensitive:
CFDictionarySetValue(element, CFSTR(kSearchStyleCaseInsensitive),
kCFBooleanTrue);
last_optind = optind; break;
case kPredOptSubstring:
CFDictionarySetValue(element, CFSTR(kSearchStyleSubstring),
kCFBooleanTrue);
last_optind = optind; break;
case 0:
default:
result = handleNonOption(opt_char, argv, context, error);
goto finish;
break;
}
}
finish:
if (index) {
*index = optind; }
return result;
}
Boolean parsePrintOptions(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * index,
QueryContext * context,
QEQueryError * error)
{
Boolean result = true; int opt_char;
reset_getopt();
while ((opt_char = getopt_long_only(argc, argv, PRINT_OPTS,
print_opt_info, NULL)) != -1) {
switch (opt_char) {
case kOptNulTerminate:
CFDictionarySetValue(element, CFSTR(kOptNameNulTerminate),
kCFBooleanTrue);
last_optind = optind;
break;
case 0:
if (longopt == kLongOptQueryPredicate) {
optind = last_optind;
goto finish;
}
default:
result = handleNonOption(opt_char, argv, context, error);
goto finish;
break;
}
}
finish:
if (index) {
*index = optind; }
return result;
}
Boolean
parseEchoOptions(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * index,
QueryContext * context,
QEQueryError * error)
{
Boolean result = true; int opt_char;
reset_getopt();
while ((opt_char = getopt_long_only(argc, argv, ECHO_OPTS,
echo_opt_info, NULL)) != -1) {
switch (opt_char) {
case kPredOptNoNewline:
CFDictionarySetValue(element, CFSTR(kPredOptNameNoNewline),
kCFBooleanTrue);
last_optind = optind; break;
case kOptNulTerminate:
CFDictionarySetValue(element, CFSTR(kOptNameNulTerminate),
kCFBooleanTrue);
last_optind = optind;
break;
case 0:
default:
result = handleNonOption(opt_char, argv, context, error);
goto finish;
break;
}
}
finish:
if (index) {
*index = optind; }
return result;
}
#define QUIBBLE_PRED "%s looks like a predicate, " \
"but is being used as a property flag argument."
#define QUIBBLE_OPT "%s looks like an (illegal) option, " \
"but is being used as a property flag argument."
#define PICKY_PRED "%s is a predicate keyword (use -- to end options " \
"before arguments starting with a hyphen)."
#define PICKY_OPT "Invalid option %s for %s (use -- to end options " \
"before arguments starting with a hyphen)."
Boolean
handleNonOption(int opt_char,
char * const argv[],
QueryContext * context,
QEQueryError * error)
{
Boolean result = false;
if ( (argv[last_optind][0] != '-') || !argv[last_optind][0]) {
optind = last_optind;
result = true;
goto finish;
}
if (opt_char) {
if (context->assertiveness == kKextfindQuibbling) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
QUIBBLE_OPT, argv[last_optind]);
optind = last_optind;
} else if (context->assertiveness == kKextfindPicky) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
PICKY_OPT, argv[last_optind], argv[0]);
*error = kQEQueryErrorInvalidOrMissingArgument;
goto finish;
}
optind = last_optind;
} else {
switch (longopt) {
case kLongOptQueryPredicate:
if (context->assertiveness == kKextfindQuibbling) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
QUIBBLE_PRED, argv[last_optind]);
optind = last_optind;
} else if (context->assertiveness == kKextfindPicky) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
PICKY_PRED, argv[last_optind]);
*error = kQEQueryErrorInvalidOrMissingArgument;
goto finish;
}
optind = last_optind;
break;
default: *error = kQEQueryErrorParseCallbackFailed;
optind = last_optind;
goto finish;
break;
}
}
result = true;
finish:
return result;
}