diff options
Diffstat (limited to 'bin/common/srtool_patcher.py')
-rwxr-xr-x | bin/common/srtool_patcher.py | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/bin/common/srtool_patcher.py b/bin/common/srtool_patcher.py new file mode 100755 index 00000000..6bf65755 --- /dev/null +++ b/bin/common/srtool_patcher.py @@ -0,0 +1,252 @@ +#!/usr/bin/env python3 +# +# ex:ts=4:sw=4:sts=4:et +# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +# +# Security Response Tool Implementation +# +# Copyright (C) 2019 Wind River Systems +# +# 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. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# +# Theory of operation +# +# * This script runs quick sanity tests +# * The '--init-test' option will: +# * Report the host package versions +# * Report errors if any required tables are empty +# * Report the running instance of the SRTool +# + +import os +import sys +import argparse +import json + +# Setup: +verbose = False + +################################# +# extract_custom_patch +# + +def extract_custom_patch(custom_file,clean_file,patch_file,label,patcher_dir): + tag_begin = "%s_EXTENSION_BEGIN" % label + tag_end = "%s_EXTENSION_END" % label + ret = 0 + + # Insure patcher working directory is ready + if not patcher_dir: + patcher_dir = os.path.dirname(custom_file) + try: + os.makedirs(patcher_dir) + except: + pass + # Prepare defaults + if not clean_file: + clean_file = os.path.join(patcher_dir,os.path.basename(custom_file) + '.clean') + if not patch_file: + patch_file = os.path.join(patcher_dir,os.path.basename(custom_file) + '.patch') + + with open(custom_file, 'r') as fs: + with open(clean_file, 'w') as fd: + state = "find" + for line in fs: + #print("LINE(%s):%s" % (state,line.strip())) + if state == "find": + if 0 < line.find(tag_begin): + #print("START:$line") + state = "found" + continue + elif state == "found": + if 0 < line.find(tag_end): + #print("STOP:$line") + state = "blank" + continue + elif state == "blank": + state = "find" + # if next line after stop is blank, hide that also + if not line.strip(): + continue + # Normal line? + if state != "found": + fd.write('%s' % line) + # Did we end cleanly? + if state != "find": + print("ERROR: START not STOPPED (%s)" % state) + os.system("diff -u %s %s > %s" % (clean_file,custom_file,patch_file)) + print("Custom File: %s" % (custom_file)) + print("Clean File: %s" % (clean_file)) + print("Patch File: %s" % (patch_file)) + return(ret,clean_file,patch_file) + +################################# +# merge_original +# + +def merge_original(custom_file,original_file,patch_file,label,patcher_dir): + ret,clean_file,patch_file = extract_custom_patch(custom_file,'',patch_file,label,patcher_dir) + custom_saved = os.path.join(os.path.dirname(patch_file),os.path.basename(custom_file) + '.saved') + if 0 == ret: + print("* Preserving custom file as '%s'" % custom_saved) + cmd = "cp %s %s" % (custom_file,custom_saved) + print(cmd) + os.system(cmd) + print("* Merging original file '%s' into custom file" % original_file) + cmd = "cp %s %s" % (original_file,custom_file) + print(cmd) + os.system(cmd) + cmd = "patch %s %s" % (custom_file,patch_file) + print(cmd) + ret = os.system(cmd) + if 0 != ret: + print("* ERROR: Merge failed, restoring previous custom file") + cmd = "cp %s %s" % (custom_saved,custom_file) + print(cmd) + os.system(cmd) + return(ret) + +################################# +# merge_custom +# + +def merge_custom(custom_file,original_file,patch_file,label,patcher_dir): + ret,clean_file,patch_file = extract_custom_patch(custom_file,'',patch_file,label,patcher_dir) + if 0 == ret: + print("== Copying clean version of custom file to '%s' ===" % original_file) + cmd = "cp -f %s %s" % (clean_file, original_file) + print(cmd) + os.system(cmd) + return(ret) + +################################# +# diff_original +# + +def diff_original(custom_file,original_file,patch_file,label,patcher_dir): + ret,clean_file,patch_file = extract_custom_patch(custom_file,'',patch_file,label,patcher_dir) + if 0 == ret: + print("== DIFF from '%s' to clean version of custom file ===" % original_file) + os.system("diff -u %s %s" % (original_file,clean_file)) + return(ret) + +################################# +# load_json_list +# + +def load_json_list(json_file): + label = 'CUSTOM' + patcher_dir = '' + file_list = [] + + with open(json_file) as json_data: + dct = json.load(json_data) + + if 'label' in dct: + label = dct['label'] + if 'patcher_dir' in dct: + patcher_dir = dct['patcher_dir'] + if 'patch_set' in dct: + for patch in dct['patch_set']: + if 'DISABLE' in patch['options']: + continue + file_list.append([patch['custom'],patch['original'],patch['patch'],patch['options']]) + return file_list,patcher_dir,label + +################################# +# main loop +# + +def main(argv): + global verbose + + # setup + parser = argparse.ArgumentParser(description='srtool_sanity_test.py: SRTool common sanity tests') + + parser.add_argument('--merge-original', '-O', action='store_const', const='merge_original', dest='command', help='Copy the (updated) original file, merge the custom patches') + parser.add_argument('--merge-custom', '-C', action='store_const', const='merge_custom', dest='command', help='Copy the (updated) file to the original, without custom patches') + + parser.add_argument('--custom', '-c', help='Custom file') + parser.add_argument('--original', '-o', help='Original file') + parser.add_argument('--label', '-l', help='Custom label tag (default="CUSTOM")') + parser.add_argument('--json', '-j', help='Use JSON file for file list') + + parser.add_argument('--extract-custom-patch', '-e', action='store_const', const='extract_custom_patch', dest='command', help='Extract a patch of the custom content') + parser.add_argument('--apply-custom-patch', '-a', action='store_const', const='extract_custom_patch', dest='command', help='Apply the custom patch to the (reset) custom file') + parser.add_argument('--patch', '-p', help='Patch file') + parser.add_argument('--diff-original', '-d', action='store_const', const='diff_original', dest='command', help='Show how the file compares to original, ignoring custom patches') + + parser.add_argument('--verbose', '-v', action='store_true', dest='verbose', help='Debugging: verbose output') + args = parser.parse_args() + + def validate_file(filename,msg): + if not (filename or os.path.isfile(filename)): + print("ERROR: %s file not found '%s'" % (msg,filename)) + exit(1) + + # Extract provided values + verbose = args.verbose + file_list = [] + if args.json: + validate_file(args.json,"JSON") + file_list,patcher_dir,label = load_json_list(args.json) + else: + custom_file = '' + if args.custom: + custom_file = args.custom + original_file = '' + if args.original: + original_file = args.original + patch_file = '' + if args.patch: + patch_file = args.patch + options = '' + file_list.append([custom_file,original_file,patch_file,options]) + label = 'CUSTOM' + if args.label: + label = args.label + patcher_dir = os.path.join(os.path.dirname(custom_file),'patcher') + + ret = 0 + for custom_file,original_file,patch_file,options in file_list: + #print("PATCH_FILE:%s,%s,%s,%s,%s" % (custom_file,original_file,patch_file,options,patcher_dir)) + if 'merge_original' == args.command: + validate_file(custom_file,'Custom') + validate_file(original_file,'Original') + ret = merge_original(custom_file,original_file,patch_file,label,patcher_dir) + elif 'merge_custom' == args.command: + validate_file(custom_file,'Custom') + validate_file(original_file,'Original') + ret = merge_custom(custom_file,original_file,patch_file,label,patcher_dir) + elif 'extract_custom_patch' == args.command: + validate_file(custom_file,'Custom') + ret,clean_file,patch_file = extract_custom_patch(custom_file,'',patch_file,label,patcher_dir) + elif 'diff_original' == args.command: + validate_file(custom_file,'Custom') + validate_file(original_file,'Original') + ret = diff_original(custom_file,original_file,patch_file,label,patcher_dir) + else: + print("Command not found '%s'" % args.command) + ret = 1 + if 0 != ret: + exit(ret) + exit(ret) + +if __name__ == '__main__': + srtool_basepath = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))) + main(sys.argv[1:]) + + + |