Application Packaging Developer's Guide

Chapter 5 Case Studies of Package Creation

This chapter provides case studies to show packaging scenarios such as installing objects conditionally, determining at run time how many files to create, and modifying an existing data file during package installation and removal.

Each case study begins with a description, followed by a list of the packaging techniques used, a narrative description of the approach taken when using those techniques, and sample files and scripts associated with the case study.

This is a list of the case studies in this chapter:

Soliciting Input From the Administrator

The package in this case study has three types of objects. The administrator may choose which of the three types to install and where to locate the objects on the installation machine.

Techniques

This case study demonstrates the following techniques:

Approach

To set up the selective installation in this case study, you must complete the following tasks:

Case Study Files

The pkginfo File

PKG=ncmp
NAME=NCMP Utilities
CATEGORY=application, tools
BASEDIR=/
ARCH=SPARC
VERSION=RELEASE 1.0, Issue 1.0
CLASSES=""
NCMPBIN=/bin
NCMPMAN=/usr/man
EMACS=/usr/emacs

The prototype File

i pkginfo
i request
x bin $NCMPBIN 0755 root other
f bin $NCMPBIN/dired=/usr/ncmp/bin/dired 0755 root other
f bin $NCMPBIN/less=/usr/ncmp/bin/less 0755 root other
f bin $NCMPBIN/ttype=/usr/ncmp/bin/ttype 0755 root other
f emacs $NCMPBIN/emacs=/usr/ncmp/bin/emacs 0755 root other
x emacs $EMACS 0755 root other
f emacs $EMACS/ansii=/usr/ncmp/lib/emacs/macros/ansii 0644 root other
f emacs $EMACS/box=/usr/ncmp/lib/emacs/macros/box 0644 root other
f emacs $EMACS/crypt=/usr/ncmp/lib/emacs/macros/crypt 0644 root other
f emacs $EMACS/draw=/usr/ncmp/lib/emacs/macros/draw 0644 root other
f emacs $EMACS/mail=/usr/ncmp/lib/emacs/macros/mail 0644 root other
f emacs $NCMPMAN/man1/emacs.1=/usr/ncmp/man/man1/emacs.1 0644 root other
d man $NCMPMAN 0755 root other
d man $NCMPMAN/man1 0755 root other
f man $NCMPMAN/man1/dired.1=/usr/ncmp/man/man1/dired.1 0644 root other
f man $NCMPMAN/man1/ttype.1=/usr/ncmp/man/man1/ttype.1 0644 root other
f man $NCMPMAN/man1/less.1=/usr/ncmp/man/man1/less.1 0644 inixmr other

The request Script

trap 'exit 3' 15
# determine if and where general executables should be placed
ans=`ckyorn -d y \
-p "Should executables included in this package be installed"
` || exit $?
if [ "$ans" = y ]
then
   CLASSES="$CLASSES bin"
   NCMPBIN=`ckpath -d /usr/ncmp/bin -aoy \
   -p "Where should executables be installed"
   ` || exit $?
fi
# determine if emacs editor should be installed, and if it should
# where should the associated macros be placed
ans=`ckyorn -d y \
-p "Should emacs editor included in this package be installed"
` || exit $?
if [ "$ans" = y ]
then
   CLASSES="$CLASSES emacs"
   EMACS=`ckpath -d /usr/ncmp/lib/emacs -aoy \
   -p "Where should emacs macros be installed"
   ` || exit $?
fi

Note that a request script can exit without leaving any files on the file system. For installations on Solaris versions prior to 2.5 and compatible versions (where no checkinstall script may be used) the request script is the correct place to test the file system in any manner necessary to ensure that the installation will succeed. When the request script exits with code 1, the installation will quit cleanly.

These example files show the use of parametric paths to establish multiple base directories. However, the preferred method involves use of the BASEDIR parameter which is managed and validated by the pkgadd command. Whenever multiple base directories are used, take special care to provide for installation of multiple versions and architectures on the same platform.

Creating a File at Installation and Saving It During Removal

This case study creates a database file at installation time and saves a copy of the database when the package is removed.

Techniques

This case study demonstrates the following techniques:

Approach

To create a database file at installation and save a copy on removal for this case study, you must complete the following tasks:

Case Study Files

The pkginfo File

PKG=krazy
NAME=KrAzY Applications
CATEGORY=applications
BASEDIR=/opt
ARCH=SPARC
VERSION=Version 1
CLASSES=none cfgdata admin

The prototype File

i pkginfo
i request
i i.admin
i r.cfgdata
d none bin 555 root sys
f none bin/process1 555 root other
f none bin/process2 555 root other
f none bin/process3 555 root other
f admin bin/config 500 root sys
d admin cfg 555 root sys
f admin cfg/datafile1 444 root sys
f admin cfg/datafile2 444 root sys
f admin cfg/datafile3 444 root sys
f admin cfg/datafile4 444 root sys
d cfgdata data 555 root sys

The space File

# extra space required by config data which is
# dynamically loaded onto the system
data 500 1

The i.admin Class Action Script

# PKGINST parameter provided by installation service
# BASEDIR parameter provided by installation service
while read src dest
do
   cp $src $dest || exit 2
done
# if this is the last time this script will be executed
# during the installation, do additional processing here.
if [ "$1" = ENDOFCLASS ]
then
# our config process will create a data file based on any changes
# made by installing files in this class; make sure the data file
# is in class `cfgdata' so special rules can apply to it during
# package removal.
   installf -c cfgdata $PKGINST $BASEDIR/data/config.data f 444 root
   sys || exit 2
   $BASEDIR/bin/config > $BASEDIR/data/config.data || exit 2
   installf -f -c cfgdata $PKGINST || exit 2
fi
exit 0

This illustrates a rare instance in which installf is appropriate in a class action script. Because a space file has been used to reserve room on a specific file system, this new file may be safely added even though it is not included in the pkgmap file.

The r.cfgdata Removal Script

# the product manager for this package has suggested that
# the configuration data is so valuable that it should be
# backed up to $PKGSAV before it is removed!
while read path
do
# path names appear in reverse lexical order.
   mv $path $PKGSAV || exit 2
   rm -f $path || exit 2
done
exit 0

Defining Package Compatibilities and Dependencies

The package in this case study uses optional information files to define package compatibilities and dependencies, and to present a copyright message during installation.

Techniques

This case study demonstrates the following techniques:

For more information on these files, see Creating Information Files.

Approach

To meet the requirements in the description, you must:

Case Study Files

The pkginfo File

PKG=case3
NAME=Case Study #3
CATEGORY=application
BASEDIR=/opt
ARCH=SPARC
VERSION=Version 3.0
CLASSES=none

The copyright File

Copyright (c) 1999 company_name
All Rights Reserved.
THIS PACKAGE CONTAINS UNPUBLISHED PROPRIETARY SOURCE CODE OF
company_name.
The copyright notice above does not evidence any
actual or intended publication of such source code

The compver File

Version 3.0
Version 2.3
Version 2.2
Version 2.1
Version 2.1.1
Version 2.1.3
Version 1.7

The depend File

P acu Advanced C Utilities
Issue 4 Version 1
P cc C Programming Language
Issue 4 Version 1
P dfm Directory and File Management Utilities
P ed Editing Utilities
P esg Extended Software Generation Utilities
Issue 4 Version 1
P graph Graphics Utilities
P rfs Remote File Sharing Utilities
Issue 1 Version 1
P rx Remote Execution Utilities
P sgs Software Generation Utilities
Issue 4 Version 1
P shell Shell Programming Utilities
P sys System Header Files
Release 3.1

Modifying a File by Using Standard Classes and Class Action Scripts

This case study modifies an existing file during package installation using standard classes and class action scripts. It uses one of three modification methods. The other two methods are described in Modifying a File by Using the sed Class and a postinstall Script and Modifying a File by Using The build Class. The file modified is /etc/inittab.

Techniques

This case study demonstrates how to use installation and removal class action scripts. For more information, see Writing Class Action Scripts.

Approach

To modify /etc/inittab during installation, using classes and class action scripts, you must complete the following tasks:

This case study is more complicated than the next one; see Modifying a File by Using the sed Class and a postinstall Script. Instead of providing two files, three are needed and the delivered /etc/inittab file is actually just a place holder containing a fragment of the entry to be inserted. This could have been placed into the i.inittab file except that the pkgadd command must have a file to pass to the i.inittab file. Also, the removal procedure must be placed into a separate file (r.inittab). While this method works fine, it is best reserved for cases involving very complicated installations of multiple files. See Modifying crontab Files During Installation.

The sed program used in Modifying a File by Using the sed Class and a postinstall Script supports multiple package instances since the comment at the end of the inittab entry is based on package instance. The case study in Modifying a File by Using The build Class shows a more streamlined approach to editing /etc/inittab during installation.

Case Study Files

The pkginfo File

PKG=case5
NAME=Case Study #5
CATEGORY=applications
BASEDIR=/opt
ARCH=SPARC
VERSION=Version 1d05
CLASSES=inittab

The prototype File

i pkginfo
i i.inittab
i r.inittab
e inittab /etc/inittab ? ? ?

The i.inittab Installation Class Action Script

# PKGINST parameter provided by installation service
while read src dest
do
# remove all entries from the table that
# associated with this PKGINST
sed -e "/^[^:]*:[^:]*:[^:]*:[^#]*#$PKGINST$/d" $dest >
/tmp/$$itab ||
exit 2
sed -e "s/$/#$PKGINST" $src >> /tmp/$$itab ||
exit 2
mv /tmp/$$itab $dest ||
exit 2
done
if [ "$1" = ENDOFCLASS ]
then
/sbin/init q ||
exit 2
fi
exit 0

The r.inittab Removal Class Action Script

# PKGINST parameter provided by installation service
while read src dest
do
# remove all entries from the table that
# are associated with this PKGINST
sed -e "/^[^:]*:[^:]*:[^:]*:[^#]*#$PKGINST$/d" $dest >
/tmp/$$itab ||
exit 2
mv /tmp/$$itab $dest ||
exit 2
done
/sbin/init q ||
exit 2
exit 0

The inittab File

rb:023456:wait:/usr/robot/bin/setup

Modifying a File by Using the sed Class and a postinstall Script

This case study modifies a file which exists on the installation machine during package installation. It uses one of three modification methods. The other two methods are described in Modifying a File by Using Standard Classes and Class Action Scripts and Modifying a File by Using The build Class. The file modified is /etc/inittab.

Techniques

This case study demonstrates the following techniques:

Approach

To modify /etc/inittab at the time of installation, using the sed class, you must complete the following tasks:

This approach to editing /etc/inittab during installation has one drawback; you have to deliver a full script (the postinstall script) simply to perform the init q command.

Case Study Files

The pkginfo File

PKG=case4
NAME=Case Study #4
CATEGORY=applications
BASEDIR=/opt
ARCH=SPARC
VERSION=Version 1d05
CLASSES=sed

The prototype File

i pkginfo
i postinstall
e sed /etc/inittab ? ? ?

The sed Class Action Script (/etc/inittab)

!remove
# remove all entries from the table that are associated
# with this package, though not necessarily just
# with this package instance
/^[^:]*:[^:]*:[^:]*:[^#]*#ROBOT$/d
!install
# remove any previous entry added to the table
# for this particular change
/^[^:]*:[^:]*:[^:]*:[^#]*#ROBOT$/d
# add the needed entry at the end of the table;
# sed(1) does not properly interpret the '$a'
# construct if you previously deleted the last
# line, so the command
# $a\
# rb:023456:wait:/usr/robot/bin/setup #ROBOT
# will not work here if the file already contained
# the modification. Instead, you will settle for
# inserting the entry before the last line!
$i\
rb:023456:wait:/usr/robot/bin/setup #ROBOT

The postinstall Script

# make init re-read inittab
/sbin/init q ||
exit 2
exit 0

Modifying a File by Using The build Class

This case study modifies a file which exists on the installation machine during package installation. It uses one of three modification methods. The other two methods are described in Modifying a File by Using Standard Classes and Class Action Scripts and Modifying a File by Using the sed Class and a postinstall Script. The file modified is /etc/inittab.

Techniques

This case study demonstrates how to use the build class. For more information on the build class, see The build Class Script.

Approach

This approach to modifying /etc/inittab uses the build class. A build class script is executed as a shell script and its output becomes the new version of the file being executed. In other words, the data file /etc/inittab that is delivered with this package will be executed and the output of that execution will become /etc/inittab.

The build class script is executed during package installation and package removal. The argument install is passed to the file if it is being executed at installation time. Notice in the sample build class script that installation actions are defined by testing for this argument.

To edit /etc/inittab using the build class, you must complete the following tasks:

This solution addresses the drawbacks described in the case studies in Modifying a File by Using Standard Classes and Class Action Scripts and Modifying a File by Using the sed Class and a postinstall Script. Only one short file is needed (beyond the pkginfo and prototype files). The file works with multiple instances of a package since the PKGINST parameter is used, and no postinstall script is required since the init q command can be executed from the build class script.

Case Study Files

The pkginfo File

PKG=case6
NAME=Case Study #6
CATEGORY=applications
BASEDIR=/opt
ARCH=SPARC
VERSION=Version 1d05
CLASSES=build

The prototype File

i pkginfo
e build /etc/inittab ? ? ?

The Build File

# PKGINST parameter provided by installation service
# remove all entries from the existing table that
# are associated with this PKGINST
sed -e "/^[^:]*:[^:]*:[^:]*:[^#]*#$PKGINST$/d" /etc/inittab ||
exit 2
if [ "$1" = install ]
then
# add the following entry to the table
echo "rb:023456:wait:/usr/robot/bin/setup #$PKGINST" ||
exit 2
fi
/sbin/init q ||
exit 2
exit 0

Modifying crontab Files During Installation

This case study modifies crontab files during package installation.

Techniques

This case study demonstrates the following techniques:

Approach

The most efficient way to edit more than one file during installation is to define a class and provide a class action script. If you used the build class approach, you would need to deliver one build class script for each crontab file edited. Defining a cron class provides a more general approach. To edit crontab files with this approach, you must:

Case Study Files

The i.cron and r.cron scripts described below are executed by superuser. Editing another user's crontab file as superuser may have unpredictable results. If necessary, change the following entry in each script:

crontab $user < /tmp/$$crontab ||

to

su $user -c "crontab /tmp/$$crontab" ||

The pkginfo Command

PKG=case7
NAME=Case Study #7
CATEGORY=application
BASEDIR=/opt
ARCH=SPARC
VERSION=Version 1.0
CLASSES=cron

The prototype File

i pkginfo
i i.cron
i r.cron
e cron /var/spool/cron/crontabs/root ? ? ?
e cron /var/spool/cron/crontabs/sys ? ? ?

The i.cron Installation Class Action Script

# PKGINST parameter provided by installation service
while read src dest
do
user=`basename $dest` ||
exit 2
(crontab -l $user |
sed -e "/#$PKGINST$/d" > /tmp/$$crontab) ||
exit 2
sed -e "s/$/#$PKGINST/" $src >> /tmp/$$crontab ||
exit 2
crontab $user < /tmp/$$crontab ||
exit 2
rm -f /tmp/$$crontab
done
exit 0

The r.cron Removal Class Action Script

# PKGINST parameter provided by installation service
while read path
do
user=`basename $path` ||
exit 2
(crontab -l $user |
sed -e "/#$PKGINST$/d" > /tmp/$$crontab) ||
exit 2
crontab $user < /tmp/$$crontab ||
exit 2
rm -f /tmp/$$crontab
done
exit 

crontab File #1

41,1,21 * * * * /usr/lib/uucp/uudemon.hour > /dev/null
45 23 * * * ulimit 5000; /usr/bin/su uucp -c
"/usr/lib/uucp/uudemon.cleanup" >
/dev/null 2>&1
11,31,51 * * * * /usr/lib/uucp/uudemon.poll > /dev/null

crontab File #2

0 * * * 0-6 /usr/lib/sa/sa1
20,40 8-17 * * 1-5 /usr/lib/sa/sa1
5 18 * * 1-5 /usr/lib/sa/sa2 -s 8:00 -e 18:01 -i 1200 -A

Note –

If editing of a group of files will increase total file size by more than 10K, supply a space file so the pkgadd command can allow for this increase. For more information on the space file, see Reserving Additional Space on a Target System.


Installing and Removing a Driver With Procedure Scripts

This package installs a driver.

Techniques

This case study demonstrates the following techniques:

For more information on these scripts, see Writing Procedure Scripts.

Approach

Case Study Files

The pkginfo File

PKG=bufdev
NAME=Buffer Device
CATEGORY=system
BASEDIR=/
ARCH=INTEL
VERSION=Software Issue #19
CLASSES=none

The prototype File

To install a driver at the time of installation, you must include the object and configuration files for the driver in the prototype file.

In this example, the executable module for the driver is named buffer; the add_drv command operates on this file. The kernel uses the configuration file, buffer.conf, to help configure the driver.

i pkginfo
i request
i postinstall
i preremove
f none $KERNDIR/buffer 444 root root
f none $KERNDIR/buffer.conf 444 root root

Looking at the prototype file for this example, notice the following:

The request Script

trap 'exit 3' 15
# determine where driver object should be placed; location
# must be an absolute path name that is an existing directory
KERNDIR=`ckpath -aoy -d /kernel/drv -p \
“Where do you want the driver object installed”` || exit $?

# make parameters available to installation service, and
# so to any other packaging scripts
cat >$1 <<!

CLASSES='$CLASSES'
KERNDIR='$KERNDIR'
!
exit 0

The postinstall Script

# KERNDIR parameter provided by `request' script
err_code=1                    # an error is considered fatal
# Load the module into the system
cd $KERNDIR
add_drv -m '* 0666 root sys' buffer || exit $err_code
# Create a /dev entry for the character node
installf $PKGINST /dev/buffer0=/devices/eisa/buffer*:0 s
installf -f $PKGINST

The preremove Script

err_code=1                    # an error is considered fatal
# Unload the driver
rem_drv buffer || exit $err_code
# remove /dev file
removef $PKGINST /dev/buffer0 ; rm /dev/buffer0
removef -f $PKGINST

Installing a Driver by Using the sed Class and Procedure Scripts

This case study describes how to install a driver using the sed class and procedure scripts. It is also different from the previous case study (see Installing and Removing a Driver With Procedure Scripts) because this package is made up of both absolute and relocatable objects.

Techniques

This case study demonstrates the following techniques:

Approach

Case Study Files

The pkginfo File

PKG=SUNWsst
NAME=Simple SCSI Target Driver
VERSION=1
CATEGORY=system
ARCH=sparc
VENDOR=Sun Microsystems
BASEDIR=/opt
CLASSES=sed

The prototype File

For example, this case study uses the hierarchical layout of the package objects shown in the figure below.

Figure 5–1 Hierarchical Package Directory Structure

The following context describes the graphic.

The package objects are installed in the same places as they are in the pkg directory above. The driver modules (sst and sst.conf) are installed into /usr/kernel/drv and the include file is installed into /usr/include/sys/scsi/targets. The sst, sst.conf, and sst_def.h files are absolute objects. The test program, sstest.c, and its directory SUNWsst are relocatable; their installation location is set by the BASEDIR parameter.

The remaining components of the package (all the control files) go in the top directory of the package on the development machine, except the sed class script. This is called devlink.tab after the file it modifies, and goes into etc, the directory containing the real devlink.tab file.

From the pkg directory, run the pkgproto command as follows:


find usr SUNWsst -print | pkgproto > prototype

The output from the above command looks like this:

d none usr 0775 pms mts
d none usr/include 0775 pms mts
d none usr/include/sys 0775 pms mts
d none usr/include/sys/scsi 0775 pms mts
d none usr/include/sys/scsi/targets 0775 pms mts
f none usr/include/sys/scsi/targets/sst_def.h 0444 pms mts
d none usr/kernel 0775 pms mts
d none usr/kernel/drv 0775 pms mts
f none usr/kernel/drv/sst 0664 pms mts
f none usr/kernel/drv/sst.conf 0444 pms mts
d none SUNWsst 0775 pms mts
f none SUNWsst/sstest.c 0664 pms mts

This prototype file is not yet complete. To complete this file, you need to make the following modifications:

This is the final prototype file:

i pkginfo
i postinstall
i preremove
i copyright
e sed /etc/devlink.tab ? ? ?
f none /usr/include/sys/scsi/targets/sst_def.h 0644 bin bin
f none /usr/kernel/drv/sst 0755 root sys
f none /usr/kernel/drv/sst.conf 0644 root sys
d none SUNWsst 0775 root sys
f none SUNWsst/sstest.c 0664 root sys

The questions marks in the entry for the sed script indicate that the access permissions and ownership of the existing file on the installation machine should not be changed.

The sed Class Action Script (/etc/devlink.tab)

In the driver example, a sed class script is used to add an entry for the driver to the file /etc/devlink.tab. This file is used by the devlinks command to create symbolic links from /dev into /devices. This is the sed script:

# sed class script to modify /etc/devlink.tab
!install
/name=sst;/d
$i\
type=ddi_pseudo;name=sst;minor=character	rsst\\A1

!remove
/name=sst;/d

The pkgrm command does not run the removal part of the script. You may need to add a line to the preremove script to run sed directly to remove the entry from the /etc/devlink.tab file.

The postinstall Installation Script

In this example, all the script needs to do is run the add_drv command.

# Postinstallation script for SUNWsst
# This does not apply to a client.
if [$PKG_INSTALL_ROOT = "/" -o -z $PKG_INSTALL_ROOT]; then
   SAVEBASE=$BASEDIR
   BASEDIR=””; export BASEDIR
   /usr/sbin/add_drv sst
   STATUS=$?
   BASEDIR=$SAVEBASE; export BASEDIR
   if [ $STATUS -eq 0 ]
   then
	     exit 20
   else
	     exit 2
   fi
else
   echo "This cannot be installed onto a client."
   exit 2
fi

The add_drv command uses the BASEDIR parameter, so the script has to unset BASEDIR before running the command, and restore it afterwards.

One of the actions of the add_drv command is to run devlinks, which uses the entry placed in /etc/devlink.tab by the sed class script to create the /dev entries for the driver.

The exit code from the postinstall script is significant. The exit code 20 tells the pkgadd command to tell the user to reboot the system (necessary after installing a driver), and the exit code 2 tells the pkgadd command to tell the user that the installation partially failed.

The preremove Removal Script

In the case of this driver example, it removes the links in /dev and runs the rem_drv command on the driver.

# Pre removal script for the sst driver
echo “Removing /dev entries”
/usr/bin/rm -f /dev/rsst*

echo “Deinstalling driver from the kernel”
SAVEBASE=$BASEDIR
BASEDIR=””; export BASEDIR
/usr/sbin/rem_drv sst
BASEDIR=$SAVEBASE; export BASEDIR

exit 

The script removes the /dev entries itself; the /devices entries are removed by the rem_drv command.

The copyright File

This is a simple ASCII file containing the text of a copyright notice. The notice is displayed at the beginning of package installation exactly as it appears in the file.


	Copyright (c) 1999 Drivers-R-Us, Inc.
	10 Device Drive, Thebus, IO 80586

All rights reserved. This product and related documentation is
protected by copyright and distributed under licenses 
restricting its use, copying, distribution and decompilation. 
No part of this product or related documentation may be 
reproduced in any form by any means without prior written 
authorization of Drivers-R-Us and its licensors, if any.