Packaging KEXTs and Software

PackageMaker is the preferred tool for packaging and distributing software consisting of multiple components. Unlike simple applications where every needed component is self–contained and embedded within the application’s bundle, more advanced software distributions, such as those containing KEXTs, may need to install components to multiple locations on the file system. For example, a driver will need to place itself within the /System/Library/Extensions directory, and it may further contain helper programs to load preferences or upgrade firmware, which require Launch Agents or Daemons to be installed. PackageMaker is able to do this and more. The PackageMaker user interface is shown in Figure 18-1.

images

Figure 18-1. PackageMaker user interface

PackageMaker’s output is a binary compressed package file with the extension “.pkg” that can be installed using the Installer.app program or the installer UNIX command, by executing something like the following:

sudo installer -pkg HelloWorld.pkg -target /

Installing using Installer.app brings up a GUI–based wizard that guides the user through the installation procedure. If the package has multiple optional sub-components, the user will have the opportunity to select or deselect them. The user can also change the target volume, where the package will be installed, provided that the package explicitly allows this, by setting the “Volume selected by user” option.

PackageMaker isn’t just limited to placing software components in the file system. It can also check for system requirements and pre-requisites, including whether the operating system version is supported, or check if some other software component it depends on is present. It can also trigger custom UNIX scripts before and after the software is installed for each component. For hardware drivers, PackageMaker also allows you to verify that your device is present before the user is allowed to continue. This works for FireWire, PCI, and USB.

images Tip When packaging KEXTs for distribution, ensure that Xcode builds for the architectures you intend to support. By using the file command on the KEXT’s binary, you can check which architectures it supports. You may also wish to ensure you are not distributing the debug version of your KEXT.

Building a Package for the Hello World Kernel Extension

Now, you can build a quick package for installing the sample Hello World KEXT. You will also need to install a Launch Daemon property lists file (Listing 18-1) and a shell script (Listing 18-2) that will be executed by the Launch Daemon, which will again load the KEXT. Before designing your own package, you will need to determine its components. For example, if you are distributing drivers for an audio device, you may wish to bundle the driver with some software that allows playback or capture of audio, and perhaps an SDK that other developers can use to write their own applications using the card. A developer may only want the driver, whereas an end–user may only want the bundled application and not the SDK, etc. In this scenario, you can create three sub-components: the driver, the application, and the SDK, and allow the user to select which components should be installed. For the HelloWorld package, you only need to add a single component.

To get started, open PackageMaker and chose “new” from the menu. You will then be prompted by a dialog, as shown in Figure 18-2.

images

Figure 18-2. Install Properties dialog

The “Organization” field should be the reverse–DNS name of your organization. The value is used to identify the package and uniquely name it. The minimum target drop–down allows you to select the oldest OS version you wish to target. The package will refuse to install on versions older than the install target. Once you have entered your selection, you can give your package a title.

Adding Contents to the Package

You can now start adding files to your package. This can be done by either choosing “Project images Add Contents . . .” from the main menu, or simply by dragging files into the left pane of PackageMaker. Figure 18-3 shows the content pane populated with the files required for the HelloWorld distribution.

images

Figure 18-3. The HelloWorld distribution

Our HelloWorld package consists of only three files (shown on the left in Figure 18-3): The KEXT itself and two helper files to allow the KEXT to load at boot–time. When you drag or add some files to the package, PackageMaker will automatically create a choice, which, in this case, we have named “Driver.” The choice represents a sub-component that can be individually selected by the user. However, if the “User Sees” field in the main pane is set to “Easy Install Only,” a user will not be prompted to select individual components, even though there may be more than one. The “Installation Destination” selection allows you to set the location where the package will be installed. At this point, we do not check any of the options, as all of our files go into absolute paths. If the “Volume selected by user” is selected, the instillation wizard will ask which volume (hard drive) the user wishes to install to. It is recommended to allow this choice to give the user more flexibility—particularly for large software packages, which a user may wish to store on a second, larger data drive.

Configuring the Package

Choosing the “Edit Interface” option from the configuration pane in Figure 18-3 will bring up a view of how the package will be presented when opened with Installer.app. PackageMaker allows you to interactively edit text and set a background image. You can also add localizations for enabling instructions in other languages.

The main pane has three tabs, as shown in Figure 18-3. The “Requirements” tab allows for the configuration of requirements that are global to the whole package. You can also set requirements for choices individually, which would allow a user to install some components even if the system didn’t meet the requirements for others. Requirements can be specified in the requirements editor, which has many pre-defined checks that can be configured. The following is a subset of available tests:

  • Megabytes Available on Target
  • Minimum CPU Frequency (HZ)
  • Memory Available (Bytes)
  • System OS Version /Target OS Version
  • File Exists on System
  • FireWire, USB, PCI Device Exists
  • Result of Script

The last option, “Result of Script,” is particularly useful when none of the pre-defined tests are suitable. You can write a shell script to perform your own tests and have the installer take action based on the return code of the script. You can also specify custom error messages that will appear if a requirements test fails. The “Actions” tab allows you to configure actions that can be performed automatically, either pre- or post-installation. For example, in the case of the HelloWorld package, we may wish to ensure that any previously installed HelloWorld.kext is unloaded before we install the new one. We can define this action as shown in Figure 18-4.

images

Figure 18-4. The action editor

In some cases, suppose you have a driver for a USB device: you may want to ensure that all applications using the device are killed before installing a new driver. An open application may prevent the driver from unloading properly. You may notice that there is no option for running a program or script; this can, however, be done on a per–file basis by selecting a file and choosing the “Scripts” tab.

images

Figure 18-5. Configuration pane for individual packages

For now, we have used the term Package to refer to the entire project as a whole, but in PackageMaker terminology, we are actually referring to a distribution that consists of several smaller packages. The smaller packages are made up of the individual files or objects added to the distributions, such as KEXTs, application bundles, or PDF files. Each object has meta-data and version information associated with it.

Figure 18-5 shows the main configuration pane for a package added to the distribution. The “Install” field specifies the source location, whereas the “Destination” field specifies the location in the file system where the object will be installed. Selecting the “Allow custom location” option allows the user to specify an alternative location. Both the source and destination location can be a relative or absolute path. In most cases, the former is recommended. In the preceding example (Figure 18-5), we have used a relative location for the source file and an absolute path in the file system for the destination, as the file must go into that directory and cannot be relocated based on the user’s preferences. The same will apply to the KEXT, which we require to be located in /System/Library/Extensions. A relative path is relative to the location of the PackageMaker project.

The “Patch” field allows you to specify an older version of the object you are installing, so that the installer can patch an existing file, rather than install a completely new file.

In the configuration pane, you can also specify a version number and identifier individually for each package. The “Restart Action” allows you to prompt users to restart their computers after the installation is complete. You may want to do this if you have Launch Agents or Daemons that must be started, or you have replaced a driver that is difficult reload (e.g., a storage or graphics driver) while the system is running. You can also require the user to logout or shutdown the system. The “Require admin authentication” checkbox will prompt the user for the administrator password before allowing the package to be installed. If you install files outside of the user’s home directory, usually, you must specify this, as the installer does not have admin rights by default. Most KEXTs, particularly drivers, must be installed under/System, which is not normally writable by a regular user.

Finally, the “Package Location” field allows one to specify an alternate location where the package object file will be installed from; for example, you can specify an HTTP URL.

The “Contents” tab of a package is shown in Figure 18-6.

images

Figure 18-6. Contents tab of the package configuration pane

The “Contents” tab allows you to examine individual files of a package. Usually, packages consist of either a bundle or an individual file. A bundle can contain other bundles or arbitrary files within it. If you need to exclude some files, you can specify regular expression patterns to do so. For instance, the meta-data directories from a source code versioning system, such as Subversion, can be excluded with the pattern “/.svn$”. You can also configure the file permissions the individual files should have once they are installed in the file system. The “Apply Recommendations” button will guess the correct permissions based on the file types and the intended destinations.

images Caution Kernel Extensions are picky about their permissions and must be owned by the root user and the wheel group. Additionally, the owner must have read, write and execute rights, whereas the group should have only read and execute rights. This corresponds to the UNIX permissions mask 0755. Meta data files (such as the Info.plist file) do not need to have the executable bit set.

The “Scripts” tab allows for the defining of pre- and post-installation scripts for a package. These can be used to perform custom installation steps that cannot be defined by the “Actions” editor. You may wish to use a pre-install script to shut down daemons or applications before they are replaced with new versions. You can also clean up files that are no longer needed by the newer versions. The scripts are typically written in Bash or another scripting language. If you remove older files from your scripts, be careful about using the “rm” command, as your package may run with administrative privileges, and an incorrectly specified filename may lead to the wrong files or directories being deleted. As an example, consider the following: rm –rf /System/Library/$MYKEXT. If the $MYKEXT variable ends up being empty, the command will instead delete the /System/Library directory. A very unhappy customer will follow.

Building the Package

Once you have finished adding and configuring all the parts you want included in the distribution, you can build it by pressing the “Build” or “Build and Run” on the toolbar. The latter will open the package in Installer.app once the building finishes. During the build phase, the package will be validated and checked; if there are errors or warnings, you can correct them and rebuild the package. The end result will look something like Figure 18-7.

images

Figure 18-7. Package as presented when launched with Installer.app

The resulting package will be written to the filename <Title>.pkg. The package is compressed and not a bundle, so the contents cannot readily be inspected in Finder. When you save a PackageMaker project, it will be saved as a bundle named <Title>.pmdoc. The project bundle contains XML files that define the project. You can edit these with a text editor or automatically replace or update contents with a script during your product’s build process. If you wish to build the package from the command line, you can do the following:


$ /Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker --doc
HelloWorld.pmdoc --version 2.0 --title 'HelloWorld'

The preceding command builds <Title>.pkg with a version number of 2.0.

Uninstalling Packages

Unfortunately, no mechanism exists for automatically uninstalling packages created with PackageMaker. To uninstall a package manually, you would need to identify the files installed by the package and delete them. You would also have to stop and remove any Launch Agents or Daemons installed by the package. A better option would be to provide your users with a script or program that performs the uninstall for them. PackageMaker are able to handle upgrades, however.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.14.136.168