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