Reloading services and kexts using AppleScript

This weekend, I had to try to convince a slightly reluctant (no-name) bluetooth mouse to work on an Apple laptop. Especially after a sleep-wakeup cycle it tends to stop reacting and my theory is that it confuses OS X's bluetooth driver to the point where it stops functioning.

As a small test, I decided to try to unload both the bluetooth daemon blued and the IOBluetoothHIDDriver when the problem occurs and see if that fixes it. For this purpose, I came up with the following one-click experiment, my very first AppleScript.

set bluedController to serviceController for "com.apple.blued" given defaults:"/Library/Preferences/com.apple.Bluetooth", preference:"ControllerPowerState"

set driverController to kextController for "com.apple.driver.IOBluetoothHIDDriver"


restart({bluedController, driverController})


-- Shutdown a list of services, waiting for each to stop, and restart them in reverse order

on restart(controllers)

repeat with controller in controllers

repeat

tell controller

shutdown()

if not isRunning() then exit repeat

end tell

display dialog "Waiting for " & controller's name & " to stop" giving up after 1

end repeat

end repeat

repeat with controller in reverse of controllers

repeat

tell controller

start()

if isRunning() then exit repeat

end tell

display dialog "Waiting for " & controller's name & " to start" giving up after 1

end repeat

end repeat

end restart


-- Return a script object that controls a launch service using its associated preference.

on serviceController for serviceLabel given defaults:prefsFile, preference:prefName

script controller

property name : "service " & last item of (wordList of serviceLabel at ".")

on launchCtl(command)

-- launchctl only knows about blued if run as admin

do shell script "launchctl " & ¬

quoted form of command & " " & ¬

quoted form of serviceLabel ¬

with administrator privileges

end launchCtl

on setPref(value)

-- turn off the service's preference

do shell script "defaults write " & ¬

quoted form of prefsFile & " " & ¬

quoted form of prefName & " " & ¬

quoted form of (value as text) ¬

with administrator privileges

end setPref

on isRunning()

return launchCtl("list") contains "\"PID\" = "

end isRunning

on shutdown()

setPref(0)

launchCtl("stop")

end shutdown

on start()

setPref(1)

launchCtl("start")

end start

end script

return controller

end serviceController


-- Return a script object that loads and unloads a kernel extension.

on kextController for bundleIdentifier

script controller

property name : "kernel extension " & last item of (wordList of bundleIdentifier at ".")

on isRunning()

do shell script "kextstat -l -b " & ¬

quoted form of bundleIdentifier

return the result contains bundleIdentifier

end isRunning

on shutdown()

try

do shell script "kextunload -b " & ¬

quoted form of bundleIdentifier ¬

with administrator privileges

end try

end shutdown

on start()

do shell script "kextload -b " & ¬

quoted form of bundleIdentifier ¬

with administrator privileges

end start

end script

return controller

end kextController


on wordList of theWords at delimiters

set oldDelimiters to text item delimiters

set text item delimiters to delimiters

try

set res to text items of theWords

set text item delimiters to oldDelimiters

return res

on error m number n

set text item delimiters to oldDelimiters

error m number n

end try

end wordList

Comments