Monday, August 27, 2012

Running an unsigned app with Gatekeeper set to 'only apps from the Mac App Store and identified developers'

So with Gatekeeper set to 'Mac App store and identified developers', how do you actually run an app that isn't signed? If you double-click you'll see something like this:




As explained previously you can delete the HFS+ attribute or run it from the commandline, but for regular users that doesn't work too well. The solution is Ctrl-Click and 'Open'.



Tuesday, August 21, 2012

OS X: get a list of running launchd jobs

Here's a nice easy way to get a list of running launchd jobs using PyObjC to talk to the ServiceManagement API:

from ServiceManagement import SMCopyAllJobDictionaries

print SMCopyAllJobDictionaries('kSMDomainSystemLaunchd')
So how does this compare to launchctl? On a first look its great, it provides way more information about each launchd job.
        {
        Label = "com.apple.systemprofiler";
        LastExitStatus = 0;
        LimitLoadToSessionType = Aqua;
        MachServices =         {
            "com.apple.systemprofiler" = 0;
        };
        OnDemand = 1;
        Program = "/Applications/Utilities/System Information.app/Contents/MacOS/System Information";
        TimeOut = 30;
    },
But wait, I'm getting different results:
$ sudo launchctl list | grep airport
- 0 com.apple.airport.updateprefs
- 0 com.apple.airportd
$ sudo python print_daemons.py | grep airport
$
So what is launchctl doing different? Why am I missing airportd and other services? I spent some time reading the source, but that didn't help. I finally realised this was a execution context issue.
$ sudo /usr/libexec/StartupItemContext python print_daemons.py | grep airport
        Label = "com.apple.airportd";
            "com.apple.airportd" = 0;
        Program = "/usr/libexec/airportd";
        Label = "com.apple.airport.updateprefs";
            "com.apple.airport.updateprefs" = 0;
            "com.apple.airport.wps" = 0;
The launchd jobs are running in the System context (there are a bunch of others, see table 1 here), and can't see jobs running in other contexts. This also means that if we use StartupItemContext as above to run in the System context, we're going to miss jobs that have set LimitLoadToSessionType to something else, as with the systemprofiler job, which only runs in the Aqua (GUI) context.
$ sudo /usr/libexec/StartupItemContext python print_daemons.py | grep systemprofiler
$ sudo python temp.py | grep systemprofiler
        Label = "com.apple.systemprofiler";
            "com.apple.systemprofiler" = 0;

Wednesday, August 15, 2012

git: undo changes, revert uncommitted changes

I mostly love git, but I can never remember the syntax for undoing and reverting things, which is partly because I don't use it that often, and partly because the syntax is un-intuitive. I'll update this post as I hit the various scenarios.
Merge broken by conflicts
Often I'll pull in changes from the stable repo, forgetting I've made some uncommitted local changes, which results in a conflict. To drop all of your local uncommitted changes:
git reset --hard HEAD

Friday, July 20, 2012

plistbuddy and defaults on OS X

I use defaults to read most plists on OS X, but it has an annoying habit of being very chatty in the logs. If you want to write code to query for a value that may or may not be present, it ends up being very noisy. e.g. even if you suppress stderr like this:
defaults read /Library/Preferences/com.apple.CrashReporter.plist DOESNT_EXIST 2> /dev/null
For some reason the defaults tool thinks the failure to read the value is really important and writes a log line like:
defaults[34157]: The domain/default pair of (com.apple.CrashReporter.plist, DOESNT_EXIST) does not exist
So if you don't want the spurious logs, you can use plist buddy to do the same thing:
/usr/local/bin/PlistBuddy -c Print:DOESNT_EXIST /Library/Preferences/com.apple.CrashReporter.plist

Monday, July 2, 2012

Mox: stub out a python builtin method like 'exit' or 'open'

Occasionally you need to stub out a part of core python for a test to work. In my case it was 'exit', another example is 'open'. This is what your test code will look like:
import __builtin__

m = mox.Mox()
m.StubOutWithMock(__builtin__, 'exit')
exit(my_module.EXIT_ERROR)

m.ReplayAll()
my_module.myfunction()
m.VerifyAll()

Friday, June 29, 2012

JAVA CA store on OS X

To get the list of CAs trusted by Java on OS X:
keytool -v -list -keystore /System/Library/Java/Support/CoreDeploy.bundle/Contents/Home/lib/security/cacerts
The default password is 'changeit'.

Thursday, June 28, 2012

Ruby foo: flatten a hash into a string

Flatten a ruby hash into a string. In this case the comma is the key value delimiter and the semicolon is the entry delimiter.
irb(main):016:0> a={'sdfs'=>['aaa','bbb'], 'ppp'=>['aa','a']}
=> {"ppp"=>["aa", "a"], "sdfs"=>["aaa", "bbb"]}
=> ["ppp:aa,a", "sdfs:aaa,bbb"]
irb(main):018:0> b=a.map { |k, v| "#{k}:#{v.join(',')}" }.join(";")
=> "ppp:aa,a;sdfs:aaa,bbb"