forked from nucked/android_misc_tools
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprocess_updater-script.py
More file actions
executable file
·142 lines (127 loc) · 6.55 KB
/
process_updater-script.py
File metadata and controls
executable file
·142 lines (127 loc) · 6.55 KB
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
#!/usr/bin/env python3
#encoding:utf-8
# WARNING: This is a python 3 script (the default on Arch Linux)
import datetime, os, argparse, sys, fileinput, hashlib, subprocess
parser = argparse.ArgumentParser(description='Process an updater-script running some commands on a local Linux box')
parser.add_argument('--logs', action='store',
help='The directory for log output')
parser.add_argument('--updater-script', action='store',
help='The updater-script to process')
parser.add_argument('--base', action='store',
help='The path to the base folder that will be updated -- It should contain system, modem and other partitions mounted as appropriate')
parser.add_argument('--ota', action='store',
help='The path to the extracted ota')
parser.add_argument('--applypatch-path', action='store',
help='The path to the compiled applypatch binary')
args = parser.parse_args()
# Timestamp for logging
today = datetime.datetime.today()
ts_string = today.isoformat('_')
# Setup / start logging
if not os.path.exists(args.logs):
os.mkdir(args.logs)
# Logs for this run
log_path = os.path.join(args.logs, ts_string) # Override log_path to be the path for this run's logsf
os.mkdir(log_path)
errorlog = open(os.path.join(log_path, 'error.log'), 'w+')
unknownlog = open(os.path.join(log_path, 'unknown_commands.log'), 'w+')
performedlog = open(os.path.join(log_path, 'performed_commands.log'), 'w+')
ignoredlog = open(os.path.join(log_path, 'ignored_commands.log'), 'w+')
if args.updater_script is None or not os.path.exists(args.updater_script):
args.updater_script = 'None'
print('You must specify a valid updater-script file; ' + args.updater_script + ' was invalid')
print('You must specify a valid updater-script file; ' + args.updater_script + ' was invalid', file=errorlog)
sys.exit(1)
if args.base is None or not os.path.exists(args.base):
args.base = 'None'
print('You must specify the path to the base folder; ' + args.base + ' was invalid')
print('You must specify the path to the base folder; ' + args.base + ' was invalid', file=errorlog)
sys.exit(1)
if args.ota is None or not os.path.exists(args.ota):
args.ota = 'None'
print('You must specify the path to the ota base folder; ' + args.ota + ' was invalid')
print('You must specify the path to the ota base folder; ' + args.ota + ' was invalid', file=errorlog)
sys.exit(1)
if args.applypatch_path is None or not os.path.exists(args.applypatch_path):
args.applypatch_path = 'None'
print('You must specify the path to the applypatch binary; ' + args.applypatch_path + ' was invalid')
print('You must specify the path to the applypatch binary; ' + args.applypatch_path + ' was invalid', file=errorlog)
sys.exit(1)
# Function for calculating sha1 hash of a given file path
def sha1OfFile(filepath):
with open(filepath, 'rb') as f:
return hashlib.sha1(f.read()).hexdigest()
command = ''
clear_command = True
with fileinput.input(files=(args.updater_script)) as f:
for line in f:
if clear_command:
clear_command = False
command = line.strip()
else:
# Combine multi-line commands into single line
command = command + line.strip()
# Process commands (all commands should end with ;)
if command.endswith(';'):
clear_command = True # Tracking to ensure the command is re-set on next pass of loop now that we found a full command string
if command.startswith('show_progress') or command.startswith('set_progress') or command.startswith('apply_patch_check') or command.startswith('ui_print'):
print(command, file=ignoredlog)
else:
if command.startswith('assert(apply_patch('):
try:
patch_command = command[19:-3]
patch_command = patch_command.replace('"', '')
arguments = patch_command.split(',')
original_file = arguments[0]
if original_file.startswith('/'):
original_file = original_file[1:]
original_file_path = os.path.join(args.base, original_file)
new_file_path = original_file_path
patched_file_sha1 = arguments[2]
new_file_size = arguments[3]
original_file_sha1 = arguments[4]
patch_file = os.path.join(args.ota, arguments[5].strip()[21:-1]) # This includes stripping off whitespace and "package_extract_file"
if original_file_sha1 != sha1OfFile(original_file_path):
print('sha1 mismatch: ' + original_file)
print('sha1 mismatch: ' + command, file=errorlog)
continue # Bail and move on with processing
patch_list = [args.applypatch_path, original_file_path, new_file_path, patched_file_sha1, new_file_size, ':'.join([original_file_sha1, patch_file])]
subprocess.Popen(patch_list)
new_file_sha1 = sha1OfFile(new_file_path)
if patched_file_sha1 != new_file_sha1:
#print('sha1 mismatch: ' + new_file_path)
print('sha1 mismatch: ' + new_file_path, file=errorlog)
print(command, file=performedlog)
except FileNotFoundError:
print('file not found: ' + original_file)
print('file not found: ' + original_file, file=errorlog)
elif command.startswith('delete_recursive'): # Must preceed delete or else conditions will be wrong
command = command[17:-2]
dirs = command.strip().split(',')
for adir in dirs:
to_delete = adir.strip().strip('"').strip()[1:]
try:
os.removedirs(os.path.join(args.base, to_delete))
except FileNotFoundError:
print('warning - directory may or may not have been deleted: ' + to_delete)
print('warning - directory may or may not have been deleted: ' + to_delete, file=errorlog)
print(command, file=performedlog)
elif command.startswith('delete'): # Most follow delete_recursive or else conditions will wrong
command = command[7:-2]
files = command.strip().split(',')
for afile in files:
to_delete = afile.strip().strip('"').strip()[1:]
try:
os.remove(os.path.join(args.base, to_delete))
except FileNotFoundError:
print('warning - file may or may not have been deleted: ' + to_delete)
print('warning - file may or may not have been deleted: ' + to_delete, file=errorlog)
except IsADirectoryError:
try:
os.removedirs(to_delete)
except FileNotFoundError:
print('warning - folder may or may not have been deleted: ' + to_delete)
print('warning - folder may or may not have been deleted: ' + to_delete, file=errorlog)
print(command, file=performedlog)
else:
print(command, file=unknownlog)