Document Title Third Party Software Installation
Document Type classified   /   confidential   /   unclassified   /   public
Author Jeff Nieusma
Date 2 Oct 2002
Revision 1.1
Scope This procedure applies to all UNIX systems managed and/or maintained by the IT department.


Background Info
There are many ways to install software on a UNIX machine. In a single machine environment, it doesn't really matter how it gets done, until it's time to update, or upgrade, the software. In a multi-platform, multi-system environment managed by a central group, the way software is installed and maintained is much more important.

Generically, users have /usr/local/bin in their PATH, so if software is installed into /usr/local/bin by the sys admin, it is available to the users of the system. The problem with this process comes when attempting to install the software package on multiple systems via rdist, and/or upgrading the software.

A better way to keep the software package together is to make it live completely in a "package directory". For example, if a system has perl verion 5.003 installed and needs perl 5.6.1, the upgrade process is easier if the old package was in /usr/local/pkg/perl_5.003 and the new package is compiled to live entirely in /usr/local/pkg/perl_5.6.1. Many software packages are distributed with source code and configure scripts that allow for easy relocation by using the --PREFIX option(s). Sometimes the software will need to build several times to ensure all dependencies are in the package directory. The strings utility is a convenient tool for finding strays;
e.g. strings /some/binary/file | grep / | less

After the package is built to live completely in the package directory, with no config files or other dependencies external to the package directory, it is very easy to copy the package from one machine to another. Here is a example of a command line to copy perl to another machine:

- nieusma@server2$ sudo -v
- nieusma@server1$ sudo -v
- nieusma@server1$ ( cd /usr/local/pkg; sudo tar cBf - perl561 ) |\
  ssh server2 'cd /usr/local/pkg ; /usr/local/bin/sudo tar xpf -'

This is all fine and good, but it creates a problem. If the software is not installed in /usr/local/bin, users will need to modify their PATH in order to use the newly installed software package. That is not a good thing. So, because the sys admin's job is to make the users' experience easy, sometimes we have to go out of our way. The easiest thing we can do is make symbolic links in the directories that the users already have in their PATH: /usr/local/bin, /usr/local/sbin, /usr/local/man. So, after all the work necessary to create a self contained package directory, we will also have to write an Install script.

The Install script should check for existing links to older (or other) versions of the software, and replace them with links to the new (or current) package. When creating these links, it is pretty important to remember the difference between linking to ../pkg/perl561/bin/perl and linking to /usr/local/pkg/perl561/bin/perl. All the links should be relative (../) to allow them to work in the event the disk is mounted in a different place than expected.

If the source code is not available, or there is some other unforseen circumstance preventing the total elimination of external "dependencies" a different approach will be needed. Since the software still has to live in a package, we need to make a list of the external dependencies, and create symbolic links external to the package from the Install script. A good example of this is building a new sendmail package. The Install script will need to delete /usr/lib/sendmail and replace it with a link to the new binary because there are so many programs that assume sendmail lives at /usr/lib/sendmail. Again, be sure all the symbolic links are relative and not absolute.


Assumptions
It is assumed that users have /usr/local/bin in the PATH and /usr/local/man in the MANPATH by one, or more, of the following means
  • set MANPATH and PATH in ~/.profile or ~/.bashrc
  • set path and setenv MANPATH in ~/.cshrc or ~/.login
  • set the system PATH in /etc/default/login
  • set a generic PATH and MANPATH in /etc/profile
  • set a generic MANPATH and prefix the PATH in /etc/profile with
    MANPATH=/usr/local/man:/usr/openwin/man:/usr/man
    PATH=/usr/local/bin:$PATH1G
    export PATH MANPATH
  • set PATH in the sshd RC script, usually /etc/init.d/sshd
Any method of including /usr/local/bin in the PATH is acceptable.


Procedure for a new software package
  1. obtain the software
  2. unpack it
  3. build it (if necessary) to live in a package
  4. use strings to find external dependencies
  5. write RC script (if necessary)
  6. write Install script
  7. be sure to start and stop services with the RC script in /etc/init.d/ to ensure they work and the service will start at the next system reboot.
  8. document the system change in the appropriate change log, or by sending e-mail to the appropriate notify list(s) for administrators and users.


Procedure for replicating a package to another server
  1. log into a machine that has the appropriate package, we'll call it server1
  2. ssh to the server which needs the package, we'll call it server2
  3. run sudo -v
  4. exit back to server1
  5. run cd /usr/local
  6. run the follow command
    sudo tar cBf - package_name | ssh server2 'cd /usr/local; sudo tar xpf -'
    ssh server2 'cd package_name; sudo ./Install'
    ssh server2 '/etc/init.d/package_name start'  ## if necessary ##
    
  7. document the system change in the appropriate change log, or by sending e-mail to the appropriate notify list(s) for administrators and users.


Examples

Simple install script for lynx

    #!/bin/sh
    
    test -d /usr/local/bin || mkdir -p /usr/local/bin
    test -d /usr/local/man/man1 || mkdir -p /usr/local/man/man1
    
    test -h /usr/local/bin/lynx && rm /usr/local/bin/lynx
    ln -s ../lynx/bin/lynx /usr/local/bin
    test -h /usr/local/man/man1/lynx.1 && rm /usr/local/man/man1/lynx.1
    ln -s ../../lynx/man/man1/lynx.1 /usr/local/man/man1
    
    /bin/echo "lynx is installed"
    
    exit 0
    

A slightly more complicated script for perl

    #!/bin/sh
    #
    
    pkg=/usr/local/perl5.005_03
    lndir=../perl5.005_03
    
    cd $pkg/bin
    binfiles="`/bin/echo *`"
    
    /bin/test -d /usr/local/bin && mkdir -p /usr/local/bin
    cd /usr/local/bin
    
    for f in $binfiles
    do
      /bin/echo $f
      /bin/test -h $f && /bin/rm $f
      /bin/ln -s $lndir/bin/$f
    done
    
    cd $pkg/man/man1
    man1f="`echo *`"
    /bin/test -d /usr/local/man/man1 || /bin/mkdir -p /usr/local/man/man1
    cd /usr/local/man/man1
    /bin/rm -f $man1f
    /bin/ln -s ../$lndir/man/man1/* .
    
    cd $pkg/man/man3
    man3f="`echo *`"
    /bin/test -d /usr/local/man/man3 || /bin/mkdir -p /usr/local/man/man3
    cd /usr/local/man/man3
    /bin/rm -f $man3f
    /bin/ln -s ../$lndir/man/man3/* .
    
    exit
    

A more complex script for samba which starts services at boot time

    #!/bin/sh
    #
    #  this package must live in /usr/local/samba-2.0.7
    #  this script will link the package into the /usr/local/ directories
    #
    
    DIR=/usr/local/samba-2.0.7
    LINKDIR="../samba-2.0.7"
    
    #
    # first, delete all the old links...
    #
    /bin/echo "clearing out old samba files..."
    cd $DIR/bin
    /bin/echo "/usr/local/bin: \c"
    for f in *
    do
      /bin/echo "$f \c"
      rm -f /usr/local/bin/$f
    done
    /bin/echo ""
    
    for mandir in man1 man5 man7 man8
    do
      cd $DIR/man/$mandir
      /bin/echo "/usr/local/man/$mandir: \c"
      for f in *
      do
        /bin/echo "$f \c"
        rm -f /usr/local/man/$mandir/$f
      done
      /bin/echo ""
    done
    
    #
    # now, make the new links
    #
    /bin/echo "linking bin files"
    cd /usr/local/bin
    ln -s $LINKDIR/bin/* .
    
    for mandir in man1 man5 man7 man8
    do
      echo "linking $mandir files"
      test -d /usr/local/man/$mandir || mkdir -p /usr/local/man/$mandir
      cd /usr/local/man/$mandir
      ln -s ../$LINKDIR/man/$mandir/* .
    done
    
    echo "creating the startup script"
    
    cp $DIR/etc/samba /etc/init.d/
    chmod 744 /etc/init.d/samba
    chown root /etc/init.d/samba
    ln /etc/init.d/samba /etc/rc2.d/S96samba
    ln /etc/init.d/samba /etc/rc1.d/K14samba
    ln /etc/init.d/samba /etc/rc0.d/K14samba
    ln /etc/init.d/samba /etc/rcS.d/K14samba
    
    exit