Xcode 3.2: Using GDB as a Non-Admin User
New in Xcode 3.2 is an authorization setting that looks like this:
<dict> <key>allow-root</key> <false/> <key>class</key> <string>rule</string> <key>comment</key> <string>For use by Apple. WARNING: administrators are advised not to modify this right.</string> <key>k-of-n</key> <integer>1</integer> <key>rule</key> <array> <string>is-admin</string> <string>is-developer</string> <string>authenticate-developer</string> </array> <key>shared</key> <true/> </dict>
The upshot of this is that if you aren’t in the _developer group in the local directory, you’ll have to authenticate as an administrator to use gdb or some of the performance tools. For the vast majority of developers on Mac OS X, who run as an administrator, this is fine, but if you’re running as a regular user, either for security reasons or because you’re in something like a lab setting, this can be a problem. To add a user to the _developer group, use the dscl command:
dscl . -append /Groups/_developer GroupMembership UserName
Replace UserName with the short name of your user account (or $(whoami)) and you should be all set.
If you’re administering Mac OS X in a lab setting, you can either create a LaunchAgent that handles this or a login hook. See the Apple tech note “Running At Login” for more information on login hooks. As an added touch, my login and logout scripts to handle this also remove all users from the group, like so:
dscl . -delete /Groups/_developer GroupMembership
If the GroupMembership key doesn’t exist, dscl will create it—and it doesn’t exist by default—so deleting it outright shouldn’t cause any problems.
How-To: Run a LaunchDaemon That Requires Networking
I’m a big fan of using launchd to automate things in Mac OS X. That serves me well, as that’s how Apple wants things done moving forward. That said, one of launchd’s biggest shortcomings is a lack of a dependency system. There is currently no way, for instance, to specify in a LaunchDaemon’s property list that the daemon requires the network to be active in order to run. This is problematic for some things, such as a script I wrote to automatically set the computer’s hostname based on the DNS server (more on that later). Luckily, Apple has already defined a function, CheckForNetwork, in /private/etc/rc.common. Here it is in all its glory:
##
# Determine if the network is up by looking for any non-loopback
# internet network interfaces.
##
CheckForNetwork()
{
local test
if [ -z "${NETWORKUP:=}" ]; then
test=$(ifconfig -a inet 2>/dev/null | sed -n -e '/127.0.0.1/d' -e '/0.0.0.0/d' -e '/inet/p' | wc -l)
if [ "${test}" -gt 0 ]; then
NETWORKUP="-YES-"
else
NETWORKUP="-NO-"
fi
fi
}
In your code, simply include rc.common, then call CheckForNetwork as needed. An example:
#!/bin/bash
# Example Daemon Starter
. /etc/rc.common
CheckForNetwork
while [ "${NETWORKUP}" != "-YES-" ]
do
sleep 5
NETWORKUP=
CheckForNetwork
done
# Now do what you need to do.
Note that this will keep the script running indefinitely until CheckForNetwork sets NETWORKUP to “-YES-,” so if there’s a networking problem your code may never execute.
Updating dyld Shared Caches with Radmind: Best Practices
Similar to my last post about updating kernel extensions, you can run into problems with Radmind due to the dyld shared cache. You may see messages like this in your system log:
current cache invalid because /System/Library/Frameworks/WebKit.framework/Versions/A/WebKit has changed
Running the update_dyld_shared_cache command will fix this, but there’s a better way. Sure, there’s almost no overhead to that command, but where’s the fun in that? Here’s a pre-apply script that will delete any shared caches that have changed, which will then be re-built at reboot.
#!/bin/sh # update_dyld_caches: Inspects the applicable transcript for something that # might cause a dyld cache to become outdated. If it exists, # delete the cache so it's re-created at startup. DYLD_CACHE_FOLDER="/private/var/db/dyld" DYLD_PREFIX="dyld_shared_cache_" ARCHITECTURES="i386 x86_64 rosetta ppc ppc64" for arch in ${ARCHITECTURES}; do cache="${DYLD_CACHE_FOLDER}/${DYLD_PREFIX}${arch}" map="${DYLD_CACHE_FOLDER}/${DYLD_PREFIX}${arch}.map" if /bin/test -f "${cache}"; then if /bin/test -f "${map}"; then /bin/cat "${map}" | grep ^/ | sort --unique --ignore-case | while read line; do if /bin/test -n "$(grep ${line} ${1})"; then # found a match /bin/rm -f "${cache}" /bin/rm -f "${map}" break; fi done else # Cache exists, but there's no map. /bin/rm -f "${cache}" fi fi done
Updating Kernel Extensions with Radmind: Best Practices
One of the problems that I’ve run into so far using Radmind to manage Mac OS X—specifically, the Leopard to Snow Leopard transition—is that kextd helpfully starts recreating your kernel extension cache as soon as you modify anything in /System/Library/Extensions. This can be problematic when you’re updating core system files; as you update the 10.5 kernel extensions to their 10.6 counterparts, you don’t want the 10.5 version of kextd creating a cache of 10.6 kernel extensions, especially as the kernel extension cache has moved (from /System/Library/Extensions.mkext to /System/Library/Caches/com.apple.kext.caches/). So, should you handle this? My solution is to stop kextd if I know that I’m updating kernel extensions; that way, they won’t be re-created until reboot. Here’s the script:
/private/var/radmind/preapply/update_kernel_extensions:
#!/bin/sh # update_kernel_extensions: Manage the replacement of old kernel extensions. # If there are updates, kill kextd and destroy the # caches. KEXT_CACHE="/System/Library/Caches/com.apple.kext.caches" KEXT_FOLDER="/System/Library/Extensions" KEXTD_LAUNCHD="com.apple.kextd" SYSTEM_LAUNCHD_FOLDER="/System/Library/LaunchDaemons" transcript="${1}" result="${transcript}.$$" /usr/bin/grep "${KEXT_FOLDER}" "${transcript}" > "${result}" if test -n "${result}"; then #result is non-empty # Disable kextd to prevent it from recreating kernel extension caches, which # will be re-created at startup. if test -n "$(/bin/launchctl list | /usr/bin/grep ${KEXTD_LAUNCHD})"; then #kextd is running /bin/launchctl unload "${SYSTEM_LAUNCHD_FOLDER}/${KEXTD_LAUNCHD}.plist" fi # Remove kernel extension cache. /bin/rm -rf "${KEXT_CACHE}" fi rm -f "${result}"
In its present form, it only works on Snow Leopard, but I’ll be updating it to work on Leopard as well.
Automatically get the latest Chromium snapshot with launchd
I’ve been checking out the snapshots of Chromium recently, and they’re coming quicker than you can say “multithreaded web browser.” To facilitate always having the latest version, I wrote a quick LaunchAgent that takes care of it on Mac OS X. First, I have a script named ~/bin/chromiupdate:
#!/bin/bash
# Downloads the latest version of Chromium.
remove_working_dir()
{
rm -rf "${WORKING_DIR}"
exit 0
}
USER_DIR=$(dscl . -read /Users/$(whoami) NFSHomeDirectory | awk '{ print $2 }')
USER_APP_DIR="${USER_DIR}/Applications"
CHROMIUM_DIR="${USER_APP_DIR}/Chromium.app"
LATEST_URL="http://build.chromium.org/buildbot/snapshots/sub-rel-mac/LATEST"
TMP_DIR="/private/tmp"
WORKING_DIR="${TMP_DIR}/.chromium_launchd"
URL_BEGIN="http://build.chromium.org/buildbot/snapshots/sub-rel-mac"
if [ ! -d "${CHROMIUM_DIR}" ]; then
mkdir -p "${CHROMIUM_DIR}"
fi
INSTALLED_VERSION="$(defaults read "${CHROMIUM_DIR}/Contents/Info" SVNRevision)"
VERSION=$(curl "${LATEST_URL}")
if [ "${VERSION}" != "${INSTALLED_VERSION}" ]; then
logger Installed Chromium version \(${INSTALLED_VERSION}\) does not equal \
latest version \(${VERSION}\), updating now...
mkdir "${WORKING_DIR}" || exit 1
trap remove_working_dir 1 2 3 6 15
cd "${WORKING_DIR}" || exit 1
curl -O "${URL_BEGIN}/${VERSION}/chrome-mac.zip"
unzip chrome-mac.zip
rsync -HavP --exclude="Contents/MacOS/chrome_debug.log" \
"${WORKING_DIR}/chrome-mac/Chromium.app/" "${CHROMIUM_DIR}/"
if [ "$(ps -aef | grep -i chromium | grep -v grep)" != "" ]; then
open "${USER_DIR}/Library/Scripts/Chromium Update Dialog.app"
fi
logger "Chromium update complete. Version ${VERSION} installed."
remove_working_dir
else
logger Installed Chromium version \(${INSTALLED_VERSION}\) is up-to-date. \
No action needed.
fi
exit 0
Next, I have a property list named ~/Library/LaunchAgents/com.slaunchaman.chromium.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd >
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.slaunchaman.chromium</string>
<key>Program</key>
<string>/Users/slauncha/bin/chromiupdate</string>
<key>KeepAlive</key>
<false/>
<key>StartInterval</key>
<integer>3600</integer>
<key>RunAtLoad</key>
<true/>
<key>StandardOutPath</key>
<string>/dev/null</string>
<key>StandardErrorPath</key>
<string>/dev/null</string>
</dict>
</plist>
Finally, I have an AppleScript at ~/Library/Scripts/Chromium Update Dialog.app:
display dialog "Chromium was just updated. You should restart it."
The LaunchAgent runs once an hour, checking to see if the installed version of Chromium is older than the latest snapshot. If so, it downloads it and uses rsync to copy the changes. The script places Chromium in ~/Applications, but it shouldn’t be hard to modify to put it into /Applications.
New Safari 3.2 Feature: Secure Website Identification
Here’s a quick tip that slipped through the blogosphere (at least none of the Mac blogs I subscribe to featured it): in Safari 3.2, released last week, Apple’s added a feature from Firefox 3’s “awesome bar”: when you’re on a secure website, such as a bank’s, that has identification information, it’s displayed in green (though in Safari it’s at the top-right of the title bar). A screenshot:

Safari 3.2 adds secure website information to the title bar.
Along with a phishing filter, it looks like Safari is stepping up to the plate as a secure browser.
Use DVD Player in Fullscreen Mode on an External Monitor
By default, DVD player will exit fullscreen mode when it’s not the active application. This is a problem if you want to watch a movie on an external monitor while working on a primary monitor. To get around it, go to Preferences in DVD Player (DVD Player -> Preferences… or command + ,), switch to the “Full Screen” tab, and ensure that “Remain in full screen when DVD Player is inactive” is checked. This should achieve the desired results.
Source: MacRumors.com Forums
Prevent Mac OS X Leopard from Prompting You to Start Synergyd Every Time You Use SynergyKM
So here’s an annoyance. Having just installed SynergyKM, a great front-end for the awesome command-line utility Synergy, launching it would result in the following prompt:
To fix this, you need to remove the extended attribute com.apple.quarantine that’s on the file. Fire up Terminal and enter the following commands:
sudo xattr -d com.apple.quarantine /Library/PreferencePanes/SynergyKM.prefPane/Contents/Resources/Synergyd.app
sudo xattr -d com.apple.quarantine /Library/PreferencePanes/SynergyKM.prefPane/Contents/Resources/Synergyd.app/Contents/MacOS/Synergyd
That will remove the flags and prevent the prompt.
Normally, you’d only see this prompt once, but since installing it for all users changes permissions such that your user account can’t remove the attribute, it isn’t removed.
Note: This is assuming that you’ve installed it for all users. If you’ve installed it for one user, it’ll be in ~/Library, not /Library.
Update: I’ve submitted a patch to SynergyKM’s SourceForge page, so if they accept it this will no longer be an issue.
Resize Your Windows Automatically for Different Resolutions
I use my MacBook Pro in a few different scenarios: by itself, plugged in to a 21” Apple Cinema Display, or plugged in to a 24” Dell 2405FPW. I’m also rather OCD; I prefer my Firefox/Safari, Mail.app, and Vienna windows to be centered, stretch from the menu bar to the top of my Dock, and be a certain width. I created a small AppleScript to auto-detect my resolution and size the windows accordingly:
tell application "Finder" set screen_resolution to bounds of window of desktop set screen_width to item 3 of screen_resolution set screen_height to item 4 of screen_resolution end tell tell application "System Events" to tell process "Dock" set dock_dimensions to size in list 1 set dock_height to item 2 of dock_dimensions end tell set desired_width to 1400 set side_space to screen_width - desired_width set left_bound to (side_space / 2) set right_bound to left_bound + desired_width set bottom_bound to screen_height - dock_height set top_bound to 22 (* for the menu bar *) try tell application "iTunes" activate set the bounds of the first window to {left_bound, top_bound, right_bound, bottom_bound} end tell end try try tell application "Firefox" activate set the bounds of the first window to {left_bound, top_bound, right_bound, bottom_bound} end tell end try try tell application "Mail" activate set the bounds of the first window to {left_bound, top_bound, right_bound, bottom_bound} end tell end try try tell application "Vienna" activate set the bounds of the first window to {left_bound, top_bound, right_bound, bottom_bound} end tell end try
With that in place, I saved it as an application in ~/Applications, and put it in my Dock. Now, whenever I change resolutions, I just click the button and everything is how I like it.
To change the script, you should be able to add any application with an AppleScript dictionary that supports moving and sizing the window. The numbers I’ve used make the windows 1,400px wide, and the height that you want will depend on the size of your Dock. The script moves windows to the center, desired_width wide, and from the menubar to the Dock.
Note: I have had some trouble recently; sometimes when I change my resolution the AppleScript doesn’t pick it up. To combat this, I told the Displays System Preferences pane to keep its icon in the menu bar; when my script uses the incorrect resolution, I change my screen resolution then change it back, which is enough for the script to detect the change.
Update 2008-05-28: Made some usability changes. Details here.

