18 October 2010

Rebuilding a Solaris Package

Have you ever needed to rebuild a package already installed on a Solaris
host?  Though it may seem to be a rare case, I've had to do this several
times in the past and have yet to find any clear information on it.
A recent instance was where a primary host had a piece of software
installed, though its peer did not.  Since the software revision was
older, it was determined to be safer to use the same software revision.
Unfortunately, the only guaranteed location of that software was the
installed version on the primary host.  The following details the process
involved for a simple package, wherein we have no care for any pre or
post install scripts, etc.  While one could go about simply copying the
appropriate files over to the secondary host, by recreating the package,
we retain details such as file ownership, permissions, symlinks, and have
a clean means of install / deinstall for this and other hosts.  For the
point of example, we'll use package SMCwget.  The following steps were
performed on a Solaris 9, SPARC host, though the process should be the
same for any recent Solaris version or architecture.  As an aside, the
details below are similar to 'Package Builds in Solaris':

        http://troysunix.blogspot.com/2010/10/package-builds-in-solaris.html

which was based upon the notes of Steve Christensen and his work on

        http://sunfreeware.com

Additionally, the package used in the examples below, SMCwget, is available
from sunfreeware.com thanks to Steve's time and efforts.  Now back to the
package rebuild.

To start, create a directory in /tmp for holding our files, etc:

        server [0] /usr/bin/mkdir /tmp/repkg
        server [0] cd /tmp/repkg

Since the SMCwget package is already installed on 'server', use the
package database for information about the installed files:

        server [0] /usr/sbin/pkgchk -l SMCwget | /usr/bin/awk '/^Pathname:/{print $2}' >> file_list

        server [0] /usr/bin/cat file_list
        /usr/local/bin
        /usr/local/bin/wget
        /usr/local/doc
        /usr/local/doc/wget
        /usr/local/doc/wget/AUTHORS
        /usr/local/doc/wget/COPYING
        /usr/local/doc/wget/ChangeLog
        /usr/local/doc/wget/ChangeLog.README
        /usr/local/doc/wget/INSTALL
        /usr/local/doc/wget/MAILING-LIST
        <snip...>

Now that we have our list of 'SMCwget' files, we need to create a usable
input file (prototype) for use by the package creation commands:

        server [0] echo "i pkginfo=./pkginfo" >> prototype
        server [0] /usr/bin/cat file_list | /usr/bin/pkgproto | /usr/bin/sed -e 's/\ \/usr\/local\//\ /g' >> prototype
        server [0] /usr/bin/cat prototype
        i pkginfo=./pkginfo
        d none bin 0755 root bin
        f none bin/wget 0755 root bin
        d none doc 0755 root bin
        d none doc/wget 0755 root bin
        f none doc/wget/AUTHORS 0644 root bin
        f none doc/wget/COPYING 0644 root bin
        f none doc/wget/ChangeLog 0644 root bin
        f none doc/wget/ChangeLog.README 0644 root bin
        f none doc/wget/INSTALL 0644 root bin
        f none doc/wget/MAILING-LIST 0644 root bin
        <snip...>

Now we need to create the 'pkginfo' file which details various points of
information about the package, such as base install directory, vendor,
architecture, etc.  Since one basically already exists on this host,
we'll copy and modify it:

        server [0] /usr/bin/cp /var/sadm/pkg/SMCwget/pkginfo .
        server [0] /usr/bin/cat pkginfo
        CLASSES=none
        BASEDIR=/usr/local
        TZ=US/Eastern
        SUNW_PKG_DIR=/var/tmp/dstreAAA6UayxC/SMCwget
        PATH=/sbin:/usr/sbin:/usr/bin:/usr/sadm/install/bin
        OAMBASE=/usr/sadm/sysadm
        PKG=SMCwget
        NAME=wget
        ARCH=sparc
        VERSION=1.10.2
        CATEGORY=application
        VENDOR=Free Software Foundation
        EMAIL=steve@smc.vnet.net
        PSTAMP=Steve Christensen
        PKGINST=SMCwget
        PKGSAV=/var/sadm/pkg/SMCwget/save
        INSTDATE=Mar 14 2007 09:45

We need to cut out some of the contents of the copied 'pkginfo' file and
quote the values contained.  The only values that we need to retain are:

        CLASSES, BASEDIR, PKG, NAME, ARCH, VERSION, CATEGORY, VENDOR,
        EMAIL, PSTAMP

After editing, the file contents should appear as such:

        CLASSES="none"
        BASEDIR="/usr/local"
        PKG="SMCwget"
        NAME="wget"
        ARCH="sparc"
        VERSION="1.10.2"
        CATEGORY="application"
        VENDOR="Free Software Foundation"
        EMAIL="steve@smc.vnet.net"
        PSTAMP="Steve Christensen"

With the package now setup, lets begin creating it:

        server [0] /usr/bin/pkgmk -r /usr/local
        ## Building pkgmap from package prototype file.
        ## Processing pkginfo file.
        ## Attempting to volumize 39 entries in pkgmap.
        part  1 -- 3112 blocks, 43 entries
        ## Packaging one part.
        /var/spool/pkg/SMCwget/pkgmap
        /var/spool/pkg/SMCwget/pkginfo
        /var/spool/pkg/SMCwget/reloc/bin/wget
        /var/spool/pkg/SMCwget/reloc/doc/wget/AUTHORS
        /var/spool/pkg/SMCwget/reloc/doc/wget/COPYING
        /var/spool/pkg/SMCwget/reloc/doc/wget/ChangeLog
        /var/spool/pkg/SMCwget/reloc/doc/wget/ChangeLog.README
        /var/spool/pkg/SMCwget/reloc/doc/wget/INSTALL
        /var/spool/pkg/SMCwget/reloc/doc/wget/MAILING-LIST
        /var/spool/pkg/SMCwget/reloc/doc/wget/NEWS
        /var/spool/pkg/SMCwget/reloc/doc/wget/PATCHES
        /var/spool/pkg/SMCwget/reloc/doc/wget/README
        /var/spool/pkg/SMCwget/reloc/doc/wget/README.checkout
        /var/spool/pkg/SMCwget/reloc/doc/wget/TODO
        /var/spool/pkg/SMCwget/reloc/doc/wget/doc/ChangeLog
        /var/spool/pkg/SMCwget/reloc/doc/wget/doc/Makefile
        /var/spool/pkg/SMCwget/reloc/doc/wget/doc/Makefile.in
        /var/spool/pkg/SMCwget/reloc/doc/wget/doc/ansi2knr.1
        /var/spool/pkg/SMCwget/reloc/doc/wget/doc/fdl.texi
        /var/spool/pkg/SMCwget/reloc/doc/wget/doc/gpl.texi
        /var/spool/pkg/SMCwget/reloc/doc/wget/doc/sample.wgetrc
        /var/spool/pkg/SMCwget/reloc/doc/wget/doc/sample.wgetrc.munged_for_texi_inclusion
        /var/spool/pkg/SMCwget/reloc/doc/wget/doc/texi2pod.pl
        /var/spool/pkg/SMCwget/reloc/doc/wget/doc/texi2pod.pl.in
        /var/spool/pkg/SMCwget/reloc/doc/wget/doc/texinfo.tex
        /var/spool/pkg/SMCwget/reloc/doc/wget/doc/version.texi
        /var/spool/pkg/SMCwget/reloc/doc/wget/doc/wget.1
        /var/spool/pkg/SMCwget/reloc/doc/wget/doc/wget.info
        /var/spool/pkg/SMCwget/reloc/doc/wget/doc/wget.pod
        /var/spool/pkg/SMCwget/reloc/doc/wget/doc/wget.texi
        /var/spool/pkg/SMCwget/reloc/etc/wgetrc
        /var/spool/pkg/SMCwget/reloc/info/wget.info
        /var/spool/pkg/SMCwget/reloc/man/man1/wget.1
        ## Validating control scripts.
        ## Packaging complete.

The 'pkgmk' command above stages the package to /var/spool/pkg/SMCwget.
To build the package, cd to /var/spool/pkg and run 'pkgtrans':

        server [0] /bin/ls
        SMCwget
        server [0] pkgtrans -s `pwd` /tmp/SMCwget-1.10.2

        The following packages are available:
          1  SMCwget     wget
                         (sparc) 1.10.2

        Select package(s) you wish to process (or 'all' to process
        all packages). (default: all) [?,??,q]: 1
        Transferring <SMCwget> package instance

Our rebuilt SMCwget package is now available for use.  The following is
just verification and cleanup of our work:

        server [0] cd /tmp
        server [0] /bin/ls
        SMCwget-1.10.2          repkg
        server [0] /usr/bin/head -3 SMCwget-1.10.2
        # PaCkAgE DaTaStReAm
        SMCwget 1 3112
        # end of header
        server [0] /usr/bin/gzip SMCwget-1.10.2
        server [0] /usr/bin/rm -r repkg
        server [0] /bin/ls
        SMCwget-1.10.2.gz