What follows are step by step instructions on creating your own Solaris packages. There are many reasons why you'd want to do this. I use the technique to roll administrative scripts out to a large number of servers. Using packages ensures that a consistent set of tools are maintained across all of the Solaris servers that I administer. I will use a simple example here, where the package will comprise of only a few files. Your packages can be as complex, or as simple, as your requirements dictate.
As always, the notes here are _very_ terse. Consult the manual pages for the various commands and file formats if you do not understand something. The best Unix documentation is the documentation available within Unix itself! So, assuming that you know what you're doing, let us begin....
We are going to be creating a package called ZBOButils. It is convention that package names are comprised of a four-letter uppercase company identifier, followed by a lower-case package identifier. The files I will be packaging are located on one of my servers under /usr/local/zb. Take a look at the following output...
# cd /usr/local
# ls -lR zb
zb:
total 6
drwxr-xr-x 2 root root 512 Jan 11 21:55 bin
drwxr-xr-x 2 root root 512 Jan 11 21:55 etc
drwxr-xr-x 2 root root 512 Jan 11 21:56 lib
zb/bin:
total 2
-rwxr-xr-x 1 root root 59 Jan 11 21:55 backup.sh
zb/etc:
total 2
-rw-r--r-- 1 root root 34 Jan 11 21:55 backup.conf
zb/lib:
total 2
-rw-r--r-- 1 root root 100 Jan 11 21:56 backup.lib
First, I will create a temporary work space. I like to place this kind of stuff under /export somewhere.
# mkdir -p /export/pkg/tmp
# cd /export/pkg/tmp
Next we create our reloc directory, as this is a relocatable package. We will be placing the files we wish to form part of the package in this directory.
# mkdir reloc
# ls -l
total 2
drwxr-xr-x 2 root root 512 Jan 11 21:57 reloc
In the root of our /export/pkg/tmp area, create your pkginfo file. If you don't know what's meant to go in here, man -s4 pkginfo. Also, if you don't like editing on the fly with cat, (shame on you ;-p), use vi!
# cat > pkginfo
PKG=ZBOButils
NAME=Package Creation Demonstration
ARCH=intel
VERSION=1.0.0
MAXINST=1
CATEGORY=application
DESC=A basic package to show how to make packages under Solaris
VENDOR=zazzybob
HOTLINE=Email zazzybob
EMAIL=kevin@zazzybob.com
CLASSES=none
BASEDIR=/usr/local/zb
^D
Obviously the ^D above is interpreted as EOF when using cat like this. Next, we cd into the directory containing our target files, and cpio them into our reloc directory.
# cd /usr/local/zb
# find . -depth -print | cpio -pvdum /export/pkg/tmp/reloc
/export/pkg/tmp/reloc/bin/backup.sh
/export/pkg/tmp/reloc/bin
/export/pkg/tmp/reloc/etc/backup.conf
/export/pkg/tmp/reloc/etc
/export/pkg/tmp/reloc/lib/backup.lib
/export/pkg/tmp/reloc/lib
/export/pkg/tmp/reloc/.
48 blocks
Okay, with that done we can create our prototype file that we will use to create our pkgmap. (man -s4 pkgmap - you get the idea...)
# cd /export/pkg/tmp
# ls
pkginfo reloc
# pkgproto reloc=. > prototype
# cat ./prototype
d none bin 0755 root root
f none bin/backup.sh=reloc/bin/backup.sh 0755 root root
d none etc 0755 root root
f none etc/backup.conf=reloc/etc/backup.conf 0644 root root
d none lib 0755 root root
f none lib/backup.lib=reloc/lib/backup.lib 0644 root root
You'll notice that the pkgproto command has been used here to create the basic prototype file for the reloc directory only. It hasn't included our pkginfo file. No worries, we'll add the entry for that ourselves....
# echo "i pkginfo=./pkginfo" >> ./prototype
# cat ./prototype
d none bin 0755 root root
f none bin/backup.sh=reloc/bin/backup.sh 0755 root root
d none etc 0755 root root
f none etc/backup.conf=reloc/etc/backup.conf 0644 root root
d none lib 0755 root root
f none lib/backup.lib=reloc/lib/backup.lib 0644 root root
i pkginfo=./pkginfo
Now that is done, we can use pkgmk to start the package creation process using our prototype file.
# pkgmk -d /export/pkg -f prototype
## Building pkgmap from package prototype file.
## Processing pkginfo file.
WARNING: parameter <PSTAMP> set to "kitekat20060111220411"
## Attempting to volumize 6 entries in pkgmap.
part 1 -- 16 blocks, 8 entries
## Packaging one part.
/export/pkg/ZBOButils/pkgmap
/export/pkg/ZBOButils/pkginfo
/export/pkg/ZBOButils/reloc/bin/backup.sh
/export/pkg/ZBOButils/reloc/etc/backup.conf
/export/pkg/ZBOButils/reloc/lib/backup.lib
## Validating control scripts.
## Packaging complete.
# pwd
/export/pkg/tmp
# cd ..
# ls
ZBOButils tmp
# cd ZBOButils
# ls
pkginfo pkgmap reloc
We can now see that pkgmk has filled in the appropriate size and checksum information for the pkginfo file we tacked onto the end of pkginfo itself earlier...
# cat pkgmap
: 1 16
1 d none bin 0755 root root
1 f none bin/backup.sh 0755 root root 59 4651 1136976910
1 d none etc 0755 root root
1 f none etc/backup.conf 0644 root root 34 3179 1136976958
1 d none lib 0755 root root
1 f none lib/backup.lib 0644 root root 100 0 1136976983
1 i pkginfo 298 25020 1136977451
Create an install directory. In here you can place {post,pre}{install,remove} scripts, and a copyright file.
# pwd
/export/pkg/ZBOButils
# mkdir install
First we'll create the copyright file that pkgadd will display in all it's glory when we finally install the package on a box...
# cat > install/copyright
**********************************************************
* (C) 2006 Zazzybob.com - ZBOButils - Pointless Package! *
* Released under the terms of the GNU GPL... *
**********************************************************
^D
Our ZBOButils package contains a backup script. We'd like to have an entry added to the root crontab to have this executed every day at 00:15. It's easy with a postinstall script. We'll also create a postremove script so that the entry will be removed if (shock horror) somebody wants to pkgrm our package.
# cat > install/postinstall
#! /bin/ksh
# postinstall script for ZBOButils
crontab -l | grep -v "backup\.sh" > /tmp/crontab.$$
echo "15 0 * * * /usr/local/zb/bin/backup.sh >/dev/null 2>&1" >> /tmp/crontab.$$
crontab /tmp/crontab.$$
rm -f /tmp/crontab.$$
echo "Entry added to root crontab for backup.sh"
exit 0
^D
# cat > install/postremove
#! /bin/ksh
# postremove script for ZBOButils
crontab -l | grep -v "backup\.sh" > /tmp/crontab.$$
crontab /tmp/crontab.$$
echo "backup.sh entry removed from root crontab"
exit 0
^D
Now we can enter the install directory, and get filesize and checksum information to append onto our pkginfo file.
# cd install
# sum *
13598 1 copyright
23237 1 postinstall
15376 1 postremove
# cksum *
454008271 236 copyright
4021934073 282 postinstall
3587409693 178 postremove
# echo "1 i copyright 236 13598 454008271" >> ../pkgmap
# echo "1 i postinstall 282 23237 4021934073" >> ../pkgmap
# echo "1 i postremove 178 15376 3587409693" >> ../pkgmap
Let's check our pkginfo file as we're nearing the final packaging...
# cat ../pkgmap
: 1 16
1 d none bin 0755 root root
1 f none bin/backup.sh 0755 root root 59 4651 1136976910
1 d none etc 0755 root root
1 f none etc/backup.conf 0644 root root 34 3179 1136976958
1 d none lib 0755 root root
1 f none lib/backup.lib 0644 root root 100 0 1136976983
1 i pkginfo 298 25020 1136977451
1 i copyright 236 13598 454008271
1 i postinstall 282 23237 4021934073
1 i postremove 178 15376 3587409693
If everything looks good, we can now use pkgtrans to translate the package from its expanded format into a single package file.
# cd /export/pkg
# ls
ZBOButils tmp
# pkgtrans . /export/pkg/ZBOButils.pkg ZBOButils
Transferring <ZBOButils> package instance
And that's it - package created! Check it out with pkginfo...
# pkginfo -l -d ./ZBOButils.pkg
PKGINST: ZBOButils
NAME: Package Creation Demonstration
CATEGORY: application
ARCH: intel
VERSION: 1.0.0
BASEDIR: /usr/local/zb
VENDOR: zazzybob
DESC: A basic package to show how to make packages under Solaris
PSTAMP: kitekat20060111220411
HOTLINE: Email zazzybob
EMAIL: kevin@zazzybob.com
STATUS: spooled
FILES: 11 spooled pathnames
3 directories
1 executables
5 package information files
3 blocks used (approx)
We've now transferred the package to another server.
# cd /tmp
# ls
ZBOButils.pkg
Now, we can install the package. First, I'll create an admin file to remove some of the questions, but as the base directory isn't going to exist the first time the package is installed, it'll still nag...
# cat > /usr/local/local_admin
mail=
instance=unique
partial=nocheck
runlevel=quit
idepend=quit
rdepend=quit
space=quit
setuid=nocheck
conflict=nochange
action=nocheck
basedir=default
^D
# pwd
/tmp
# pkgadd -a /usr/local/local_admin -d ZBOButils.pkg all
rocessing package instance <ZBOButils> from </tmp/ZBOButils.pkg>
Package Creation Demonstration(intel) 1.0.0
**********************************************************
* (C) 2006 Zazzybob.com - ZBOButils - Pointless Package! *
* Released under the terms of the GNU GPL... *
**********************************************************
The selected base directory </usr/local/zb> must exist before
installation is attempted.
Do you want this directory created now [y,n,?,q] y
Using </usr/local/zb> as the package base directory.
## Processing package information.
## Processing system information.
## Verifying disk space requirements.
Installing Package Creation Demonstration as <ZBOButils>
## Installing part 1 of 1.
/usr/local/zb/bin/backup.sh
/usr/local/zb/etc/backup.conf
/usr/local/zb/lib/backup.lib
[ verifying class <none> ]
## Executing postinstall script.
Entry added to root crontab for backup.sh
Installation of <ZBOButils> was successful.
Our package has installed successfully! You will also have seen Entry added to root crontab for backup.sh. That was our postinstall script in action. Let's verify that it's worked...
# crontab -l | grep backup
15 0 * * * /usr/local/zb/bin/backup.sh >/dev/null 2>&1
Let's verify some more that we've actually installed our _own_ package!
# /usr/local/zb/bin/backup.sh
This could be a backup script!
# ls -l /usr/local/zb/bin/backup.sh
-rwxr-xr-x 1 root root 59 Jan 11 21:55 /usr/local/zb/bin/backup.sh
# pkginfo -l ZBOButils
PKGINST: ZBOButils
NAME: Package Creation Demonstration
CATEGORY: application
ARCH: intel
VERSION: 1.0.0
BASEDIR: /usr/local/zb
VENDOR: zazzybob
DESC: A basic package to show how to make packages under Solaris
PSTAMP: kitekat20060111220411
INSTDATE: Jan 11 2006 22:15
HOTLINE: Email zazzybob
EMAIL: kevin@zazzybob.com
STATUS: completely installed
FILES: 6 installed pathnames
3 directories
1 executables
3 blocks used (approx)
# ls -ld /var/sadm/pkg/ZBOButils
drwxr-xr-x 4 root root 512 Jan 11 22:16 /var/sadm/pkg/ZBOButils
Now that the initial excitement has ebbed away, let's remove the package - we're done with it now.
# pkgrm ZBOButils
The following package is currently installed:
ZBOButils Package Creation Demonstration
(intel) 1.0.0
Do you want to remove this package? [y,n,?,q] y
## Removing installed package instance <ZBOButils>
This package contains scripts which will be executed with super-user
permission during the process of removing this package.
Do you want to continue with the removal of this package [y,n,?,q] y
## Verifying package <ZBOButils> dependencies in global zone
## Processing package information.
## Removing pathnames in class <none>
/usr/local/zb/lib/backup.lib
/usr/local/zb/lib
/usr/local/zb/etc/backup.conf
/usr/local/zb/etc
/usr/local/zb/bin/backup.sh
/usr/local/zb/bin
## Executing postremove script.
backup.sh entry removed from root crontab
## Updating system information.
Removal of <ZBOButils> was successful.
It's gone. Let's verify that the postremove script done it's job...
# crontab -l | grep backup
# echo $?
1
All done!
So we've created our own package from scratch, created custom installation scripts for the post-install and post-removal actions, and verified that the whole thing works. As I mentioned at the start, there is no substitute for the manual pages as this article has only _just_ scratched the surface. Enjoy!
Cheers
Kevin Waldron
kevin@zazzybob.com
Disclaimer! - This article is provided for guidance only, and does not replace the relevant official documentation and manuals. I will not be held liable for any hosed systems and/or data.