Last Week on My Mac: Miss Havisham Syndrome

Like all great novellists, Charles Dickens was an astute observer of the human condition. In his novel Great Expectations, Miss Havisham displays the syndrome now associated with her name, and that of Diogenes: after being jilted at the altar, she spends the rest of her life wearing her wedding dress, surrounded by the rotting remains of what was to have been her wedding breakfast. In the psychiatric condition, prolonged self-neglect leads to compulsive hoarding of rubbish, and living in squalor, hence the alternative name Senile Squalor Syndrome.

I’ve spent much of the last week in the squalor that is macOS. To be more precise, trying to get information about a Mac’s key hardware features such as the type and numbers of CPUs, logic board ID, and type of internal storage. Although not commonplace in apps, my needs are hardly extreme, and grow from recent experience with failed firmware updates in the iMac17,1, and other phenomena such as panicking on wake which appear confined to some Macs but not others of the same model. I’d like to be able to use those and other details gathered using my free app Mints to try to associate specific hardware configurations with well-known misbehaviours.

Users can obtain much of those data from System Information, and there’s a command line equivalent in
system_profiler -detailLevel mini
but even turning the output down to that mini level you have to wade through unnecessary noise, including a listing of every printer driver installed. Wouldn’t it be nice if macOS had an API which I could simply query for each item that I want to know?

It did once in Gestalt, which was introduced with System 6.0.4 in 1989, but for several years now has been deprecated, and what remains is as ruined as Miss Havisham’s mansion. Apple instead advises using its sysctl calls, which are inevitably poorly documented, and not yet wrapped for convenient access using Swift. You can get a taste for this using
sysctl -n [category]
in Terminal, where the category is something like hw.memsize to get the amount of installed memory.

Rather than calling the command tool, you can use the C call sysctlbyname(), although the Developer Documentation provided with Xcode gives no further details. From a higher language like Swift, this is cumbersome at best, and you’d be well advised to read Matt Gallagher’s article about doing that before writing any code.

As Matt points out, the sysctl calls in C are themselves only wrappers for calls to access data in IOKit’s vast IORegistry, which really is Miss Havisham in her wedding dress. The Xcode documentation reveals extensive support for SCSI and FireWire, but little that seems to target Mac hardware made in the last eight years. The detail increases when you study Apple’s previous accounts of IOKit, in Accessing Hardware From Applications and IOKit Fundamentals. But those are so ancient that they still list data for ADB, a predecessor to USB which Apple retired in 1999, when Miss Havisham’s wedding should have taken place.

It was then that my own compulsive hoarding paid off: old documentation referred to a tool which I still had in my Xcode Tools folder, IORegistryExplorer. A bit of rooting around revealed this to be one of the tools still provided in Apple’s Additional Tools for Xcode, where the current version has even been updated to work in Dark Mode.

ioregexp

Accessing anything in the IORegistry is like trying to find fresh flowers in Miss Havisham’s mansion: when you think you’ve got a clue from the old documentation, IORegistryExplorer never fails to disappoint. Perhaps I just haven’t got the hang of it, but this has become the most opaque coding I have ever attempted.

So I went back to long series of Google searches. Although I had been quickly successful in discovering how to find the logic board ID, simple information like the type of internal storage, even the graphics card, remained elusive. One ‘solution’ I found for locating graphics card details actually delivers the model of Ethernet adaptor, and for storage all I’d been able to do was list the details of external SSDs connected via Thunderbolt. The simplest solution for getting details of the graphics card seems to be to list Metal Graphics Devices using MTLCopyAllDevices().

So far, to obtain a short list of hardware and software details, I’m calling sysctl as a command so that it consistently returns results in a string, accessing IORegistry’s IOPlatformExpertDevice and at other points, calling diskutil as a command to discover the size of internal storage, accessing Metal info, and reading ProcessInfo.processInfo.operatingSystemVersionString. Much of this has been based not on any documentation from Apple, but repeated web searches. I’ve been reduced to coding by rumour.

In a few weeks time, this all becomes even more complicated when Apple Silicon Macs start shipping. It’s bad enough now that some Macs which undergo logic board replacement end up without any serial number. When my code starts asking embarrassing questions of totally different hardware, it will be interesting to see what happens.

This is just the time that we most need clear and systematic documentation, and clear and consistent mechanisms for accessing that information which are designed to work cleanly with languages such as Swift. This is no time for the squalor which currently pervades IORegistry, sysctl and all the other bits tacked on seemingly at random.

The fate of Miss Havisham is pure tragedy. After repenting, her wedding dress catches fire. Although rescued by Pip, the orphaned hero, she dies a few weeks later from her burns. This is no time for any of us to get burned.