How to unpackage and repackage a pkg (OS X Lion+ / Xcode 4.3+)
Published 2013-3-22The first thing you may ask is "AJ, why are you wasting your time on this? There are already tutorials on how to do this!"
Well, yes, but there are new tools for Xcode 4.3 and up that do a better,
simpler job than the cat <Payload|Script> | gzip -d - | cpio -id
method.
Plus, here we get a chance to look at the Bom
and plist
as well!
Here's my use case. A friend of mine packaged a package for a company we used to work, but the documentation was never written or lost.
I want to use that work as the basis for a package that I'm creating, but I don't know where to start... so I'm going to rip apart the old package instead of starting from scratch.
Install Xcode
You can get Xcode from App Store, but you'll also need the Command line tools from https://developer.apple.com/downloads/index.action (Log in and then search for it in Developer Downloads)
Note: On Ubuntu (or other Linux) you will need to have lsbom
and mkbom
installed.
Unpack Example.pkg
See the File Commands section of http://developer.apple.com/.../pkgutil.1.html
So let's say I have ~/Downloads/ExampleApp.pkg
(which I do!) and I want to extract / upack it.
pushd /tmp
pkgutil --expand ~/Downloads/ExampleApp.pkg /tmp/ExampleApp.unpkg
Then, for fun, I like to see what all was extracted
find /tmp/ExampleApp.unpkg
For reference, the long way of doing this (i.e. for Linux) is
mkdir -p /tmp/ExampleApp.unpkg
pushd /tmp/ExampleApp.unpkg
xar -xf ~/Downloads/ExampleApp.pkg
ls -d *.pkg | while read PKGDIR
do
pushd $PKGDIR || continue
mv Scripts Scripts.bin
mkdir -p Scripts
pushd Scripts
cat ../Scripts.bin | gzip -d | cpio -id
popd
popd
done
Note that the file Scripts
is unpackaged to a folder Scripts, with the scripts inside.
List Bom
I'm going to take a wild guess and say that Bom stands for Bill of materials, which is hardware engineers submit to off-site manufacturing facilities.
It's basically the tar --list
(same as tar -t
) of pkgs.
See the options section of http://developer.apple.com/.../lsbom.8.html
lsbom comexample.pkg/Bom
Note that you can extract just the Boms, with slightly less verbosity with pkgutil --bom ~/Downloads/ExampleApp.pkg
List PackageInfo
PackageInfo
is already a plain text file.
It contains the organization identifiers, install location, number of files and bytes to install, etc.
Extract Payload
So, you still end up having to use the old black magic for the payload
pushd ~/tmp/ExampleApp.unpkg/
pushd example.pkg/
cat Payload | gzip -d | cpio -id
ls
The Distribution file and the Resources folder
The Resources folder contains resources that are needed for the installer, but not to be installed - such as the background image to use.
The Distribution file contains configuration information to be used by the installer as well as possibly some black magic JavaScript.
Repackage
If you somehow accidentally deleted the package, but you didn't change anything you can repackage the pkg like-a-so:
pkgutil --flatten /tmp/ExampleApp.unpkg ~/Desktop/ExampleApp.pkg
But let's say you do change a file (or add one, etc). What then?
First we extract the Payload to a clean directory, like so:
mkdir /tmp/ExampleApp-example.pkg
pushd /tmp/ExampleApp-example.pkg
cat /tmp/ExampleApp.unpkg/example.pkg/Payload | gzip -d | cpio -id
Next you add / remove / edit your files
Then you repackage the Payload with a new Bom
rm /tmp/ExampleApp.unpkg/example.pkg/Payload
rm /tmp/ExampleApp.unpkg/example.pkg/Bom
# Still in /tmp/ExampleApp-example.pkg
find . | cpio -o --format odc | gzip -c \
> /tmp/ExampleApp.unpkg/example.pkg/Payload
mkbom /tmp/ExampleApp-example.pkg/ /tmp/ExampleApp.unpkg/example.pkg/Bom
And finally update the PackgeInfo with the number of KB and files
installKBytes
is the number of KiB assuming that the disk using 4KiB blocks, minus 4KiB:
du -sk /tmp/ExampleApp-example.pkg/ # subtract 4 from that number!!!
numberOfFiles
is the number of nodes (files, directories, sockets, whatever), including .
:
find /tmp/ExampleApp-example.pkg/ | wc
Those values can be edited at /tmp/ExampleApp.unpkg/example.pkg/PackageInfo
With all of that done you can now repackage the entire shebang:
pkgutil --flatten /tmp/ExampleApp.unpkg/ /tmp/ExampleApp.new.pkg
Note: If you used xar
to extract (on Linux) instead of pkgutil
,
you'll need to use that again:
pushd /tmp/ExampleApp.unpkg
xar -cf ../ExampleApp.new.pkg .
Test and enjoy!
open /tmp/ExampleApp.new.pkg
Linux Only
If you need to do all of this from Linux - perhaps you need to edit a uuid for every download or something - then make sure to peek at the notes here as well:
Other References
By AJ ONeal
Did I make your day?
Buy me a coffee
(you can learn about the bigger picture I'm working towards on my patreon page )