OS X includes a handy Terminal tool called ‘pkgbuild’ for compiling package installer files.

To demonstrate pkgbuild I will use my 'Enable ARD' (Apple Remote Desktop) package.

This package places an enableard.sh script into /Library/Scripts/Enable ARD/ and creates a LaunchDaemon to run that script on boot. The enableard.sh script simply removes all users from Remote Management (ARD) and then gives full access to a specified username, ensuring that user has remote access.

Structure

To keep things organised when creating a package, I create a directory consisting of the following files and folders:

build.sh: Includes the package name, versioning information and is used to compile the package.

complied: Is where the product of build.sh is written.

files: Contains the files the package will copy into place.

scripts: Can contain preinstall and/or postinstall scripts. A preinstall script is run before the contents of files is copied into place, whereas postinstall is after. It is important not to give these script files an extension.

Contents of build.sh:

#!/bin/bash

# Name of the package.
NAME="enableard"

# Once installed the identifier is used as the filename for a receipt files in /var/db/receipts/.
IDENTIFIER="au.com.errorfreeit.$NAME"

# Package version number.
VERSION="1.0"

# The location to copy the contents of files.
INSTALL_LOCATION="/Library/Scripts/Enable ARD"


# Remove any unwanted .DS_Store files.
find files/ -name '*.DS_Store' -type f -delete

# Set full read, write, execute permissions for owner and just read and execute permissions for group and other.
/bin/chmod -R 755 files

# Remove any extended attributes (ACEs).
/usr/bin/xattr -rc files

# Build package.
/usr/bin/pkgbuild \
    --root files/ \
    --install-location "$INSTALL_LOCATION" \
    --scripts scripts/ \
    --identifier "$IDENTIFIER" \
    --version "$VERSION" \
    "compiled/$NAME-$VERSION.pkg"

 

Contents of scripts/postinstall:

#!/bin/bash

# Filename of script.
NAME="enableard.sh"

# Path to script.
PATH="/Library/Scripts/Enable ARD"

# Script identifier (same as package identifier).
IDENTIFIER="au.com.errorfreeit.enableard"


LAUNCH_DAEMON_PLIST="/Library/LaunchDaemons/$IDENTIFIER.plist"

# Write LaunchDaemon plist file.
echo '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>'$IDENTIFIER'</string>
    <key>ProgramArguments</key>
    <array>
        <string>'$PATH/$NAME'</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>' > "$LAUNCH_DAEMON_PLIST"

# Load the new LaunchDaemon.
/bin/launchctl load "$LAUNCH_DAEMON_PLIST"

# Check LaunchDaemon is loaded.
STATUS=`/bin/launchctl list | /usr/bin/grep $IDENTIFIER | /usr/bin/awk '{print $3}'`

if [ "$STATUS" = "$IDENTIFIER" ]
then
        echo "Success: LaunchDaemon loaded."
        exit 0      
else
        echo "Error: LaunchDaemon not loaded."      
        exit 1
fi

 

Contents of files/enableard.sh:

#!/bin/bash

# Username of account used for ARD access.
USER="ardadmin"

# Revoke ARD access for all users.
/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -activate -configure -access -off

# Assign full privileges to an ARD Administrator account.
/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -activate -configure -access -on -users $USER -privs -all -restart -agent -menu

# Set Remote Management to only accept the user specified.
/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -configure -allowAccessFor -specifiedUsers

Ready To Compile

To compile a package:

Open Terminal,

type 'cd ' (change directory),

drag the folder containing build.sh into Terminal and hit return,

type 'chmod +x build.sh' to make it executable,

lastly type ‘./build.sh’ and hit return.

You should now have a new package file in the compiled directory.

Bonus Tips

Use Full Paths

When writing scripts it is important to include the full path to any binaries used. You can easily find the full path of a binary with the ‘which’ command.

Check Your Packages

Sometimes I want to know what a package would do without running it. This is where the Finder QuickLook plug-in called ‘Suspicious Package’ comes in handy, as it shows where files would be copied and the contents of any preinstall and postinstall scripts. I also like to use Suspicious Package on my own package files to ensure files are being copied into the correct directory and any scripts are present.

Read The Manual

My example build.sh script does not take advantage of pkgbuild’s complete feature-set, for example packages can also be signed to prove authenticity. If you want to know more about pkgbuild simply read the man (manual) file, by typing ‘man pkgbuild’ into Terminal.

Comment