Application Packaging Developer's Guide

Beyond Tradition

The approach described in this section does not apply to all packages, but it does result in improved performance during installation to an heterogeneous environment. Very little of this applies to packages that are delivered as part of the Solaris operating environment (bundled packages); however, unbundled packages can practice non-traditional packaging.

The reason behind encouraging relocatable packages is to support this requirement:

When a package is added or removed, the existing desirable behaviors of installed software products will be unchanged.

Unbundled packages should reside under /opt so as to assure that the new package does not interfere with existing products.

Another Look at Composite Packages

There are two rules to follow when constructing a functional composite package:

In other words, since "relocatable" means the object can be installed anywhere and still work, no startup script run by init at boot time can be considered relocatable! While there is nothing wrong with specifying /etc/passwd as a relative path in the delivered package, there is only one place it can go.

Making Absolute Path Names Look Relocatable

If you are going to construct a composite package, the absolute paths must operate in a manner which does not interfere with existing installed software. A package that can be entirely contained in /opt gets around this problem since there are no existing files in the way. When a file in /etc is included in the package, you must ensure that the absolute path names behave in the same way that is expected from relative path names. Consider the following two examples.

Example--Modifying a File

Description

An entry is being added to a table, or the object is a new table which is likely to be modified by other programs or packages.

Implementation

Define the object as file type e and belonging to the build, awk, or sed class. The script that performs this task must remove itself as effectively as it adds itself.

Example

An entry needs to be added to /etc/vfstab in support of the new solid state hard disk.

The entry in the pkgmap file might be


1 e sed /etc/vfstab ? ? ?

The request script asks the operator if /etc/vfstab should be modified by the package. If the operator answers "no" then the request script will print instructions on how to do the job manually and will execute


echo "CLASSES=none" >> $1

If the operator answers "yes" then it executes


echo "CLASSES=none sed" >> $1

which activates the class action script that will make the necessary modifications. The sed class means that the package file /etc/vfstab is a sed program which contains both the install and remove operations for the same-named file on the target system.

Example--Creating a New File

Description

The object is an entirely new file that is unlikely to be edited at a later time or, it is replacing a file owned by another package.

Implementation

Define the package object as file type f and install it using a class action script capable of undoing the change.

Example

A brand new file is required in /etc to provide the necessary information to support the solid state hard disk, named /etc/shdisk.conf. The entry in the pkgmap file might look like this:

.
.
.
1 f newetc /etc/shdisk.conf
.
.
.

The class action script i.newetc is responsible for installing this and any other files that need to go into /etc. It checks to make sure there is not another file there. If there is not, it will simply copy the new file into place. If there is already a file in place, it will back it up before installing the new file. The script r.newetc removes these files and restores the originals, if required. Here is the key fragment of the install script.

# i.newetc
while read src dst; do
	  if [ -f $dst ]; then
	    dstfile=`basename $dst`
	    cp $dst $PKGSAV/$dstfile
	  fi
	  cp $src $dst
done

if [ "${1}" = "ENDOFCLASS" ]; then
	  cd $PKGSAV
	  tar cf SAVE.newetc .
	  $INST_DATADIR/$PKG/install/squish SAVE.newetc
fi

Notice that this script uses the PKGSAV environment variable to store a backup of the file to be replaced. When the argument ENDOFCLASS is passed to the script, that is the pkgadd command informing the script that these are the last entries in this class, at which point the script archives and compresses the files that were saved using a private compression program stored in the install directory of the package.

While the use of the PKGSAV environment variable is not reliable during a package update; if the package is not updated (through a patch, for instance) the backup file is secure. The following remove script includes code to deal with the other issue--the fact that older versions of the pkgrm command do not pass the scripts the correct path to the PKGSAV environment variable.

The removal script might look like this.

# r.newetc

# make sure we have the correct PKGSAV
if [ -d $PKG_INSTALL_ROOT$PKGSAV ]; then
	  PKGSAV="$PKG_INSTALL_ROOT$PKGSAV"
fi

# find the unsquish program
UNSQUISH_CMD=`dirname $0`/unsquish

while read file; do
	  rm $file
done

if [ "${1}" = ENDOFCLASS ]; then
	  if [ -f $PKGSAV/SAVE.newetc.sq ]; then
	     $UNSQUISH_CMD $PKGSAV/SAVE.newetc
	  fi

	  if [ -f $PKGSAV/SAVE.newetc ]; then
	     targetdir=dirname $file	# get the right directory
	     cd $targetdir
		    tar xf $PKGSAV/SAVE.newetc
		    rm $PKGSAV/SAVE.newetc
	  fi
fi

This script uses a private uninstalled algorithm (unsquish) which is in the install directory of the package database. This is done automatically by the pkgadd command at install time. All scripts not specifically recognized as install-only by the pkgadd command are left in this directory for use by the pkgrm command. You cannot count on where that directory is, but you can depend on the directory being flat and containing all appropriate information files and installation scripts for the package. This script finds the directory by virtue of the fact that the class action script is guaranteed to be executing from the directory that contains the unsquish program.

Notice, also, that this script does not just assume the target directory is /etc. It may actually be /export/root/client2/etc. The correct directory could be constructed in one of two ways.

By using this approach for each absolute object in the package, you can be sure that the current desirable behavior is unchanged or at least recoverable.

Example--A Composite Package

This is an example of the pkginfo and pkgmap files for a composite package.

The pkginfo File

PKG=SUNWstuf
NAME=software stuff 
ARCH=sparc
VERSION=1.0.0,REV=1.0.4
CATEGORY=application
DESC=a set of utilities that do stuff
BASEDIR=/opt
VENDOR=Sun Microsystems, Inc.
HOTLINE=Please contact your local service provider
EMAIL=
MAXINST=1000
CLASSES=none daemon
PSTAMP=hubert980707141632

The pkgmap File

: 1 1758
1 d none SUNWstuf/EZstuf 0775 root bin
1 f none SUNWstuf/EZstuf/dirdel 0555 bin bin 40 773 751310229
1 f none SUNWstuf/EZstuf/usrdel 0555 bin bin 40 773 751310229
1 f none SUNWstuf/EZstuf/filedel 0555 bin bin 40 773 751310229
1 d none SUNWstuf/HRDstuf 0775 root bin
1 f none SUNWstuf/HRDstuf/mksmart 0555 bin bin 40 773 751310229
1 f none SUNWstuf/HRDstuf/mktall 0555 bin bin 40 773 751310229
1 f none SUNWstuf/HRDstuf/mkcute 0555 bin bin 40 773 751310229
1 f none SUNWstuf/HRDstuf/mkeasy 0555 bin bin 40 773 751310229
1 d none /etc	? ? ?
1 d none /etc/rc2.d ? ? ?
1 e daemon /etc/rc2.d/S70dostuf 0744 root sys 450 223443
1 i i.daemon 509 39560 752978103
1 i pkginfo 348 28411 760740163
1 i postinstall 323 26475 751309908
1 i postremove 402 33179 751309945
1 i preinstall 321 26254 751310019
1 i preremove 320 26114 751309865
1 i r.daemon 320 24573 742152591

While S70dostuf belongs to the daemon class, the directories that lead up to it (which are already in place at install time) belong to the none class. Even if the directories were unique to this package, you should leave them in the none class. The reason for this is that the directories need to be created first and deleted last, and this is always true for the none class. The pkgadd command creates directories; they are not copied from the package and they are not passed to a class action script to be created. Instead, they are created by the pkgadd command before it calls the install class action script, and the pkgrm command deletes directories after completion of the removal class action script.

This means that if a directory in a special class contains objects in the class none, when the pkgrm command attempts to remove the directory, it fails because the directory will not be empty in time. If an object of class none is to be inserted into a directory of some special class, that directory will not exist in time to accept the object. The pkgadd command will create the directory on-the-fly during installation of the object and may not be able to synchronize the attributes of that directory when it finally sees the pkgmap definition.


Note -

When assigning a directory to a class, always remember the order of creation and deletion.