Rapid Program-Delivery Morsels, RPM

by Marcel Gagné

François! Why did you not tell me immédiatement that these distinguished diners had arrived? Run along, now. Vite! Bring the '82 Margaux from the cellar.

Forgive me, mes amis, for not welcoming you sooner. François does not like to disturb me when I sample, or rather, take inventory of the wine cellar. Please, sit down, and welcome once more to Chez Marcel. As you know, this month's issue features delightful forays into the world of software development.

Installing and distributing software can be a difficult task. For the, shall we say, not-so-technical users, untarring and unzipping source, compiling, installing and keeping track of all that has been done can be daunting. Upgrading that software once the deed is done can be another trial. This is what a package manager seeks to simplify. The most popular and versatile of these is RPM, the Red Hat Package Manager. With RPM, you can make managing your distribution an easy process for the end user by transforming the whole process of untarring, compiling, installing and cleaning up into a single, one-line command. RPM even maintains a database of installed products so that you can verify installed software for completeness or query file locations.

A number of Linux distributions come with RPM as their package manager of choice. You'll find RPM used by Red Hat, Caldera, Mandrake and TurboLinux, just to name a few. Even if your Linux distribution does not come with RPM, you can still install and use it. What's even more exciting is that RPM will run on a number of other UNIX flavors as well. These include AIX, HP-UX, IRIX and others. I can hear the ads now: “The Red Hat Package Manager . . . it's not just for Red Hat anymore.”

Your taste buds are proving Monsieur Pavlov correct, non? You want to try your own hand at distributing your software using RPM, but you do not know where to begin? Follow me into the kitchen and I will show you a simple recipe for creating your own RPMs.

Let's pretend I want to distribute a clever little package called gatekeeper, version 1.0. This neat little piece of hypothetical software comes with a web interface for authentication, a CGI script which calls a small setuid program, which then calls another Perl script to update /etc/hosts.allow in order to grant access. The installed files are as follows:

/home/httpd/html/gatekeeper/keypad.html
/home/httpd/cgi-bin/gatekeeper/locksmith.pl
/usr/local/.Admin/sethosts.pl
/usr/local/bin/suguard

My setuid program is suguard and will therefore install with setuid permissions, while the .pl files will require standard executable permissions for CGI scripts. We should perhaps add a README to go with this collection. We also want to release this software under the GNU Public License. So, where do we go from here?

The first step in creating your new RPM is to build a .spec file, the basic configuration file for RPM. It is essentially a recipe that RPM uses to build your final package. As with any recipe, you have some flexibility in terms of what can be added or removed, but there are basics that should be followed. After all, if you make Tourtière with apples instead of meat, you have apple pie with vegetables and spices and it just does not work. Even François may not be able to provide you with enough wine to wash that down.

We will now cover the details of this recipe, the spec .file. In my case, it is called gatekeeper-1.0-x.spec and is broken up into sections addressing specific characteristics of the distribution package to be built. The important sections are the “preamble”, “%prep”, “%build”, “%install” and “%files”. The preamble is a description of the package: release information, who built it and where to obtain the source. As the name implies, this is located right at the top of my .spec file. Unlike the other sections, it has no header—you simply begin the file with it. For my gatekeeper program, I have the following preamble:

Summary: Allows authorized clients firewall access
Name: gatekeeper
Version: 1.0
Release: 1
Copyright: GPL
Group: Applications/Networking
Source: ftp://ftp.mycompany.com/pub/packages/gatekeeper-1.0.tar.gz
URL: http://www.mycompany.com/
Packager: Chef Marcel
ExclusiveArch: i386

We begin with a simple summary description of the package. This is followed by the name, a version number, and a release number. If you have ever downloaded or installed with RPM, you are familiar with what is happening here. My package, when complete, will be named gatekeeper-1.0-1.i386.rpm. I include a copyright statement, the source location (where the package can be downloaded using FTP), a URL for documentation on the package, and the chef who put the whole package together is mentioned as “Packager”.

For an example of where this becomes useful, try giving the command below to any package on your system. For example, let's query the “net-tools” package:

rpm -qi net-tools

Here is the output from that command.

Name: net-tools
Relocations: (not relocateable)
Version: 1.53
Vendor: Red Hat Software
Release: 1
Build Date: Sun 29 Aug 1999
08:16:43 PM EDT
Install date: Mon 17 Jan 2000 05:07:51 PM EST
Build Host: porky.devel.redhat.com
Group: System Environment/Base
Source RPM: net-tools-1.53-1.src.rpm
Size: 569756
License: GPL
Packager: Red Hat Software http://developer.redhat.com/bugzilla
Summary: Basic tools for setting up networking:
Description: The net-tools package contains the
basic tools needed for setting up networking:
arp, rarp, ifconfig, netstat, ethers and route.
Next, in my “.spec” file, I include a %description heading. In this section, I include a somewhat more descriptive explanation of the package than my simple one-liner at the top of the last section. In a way, this is part of the first section, in that it makes up the total package description.
%description
Allows authorized clients firewall access
What makes this so cool is that clients with
dynamic IP addresses can still be allowed access
to network resources with proper authentication.
After a set inactivity time (fifteen minutes),
access is deleted from the system.
So far, we have a lot of information, but now the real work begins. If you look at this next section closely (%prep), you'll see it is just a place to put commands that prepare your sources (or in my examples, a few scripts) for building. You could conceivably just call a shell script to do everything, or list the commands specifically. You'll see it is fairly simple.
%prep
rm -rf $RPM_BUILD_DIR/gatekeeper-1.0
zcat $RPM_SOURCE_DIR/gatekeeper-1.0.tar.gz |
tar -xvf -
Some of these section headers are actually powerful macros. For instance, the %setup header for the next section can do a fair bit without being given any arguments. (In exactly the same way I did not! Very clever, non?) What this macro does without any help is unpack the sources (the tar.gz file) and move (using cd) into that directory—very nice. You can also add some flags to this macro to customize your build. Today, we'll keep things simple:
%setup
While we look at this lonely but powerful %setup macro, I should point out that there is another. A %patch macro is available to help you easily apply patches to your build. Next in line is the %build section:
%build
Ah, yes, another lonely section. François, could you pour a glass of wine for our build section to help it through its loneliness? Sit down, François; I was only joking. What we have here is a section that is open to any shell commands you may need to use in order to build your package. For instance, if I was working with a source package, I could have something like this:
%build
ftl_drive_preparations
make depend
make
Obviously, this would be a much higher tech package than I am building here, non?

As we move down the .spec file, the demands for detail increase. For instance, the %install section contains a list of commands necessary to install the package: any directory creation commands, install commands and anything else required. You could also simply call another shell script or a make install. I prefer my .spec file to reflect what happens with my build. Note the backslashes for lines that were too long to fit in this example.

%install
mkdir -p $RPM_BUILD_ROOT/home/httpd/html/gatekeeper
mkdir -p $RPM_BUILD_ROOT/home/httpd/cgi-bin/gatekeeper
mkdir -p $RPM_BUILD_ROOT/usr/local/.Admin
mkdir -p $RPM_BUILD_ROOT/usr/local/bin
install -m 644 home/httpd/html/scidns/keypad.html\
$RPM_BUILD_ROOT/home/httpd/html/scidns/keypad.html
install -m 755 home/httpd/cgi-bin/scidns/locksmith.pl
$RPM_BUILD_ROOT/home/httpd/cgi-bin/scidns/locksmith.pl
install -m 755 usr/local/.Admin/sethosts.pl \
$RPM_BUILD_ROOT/usr/local/.Admin/sethosts.pl
install -m 4755 usr/local/bin/suguard \
$RPM_BUILD_ROOT/usr/local/bin/suguard

Almost there, mes amis. When we have finished putting our RPM binary together, we should clean up after ourselves, non? This is where we do it. This is the %clean section.

%clean
rm -rf $RPM_BUILD_ROOT
Now we come to our final section, %files. This is simply a list of all files that make up your package. Keep in mind that the files must be listed here—anything missing in this section will not make it into the final RPM.
%files
%doc README
/home/httpd/html/gatekeeper/keypad.html
/home/httpd/cgi-bin/gatekeeper/locksmith.pl
/usr/local/.Admin/sethosts.pl
/usr/local/bin/suguard
While you are analyzing the wonderful simplicity of this section, note also the %doc parameter. The file I include here will automatically get installed under the /usr/doc hierarchy on my system to represent the package. In this case, the directory would be /usr/doc/gatekeeper-1.0 with one file (README) sitting underneath it.

Now comes the moment we have all been waiting for. Your .spec file is complete, and you long to see this work. This is how you build your package:

rpm -bb gatekeeper-1.0-.spec

The -bb option means “build binary”. The rpm command has many flags that define whether you are building source or binaries, or executing an individual section of the .spec file. When you press ENTER on the above command, many things start scrolling past your eyes as RPM deals with every section of your .spec file. The line I look for in this case is

Wrote: /usr/src/redhat/RPMS/i386/gatekeeper-1.0-1.i386.rpm
That, mes amis, is a beautiful thing.

Throughout this article, I have referred to variables like RPM_BULD_ROOT without explaining where these things come from. In the case of a Red Hat system like mine, this is /usr/src/redhat where I find the following directories: BUILD, RPMS, SOURCES, SPECS and SRPMS. If you are curious as to how they are defined, have a look through the file /usr/lib/rpm/macros. If you cannot find the “macros” file in this location (remember, rpm must be loaded), use this command to locate it:

rpm -ql rpm | grep macros

You see, rpm is a wonderful tool for so many things, including working with rpm itself.

What? Ah, yes. I hear you, mes amis. You are asking, “Marcel, is there no other way to build an RPM, something perhaps a little friendlier?” Do not despair. Chef Marcel has a particular fondness for that well-aged UNIX editor, vi. Nevertheless, there are other ways to build an RPM package that bring the process to the desktop. Allow me to show you these delicacies.

The first item I will mention is something from KLabs called (strangely enough) RPM Builder (see Figure 1). This is a Tcl/Tk application (written by Seek3r) that automatically builds the framework for a .spec file from a tar.gz distribution. Very neat, despite the fact that our friends at KLabs built the screen based on a 1024x768 screen. On my 800x600 screen, I lose part of it at the bottom of my notebook. There is no need to tell them—they already know about it. Still, it is worth checking out.

Rapid Program-Delivery Morsels, RPM

Figure 1. RPM Builder

Another package I would recommend is pkgbuild (see Figure 2) from Davin S. Hills of the Hills Design Group. This is a very nice-looking package with a screen design that breaks the GUI into sections not unlike the RPM-build process itself. You have a tab for the preamble, one for “Prep and Build”, “Install and Clean” and so on. Everything can be done from one interface. The software is built on the FOX C++ development libraries written by Jeroen van der Zijp, so you will need to pick that up if you want to build the package yourself. RPMs of pkgbuild are available for Red Hat users.

Rapid Program-Delivery Morsels, RPM

Figure 2. pkgbuild

Make sure you check out the RPM resources in the sidebar. For more RPM masterpieces, I invite you to visit the official RPM web site for all things RPM, and the RPM Documentation Project. The RPM Documentation Project web site is in its infancy and somewhat sparse. The maintainers promise much more information in the near future, so by the time you read this, it may be brimming with information. Check it out anyhow. You will find a link to the Maximum RPM book by Edward C. Bailey, free and on-line. This edition of the book is a couple of years old, but you will still find lots of useful information.

Well, mes amis, that dreadful rooster outside is telling me it is closing time. I sincerely hope I have managed to assist you in bringing your brilliant Linux software package a little closer to reality and a little closer to simple, reproducible installations and updates. Au revoir, mes amis. Remember, you are always welcome here at Chez Marcel. Bon Appétit!

Resources

Rapid Program-Delivery Morsels, RPM
email: mggagne@salmar.com

Marcel Gagné (mggagne@salmar.com) lives in Mississauga, Ontario. In real life, he is president of Salmar Consulting Inc., a systems integration and network consulting firm. He is also a pilot, writes science fiction and fantasy and edits TransVersions, a science fiction, fantasy and horror magazine. He loves Linux and all flavors of UNIX and will even admit it in public. Check out his System Administration column on LJ's web site.

Load Disqus comments

Firstwave Cloud