aboutsummaryrefslogtreecommitdiffstats
path: root/tools/kconf_check
blob: 5f25f1763f31960240c6c32b447648fb43d3ad03 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-only

#  Copyright (c) 2009-2016 Wind River Systems, Inc.

#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License version 2 as
#  published by the Free Software Foundation.

#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#  See the GNU General Public License for more details.

# Basic sanity checks on the kernel fragments, i.e. whether a BSP
# is setting things it shouldn't, whether things are redefined,
# and whether what you asked for is what you got.


# For consistent behaviour with "grep -w"
LC_ALL=C
export LC_ALL

usage() {
    cat << EOF

 kconf_check [--help] [--report] [--meta <dir>] [--artifacts <output dir>] [--force] [-v] <path>/.config <kernel source> <fragments or CONFIG_>

      --help:           This message
      --force:          force overwrite output file if it already exists
      -v:               verbose output
      --report:         Generate a summary of issues
      --meta:           path to optional meta data (option classification)
      --artifacts:      directory to store artifacts
      .config:          .config to check
      kernel source:    kernel source tree
      fragments:        fragments to check
      CONFIG_:          command line options to check (CONFIG_FOO=<blah>)


EOF
}

if [ -z "$1" ]; then
    usage
    exit 1
fi

while [ $# -gt 0 ]; do
    case "$1" in
	--help)
	    usage
	    exit
	    ;;
	--force|-f)
	    force=t
	    ;;
        --meta)
            metadata=$2
            shift
            ;;
        --report)
            report=t
            ;;
        --artifacts|-o)
            artifacts_dir=$2
            shift
            ;;
	-w)
	    warn_on_missing=t
	    ;;
	-v) verbose=t
	    ;;
	*) break
	   ;;
    esac
    shift
done


# $1 is the .config
# $2 is the source tree
# $3 are the configuration fragments
dot_config=$1
shift
kernel_source=$1
shift
config_frags=$@

if [ ! -f "${dot_config}" ]; then
    echo "[ERROR]. Could not find .config (${dot_config})"
    exit 1
fi

if [ ! -f "${kernel_source}/Makefile" ]; then
    echo "[ERROR]. Could not find kernel source in directory ${kernel_source}"
    exit 1
fi

if [ -d ".kernel-meta" ]; then
    if [ -z "${metadata}" ]; then
        metadata=.kernel-meta
    fi
fi
if [ -n "${verbose}" ]; then
    echo "[INFO]: checking dot config: ${dot_config}"
    echo "        Against kernel source: ${kernel_source}"
    echo "        Against fragments: ${config_frags}"
    if [ -n "${metadata}" ]; then
        echo "        Against meta data: ${metadata}"
    fi
fi

# This is used to filter out duplicate declarations within a single fragment.
# People shouldn't do this, but we must behave predictably if they do...
# Also check for lines that start with "# CONFIG_" but don't end with the all
# so important " is not set" -- as this always seems to surprise people who
# think the leading hash is all that matters.
function sanitize_fragment ()
{
	ORIG_FRAG=$1
	CLEAN_FRAG=$2

	rm -f $CLEAN_FRAG
	touch $CLEAN_FRAG
	CFG_LIST=`grep '^\(# \)\{0,1\}CONFIG_[a-zA-Z0-9_]*[=\( is not set\)]' \
	  $ORIG_FRAG | sed 's/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/'`

	for i in $CFG_LIST ; do
		LASTVAL=`grep -w $i $ORIG_FRAG | tail -n1`
		echo $LASTVAL|grep -q '^# CONFIG_'
		HEAD_OK=$?
		echo $LASTVAL|grep -q ' is not set$'
		TAIL_OK=$?

		echo $LASTVAL | grep -q '.* ='
		if [ $? -eq 0 ]; then
			space_before_equals=t
		fi
		echo $LASTVAL | grep -q '= '
		if [ $? -eq 0 ]; then
			space_after_equals=t
		fi

		grep -q -w $i $CLEAN_FRAG
		if [ $? == 0 ] ; then	
			echo Warning: Value of $i is defined multiple times within fragment $ORIG_FRAG:
			grep -w $i $ORIG_FRAG
			echo
		elif [ $HEAD_OK -eq 0 ] && [ $TAIL_OK -ne 0 ]; then
			# Enforce proper "# CONFIG_FOO is not set" syntax.
			# LKC would ignore it anyway, so let them know.
			echo Warning: Ignoring \"$LASTVAL\" -- invalid CONFIG syntax.
		elif [ -n "$space_before_equals" ] || [ -n "$space_after_equals" ]; then
			echo Warning: Ignoring \"$LASTVAL\" -- spaces around equals are invalid
		else
			echo $LASTVAL >> $CLEAN_FRAG
		fi
	done
}

# This function takes a fragment, and looks in its directory to see
# if there are classifers. We take those classifiers and put them into
# files that we can check later.
function classify_options() {
    local frag=$1
    local frag_dir=$(dirname ${frag})

    # Possible fixme -- could check hdw additions against the non-hdw
    # and vice versa -- it would allow folks to mask things.
    # See alternate solution just at the bottom of this loop.
    if [ -f $frag_dir/non-hardware.kcf ]; then
	cat $frag_dir/non-hardware.kcf | grep -v '^#' | \
	    sed '/^$/d' >> $KCONF_NONHDW
    fi
    if [ -f $frag_dir/hardware.kcf ]; then
	cat $frag_dir/hardware.kcf | grep -v '^#' | \
	    sed '/^$/d' >> $KCONF_HDW
    fi
    if [ -f $frag_dir/non-hardware.cfg ]; then
	cat $frag_dir/non-hardware.cfg | grep -v '^#' | \
	    sed '/^$/d' >> $CONF_NONHDW
    fi
    if [ -f $frag_dir/hardware.cfg ]; then
	cat $frag_dir/hardware.cfg | grep -v '^#' | \
	    sed '/^$/d' >> $CONF_HDW
    fi
    if [ -f $frag_dir/required.cfg ]; then
	cat $frag_dir/required.cfg | grep -v '^#' | \
	    sed '/^$/d' >> $CONF_REQUIRED
    fi
    if [ -f $frag_dir/optional.cfg ]; then
	cat $frag_dir/optional.cfg | grep -v '^#' | \
	    sed '/^$/d' >> $CONF_OPTIONAL
    fi
}

# Temporary files to store sanitized list and fragment errors.
# Create those files in /tmp because /tmp in most cases is stored in RAM
# This greatly increases performance, as we will append data to those files
# and some file systems (like ZFS) are very slow at appends.
FRAGMENT_ERRORS_TMP=`mktemp`
SANITIZED_LIST_TMP=`mktemp`

# Clean temporary files from /tmp on exit
function cleanup {
    rm -f $FRAGMENT_ERRORS_TMP
    rm -f $SANITIZED_LIST_TMP
}

trap cleanup EXIT

# step #1.
# run merge_config.sh (without regenerating the .config), and capture its output.
# This gets us redefined options, and a combined (but unprocessed) config.
#
if [ -n "${artifacts_dir}" ]; then
    LOGDIR=${artifacts_dir}
else
    LOGDIR=".kconf_scratch"
fi
mkdir -p ${LOGDIR}

# On the fly list of all known hardware related Kconfig* files
KCONF_HDW=$LOGDIR/hardware.kcf
# Same for all known non-hardware related Kconfig* files
KCONF_NONHDW=$LOGDIR/non-hardware.kcf
rm -f ${KCONF_HDW}
rm -f ${KCONF_NONHDW}
touch ${KCONF_HDW}
touch ${KCONF_NONHDW}

# On the fly override for hardware CONFIG items that are in a non-hardware Kconfig.
# These are used to prevent warnings
CONF_HDW=$LOGDIR/always_hardware.cfg
# Same for non-hardware CONFIG items that are in a hardware Kconfig.
CONF_NONHDW=$LOGDIR/always_nonhardware.cfg
rm -f ${CONF_HDW}
rm -f ${CONF_NONHDW}

CONF_REQUIRED=$LOGDIR/required_configs.cfg
CONF_OPTIONAL=$LOGDIR/optional_configs.cfg

# step #2.
# find all the Kconfig* files in the source dir, we'll use this for invalid
# option checking later
#
find ${kernel_source} \
     -path $kernel_source/.kernel-meta -prune				\
     -o -path $kernel_source/.git -prune		                \
     -o -type f -a -name 'Kconfig*' -print |				\
    sort | sed 's=^'$kernel_source'==' |                                \
    sed 's%^/%%' > ${LOGDIR}/all.kcf


# Collect the list of all avail related CONFIG_ options from the
# known list of all Kconfig* files.  Again, must filter dups.
rm -f ${LOGDIR}/all.cfg
for i in `cat ${LOGDIR}/all.kcf` ; do
    cat ${kernel_source}/$i | grep '^[ 	]*\(menu\)*config' | \
	awk '{print "CONFIG_"$2}' >> ${LOGDIR}/all.cfg
done
mv -f ${LOGDIR}/all.cfg ${LOGDIR}/all.cfg~
cat ${LOGDIR}/all.cfg~ | sort | uniq > ${LOGDIR}/all.cfg
rm -f ${LOGDIR}/all.cfg~

# This is the .config passed on the command line. This .config has been
# processed by the kernel build process
dot_config=$(readlink -f ${dot_config})

# take any command line options, and wrap them in a .cfg, so we don't have
# to treat them as special.
rm -f ${LOGDIR}/cmd_line_frag.cfg
touch ${LOGDIR}/cmd_line_frag.cfg
for c in ${config_frags}; do
    case ${c} in
        CONFIG_*)
            echo ${c} >> ${LOGDIR}/cmd_line_frag.cfg
            ;;
        *)
            configs_abs="${configs_abs} $(readlink -f ${c})"
            ;;
    esac
done
if [ -s "${LOGDIR}/cmd_line_frag.cfg" ]; then
    configs_abs="${configs_abs} $(readlink -f ${LOGDIR}/cmd_line_frag.cfg)"
fi

# Step 3.
# run merge_config to look for repeated options, etc. We redirect the output
# to our log directory, so we can process things later.
#
if [ -n "${verbose}" ]; then
    echo "[INFO]: creating merged config"
    echo "        merge_config.sh -O ${LOGDIR} -m ${configs_abs}"
fi
merge_config.sh -O ${LOGDIR} -m ${configs_abs} &> ${LOGDIR}/merge_config_audit.log

if [ -n "${metadata}" ]; then
    if [ -n "${verbose}" ]; then
        echo "[INFO]: meta data detected, classifying config options"
    fi
fi

# check for per-fragment errors
if [ -n "${verbose}" ]; then
    echo "[INFO]: checking for per fragment errors"
fi
SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p"
rm -f ${LOGDIR}/fragment_errors.txt
declare -A CONFIGMAP
for c in ${configs_abs}; do
    sanitize_fragment ${c} $SANITIZED_LIST_TMP >> $FRAGMENT_ERRORS_TMP
    cfg_list=$(sed -n "$SED_CONFIG_EXP" ${c})
    for option in ${cfg_list}; do
        if [ -z "${CONFIGMAP[${option}]}" ]; then
            CONFIGMAP[${option}]=${c}
        else
            CONFIGMAP[${option}]="${CONFIGMAP[${option}]} ${c}"
        fi
    done

    if [ -n "${metadata}" ]; then
        classify_options ${c}
    fi
done

mv $FRAGMENT_ERRORS_TMP ${LOGDIR}/fragment_errors.txt
mv $SANITIZED_LIST_TMP ${LOGDIR}/sanitized_list

# If we had meta data, we can use the classifications to group the options.
if [ -n "${metadata}" ]; then
    rm -f $LOGDIR/avail_hardware.cfg
    for i in `cat $KCONF_HDW` ; do
	if [ -f ${kernel_source}/$i ] ; then
	    cat ${kernel_source}/$i | grep '^\(menu\)*config ' | \
		awk '{print "CONFIG_"$2}' >> $LOGDIR/avail_hardware.cfg
	fi
    done

    # The following files come from the processing of the meta data (i.e. if scc/spp was used):
    #    hardware_frags.txt
    #    non-hardware_frags.txt
    #    required_frags.txt
    #    optional_frags.txt

    rm -f $LOGDIR/input_hardware_configs.cfg~
    touch $LOGDIR/input_hardware_configs.cfg
    if [ -s "${metadata}/hardware_frags.txt" ]; then
        for i in `cat ${metadata}/hardware_frags.txt` ; do
            cat $i | \
                grep '^\(# \)\{0,1\}CONFIG_[a-zA-Z0-9_]*[=\( is not set\)]' | \
                sed 's/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/' \
                    >> $LOGDIR/input_hardware_configs.cfg~
        done
        if [ -e $LOGDIR/input_hardware_configs.cfg~ ]; then
            sort < $LOGDIR/input_hardware_configs.cfg~ | uniq > $LOGDIR/input_hardware_configs.cfg
        fi
        rm -f $KCONF_DIR/input_hardware_configs.cfg~
    fi

    # and non-hardware!
    rm -f $LOGDIR/input_nonhardware_configs.cfg~
    touch $LOGDIR/input_nonhardware_configs.cfg
    if [ -s "${metadata}/non-hardware_frags.txt" ]; then
        for i in `cat ${metadata}/non-hardware_frags.txt` ; do
            cat $i | \
                grep -e '^\(# \)\{0,1\}CONFIG_[a-zA-Z0-9_]*[=\( is not set\)]' -e '^\(# \)\{0,1\}CONFIG_[a-zA-Z0-9_]*' | \
                sed 's/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/' \
                    >> $LOGDIR/input_nonhardware_configs.cfg~
        done
        if [ -e $LOGDIR/input_nonhardware_configs.cfg~ ]; then
            sort < $LOGDIR/input_nonhardware_configs.cfg~ | uniq > $LOGDIR/input_nonhardware_configs.cfg
        fi
        rm -f $KCONF_DIR/input_nonhardware_configs.cfg~
    fi

    # and required!
    rm -f $LOGDIR/input_required_configs.cfg~
    touch $LOGDIR/input_required_configs.cfg
    if [ -s "${metadata}/required_frags.txt" ]; then
        for i in `cat ${metadata}/required_frags.txt` ; do
            cat $i | \
                grep '^\(# \)\{0,1\}CONFIG_[a-zA-Z0-9_]*[=\( is not set\)]' | \
                sed 's/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/' \
                    >> $LOGDIR/input_required_configs.cfg~
        done
        if [ -e $LOGDIR/input_required_configs.cfg~ ]; then
            sort < $LOGDIR/input_required_configs.cfg~ | uniq > $LOGDIR/input_required_configs.cfg
        fi
        rm -f $KCONF_DIR/input_required_configs.cfg~
    fi

    # and optional!
    rm -f $LOGDIR/input_optional_configs.cfg~
    touch $LOGDIR/input_optional_configs.cfg
    if [ -s "${metadata}/optional_frags.txt" ]; then
        for i in `cat ${metadata}/optional_frags.txt` ; do
            cat $i | \
                grep '^\(# \)\{0,1\}CONFIG_[a-zA-Z0-9_]*[=\( is not set\)]' | \
                sed 's/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/' \
                    >> $LOGDIR/input_optional_configs.cfg~
        done
        if [ -e $LOGDIR/input_optional_configs.cfg~ ]; then
            sort < $LOGDIR/input_optional_configs.cfg~ | uniq > $LOGDIR/input_optional_configs.cfg
        fi
        rm -f $KCONF_DIR/input_optional_configs.cfg~
    fi
fi

# Debug: dump all the configs and what fragment they came from
# for K in "${!CONFIGMAP[@]}"; do
#    echo $K --- ${CONFIGMAP[$K]};
# done

if [ -n "${verbose}" ]; then
    echo "[INFO]: checking for redefinitions"
fi
# break the merge log down into parts that can be processed later
grep -A2 "^Value of" ${LOGDIR}/merge_config_audit.log > ${LOGDIR}/redefinition.txt

# The tmp .config is one that merge_config assembled, but didn't run through
# the actual kernel configuration. We check that against the one passed to this
# script, that WAS run throught he process.
if [ -n "${verbose}" ]; then
    echo "[INFO]: checking for dropped CONFIG_ entries"
fi
rm -f ${LOGDIR}/mismatch.cfg
rm -f ${LOGDIR}/mismatch.txt
TMP_FILE="${LOGDIR}/.config"
for CFG in $(sed -n "$SED_CONFIG_EXP" $TMP_FILE); do
    REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE)
    ACTUAL_VAL=$(grep -w -e "$CFG" ${dot_config})

    # special case. If someone asked for # CONFIG_FOO is not set and CONFIG_FOO
    # doesn't appear in the final .config, this is not a mismatch .. it is a
    # variant of what they wanted. This allows common fragments to set things,
    # but for a specific BSP to cleanly override them (without declaring them as
    # "non hw") when you know dependencies won't be met.
    asked_for_not_set=
    log_mismatch=t
    echo "$REQUESTED_VAL" | grep -q "is not set"
    if [ $? -eq 0 ]; then
        asked_for_not_set=t
    fi

    if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then
        if [ -n "$asked_for_not_set" ] && [ "$ACTUAL_VAL" = "" ]; then
            log_mismatch=
        fi
        if [ -n "${log_mismatch}" ]; then
            echo "Config: $CFG" >> ${LOGDIR}/mismatch.txt
            echo "From: ${CONFIGMAP[$CFG]}" >> ${LOGDIR}/mismatch.txt
            echo "Requested value:  $REQUESTED_VAL" >> ${LOGDIR}/mismatch.txt
            echo "Actual value:     $ACTUAL_VAL" >> ${LOGDIR}/mismatch.txt
            echo "" >> ${LOGDIR}/mismatch.txt
            echo $CFG >> ${LOGDIR}/mismatch.cfg
        fi
    fi
done

# Find the options that are just obsolete trash and don't exist in any
# file whatsoever (leftovers from kernel uprev, etc etc)
if [ -n "${verbose}" ]; then
    echo "[INFO]: checking for invalid/obsolete CONFIG_ entries"
fi
rm -f ${LOGDIR}/invalid.cfg
touch ${LOGDIR}/invalid.cfg
for i in "${!CONFIGMAP[@]}"; do
    grep -q -x -e $i ${LOGDIR}/all.cfg
    if [ $? != 0 ]; then
	echo $i >> ${LOGDIR}/invalid.cfg
    fi
done

# we are done if no report has been requested
if [ -z "${report}" ]; then
    exit 0
fi

output_report_header()
{
    echo ""
    echo "kernel config audit results"
    echo "==========================="
}

if [ -s $LOGDIR/invalid.cfg ]; then
    reported=t
    OPT_COUNT=`wc -l $LOGDIR/invalid.cfg | awk '{print $1}'`
    echo -n "[invalid ($OPT_COUNT)]: "
    echo $LOGDIR/invalid.cfg
    echo "   This BSP sets config options that are not offered anywhere within this kernel"
    echo
fi

if [ -s "$LOGDIR/fragment_errors.txt" ]; then
    reported=t
    OPT_COUNT=`cat $LOGDIR/fragment_errors.txt |grep Warning: | wc -l | awk '{print $1}'`
    echo -n "[errors ($OPT_COUNT): "
    echo $LOGDIR/fragment_errors.txt
    echo "   There are errors withing the config fragments."
    echo
fi

if [ -n "$verbose" ] && [ -s $LOGDIR/redefinition.txt ]; then
    reported=t
    OPT_COUNT=`cat $LOGDIR/redefinition.txt |grep Value | wc -l | awk '{print $1}'`
    echo -n "[redefined ($OPT_COUNT)]: "
    echo $LOGDIR/redefinition.txt
    echo "   kernel configuration options were defined in more than one config"
    echo "   fragment and had their value changed from their initial setting"
    echo
fi

# One could argue that any mismatch is a valid reason to declare failure.
if [ -s $LOGDIR/mismatch.txt ]; then
    reported=t

    # if there was meta data, and hence hardware classifications, we only
    # report those options as missing. We also shouldn't report any that
    # were invalid, since that is reported separately.
    if [ -e "$LOGDIR/input_hardware_configs.cfg" ] || [ -e "$LOGDIR/input_required_configs.cfg" ]; then
        rm -f $LOGDIR/mismatch-hardware.txt
        cp $LOGDIR/mismatch.txt $LOGDIR/mismatch-all.txt
        rm -f $LOGDIR/mismatch.txt

        OPT_COUNT=0
        for opt in `cat $LOGDIR/mismatch.cfg`; do
            report=
            grep -q -w $opt $LOGDIR/input_hardware_configs.cfg $LOGDIR/input_required_configs.cfg
            if [ $? -eq 0 ]; then
                # so we know it was a hardware option, and we should likely report it, but lets
                # do another check .. if it isn't invalid, we should report it. If it is in the
                # invalid list we skip it
                inhibit_report=
                grep -q -w $opt $LOGDIR/invalid.cfg
                if [ $? -eq 0 ]; then
                    inhibit_report=t
                fi
                grep -q -w $opt $LOGDIR/input_nonhardware_configs.cfg
                if [ $? -eq 0 ]; then
                    inhibit_report=t
                fi
                if [ -z "$inhibit_report" ]; then
                    report=t
                fi
            fi

            if [ -n "${report}" ]; then
                let OPT_COUNT=$OPT_COUNT+1
                echo "---------- $opt -----------------" >> $LOGDIR/mismatch.txt
                grep -A4 "Config: $opt" $LOGDIR/mismatch-all.txt >> $LOGDIR/mismatch.txt

                # drop CONFIG_ from the symbol name, since symbol_why doesn't expect it.
                opt_to_check=$(echo $opt | sed 's%CONFIG_%%')
                srctree=. CC=gcc ARCH=x86 symbol_why.py --dotconfig=${dot_config} --ksrc="." --conditions $opt_to_check >> $LOGDIR/mismatch.txt
                echo "" >> $LOGDIR/mismatch.txt
            fi
        done
        if [ $OPT_COUNT -gt 0 ]; then
            echo -n "[mismatch ($OPT_COUNT)]: "
            echo $LOGDIR/mismatch.txt
            echo "   There were hardware options requested that do not"
            echo "   have a corresponding value present in the final \".config\" file."
            echo "   This probably means you aren't getting the config you wanted."
            echo
        fi
    else
        OPT_COUNT=`grep '^Actual value' $LOGDIR/mismatch.txt | wc -l | awk '{print $1}'`
        echo -n "[mismatch ($OPT_COUNT)]: "
        echo $LOGDIR/mismatch.txt
        echo "   There were options requested that do not"
        echo "   have a corresponding value present in the final \".config\" file."
        echo "   This probably means you aren't getting the config you wanted."
        echo
    fi
fi

if [ -z "$reported" ]; then
    echo "[kconfig] clean configuration. No Warnings or Errors found."
fi