JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
Packaging and Delivering Software With the Image Packaging System in Oracle Solaris 11.1     Oracle Solaris 11.1 Information Library
search filter icon
search icon

Document Information

Preface

1.  IPS Design Goals, Concepts, and Terminology

2.  Packaging Software With IPS

Designing a Package

Creating and Publishing a Package

Generate a Package Manifest

Add Necessary Metadata to the Generated Manifest

Evaluate Dependencies

Generate Package Dependencies

Resolve Package Dependencies

Add Any Facets or Actuators That Are Needed

Verify the Package

Publish the Package

Publish to a Local File Repository

Publish as a Package Archive

Using Package Repositories and Archives

Test the Package

Converting SVR4 Packages To IPS Packages

Generate an IPS Package Manifest from a SVR4 Package

Verify the Converted Package

Other Package Conversion Considerations

3.  Installing, Removing, and Updating Software Packages

4.  Specifying Package Dependencies

5.  Allowing Variations

6.  Modifying Package Manifests Programmatically

7.  Automating System Change as Part of Package Installation

8.  Advanced Topics For Package Updating

9.  Signing IPS Packages

10.  Handling Non-Global Zones

11.  Modifying Published Packages

A.  Classifying Packages

B.  How IPS Is Used To Package the Oracle Solaris OS

Creating and Publishing a Package

Packaging software with IPS is usually straightforward due to the amount of automation that is provided. Automation avoids repetitive tedium, which seems to be the principal cause of most packaging bugs.

Publication in IPS consists of the following steps:

  1. Generate a package manifest.

  2. Add necessary metadata to the generated manifest.

  3. Evaluate dependencies.

  4. Add any facets or actuators that are needed.

  5. Verify the package.

  6. Publish the package.

  7. Test the package.

Generate a Package Manifest

The easiest way to get started is to organize the component files into the same directory structure that you want on the installed system.

Two ways to do this are:

Suppose your software consists of a binary, a library, and a man page, and you want to install this software in a directory under /opt named mysoftware. Create a directory in your build area under which your software appears in this layout. In the following example, this directory is named proto:

proto/opt/mysoftware/lib/mylib.so.1
proto/opt/mysoftware/bin/mycmd
proto/opt/mysoftware/man/man1/mycmd.1

Use the pkgsend generate command to generate a manifest for this proto area. Pipe the output package manifest through pkgfmt to make the manifest more readable. See the pkgsend(1) and pkgfmt(1) man pages for more information.

In the following example, the proto directory is in the current working directory:

$ pkgsend generate proto | pkgfmt > mypkg.p5m.1

The output mypkg.p5m.1 file contains the following lines:

dir  path=opt owner=root group=bin mode=0755
dir  path=opt/mysoftware owner=root group=bin mode=0755
dir  path=opt/mysoftware/bin owner=root group=bin mode=0755
file opt/mysoftware/bin/mycmd path=opt/mysoftware/bin/mycmd owner=root \
    group=bin mode=0644
dir  path=opt/mysoftware/lib owner=root group=bin mode=0755
file opt/mysoftware/lib/mylib.so.1 path=opt/mysoftware/lib/mylib.so.1 \
    owner=root group=bin mode=0644
dir  path=opt/mysoftware/man owner=root group=bin mode=0755
dir  path=opt/mysoftware/man/man1 owner=root group=bin mode=0755
file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \
    owner=root group=bin mode=0644

The path of the files to be packaged appears twice in the file action:

This double entry enables you to modify the installation location without modifying the proto area. This capability can save significant time, for example if you repackage software that was designed for installation on a different operating system.

Notice that pkgsend generate has applied default values for directory owners and groups. In the case of /opt, the defaults are not correct. Delete that directory because it is delivered by other packages already on the system, and pkg(1) will not install the package if the attributes of /opt conflict with those already on the system. Add Necessary Metadata to the Generated Manifest below shows a programmatic way to delete the unwanted directory.

If a file name contains an equal symbol (=), double quotation mark ("), or space character, pkgsend generates a hash attribute in the manifest, as shown in the following example:

$ mkdir -p proto/opt
$ touch proto/opt/my\ file1
$ touch proto/opt/"my file2"
$ touch proto/opt/my=file3
$ touch proto/opt/'my"file4'
$ pkgsend generate proto
dir group=bin mode=0755 owner=root path=opt
file group=bin hash=opt/my=file3 mode=0644 owner=root path=opt/my=file3
file group=bin hash="opt/my file2" mode=0644 owner=root path="opt/my file2"
file group=bin hash='opt/my"file4' mode=0644 owner=root path='opt/my"file4'
file group=bin hash="opt/my file1" mode=0644 owner=root path="opt/my file1"

When the package is published (see Publish the Package), the value of the hash attribute becomes the SHA-1 hash of the file contents, as noted in File Actions.

Add Necessary Metadata to the Generated Manifest

A package should define the following metadata. See Set Actions for more information about these values and how to set these values.

pkg.fmri

The name and version of the package as described in Package Identifier: FMRI. A description of Oracle Solaris versioning can be found in Oracle Solaris Package Versioning.

pkg.description

A description of the contents of the package

pkg.summary

A one-line synopsis of the description.

variant.arch

Each architectures for which this package is suitable. If the entire package can be installed on any architecture, variant.arch can be omitted. Producing packages that have different components for different architectures is discussed in Chapter 5, Allowing Variations.

info.classification

A grouping scheme used by the packagemanager(1) GUI. The supported values are shown in Appendix A, Classifying Packages. The example in this section specifies an arbitrary classification.

This example also adds a link action to /usr/share/man/index.d that points to the man directory under mysoftware. This link is discussed further in Add Any Facets or Actuators That Are Needed.

Rather than modifying the generated manifest directly, use pkgmogrify(1) to edit the generated manifest. See Chapter 6, Modifying Package Manifests Programmatically for a full description of using pkgmogrify to modify package manifests.

Create the following pkgmogrify input file to specify the changes to be made to the manifest. Name this file mypkg.mog. In this example, a macro is used to define the architecture, and regular expression matching is used to delete the /opt directory from the manifest.

set name=pkg.fmri value=mypkg@1.0,5.11-0
set name=pkg.summary value="This is an example package"
set name=pkg.description value="This is a full description of \
all the interesting attributes of this example package."
set name=variant.arch value=$(ARCH)
set name=info.classification \
    value=org.opensolaris.category.2008:Applications/Accessories
link path=usr/share/man/index.d/mysoftware target=opt/mysoftware/man
<transform dir path=opt$->drop>

Run pkgmogrify on the mypkg.p5m.1 manifest with the mypkg.mog changes:

$ pkgmogrify -DARCH=`uname -p` mypkg.p5m.1 mypkg.mog | pkgfmt > mypkg.p5m.2

The output mypkg.p5m.2 file has the following content. The dir action for path=opt has been removed, and the metadata and link contents from mypkg.mog have been added to the original mypkg.p5m.1 contents.

set name=pkg.fmri value=mypkg@1.0,5.11-0
set name=pkg.summary value="This is an example package"
set name=pkg.description \
    value="This is a full description of all the interesting attributes of this example package."
set name=info.classification \
    value=org.opensolaris.category.2008:Applications/Accessories
set name=variant.arch value=i386
dir  path=opt/mysoftware owner=root group=bin mode=0755
dir  path=opt/mysoftware/bin owner=root group=bin mode=0755
file opt/mysoftware/bin/mycmd path=opt/mysoftware/bin/mycmd owner=root \
    group=bin mode=0644
dir  path=opt/mysoftware/lib owner=root group=bin mode=0755
file opt/mysoftware/lib/mylib.so.1 path=opt/mysoftware/lib/mylib.so.1 \
    owner=root group=bin mode=0644
dir  path=opt/mysoftware/man owner=root group=bin mode=0755
dir  path=opt/mysoftware/man/man1 owner=root group=bin mode=0755
file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \
    owner=root group=bin mode=0644
link path=usr/share/man/index.d/mysoftware target=opt/mysoftware/man

Evaluate Dependencies

Use the pkgdepend(1) command to automatically generate dependencies for the package. The generated depend actions are defined in Depend Actions and discussed further in Chapter 4, Specifying Package Dependencies.

Dependency generation is composed of two separate steps:

  1. Dependency generation. Determine the files on which the software depends. Use the pkgdepend generate command.

  2. Dependency resolution. Determine the packages that contain those files on which the software depends. Use the pkgdepend resolve command.

Generate Package Dependencies

In the following command, the -m option causes pkgdepend to include the entire manifest in its output. The -d option passes the proto directory to the command.

$ pkgdepend generate -md proto mypkg.p5m.2 | pkgfmt > mypkg.p5m.3

The output mypkg.p5m.3 file has the following content. The pkgdepend utility added notations about a dependency on libc.so.1 by both mylib.so.1 and mycmd. The internal dependency between mycmd and mylib.so.1 is silently omitted.

set name=pkg.fmri value=mypkg@1.0,5.11-0
set name=pkg.summary value="This is an example package"
set name=pkg.description \
    value="This is a full description of all the interesting attributes of this example package."
set name=info.classification \
    value=org.opensolaris.category.2008:Applications/Accessories
set name=variant.arch value=i386
dir  path=opt/mysoftware owner=root group=bin mode=0755
dir  path=opt/mysoftware/bin owner=root group=bin mode=0755
file opt/mysoftware/bin/mycmd path=opt/mysoftware/bin/mycmd owner=root \
    group=bin mode=0644
dir  path=opt/mysoftware/lib owner=root group=bin mode=0755
file opt/mysoftware/lib/mylib.so.1 path=opt/mysoftware/lib/mylib.so.1 \
    owner=root group=bin mode=0644
dir  path=opt/mysoftware/man owner=root group=bin mode=0755
dir  path=opt/mysoftware/man/man1 owner=root group=bin mode=0755
file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \
    owner=root group=bin mode=0644
link path=usr/share/man/index.d/mysoftware target=opt/mysoftware/man
depend fmri=__TBD pkg.debug.depend.file=libc.so.1 \
    pkg.debug.depend.reason=opt/mysoftware/bin/mycmd \
    pkg.debug.depend.type=elf type=require pkg.debug.depend.path=lib \
    pkg.debug.depend.path=opt/mysoftware/lib pkg.debug.depend.path=usr/lib
depend fmri=__TBD pkg.debug.depend.file=libc.so.1 \
    pkg.debug.depend.reason=opt/mysoftware/lib/mylib.so.1 \
    pkg.debug.depend.type=elf type=require pkg.debug.depend.path=lib \
    pkg.debug.depend.path=usr/lib

Resolve Package Dependencies

To resolve dependencies, pkgdepend examines the packages currently installed in the image used for building the software. By default, pkgdepend puts its output in mypkg.p5m.3.res. This step takes a while to run since it loads a large amount of information about the system on which it is running. The pkgdepend utility can resolve many packages at once if you want to amortize this time over all packages. Running pkgdepend on one package at a time is not time efficient.

$ pkgdepend resolve -m mypkg.p5m.3

When this completes, the output mypkg.p5m.3.res file contains the following content. The pkgdepend utility has converted the notation about the file dependency on libc.so.1 to a package dependency on pkg:/system/library, which delivers that file.

set name=pkg.fmri value=mypkg@1.0,5.11-0
set name=pkg.summary value="This is an example package"
set name=pkg.description \
    value="This is a full description of all the interesting attributes of this example package."
set name=info.classification \
    value=org.opensolaris.category.2008:Applications/Accessories
set name=variant.arch value=i386
dir  path=opt/mysoftware owner=root group=bin mode=0755
dir  path=opt/mysoftware/bin owner=root group=bin mode=0755
file opt/mysoftware/bin/mycmd path=opt/mysoftware/bin/mycmd owner=root \
    group=bin mode=0644
dir  path=opt/mysoftware/lib owner=root group=bin mode=0755
file opt/mysoftware/lib/mylib.so.1 path=opt/mysoftware/lib/mylib.so.1 \
    owner=root group=bin mode=0644
dir  path=opt/mysoftware/man owner=root group=bin mode=0755
dir  path=opt/mysoftware/man/man1 owner=root group=bin mode=0755
file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \
    owner=root group=bin mode=0644
link path=usr/share/man/index.d/mysoftware target=opt/mysoftware/man
depend fmri=pkg:/system/library@0.5.11-0.175.1.0.0.21.0 type=require

You should use pkgdepend to generate dependencies, rather than declaring depend actions manually. Manual dependencies can become incorrect or unnecessary as the package contents change over time. For example, when a file that an application depends on gets moved to a different package, any manually declared dependencies on the previous package would then be incorrect for that dependency.

Some manually declared dependencies might be necessary if pkgdepend is unable to determine dependencies completely. In such a case, you should add explanatory comments to the manifest.

Add Any Facets or Actuators That Are Needed

Facets and actuators are discussed in more detail in Chapter 5, Allowing Variations and Chapter 7, Automating System Change as Part of Package Installation. A facet denotes an action that is not required but can be optionally installed. An actuator specifies system changes that must occur when the associated action is installed, updated, or removed

This example package delivers a man page in opt/mysoftware/man/man1. This section shows how to add a facet to indicate that man pages are optional. The user could choose to install all of the package except the man page. (If the user sets the facet to false, no man pages are installed from any package if their file actions are tagged with that facet.)

To include the man page in the index, the svc:/application/man-index:default SMF service must be restarted when the package is installed. This section shows how to add the restart_fmri actuator to perform that task. The man-index service looks in /usr/share/man/index.d for symbolic links to directories that contain man pages, adding the target of each link to the list of directories it scans. To include the man page in the index, this example package includes a link from /usr/share/man/index.d/mysoftware to /opt/mysoftware/man. Including this link and this actuator is a good example of the self-assembly discussed in Software Self-Assembly and used throughout the packaging of the Oracle Solaris OS.

A set of pkgmogrify transforms that you can use are available in /usr/share/pkg/transforms. These transforms are used to package the Oracle Solaris OS, and are discussed in more detail in Chapter 6, Modifying Package Manifests Programmatically.

The file /usr/share/pkg/transforms/documentation contains transforms similar to the transforms needed in this example to set the man page facet and restart the man-index service. Since this example delivers the man page to /opt, the documentation transforms must be modified as shown below. These modified transforms include the regular expression opt/.+/man(/.+)? which matches all paths beneath opt that contain a man subdirectory. Save the following modified transforms to /tmp/doc-transform:

<transform dir file link hardlink path=opt/.+/man(/.+)? -> \
    default facet.doc.man true>
<transform file path=opt/.+/man(/.+)? -> \
    add restart_fmri svc:/application/man-index:default>

Use the following command to apply these transforms to the manifest:

$ pkgmogrify mypkg.p5m.3.res /tmp/doc-transform | pkgfmt > mypkg.p5m.4.res

The input mypkg.p5m.3.res manifest contains the following three man-page-related actions:

dir  path=opt/mysoftware/man owner=root group=bin mode=0755
dir  path=opt/mysoftware/man/man1 owner=root group=bin mode=0755
file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \
    owner=root group=bin mode=0644

After the transforms are applied, the output mypkg.p5m.4.res manifest contains the following modified actions:

dir  path=opt/mysoftware/man owner=root group=bin mode=0755 facet.doc.man=true
dir  path=opt/mysoftware/man/man1 owner=root group=bin mode=0755 \
    facet.doc.man=true
file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \
    owner=root group=bin mode=0644 \
    restart_fmri=svc:/application/man-index:default facet.doc.man=true

For efficiency, these transforms could have been added when metadata was originally added, before evaluating dependencies.

Verify the Package

The last step before publication is to run pkglint(1) on the manifest to find errors that can be identified before publication and testing. Some of the errors that pkglint can find would also be found either at publication time or when a user attempts to install the package, but of course you want to identify errors as early as possible in the package authoring process.

Examples of errors that pkglint reports include:

You can run pkglint in one of the following modes:

Use the pkglint -L command to show the full list of checks that pkglint performs. Detailed information about how to enable, disable, and bypass particular checks is given in the pkglint(1) man page. The man page also details how to extend pkglint to run additional checks.

The following output shows problems with the example manifest:

$ pkglint mypkg.p5m.4.res
Lint engine setup...
Starting lint run...
WARNING pkglint.action005.1       obsolete dependency check skipped: unable
to find dependency pkg:/system/library@0.5.11-0.175.1.0.0.21.0 for
pkg:/mypkg@1.0,5.11-0

This warning is acceptable for this example. The pkglint.action005.1 warning says that pkglint could not find a package called pkg:/system/library@0.5.11-0.175.1.0.0.21.0, on which this example package depends. The dependency package is in a package repository and could not be found since pkglint was called with only the manifest file as an argument.

In the following command, the -r option references a repository that contains the dependency package. The -c option specifies a local directory used for caching package metadata from the lint and reference repositories:

$ pkglint -c ./solaris-reference -r http://pkg.oracle.com/solaris/release mypkg.p5m.4.res

Publish the Package

IPS provides three different ways to deliver a package:

Generally, publishing to a file-based repository is sufficient to test a package.

If the package must be transferred to other machines that cannot access the package repositories, converting one or more packages to a package archive can be convenient.

The package can also be published directly to an HTTP repository, hosted on a machine with a read/write instance of the svc:/application/pkg/server service, which in turn runs pkg.depotd(1M).

Publishing to an HTTP repository is not generally recommended since there are no authorization or authentication checks on the incoming package when publishing over HTTP. Publishing to HTTP repositories can be convenient on secure networks or when testing the same package across several machines if NFS or SMB access to the file repository is not possible.

Installing packages over HTTP or HTTPS is fine.

Publish to a Local File Repository

Use the pkgrepo(1) command to create and manage repositories. Choose a location on your system, create a repository, then set the default publisher for that repository:

$ pkgrepo create my-repository
$ pkgrepo -s my-repository set publisher/prefix=mypublisher
$ ls my-repository
pkg5.repository

Use the pkgsend(1) command to publish the example package, and then use pkgrepo to examine the repository:

$ pkgsend -s my-repository publish -d proto mypkg.p5m.4.res
pkg://mypublisher/mypkg@1.0,5.11-0:20120331T034425Z
PUBLISHED
$ pkgrepo -s my-repository info
PUBLISHER   PACKAGES STATUS           UPDATED
mypublisher 1        online           2012-03-31T03:44:25.235964Z

The file repository can then be served over HTTP or HTTPS using pkg.depotd if required.

Publish as a Package Archive

Package archives enable you to distribute groups of packages in a single file. Use the pkgrecv(1) command to create package archives from package repositories, or to create package repositories from package archives.

Package archives can be easily downloaded from an existing web site, copied to a USB key, or burned to a DVD for installation in cases where a package repository is not available.

The following command creates a package archive from the simple repository created in the previous section:

$ pkgrecv -s my-repository -a -d myarchive.p5p mypkg
Retrieving packages for publisher mypublisher ...
Retrieving and evaluating 1 package(s)...
DOWNLOAD                                  PKGS       FILES   XFER (MB)   SPEED
Completed                                  1/1         3/3     0.7/0.7 17.9k/s

ARCHIVE                                              FILES   STORE (MB)
myarchive.p5p                                        14/14      0.7/0.7

Using Package Repositories and Archives

Use the pkgrepo command to list the newest available packages from a repository or archive:

$ pkgrepo -s my-repository list '*@latest'
PUBLISHER   NAME                                          O VERSION
mypublisher mypkg                                           1.0,5.11-0:20120331T034425Z
$ pkgrepo -s myarchive.p5p list '*@latest'
PUBLISHER   NAME                                          O VERSION
mypublisher mypkg                                           1.0,5.11-0:20120331T034425Z

This output can be useful for constructing scripts to create archives with the latest versions of all packages from a given repository.

Temporary repositories or package archives can be provided to pkg install and other pkg operations by using the -g option. Such temporary repositories and archives cannot be used on systems with child or parent images (for example, systems with non-global zones) since the system repository does not get temporarily configured with that publisher information. Non-global zones have a child/parent relationship with the global zone. Package archives can be set as sources of local publishers in non-global zones, however.

Test the Package

The final step in package development is to test whether the published package has been packaged properly.

To test installation without requiring root privilege, assign the test user the Software Installation profile. Use the -P option of the usermod command to assign the test user the Software Installation profile.


Note - If this image has child images (non-global zones) installed, you cannot use the -g option with the pkg install command to test installation of this package. You must configure the my-repository repository in the image.


Add the publisher in the my-repository repository to the configured publishers in this image:

$ pfexec pkg set-publisher -p my-repository
pkg set-publisher:
  Added publisher(s): mypublisher

You can use the pkg install -nv command to see what the install command will do without making any changes. The following command actually installs the package:

$ pfexec pkg install mypkg
           Packages to install:  1 
       Create boot environment: No
Create backup boot environment: No
            Services to change:  1

DOWNLOAD                                  PKGS       FILES   XFER (MB)   SPEED
Completed                                  1/1         3/3     0.0/0.0    0B/s

PHASE                                          ITEMS
Installing new actions                         15/15
Updating package state database                 Done
Updating image state                            Done
Creating fast lookup database                   Done
Reading search index                            Done
Updating search index                            1/1

Examine the software that was delivered on the system:

$ find /opt/mysoftware/
/opt/mysoftware/
/opt/mysoftware/bin
/opt/mysoftware/bin/mycmd
/opt/mysoftware/lib
/opt/mysoftware/lib/mylib.so.1
/opt/mysoftware/man
/opt/mysoftware/man/man-index
/opt/mysoftware/man/man-index/term.doc
/opt/mysoftware/man/man-index/.index-cache
/opt/mysoftware/man/man-index/term.dic
/opt/mysoftware/man/man-index/term.req
/opt/mysoftware/man/man-index/term.pos
/opt/mysoftware/man/man1
/opt/mysoftware/man/man1/mycmd.1

In addition to the binaries and man page, the system has also generated the man page indexes as a result of the actuator restarting the man-index service.

The pkg info command shows the metadata that was added to the package:

$ pkg info mypkg
          Name: mypkg
       Summary: This is an example package
   Description: This is a full description of all the interesting attributes of
                this example package.
      Category: Applications/Accessories
         State: Installed
     Publisher: mypublisher
       Version: 1.0
 Build Release: 5.11
        Branch: 0
Packaging Date: March 31, 2012 03:44:25 AM 
          Size: 0.00 B
          FMRI: pkg://mypublisher/mypkg@1.0,5.11-0:20120331T034425Z

The pkg search command returns hits when querying for files that are delivered by mypkg:

$ pkg search -l mycmd.1
INDEX      ACTION VALUE                           PACKAGE
basename   file   opt/mysoftware/man/man1/mycmd.1 pkg:/mypkg@1.0-0