aboutsummaryrefslogtreecommitdiffstats
path: root/bin/common/srtool_patcher.py
diff options
context:
space:
mode:
Diffstat (limited to 'bin/common/srtool_patcher.py')
-rwxr-xr-xbin/common/srtool_patcher.py252
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:])
+
+
+