Articles,Deployment,OS X March 14, 2013 at 9:26 am

Fixing Broken Software I: Logitech Control Center

This is part one of a series on dealing with the issues software can cause in enterprise environments, and how to combat these issues.

One of the most important skills in a Mac Admin’s toolbox is being able to identify and work around issues with vendor software.  Many vendors release software packages that are ill-suited for use with management tools such as Munki and Casper, and it is important to know how to dig into these issues to be able to support a managed environment.

If you are buying non-Apple mice and keyboards, it is very likely that they are Logitech models.  If an admin wants the full functionality of these devices,  OS X needs the drivers and control panel that Logitech distributes as the Logitech Control Center.  This installs a .prefPane as well as drivers for most modern Logitech input devices.

However, Logitech’s installer is not friendly for deployment though Munki or Casper, as it opens prompts during the installer, and then installs a registration prompt that launches when users login. Thankfully, we can easily modify the preflight and postflight scripts of the installer to recitfy all of these issues.

The download for the Logitech Control Center is a .app, but there is a package installer at Logitech Control Center.app/Contents/Resources/Logitech Control Center.mpkg.  This is a flat package, so we must expand it for modification using the following command:

pkgutil –expand LCC\ Installer.app/Contents/Resources/Logitech\ Control\ Center.mpkg Logitech\ Control\ Center.expanded.mpkg

view raw
gistfile1.sh
hosted with ❤ by GitHub

Navigate to Logitech Control Center.expanded.mpkg/logitechControlCenter.pkg/Scripts, and you will find preflight and posflight scripts, both of which need to be edited.

Preflight:

#!/bin/sh
# $1 has the path to the source package
# $2 has the path to the target folder
# $3 has the path to the target volume
# $USER has the name of the user who launched the installer
echo ". . . . . running the postflight script . . . . ."
echo " source path is: $1"
echo " target path is: $2"
echo " target volume path is: $3"
export LCC36P=`dirname "$1"`
echo " path to tools is: $LCC36P"
if [ -f "/tmp/LGT_region.plist" ]; then
echo " User has already chosen keyboard, exiting"
exit 0
else
echo " User has not chosen keyboard yet"
fi
if [ -f "$LCC36P/KeyboardChooser.app/Contents/MacOS/KeyboardChooser" ]; then
/usr/bin/sudo -u $USER "$LCC36P/KeyboardChooser.app/Contents/MacOS/KeyboardChooser"
fi
if [ -e "$LCC36P/LCC Uninstaller Tool" ] ; then
"$LCC36P/LCC Uninstaller Tool" –preinstall
fi
# "$1/Contents/Resources/RMover" "$1" –preflight
echo "try to run RMover from Scripts"
# "$1/logitechControlCenter.pkg/Scripts/RMover" "$1" –preflight
"$LCC36P/RMover" "$LCC36P" –preflight
# enforce permissions
if [ -e "/System/Library/Extensions/LogitechHIDDevices.kext" ] ; then
/usr/sbin/chown -R root:wheel "/System/Library/Extensions/LogitechHIDDevices.kext"
/bin/chmod -R ug+r,go-w "/System/Library/Extensions/LogitechHIDDevices.kext"
elif [ -e "/System/Library/Extensions/LogicoolHIDDevices.kext" ] ; then
/usr/sbin/chown -R root:wheel "/System/Library/Extensions/LogicoolHIDDevices.kext"
/bin/chmod -R ug+r,go-w "/System/Library/Extensions/LogicoolHIDDevices.kext"
fi
echo "pausing for 3 seconds"
sleep 3
if [ -f "/tmp/LGT_region.plist" ]; then
echo "Check2: found keyboard flag file"
else
echo "Check2: keyboard flag file not found"
fi
exit 0

view raw
preflight.sh
hosted with ❤ by GitHub

In the preflight script, line 25 runs KeyboardChooser.app, prompting the selection of a region:

This will not work at the loginwindow, and users should not have to make this selection.  Using fseventer, we can see that all this application does is write to /tmp/LGT_region.plist, with a 0 for EU, 1 for US, and 2 for JP.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>script</key>
<integer>1</integer>
</dict>
</plist>

view raw
LGT_region.plist
hosted with ❤ by GitHub

To take place of KeyboardChooser.app, replace lines 24 through 26 with the following script, which will write the file that the installer needs to continue.  The installer wants an XML formatted plist, so the second line will convert the binary to XML.

## use 0 for EU, 1 for US, 2 for JP
defaults write /tmp/LGT_region.plist script -int 1
## make sure plist is XML
plutil -convert xml1 /tmp/LGT_region.plist

view raw
gistfile1.sh
hosted with ❤ by GitHub

Once these modifications have been made, save the file and move on to the postflight.

Postflight

#!/bin/sh
# $1 has the path to the source package
# $2 has the path to the target folder
# $3 has the path to the target volume
# $USER has the name of the user who launched the installer
# enforcing some critical permissions, just to be sure everything is OK
echo ". . . . . running the postflight script . . . . ."
echo " source path is: $1"
echo " target path is: $2"
echo " target volume path is: $3"
export LCC36P=`dirname "$1"`
echo " path to tools is: $LCC36P"
if [ -e "/System/Library/Extensions/LogitechHIDDevices.kext" ] ; then
/usr/sbin/chown -R root:wheel "/System/Library/Extensions/LogitechHIDDevices.kext"
/bin/chmod -R ug+r,go-w "/System/Library/Extensions/LogitechHIDDevices.kext"
elif [ -e "/System/Library/Extensions/LogicoolHIDDevices.kext" ] ; then
/usr/sbin/chown -R root:wheel "/System/Library/Extensions/LogicoolHIDDevices.kext"
/bin/chmod -R ug+r,go-w "/System/Library/Extensions/LogicoolHIDDevices.kext"
fi
if [ -e "/System/Library/Extensions/LogitechUnifying.kext" ] ; then
/usr/sbin/chown -R root:wheel "/System/Library/Extensions/LogitechUnifying.kext"
/bin/chmod -R ug+r,go-w "/System/Library/Extensions/LogitechUnifying.kext"
elif [ -e "/System/Library/Extensions/LogicoolUnifying.kext" ] ; then
/usr/sbin/chown -R root:wheel "/System/Library/Extensions/LogicoolUnifying.kext"
/bin/chmod -R ug+r,go-w "/System/Library/Extensions/LogicoolUnifying.kext"
fi
if [ -e "/Library/LaunchAgents/com.Logitech.Control Center.Daemon.plist" ] ; then
/usr/sbin/chown -R root:wheel "/Library/LaunchAgents/com.Logitech.Control Center.Daemon.plist"
/bin/chmod -R 644 "/Library/LaunchAgents/com.Logitech.Control Center.Daemon.plist"
fi
if [ -e "/Applications/Utilities/LCC Connection Utility.app" ]; then
/usr/sbin/chown -R root:admin "/Applications/Utilities/LCC Connection Utility.app"
/bin/chmod -R ug+rw,o-w "/Applications/Utilities/LCC Connection Utility.app"
fi
if [ -e "/Applications/Utilities/LCC Uninstaller.app" ]; then
/usr/sbin/chown -R root:admin "/Applications/Utilities/LCC Uninstaller.app"
/bin/chmod -R ug+rw,o-w "/Applications/Utilities/LCC Uninstaller.app"
fi
if [ -e "/Library/Application Support/Logitech.localized" ]; then
/usr/sbin/chown -R root:admin "/Library/Application Support/Logitech.localized"
/bin/chmod -R ug+rw,o-w "/Library/Application Support/Logitech.localized"
fi
if [ -e "/Library/Application Support/Logitech.localized/Logitech Control Center.localized/LCCDaemon.app" ]; then
/usr/sbin/chown root:admin "/Library/Application Support/Logitech.localized/Logitech Control Center.localized/LCCDaemon.app/Contents/Resources/SetPriority"
/bin/chmod u+s "/Library/Application Support/Logitech.localized/Logitech Control Center.localized/LCCDaemon.app/Contents/Resources/SetPriority"
fi
if [ -e "/Library/PreferencePanes/Logitech Control Center.prefPane" ]; then
/usr/sbin/chown -R root:admin "/Library/PreferencePanes/Logitech Control Center.prefPane"
/bin/chmod -R ug+rw,o-w "/Library/PreferencePanes/Logitech Control Center.prefPane"
/bin/chmod ugo+w "/Library/PreferencePanes/Logitech Control Center.prefPane"/Contents/Resources/*.lproj/html/
/bin/chmod ugo+w "/Library/PreferencePanes/Logitech Control Center.prefPane"/Contents/Resources/*.lproj/html/warranty_keyboards.htm
/bin/chmod ugo+w "/Library/PreferencePanes/Logitech Control Center.prefPane"/Contents/Resources/*.lproj/html/warranty_mice.htm
elif [ -e "/Library/PreferencePanes/Logicool Control Center.prefPane" ]; then
/usr/sbin/chown -R root:admin "/Library/PreferencePanes/Logicool Control Center.prefPane"
/bin/chmod -R ug+rw,o-w "/Library/PreferencePanes/Logicool Control Center.prefPane"
/bin/chmod ugo+w "/Library/PreferencePanes/Logicool Control Center.prefPane"/Contents/Resources/*.lproj/html/
/bin/chmod ugo+w "/Library/PreferencePanes/Logicool Control Center.prefPane"/Contents/Resources/*.lproj/html/warranty_keyboards.htm
/bin/chmod ugo+w "/Library/PreferencePanes/Logicool Control Center.prefPane"/Contents/Resources/*.lproj/html/warranty_mice.htm
fi
# Cleanup
if [ -e "$LCC36P/LCC Uninstaller Tool" ] ; then
"$LCC36P/LCC Uninstaller Tool" –postflight
fi
# Install last bits
# "$1/Contents/Resources/RMover" "$1" –postflight
echo "try to run RMover from Scripts"
"$LCC36P/RMover" "$LCC36P" –postflight
# Be sure that the system realizes that something changed, and rebuild extension cache
if [ -f "/Users/$USER/Library/Caches/.ApplePrefPanesCache" ]; then
/bin/rm -f "/Users/$USER/Library/Caches/.ApplePrefPanesCache"
fi
if [ -f "/Users/$USER/Library/Caches/com.apple.preferencepanes.cache" ]; then
/bin/rm -f "/Users/$USER/Library/Caches/com.apple.preferencepanes.cache"
fi
/usr/bin/touch "/Library/PreferencePanes"
/usr/bin/touch "/System/Library/PreferencePanes"
/usr/bin/touch "/Library/Keyboard Layouts"
if [ -f "/System/Library/Extensions.mkext" ]; then
/bin/rm -f "/System/Library/Extensions.mkext"
fi
# make sure drivers are 'loaded' so that the cache will include them
if [ -e "/System/Library/Extensions/LogitechHIDDevices.kext" ] ; then
/sbin/kextload "/System/Library/Extensions/LogitechHIDDevices.kext"
fi
if [ -e "/System/Library/Extensions/LogicoolHIDDevices.kext" ] ; then
/sbin/kextload "/System/Library/Extensions/LogicoolHIDDevices.kext"
fi
if [ -e "/System/Library/Extensions/LogitechUnifying.kext" ] ; then
/sbin/kextload "/System/Library/Extensions/LogitechUnifying.kext"
fi
/usr/bin/touch "/System/Library/Extensions"
# Daemon, launchd & login items
if [ -e "/Library/Application Support/Logitech.localized/Logitech Control Center.localized/LCCDaemon.app" ] ; then
/usr/bin/sudo -u $USER /usr/bin/osascript -e "tell application \"System Events\" to delete (every login item whose path ends with \"LCCDaemon.app\")"
if [ -e "/Library/LaunchAgents/com.Logitech.Control Center.Daemon.plist" ] ; then
/bin/launchctl load -w "/Library/LaunchAgents/com.Logitech.Control Center.Daemon.plist"
else
/usr/bin/sudo -u $USER /usr/bin/osascript -e "tell application \"System Events\" to make new login item with properties { path: \"/Library/Application Support/Logitech.localized/Logitech Control Center.localized/LCCDaemon.app\", hidden: false } at beginning"
fi
fi
# Add eReg to login items
if [ -e "/Library/Application Support/Logitech.localized/Logitech Control Center.localized/Logitech Registration.app" ] ; then
/usr/bin/sudo -u $USER /usr/bin/osascript -e "tell application \"System Events\" to make new login item with properties { path: \"/Library/Application Support/Logitech.localized/Logitech Control Center.localized/Logitech Registration.app\", hidden: false } at end"
elif [ -e "/Library/Application Support/Logitech.localized/Logitech Control Center.localized/Logicool Registration.app" ] ; then
/usr/bin/sudo -u $USER /usr/bin/osascript -e "tell application \"System Events\" to make new login item with properties { path: \"/Library/Application Support/Logitech.localized/Logitech Control Center.localized/Logicool Registration.app\", hidden: false } at end"
fi
# Launch the daemon (no longer needed, handled by launchd)
#if [ -e "/Library/Application Support/Logitech.localized/Logitech Control Center.localized/LCCDaemon.app" ] ; then
# /usr/bin/sudo -u $USER -b /Library/Application\ Support/Logitech.localized/Logitech\ Control\ Center.localized/LCCDaemon.app/Contents/MacOS/LCCDaemon
#fi
exit 0

view raw
postflight.sh
hosted with ❤ by GitHub

Most of the postflight script, until line 110, is just making sure permissions are correct and drivers are loaded.  These actions are fine, but lines 125-129 add a login item for all users which greets them with an annoying registration prompt, which is particularly a problem on shared machines.

Comment out or delete lines 125-129, which will stop the the login item from being created. Save the script, as all edits have now been completed.

Wrapping Up

The main metapackage contains more than just the Logitech Control Center, it also has the Logitech Updater and Logitech Unifying software.  If you are in a managed environment, you probably do not want the updater, and if you are not using Logitech’s wireless products with the Unified Receiver, you really do not need that either.  If this is the case, you are ready to flatten the package, using this command:

pkgutil –flatten logitechControlCenter.pkg logitechControlCenter.fixed.pkg

view raw
gistfile1.sh
hosted with ❤ by GitHub

Import the resulting package into your management software, and you are ready to deploy it to your fleet.

If you would like to use the metapackage, flatten it using the following command, and optionally use ChoiceChangesXML to choose what you would like to install.

pkgutil –flatten Logitech\ Control\ Center.expanded.mpkg Logitech\ Control\ Center.fixed.mpkg

view raw
gistfile1.sh
hosted with ❤ by GitHub

Conclusion

Many vendors continue to ship enterprise-unfriendly software, but by knowing how to combat the issues with this software, admins will save many long-term headaches.  With just a bit of time invested and some easy changes to a couple of scripts, a package that was previously unusable in a managed environment can become just another friendly package.  While other software may require full-on repackaging, minor changes saved the Logitech Control Center.

Of course, the best course of action is to complain to your vendors and vote with your dollars, but this may be impossible with free software or if there is no alternative.

Samuel Keeley

Samuel Keeley can frequently be found in ##osx-server on Freenode, or on Twitter @keeleysam.

More Posts - Website

Follow Me:
Twitter

Leave a reply

You must be logged in to post a comment.