xref: /kernel/linux/linux-6.6/scripts/diffconfig (revision 62306a36)
162306a36Sopenharmony_ci#!/usr/bin/env python3
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci#
462306a36Sopenharmony_ci# diffconfig - a tool to compare .config files.
562306a36Sopenharmony_ci#
662306a36Sopenharmony_ci# originally written in 2006 by Matt Mackall
762306a36Sopenharmony_ci#  (at least, this was in his bloatwatch source code)
862306a36Sopenharmony_ci# last worked on 2008 by Tim Bird
962306a36Sopenharmony_ci#
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ciimport sys, os
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cidef usage():
1462306a36Sopenharmony_ci    print("""Usage: diffconfig [-h] [-m] [<config1> <config2>]
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciDiffconfig is a simple utility for comparing two .config files.
1762306a36Sopenharmony_ciUsing standard diff to compare .config files often includes extraneous and
1862306a36Sopenharmony_cidistracting information.  This utility produces sorted output with only the
1962306a36Sopenharmony_cichanges in configuration values between the two files.
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciAdded and removed items are shown with a leading plus or minus, respectively.
2262306a36Sopenharmony_ciChanged items show the old and new values on a single line.
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ciIf -m is specified, then output will be in "merge" style, which has the
2562306a36Sopenharmony_cichanged and new values in kernel config option format.
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciIf no config files are specified, .config and .config.old are used.
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ciExample usage:
3062306a36Sopenharmony_ci $ diffconfig .config config-with-some-changes
3162306a36Sopenharmony_ci-EXT2_FS_XATTR  n
3262306a36Sopenharmony_ci CRAMFS  n -> y
3362306a36Sopenharmony_ci EXT2_FS  y -> n
3462306a36Sopenharmony_ci LOG_BUF_SHIFT  14 -> 16
3562306a36Sopenharmony_ci PRINTK_TIME  n -> y
3662306a36Sopenharmony_ci""")
3762306a36Sopenharmony_ci    sys.exit(0)
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci# returns a dictionary of name/value pairs for config items in the file
4062306a36Sopenharmony_cidef readconfig(config_file):
4162306a36Sopenharmony_ci    d = {}
4262306a36Sopenharmony_ci    for line in config_file:
4362306a36Sopenharmony_ci        line = line[:-1]
4462306a36Sopenharmony_ci        if line[:7] == "CONFIG_":
4562306a36Sopenharmony_ci            name, val = line[7:].split("=", 1)
4662306a36Sopenharmony_ci            d[name] = val
4762306a36Sopenharmony_ci        if line[-11:] == " is not set":
4862306a36Sopenharmony_ci            d[line[9:-11]] = "n"
4962306a36Sopenharmony_ci    return d
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cidef print_config(op, config, value, new_value):
5262306a36Sopenharmony_ci    global merge_style
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci    if merge_style:
5562306a36Sopenharmony_ci        if new_value:
5662306a36Sopenharmony_ci            if new_value=="n":
5762306a36Sopenharmony_ci                print("# CONFIG_%s is not set" % config)
5862306a36Sopenharmony_ci            else:
5962306a36Sopenharmony_ci                print("CONFIG_%s=%s" % (config, new_value))
6062306a36Sopenharmony_ci    else:
6162306a36Sopenharmony_ci        if op=="-":
6262306a36Sopenharmony_ci            print("-%s %s" % (config, value))
6362306a36Sopenharmony_ci        elif op=="+":
6462306a36Sopenharmony_ci            print("+%s %s" % (config, new_value))
6562306a36Sopenharmony_ci        else:
6662306a36Sopenharmony_ci            print(" %s %s -> %s" % (config, value, new_value))
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cidef show_diff():
6962306a36Sopenharmony_ci    global merge_style
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci    # parse command line args
7262306a36Sopenharmony_ci    if ("-h" in sys.argv or "--help" in sys.argv):
7362306a36Sopenharmony_ci        usage()
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci    merge_style = 0
7662306a36Sopenharmony_ci    if "-m" in sys.argv:
7762306a36Sopenharmony_ci        merge_style = 1
7862306a36Sopenharmony_ci        sys.argv.remove("-m")
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci    argc = len(sys.argv)
8162306a36Sopenharmony_ci    if not (argc==1 or argc == 3):
8262306a36Sopenharmony_ci        print("Error: incorrect number of arguments or unrecognized option")
8362306a36Sopenharmony_ci        usage()
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci    if argc == 1:
8662306a36Sopenharmony_ci        # if no filenames given, assume .config and .config.old
8762306a36Sopenharmony_ci        build_dir=""
8862306a36Sopenharmony_ci        if "KBUILD_OUTPUT" in os.environ:
8962306a36Sopenharmony_ci            build_dir = os.environ["KBUILD_OUTPUT"]+"/"
9062306a36Sopenharmony_ci        configa_filename = build_dir + ".config.old"
9162306a36Sopenharmony_ci        configb_filename = build_dir + ".config"
9262306a36Sopenharmony_ci    else:
9362306a36Sopenharmony_ci        configa_filename = sys.argv[1]
9462306a36Sopenharmony_ci        configb_filename = sys.argv[2]
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci    try:
9762306a36Sopenharmony_ci        a = readconfig(open(configa_filename))
9862306a36Sopenharmony_ci        b = readconfig(open(configb_filename))
9962306a36Sopenharmony_ci    except (IOError):
10062306a36Sopenharmony_ci        e = sys.exc_info()[1]
10162306a36Sopenharmony_ci        print("I/O error[%s]: %s\n" % (e.args[0],e.args[1]))
10262306a36Sopenharmony_ci        usage()
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci    # print items in a but not b (accumulate, sort and print)
10562306a36Sopenharmony_ci    old = []
10662306a36Sopenharmony_ci    for config in a:
10762306a36Sopenharmony_ci        if config not in b:
10862306a36Sopenharmony_ci            old.append(config)
10962306a36Sopenharmony_ci    old.sort()
11062306a36Sopenharmony_ci    for config in old:
11162306a36Sopenharmony_ci        print_config("-", config, a[config], None)
11262306a36Sopenharmony_ci        del a[config]
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci    # print items that changed (accumulate, sort, and print)
11562306a36Sopenharmony_ci    changed = []
11662306a36Sopenharmony_ci    for config in a:
11762306a36Sopenharmony_ci        if a[config] != b[config]:
11862306a36Sopenharmony_ci            changed.append(config)
11962306a36Sopenharmony_ci        else:
12062306a36Sopenharmony_ci            del b[config]
12162306a36Sopenharmony_ci    changed.sort()
12262306a36Sopenharmony_ci    for config in changed:
12362306a36Sopenharmony_ci        print_config("->", config, a[config], b[config])
12462306a36Sopenharmony_ci        del b[config]
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci    # now print items in b but not in a
12762306a36Sopenharmony_ci    # (items from b that were in a were removed above)
12862306a36Sopenharmony_ci    new = sorted(b.keys())
12962306a36Sopenharmony_ci    for config in new:
13062306a36Sopenharmony_ci        print_config("+", config, None, b[config])
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cidef main():
13362306a36Sopenharmony_ci    try:
13462306a36Sopenharmony_ci        show_diff()
13562306a36Sopenharmony_ci    except BrokenPipeError:
13662306a36Sopenharmony_ci        # Python flushes standard streams on exit; redirect remaining output
13762306a36Sopenharmony_ci        # to devnull to avoid another BrokenPipeError at shutdown
13862306a36Sopenharmony_ci        devnull = os.open(os.devnull, os.O_WRONLY)
13962306a36Sopenharmony_ci        os.dup2(devnull, sys.stdout.fileno())
14062306a36Sopenharmony_ci        sys.exit(1)  # Python exits with error code 1 on EPIPE
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ciif __name__ == '__main__':
14462306a36Sopenharmony_ci    main()
145