You are on page 1of 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

together, just perform a


$ gmake install

again, and you are nearly done with the package. Unfortunately, not all Open Source source tarballs come with a proper Makefile.in file, where the DESTDIR variable has to be enabled during creation of 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 file


This 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=ARbc NAME="bc - a binary calculator" ARCH=sparc VERSION=1.0.6 CATEGORY=utility DESC="bc - a binary commandline calculator often used in shellscripts for calculating" VENDOR="(C) 2002 Garex Inc." VSTOCK="123456" HOTLINE="+49-123456-TOLL-FREE" EMAIL="garex@garex.net" BASEDIR=/ MAXINST=1 INTONLY=1 CLASSES=application none ISTATES="S 2 3" RSTATES="S 2 3" PSTAMP="20020718 19:35" ULIMIT=20 ORDER=none application

The variables have the following meaning: Variable PKG ARCH VERSION CATEGORY DESC VENDOR Description Package name (up to 10 characters) Solaris architecture (sparc/x86) The version of the package Kind of software (system/application/library/utility etc). Can be freely defined. This is the long description Self-explaining :)

VSTOCK HOTLINE EMAIL BASEDIR MAXINST INTONLY CLASSES ISTATES RSTATES PSTAMP ULIMIT ORDER

Number of product (stock number) Self-explaining (put a telephone number here) Self-explaining (put a valid email address for contact here) Describes the top-level directory for installing the packaged files from and for searching the files to be packaged Maximum number of simultaneously installed instances of the same package Interactive Only. (value not equal to "0" means user interaction required) Needed to define installation classes. Init States the package is allowed to be installed Init States the package is allowed to be removed Production time stamp (package creation time stamp) Parameter for the ulimit command for maximum file size. (equal to ulimit -f; value will be calculated in 512 byte blocks) Defines the installation order for the specified classes

Most variables mentioned here are required: PKG, ARCH, CATEGORY, DESC, BASEDIR, VERSION For 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 come into action while the packaging process is running. Additionally, those variables can be used by installation or removal scripts, e.g. for doing dependancy checks. NOTE: If you don't specify PSTAMP with your own format, then a PSTAMP entry of the kind <hostname><YYMMDDhhmm> will be created for you and added to the pkginfo file.

3. Syntax of the prototype file


WARNING: 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 files should be included in your package. In our example, it would look like this:
$ cd <temporarily installation root> $ pkgproto * | sort d none bin 0755 root other d none info 0755 root other

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

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

File Types:
Typ e b c d e f i l p s v x Description block special device (usually a file system) character special device (usually a raw disk device) directory editable file (will be usually edited during install) file include file hard link named pipe (FIFO) symbolic link volatile file (file to be created which changes size later -> logfiles) directory only accessible for this package

You can get additional information on a Solaris machine by


$ man -s4 prototype

4. Include options:
The include directive means that the specified file will be treated as a file vital to the package. The usual 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 installed before we can install our ARbc package. Types of dependancies are: DependancyType P I R Description Prerequisite (required package) Incompatible PKG (actual package to be installed cannot be installed due to incompatibilities to the named package) Reverse Dependancy (tells us that the package currently being installed is a prerequisite 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, but useful 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. to create 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. to stop a webserver.

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 execute checkinstall script and 3. gather 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 are required and not defined in the prototype file.

Back to our example


Now that we got all the files, we have to modify the newly created prototype file. First of all, save it to your 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 created prototype 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 compilation and installation run with the final location. Then we modify our prototype file to this:
i pkginfo=pkginfo 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 bin f none usr/local/bin/dc 0755 bin bin f none usr/local/info/bc.info 0644 bin bin f none usr/local/info/dc.info 0644 bin bin f none usr/local/man/man1/bc.1 0644 bin bin f none usr/local/man/man1/dc.1 0644 bin bin

In the former document about the pkginfo file, the variable BASEDIR defines the packaging - and later the installation root - to be "/", but our files are located somewhere else. The only solution to come around this problem is to do two compilation runs (you remember, I told you in the introduction). The first run for catching all files in a temporarily install location, the second for the final installation path. Although bc does really not need a bootskript as it is no daemon, we will include a dummy bootscript called bc_startup.sh, just as an example. But how will we be able to build a system PKG if we can't become superuser to copy the bootskript to /etc/init.d and create a symbolic link to /etc/rc3.d? The answer 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 the following 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

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 listed first! 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/local directory 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>*.sh do . $script done ...

Bootscripts not ending with ".sh" are treated as shell skripts and are therefore executed. (If you are interested in, where in the init bootprocess this happens, take a look at /sbin/rcS and search for a similar 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=pkginfo 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 bin f none usr/local/bin/dc 0755 bin bin

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

5. Creating installation/remove scripts


PROBLEM: During a Solaris installation - either by cdrom or jumpstart - the local harddisks/partitions are mounted at a read-writable mount point called "/a". The running Solaris itself is mounted readonly by NFS. Equally, the BASEDIR variable is also set to "/a". "/a" therefore is the location where all packages to be installed will be written to. If you have this in mind, then you will understand why I strongly 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-only in memory, a PKG containing /usr/local in its pkgmap will fail to install as the files _cannot_ be installed in "/"! Therefore any installation script using special shell commands like useradd, groupadd, mkdir or any other 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. 2. 3. 4. 5. 6. request checkinstall preinstall postinstall preremove postremove

6. Differences between installation/procedure scripts


There 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) exists somewhere on the harddisk. They can gather data from the system (checkinstall) or the administrator (request). They can modify global variables like CLASSES, so only certain files will be installed.

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

7. Package environment variables available to all scripts


Variable name Description

The base directory with respect to the target system. While BASEDIR is the variable CLIENT_BAS to use if referring to a package on the cdrom/ install server, this variable is the path EDIR to include in files placed on the client system. INST_DATADI The directory where the package now being read is located. R The search list used by sh to find commands on script invocation. PATH The instance identifier of the package being installed. PKGINST The directory where files can be saved for use by removal scripts or where PKGSAV previously saved files can be found. PKG_INSTAL 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. L_ROOT PKG_NO_UNI Is an env variable that gets set if the pkgadd/pkgrm command is invoked with the -R -M option. FIED This 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 and UPDATE architecture is already installed on the system or that the installing PKG will overwrite 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.

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 an automated package install will maybe result in a partially installed package or the jumpstart mechanism will halt until an administrator gives the right answer. The only solution is to provide default 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 noninteractive 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/sh REALNAME="" echo "Enter your realname: " read REALNAME # export REALNAME to global PKG environment cat >> $1 << EOT REALNAME=${REALNAME} EOT

Doing like this will make the variable REALNAME and its content available to the following installation/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 the temporarily 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 modify environment variables in order to control the course of the resulting installation. It is also capable of halting cleanly the installation process. The checkinstall script is intended to perform basic checks on a file system that would not be normal for the pkgadd command. For example, it can manage general software dependancies, in contradiction 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.

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 installed pkginfo -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 fi else BASHROOT="`pkgparam ARbash1 BASEDIR`/usr/local/bin" # old one fi # Now look for the bash executable we will need for our silly bootscript if [ $BASHROOT/bash ] then exit 0 # all OK else echo "No bash executable can be found. Please check your bash" echo "package for integrity and try this installation again." exit 3 # Suspend fi

9. Procedure scripts
Procedure scripts provide a set of instructions to be performed at particular point in package installation or removal. Of course there are also restrictions which apply to procedure scripts as well as 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 command to 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:

#!/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 directory cd ${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 relative commandline syntax, e.g. with a ${BASEDIR} as prefix. Honestly, I never saw a package removal during Solaris installation. Additionally I think that package removal _has_ to be done interactively.

10. Writing class action scripts


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

Defining classes
Classes can be only defined in two files: the CLASSES variable in the pkginfo file and by assigning certain files to this predefined class in the prototype file. Then pkgadd/pkgrm will create a file list containing all these files during an installation/removal and invoke the class action scripts with the file list as 1st parameter. Class names can be freely defined except for the following exceptions: Class Description Provides a method for using sed instructions to edit files upon package installation sed and removal. Provides a method for using awk instructions to edit files upon package awk installation and removal. Provied a method to dynamically construct or modify files using Bourne shell build commands. preserv Provides a method to preserve files that should not be overwritten by future package installations. e 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 awk system class.

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 to make:
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 file which belongs to the class "awk". The third entry tells us it is a file located in /tmp which contains the awk commands. Irritating, isn't it? We want to _modify_ an existing file and not placing a new file with awk commands there! As the /tmp/dummy.conf can't contain any awk commands, we place a awk command file _over_ it. The commands in this file will be then applied to the file it covers. It's like a hat you put on your head. A _very important_ information I gave to you when explaining the prototype file syntax will now be useful 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 file like 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 as tmp/dummy.conf and during installation/removal the script will be then applied to the dummy.conf file. Now we are half on our way to Chicago, folks :). The next part is the syntax of the script. This is quite simple and looks like this:
!install # awk program to install changes BEGIN { } END { print "Installing..."; } !remove # awk program to remove changes BEGIN { } { } print "Removing...";

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

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

The "build" class


The "build" class is used to create _and_ modify a package object file by executing Bourne shell instructions. 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 creator if [ -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/dummy fi !remove # dummy file deconstructor if [ -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 fi fi

The "preserve" class


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

If the file to be installed does not already exist in the target directory, the file will be installed normally. If the file to be installed exists in the target directory, a message describing the file exists is displayed and the file is not installed.

An example of a preserve class action script would be:


error=no echo "## checking common configuration files" while read src dest do [ "$src" = /dev/null ] && continue if [ -f "$dest" ] then echo $dest preserve

else fi

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

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

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

12. Creating class action scripts with own classes


You 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.manpage i 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 install the file. The pkgadd command does not install files for which a class action script exists, although it does verify the installation. And, if you define a class but do not deliver a class action script, the only action taken for that class is to copy components from the installation medium (a package) to the target system (the default pkgadd behaviour).

13. Creating a package


Whoa! The last two chapters were hard stuff to read, so I think we continue with our example of the binary calculator. First I want to explain to you, which commands we will need: Command /bin/pkgpr oto /bin/pkgmk /bin/pkgtra ns /bin/pkgck eck Description This command creates a basic prototype file with all entries we need. This generic prototype file has to be edited later to include further pkg information files. This command creates the package. This command is used to transfer packages from the directory format to a package file. This command is used to check the integrity of a package

If you remember, our pkginfo file looks like this:


PKG=ARbc NAME="bc - a binary calculator" ARCH=sparc VERSION=1.0.6 CATEGORY=utility DESC="bc - a binary commandline calculator often used in shellscripts for calculating" VENDOR="(C) 2002 Garex Inc." VSTOCK="123456" HOTLINE="+49-123456-TOLL-FREE" EMAIL="garex@garex.net" BASEDIR=/ MAXINST=1 INTONLY=1 CLASSES=application none ISTATES="S 2 3" RSTATES="S 2 3" PSTAMP="20020718 19:35" ULIMIT=20 ORDER=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 bin f none usr/local/info/dc.info 0644 bin bin f none usr/local/man/man1/bc.1 0644 bin bin f none usr/local/man/man1/dc.1 0644 bin bin

14. Completing the prototype file


There are several lines are missing for our package. The include of the pkginfo file, usually located in the same directory as the prototype file, the line for our simple, but useless bc bootscript and its symbolic 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 other s none etc/rc3.d/S99bc_startup=../init.d/bc_startup

So our final prototype looks like this:


i pkginfo d 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 bin f none usr/local/bin/dc 0755 bin bin f none usr/local/info/bc.info 0644 bin bin f none usr/local/info/dc.info 0644 bin bin f none usr/local/man/man1/bc.1 0644 bin bin f none usr/local/man/man1/dc.1 0644 bin bin f none etc/init.d/bc_startup=bc_startup 0755 root other s 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 be included 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 to less diskspace. Adding /opt as of type d then results in replacing the symbolic link /opt with a real directory called /opt, which will be created in "/" and your package may be not installed, if "/" has not enough disk space!

15. The Packaging Commands The pkgmk command


Assuming 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 Overwrites an existing package instance in the PKG spool directory /var/spool/pkg. -o Useful if you are testing PKG creation techniques for the first time. -r <rootBy using this option, you override the default destination paths defined in the prototype file path> Prepend the indicated base_src_dir to locate relocatable objects on the source -b machine. <base_src_ Instead of including all files in the prototype file as <dst>=<src>, you can tell pkgmk dir> where 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 command


Now we created our ARbc package. Finally, we have to verify its integrity with
$ cd /var/spool/pkg $ pkgchk -vd . ARbc Checking uninstalled directory format package <ARbc> from </var/spool/pkg> ## Checking control scripts. ## Checking package objects. etc/init.d/bc_startup pkginfo usr/local/bin/bc usr/local/bin/dc usr/local/info/bc.info

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

If no errors were found, your package is fine.

The pkgtrans command


Finally as a gimmick we transfer the package directory to a package file, which is easier to transfer to remote hosts:
$ pkgtrans /var/spool/pkg /tmp/ARbc-1.0-sol8-test ARbc Transferring 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 ARbc Transferring package instance $ ls -ld /tmp/ARbc drwxr-xr-x 3 garex staff 306 Jul 22 19:29 /tmp/ARbc

Doing a testinstallation
Now 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

You might also like