NAME

build-pkg - A script to aid packaging


SYNOPSIS

build-pkg [-hivlomPKFRNT] [-C config] [-w work_dir] [-I cmd] [-n file] [-c category] [-p name] [-u user] [-g group] [-y args] [-U src:dst[, ...]] [-G src:dst[, ...]] [-V version] [-O file] [cmd ...]


OPTIONS

Supported options are:

-h
Display usage information

-i
Only ask the questions required to build the pkginfo file if that is required.

-v
Verbose; show commands run by this program

-l
Leave all build files in place; by default the directory package created by pkgmk is removed.

-o
Use the actual ownership of the files and directories in the build directory and not the defaults of root for the owner and bin for the group.

This is useful if you are building a package where the software concerned makes use of setuid, setuid components, directories owned by non-root users, etc.

-m
Use the actual permissions of the files and directories in the build directory and do not play around with the permissions

This is useful if you are building a package where the software concerned makes use of setuid, setuid components, directories owned by non-root users, etc.

-P
We are not dealing with a perl module, even if the blib directory exists under the current working directory.

-K
Instruct chroot-install that it should clean the build directory before performing any work. See the -S option to chroot-install for more details.

-F
Instruct chroot-install that it should fix the file permissions it finds. See the -F option to chroot-install for more details.

Note that if chroot-install is not called - i.e. the InstallPackage/build directory is already built - then this option instructs build-pkg to fix the directory permissions directly.

-R
Generate a relocatable package. Please see the notes later on this topic.

-N
Do not run chroot-install, even if build-pkg thinks that it should be run. This is most useful if you are attempting to build a package which consists solely of package control scripts like postinstall, postremote, etc.

-T
Do not run template-control to process any package control script template files.

-V version
Set the VERSION string held within the pkginfo file. Useful if you re-use a pkginfo file for a new version of the software.

-C config
The configuration file to use. By default we look in $HOME/.build-pkg This file has a relatively simple format. Lines starting with a # or which are blank (no characters or all spaces) are ignored. All other lines have the format of:
  key = value

Where valid keys are:

  +-------------+-----------------------------------------+
  |    Key      | Value should be...                      |
  +-------------+-----------------------------------------+
  | PkgPrefix   | Prefix to the package name              |
  | BaseDir     | The base directory                      |
  | PerlBaseDir | The base directory for perl modules     |
  | Category    | The category prefix                     |
  | Vendor      | Vendor name                             |
  | Class       | Class of package                        |
  | Email       | EMail address of package builder        |
  | Name        | Name of the package builder             |
  | WaitTime    | Time to wait after an error has occured |
  +-------------+-----------------------------------------+

-w work_dir
The work directory were everything happens. The final package will be found here. The default is $PWD/InstallPackage

-I cmd
The name/location of the chroot-install command; this can be a command name which is on the PATH. The default is chroot-install

-n file
The final name of the package. This may contain macros which will be expanded. The format of these macros are ``%[pkginfo variable]%''. eg %PKG%. The default is %PKG%-v%VERSION%-sol%OSVER%-%ARCH%.pkg.

-c category
Set the category for the package directly. Note that this ensures that the given category will contain the category ``application'' or ``system''. If neither is present then the category of ``application'' is added.

-p name
Set the package name directly

-u user
Ensure that entries are owned by the given user. The user has to exist in /etc/passwd. Numeric UIDs can not be given.

-g group
Ensure that entries are owned by the given group. The group has to exist in /etc/group. Numeric GIDs can not be given.

-y args
Command line arguments to pass to chroot-install. This allows you to pass specific arguements to chroot-install like the -d and -l options. Remember that you'll have have to surround such options with quotes so that build-pkg does not view them as options to itself.

Note that this differs from the passing of a command with options to be run by chroot-install as you can not pass options for chroot-install itself in this way.

Thus if you wanted to copy the directory /foo/bar into the chroot()ed area then you could use:

  build-pkg -y '-d /foo/bar' make install

To get the required effect.

-U src:dst[, ...]
A comma separated list of users to change. The user given in src will be mapped to the username given in dst. Thus if you specify:
  -U root:bin,adm:nobody

Then any files owned by root will be shown as being owned by bin and any files owned by adm will be shown as being owned by nobody.

-G src:dst[, ...]
A comma separated list of groups to change. The group given in src will be mapped to the group given in dst. Thus if you specify:
  -U other:bin,sys:bin

Then any files in the groups other or sys will be placed in the group bin.

-O file
Specify an overlay file which is used to over ride lines in the prototype file generated by build-pkg. Please see the section titled ``HANDLING OF SYSTEM DIRECTORIES AND USING OVERLAY FILES'' for more details on this option.

cmd ...
Commands to be passed verbatim to chroot-install; i.e.:
  build-pkg make install

Note that if you do not specify a command then you will be dropped into a shell running within the chroot()ed environment.


DESCRIPTION

This script is designed to help build a Solaris package using a combination of the Solaris packaging tools and chroot-install.

It works by performing the following:

At the end of the above the package will be in the work directory as a single file. With the default options you will see, relative to the current working directory, the following file:

    InstallPackage/%PKG%-v%VERSION%-%ARCH%.pkg

Where the values surrounded by % signs are macros set for the current package. Thus if the package has a name of SomePackage, with a version of 1.0.2 and was built in the SPARC architecture then the name would be:

    InstallPackage/SomePackage-v1.0.2-sparc.pkg

This package is suitable for adding to a system by using the following command line:

    # pkgadd -d InstallPackage/SomePackage-v1.0.2-sparc.pkg

Note that to run pkgadd you have to be the root user.


EXAMPLE

Whilst it looks complex from the outside, build-pkg is relatively simple to use in day-to-day usage.

For example to create a package for gcc and friends (i.e. gcc, g++, g77, etc) under Solaris 8 all I did was to:

o
Get hold of gcc version 3.0.3

o
Ensure that I had GNU make installed from the Companion CD and that it was available at /opt/sfw/bin/gmake. Note that you could always use the -x option to chroot-install to copy GNU make into the chroot environment.

o
Build the gcc package as normal

o
Type the following command:
  % simple-proj

Whilst not an essential command, this will prepare an InstallPackage directory and place a number of package script files within it. Currently these are postinstall and postremove scripts which will re-build the manual page windex in the /usr/local/man manual tree.

Doing this will ensure that any manual pages installed by the package will be available immediately after package installation.

o
Type the following command:
  % build-pkg -c gnu -p GNUgcc -F gmake install

In the top level directory of gcc. After answering questions relating to the contents of the pkginfo file, build-pkg went away and built the package for me.

The use of the -c option to add ``gnu'' to the package category and -p to make the package name default to ``GNUgcc'' are due to specific settings in my $HOME/.build-pkg file. However even if you do not have a .build-pkg file it is useful to specify these on the command line

Note that the -F option to build-pkg is to ensure that all of the files installed by gcc have the correct permissions; there are a number of include files installed by gcc which end up with a file mode of 0600 even when a file creation mask (aka the umask) of 022 is used.

o
Became root and typed in:
  # pkgadd -d InstallPackage/GNUgcc-v3.0.3-i386.pkg GNUgcc

And watched whilst the package was installed.


DEALING WITH PROBLEMS

Sometimes even the installation of software will have strange dependancies; for example perl 5.6.1 has a dependancy on the gcc specific file float.h. Thus when the attempt to build the package was made using just:

  % build-pkg make install

The following was in the output returned by the make install run by chroot-install:

  chroot-install: chroot()ing to /home/software/compiled/perl-5.6.1/perl-5.6.1/InstallPackage/build
  make install.perl install.man STRIPFLAGS=
  make[1]: Entering directory `/home/software/compiled/perl-5.6.1/perl-5.6.1'
  make[1]: *** No rule to make target `/usr/local/lib/gcc-lib/i386-pc-solaris2.8/3.0.3/include/float.h', needed by `miniperlmain.o'.  Stop.
  make[1]: Leaving directory `/home/software/compiled/perl-5.6.1/perl-5.6.1'
  make: *** [install] Error 2
  chroot-install: Cleaning up random files

The solution to this was to mount /usr/local/lib/gcc-lib/ into the chroot()ed area. This can be done by using the -y flag to build-pkg to pass chroot-install its -l flag which is used to specify additional directories to mount via lofs. Thus the command line used was:

  % build-pkg -y '-l /usr/local/lib/gcc-lib/' make install

Which made make happen and thus allowed the installation to finish.


CUSTOMIZATION

The packages which are produced by the process the above description lays out are quite simple; infact they are as about as simple as you can get with a Solaris package.

There are some additional features you can make use of within Solaris packages. These are configured by a number of different files outlined below. You can just place these files in the InstallPackage directory for them to be taken into account when the package is built.

One very useful feature is the setting dependancies, i.e. saying that package foo relies on package bar; if when package foo is added to the system package bar has not been installed yet then a warning message will be displayed. Likewise, if you have installed both packages and you attempt to remove bar then a warning message tells you that package foo depends on bar.

You configure such dependancies via the depend file. The format of this file is fully described in the depend(4); however a simple example is shown below:

    P perl Perl scripting language
    P PMlwp LWP Perl module
          1.0.1

The above depend file states that the package depends on the perl package existing on the system and that version 1.0.1 of the PMlwp package eixsts as well.

There are other files which can be used as well:

request
A request script solicits data from the admin installing the package and then sets or redefines environment variables used by other scripts.

checkinstall
A checkinstall script examines the target system for needed data, patches required, etc. It determines if the package installation is to proceed.

Note that a major problem with the checkinstall script is that it is run as the user nobody. This means that the checkinstall script has to be readable by the nobody user for it to work. For spool-based packages this is relatively easy to ensure as you can physically examine the path. For data stream packages of the type build-pkg creates things are a little more complex as pkgadd will convert the data stream package into a spool-based package for the addition by creating a directory under /tmp/. When it does this it fails to mkdir() the directory used to a sensible permission to take into account someone running with a reasonable umask (i.e. 077).

If you do use a checkinstall script it is recommended that you also inform the people who will be pkgadding the package to their systems that they do so by first setting their umask to 022; i.e.

  # umask 022
  # pkgadd -d PACKAGE

preinstall
A procedure script invoked before installation occurs. Personally I use this script in place of a checkinstall script for checking to see if package installation should occur as it is run as the root user. Its group it runs in is other.

Note that no files should be installed by this script.

postinstall
A procedure script invoked after installation occurs. Personally I use this script to re-build the manual page windex file. This is run as the root user with a group of other.

preremove
A procedure script invoked before the removal of the package. This is run as the root user and with a group of other.

Note that no files should be removed by this script.

postremove
A procedure script invoked after the removal of the package. I use this script to re-build the manual page windex file. This is run as the root user and with a group of other.

copyright
A plain text file displayed to the user during package installation.

compver
A plain text file which defines previous versions of the package that are compatible with this version.

space
A plain text file which defines disk space requirements for the target environment, beyond what is needed by the objects defined in the prototype file.

For example, additional space might be needed for files that are dynamically created at installation time.

Note that if you use installf to add items to the package database in the any of the package control scripts (i.e. postinstall) and you do not provide a space file then a warning message will be displayed to this effect when you build the package.

All of the above scripts should be Bourne shell scripts calling /sbin/sh

If you are generating relocatable packages with the -R flag it is recommended that the scripts use the variable $BASEDIR rather than hardcode the base directory to /

The return code of the scripts is important as it controls what the packaging tools do after a script has finished. The table below summerises the

  +----+-----------------------------------------------------------+
  |Code| Meaning                                                   |
  +----+-----------------------------------------------------------+
  | 0  | Successful completion of script                           |
  +----+-----------------------------------------------------------+
  | 1  | Fatal error; installation process is halted at this point |
  +----+-----------------------------------------------------------+
  | 2  | Warning or error condition; installation continues. A     |
  |    | warning message is displayed at the time of completion    |
  +----+-----------------------------------------------------------+
  | 3  | The pkgadd command is cleanly halted. Only the            |
  |    | checkinstall script returns this code                     |
  +----+-----------------------------------------------------------+
  | 10 | System should be rebooted when installation of all        |
  |    | selected packages is completed. This value should be      |
  |    | added to one of the single digit return codes above.      |
  +----+-----------------------------------------------------------+
  | 20 | System should be rebooted immediately after the current   |
  |    | package has been installed. This value should be added to |
  |    | one of the single digit return codes above.               |
  +----+-----------------------------------------------------------+

More details are available in Sun's Application Packaging Developer's Guide.

To make use of the above files, you just need to place them into the work directory, i.e. InstallPackage.


HANDLING OF SYSTEM DIRECTORIES AND USING OVERLAY FILES

Certain system directories are handled in a special way; such directories have their entries in the generated prototype file changed so that the ownership and permissions of the directory under the InstallPackage directory will not be imposed on the system which the resulting package is installed on.

For example if the directory InstallPackage/build/usr had the permissions of 0700 then the resulting prototype line would be:

  d none /usr root bin 0700

This is not very useful as installing a package with the above line would result in pkgadd complaining about an installed item not matching what the package to be installed wants. If the package is still installed then the result would be that the system would only work for the root user!

The line which is actually generated is:

  d none /usr ? ? ?

Which is more useful. System directories which have this treatment are:

  /usr
  /usr/bin
  /usr/lib
  /var
  /home
  /etc
  /etc/rc*.d
  /etc/init.d
  /var/run
  /usr/man
  /usr/include
  /usr/man/man*
  /var/log
  /usr/share
  /opt
  /tmp

/etc/rc*.d represents all of the startup directories like /etc/rcS.d et al. /usr/man/man* represents all of the manual page directories like /usr/man/man1m et al.

It is also possible to specify an overlay file using the -O option which is used to over ride lines in the prototype file generated by build-pkg. The file given to -O should be in a similar format to a prototype file; the only difference are:

Lines which do not conform to the above will be ignored and have a warning output to the standard error.

It is the responsibility of the caller to ensure that the entries in the provided overlay file are syntically correct.

System directories which are automatically ignored - see above for the list - are not affected by the contents of the overlay file.

This option has been added so that it is possible to build packages which ignore the ownership and permissions of user-defined files and directories in much the same way as the permissions for directories like /etc and </home> are ignored automatically.

Trying to use this option to do more than this probably is not a good idea and has not been tested.


DIRECTORY STRUCTURE OF InstallPackage

build-pkg keeps its various files and directories in the InstallPackage directory (changable via the -w option) under the working directory build-pkg was run in.

This directory can contain the following entries generated by build-pkg:

BaseDir
A file which contains the base directory the package is to be under

FileChange
A file which records the changes to the /etc/passwd and /etc/group files within the chroot()ed environment. This file is written to by chroot-install called with the -Y flag. It is used to track users and groups added whilst within the chroot() environment.

pkginfo
The package pkginfo file - see pkginfo(4) for details.

prototype
The package prototype file - see prototype(4) for details.

build/
The directory the contents of the package is to be installed under. This has to mirror the final location of the package contents on the remote system. So if your package contains a file called /usr/local/bin/waterbuffalo then the location of the file so that build-pkg can see it would be:
  $CWD/InstallPackage/build/usr/local/bin/waterbuffalo

The final package
The final package is placed within the InstallPackage directory. By default the name of the file will be %PKG%-v%VERSION%-%ARCH%.pkg where the %..% values are taken from the pkginfo file.

It should be noted that you can also place the other various package configuration files supported by the Sun packaging system into the InstallPackage directory as well. The current list of supported package configuration files is:

 o depend
 o request
 o checkinstall
 o preinstall
 o postinstall
 o preremove
 o postremove
 o copyright
 o space
 o compver

Finally, you can also place a file called ExtraPrototype into the InstallPackage directory which can contain hand crafted lines for the prototype file.


USING BUILD-PKG WITHOUT CHROOT-INSTALL

It is possible to use build-pkg without also using chroot-install or working with a perl module; all you have to do is present build-pkg with the directory structure it expects. This has the advantage of not requiring root privilages to build the package.

Thus all you need to do is create the InstallPackage/build directory mentioned in the previous section and populate it appropriately. build-pkg will create everything else if required.

It should be noted that if you do this that you'll have to ensure that all of the permissions on the files are correct as what you put into the build directory will be mirrored in the resulting package.

It is also recommended that you do not use the -K option as this will end up with chroot-install being invoked by build-pkg.

You can also install software based on GNU autoconf without using chroot-install by using the following:

  % ./configure
  % gmake install
  % simple-proj
  % umask 022
  % mkdir -p InstallPackage/build/usr/local
  % gmake install prefix=`pwd`/InstallPackage/build/usr/local
  % build-pkg -c gnu -p GNUgcc

This works by telling the Makefile that the ${prefix} - from which all pathnames within the Makefile are hopefully derived - is actually under $PWD/InstallPackage/build/usr/local rather than the /usr/local which the package was built with.

This works as build-pkg sees the directory $PWD/InstallPackage/build as the root point for the package being built.

However this method does have problems. For starters it does not deal with files installed outside of ${prefix} - for example configuration files installed into /etc

For that reason it is recommended that you use chroot-install when dealing with 3rd-party software.


SEE ALSO

pkgadd(1M), pkgrm(1M), pkginfo(1), pkgmk(1), pkgtrans(1), pkginfo(4), depend(4), prototype(4), chroot-install(1) template-control(1)


BUGS

If you specify a package name prefix (ie PkgPrefix in the $HOME/.build-pkg file) then you can not remove this prefix when specifying the package name unless you specify the package name directory with the -p option

We do not support classes within packages


AUTHOR

Simon Burr <simes@bpfh.net>


LICENSE

Copyright (c) 2002, Simon Burr <simes@bpfh.net> All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer. 
  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution. 
  * Neither the name of the author nor the names of its contributors may
    be used to endorse or promote products derived from this software
    without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.