21
How to make a Solaris Package 1. Introduction to create SUN software packages In this document you will learn how to create simple SUN packages. Or, how to create SUN packages simple. :) This small howto is for developpers who want to simplifiy software installation. You should be experienced in compiling and installing software and you should be experienced in user management. All you need is a SUN/Solaris machine and a shell login. For creating system packages you need to be root. The following chapters will deal how to build a package using the example of GNU bc, a small and simple commandline calculator. Prerequisites: First of all you need your compilation results as we want your files to be put in a package (PKG). There are two possibilities to get there: Using standard compiler and Solaris make Using gcc and GNU Make • Using standard compiler and Solaris make Unfortunately you have to compile your software twice: One time for getting all the files you want to put in the package and a second time for the final location. I suggest you create somewhere public (like in /var/tmp) a subdirectory, where you can put all the files in and where "nothing bad can happen". Take this directory as installation prefix and do a $ make install In the following chapters you will see how to operate on this. Afterwards, you have to do the compilation and installation again for the final location. • Using gcc and GNU make You are a lucky winner! GNU make supports an installation variable called DESTDIR, which defines a installation root. For instance, if you compiled your software to be located in /usr/local then you can do: $ ./configure --prefix=/usr/local ... ... <configuration and compilation output> $ gmake install DESTDIR=/var/tmp/garex gmake (as I call it) will then perform an installation at the DESTDIR as it would do in /usr/local, including the creation of all sub-directories of the former install-root "/". If you then got all the files

Solaris Packaging

Embed Size (px)

Citation preview

Page 1: Solaris Packaging

How to make a Solaris Package

1. Introduction to create SUN software packagesIn this document you will learn how to create simple SUN packages. Or, how to create SUNpackages simple. :) This small howto is for developpers who want to simplifiy software installation.You should be experienced in compiling and installing software and you should be experienced inuser management. All you need is a SUN/Solaris machine and a shell login. For creating systempackages you need to be root. The following chapters will deal how to build a package using the example of GNU bc, a small andsimple commandline calculator.

Prerequisites:First of all you need your compilation results as we want your files to be put in a package (PKG).There are two possibilities to get there:

• Using standard compiler and Solaris make • Using gcc and GNU Make

• Using standard compiler and Solaris makeUnfortunately you have to compile your software twice: One time for getting all the files you want toput in the package and a second time for the final location.I suggest you create somewhere public (like in /var/tmp) a subdirectory, where you can put all thefiles in and where "nothing bad can happen". Take this directory as installation prefix and do a $ make install

In the following chapters you will see how to operate on this. Afterwards, you have to do thecompilation and installation again for the final location.

• Using gcc and GNU makeYou are a lucky winner! GNU make supports an installation variable called DESTDIR, which definesa installation root. For instance, if you compiled your software to be located in /usr/local then you cando: $ ./configure --prefix=/usr/local ...... <configuration and compilation output>$ gmake install DESTDIR=/var/tmp/garex

gmake (as I call it) will then perform an installation at the DESTDIR as it would do in /usr/local,including the creation of all sub-directories of the former install-root "/". If you then got all the files

Page 2: Solaris Packaging

together, just perform a $ gmake install

again, and you are nearly done with the package. Unfortunately, not all Open Source source tarballscome with a proper Makefile.in file, where the DESTDIR variable has to be enabled during creationof the source tarball with GNU autoconf. But there is a way around, which is more the "hackers way".You will have to manually edit the Makefile and seek the "install:" section. Then add a $(DESTDIR)/...

before every installation path.

2. Syntax of the pkginfo fileThis file contains important information about the package itself like name of the package, version,vendor and so on. For our example it will look like this: PKG=ARbcNAME="bc - a binary calculator"ARCH=sparcVERSION=1.0.6CATEGORY=utilityDESC="bc - a binary commandline calculator often used in shellscripts forcalculating"VENDOR="(C) 2002 Garex Inc."VSTOCK="123456"HOTLINE="+49-123456-TOLL-FREE"EMAIL="[email protected]"BASEDIR=/MAXINST=1INTONLY=1CLASSES=application noneISTATES="S 2 3"RSTATES="S 2 3"PSTAMP="20020718 19:35"ULIMIT=20ORDER=none application

The variables have the following meaning:

Variable DescriptionPKG Package name (up to 10 characters)ARCH Solaris architecture (sparc/x86)VERSION The version of the packageCATEGORY Kind of software (system/application/library/utility etc). Can be freely defined.DESC This is the long descriptionVENDOR Self-explaining :)

Page 3: Solaris Packaging

VSTOCK Number of product (stock number)HOTLINE Self-explaining (put a telephone number here)EMAIL Self-explaining (put a valid email address for contact here)

BASEDIR Describes the top-level directory for installing the packaged files from and forsearching the files to be packaged

MAXINST Maximum number of simultaneously installed instances of the same packageINTONLY Interactive Only. (value not equal to "0" means user interaction required)CLASSES Needed to define installation classes.ISTATES Init States the package is allowed to be installedRSTATES Init States the package is allowed to be removedPSTAMP Production time stamp (package creation time stamp)

ULIMIT Parameter for the ulimit command for maximum file size. (equal to ulimit -f; value willbe calculated in 512 byte blocks)

ORDER Defines the installation order for the specified classes

Most variables mentioned here are required:PKG, ARCH, CATEGORY, DESC, BASEDIR, VERSIONFor instance, if you delete the VERSION variable, you will get an error like this during "pkgmk": $ pkgmk -o -b / -r /## Building pkgmap from package prototype file.## Processing pkginfo file.WARNING: parameter <VERSION> set to "Dev Release 07/19/2002"...

Of course you can define other variables as well. When creating the package, those variables comeinto action while the packaging process is running. Additionally, those variables can be used byinstallation or removal scripts, e.g. for doing dependancy checks. NOTE: If you don't specifyPSTAMP with your own format, then a PSTAMP entry of the kind <hostname><YYMMDDhhmm> willbe created for you and added to the pkginfo file.

3. Syntax of the prototype fileWARNING: The following chapter is big and is a little bit hard to read.

The prototype file is essentially important for the packaging process, as it defines _how_ the filesshould be included in your package. In our example, it would look like this: $ cd <temporarily installation root>$ pkgproto * | sortd none bin 0755 root otherd none info 0755 root other

Page 4: Solaris Packaging

d none man 0755 root otherd none man/man1 0755 root otherf none bin/bc 0755 root otherf none bin/dc 0755 root otherf none info/bc.info 0644 root otherf none info/dc.info 0644 root otherf none man/man1/bc.1 0644 root otherf none man/man1/dc.1 0644 root other

Explanation:The syntax is:<type> <class> <name of file> <permissions> <user> <group>

File Types:

Type Description

b block special device (usually a file system)c character special device (usually a raw disk device)d directorye editable file (will be usually edited during install)f filei include filel hard linkp named pipe (FIFO)s symbolic link

v volatile file (file to be created which changes size later-> logfiles)

x directory only accessible for this package

You can get additional information on a Solaris machine by $ man -s4 prototype

Page 5: Solaris Packaging

4. Include options:The include directive means that the specified file will be treated as a file vital to the package. Theusual Options are: i depend(=<path to dependancy file>)

This tells us, where the dependancy file is located. The syntax of depend is: P ARbash Bourne Again Shell - 2.05a

as in<type> <pkg name> <full pkg name>

For the installation of our binary calculator this means that we would have ARbash first installedbefore we can install our ARbc package.

Types of dependancies are:

Dependancy-Type Description

P Prerequisite (required package)

I Incompatible PKG (actual package to be installed cannot be installed due toincompatibilities to the named package)

R Reverse Dependancy (tells us that the package currently being installed is a pre-requisite dependancy to another package)

Package name: This is the package's name our dependancy lies on.

Full package name: This is the package's full name as it appears in "pkginfo". Not required, butuseful during packaging. i pkginfo(=<path to pkginfo file>)

Defines, where to look for the _required_ pkginfo file. i version(=<path to version file>)

Tells "pkgmk" where to look for a version file. This is optional/ informational. i preinstall(=<path to preinstall script>)

Tells "pkgmk" where to look for a script to be executed _before_ the package will be installed, e.g. tocreate application specific users. i preremove(=<path to preremove script>)

Tells "pkgmk" where to look for a script to be executed _before_ the package will be removed, e.g. tostop a webserver.

Page 6: Solaris Packaging

i postinstall(=<path to postinstall script>)

Tells "pkgmk" where to look for a script to be executed _after_ the package has been installed, e.g.start a webserver with a default config. i postremove(=<path to postremove script>)

Tells "pkgmk" where to look for a script to be executed _after_ the package has been removed, e.g.cleaning up some old temporary files. i request(=<path to request script>)

Tells "pkgmk" where to look for a script which asks the user for certain information, e.g. license key. i checkinstall(=<path to checkinstall script>)

Tells "pkgmk" where to look for a script which gathers installation data The sequence of these scripts during package installation is:

1. display copyright 2. execute request script and ask user

3. execute checkinstall script andgather data

4. execute preinstall 5. execute postinstall 6. execute preremove 7. execute postremove Additionally, there are the following directives: ! <command>

This means that the following string is a shell command, e.g. means !PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/bin

the binary path to be set. ! search <dir1> <dir2> <dir3> ...

This means that within the following directories the files to be packaged will be searched in. ! include <dir>

This means that another prototype will be included in the mentioned directory. ! default <attributes>

This means that a list of default parameters like mode, owner and group will be defined, but they arerequired and not defined in the prototype file.

Page 7: Solaris Packaging

Back to our exampleNow that we got all the files, we have to modify the newly created prototype file. First of all, save it toyour temporarily installation root: $ cd <temporarily installation root>$ pkgproto * | sort > prototype

The only one absolutely _required_ file we have to add is the pkginfo file. So open the newly createdprototype file with your favourite editor and add a i pkginfo=<name/location of pkginfo file>

to the file. Assuming the pkinfo file is located in the same directory as the prototype file, a simple i pkginfo

also does the job. Now we need to change the location of the files. Just do the second compilationand installation run with the final location. Then we modify our prototype file to this: i pkginfo=pkginfod none usr ? ? ?d none usr/local ? ? ?d none usr/local/bin ? ? ?d none usr/local/info ? ? ?d none usr/local/man ? ? ?d none usr/local/man/man1 ? ? ?f none usr/local/bin/bc 0755 bin binf none usr/local/bin/dc 0755 bin binf none usr/local/info/bc.info 0644 bin binf none usr/local/info/dc.info 0644 bin binf none usr/local/man/man1/bc.1 0644 bin binf none usr/local/man/man1/dc.1 0644 bin bin

In the former document about the pkginfo file, the variable BASEDIR defines the packaging - andlater the installation root - to be "/", but our files are located somewhere else. The only solution tocome around this problem is to do two compilation runs (you remember, I told you in theintroduction). The first run for catching all files in a temporarily install location, the second for the finalinstallation path. Although bc does really not need a bootskript as it is no daemon, we will include a dummy bootscriptcalled bc_startup.sh, just as an example. But how will we be able to build a system PKG if we can'tbecome superuser to copy the bootskript to /etc/init.d and create a symbolic link to /etc/rc3.d? Theanswer is quite simple. Within the prototype file we can work with include paths and symbolic links.Assuming our boot script is in the same directory as our pkginfo and prototype file, we simply add thefollowing line to the prototype file: f none etc/init.d/bc_startup=bc_startup 0755 root other

"pkgmk" will add our local bc_startup.sh to the package as it would reside in /etc/init.d/bc_startup.Finally we add another entry to the prototype file: s none etc/rc3.d/S99bc_startup=../init.d/bc_startup

Page 8: Solaris Packaging

This will create a symbolic link from the central init skript directory in /etc/init.d to /etc/rc3.d/S99bc_startup The syntax for these include paths is:<destination path>=<source path>

IMPORTANT NOTE: When adding a symbolic link, the file that the link refers to _HAS_ to be listedfirst! As a consequence it is the best solution to put all symbolic links at the end of the prototype file.Additionally, you will have noticed in the prototype file above that I listed the complete /usr/localdirectory structure and added "?" at the end of the line. Why that?

1. Add all needed directories, also the parent directories 2. Adding "? ? ?" after the filename will result in the Solaris defaults for permissions, user and

group. 3. Omit the trailing "/" to create relocatable PKG (later in this guide).

One word to Solaris init scripts:There is a small but very important difference between bootscripts with or without a ".sh" ending.Bootscripts ending with ".sh" are treated as shell includes and are not executed. Think of a "for-loop":...for script in <current runlevel>*.shdo . $scriptdone...

Bootscripts not ending with ".sh" are treated as shell skripts and are therefore executed. (If you areinterested in, where in the init bootprocess this happens, take a look at /sbin/rcS and search for asimilar text block: ... if [ -d /etc/rcS.d ]; then for f in /etc/rcS.d/S*; do if [ -s $f ]; then case $f in *.sh) . $f ;; *) /sbin/sh $f start ;; esac fi done fi...

Finally: So our final prototype file will look like: i pkginfo=pkginfod none usr ? ? ?d none usr/local ? ? ?d none usr/local/bin ? ? ?d none usr/local/info ? ? ?d none usr/local/man ? ? ?d none usr/local/man/man1 ? ? ?f none usr/local/bin/bc 0755 bin binf none usr/local/bin/dc 0755 bin bin

Page 9: Solaris Packaging

f none usr/local/info/bc.info 0644 bin binf none usr/local/info/dc.info 0644 bin binf none usr/local/man/man1/bc.1 0644 bin binf none usr/local/man/man1/dc.1 0644 bin binf none etc/init.d/bc_startup=bc_startup 0755 root others none etc/rc3.d/S99bc_startup=../init.d/bc_startup

5. Creating installation/remove scriptsPROBLEM: During a Solaris installation - either by cdrom or jumpstart - the local harddisks/partitionsare mounted at a read-writable mount point called "/a". The running Solaris itself is mounted read-only by NFS. Equally, the BASEDIR variable is also set to "/a". "/a" therefore is the location where allpackages to be installed will be written to. If you have this in mind, then you will understand why Istrongly recommend omitting the trailing "/" when creating a prototype file and why I _strongly_recommend not using any kind of absolute pathnames. As the booted system is mounted read-onlyin memory, a PKG containing /usr/local in its pkgmap will fail to install as the files _cannot_ beinstalled in "/"!

Therefore any installation script using special shell commands like useradd, groupadd, mkdir or anyother command should reference the commands like CHROOTDIR="${BASEDIR}"${BASEDIR}/usr/sbin/chroot ${CHROOTDIR} /usr/sbin/groupadd -g 80 httpd${BASEDIR/usr/bin/mkdir $BASEDIR/tmp/foobar

Global environment variables _always_ override the definitions in the pkginfo file!

As you may remeber from the former chapter, there are six types of scripts you can create: 1. request 2. checkinstall 3. preinstall 4. postinstall 5. preremove 6. postremove

6. Differences between installation/procedure scriptsThere are installation scripts and procedure scripts. Installation scripts are request and checkinstall.Procedure scripts are preinstall, postinstall, preremove, postremove.

Installation scripts cannot modify files. They can do global software dependancy checks, e.g.whether a certain version of a binary is installed or whether a needed file (database file) existssomewhere on the harddisk. They can gather data from the system (checkinstall) or theadministrator (request). They can modify global variables like CLASSES, so only certain files will beinstalled.

Page 10: Solaris Packaging

Procedure scripts provide a mechanism to influence the package installation process. They canonly do package-based dependancy checks. They can modify system resources like adding users orchanging permissions. They cannot be used for gathering data interactively.

7. Package environment variables available to all scripts

Variablename Description

CLIENT_BASEDIR

The base directory with respect to the target system. While BASEDIR is the variableto use if referring to a package on the cdrom/ install server, this variable is the pathto include in files placed on the client system.

INST_DATADIR The directory where the package now being read is located.

PATH The search list used by sh to find commands on script invocation. PKGINST The instance identifier of the package being installed.

PKGSAV The directory where files can be saved for use by removal scripts or wherepreviously saved files can be found.

PKG_INSTALL_ROOT

The root file system on the target system where the package is being installed.Available for pkgadd/pkgrm only when these commands are invoked with -R option.

PKG_NO_UNIFIED

Is an env variable that gets set if the pkgadd/pkgrm command is invoked with the -R-M option.

UPDATEThis variable does not exist under most installation environments. If it does exist(with the value yes), it means that a PKG with the same name, version andarchitecture is already installed on the system or that the installing PKG willoverwrite an installed PKG. The original BASEDIR is then used.

8. Installation scripts

The "request" script

There are certain restrictions which apply to the request script: • There can be only one request script for every PKG and it must be named "request" • The "request" script cannot modify any files • Environment variable assignments have to be made public by adding them to the global

response file, usually $1. • Only the CLASSES and the BASEDIR parameters can be modified by the script. This means

that global system environment variables or installation PKG variables cannot be modified. • The request script is not executed during PKG removal. • Every environment variable that may be modified should be defined in the pkginfo file. • The output format of the modified variables _must_ be PARAM=value • Do not perform any special analysis of the target system in a request script. Data system

collection is to be done by the "checkinstall" script. • The request script runs as user install or - if this user is not available - as user nobody.

Page 11: Solaris Packaging

NOTE: When you include a request script in a package that you want to add to a jumpstart server,keep in mind that noone can answer the questions you may ask in the script. Therefore anautomated package install will maybe result in a partially installed package or the jumpstartmechanism will halt until an administrator gives the right answer. The only solution is to providedefault values for your questions and to define those default values in the pkginfo file. Additionally,you can check whether the installation is taking part in an interactive environment or in a non-interactive environment by checking the content of the ${BASEDIR} variable. Remember: if you are running in a non-interactive environment, e.g. cdrom or jumpstart installation,${BASEDIR} refers to /a.

Here is an example for a request script: #!/bin/shREALNAME=""echo "Enter your realname: "read REALNAME

# export REALNAME to global PKG environmentcat >> $1 << EOTREALNAME=${REALNAME}EOT

Doing like this will make the variable REALNAME and its content available to the followinginstallation/procedure scripts. If you add a echo "installation response file: $1"

to your request script, then you will realize that pkgadd calls the request script with the name of thetemporarily response file as first parameter.

The "checkinstall" script

The checkinstall script is executed shortly after the optional request script. The checkinstall script is_strictly_ a data gatherer. However, based on the information it gathers, it can create or modifyenvironment variables in order to control the course of the resulting installation. It is also capable ofhalting cleanly the installation process.The checkinstall script is intended to perform basic checks on a file system that would not be normalfor the pkgadd command. For example, it can manage general software dependancies, incontradiction to the depend file of a package which manages only package-level dependencies.

• There can be only one checkinstall script for every PKG and it must be named "checkinstall" • The "checkinstall" script cannot modify files. • Environment variable assignments have to be made public by adding them to the global

response file, usually $1. • Only the CLASSES and the BASEDIR parameters can be modified by the script. This means

that global system environment variables or installation PKG variables cannot be modified. • The checkinstall script is not executed during PKG removal. • Every environment variable that may be modified should be defined in the pkginfo file. • The output format of the modified variables _must_ be PARAM=value • Administrator interaction is not permitted during execution of a checkinstall script. This has to

be done in the request script.

Page 12: Solaris Packaging

• The checkinstall script runs as user install or - if this user is not available - as user nobody. Here is an example for a checkinstall script: #!/bin/sh# checkinstall script for ARbc

# First find which bash package has been installedpkginfo -q ARbash1 # try the older one first

if [ $? -ne 0 ]then pkginfo -q ARbash # now the latest if [ $? -ne 0 ] then echo "No bash package can be found. Please install the" echo "ARbash package and try this installation again." exit 3 # Suspend else BASHROOT="`pkgparam ARbash BASEDIR`/usr/local/bin" # new one fielse BASHROOT="`pkgparam ARbash1 BASEDIR`/usr/local/bin" # old onefi

# Now look for the bash executable we will need for our silly bootscriptif [ $BASHROOT/bash ]then exit 0 # all OKelse echo "No bash executable can be found. Please check your bash" echo "package for integrity and try this installation again." exit 3 # Suspendfi

9. Procedure scriptsProcedure scripts provide a set of instructions to be performed at particular point in packageinstallation or removal. Of course there are also restrictions which apply to procedure scripts as wellas they did to the installation scripts "request" and "checkinstall":

• Procedure scripts run as uid=root and gid=other • Each script should be able to be executed more than once since it is executed for each

volume in a package. • Administrator interaction is not permitted during execution. Administrator interaction is

restricted to the request script. • Each procedure script installing a package object lot listed in the pkgmap file _must_ use the

installf command to notify the package database that it is adding or modifying a path name.See installf(1M) for more information.

• Each script removing files that are not listed in the pkgmap _must_ use the removef commandto notify the package database that it is removing a path name. See removef(1M) for details.

• Only postinstall and postremove scripts may install/modify package objects in that way. Here is an example for a preinstall script:

Page 13: Solaris Packaging

#!/bin/sh

CHROOTDIR="${BASEDIR}"

# Create a group for our new service${BASEDIR}/usr/sbin/chroot ${CHROOTDIR} /usr/sbin/groupadd -g 80 httpd

# Create a user for our new service${BASEDIR}/usr/sbin/chroot ${CHROOTDIR} /usr/sbin/useradd -u 80 -g 80 -d /data/www -m -s /bin/sh -c "Webserver User" httpd

Here is an example for a postinstall script: #!/bin/sh

# Create logfile directory for our webserver${BASEDIR}/bin/mkdir -p ${BASEDIR}/data/logs/www

Here is an example for a preremove script: #!/bin/sh

# Stop our webserver first

/etc/init.d/webserver stop

Here is an example for a postremove script #!/bin/sh

LOGDIR=/data/logs

# collect all logfiles to a .tar. gz and trash the directorycd ${LOGDIR} /usr/local/bin/gtar cvfz ${LOGDIR}/logfiles.tar.gz && \rm -rf ${LOGDIR}

NOTE: You may have noticed that the preremove/postremove scripts do not use the relativecommandline syntax, e.g. with a ${BASEDIR} as prefix. Honestly, I never saw a package removalduring Solaris installation. Additionally I think that package removal _has_ to be done interactively.

Page 14: Solaris Packaging

10. Writing class action scriptsFor writing class action scripts we first have to know how they interact within the packageinstallation/removal procedure. And of course we have to know how classes can be defined andwhere they are defined. With classes you are able to group certain files within a package. Forinstance, you will be able to group certain files together and choose only these files for installation.

Defining classesClasses can be only defined in two files: the CLASSES variable in the pkginfo file and by assigningcertain files to this predefined class in the prototype file. Then pkgadd/pkgrm will create a file listcontaining all these files during an installation/removal and invoke the class action scripts with the filelist as 1st parameter. Class names can be freely defined except for the following exceptions:

Class Description

sed Provides a method for using sed instructions to edit files upon package installationand removal.

awk Provides a method for using awk instructions to edit files upon packageinstallation and removal.

build Provied a method to dynamically construct or modify files using Bourne shellcommands.

preserve

Provides a method to preserve files that should not be overwritten by futurepackage installations.

There are two possibilities class action scripts can come into action: • Using a default class • Using own class scripts

The easiest way is using a default class, so we start off with this. Let's do this by choosing the awksystem class.

Page 15: Solaris Packaging

11. Using a default system class (sed/awk)To explain how this works out it is best to show you first the entry for the prototype file you have tomake: e awk tmp/dummy.conf 0755 root other

What does this mean? The "e" tells us we have a editable file. The "awk" tells us we have a filewhich belongs to the class "awk". The third entry tells us it is a file located in /tmp which contains theawk commands. Irritating, isn't it? We want to _modify_ an existing file and not placing a new file withawk commands there! As the /tmp/dummy.conf can't contain any awk commands, we place a awkcommand file _over_ it. The commands in this file will be then applied to the file it covers. It's like ahat you put on your head.

A _very important_ information I gave to you when explaining the prototype file syntax will now beuseful for us. Of course we can't overwrite an existing configuration file for creating a package(imagine it would be a vital system file like /etc/syslog.conf). If you remember the link syntax<destination>=<source>, you can set the path to the final awk script to modify our configuration filelike this: e awk tmp/dummy.conf=/var/tmp/build-root/modify_config.awk 0755 root other

When you create the package then, the file modify_config.awk will be put in the package astmp/dummy.conf and during installation/removal the script will be then applied to the dummy.conffile. Now we are half on our way to Chicago, folks :). The next part is the syntax of the script. This isquite simple and looks like this: !install# awk program to install changesBEGIN {}

END { print "Installing...";}

!remove# awk program to remove changesBEGIN {}

{ print "Removing...";}

As you can clearly see the script is divided into two parts: the "install" and the "remove" part. Whenour package is installed/removed, pkgadd/pkgrm creates a list of files which belong to this class andinvokes the class action script with the file list. Here we only have one file so the script will be appliedonly to one file. There is no difference between creating scripts for the sed class or the awk class except that in the

Page 16: Solaris Packaging

first case any command is a sed command and in the second case we have awk commands onlyAND that the sed/awk classes _modify_ existing files only.

The "build" classThe "build" class is used to create _and_ modify a package object file by executing Bourne shellinstructions. The prototype entry would look like this: e build tmp/dummy=/var/tmp/build-root/modify_dummy.sh ? ? ?

The package object tmp/dummy would then look like this: !install# dummy file creatorif [ -r ${PKG_INSTALL_ROOT}/tmp/dummy ]then echo "/tmp/dummy already in place"else echo "# /tmp/dummy" > ${PKG_INSTALL_ROOT}/tmp/dummy echo "123456 # first random number" >> ${PKG_INSTALL_ROOT}/tmp/dummyfi

!remove# dummy file deconstructorif [ -f ${PKG_INSTALL_ROOT}/tmp/dummy ]then # The file can be removed if unchanged if [ egrep "first random number" ${PKG_INSTALL_ROOT}/tmp/dummy ] then rm ${PKG_INSTALL_ROOT}/tmp/dummy fifi

The "preserve" classThe preserve class preserves a package object file by determinig whether or not an existing fileshould be overwritten when the package is installed. Two possible scenarios when using a preserveclass script are:

• If the file to be installed does not already exist in the target directory, the file will be installednormally.

• If the file to be installed exists in the target directory, a message describing the file exists isdisplayed and the file is not installed.

An example of a preserve class action script would be: error=noecho "## checking common configuration files"while read src destdo [ "$src" = /dev/null ] && continue

if [ -f "$dest" ] then echo $dest preserve

Page 17: Solaris Packaging

else echo $dest cp $src $dest || error=yes fi

done[ "$error" = yes ] && exit 2exit 0

You may ask, what "$src" and "$dest" mean here. Very easy: The default behaviour of pkgadd is tocopy the packaged file from the installation medium (e.g. a package) to its final destination. In thisexample we just want to know whether the file already exists ($src set to /dev/null).

12. Creating class action scripts with own classesYou already know the basics for this from the paragraphs above, so we will summarize it in a list:

1. Assign the package objects in the prototype file the desired class names. For instance, f manpage usr/share/man/man1/myapp.1

2. Modify the CLASSES variable in the pkginfo file to contain the newly defined class name, e.g. CLASSES=manpage application none

3. Create the class scripts. An installation script for a certain class must be named i.<class>, e.g.i.manpage

A removal class action script for a certain class must be named r.<class>, e.g. r.manpage

4. Add the required class scripts separately to the prototype file, e.g. i i.manpagei r.manpage

5. Create your package using pkgmk. NOTE: Remember, when a file is part of a class that has a class action script, the script must installthe file. The pkgadd command does not install files for which a class action script exists, although itdoes verify the installation. And, if you define a class but do not deliver a class action script, the onlyaction taken for that class is to copy components from the installation medium (a package) to thetarget system (the default pkgadd behaviour).

Page 18: Solaris Packaging

13. Creating a packageWhoa! The last two chapters were hard stuff to read, so I think we continue with our example of thebinary calculator. First I want to explain to you, which commands we will need:

Command Description/bin/pkgproto

This command creates a basic prototype file with all entries we need. This genericprototype file has to be edited later to include further pkg information files.

/bin/pkgmk This command creates the package./bin/pkgtrans This command is used to transfer packages from the directory format to a package file.

/bin/pkgckeck This command is used to check the integrity of a package

If you remember, our pkginfo file looks like this: PKG=ARbcNAME="bc - a binary calculator"ARCH=sparcVERSION=1.0.6CATEGORY=utilityDESC="bc - a binary commandline calculator often used in shellscripts forcalculating"VENDOR="(C) 2002 Garex Inc."VSTOCK="123456"HOTLINE="+49-123456-TOLL-FREE"EMAIL="[email protected]"BASEDIR=/MAXINST=1INTONLY=1CLASSES=application noneISTATES="S 2 3"RSTATES="S 2 3"PSTAMP="20020718 19:35"ULIMIT=20ORDER=none application

And our generic prototype file looks like this, as we created it by the pkgproto command : d none usr ? ? ?d none usr/local ? ? ?d none usr/local/bin ? ? ?d none usr/local/info ? ? ?f none usr/local/info/bc.info 0644 bin binf none usr/local/info/dc.info 0644 bin binf none usr/local/man/man1/bc.1 0644 bin binf none usr/local/man/man1/dc.1 0644 bin bin

Page 19: Solaris Packaging

14. Completing the prototype fileThere are several lines are missing for our package. The include of the pkginfo file, usually located inthe same directory as the prototype file, the line for our simple, but useless bc bootscript and itssymbolic link. Therefore we have to add the following lines to the prototype file: i pkginfo=pkginfo...f none etc/init.d/bc_startup=bc_startup 0755 root others none etc/rc3.d/S99bc_startup=../init.d/bc_startup

So our final prototype looks like this: i pkginfod none etc ? ? ?d none etc/init.d ? ? ?d none etc/rc3.d ? ? ?d none usr ? ? ?d none usr/local ? ? ?d none usr/local/bin ? ? ?d none usr/local/info ? ? ?d none usr/local/man ? ? ?d none usr/local/man/man1 ? ? ?f none usr/local/bin/bc 0755 bin binf none usr/local/bin/dc 0755 bin binf none usr/local/info/bc.info 0644 bin binf none usr/local/info/dc.info 0644 bin binf none usr/local/man/man1/bc.1 0644 bin binf none usr/local/man/man1/dc.1 0644 bin binf none etc/init.d/bc_startup=bc_startup 0755 root others none etc/rc3.d/S99bc_startup=../init.d/bc_startup

REMEMBER: When adding files to the package, every directory leading to the destination has to beincluded as well! That's the reason why etc, etc/init.d and etc/rc3.d has to be listed here as well! There may be several reasons to omit a directory, e.g. let /opt be a symbolic lic to /var/opt due toless diskspace. Adding /opt as of type d then results in replacing the symbolic link /opt with a realdirectory called /opt, which will be created in "/" and your package may be not installed, if "/" has notenough disk space!

Page 20: Solaris Packaging

15. The Packaging Commands

The pkgmk commandAssuming you did the final "make install", we can now go to the final package creation using"pkgmk". Before we invoke "pkgmk", you have to know about the three main options we will need:

Option flag Description

-o Overwrites an existing package instance in the PKG spool directory /var/spool/pkg.Useful if you are testing PKG creation techniques for the first time.

-r <root-path>

By using this option, you override the default destination paths defined in theprototype file

-b<base_src_dir>

Prepend the indicated base_src_dir to locate relocatable objects on the sourcemachine.Instead of including all files in the prototype file as <dst>=<src>, you can tell pkgmkwhere to search for the files.

Now let's invoke the pkgmk command: $ pkgmk -o -b / -r /## Building pkgmap from package prototype file.## Processing pkginfo file.## Attempting to volumize 17 entries in pkgmap.part 1 -- 853 blocks, 19 entries## Packaging one part./var/spool/pkg/ARbc/pkgmap/var/spool/pkg/ARbc/pkginfo/var/spool/pkg/ARbc/reloc/etc/init.d/bc_startup/var/spool/pkg/ARbc/reloc/usr/local/bin/bc/var/spool/pkg/ARbc/reloc/usr/local/bin/dc/var/spool/pkg/ARbc/reloc/usr/local/info/bc.info/var/spool/pkg/ARbc/reloc/usr/local/info/dc.info/var/spool/pkg/ARbc/reloc/usr/local/man/man1/bc.1/var/spool/pkg/ARbc/reloc/usr/local/man/man1/dc.1## Validating control scripts.## Packaging complete.

The pkgchk commandNow we created our ARbc package. Finally, we have to verify its integrity with $ cd /var/spool/pkg$ pkgchk -vd . ARbcChecking uninstalled directory format package <ARbc> from </var/spool/pkg>## Checking control scripts.## Checking package objects.etc/init.d/bc_startuppkginfousr/local/bin/bcusr/local/bin/dcusr/local/info/bc.info

Page 21: Solaris Packaging

usr/local/info/dc.infousr/local/man/man1/bc.1usr/local/man/man1/dc.1## Checking is complete.

If no errors were found, your package is fine.

The pkgtrans commandFinally as a gimmick we transfer the package directory to a package file, which is easier to transfer toremote hosts: $ pkgtrans /var/spool/pkg /tmp/ARbc-1.0-sol8-test ARbcTransferring package instance$ ls -l /tmp/ARbc-1.0-sol8-test-rw-r--r-- 1 garex staff 402432 Jul 22 19:26 /tmp/ARbc-1.0-sol8-test

Transferring the file back to the package directory is also quite simple: $ pkgtrans /tmp/ARbc-1.0-sol8-test /tmp ARbcTransferring package instance$ ls -ld /tmp/ARbcdrwxr-xr-x 3 garex staff 306 Jul 22 19:29 /tmp/ARbc

Doing a testinstallationNow try installing the packge first from the directory, then from the file: $ cd /tmp$ pkgadd -d . ARbc...$ pkgrm ARbc...$ pkgadd -d ARbc-1.0-sol8-test...$ pkgrm ARbc...

If this works, you are really through it. CONGRATULATIONS!

Compiled by : Anil Kashyap