defaults – the Plist Killer

Last week, fellow MacAdmin Kyle Crawford has discovered that on macOS High Sierra the defaults will delete a property list file with invalid plist/XML syntax, even when you just attempt to read data. Erik Holtham has a more detailed OpenRadar bug.

Patrik Wardle has found the relevant code, which deletes the file when it doesn’t validate.

This is bad. Thanks to all involved for finding, documenting and sharing this.

This is new behavior in High Sierra. I am not yet sure which version of High Sierra this new behavior was introduced. The behavior makes sense in the context of an application attempting to read a settings file, but the defaults tool deleting arbitrary files is, of course, dangerous.

Update: This behavior has been fixed in 10.13.4. However, it is still good practice to avoid defaults for anything other than actual preferences files.

What to do?

As usual, don’t panic. This will only affect Macs running High Sierra and corrupt or broken files. However, if you have a script that accidently points the defaults command at a different file, it will delete that. So you have to use it with care.

It is probably a good practice to verify a file before you attempt to modify it with the defaults command in a script with the plutil command:

if ! plutil -lint path/to/file.plist; then
    echo "broken plist"
    exit 1
else
    defaults path/to/file …
fi

Alternatives to defaults

Alternatively, you can and should use plutil or PlistBuddy to read and modify property list files.

Learn more about plutil, PlistBuddy and other tools to read and write property lists in my book: “Property Lists, Preferences and Profiles for Apple Administrators”

plutil is unfortunately not really useful to read a single value from a property list file. The extract verb will show any value as its own plist. The plutil command is useful to edit existing plist files. (Read details on the plutil command.)

PlistBuddy, however is very useful for both reading an writing values to a property list file:

$ /usr/libexec/PlistBuddy berry.plist -c "print size"
$ /usr/libexec/PlistBuddy berry.plist -c "set size enormous"

PlistBuddy has the additional advantage of allowing to add or edit values nested deep in dict or array structures.

You can get more information on PlistBuddy in its man page or my book.

The interactive mode of PlistBuddy is also very useful.

So the defaults command is dead?

No.

Apple has been warning us to not use defaults for generic property list file editing and parsing for quite a while in the defaults command’s man page:

WARNING: The defaults command will be changed in an upcoming major release to only operate on preferences domains. General plist manipulation utilities will be folded into a different command-line program.

As this warning states, the defaults tool reads and writes data to plist files through macOS’s preferences system. This has the advantage that the tool gets (and changes) the current value whether it is cached in memory or not. When an application is listening for notifications that a preference has changed (not many do) then it will be notified.

Files for preference domains are usually stored in /Library/Preferences/, ~/Library/Preferences or their ByHost subfolders. Sandboxed applications will have their preference plist files in their container.

There, however, many other files that are property list files which are not part of the user defaults system: launchd files, configuration profiles and AutoPkg` recipes to name just a few.

Mac Admins commonly use the defaults tool, despite Apple’s warning, to create, read and edit generic plist files. As mentioned above, plutil, PlistBuddy or direct manipulation through Obj-C, Python or Swift, are better choices for generic plist files.

You can learn about all these options in my book: “Property Lists, Preferences and Profiles for Apple Administrators”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.