diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..9bbf492 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +2.7.14 diff --git a/README.md b/README.md index bfc00cd..5e6ad99 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,27 @@ -# TRIM patcher # +# TB3 enabler # -**This project is made obsolete by El Capitan, which enables TRIM for third party SSDs out of the box.** +**[Ryan Govostes](https://github.com/rgov) came up with a better solution. [Thunderbolt3Unblocker](https://github.com/rgov/Thunderbolt3Unblocker) uses a separate kext and override `IOThunderboltFamily` in runtime. That approach is better because you don't need to manually re-apply the binary patch everytime when there is a macOS update.** -Based on Grant Pannell [information](http://digitaldj.net/2011/07/21/trim-enabler-for-lion/) about how to patch -Lion properly to enable TRIM support on non-Apple branded -SSDs, here's a script that ought to make it harder to shoot -yourself in the foot. - -## Important note about Yosemite ## - -Yosemite now signs kexts and refuses to load unsigned ones. This means a patched version won't load, hence your Mac won't boot. If you still want to use TRIM patcher on Yosemite, you can use the following command to allow unsigned kexts to load: - - nvram boot-args=kext-dev-mode=1 - -This comes at a price though, as you're lowering one level of defense in your system security. +For unknown reasons, Apple decided to block the support for some categories of Thunderbolt 3 peripherals under macOS and when you connect those Thunderbolt 3 peripheral, you simply get an "Unsupported" message under Thunderbolt Device Tree. After digging around, it turns out the block is implemented in software level and it is possible to bypass the block by patching the related kext. This patch modifies IOThunderboltFamily and allows "Unsupported" Thunderbolt 3 peripherals to work under macOS Sierra. ## Warning ## -I took most steps I could to ensure kitten safety, but can make no warranty.In any case you're on your own. This is ultimately a sensitive hack and you take full responsibility by running this script. - -I have tested this successfully on a MacBook Pro 5,5 with Mac OS X 10.7.1 upgraded from 10.7 and a SATA-II Samsung 470 Series 128G in the HD slot. The patched file is the same as in 10.7. I later tested it on 10.7.2. +I cannot be sure whether blocking the Thunderbolt 3 peripherals is purely a business decision or actually trying to protect MacBook Pro defected Thunderbolt 3 peripherals. However, given those peripherals work fine under Windows via Boot Camp, it doesn't look like the block exists for protection. -## Usage ## - -Simply start up a terminal and run the script: - - python trim_patcher.py +I took most steps I could to ensure kitten safety, but can make no warranty. In any case you're on your own. This is ultimately a sensitive hack and you take full responsibility by running this script. -As the kext cache gets cleared upon success you might find it seems to -take some time to complete. +I have tested the patch on MacBook Pro 13,3 with macOS 10.12.1 (16B2659) and there are reports of this working with MacBook Pro 13,1. -Once the script ends, reboot. +## Usage ## -You can then check if it was taken into account via the System Profiler: go to Serial-ATA and look for "TRIM support: yes". +1. [Disable](https://developer.apple.com/library/content/documentation/Security/Conceptual/System_Integrity_Protection_Guide/ConfiguringSystemIntegrityProtection/ConfiguringSystemIntegrityProtection.html) System Integrity Protection +2. Run the script from Terminal -It is debated whether Sandforce-based SSDs (or other recent auto-GC SSDs) actually need this, both performance-wise and wear-wise. + ``` + tb3-enabler.py apply + ``` + +3. Reboot ## Available arguments ## @@ -52,6 +39,4 @@ In any case of changing success, the kext cache gets cleared. ## Thanks ## -- [Grant Pannell](http://digitaldj.net/2011/07/21/trim-enabler-for-lion/) -- [digital_dreamer](http://www.insanelymac.com/forum/index.php?s=523f85101e81849b73e6333ed420c6de&showtopic=256493&st=0&p=1680183&#entry1680183) - +- [netkas](http://forum.netkas.org/index.php/topic,11654.msg34142.html#msg34142) diff --git a/tb3-enabler.py b/tb3-enabler.py new file mode 100755 index 0000000..7b4cfe0 --- /dev/null +++ b/tb3-enabler.py @@ -0,0 +1,330 @@ +#!/usr/bin/env python + +# Modified based on Loic Nageleisen's trim_patcher +# https://github.com/lloeki/trim_patcher/ + +from __future__ import print_function +import os +import sys +import re +import hashlib +import shutil +from subprocess import Popen, PIPE +import shlex + +ORIGINAL = 'original' +PATCHED = 'patched' + +target = ("/System/Library/Extensions/IOThunderboltFamily.kext/" + "Contents/MacOS/IOThunderboltFamily") +backup = "%s.original" % target + +md5_version = { + "00e2f0eb5db157462a83e4de50583e33": ["10.12.1 (16B2659)"], + "ebde660af1f51dc7482551e8d07c62fd": ["10.12.2 (16C67)"], + "7fbc510cf91676739d638e1319d44e0e": ["10.12.3 (16D32)"], + "33ff6f5326eba100d4e7c490f9bbf91e": ["10.12.4 (16E195)"], + "58703942f8d4e5d499673c42cab0c923": ["10.12.5 (16F73)"], + "8ef3cf6dd8528976717e239aa8b20129": ["10.12.6 (16G29)"], + "9d6788e5afe3369cac79546a66f34842": ["10.12.6 (16G1036)"], + "096de0ab3c312a2e432e056d398a096b": ["10.12.6 (16G1114)"], + "cb95148ca3508790d6bdad38da79c649": ["10.12.6 (16G1212)"], + "b58ba765f901b3b6f2fac39c2040e523": ["10.13.0 (17A365)"], + "bcb319c05541da0ccffd7a52da7236c5": ["10.13.1 (17B48)"], + "427b87e16e15c55c687a565fbd555e03": ["10.13.2 (17C88)"], + "a47a724fdb13df4cef1b662b7ccbc9d1": ["10.13.3 (17D47)"], + "f2ed59d381f83c61ad0ec835364b2b79": ["10.13.4 (17E199)"], + "e64e2678bb38f6f60d3a9647c5d53eb6": ["10.13.4 (17E202)"], + "f46b4c2d8025c479d9a66e62cfa6d851": ["10.14 (18A391)"], + "8de0163c0ae5dab4b725dab2d9a1f0a1": ["10.14.2 (18C54)"], + "17ab6da0bd11078a35c88a1380bc378e": ["10.14.5 (18F132)"] +} +md5_patch = { + "00e2f0eb5db157462a83e4de50583e33": "a6c2143c2f085c2c104369d7a1adfe03", + "ebde660af1f51dc7482551e8d07c62fd": "2ebb68137da4a1cb0dfc6e6f05be3db2", + "7fbc510cf91676739d638e1319d44e0e": "0af475c26cdf5e26f8fd7e4341dadea5", + "33ff6f5326eba100d4e7c490f9bbf91e": "9237f013ab92f7eb5913bd142abf5fae", + "58703942f8d4e5d499673c42cab0c923": "86c40c5b6cadcfe56f7a7a1e1d554dc9", + "8ef3cf6dd8528976717e239aa8b20129": "bc84c36d884178d6e743cd11a8a22e93", + "9d6788e5afe3369cac79546a66f34842": "f1b280854306616dafb54b679c13e58e", + "096de0ab3c312a2e432e056d398a096b": "52f6d17ef3fb3a0a899c0ea6a255afc9", + "cb95148ca3508790d6bdad38da79c649": "f685774227156630f26a7448c886151b", + "b58ba765f901b3b6f2fac39c2040e523": "06a1a1fedc294b1bb78bc92625e412e1", + "bcb319c05541da0ccffd7a52da7236c5": "d0ae8daed7faccb8107f7b17772163b8", + "427b87e16e15c55c687a565fbd555e03": "d5c12e6f04d87d5b5a8ceef42cd36531", + "a47a724fdb13df4cef1b662b7ccbc9d1": "bcf9f00b8028bd305176816563ab2c00", + "f2ed59d381f83c61ad0ec835364b2b79": "9591b6f618d5d6ecc016488bc29e2b9f", + "e64e2678bb38f6f60d3a9647c5d53eb6": "555a6efce42709e06530251eb0f71315", + "f46b4c2d8025c479d9a66e62cfa6d851": "07a13e6e367608846ecbe3a1154bd05c", + "8de0163c0ae5dab4b725dab2d9a1f0a1": "b242fcabdf46bb83f083af2c97179bb2", + "17ab6da0bd11078a35c88a1380bc378e": "c49dccab2d8b23b3f170efc3e5519941" +} +md5_patch_r = dict((v, k) for k, v in md5_patch.items()) + +re_index = [ + { + 'search': "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x53\x48\x81\xEC\x38\x01", + 'replace': "\x55\x48\x89\xE5\x31\xC0\x5D\xC3\x41\x55\x41\x54\x53\x48\x81\xEC\x38\x01" + }, + { + 'search': "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x53\x48\x81\xEC\x28\x01", + 'replace': "\x55\x48\x89\xE5\x31\xC0\x5D\xC3\x41\x55\x41\x54\x53\x48\x81\xEC\x28\x01" + } +] +re_md5 = { + 0: [ + "00e2f0eb5db157462a83e4de50583e33", + "ebde660af1f51dc7482551e8d07c62fd", + "7fbc510cf91676739d638e1319d44e0e", + "33ff6f5326eba100d4e7c490f9bbf91e", + "58703942f8d4e5d499673c42cab0c923", + "8ef3cf6dd8528976717e239aa8b20129", + "9d6788e5afe3369cac79546a66f34842", + "096de0ab3c312a2e432e056d398a096b", + "cb95148ca3508790d6bdad38da79c649" + ], + 1: [ + "b58ba765f901b3b6f2fac39c2040e523", + "bcb319c05541da0ccffd7a52da7236c5", + "427b87e16e15c55c687a565fbd555e03", + "a47a724fdb13df4cef1b662b7ccbc9d1", + "f46b4c2d8025c479d9a66e62cfa6d851", + "b242fcabdf46bb83f083af2c97179bb2" + "8de0163c0ae5dab4b725dab2d9a1f0a1" + ] +} +md5_re = dict((v, re_index[k]) for k, l in re_md5.items() for v in l) + + +def md5(filename): + h = hashlib.md5() + with open(filename, 'rb') as f: + for chunk in iter(lambda: f.read(8192), b''): + h.update(chunk) + return h.hexdigest() + + +def backquote(command): + return Popen(shlex.split(command), stdout=PIPE).communicate()[0] + +def check_SIP(): + sip_info = backquote("nvram csr-active-config") + if sip_info.find("%00%00%00") == -1: + print("you must disable System Integrity Protection",file=sys.stderr) + sys.exit(1) + +def check_rootness(): + if os.geteuid() != 0: + print("you must be root",file=sys.stderr) + sys.exit(1) + + +def clear_kext_cache(): + print( "clearing kext cache...",end="") + backquote("kextcache -system-prelinked-kernel") + backquote("kextcache -system-caches") + print("done") + + +class UnknownFile(Exception): + def __init__(self, md5=None): + self.md5 = md5 + + +class NoBackup(Exception): + pass + + +def target_status(): + h = md5(target) + try: + return (ORIGINAL, md5_version[h]) + except KeyError: + pass + try: + return (PATCHED, md5_version[md5_patch_r[h]]) + except KeyError: + pass + raise UnknownFile(h) + + +def backup_status(): + if not os.path.exists(backup): + raise NoBackup + h = md5(backup) + try: + return (ORIGINAL, md5_version[h]) + except KeyError: + pass + try: + return (PATCHED, md5_version[md5_patch_r[h]]) + except KeyError: + pass + raise UnknownFile(h) + + +def apply_patch(): + h = md5(target) + search_re = md5_re[h]['search'] + replace_re = md5_re[h]['replace'] + with open(target, 'rb') as f: + source_data = f.read() + patched_data = source_data.replace(search_re, replace_re) + with open(target, 'wb') as out: + out.write(patched_data) + + +def perform_backup(): + shutil.copyfile(target, backup) + +def do_backup(): + check_rootness() + check_SIP() + try: + s, t = target_status() + if s == PATCHED: + print("already patched, won't backup") + sys.exit(1) + else: + try: + _, v = backup_status() + except NoBackup: + print( "backing up...",end="") + perform_backup() + print( "done") + else: + if v == t: + print("backup found") + else: + print("backing up...",end="") + perform_backup() + print("done") + except UnknownFile as e: + print( "unknown file, won't backup (md5=%s)" % e.md5) + sys.exit(1) + + +def do_restore(): + check_rootness() + check_SIP() + print("restoring...",end="") + backup_status() + shutil.copyfile(backup, target) + print("done") + clear_kext_cache() + + +def do_apply(): + check_rootness() + check_SIP() + do_backup() + try: + s, v = target_status() + if s == PATCHED: + print("already patched") + sys.exit() + except UnknownFile as e: + print("unknown file: won't patch (md5=%s)" % e.md5) + sys.exit(1) + + print("patching...",end="") + apply_patch() + + try: + s, v = target_status() + if s != PATCHED: + print("no change made") + else: + print("done") + clear_kext_cache() + except UnknownFile as e: + print("failed (md5=%s), " % e.md5,end="") + do_restore() + +def do_force_apply(): + check_rootness() + check_SIP() + if os.path.exists(backup): + print("backup already exists. won't patch. Please remove the backup from %s and try again." % backup, end="") + sys.exit(1) + h = md5(target) + print("original md5=%s " % h, end="") + perform_backup() + with open(target, 'rb') as f: + source_data = f.read() + + search_re1012 = "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x53\x48\x81\xEC\x38\x01" + replace_re1012 = "\x55\x48\x89\xE5\x31\xC0\x5D\xC3\x41\x55\x41\x54\x53\x48\x81\xEC\x38\x01" + + search_re1013 = "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x53\x48\x81\xEC\x28\x01" + replace_re1013 = "\x55\x48\x89\xE5\x31\xC0\x5D\xC3\x41\x55\x41\x54\x53\x48\x81\xEC\x28\x01" + + for replace in [replace_re1012, replace_re1013]: + if (source_data.find(replace) != -1): + print ("Looks like file is already patched, aborting") + sys.exit(1) + + if (source_data.find(search_re1012) != -1): + patched_data = source_data.replace(search_re1012, replace_re1012) + else: + print ("Could not location to patch for 10.12, trying for 10.13") + if (source_data.find(search_re1013) != -1): + patched_data = source_data.replace(search_re1013, replace_re1013) + else: + print ("10.13 also not found, exiting") + sys.exit(1) + + with open(target, 'wb') as out: + out.write(patched_data) + h = md5(target) + print("done, patched md5=%s" % h, end="") + clear_kext_cache() + +def do_status(): + try: + print("target:",end="") + s, v = target_status() + print( s+',', ' or '.join(v)) + except UnknownFile as e: + print( "unknown (md5=%s)" % e.md5) + + try: + print("backup:",end="") + s, v = backup_status() + print( s+',', ' or '.join(v)) + except NoBackup: + print( "none") + except UnknownFile as e: + print( "unknown (md5=%s)" % e.md5) + + +def do_diff(): + try: + backup_status() + except NoBackup: + print("no backup") + else: + command = ("bash -c " + "'diff <(xxd \"%s\") <(xxd \"%s\")'" % (backup, target)) + print(os.system(command)) + + +commands = { + 'status': do_status, + 'backup': do_backup, + 'apply': do_apply, + 'restore': do_restore, + 'diff': do_diff, + 'forceApply': do_force_apply, +} + +try: + function = commands[sys.argv[1]] + function() +except IndexError: + print("no command provided",file=sys.stderr) + print("list of commands: %s" % ', '.join(commands.keys()),file=sys.stderr) + sys.exit(1) +except KeyError: + print ("unknown command",file=sys.stderr) + sys.exit(1) diff --git a/trim_patch.py b/trim_patch.py deleted file mode 100755 index 7d157d4..0000000 --- a/trim_patch.py +++ /dev/null @@ -1,296 +0,0 @@ -#!/usr/bin/env python - -import os -import sys -import re -import hashlib -import shutil -from subprocess import Popen, PIPE -import shlex - -ORIGINAL = 'original' -PATCHED = 'patched' - -target = ("/System/Library/Extensions/IOAHCIFamily.kext/" - "Contents/PlugIns/IOAHCIBlockStorage.kext/" - "Contents/MacOS/IOAHCIBlockStorage") -backup = "%s.original" % target - -md5_version = { - "25a29cbdbb89329a6ce846c9b05af5f0": ["10.6.8"], - "155b426c856c854e54936339fbc88d72": ["10.7"], - "00bd8e1943e09f2bd12468882aad0bbb": ["10.7.1"], - "38100e96270dcb63d355ea8195364bf5": ["10.7.2"], - "d2c20ed8211bf5b96c4610450f56c1c3": ["10.7.3"], - "48e392b3ca7267e1fd3dd50a20396937": ["10.7.4"], - "583d7bbcbe5c5d06d7877d6ccb6c5699": ["10.7.5"], - "ff7a9115779fa5923950cbdc6ffb273d": ["10.8"], - "03d3a46c6d713b00980bc9be453755ff": ["10.8.1"], - "85390d06d5aad08b471cf9b7cd69aff4": ["10.8.2 (12C60)"], - "c3df44c5ccb86b423e17406f6f9a2bd1": ["10.8.2 (12C3006/12C3012)"], - "8bbf5f3928d55dc9ec8017b37a6748f8": ["10.8.3 (12D78)"], - "8c5a53a607ffb335c039bad220fa0230": ["10.8.5"], - "8a6e253e621db78e1fa0d14274ade63c": ["10.9"], - "a11100b558cade33c35924f08924a728": ["10.9.2"], - "3e794ede0ec1becce65c580a6efceaca": ["10.9.3"], - "2a8c2b865eba74fe0c5ca8bfa9f7d603": ["10.9.4"], - "538221c151b847490fbac997e1776d82": ["10.9.5"], -} -md5_patch = { - "25a29cbdbb89329a6ce846c9b05af5f0": "d76b57daf4d4c2ff5b52bc7b4b2dcfc1", - "155b426c856c854e54936339fbc88d72": "945944136009c9228fffb513ab5bf734", - "00bd8e1943e09f2bd12468882aad0bbb": "155b426c856c854e54936339fbc88d72", - "38100e96270dcb63d355ea8195364bf5": "5762b2fbb259101c361e5414c349ffa1", - "d2c20ed8211bf5b96c4610450f56c1c3": "15901d7c6fd99f5dd9c5ca493de6109b", - "48e392b3ca7267e1fd3dd50a20396937": "a2f64369e775c76be4ec03ce5172a294", - "583d7bbcbe5c5d06d7877d6ccb6c5699": "a81d7e61a744b0d27f17cad5d441fccb", - "ff7a9115779fa5923950cbdc6ffb273d": "4d265ac3f471b0ef0578d5dbb1eafadb", - "03d3a46c6d713b00980bc9be453755ff": "1c3cfe37c7716a9b4e2a5d7a6c72b997", - "85390d06d5aad08b471cf9b7cd69aff4": "181941753186a9c292ae9279040fb023", - "c3df44c5ccb86b423e17406f6f9a2bd1": "59a2b95b7c7695d9ea29adc8e3a5945d", - "8bbf5f3928d55dc9ec8017b37a6748f8": "ff48b74b876f58969768b5436523bca9", - "8c5a53a607ffb335c039bad220fa0230": "fa1ad2aed34ce95585c13765d831ee65", - "8a6e253e621db78e1fa0d14274ade63c": "17dc2e1edc35447ea693a29aef969f21", - "a11100b558cade33c35924f08924a728": "3409ad454e58f6415c38ab2b9e39d64d", - "3e794ede0ec1becce65c580a6efceaca": "3ae907c12b58e2e682e215627c87be67", - "2a8c2b865eba74fe0c5ca8bfa9f7d603": "9a254024a1c43a102a5c558a6510413e", - "538221c151b847490fbac997e1776d82": "6c012761dcbf71437ee1274380347e92", -} -md5_patch_r = dict((v, k) for k, v in md5_patch.items()) - -re_index = [ - { - 'search': ("(\x52\x6F\x74\x61\x74\x69\x6F\x6E\x61\x6C" - "\x00{1,20})[^\x00]{9}(\x00{1,20}[^\x00])"), - 'replace': "\\1\x00\x00\x00\x00\x00\x00\x00\x00\x00\\2" - }, - { - 'search': ("(\x4F\x6E\x57\x61\x6B\x65\x4B\x65\x79\x0A" - "\x00{1,20})[^\x00]{9}(\x00{1,20}[^\x00])"), - 'replace': "\\1\x00\x00\x00\x00\x00\x00\x00\x00\x00\\2" - }, -] -re_md5 = { - 0: [ - "25a29cbdbb89329a6ce846c9b05af5f0", - "155b426c856c854e54936339fbc88d72", - "00bd8e1943e09f2bd12468882aad0bbb", - "38100e96270dcb63d355ea8195364bf5", - "d2c20ed8211bf5b96c4610450f56c1c3", - "48e392b3ca7267e1fd3dd50a20396937", - "583d7bbcbe5c5d06d7877d6ccb6c5699", - "ff7a9115779fa5923950cbdc6ffb273d", - "03d3a46c6d713b00980bc9be453755ff", - "85390d06d5aad08b471cf9b7cd69aff4", - "c3df44c5ccb86b423e17406f6f9a2bd1", - "8bbf5f3928d55dc9ec8017b37a6748f8", - "8c5a53a607ffb335c039bad220fa0230", - "8a6e253e621db78e1fa0d14274ade63c", - "a11100b558cade33c35924f08924a728", - "3e794ede0ec1becce65c580a6efceaca", - ], - 1: [ - "2a8c2b865eba74fe0c5ca8bfa9f7d603", - "538221c151b847490fbac997e1776d82", - ], -} -md5_re = dict((v, re_index[k]) for k, l in re_md5.items() for v in l) - - -def md5(filename): - h = hashlib.md5() - with open(filename, 'rb') as f: - for chunk in iter(lambda: f.read(8192), ''): - h.update(chunk) - return h.hexdigest() - - -def backquote(command): - return Popen(shlex.split(command), stdout=PIPE).communicate()[0] - - -def check_rootness(): - if os.geteuid() != 0: - print >> sys.stderr, "you must be root" - sys.exit(1) - - -def clear_kext_cache(): - print "clearing kext cache...", - backquote("kextcache -system-prelinked-kernel") - backquote("kextcache -system-caches") - print "done" - - -class UnknownFile(Exception): - def __init__(self, md5=None): - self.md5 = md5 - - -class NoBackup(Exception): - pass - - -def target_status(): - h = md5(target) - try: - return (ORIGINAL, md5_version[h]) - except KeyError: - pass - try: - return (PATCHED, md5_version[md5_patch_r[h]]) - except KeyError: - pass - raise UnknownFile(h) - - -def backup_status(): - if not os.path.exists(backup): - raise NoBackup - h = md5(backup) - try: - return (ORIGINAL, md5_version[h]) - except KeyError: - pass - try: - return (PATCHED, md5_version[md5_patch_r[h]]) - except KeyError: - pass - raise UnknownFile(h) - - -def apply_patch(): - h = md5(target) - search_re = md5_re[h]['search'] - replace_re = md5_re[h]['replace'] - with open(target, 'rb') as f: - source_data = f.read() - patched_data = re.sub(search_re, replace_re, source_data) - with open(target, 'wb') as out: - out.write(patched_data) - - -def perform_backup(): - shutil.copyfile(target, backup) - - -def is_trim_enabled(): - trim_info = backquote("system_profiler SPSerialATADataType" - " -detailLevel mini") - return trim_info.find("TRIM Support: Yes") != -1 - - -def do_backup(): - check_rootness() - try: - s, t = target_status() - if s == PATCHED: - print "already patched, won't backup" - sys.exit(1) - else: - try: - _, v = backup_status() - except NoBackup: - print "backing up...", - perform_backup() - print "done" - else: - if v == t: - print "backup found" - else: - print "backing up...", - perform_backup() - print "done" - except UnknownFile as e: - print "unknown file, won't backup (md5=%s)" % e.md5 - sys.exit(1) - - -def do_restore(): - check_rootness() - print "restoring...", - backup_status() - shutil.copyfile(backup, target) - print "done" - clear_kext_cache() - - -def do_apply(): - check_rootness() - do_backup() - try: - s, v = target_status() - if s == PATCHED: - print "already patched" - sys.exit() - except UnknownFile as e: - print "unknown file: won't patch (md5=%s)" % e.md5 - sys.exit(1) - - print "patching...", - apply_patch() - - try: - s, v = target_status() - if s != PATCHED: - print "no change made" - else: - print "done" - clear_kext_cache() - except UnknownFile as e: - print "failed (md5=%s), " % e.md5, - do_restore() - - -def do_status(): - try: - print "target:", - s, v = target_status() - print s+',', ' or '.join(v) - except UnknownFile as e: - print "unknown (md5=%s)" % e.md5 - - try: - print "backup:", - s, v = backup_status() - print s+',', ' or '.join(v) - except NoBackup: - print "none" - except UnknownFile as e: - print "unknown (md5=%s)" % e.md5 - - if is_trim_enabled(): - print "TRIM: enabled" - else: - print "TRIM: disabled" - - -def do_diff(): - try: - backup_status() - except NoBackup: - print "no backup" - else: - command = ("bash -c " - "'diff <(xxd \"%s\") <(xxd \"%s\")'" % (backup, target)) - print os.system(command) - - -commands = { - 'status': do_status, - 'backup': do_backup, - 'apply': do_apply, - 'restore': do_restore, - 'diff': do_diff, -} - -try: - function = commands[sys.argv[1]] - function() -except IndexError: - print >> sys.stderr, "no command provided" - print >> sys.stderr, "list of commands: %s" % ', '.join(commands.keys()) - sys.exit(1) -except KeyError: - print >> sys.stderr, "unknown command" - sys.exit(1)