#!/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 /
}