151839e29SAndy Shevchenko#!/usr/bin/env python3 2b2441318SGreg Kroah-Hartman# SPDX-License-Identifier: GPL-2.0 3a717417eSTim Bird# 4a717417eSTim Bird# diffconfig - a tool to compare .config files. 5a717417eSTim Bird# 6a717417eSTim Bird# originally written in 2006 by Matt Mackall 7a717417eSTim Bird# (at least, this was in his bloatwatch source code) 8a717417eSTim Bird# last worked on 2008 by Tim Bird 9a717417eSTim Bird# 10a717417eSTim Bird 11a717417eSTim Birdimport sys, os 12a717417eSTim Bird 13a717417eSTim Birddef usage(): 14c8272fafSMike Pagano print("""Usage: diffconfig [-h] [-m] [<config1> <config2>] 15a717417eSTim Bird 16a717417eSTim BirdDiffconfig is a simple utility for comparing two .config files. 17a717417eSTim BirdUsing standard diff to compare .config files often includes extraneous and 18a717417eSTim Birddistracting information. This utility produces sorted output with only the 19a717417eSTim Birdchanges in configuration values between the two files. 20a717417eSTim Bird 21a717417eSTim BirdAdded and removed items are shown with a leading plus or minus, respectively. 22a717417eSTim BirdChanged items show the old and new values on a single line. 23a717417eSTim Bird 24a717417eSTim BirdIf -m is specified, then output will be in "merge" style, which has the 25a717417eSTim Birdchanged and new values in kernel config option format. 26a717417eSTim Bird 27a717417eSTim BirdIf no config files are specified, .config and .config.old are used. 28a717417eSTim Bird 29a717417eSTim BirdExample usage: 30a717417eSTim Bird $ diffconfig .config config-with-some-changes 31a717417eSTim Bird-EXT2_FS_XATTR n 32a717417eSTim Bird CRAMFS n -> y 33a717417eSTim Bird EXT2_FS y -> n 34a717417eSTim Bird LOG_BUF_SHIFT 14 -> 16 35a717417eSTim Bird PRINTK_TIME n -> y 36c8272fafSMike Pagano""") 37a717417eSTim Bird sys.exit(0) 38a717417eSTim Bird 39a717417eSTim Bird# returns a dictionary of name/value pairs for config items in the file 40a717417eSTim Birddef readconfig(config_file): 41a717417eSTim Bird d = {} 42a717417eSTim Bird for line in config_file: 43a717417eSTim Bird line = line[:-1] 44a717417eSTim Bird if line[:7] == "CONFIG_": 45a717417eSTim Bird name, val = line[7:].split("=", 1) 46a717417eSTim Bird d[name] = val 47a717417eSTim Bird if line[-11:] == " is not set": 48a717417eSTim Bird d[line[9:-11]] = "n" 49a717417eSTim Bird return d 50a717417eSTim Bird 51a717417eSTim Birddef print_config(op, config, value, new_value): 52a717417eSTim Bird global merge_style 53a717417eSTim Bird 54a717417eSTim Bird if merge_style: 55a717417eSTim Bird if new_value: 56a717417eSTim Bird if new_value=="n": 57c8272fafSMike Pagano print("# CONFIG_%s is not set" % config) 58a717417eSTim Bird else: 59c8272fafSMike Pagano print("CONFIG_%s=%s" % (config, new_value)) 60a717417eSTim Bird else: 61a717417eSTim Bird if op=="-": 62c8272fafSMike Pagano print("-%s %s" % (config, value)) 63a717417eSTim Bird elif op=="+": 64c8272fafSMike Pagano print("+%s %s" % (config, new_value)) 65a717417eSTim Bird else: 66c8272fafSMike Pagano print(" %s %s -> %s" % (config, value, new_value)) 67a717417eSTim Bird 68*87c7ee67SMasahiro Yamadadef show_diff(): 69a717417eSTim Bird global merge_style 70a717417eSTim Bird 71a717417eSTim Bird # parse command line args 72a717417eSTim Bird if ("-h" in sys.argv or "--help" in sys.argv): 73a717417eSTim Bird usage() 74a717417eSTim Bird 75a717417eSTim Bird merge_style = 0 76a717417eSTim Bird if "-m" in sys.argv: 77a717417eSTim Bird merge_style = 1 78a717417eSTim Bird sys.argv.remove("-m") 79a717417eSTim Bird 80a717417eSTim Bird argc = len(sys.argv) 81a717417eSTim Bird if not (argc==1 or argc == 3): 82c8272fafSMike Pagano print("Error: incorrect number of arguments or unrecognized option") 83a717417eSTim Bird usage() 84a717417eSTim Bird 85a717417eSTim Bird if argc == 1: 86a717417eSTim Bird # if no filenames given, assume .config and .config.old 87a717417eSTim Bird build_dir="" 88c8272fafSMike Pagano if "KBUILD_OUTPUT" in os.environ: 89a717417eSTim Bird build_dir = os.environ["KBUILD_OUTPUT"]+"/" 90a717417eSTim Bird configa_filename = build_dir + ".config.old" 91a717417eSTim Bird configb_filename = build_dir + ".config" 92a717417eSTim Bird else: 93a717417eSTim Bird configa_filename = sys.argv[1] 94a717417eSTim Bird configb_filename = sys.argv[2] 95a717417eSTim Bird 966bf2e84bSMike Pagano try: 97c8272fafSMike Pagano a = readconfig(open(configa_filename)) 98c8272fafSMike Pagano b = readconfig(open(configb_filename)) 996bf2e84bSMike Pagano except (IOError): 1006bf2e84bSMike Pagano e = sys.exc_info()[1] 1016bf2e84bSMike Pagano print("I/O error[%s]: %s\n" % (e.args[0],e.args[1])) 1026bf2e84bSMike Pagano usage() 103a717417eSTim Bird 104a717417eSTim Bird # print items in a but not b (accumulate, sort and print) 105a717417eSTim Bird old = [] 106a717417eSTim Bird for config in a: 107a717417eSTim Bird if config not in b: 108a717417eSTim Bird old.append(config) 109a717417eSTim Bird old.sort() 110a717417eSTim Bird for config in old: 111a717417eSTim Bird print_config("-", config, a[config], None) 112a717417eSTim Bird del a[config] 113a717417eSTim Bird 114a717417eSTim Bird # print items that changed (accumulate, sort, and print) 115a717417eSTim Bird changed = [] 116a717417eSTim Bird for config in a: 117a717417eSTim Bird if a[config] != b[config]: 118a717417eSTim Bird changed.append(config) 119a717417eSTim Bird else: 120a717417eSTim Bird del b[config] 121a717417eSTim Bird changed.sort() 122a717417eSTim Bird for config in changed: 123a717417eSTim Bird print_config("->", config, a[config], b[config]) 124a717417eSTim Bird del b[config] 125a717417eSTim Bird 126a717417eSTim Bird # now print items in b but not in a 127a717417eSTim Bird # (items from b that were in a were removed above) 128c8272fafSMike Pagano new = sorted(b.keys()) 129a717417eSTim Bird for config in new: 130a717417eSTim Bird print_config("+", config, None, b[config]) 131a717417eSTim Bird 132*87c7ee67SMasahiro Yamadadef main(): 133*87c7ee67SMasahiro Yamada try: 134*87c7ee67SMasahiro Yamada show_diff() 135*87c7ee67SMasahiro Yamada except BrokenPipeError: 136*87c7ee67SMasahiro Yamada # Python flushes standard streams on exit; redirect remaining output 137*87c7ee67SMasahiro Yamada # to devnull to avoid another BrokenPipeError at shutdown 138*87c7ee67SMasahiro Yamada devnull = os.open(os.devnull, os.O_WRONLY) 139*87c7ee67SMasahiro Yamada os.dup2(devnull, sys.stdout.fileno()) 140*87c7ee67SMasahiro Yamada sys.exit(1) # Python exits with error code 1 on EPIPE 141*87c7ee67SMasahiro Yamada 142*87c7ee67SMasahiro Yamada 143*87c7ee67SMasahiro Yamadaif __name__ == '__main__': 144a717417eSTim Bird main() 145