Thursday, March 13, 2008

Creating Solaris Pkg Files From Already Installed Packages

pkgremk CSWtop package install output

Please click above for a larger resolution version of the sample output shown.

Hey again,

For today, I put together a shell script, in ksh, to create new Solaris pkg files from already installed packages. The motivation for this sometimes seems hard to explain since you generally don't really "need" to have packages of any software that's installed on your system. It's there already; plus you probably have the install CD or a JumpStart server sitting around somewhere on your network with the original installation packages on them, right?

Other options we've looked at in previous posts include using pkg-get to help you out in a pinch and, if you have the means, creating your own packages from source quickly and making them the long, hard old-fashioned way. For today, we're going to assume none of these avenues are available to you.

I've found that, on more than several occasions, I've been stuck on a machine which needed a package installed and been out-of-luck on both counts (No software CD's and no Network Install Server). And some packages are hard to come by, like some of the obscure, but almost absolutely necessary, Solaris system packages like SUNWexplo. Well, okay, you don't really "need" to have Sun Explorer installed on your machine either, but it's usually the first output Sun's phone support requests you send them, so let's just pretend it's essential for argument's sake ;)

With today's script (called, simply, pkgremk <--- Slight homage to pkgmk since we're remaking the packages ;) you can take any pkg that's installed on your Solaris system and create a perfectly valid datastream package for use on any other machine of suitably similar or compatible architecture and/or Solaris Unix version.

So, for example, if you found yourself in a situation where you were stuck without Sun's Explorer to gather evidence on your Solaris 9 box, you needed to run it to send to Sun support and you had it on a second Solaris 9 box, you could run pkgremk on the second box, transfer the pkg from the second box to the first, install Explorer and run it right then and there! Kind of like this (Glossing over tons of little things here ;)

host b # ./pkgremk SUNWexplo
host b # scp SUNWexplo.pkg hosta:/home/user1/.

host a # pkgadd -d /home/user1/SUNWexplo.pkg
host a # /opt/SUNWexplo/bin/explorer
<--- And the data collection begins.

It's really pretty much that simple. The only things the pkgremk script requires are that you already have the software installed on the server that you want to "remake" the package on, and that you pass it the exact package name as the only argument on the command line (you can find this information out easily by either doing an ls of the /var/sadm/pkg directory or just running pkginfo with no arguments).

I tried to take into account all parts of the pkg making process and accounted for getting all the package file names, types and ownership/permission information from /var/sadm/install/contents, as well as all the pkginfo, dependency and installation files in /var/sadm/pkg and playing with those so that you could, literally, type one quick command line and create any package you need to replicate on your machine, for whatever reason, and be able to use it just about anywhere else (On Solaris, of course - I'll be doing this for Linux soon, as well :) The finished product should be easy to move around since we use pkgtrans to make it a single file datastream format package, rather than a directory structure that you'd have to tar up and mess around with. Basically, you're going to be getting a Sun standards-compliant pkg software distribution file!

This script could be nice for insurance purposes, as well. If, for instance, you weren't sure you wanted to remove the CSWtop package. If you didn't have the pkg file you got originally, you could just create it on the fly and then re-install from that new package if you found you really did need it, like so:

host # ls -d /var/sadm/pkg/CSWtop
host # ./pkgremk CSWtop
<--- See the picture above for the full command output
host # ls
CSWtop.pkg CSWtop_mk.12473.out
host # pkgrm CSWtop
Removal of <CSWtop> was successful.
host # top
bash: top: command not found
<--- For our example's sake, you've just realized how desperately you need top ;)
host # pkgadd -d CSWtop.pkg <--- or "pkgadd -d /full/path/to/CSWtop.pkg" if you're not in the same directory as the package.

A few keystrokes, and you're back in business :) I hope this script helps you out and you can find even more good uses for it!

Best wishes,

Creative Commons License

This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License


# pkgremk - Create pkgs from existing installations on Solaris
# 2008 - Mike Golvach -
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

trap 'cd $orig_pwd;rm -rf $tmp_dir;rm -rf ${pkgname}_mk.out;exit' 1 2 3 9 15

if [ $# -ne 1 ]
echo "Usage: $0 PKGname"
echo "Package must be installed on system"


if [ ! -d /var/sadm/pkg/$pkgname ]
echo "$pkgname does not exist in the pkg repository. Exiting..."


if [ -d $tmp_dir ]
echo "Removing existing temp dir"
rm -r $tmp_dir
echo "Creating temp work directory..."
mkdir $tmp_dir

cd $tmp_dir

echo "Copying over \"install\" directory"
(cd /var/sadm/pkg/$pkgname;tar cpf - install)|tar xpf -

echo "Copying over pkginfo file"
cp /var/sadm/pkg/$pkgname/pkginfo .

if [ -f prototype ]
rm prototype

echo "Deriving new prototype file"
echo "Generating includes"
if [ -f pkginfo ]
echo "i pkginfo" >>prototype
echo "pkginfo disappeared. Package will not build. Exiting..."

cd install
ls -1d * 2>/dev/null|while read line
echo "i $line"
echo "i $line" >>../prototype
mv $line ../

cd ..

if [ -d install ]
echo "Removing install directory"
rm -r install

grep $pkgname /var/sadm/install/contents |cut -d' ' -f 1,2,3,4,5,6|awk '{print $2 " " $3 " " $1 " " $4 " " $5 " " $6}'>>prototype

orig_basedir=`grep BASEDIR pkginfo|awk -F"=" '{print $2 "/"}'`
old_basedir=`grep BASEDIR pkginfo|awk -F"=" '{print $2 "/"}'|sed 's/\//\\\\\//g'`
if [ $orig_basedir = "//" ]
if [ $old_basedir = "\/\/" ]

echo "Stripping pathnames to compensate for BASEDIR=$orig_basedir"
echo "directive in pkginfo file"
sed "s/$old_basedir//" prototype >>$this_temp
mv $this_temp prototype

echo "Removing non-pkginfo/pkgmap lines from prototype"
awk '{ if ( $1 ~ /^[ifcsd]/ ) print $0}' prototype >>$that_temp
mv $that_temp prototype

echo "Creating distributable pkg from existing files as ${pkgname}.pkg"
echo "Output of pkgmk command dumping to ${pkgname}_mk.out"
/usr/bin/pkgmk -b $orig_basedir -d /tmp >${orig_pwd}/${pkgname}_mk.$$.out 2>&1
cd ..
echo "Transferring package to datastream format"
if [ -f `pwd`/${pkgname}.pkg ]
echo "Found existing `pwd`/${pkgname}.pkg file"
echo "Copying to `pwd`/${pkgname}.pkg.$tmp_pid"
mv `pwd`/${pkgname}.pkg `pwd`/${pkgname}.pkg.$tmp_pid
/usr/bin/pkgtrans -s /tmp `pwd`/${pkgname}.pkg $pkgname
rm -r /tmp/$pkgname

echo "Done!"
cd $orig_pwd
rm -rf $tmp_dir

, Mike