Spot problem commands in Apple Installer package scripts

It should come as no surprise that Apple Installer installation packages can contain scripts. These scripts are supposed to conduct important operations during the course of the software installation.

However, when you are the system administrator of more than one Mac, you find that developers sometimes miss a good balance between what you think should be in the installer payload versus what should be in its scripts. The payload of a installer, by definition, are the files and links that should be installed, along with information on where they should be installed as well as how (i.e. ownership, permissions).

Therefore, developers should not need to run scripts that create or delete files — they should be created from the payload itself, and if a file must be deleted during the install then consider that perhaps you’re doing it wrong. Likewise, there should be little need move or copy files, because as many copies as desired can be installed from the paylod. Similarly, the need to change ownership or modify permissions should be taken care of in the payload.

Perhaps I’m being a purist here. I’m certainly accused of that, from time to time. However, this just makes sense to me and I happen to think that many developers are similarly logical people. They just aren’t the kind of logical people who happen to spend effort on software installation, especially the kind that results in a deployment-friendly installer package.

So how do we as administrators verify the quality of the scripts in installers? Is there a way we can quickly peer into them to decide if any of the scripts’ steps will be superfluous or even (gasp!) harmful?

Well, I have a quick suggestion for scanning packaged installers. The following one-liner shell command will search an installer package or metapackage for scripts that have the kinds of steps outlined above.

$ find /path/to/installer.pkg -regex '.*/*\(flight\)' -or -regex '.*/*\(install\)' -or -regex '.*/*\(upgrade\)' -exec grep --with-filename --line-number '\(cp\|mv\|ln\|>{1,2}\|cat\|echo\|chown\|chmod\|rm\|srm\)' {} \;

Note that this will only work for the traditional installer packages; it will not work with Leopard-style flat packages (which are documented so badly by Apple that the best description comes from reverse engineering by Iceberg's author). The one-liner will currently only find the defined install operations scripts: preflight, preinstall, preupgrade, postinstall, postupgrade, and postflight. (Any other scripts are likely to be called by one of those six.) It assumes those scripts will be shell scripts, currently, even though any of them could be written in other scripting languages installed with Mac OS X, like Python, Perl, or Ruby. It will also not work on the JavaScript-based system and volume requirements portions of the installation.

However, it’s a start. The output displays the offending file and line number, so you can conduct more careful examination of the matches it finds.

I haven’t run this on an exhaustive list of installation packages, but I have already seen at least one installer that produces worrisome output.

Update: I’ve changed the regex for the pre/postflight script so that it is more general that what I originally posted. I’m also having some problems with the snippet working with a certain installer whose scripts I know have cp and chmod commands. So, I may be back to the drawing board with this; comments are welcome.