#!/bin/bash # joevt May 8, 2023 #10.4 Tiger to 10.13 High Sierra kextload=kextload # Later macOS versions command -v kextutil > /dev/null && kextload=kextutil getkextidentifier () { local thekextpath="$1" if [[ ! -f "$thekextpath/Contents/Info.plist" ]]; then echo "# Missing Info.plist." 1>&2 return 1 fi # Mac OS X 10.4 doesn't have PlistBuddy so just use perl perl -0777 -n -e 'if (m|CFBundleIdentifier\s*(.+)|) { print $1 }' "$thekextpath/Contents/Info.plist" } checkkext () { local thekextpath="$1" if [[ -d "$thekextpath" ]]; then if [[ -f "$thekextpath/Contents/Info.plist" ]]; then local kextname kextname="$(basename "$thekextpath")" if grep -q -E "\.kext$" <<< "$kextname"; then local kextidentifier="" kextidentifier="$(getkextidentifier "$thekextpath")" local theerr=$? if (( theerr == 0 )); then return 0 else echo "# Missing CFBundleIdentifier." 1>&2 return 1 fi else echo "# That's not a kext." 1>&2 return 1 fi else echo "# Missing Info.plist." 1>&2 return 1 fi else echo "# Expected a kext package directory." 1>&2 return 1 fi } unloadkext () { local thekextpath="$1" checkkext "$thekextpath" || return 1 local kextname kextname="$(basename "$thekextpath")" local kextidentifier kextidentifier="$(getkextidentifier "$thekextpath")" echo "# kextname: $kextname" echo "# kextidentifier: $kextidentifier" if ( kextstat 2> /dev/null | grep -q "$kextidentifier" ); then while : ; do echo "# Unloading ${kextname}." sudo kextunload -b "$kextidentifier" ( kextstat 2> /dev/null | grep -q "$kextidentifier" ) || break sleep 1 done echo "# Unloaded ${kextname}." else echo "# ${kextname} is not loaded." fi } checkkextpermissions () { local thekextpath="$1" checkkext "$thekextpath" || return 1 badpermissions="$(find "$thekextpath" -exec ls -ld {} \; | sed -E '/drwxr-xr-x.* root *wheel /d ; /-rw.r-.r-..* root *wheel /d')" if (( $(printf "%s" "$badpermissions" | wc -l) == 0 )); then return 0 fi echo "# Permissions are not correct for the following:" 1>&2 echo "$badpermissions" 1>&2 return 1 } fixkextpermissions () { local thekextpath="$1" checkkext "$thekextpath" || return 1 if checkkextpermissions "$thekextpath" 2> /dev/null ; then echo "# Permissions are good. No changes were required." return 0 fi sudo chown -R root:wheel "$thekextpath" sudo find "$thekextpath" -type d -exec /bin/chmod 0755 {} \; sudo find "$thekextpath" -type f -exec /bin/chmod 0644 {} \; if checkkextpermissions "$thekextpath" 2> /dev/null ; then echo "# Fixed permissions." return 0 fi echo "# Could not fix permissions." 1>&2 return 1 } loadkext () { local thekextpath="$1" checkkext "$thekextpath" || return 1 local kextname kextname="$(basename "$thekextpath")" local kextloadpath if fixkextpermissions "$thekextpath" > /dev/null 2>&1 ; then kextloadpath="$thekextpath" else echo "# Cannot fix permissions. Will load kext from temporary directory." 1>&2 local kexttmpdir kexttmpdir="$(mktemp -d /tmp/KextUtil_XXXXXXX)" kextloadpath="$kexttmpdir/$kextname" sudo cp -R "$thekextpath" "kextloadpath" if ! fixkextpermissions "kextloadpath" ; then return 1 fi fi unloadkext "$kextloadpath" if ( sudo "$kextload" "$kextloadpath" ); then echo "# Loaded ${kextname}." return 0 else echo "# $kextname was not loaded." 1>&2 return 1 fi } mountsystemrw () { mount | grep ' on / ' | grep -q 'read-only' && sudo mount -uw / } installkext () { local doload=0 local dosystem=0 while (( $# )); do if [[ "$1" == "-l" ]]; then doload=1 elif [[ "$1" == "-s" ]]; then dosystem=1 else break fi shift 1 done local thekextpath="$1" checkkext "$thekextpath" || return 1 local kextname kextname="$(basename "$thekextpath")" local kextinstalldir="/Library/Extensions" if ((dosystem)); then kextinstalldir="/System/Library/Extensions" fi local kextidentifier kextidentifier="$(getkextidentifier "$thekextpath")" if ((doload)); then # unloadkext will do these echo lines for us: # echo "# kextname: $kextname" # echo "# kextidentifier: $kextidentifier" unloadkext "$thekextpath" else echo "# kextname: $kextname" echo "# kextidentifier: $kextidentifier" fi local kexttmpdir kexttmpdir="$(mktemp -d /tmp/KextUtil_XXXXXXX)" kextloadpath="$kexttmpdir/$kextname" sudo cp -R "$thekextpath" "kextloadpath" if ! fixkextpermissions "kextloadpath" ; then return 1 fi if [[ -d "/System/Library/Extensions/$kextname" ]]; then mountsystemrw sudo rm -R "/System/Library/Extensions/$kextname" fi if [[ -d "/Library/Extensions/$kextname" ]]; then sudo rm -R "/Library/Extensions/$kextname" fi if ((dosystem)); then mountsystemrw fi sudo mv "kextloadpath" "$kextinstalldir" if ((doload)); then sudo "$kextload" "$kextinstalldir/$kextname" kextstat 2> /dev/null | grep "$kextidentifier" fi } removekext () { local thekextpath="$1" checkkext "$thekextpath" || return 1 if [[ -d "$thekextpath" ]]; then if [[ "$thekextpath" == /System/Library/* ]] ; then mountsystemrw fi sudo rm -R "$thekextpath" fi } rebuildkextcache () { sudo kextcache -i / }