Author: elliss
Update of /cvs/docs/rpm-guide
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv2417
Added Files:
rpm-guide-scripting-en.xml
Log Message:
--- NEW FILE rpm-guide-scripting-en.xml ---
<!-- $Id: -->
<chapter id="ch-scripting">
<title>Automating RPM with Scripts</title>
<para>
Copyright (c) 2005 by Eric Foster-Johnson. This material may be
distributed only subject to the terms and conditions set forth in
the Open Publication License, v1.0 or later (the latest version is
presently available at http://www.opencontent.org/openpub/)
</para>
<para/>
<para>
In This Chapter
</para>
<para>
*Deciding when to program and when to script
</para>
<para>
*Examining RPM files with scripts
</para>
<para>
*Querying the RPM database with scripts
</para>
<para>
The rpm command provides a very high-level view of package
management. Most of the operations you need to perform require only
a single invocation. Some of the command-line options to the rpm
command tend to get very complex, however, especially for detailed
queries. That���s where scripting can help.
</para>
<para>
This chapter covers scripting, specifically shell scripting, with
the rpm command, especially for newcomers to Linux scripting
</para>
<sect1>
<title>Scripting</title>
<para>
Scripting allows you to quickly write new commands in a language,
called a scripting language, that can help automate your work.
Used heavily by system administrators and lightly by software
developers, scripts can help remove some of the tedium from your
day-to-day tasks. Scripts can also hold the complex query formats
used with the rpm command so you don���t have to remember them.
</para>
<para>
Scripts start out as text files. These text files hold commands in
the scripting language. Most of these script file commands run
commands installed on your system, such as rpm. To run a script,
invoke a command, called an interpreter, that reads in the script
file and executes the commands inside the script.
</para>
<para>
Programming is usually considered different from scripting, even
though there are many similarities. Programs start out as text
files. These text files hold commands in the programming language
and sometimes, not often, calls to commands installed on your
system. Programs generally involve more work than scripts and are
generally larger, containing more commands.
</para>
<para>
Furthermore, most programs need to be compiled. A separate command
parses the program text files and generates some form of machine
code. Multiple pieces of a program may be linked together to form
a command you can call from your shell prompt.
</para>
<para>
Some programming languages, such as Java or C#, are compiled to a
generic bytecode format. A compiled Java program, for example, is
the same no matter what the architecture. To run such a program,
you need a runtime engine such as the java command provides.
(Runtime engine is a fancy term for interpreter.)
</para>
<para>
Such differences between scripting and programming sometimes get
in the way of performing real work. For example, I once worked
with a group of people who were convinced that they were not
programmers. They felt that programming was an art that was far
beyond them. Yet, they wrote hundreds of kilobytes of scripts to
create a sophisticated graphical interface for a Computer-Aided
Design system. In my mind, they were programming (and doing quite
well at it). In their minds, though, there was a clear distinction
between scripting@mdwhat they could do@mdand programming, which
was beyond them, they thought.
</para>
<para>
Don���t get caught up in this. Use the right tool for the job.
</para>
</sect1>
<sect1>
<title>Distinguishing Scripting Languages from Programming Languages</title>
<para>
Experts differ regarding what defines a scripting language and
what defines a programming language. It���s clear that languages
such as Python blur the old distinction between programming and
scripting.
</para>
<para>
Originally, scripting was writing small files of commands that
invoked other system commands. For example, you could write a
script that wraps the Linux file command. Scripts were executed by
scripting-language interpreters that parsed each command one at a
time and then executed the command.
</para>
<para>
Modern scripting languages, such as Tcl, are parsed at runtime and
compiled into an internal bytecode format. Once compiled, there is
no real difference from a language associated with programming
such as Java.
</para>
<para>
With a scripting language
</para>
<para>
*You generally don���t have to compile the script in advance. The
scripting language interpreter may compile the program, often to
an internal byte code, but you don���t have to invoke a compiler
as a separate step.
</para>
<para>
*The facilities of the language generally provide a higher level
and more abstract level of interaction with the system than with
programming languages. For example, writing socket-based
networking code in Tcl requires a lot less code than writing the
same code in a programming language such as C. Tcl provides a more
abstract view of networking; therefore, your code is a lot
simpler.
</para>
<para>
*The commands in the scripting language are mostly the commands
available to you on the command line. Scripting languages
introduce their own commands, too.
</para>
<para>
*The language is generally identified as a scripting language.
This is more consensus than anything else. Forth is considered an
interpreted programming language, while Perl is considered a
scripting language.
</para>
<para>
Table 15-1 lists some of the more common scripting and programming
languages. Note that these are the generally-accepted categories
for these languages, not hard and fast rules. This should not stop
you, for example, from writing programs in Perl or Python. The
distinctions between programming and scripting have blurred in
recent years.
</para>
<para>
Table 15-1 Common Scripting Languages and Common Programming
Languages
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
Scripting Languages
</para>
</entry>
<entry>
<para>
Programming Languages
</para>
</entry>
</row>
<row>
<entry>
<para>
Bash (Bourne Again shell) Csh (C shell) JavaScript Ksh
(Korn shell) Lua MS-DOS batch files Perl Python Ruby Sh
(Bourne shell) Tcl
</para>
</entry>
<entry>
<para>
Assembler BASIC C C++ C# FORTRAN Forth Java LISP
Modula-2, Modula-3 Oberon Pascal
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect1>
<sect1>
<title>Deciding When to Program and When to Script</title>
<para>
Just as the distinction between programming and scripting
languages has blurred in the last few years, so have the
guidelines for when you should program and when you should script.
The simplest rule remains, though: Use whatever techniques make
you productive. In the end, no one really cares if you call it a
program or a script.
</para>
<para>
Even so, these guidelines may help:
</para>
<para>
*If you have to perform a lot of operations on a lot of RPMs, a
program will likely perform much faster than a script that calls
the rpm command over and over.
</para>
<para>
*If the task is relatively simple, scripting generally works best.
</para>
<para>
*If you are more experienced with a particular language, use it.
</para>
<para>
*If you need to perform complex operations, perhaps involving
transactions, a program is probably the right way to go.
</para>
<para>
*In many cases, programming languages work better for creating
graphical user interfaces, although Python and Perl offer
graphical user interface toolkits, such as Perl/Tk or PyQt.
</para>
<para>
There isn���t one right way to do it. Pick what works best for
you.
</para>
<para>
Cross Reference
</para>
<para>
This chapter covers shell scripting. Chapter 16 covers C
programming. Chapter 17 covers Python scripting and programming,
and Chapter 18 covers Perl scripting.
</para>
</sect1>
<sect1>
<title>Shell Scripting Basics</title>
<para>
For newcomers to scripting, don���t worry. A script, in this case
a shell script, is merely a text file with commands mostly the
same as the commands you can type at the keyboard. I���ll point
out the differences.
</para>
<para>
The following sections quickly introduce scripting for those new
to this venture.
</para>
<sect2>
<title>Writing a script</title>
<para>
For your first venture, enter the following script into a text
file:
</para>
<para>
rpm -qa | grep rpm
</para>
<para>
This script has a two-part command. The rpm ���qa part queries
all RPM packages, as covered in Chapter 4. The grep rpm part
finds only packages with rpm in their names. This is a very
simple script, but it can serve to show how to work with
scripts.
</para>
<para>
Save this file under the name listrpmpkgs, since this script
lists RPM packages.
</para>
<para>
Note
</para>
<para>
If you���re new to Linux, you���ll notice there���s no program
named Notepad.exe. There are, though, a plethora of Linux text
editors to choose from. See Appendix F for a listing of Linux
text-editing tools.
</para>
</sect2>
<sect2>
<title>Running a script</title>
<para>
Once you���ve entered a script, you can run it with the sh
command, as shown following, passing the name of your script to
the sh command:
</para>
<para>
$ sh listrpmpkgs
</para>
<para>
librpm404-devel-4.0.4-8x.27
</para>
<para>
librpm404-4.0.4-8x.27
</para>
<para>
rpm404-python-4.0.4-8x.27
</para>
<para>
rpm-4.1-1.06
</para>
<para>
rpm-devel-4.1-1.06
</para>
<para>
gnorpm-0.9-1
</para>
<para>
rpm-python-4.1-1.06
</para>
<para>
redhat-rpm-config-8.0-1
</para>
<para>
rpm-build-4.1-1.06
</para>
<para>
rpmrebuild-1.0-0
</para>
<para>
Type the command you have placed in your script at the command
line. There should be no difference in the output. For example:
</para>
<para>
$ rpm -qa | grep rpm
</para>
<para>
librpm404-devel-4.0.4-8x.27
</para>
<para>
librpm404-4.0.4-8x.27
</para>
<para>
rpm404-python-4.0.4-8x.27
</para>
<para>
rpm-4.1-1.06
</para>
<para>
rpm-devel-4.1-1.06
</para>
<para>
gnorpm-0.9-1
</para>
<para>
rpm-python-4.1-1.06
</para>
<para>
redhat-rpm-config-8.0-1
</para>
<para>
rpm-build-4.1-1.06
</para>
<para>
rpmrebuild-1.0-0
</para>
</sect2>
<sect2>
<title>Problems running scripts</title>
<para>
The previous script example required the sh program, a Linux
shell, to run the script. You also had to have the script file,
such as listrpmpkgs, available. So, if you have stored the file
in /home2/bin, to run the script, use the following command:
</para>
<para>
$ sh /home2/bin/listrpmpkgs
</para>
<para>
That���s not very convenient. Furthermore, you always have to
remember where you stored the script file listrpmpkgs. To make
this command work better, you can turn your script into a
command.
</para>
</sect2>
<sect2>
<title>Turning a script into a command</title>
<para>
To turn a script into a command, do three simple things:
</para>
<para>
1.Add a special magic comment to the start of the file so Linux
recognizes your text file as a command script.
</para>
<para>
2.Change the permissions on the file so that it is marked as
executable.
</para>
<para>
3.Copy the file to a directory located in your command path.
</para>
<para>
Shell scripts use a # to indicate a comment, text intended for
human readers that can help explain the purpose of the script.
By convention, Linux shells use a #! comment in the first line
of a script file as a special marker that indicates the file is
a shell script. The text that comes after the #! holds the name
of the command that should be used to run the script. In almost
all cases, that command should be /bin/sh for a shell script.
</para>
<para>
So edit the listrpmpkgs script again, and add the magic comment
so that the file reads as follows:
</para>
<para>
#!/bin/sh
</para>
<para>
rpm -qa | grep rpm
</para>
<para>
Make sure the #! comment starts at the beginning of the first
line.
</para>
<para>
Next, change the permissions on the script to mark it as an
executable program. Use the chmod command to do this. The chmod
command changes the file permissions. To see the permissions,
run the ls ���l command before changing the permissions:
</para>
<para>
$ ls -l listrpmpkgs
</para>
<para>
-rw-rw-r-- 1 ericfj ericfj 31 Nov 7 20:02 listrpmpkgs
</para>
<para>
The first set of characters, the -rw-rw-r--, indicate the
permissions in three batches: permissions for the file owner,
the owner���s group of users, and world (everyone else). The rw
means read and write, and the r alone means read only for
everyone not the owner and not in the owner���s group.
</para>
<para>
To add the permission to execute the file for the file owner
only, use the following command:
</para>
<para>
$ chmod u+x listrpmpkgs
</para>
<para>
In this command, the u stands for the user who owns the file
(for historical reasons, an o stands for others, not owner). The
+x means add the x permission, short for execute permission.
</para>
<para>
After running this command, you can see the revised permissions.
</para>
<para>
$ ls -l listrpmpkgs
</para>
<para>
-rwxrw-r-- 1 ericfj ericfj 31 Nov 7 20:02 listrpmpkgs
</para>
<para>
Cross Reference
</para>
<para>
Use the man chmod command to see more information on this
command.
</para>
<para>
You now have a command you can run locally. For example:
</para>
<para>
$ ./listrpmpkgs
</para>
<para>
librpm404-devel-4.0.4-8x.27
</para>
<para>
librpm404-4.0.4-8x.27
</para>
<para>
rpm404-python-4.0.4-8x.27
</para>
<para>
rpm-4.1-1.06
</para>
<para>
rpm-devel-4.1-1.06
</para>
<para>
gnorpm-0.9-1
</para>
<para>
rpm-python-4.1-1.06
</para>
<para>
redhat-rpm-config-8.0-1
</para>
<para>
rpm-build-4.1-1.06
</para>
<para>
rpmrebuild-1.0-0
</para>
<para>
The next step is to copy the file to a directory in your system
command path. To see which directories are in your path, run the
following command:
</para>
<para>
$ echo $PATH
</para>
<para>
/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/ericfj/bin:/usr/java/j2sdk1.4.0_01/bin
</para>
<para>
Pick one of these directories. The /usr/local/bin directory is a
common place to share locally created commands. If this is a
personal command for your own use only, a directory under your
home directory will be better. In this example, the
/home/ericfj/bin is one such directory.
</para>
<para>
Copy the script file to a directory in your command path, and
you are ready to go.
</para>
<para>
Note
</para>
<para>
If you use the C shell, csh, or the T C shell, tcsh, you need to
run the rehash command to tell the shell to look again at the
set of commands available in your command path.
</para>
<para>
Enter the following command:
</para>
<para>
$ listrpmpkgs
</para>
<para>
librpm404-devel-4.0.4-8x.27
</para>
<para>
librpm404-4.0.4-8x.27
</para>
<para>
rpm404-python-4.0.4-8x.27
</para>
<para>
rpm-4.1-1.06
</para>
<para>
rpm-devel-4.1-1.06
</para>
<para>
gnorpm-0.9-1
</para>
<para>
rpm-python-4.1-1.06
</para>
<para>
redhat-rpm-config-8.0-1
</para>
<para>
rpm-build-4.1-1.06
</para>
<para>
rpmrebuild-1.0-0
</para>
<para>
You have now extended the Linux command set with your own
command.
</para>
<para>
Note
</para>
<para>
Windows users may be used to the convention that program file
names end in .exe and scripts end in .bat or .cmd. When you run
these programs or scripts, you don���t include the extension,
exe, .bat, or .cmd. With Linux and UNIX, though, the full file
name is important, so if you name your script rpminfo.bat, you
must type rpminfo.bat each time you run the script. That���s why
most Linux programs and scripts have no filename extension.
</para>
<para>
If you want to share your script with others, you should give
them the right to execute it as well. You can do that with the
following command:
</para>
<para>
$ chmod a+x listrpmpkgs
</para>
<para>
In this case, the a stands for all users.
</para>
</sect2>
<sect2>
<title>Passing command-line options to your script</title>
<para>
The listrpmpkgs script used so far isn���t very useful. It
performs one command and that���s it. We cannot customize it
without writing a new script.
</para>
<para>
One way to make a script more flexible is to allow it to use
command-line options. Just like the rpm command accepts a
zillion options, you can make your scripts accept options.
</para>
<para>
Shells define special variables for the command-line options
passed to the shell. Table 15-2 lists these options.
</para>
<para>
Table 15-2: Shell variables for command-line options
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
Variable
</para>
</entry>
<entry>
<para>
Holds
</para>
</entry>
</row>
<row>
<entry>
<para>
$0
</para>
</entry>
<entry>
<para>
The name of the script itself, from the command line
</para>
</entry>
</row>
<row>
<entry>
<para>
$1
</para>
</entry>
<entry>
<para>
The first option
</para>
</entry>
</row>
<row>
<entry>
<para>
$2
</para>
</entry>
<entry>
<para>
The second option
</para>
</entry>
</row>
<row>
<entry>
<para>
$3
</para>
</entry>
<entry>
<para>
The third option
</para>
</entry>
</row>
<row>
<entry>
<para>
$4
</para>
</entry>
<entry>
<para>
The fourth option
</para>
</entry>
</row>
<row>
<entry>
<para>
$5
</para>
</entry>
<entry>
<para>
The fifth option
</para>
</entry>
</row>
<row>
<entry>
<para>
$6
</para>
</entry>
<entry>
<para>
The sixth option
</para>
</entry>
</row>
<row>
<entry>
<para>
$7
</para>
</entry>
<entry>
<para>
The seventh option
</para>
</entry>
</row>
<row>
<entry>
<para>
$8
</para>
</entry>
<entry>
<para>
The eighth option
</para>
</entry>
</row>
<row>
<entry>
<para>
$9
</para>
</entry>
<entry>
<para>
The ninth option
</para>
</entry>
</row>
<row>
<entry>
<para>
$*
</para>
</entry>
<entry>
<para>
All command-line options
</para>
</entry>
</row>
<row>
<entry>
<para>
$#
</para>
</entry>
<entry>
<para>
Holds the number of command-line options
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
Note
</para>
<para>
Use $#argv in place of $# if you use the C shell to run your
scripts.
</para>
<para>
You can use these variables to allow the user to pass the text
to search for, instead of always searching for rpm. With this
addition, your new script, renamed rpmgrep, follows in Listing
15-1:
</para>
<para>
Listing 15-1: rpmgrep
</para>
<para>
#!/bin/sh
</para>
<para/>
<para>
rpm -qa | grep $*
</para>
<para>
This script now expects a command-line option that holds the
text to search for. Mark this script as an executable; then you
can run it as follows:
</para>
<para>
$ ./rpmgrep python
</para>
<para>
python-devel-2.2.1-17
</para>
<para>
gnome-python2-gtkhtml2-1.99.11-8
</para>
<para>
gnome-python2-canvas-1.99.11-8
</para>
<para>
gnome-python2-1.99.11-8
</para>
<para>
rpm404-python-4.0.4-8x.27
</para>
<para>
orbit-python-1.99.0-4
</para>
<para>
gnome-python2-bonobo-1.99.11-8
</para>
<para>
gnome-python2-gconf-1.99.11-8
</para>
<para>
libxslt-python-1.0.19-1
</para>
<para>
libxml2-python-2.4.23-1
</para>
<para>
python-optik-1.3-2
</para>
<para>
python-2.2.1-17
</para>
<para>
rpm-python-4.1-1.06
</para>
<para>
mod_python-3.0.0-10
</para>
<para>
python-tools-2.2.1-17
</para>
<para>
If you want to make this command available, copy it to a
directory in your command path as described in the preceding
section.
</para>
</sect2>
</sect1>
<sect1>
<title>Examining RPM Files</title>
<para>
When you work with a lot of RPM files, you���ll find that you run
the same commands over and over again for each new package you
get. For example, you may want to see what capabilities a package
requires. You can type in the rpm command each time, or write a
short shell script with the necessary command-line options.
Listing 15-2 shows this script.
</para>
<para>
Listing 15-2: rpmdepend
</para>
<para>
#!/bin/sh
</para>
<para/>
<para>
rpm -qp --requires $*
</para>
<para>
This script expects the name of an RPM package file. Run the
command as follows:
</para>
<para>
$ rpmdepend vim-common-6.1-14.i386.rpm
</para>
<para>
rpmlib(PayloadFilesHavePrefix) <= 4.0-1
</para>
<para>
rpmlib(CompressedFileNames) <= 3.0.4-1
</para>
<para>
/bin/sh
</para>
<para>
/usr/bin/awk
</para>
<para>
libc.so.6
</para>
<para>
libc.so.6(GLIBC_2.0)
</para>
<para>
libc.so.6(GLIBC_2.1)
</para>
<para>
Another common task I perform involves listing all the files in an
RPM along with the descriptive information on the package. This
can really help, since so many Linux packages have nondescriptive
names such as dia and anaconda.
</para>
<para>
Listing 15-3 shows the rpminfo script.
</para>
<para>
Listing 15-3: rpminfo
</para>
<para>
#!/bin/sh
</para>
<para/>
<para>
rpm -qilp $* | less
</para>
<para>
This script lists a potentially long set of lines, so the script
pipes the output to the less command. For example:
</para>
<para>
$ ./rpminfo perl-XML-Dumper-0.4-22.noarch.rpm
</para>
<para>
Name : perl-XML-Dumper Relocations: /usr
</para>
<para>
Version : 0.4 Vendor: Red Hat, Inc.
</para>
<para>
Release : 22 Build Date: Tue 06 Aug 2002 01:53:30 PM CDT
</para>
<para>
Install date: (not installed) Build Host: vegeta.devel.redhat.com
</para>
<para>
Group : System Environment/Libraries Source RPM:
perl-XML-Dumper-0.4-22.src.rpm
</para>
<para>
Size : 10015 License: GPL
</para>
<para>
Signature : DSA/SHA1, Tue 06 Aug 2002 02:11:39 PM CDT, Key ID
fd372689897da07a
</para>
<para>
Packager : Red Hat, Inc.
<http://bugzilla.redhat.com/bugzilla>
</para>
<para>
URL : http://www.cpan.org
</para>
<para>
Summary : Perl module for dumping Perl objects from/to XML
</para>
<para>
Description :
</para>
<para>
XML::Dumper dumps Perl data to XML format. XML::Dumper can also
read
</para>
<para>
XML data that was previously dumped by the module and convert it
back
</para>
<para>
to Perl. Perl objects are blessed back to their original
packaging;
</para>
<para>
if the modules are installed on the system where the perl objects
are
</para>
<para>
reconstituted from xml, they will behave as expected. Intuitively,
if
</para>
<para>
the perl objects are converted and reconstituted in the same
</para>
<para>
environment, all should be well.
</para>
<para>
/usr/lib/perl5/vendor_perl/5.8.0/XML/Dumper.pm
</para>
<para>
/usr/share/man/man3/XML::Dumper.3pm.gz
</para>
<para>
I use this script so that I know what files a package wants to
install.
</para>
</sect1>
<sect1>
<title>Querying the RPM Database</title>
<para>
In addition to querying RPM files, you can script the commands you
use to query the RPM database. This is most useful for the long
commands with query formats, especially if you have a hard time
remembering all the formats.
</para>
<sect2>
<title>Querying for all packages installed at the same time</title>
<para>
If you want to list all the packages that were installed with
the same transaction ID as a particular package, for example,
you can use a script like rpmtran, in Listing 15-4.
</para>
<para>
Listing 15-4: rpmtran
</para>
<para>
#!/bin/sh
</para>
<para/>
<para>
tid=`rpm -q --qf "%{INSTALLTID}\n" $*`
</para>
<para/>
<para>
rpm -q --tid $tid
</para>
<para>
This script uses the query format to get the transaction ID, or
tid, for a particular package. It then passes this transaction
ID to the rpm command to query for all packages installed with
the same transaction ID.
</para>
<para>
For example:
</para>
<para>
$ ./rpmtran tcl
</para>
<para>
itcl-3.2-74
</para>
<para>
tclx-8.3-74
</para>
<para>
tcl-8.3.3-74
</para>
<para>
tix-8.2.0b1-74
</para>
<para>
tkinter-2.2.1-17
</para>
</sect2>
<sect2>
<title>Reading HTML documentation for a package</title>
<para>
You can combine the rpm command with other commands as well. For
example, the rpm ���qd command lists the documentation files
with a package. If this documentation is in HTML format, you can
display this documentation in a Web browser such as Mozilla.
Furthermore, by convention, the starting page for HTML
documentation should be a file named index.html. Listing 15-5
combines all these factors:
</para>
<para>
Listing 15-5: rpmmoz
</para>
<para>
#!/bin/sh
</para>
<para/>
<para>
html_file=`rpm -qd $* | grep index.html | head -n 1 `
</para>
<para/>
<para>
echo "Launching Web browser with $html_file"
</para>
<para/>
<para>
htmlview $html_file &
</para>
<para>
This script searches for the documentation for a given package
name, finds the first file named index.html, and launches the
Web browser in the background to display this file, using the
htmlview command which will likely run mozilla or your
configured Web browser. When you run this command, you should
see output like the following; then the Web browser should
appear:
</para>
<para>
$ ./rpmmoz rpm-devel
</para>
<para>
Launching Web browser with
/usr/share/doc/rpm-devel-4.1/apidocs/html/index.html
</para>
<para>
Note
</para>
<para>
This script does not check for errors. If there are no files
named index.html, the script launches the Web browser anyway.
You could fix this by changing the script to validate the
html_file variable prior to launching the Web browser.
</para>
</sect2>
</sect1>
<sect1>
<title>Where to Go From Here</title>
<para>
This chapter just introduces the basics for shell scripting. There
are many more things you can do. The online manual pages for the
bash or tcsh commands provide a wealth of reference information on
these shells.
</para>
<para>
A number of Web sites provide tutorials on bash, including
http://pegasus.rutgers.edu/~elflord/unix/bash-tute.html and
www.linuxorbit.com/modules.php?op=modload&name=Sections&file=index&….
In addition, the Linux Documentation Project at
www.tldp.org/guides.html provides a bash scripting guide, along
with a number of bash- and shell-related how-to documents at
www.tldp.org/HOWTO/HOWTO-INDEX/howtos.html.
</para>
<para>
Teach Yourself Linux, by Steve Oualline and Eric Foster-Johnson
(John Wiley & Sons, 2000), introduces a number of Linux
topics, including text editors and scripting, for those new to
Linux. And Graphical Applications with Tcl and Tk (Hungry Minds,
Inc., 1997) by Eric Foster-Johnson, covers another scripting
language, Tcl/Tk.
</para>
<para>
Use your imagination. Any command that you run often or that is
hard to type can be scripted. Furthermore, you can write complex
scripts that automate some of the more tedious tasks you need to
perform.
</para>
</sect1>
<sect1>
<title>Summary</title>
<para>
Scripting is the art of writing a set of commands into text files
to speed up your work. Programming is the art of writing a set of
commands into text files, compiling the text files, and getting
paid more. Choosing when to program and when to script isn���t
always a clear-cut decision, but generally programs are move
involved and complex, while scripts are shorter tools that
automate your work. This chapter provides just a glimpse of all
you can do with scripts and the RPM system.
</para>
<para>
Scripts work very well for capturing obscure syntax options for
the rpm command, especially the query formats. You can figure out
a command once and then save the command as a script to save time
in the future.
</para>
<para>
Scripts aren���t the best choice for all tasks, though. In many
cases, you need to write a program to accomplish your goals. The
next chapter delves into the RPM C programming API, rpmlib.
</para>
</sect1>
</chapter>
<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide-en.xml" "book" "chapter")
fill-column: 72
End:
-->
Author: elliss
Update of /cvs/docs/rpm-guide
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv1023
Added Files:
rpm-guide-rpm-overview-en.xml
Log Message:
--- NEW FILE rpm-guide-rpm-overview-en.xml ---
<!-- $Id: -->
<chapter id="ch-rpm-overview">
<title>RPM Overview</title>
<para>
Copyright (c) 2005 by Eric Foster-Johnson. This material may be
distributed only subject to the terms and conditions set forth in
the Open Publication License, v1.0 or later (the latest version is
presently available at http://www.opencontent.org/openpub/)
</para>
<para/>
<para>
In This Chapter
</para>
<para>
*Understanding the package file
</para>
<para>
*Querying the RPM database
</para>
<para>
*Running RPM commands
</para>
<para>
Working with RPM packages, files, commands, and databases can be
complicated. There are thousands of files, for hundreds if not
thousands of packages, installed on your system. You need some way
to manage it all. The RPM system can help you do that.
</para>
<para>
This chapter provides an overview of the components that make up the
RPM system for package management: package files, databases, and RPM
commands.
</para>
<sect1>
<title>Understanding the Package File</title>
<para>
RPM provides for installing, upgrading and removing packages.
Typically, each package is an application and all the necessary
files associated with that application. For example, the Apache
Web server comes with a number of configuration files, a large set
of documentation files, and the Apache server itself. All of this
fits into one RPM package.
</para>
<para>
One of the main advantages of the RPM system is that each .rpm
file holds a complete package. For example, the following file
holds the xcopilot package:
</para>
<para>
xcopilot-0.6.6-3.i386.rpm
</para>
<para>
Based on the naming conventions discussed in Chapter 2, this
package represents xcopilot package, version 0.6.6, third build of
an RPM package, for i386 (Intel) architecture systems.
</para>
<para>
With a single command, you can copy an .rpm file to another Linux
system and install it, getting the complete contents of the
package, or you can use other commands to remove or update the
package.
</para>
<sect2>
<title>RPM file format</title>
<para>
RPM files hold a number of tagged data items and a payload, the
files to install on your system. The tagged data items describe
the package and can contain optional features. For example, the
NAME tag holds the package name. The optional PRE tag holds a
pre-installation script, a script that the rpm command runs
prior to installing the files in the package payload.
</para>
<para>
Under the covers, RPM package files contain four sections. The
first is a leading identification area that marks the file as an
RPM package (created with a particular version of the RPM
system). The remaining sections are the signature, the tagged
data (called the header), and the payload. Each of these
sections has important information about the package, although
the payload section contains the actual content of the package.
</para>
<para>
*The signature appears after the lead or identifier section,
which marks the file as an RPM file. Like your signature when
you sign a check, the RPM signature helps verify the integrity
of the package. No, the signature doesn���t check for bugs in
software applications. Instead, it ensures that you have
downloaded a valid RPM archive.
</para>
<para>
The signature works by performing a mathematical function on the
header and archive sections of the file. The mathematical
function can be an encryption process, such as PGP (Pretty Good
Privacy), or a message digest in MD5 format.
</para>
<para>
*The header contains zero or more tagged blocks of data that
pertain to the package. The header contains information such as
copyright messages, version numbers, and package summaries.
</para>
<para>
*The payload section contains the actual files used in the
package. These files are installed when you install the package.
To save space, data in the archive section is compressed in GNU
gzip format.
</para>
<para>
Once uncompressed, the data is in cpio format, which is how the
rpm2cpio command (introduced in the "Other RPM commands" section
later in this chapter) can do its work.
</para>
</sect2>
<sect2>
<title>Binary RPMs and Source RPMs</title>
<para>
There are two main types of RPM packages: binary (or
applications) and source. A binary RPM has been compiled for a
particular architecture. For example, the Apache Web server
compiled for an Intel Pentium, or i586, architecture won���t
work on a Sharp Zaurus, which runs an Intel ARM processor. To
run on both systems, you would need two separate packages: one
for the Pentium i586 and one for the ARM.
</para>
<para>
In addition to binary RPMs, you can get source code RPMs. These
RPMs are packages that provide the source code for other
packages. Sounds kind of circular, doesn���t it?
</para>
<sect3>
<title>binary RPMs</title>
<para>
Binary RPMs hold complete applications or libraries of
functions compiled for a particular architecture. Most binary
RPMs contain complete applications, such as the Apache Web
server or the AbiWord word processor. These application binary
RPMs usually depend on a number of system libraries which are,
in turn, also provided by binary RPMs.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 8 covers a number of locations where you can find RPM
applications galore. Your Linux installation CDs are also a
great source for applications. Most Linux distributions come
with more applications than you can imagine using.
</para>
<para>
Although most binary RPMs are complete applications, others
provide libraries. For example, the Simple DirectMedia Layer
library (SDL), which provides really cool graphics for many
games, can be packaged as an RPM file. A number of programs,
mostly games, use this library for enhanced multimedia such as
rich graphics. RPMs that provide libraries allow multiple
applications to share the same library. Typically, the
libraries are packaged into separate RPMs from the
applications.
</para>
<para>
In addition to binary RPMs that hold applications or libraries
compiled for a particular architecture, RPM supports the
concept of platform-independent binary RPMs. These
platform-independent RPMs, called noarch as a shorted form of
���no architecture��� dependencies, provide applications or
libraries that are not dependent on any platform. Applications
written in Perl, Python, or other scripting languages often do
not depend on code compiled for a particular architecture. In
addition, compiled Java applications are usually free of
platform dependencies.
</para>
</sect3>
</sect2>
<sect2>
<title>Source RPMs</title>
<para>
The xcopilot package, mentioned previously, contains the
xcopilot application used for synchronization with Palm handheld
devices. The source code used to create this application is
stored in an xcopilot source RPM, for example:
</para>
<para>
xcopilot-0.6.6-3.src.rpm
</para>
<para>
By convention, source RPMs have a file name ending in .src.rpm.
</para>
<para>
Source RPMs should contain all the commands, usually in scripts,
necessary
</para>
<para>
to recreate the binary RPM. Having a source RPM means that you
can recreate the binary RPM at any time. This is a very
important goal of the RPM system.
</para>
<para>
Note
</para>
<para>
Source RPMs have nothing to do with open-source software
licenses. Linux is famous for being an open-source operating
system. In RPM terms, that means the source code for the Linux
kernel and most Linux applications are freely available as
source RPMs. But you can also make source RPMs for proprietary
programs. The key issue is that you are unlikely to distribute
the source RPMs for proprietary packages.
</para>
<para>
Furthermore, a number of open-source applications are not
available as source RPMs. That's a shame, since source RPMs
would make these applications easier to install.
</para>
<para>
While source RPMs hold the commands necessary to create the
binary RPM, there may be differences in your Linux environment
that would result in rebuilding a binary RPM that is different
from the original binary RPM. For example, the compile scripts
for some packages may add in optional code depending on which
libraries or which versions of libraries are found on your
system. Chapter 14 covers many issues in creating RPMs, and
Chapters 19 and 20 cover issues related to other versions of
Linux and other operating systems, respectively. If you follow
the guidelines when making your own RPMs, you should result in
source RPMs that reproduce binary RPMs as consistently as
possible.
</para>
</sect2>
</sect1>
<sect1>
<title>Querying the RPM Database</title>
<para>
The RPM database holds information about all the RPM packages
installed on your system. You can use this database to query what
is installed, to help determine if you have the latest versions of
software, and to verify that your system is properly set up, at
least from a packaging point of view.
</para>
<para>
The RPM database itself is stored in the directory /var/lib/rpm,
and should contain files like the following:
</para>
<para>
Basenames
</para>
<para>
Conflictname
</para>
<para>
__db.001
</para>
<para>
__db.002
</para>
<para>
__db.003
</para>
<para>
Dirnames
</para>
<para>
Filemd5s
</para>
<para>
Group
</para>
<para>
Installtid
</para>
<para>
Name
</para>
<para>
Packages
</para>
<para>
Providename
</para>
<para>
Provideversion
</para>
<para>
Pubkeys
</para>
<para>
Requirename
</para>
<para>
Requireversion
</para>
<para>
Sha1header
</para>
<para>
Sigmd5
</para>
<para>
Triggername
</para>
<para>
Cross-reference
</para>
<para>
Chapter 5 covers the database in more detail.
</para>
<para>
These files make up the RPM database. The file __db.001 and
similar files are lock files used by the RPM system. The other
files are databases in Berkeley DB format. The most important file
is Packages. The Packages file contains the header tag information
for each package indexed by an index number for each package. This
number slowly grows with time.
</para>
<para>
The other files, such as Name, Providename, and Group, exist to
speed access to particular types of information. Treat your RPM
database with care. Back up the files, especially after upgrading,
installing, or removing packages.
</para>
<para>
Note
</para>
<para>
Only the Packages file is essential. You can recreate the rest of
the files using the rpm --rebuilddb command, introduced in Chapter
5.
</para>
</sect1>
<sect1>
<title>Running RPM Commands</title>
<para>
The primary RPM command is simply rpm. One of the original goals
of the RPM system is providing ease of use. In support of this
goal, just about everything you want to do with the RPM system can
be done with this one command. For most usage, the command-line
parameters to the rpm command determine the actions it should
take.
</para>
<sect2>
<title>Working with the rpm command</title>
<para>
The rpm command performs the most common package-management
functions, along with a host of uncommon functions as well.
Table 3-1 lists the main operations you can perform with the rpm
command and the command-line options to specify the given
operations.
</para>
<para>
Table 3-1 The main rpm operations
</para>
<informaltable frame="all">
<tgroup cols="3">
<tbody>
<row>
<entry>
<para>
Operation
</para>
</entry>
<entry>
<para>
Short Option
</para>
</entry>
<entry>
<para>
Long Option
</para>
</entry>
</row>
<row>
<entry>
<para>
Upgrade/install
</para>
</entry>
<entry>
<para>
-U
</para>
</entry>
<entry>
<para>
--upgrade
</para>
</entry>
</row>
<row>
<entry>
<para>
Install
</para>
</entry>
<entry>
<para>
-I
</para>
</entry>
<entry>
<para>
--install
</para>
</entry>
</row>
<row>
<entry>
<para>
Remove
</para>
</entry>
<entry>
<para>
-e
</para>
</entry>
<entry>
<para>
--erase
</para>
</entry>
</row>
<row>
<entry>
<para>
Query
</para>
</entry>
<entry>
<para>
-q
</para>
</entry>
<entry>
<para>
--query
</para>
</entry>
</row>
<row>
<entry>
<para>
Verify
</para>
</entry>
<entry>
<para>
-V
</para>
</entry>
<entry>
<para>
--verify
</para>
</entry>
</row>
<row>
<entry>
<para>
Check signature
</para>
</entry>
<entry>
<para>
-K
</para>
</entry>
<entry>
<para>
--checksig
</para>
</entry>
</row>
<row>
<entry>
<para>
Freshen (upgrade) already-installed package
</para>
</entry>
<entry>
<para>
-F
</para>
</entry>
<entry>
<para>
--freshen
</para>
</entry>
</row>
<row>
<entry>
<para>
Initialize database
</para>
</entry>
<entry>
<para>
None
</para>
</entry>
<entry>
<para>
--initdb
</para>
</entry>
</row>
<row>
<entry>
<para>
Rebuild database
</para>
</entry>
<entry>
<para>
None
</para>
</entry>
<entry>
<para>
--rebuilddb
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
Using Table 3-1 as a guide, you can explore the options to the
rpm command. To install or upgrade a package, use the -U
command-line option:
</para>
<para>
# rpm -U filename.rpm
</para>
<para>
For example, to install the xcopilot RPM used as an example in
this chapter,
</para>
<para>
run the following command:
</para>
<para>
# rpm -U xcopilot-0.6.6-3.i386.rpm
</para>
<para>
To get extra feedback, you can use a command like the following,
with the
</para>
<para>
-h and -v options in conjunction with the ���U option:
</para>
<para>
# rpm -Uhv xcopilot-0.6.6-3.i386.rpm
</para>
<para>
When you run this command you will see more output than the
default, which is no output unless there are errors. With the
���h option, the rpm command will print a series of hash marks,
#, to provide feedback that the command is still running. With
the ���v option, the rpm command provides more verbose messages.
</para>
<para>
Note
</para>
<para>
The most common command to install a package is:
</para>
<para>
# rpm -Uhv package_file.rpm
</para>
<para>
This command upgrades a package with extra output. If the
package has not been installed, this command installs the
package. See Chapter 4 for more on upgrading and installing.
</para>
<para>
To remove a package (called erase in RPM terminology), use the
���e command-line option:
</para>
<para>
# rpm ���e package_name
</para>
<para>
Note
</para>
<para>
Notice that you install a package file using the file name that
ends in .rpm, but uninstall or erase a package without the .rpm
extension. This is because you install RPM files, but once
installed, you work with the installed packages. The file name
and the package name do not have to correspond, but typically
(and sanely) they have the same base name.
</para>
<para>
To list every RPM package installed on your system, use a
command like the following.
</para>
<para>
$ rpm ���qa
</para>
<para>
Expect to wait while this command completes. Most Linux systems
have numerous packages installed, which will result in many
lines of output. To better see the output, you can pipe this
command to the more command, as shown following:
</para>
<para>
rpm ���qa | more
</para>
<para>
You will then see the package listing one screen at a time.
</para>
<para>
Cross Reference
</para>
<para>
Appendix A lists all the options for the rpm command.
</para>
</sect2>
<sect2>
<title>Other RPM commands</title>
<para>
In addition to rpm, the RPM system includes a few more commands,
including rpmbuild and rpm2cpio.
</para>
<para>
The rpmbuild command helps build RPM packages. I describe its
usage in depth in Part II of this book.
</para>
<para>
The rpm2cpio command exports an RPM package file into the format
that the cpio command expects. The cpio command works with many
tape-backup packages. You can also take advantage of the fact
that cpio can list the individual files in a cpio archive or
extract files. To list the files in an RPM package, use a
command like the following:
</para>
<para>
$ rpm2cpio package_file.rpm | cpio ���t
</para>
<para>
For example, the following command lists all the files in the
xcopilot package:
</para>
<para>
$ rpm2cpio xcopilot-0.6.6-3.i386.rpm | cpio ���t
</para>
<para>
/etc/X11/applink/Applications/xcopilot.desktop
</para>
<para>
usr/bin/xcopilot
</para>
<para>
usr/doc/xcopilot-0.6.6
</para>
<para>
usr/doc/xcopilot-0.6.6/README
</para>
<para>
usr/include/X11/pixmaps/xcopilot.xpm
</para>
<para>
usr/include/X11/pixmaps/xcopilot2.xpm
</para>
<para>
3120 blocks
</para>
<para>
The rpm2cpio command can also help if you want to extract a
single file from the RPM package, using the cpio ���ivd
command-line options, as follows:
</para>
<para>
$ rpm2cpio xcopilot-0.6.6-3.i386.rpm | cpio ���ivd
usr/doc/xcopilot-0.6.6/README
</para>
<para>
This command will output local usr/doc/xcopilot-0.6.6
subdirectories and the README file located under
usr/doc/xcopilot-0.6.6.
</para>
<para>
The ���i option tells cpio to extract files. The ���d option
tells cpio to make any local subdirectories as needed
(usr/doc/xcopilot-0.6.6, in this example), and the ���v option
asks cpio to politely output verbose messages about what it
does. Of course, verbose is in the eye of the beholder; with
many Unix and Linux commands, verbose output is still somewhat
terse.
</para>
</sect2>
</sect1>
<sect1>
<title>Summary</title>
<para>
The RPM files, the RPM database, and the RPM commands are the
primary components that make up the RPM system. This chapter
introduces you to the format and types of RPM files, the
importance of maintaining the database, and the basic rpm command.
</para>
<para>
The next chapter covers the most frequently used RPM commands.
These commands allow you to install, uninstall, and update RPM
packages.
</para>
</sect1>
</chapter>
<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide-en.xml" "book" "chapter")
fill-column: 72
End:
-->
Author: elliss
Update of /cvs/docs/rpm-guide
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv987
Added Files:
rpm-guide-rpm-evolution-en.xml
Log Message:
--- NEW FILE rpm-guide-rpm-evolution-en.xml ---
<!-- $Id: -->
<chapter id="ch-rpm-evolution">
<title>RPM Feature Evolution</title>
<para>
Copyright (c) 2005 by Eric Foster-Johnson. This material may be
distributed only subject to the terms and conditions set forth in
the Open Publication License, v1.0 or later (the latest version is
presently available at http://www.opencontent.org/openpub/)
</para>
<para/>
<para>
Although RPM implementations are largely compatible from version to
version, RPM packagers must remember that RPM is a still-evolving
program and that its developers are adding features to it with each
new version. When producing RPM package files, packagers must keep
in mind the audience that will be using the final RPM package files.
They must decide which versions of RPM they intend the package to be
used with and must use only the lowest common denominator set of
features implemented in the oldest of the RPM versions they are
targeting. As a quick reference, keep in mind the RPM features noted
here and the RPM version in which they are introduced. In
considering these revisions of RPM, the main releases of interest
are RPM 2.5, RPM 3.0.5, RPM 4.0.4, and RPM 4.1.
</para>
<para>
RPM 2.5 is not widely used anymore; packages should target RPM 2.5
only if the intention is for the RPM package to install using
absolutely all RPM versions.
</para>
<para>
RPM 3.0.5 is the final release of the 3.x series of RPM. It was the
release of RPM shipped with Red Hat Linux 6.2 and older releases. It
is still in wide use by other vendors as well. Cobalt���s Linux
distributions use an RPM implementation version based on RPM 3.0.5,
for example. (Red Hat Linux was upgraded to RPM 4 via an errata.)
</para>
<para>
RPM 4.0.4 was used with the 7.x releases of Red Hat Linux, and RPM
4.1 first shipped with Red Hat Linux 8.0. Packages produced
targeting RPM 3.0.5 should work with nearly all implementations of
RPM still in use today. Packages produced targeting RPM 4.0.4 or RPM
4.1 will work only with recent RPM implementations.
</para>
<para>
RPM 2.5 is the oldest version of RPM that can, by any stretch of the
imagination, still be considered in use. With RPM 2.5, most of the
basic RPM features were in place, as well as more advanced functions
such as triggers and support for internationalization of Summary:,
Description:, and Group: tags in the RPM file header. RPM 2.5 was
also the first version of RPM to use the RPM version 3 RPM file
format.
</para>
<para>
RPM 2.5.3 added support for Epochs to the RPM header, implementing
RPMTAG_EPOCH.
</para>
<para>
RPM 2.5.4 introduced the %license and %readme file types, which can
be used in the RPM spec file to indicate license and README files.
</para>
<para>
RPM 2.5.6 added support for usage of the Epoch: keyword in the RPM
spec file, allowing you to force an Epoch for your package. The
Epoch: keyword replaced the older Serial: keyword, which
semantically behaved similarly.
</para>
<para>
RPM 2.5.7 enforced the previously implied standard that the "-"
character should not be used within the Version or Release fields in
the RPM spec file.
</para>
<para>
RPM 2.90 introduced support for signing and verifying RPM package
files using GPG, the GNU Privacy Guard.
</para>
<para>
RPM 2.91 allowed the usage of Provides: directives that defined
absolute paths to provided files. Prior to RPM 2.91, Provides: could
be used only for listing provided capabilities, not for using
statements like Provides: /path/to/file to indicate provided files.
</para>
<para>
RPM 3.0.2 permitted usage of multiple Provides: lines for the first
time, eliminating the need to combine all provided capabilities and
files on the same line in the spec file.
</para>
<para>
RPM 3.0.3 added support for versioned dependencies. Prior to RPM
3.0.3, spec files could indicate that a package required another
package or provided a specific capability, but they could not
indicate the acceptable versions of the required package or which
version of the capability the package provided.
</para>
<para>
RPM 3.0.4 introduced CompressedFileNames support to RPM. Prior to
RPM 3.0.4, RPM packaged the absolute paths of all archived files
within the package file. Package file headers contained statements
such as
</para>
<para>
fileName #0: /usr/bin/ar
</para>
<para>
fileName #1: /usr/bin/as
</para>
<para>
fileName #2: /usr/bin/gasp
</para>
<para>
fileName #3: /usr/bin/gprof
</para>
<para>
With CompressedFileNames support, the RPM package file header
instead stores the directory name, then just the base name of files
within that directory. Package file headers now contain statements
such as the following for a given directory with a number of files
within that directory:
</para>
<para>
dirName #0: /usr/bin
</para>
<para>
baseName dirIndex
</para>
<para>
#0 ar 0
</para>
<para>
#1 as 0
</para>
<para>
#2 gasp 0
</para>
<para>
#3 gprof 0
</para>
<para>
Each file entry now holds the file's base name within the directory,
as well as an index number that refers to the directory entry. Since
packages typically contain lots of files within the same directory,
CompressedFileNames support results in significant memory savings
when processing packages for installation.
</para>
<para>
RPM 3.0.5 added PayloadIsBzip2 support to RPM, allowing the data
payload of RPM package files to be compressed using bzip2 instead of
gzip. Even though RPM now supports bzip2 compression of package
files, this feature is rarely used in practice, since significantly
more memory and time is required to install bzip2-compressed RPM
package files than to install gzip-compressed RPM package files. RPM
3.0.5 also added support to RPM for manipulating existing RPM
version 4 file format packages; packages produced with RPM 3.0.5 can
only be RPM version 3 file format, however.
</para>
<para>
RPM 4.0 implemented several significant changes to RPM. RPM 4.0
created package files using RPM version 4 package file format. RPM
4.0 also switched from Berkeley db 1.85 to Berkeley db 3.1 as the
database program used for creation and manipulation of the RPM
database. The RPM package database file was renamed as well. The db3
package database file is /var/lib/rpm/Packages, and the older db1
package database file was /var/lib/rpm/packages.rpm. Changing the
package database file name allowed old and new versions to co-exist
if necessary, simplifying upgrades from older RPM releases to the
new RPM 4.0 release. RPM 4.0 also introduced the
PayloadFilesHavePrefix feature, changing the way archived files are
named within the RPM package file. RPM package files contain a cpio
archive of files. Prior to RPM 4.0, file names in the cpio archive
were stored without a root prefix. With PayloadFilesHavePrefix, all
file names within the cpio archive files now have a root prefix,
such as ./usr/bin/ar. This modification made it possible for RPM
package files to contain the root directory, ���./���. Additional
sanity-checking was added to the RPM 4.0 spec file parser; beginning
with 4.0, RPM no longer allows dangling symbolic links that contain
the BuildRoot. This change eliminates a class of common mistakes
made when producing RPMs. Finally, RPM 4.0 implicitly generates
Provides: directives; whenever a package header is read, the
Provides: directive Provides: %{name} =
%{epoch}:%{version}-%{release} is automatically generated, ensuring
that all packages explicitly provide themselves as a capability and
removing the need to provide self-capabilities within the package
spec file.
</para>
<para>
RPM 4.0.2 introduced the use of SHA-1 message digests to validate
RPM header regions.
</para>
<para>
RPM 4.0.3 added the %dev(type,major,minor) spec file directive,
allowing creation of device nodes. In addition, the %configure spec
file directive now supported --target and ���host, simplifying cross
compilation when using RPM. The %files directive was extended by
adding the %exclude subdirective that could be used to exclude files
from inclusion. Finally, RPM 4.0.3 switched back to creating package
files in RPM version 3 package file format by default, although it
still supports RPM version 4 package file format as well.
</para>
<para>
RPM 4.0.4 provided PartialHardlinkSets support. RPM package files
are sometimes created which contain multiple copies of the same
file, stored as hard links to save space. Prior to RPM 4.0.4, RPM
has always treated collections of hard links as an all-or-nothing
proposition; all hard links were created, or else none were created.
This behavior posed problems when some hard links in a set were
tagged with attributes such as %doc or %lang, since rpm commands
make it possible to install an RPM package file without installing
any files with %doc attributes. Prior to RPM 4.0.4, doing so would
break the hard link set, preventing creation of all hard links in
the set. PartialHardlinkSet corrects this problem by allowing
successful creation of subsets of the hard link set. RPM 4.0.4 also
provided automatic generation of Perl module Requires: directives.
find-requires now parses all packaged Perl scripts, generating any
determined dependencies. In addition, RPM 4.0.4 provides transaction
support for RPM.
</para>
<para>
RPM 4.1 adds separate header DSA and RSA signatures, allowing
verification of RPM package headers.
</para>
<para>
Finally, when considering the RPM features required by your prepared
package, remember that some required RPM features are specified
manually within the package spec file, while others are
automatically added by RPM during the RPM package file build
process. For example, usage of versioned Requires: directives in a
spec file will make the resulting RPM package file correctly
installable only by RPM release 3.0.3 or later. Similarly, the
preparation of any package using RPM release 4.0 or later will
automatically produce RPM package files that can only be manipulated
by releases of RPM that support the PayloadFilesHavePrefix feature.
In the first case, you chose to produce packages that worked with
RPM release 3.0.5 or later but not with RPM release 2.5 by including
a new directive in the package spec file. In the second case,
however, you did not explicitly produce packages that work only with
recent RPM releases. The simple fact that you built your RPM package
using RPM release 4.0 means that you automatically used features
that only RPM 4.0 and later releases understand. These automatic
internal requirements are quite common in the later versions; as a
result, the best practice is to decide the oldest version of RPM
that you wish to support, then to build all packages using that
version of RPM, keeping its feature set in mind as you prepare and
build the packages.
</para>
</chapter>
Author: elliss
Update of /cvs/docs/rpm-guide
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv955
Added Files:
rpm-guide-rpmbuild-en.xml
Log Message:
--- NEW FILE rpm-guide-rpmbuild-en.xml ---
<!-- $Id: -->
<chapter id="ch-rpmbuild">
<title>Controlling the Build with rpmbuild</title>
<para>
Copyright (c) 2005 by Eric Foster-Johnson. This material may be
distributed only subject to the terms and conditions set forth in
the Open Publication License, v1.0 or later (the latest version is
presently available at http://www.opencontent.org/openpub/)
</para>
<para/>
<para>
In This Chapter
</para>
<para>
*Building with the rpmbuild command
</para>
<para>
*Building RPMs without an external spec file
</para>
<para>
*Working with source RPMs
</para>
<para>
*Optimizing builds
</para>
<para>
*Signing built RPMs
</para>
<para>
The preceding chapters in this Part cover details on how to put
together RPMs. This chapter rounds out the discussion by delving
into more details on the rpmbuild command.
</para>
<para>
You can customize how rpmbuild creates RPMs, and you can use RPM
commands to test and debug your package.
</para>
<sect1>
<title>Building RPMs with the rpmbuild Command</title>
<para>
The rpmbuild command provides a workhorse command for building
RPMs in all sorts of ways. The basic syntax, as shown in Chapter
9, is:
</para>
<para>
rpmbuild -bBuildStage spec_file
</para>
<para>
The BuildStage is a letter, such as c, to prepare and compile the
application, executing through the %build section, or i, to
execute through the %install section. This allows you a good deal
of flexibility for building the entire RPM or stopping at some
point prior to a full build.
</para>
<para>
There���s more to the rpmbuild command, though. Quite a few
additional options allow you to further customize the build.
</para>
<para>
Note
</para>
<para>
As mentioned in Chapter 9, previous versions of the RPM system
used the rpm command with a -b, for build, option. This option is
no longer supported. Use the rpmbuild command to build RPMs.
</para>
<sect2>
<title>Customizing the build</title>
<para>
You can customize the rpmbuild command with the options listed
in Table 12-1.
</para>
<para>
Table 12-1 Extra build options for the rpmbuild command
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
Option
</para>
</entry>
<entry>
<para>
Usage
</para>
</entry>
</row>
<row>
<entry>
<para>
--buildroot directory
</para>
</entry>
<entry>
<para>
Override the default root directory for building with
directory, generally not very useful since most
packages already name a buildroot
</para>
</entry>
</row>
<row>
<entry>
<para>
--clean
</para>
</entry>
<entry>
<para>
Remove the build tree after building
</para>
</entry>
</row>
<row>
<entry>
<para>
--nobuild
</para>
</entry>
<entry>
<para>
Just test the spec file and do not run the build
</para>
</entry>
</row>
<row>
<entry>
<para>
--rmsource
</para>
</entry>
<entry>
<para>
Remove the sources after the build
</para>
</entry>
</row>
<row>
<entry>
<para>
--rmspec
</para>
</entry>
<entry>
<para>
Remove the spec file after the build
</para>
</entry>
</row>
<row>
<entry>
<para>
--short-circuit
</para>
</entry>
<entry>
<para>
With the -bc or -bi options, jump directly to the
given stage and resume the build from that stage
</para>
</entry>
</row>
<row>
<entry>
<para>
--sign
</para>
</entry>
<entry>
<para>
Sign the package with a GPG signature
</para>
</entry>
</row>
<row>
<entry>
<para>
--target platform
</para>
</entry>
<entry>
<para>
Build for the given platform. May not work if you
don't have the other platform build commands, such as
cross compilers, set up. Can work for Intel platforms
with i386, i686, and so on.
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect2>
<sect2>
<title>Testing the build</title>
<para>
One of the most useful options is --nobuild, which tells the
rpmbuild command to not build anything. This may seem silly, but
the --nobuild option is very useful for testing whether your
RPMs can be built. With the --nobuild option, the rpmbuild
command parses the spec file and checks for errors, but does not
run any of the build stages.
</para>
<para>
The --buildroot allows you to specify a different top-level
directory for building, overriding the BuildRoot tag in the spec
file. This means you can build in a separate location, which is
helpful in case there are mistakes. Using a separate directory
means the build won���t get mixed with anything else in the
build root directory.
</para>
</sect2>
<sect2>
<title>Debugging the build</title>
<para>
The --short-circuit option tells the rpmbuild command to restart
at a particular location in the build. Rather than working its
way through all the steps up to the build stage you ask for, the
--short-circuit option allows the rpmbuild command to restart
just at the step you ask for.
</para>
<para>
Note
</para>
<para>
This works with the -bc and -bi options only, as well as the -tc
and -ti options covered later in this chapter.
</para>
<para>
For example, if you run the rpmbuild -bc command to stop after
the %build section, you can use the --short-circuit option to
restart the build at the %build section. If you found a problem
in the %build section and corrected it, you can quickly get
going again by restarting the build at the %build section rather
than extracting all the sources yet again.
</para>
<para>
This option is most useful when you are compiling a package, hit
an error, and fix that error. Without the --short-circuit
option, you���ll likely end up spending a lot of time
recompiling the code you have already compiled.
</para>
<para>
During normal development of an RPM package, you will likely
execute each build section, one at a time, stop, fix any errors
and restart where you left off. You���ll go through this cycle a
number of times before the RPM finally builds right.
</para>
<para>
Warning
</para>
<para>
Never distribute an RPM made with the --short-circuit option.
Instead, once you have everything working, start from scratch
and rebuild the RPM. This is to avoid any problems with a
partially-created RPM.
</para>
</sect2>
<sect2>
<title>Cleaning up</title>
<para>
The --clean option tells the rpmbuild command to remove the
build tree when complete. This helps ensure that the next time
you run the rpmbuild command, you are starting from a known
situation.
</para>
<para>
For example:
</para>
<para>
$ rpmbuild --clean /usr/src/redhat/SPECS/jikes.spec
</para>
<para>
Executing(--clean): /bin/sh -e /var/tmp/rpm-tmp.98247
</para>
<para>
+ umask 022
</para>
<para>
+ cd /usr/src/redhat/BUILD
</para>
<para>
+ rm -rf jikes-1.17
</para>
<para>
+ exit 0
</para>
<para>
You can use the --clean option alone, as shown previously, or in
concert with another option such as -bi to build and install a
binary RPM. In the latter case, the rpmbuild command will clean
the built files after the rest of the command finishes.
</para>
<para>
Similarly, the --rmsource option tells the rpmbuild command to
remove the sources after completing the command. You can call
this option with another option, such as -bi for building and
installing a binary RPM (and then removing the sources), or
alone on the command line to remove the sources only.
</para>
<para>
For example:
</para>
<para>
rpmbuild --rmsource jikes.spec
</para>
<para>
Note
</para>
<para>
The abbreviation rm is short for remove. It comes from the Linux
rm command, used for removing files.
</para>
<para>
The --rmspec option tells the rpmbuild command to remove the
spec file when done with the command. As with the --rmsource
option, you can use the --rmspec option in conjunction with
another rpmbuild option or on its own to just remove the spec
file.
</para>
<para>
For example:
</para>
<para>
rpmbuild --rmspec jikes.spec
</para>
<para>
Warning
</para>
<para>
The file you are removing with this command is the spec file you
are passing to the command. Be careful, because you cannot undo
this operation and you have now lost your spec file, except
inside your source package.
</para>
</sect2>
<sect2>
<title>Building for other platforms</title>
<para>
The --target option tells the rpmbuild command to build a
package for another platform. You need to pass the name of the
platform. For example:
</para>
<para>
rpmbuild -bi --target i486-redhat-linux
</para>
<para>
The basic format is:
</para>
<para>
cpu-vendor-os
</para>
<para>
For example, i686-redhat-linux specifies a 686 CPU with Red Hat
Linux. Other CPUs include ppc for PowerPC and sparc for Sun
SPARC.
</para>
<para>
Cross Reference
</para>
<para>
The --target option sets the target architecture at build time.
Chapter 4 covers how you can use the --ignoreos and --ignorearch
options when installing RPMs to ignore the operating system and
architecture that is flagged within the RPM. Of course, this
works only if you are installing on a compatible architecture.
</para>
<para>
On the surface level, the --target option overrides some of the
macros in the spec file, %_target, %_target_arch, and
%_target_os. This flags the RPM for the new target platform.
</para>
<para>
Under the covers, setting the architecture macros is not enough.
You really cannot create a PowerPC executable, for example, on
an Intel-architecture machine, unless you have a PowerPC cross
compiler, a compiler that can make PowerPC executables.
</para>
<para>
Warning
</para>
<para>
Set the target with care. Make sure you can really build
executable programs for that architecture.
</para>
<para>
If you try to compile a system that uses the GNU configure
system to configure the build, your target will likely be
ignored. For example, if you try to build the aforementioned
jikes package with a target of ppc-ibm-aix, to specify IBM���s
UNIX, called AIX, on a PowerPC architecture, you will see the
target ignored as the configure system detects that it's running
on Linux on an i686 architecture.
</para>
<para>
For example:
</para>
<para>
$ rpmbuild -bc --target ppc-ibm-aix
/usr/src/redhat/SPECS/jikes.spec
</para>
<para>
Building target platforms: ppc-ibm-aix
</para>
<para>
Building for target ppc-ibm-aix
</para>
<para>
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.94955
</para>
<para>
+ umask 022
</para>
<para>
+ cd /usr/src/redhat/BUILD
</para>
<para>
+ LANG=C
</para>
<para>
+ export LANG
</para>
<para>
+ cd /usr/src/redhat/BUILD
</para>
<para>
+ rm -rf jikes-1.17
</para>
<para>
+ /usr/bin/gzip -dc /usr/src/redhat/SOURCES/jikes-1.17.tar.gz
</para>
<para>
+ tar -xf -
</para>
<para>
+ STATUS=0
</para>
<para>
+ '[' 0 -ne 0 ']'
</para>
<para>
+ cd jikes-1.17
</para>
<para>
++ /usr/bin/id -u
</para>
<para>
+ '[' 500 = 0 ']'
</para>
<para>
++ /usr/bin/id -u
</para>
<para>
+ '[' 500 = 0 ']'
</para>
<para>
+ /bin/chmod -Rf a+rX,g-w,o-w .
</para>
<para>
+ exit 0
</para>
<para>
Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.15710
</para>
<para>
+ umask 022
</para>
<para>
+ cd /usr/src/redhat/BUILD
</para>
<para>
+ cd jikes-1.17
</para>
<para>
+ LANG=C
</para>
<para>
+ export LANG
</para>
<para>
+ ./configure CXXFLAGS=-O3 --prefix=/tmp/jikesrpm/usr
</para>
<para>
checking for a BSD-compatible install... /usr/bin/install -c
</para>
<para>
checking whether build environment is sane... yes
</para>
<para>
checking for gawk... gawk
</para>
<para>
checking whether make sets ${MAKE}... yes
</para>
<para>
checking whether to enable maintainer-specific portions of
Makefiles... no
</para>
<para>
checking build system type... i686-pc-linux-gnu
</para>
<para>
checking host system type... i686-pc-linux-gnu
</para>
<para>
checking for g++... g++
</para>
<para>
As you can see, the command starts out with the target as the
platform, but the configure script soon overrides that, as shown
at the end of the truncated output.
</para>
</sect2>
</sect1>
<sect1>
<title>Building RPMs Without an External Spec File</title>
<para>
Most of the options for the rpmbuild command require an RPM spec
file. This file defines all the necessary parameters for the RPM
to build. If you���ve downloaded an application, though, you may
not have all the information needed to build a spec file. In
addition, writing the spec file is the most time-consuming task
when building RPMs. If you are lucky, the provider of a given
application may have already created a spec file and included the
spec file within the source distribution.
</para>
<sect2>
<title>Options for working with tar archives</title>
<para>
A special set of options aims toward building RPMs with spec
files stored in tar archives, also called tarballs. Tarballs are
files combined with the tar (tape archiver) utility and then
optionally compressed, usually with the gzip command. Because
this format is used so often for UNIX and Linux software, you
can use a set of -t options to the rpmbuild command that mimic
the -b options.
</para>
<para>
The basic syntax follows:
</para>
<para>
rpmbuild -tBuildStage compressed_tar_archive
</para>
<para>
The -t option is a lot like the -b option covered in Chapter 9,
except -t tells rpmbuild to build an RPM from a compressed tar
archive instead of from an RPM spec file. You still need a spec
file. These commands just assume that the spec file is located
within the tar archive. The extra BuildStage option is a special
code that tells the rpmbuild command how far to go when
building. Table 12-2 lists these options:
</para>
<para>
Table 12-2 Options for building with rpmbuild with tar archives
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
Option
</para>
</entry>
<entry>
<para>
Usage
</para>
</entry>
</row>
<row>
<entry>
<para>
-ta
</para>
</entry>
<entry>
<para>
Build all, both a binary and source RPM
</para>
</entry>
</row>
<row>
<entry>
<para>
-tb
</para>
</entry>
<entry>
<para>
Build a binary RPM
</para>
</entry>
</row>
<row>
<entry>
<para>
-tc
</para>
</entry>
<entry>
<para>
Stop after the %build section
</para>
</entry>
</row>
<row>
<entry>
<para>
-tp
</para>
</entry>
<entry>
<para>
Stop after the %prep section
</para>
</entry>
</row>
<row>
<entry>
<para>
-ti
</para>
</entry>
<entry>
<para>
Stop after the %install section
</para>
</entry>
</row>
<row>
<entry>
<para>
-tl
</para>
</entry>
<entry>
<para>
Check the listing of files for the RPM
</para>
</entry>
</row>
<row>
<entry>
<para>
-ts
</para>
</entry>
<entry>
<para>
Build a source RPM only
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
Note
</para>
<para>
These command-line options work with a tar archive or a
compressed tar archive.
</para>
</sect2>
<sect2>
<title>The expected archive structure</title>
<para>
To build a package this way, the tar archive must have enough of
an expected structure, such as a configure script and a Makefile
with the expected make targets. The most crucial element is that
the tar archive must have the package spec file.That���s because
the rpmbuild command doesn���t know how to build every program
in the universe. Instead, rpmbuild expects to find a spec file
to tell it what to do. If you see an error like the following,
then your tar archive likely is missing the spec file:
</para>
<para>
$ rpmbuild -tc vixie-cron*tar.gz
</para>
<para>
error: Name field must be present in package: (main package)
</para>
<para>
error: Version field must be present in package: (main package)
</para>
<para>
error: Release field must be present in package: (main package)
</para>
<para>
error: Summary field must be present in package: (main package)
</para>
<para>
error: Group field must be present in package: (main package)
</para>
<para>
error: License field must be present in package: (main package)
</para>
<para>
These errors show expected tags from the missing spec file.
</para>
<para/>
<para/>
</sect2>
</sect1>
<sect1>
<title>Working with Source RPMs</title>
<para>
Most of your work with the rpmbuild command will likely be to
create binary RPMs after you have the sources for an application
and a spec file. You can also get a lot of mileage out of source
RPMs, whether you build them or download them.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 10 covers the spec file in depth.
</para>
<para>
Because they are RPMs themselves, source RPMs act like other RPMs.
For example, you can use the rpm -i command to install a source
RPM. This installs the sources provided by the source RPM, not the
actual application. Normally, when you install a source RPM on a
Red Hat Linux system, the package gets installed into
/usr/src/redhat.
</para>
<para>
Note
</para>
<para>
This directory is obviously specific to Red Hat Linux. On other
Linux distributions, you'll likely see directories such as
/usr/src/OpenLinux for SCO (formerly Caldera) OpenLinux.
</para>
<para>
Installing a source RPM is not exactly the same as installing a
binary RPM. For example, the rpm command does not update the RPM
database when you install a source RPM. In addition, listing the
files in a source RPM only shows the relative paths, not the full
paths.
</para>
<para>
Once installation is complete, you can use the rpmbuild command to
create a binary RPM from the sources in the source RPM, using the
-b command-line options introduced in Chapter 9. The next sections
show more shortcuts with source RPMs.
</para>
<sect2>
<title>Rebuilding binary RPMS from source RPMs</title>
<para>
As a shortcut, you do not have to install a source RPM to create
a binary RPM. Instead, you can build the binary RPM directory
using the --rebuild option.
</para>
<para>
The --rebuild option tells the rpmbuild command to rebuild a
binary RPM from a source RPM file. The basic syntax is:
</para>
<para>
rpmbuild --rebuild package.src.rpm
</para>
<para>
This command builds a binary RPM out of a source RPM with a
minimum of fuss. For example:
</para>
<para>
$ rpmbuild --rebuild unix2dos-2.2-17.src.rpm
</para>
<para>
Installing unix2dos-2.2-17.src.rpm
</para>
<para>
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.15828
</para>
<para>
+ umask 022
</para>
<para>
+ cd /usr/src/redhat/BUILD
</para>
<para>
+ LANG=C
</para>
<para>
+ export LANG
</para>
<para>
+ cd /usr/src/redhat/BUILD
</para>
<para>
+ rm -rf unix2dos-2.2
</para>
<para>
+ /bin/mkdir -p unix2dos-2.2
</para>
<para>
+ cd unix2dos-2.2
</para>
<para>
+ /usr/bin/gzip -dc /usr/src/redhat/S
OURCES/unix2dos-2.2.src.tar.gz
</para>
<para>
+ tar -xf -
</para>
<para>
+ STATUS=0
</para>
<para>
+ '[' 0 -ne 0 ']'
</para>
<para>
++ /usr/bin/id -u
</para>
<para>
+ '[' 500 = 0 ']'
</para>
<para>
++ /usr/bin/id -u
</para>
<para>
+ '[' 500 = 0 ']'
</para>
<para>
+ /bin/chmod -Rf a+rX,g-w,o-w .
</para>
<para>
+ echo 'Patch #0 (unix2dos-mkstemp.patch):'
</para>
<para>
Patch #0 (unix2dos-mkstemp.patch):
</para>
<para>
+ patch -p1 -b --suffix .sec -s
</para>
<para>
+ echo 'Patch #1 (unix2dos-2.2-segfault.patch):'
</para>
<para>
Patch #1 (unix2dos-2.2-segfault.patch):
</para>
<para>
+ patch -p1 -b --suffix .segf -s
</para>
<para>
+ echo 'Patch #2 (unix2dos-2.2-manpage.patch):'
</para>
<para>
Patch #2 (unix2dos-2.2-manpage.patch):
</para>
<para>
+ patch -p1 -b --suffix .man -s
</para>
<para>
+ perl -pi -e 's,^#endif.*,#endif,g;s,^#else.*,#else,g'
unix2dos.c unix2dos.h
</para>
<para>
+ exit 0
</para>
<para>
Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.60650
</para>
<para>
+ umask 022
</para>
<para>
+ cd /usr/src/redhat/BUILD
</para>
<para>
+ cd unix2dos-2.2
</para>
<para>
+ LANG=C
</para>
<para>
+ export LANG
</para>
<para>
+ gcc -O2 -march=i386 -mcpu=i686 -ounix2dos unix2dos.c
</para>
<para>
+ exit 0
</para>
<para>
Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.35128
</para>
<para>
+ umask 022
</para>
<para>
+ cd /usr/src/redhat/BUILD
</para>
<para>
+ cd unix2dos-2.2
</para>
<para>
+ LANG=C
</para>
<para>
+ export LANG
</para>
<para>
+ rm -rf /var/tmp/unix2dos-root
</para>
<para>
+ mkdir -p /var/tmp/unix2dos-root/usr/bin /var/tmp/unix2dos-
</para>
<para>
root/usr/share/man/man1
</para>
<para>
+ install -m755 unix2dos /var/tmp/unix2dos-root/usr/bin
</para>
<para>
+ install -m444 unix2dos.1
/var/tmp/unix2dos-root/usr/share/man/man1
</para>
<para>
+ /usr/lib/rpm/redhat/brp-compress
</para>
<para>
+ /usr/lib/rpm/redhat/brp-strip
</para>
<para>
+ /usr/lib/rpm/redhat/brp-strip-comment-note
</para>
<para>
Processing files: unix2dos-2.2-17
</para>
<para>
Executing(%doc): /bin/sh -e /var/tmp/rpm-tmp.12033
</para>
<para>
+ umask 022
</para>
<para>
+ cd /usr/src/redhat/BUILD
</para>
<para>
+ cd unix2dos-2.2
</para>
<para>
+ DOCDIR=/var/tmp/unix2dos-root/usr/share/doc/unix2dos-2.2
</para>
<para>
+ export DOCDIR
</para>
<para>
+ rm -rf /var/tmp/unix2dos-root/usr/share/doc/unix2dos-2.2
</para>
<para>
+ /bin/mkdir -p
/var/tmp/unix2dos-root/usr/share/doc/unix2dos-2.2
</para>
<para>
+ cp -pr COPYRIGHT
/var/tmp/unix2dos-root/usr/share/doc/unix2dos-2.2
</para>
<para>
+ exit 0
</para>
<para>
Finding Provides: /usr/lib/rpm/find-provides
</para>
<para>
Finding Requires: /usr/lib/rpm/find-requires
</para>
<para>
PreReq: rpmlib(PayloadFilesHavePrefix) <= 4.0-1
rpmlib(CompressedFileNames)
</para>
<para>
<= 3.0.4-1
</para>
<para>
Requires(rpmlib): rpmlib(PayloadFilesHavePrefix) <= 4.0-1
</para>
<para>
rpmlib(CompressedFileNames) <= 3.0.4-1
</para>
<para>
Requires: libc.so.6 libc.so.6(GLIBC_2.0) libc.so.6(GLIBC_2.1)
</para>
<para>
Checking for unpackaged file(s): /usr/lib/rpm/check-files
/var/tmp/unix2dos-root
</para>
<para>
Wrote: /usr/src/redhat/RPMS/i386/unix2dos-2.2-17.i386.rpm
</para>
<para>
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.47653
</para>
<para>
+ umask 022
</para>
<para>
+ cd /usr/src/redhat/BUILD
</para>
<para>
+ cd unix2dos-2.2
</para>
<para>
+ rm -rf /var/tmp/unix2dos-root
</para>
<para>
+ exit 0
</para>
<para>
Executing(--clean): /bin/sh -e /var/tmp/rpm-tmp.47653
</para>
<para>
+ umask 022
</para>
<para>
+ cd /usr/src/redhat/BUILD
</para>
<para>
+ rm -rf unix2dos-2.2
</para>
<para>
+ exit 0
</para>
<para>
With the --rebuild option, the rpmbuild command installs the
source RPM for you and then performs the preparation, compile,
and installation stages of building a binary RPM. Unless there
are errors, you should have a new binary RPM file.
</para>
<para>
When complete, the rpmbuild --rebuild command cleans out the
built files in the build directory, as if the --clean option
were used. The rpmbuild --rebuild command also removes the
installed sources and spec file upon completion.
</para>
</sect2>
<sect2>
<title>Recompiling binaries from source RPMs</title>
<para>
If you just want to recompile the files in a source RPM, you can
use the --recompile option. The --recompile option tells the
rpmbuild command to recompile the binary application from a
source RPM.
</para>
<para>
For example:
</para>
<para>
rpmbuild --recompile package.src.rpm
</para>
<para>
This is the same as installing the source RPM and then running
rpmbuild -bc --clean with the package spec file.
</para>
<para>
Note
</para>
<para>
There is no difference between --recompile and --rebuild in RPM
4.1. RPM 4.2 fixes this problem.
</para>
<para/>
<para/>
</sect2>
<sect2>
<title>SRPMS? Finding source RPMs</title>
<para>
Often, source RPMs are abbreviated as SRPMs. In fact, if you see
a directory named SRPM or SRPMS, chances are the directory holds
source RPMs. (Red Hat uses this convention for its Linux
distributions.)
</para>
<para>
The SRPMS directories on Red Hat CD-ROMs or on the Red Hat FTP
Internet site, ftp.redhat.com, indicate directories that hold
source RPMs.
</para>
</sect2>
</sect1>
<sect1>
<title>Signing Built RPMs</title>
<para>
Signing RPMs adds an extra level of trustworthiness to your RPMs.
A digital signature helps establish that the package comes from
you, really you, and not from someone masquerading as you.
Unfortunately, the RPM system requires a bit of set up work before
you can sign RPMs.
</para>
<sect2>
<title>Checking that the GPG software is installed</title>
<para>
To sign packages, you need to ensure that you have the gpg
command installed and configured. To check that this command is
installed, use a command like the following:
</para>
<para>
$ rpm -qf `which gpg`
</para>
<para>
gnupg-1.0.7-6
</para>
<para>
This shows that the command is available.
</para>
<para>
GPG and PGP? Acronyms Explained
</para>
<para>
The RPM documentation uses GPG and PGP pretty much
interchangeably, so much so, in fact, that you may think these
are typographical errors. Not so.
</para>
<para>
PGP stands for Pretty Good Privacy. Invented by Phil Zimmerman,
PGP was originally invented to encrypt e-mail to allow for
private communication. Based on a public-key cryptography
algorithm, PGP also supports encrypted digital signatures. These
signatures allow you to verify that a package you have
downloaded really comes from the vendor you think it does. You
do this by using the vendor���s public key.
</para>
<para>
GPG stands for GNU Privacy Guard, a free, open-source
implementation of PGP from the GNU project. GPG aims to be
compatible with the OpenPGP Internet standard as defined in RFC
2440. It started when a number of developers wanted a free
implementation. One such free implementation, GPG, allows Linux
vendors such as Red Hat to include PGP in their products. So, in
a sense, GPG provides PGP.
</para>
<para>
PGP has a long and somewhat troubled history as an open-source
product and as a commercial product. See www.philzimmermann.com
for background on PGP and its long history. See www.gnupg.org
for more details on GPG.
</para>
</sect2>
<sect2>
<title>Configuring a signature</title>
<para>
To configure a signature, you first need to create a new key
with the gpg command, using the --gen-key option, as shown
following:
</para>
<para>
$ gpg --gen-key
</para>
<para>
gpg (GnuPG) 1.0.7; Copyright (C) 2002 Free Software Foundation,
Inc.
</para>
<para>
This program comes with ABSOLUTELY NO WARRANTY.
</para>
<para>
This is free software, and you are welcome to redistribute it
</para>
<para>
under certain conditions. See the file COPYING for details.
</para>
<para/>
<para>
gpg: Warning: using insecure memory!
</para>
<para>
gpg: please see http://www.gnupg.org/faq.html for more
information
</para>
<para>
gpg: keyring `/home2/ericfj/.gnupg/secring.gpg' created
</para>
<para>
gpg: keyring `/home2/ericfj/.gnupg/pubring.gpg' created
</para>
<para>
Please select what kind of key you want:
</para>
<para>
(1) DSA and ElGamal (default)
</para>
<para>
(2) DSA (sign only)
</para>
<para>
(4) ElGamal (sign and encrypt)
</para>
<para>
(5) RSA (sign only)
</para>
<para>
Your selection? 1
</para>
<para>
DSA keypair will have 1024 bits.
</para>
<para>
About to generate a new ELG-E keypair.
</para>
<para>
minimum keysize is 768 bits
</para>
<para>
default keysize is 1024 bits
</para>
<para>
highest suggested keysize is 2048 bits
</para>
<para>
What keysize do you want? (1024)
</para>
<para/>
<para>
Requested keysize is 1024 bits
</para>
<para>
Please specify how long the key should be valid.
</para>
<para>
0 = key does not expire
</para>
<para>
<n> = key expires in n days
</para>
<para>
<n>w = key expires in n weeks
</para>
<para>
<n>m = key expires in n months
</para>
<para>
<n>y = key expires in n years
</para>
<para>
Key is valid for? (0)
</para>
<para/>
<para>
You need a User-ID to identify your key; the software constructs
the user id
</para>
<para>
from Real Name, Comment and Email Address in this form:
</para>
<para>
"Heinrich Heine (Der Dichter) <heinrichh(a)duesseldorf.de>"
</para>
<para/>
<para>
Real name: Eric Foster-Johnson
</para>
<para>
Email address: please_no_spam(a)nospam.com
</para>
<para>
Comment: Example for Red Hat RPM Guide
</para>
<para>
You selected this USER-ID:
</para>
<para>
"Eric Foster-Johnson (Example for Red Hat RPM Guide)
<erc(a)no_spam.com>"
</para>
<para>
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit?
</para>
<para>
O
</para>
<para>
You need a Passphrase to protect your secret key.
</para>
<para/>
<para>
Enter passphrase:
</para>
<para>
We need to generate a lot of random bytes. It is a good idea to
perform
</para>
<para>
some other action (type on the keyboard, move the mouse, utilize
the
</para>
<para>
disks) during the prime generation; this gives the random number
</para>
<para>
generator a better chance to gain enough entropy.
</para>
<para>
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
</para>
<para>
+++++++++++++++++++++++++++++++++++..+++++..++++++++++>++++++++++........+++++
</para>
<para>
gpg: /home2/ericfj/.gnupg/trustdb.gpg: trustdb created
</para>
<para>
public and secret key created and signed.
</para>
<para>
key marked as ultimately trusted.
</para>
<para/>
<para>
pub 1024D/01681C24 2002-11-05 Eric Foster-Johnson (Example for
Red Hat RPM
</para>
<para>
Guide) <please_no_spam(a)nospam.com>
</para>
<para>
Key fingerprint = 8C14 A2E9 47D1 301B 2153 7CDF BEE5 9C10 0268
1D24
</para>
<para>
sub 1024g/1A15D6C8 2002-11-05
</para>
<para>
You can choose the default options for most choices. You need to
enter a real name, an e-mail address, and a pass phrase.
Remember the pass phrase. You will need to enter the pass phrase
every time you wish to sign a package.
</para>
<para>
Once you have a key, the next step is to set up some RPM macros.
There are a number of places you can do this, but using the
.rpmmacros file in your home directory is one of the easiest.
Edit this file as shown in the following example:
</para>
<para>
%_signature gpg
</para>
<para>
%_gpg_path /home2/ericfj/.gnupg
</para>
<para>
%_gpg_name EricFJ (Eric Key) <erc(a)no_spam.com>
</para>
<para>
%_gpgbin /usr/bin/gpg
</para>
<para>
Add lines like these to the $HOME/.rpmmacros file. (Create this
file if it does not exist.)
</para>
<para>
Cross Reference
</para>
<para>
Chapter 21 covers RPM macros and the $HOME/.rpmmacros file.
</para>
<para>
Inside the file, change the %gpg_path macro to the .gnupg
directory under your home directory (or the root user���s home
directory). Change the %_gpg_name macro to the name you have
entered into the gpg program.
</para>
</sect2>
<sect2>
<title>Signing with the rpmbuild command</title>
<para>
The --sign option tells the rpmbuild command to sign the created
package. You need to have configured the RPM system for your
signature as shown in the previous sections.
</para>
<para>
When you then build an RPM, you will be prompted for your pass
phrase prior to the package build. For example, the following
shows this prompt (and truncates the rest of the rpmbuild
messages that follow):
</para>
<para>
$ rpmbuild -bb --sign xtoolwait-1.2.spec
</para>
<para>
Enter pass phrase:
</para>
<para>
Pass phrase is good.
</para>
</sect2>
<sect2>
<title>Signing with the rpm command</title>
<para>
In addition to the --sign option for the rpmbuild command, you
can sign packages that have already been created using the rpm
command. The --addsign and --resign options generate new
signatures and insert them into the passed-in package file. The
basic syntax is:
</para>
<para>
rpm --addsign package.rpm
</para>
<para>
rpm --resign package.rpm
</para>
<para>
The --addsign option adds another signature to the RPM. RPM
versions prior to 4.1 allowed you to sign a package with
multiple keys, which causes problems for automatic verification.
Because of that, use the --resign option, which removes the old
signature and inserts a new signature into the package.
</para>
</sect2>
<sect2>
<title>Verifying signatures</title>
<para>
You can verify the RPM signature to ensure that the package has
not been modified since it has been signed. Verification also
checks that the package is signed by the key that matches the
claimed vendor.
</para>
<para>
To verify the signature in an RPM, use the -K option to the rpm
command. The basic syntax is:
</para>
<para>
rpm -K package.rpm
</para>
<para>
Note
</para>
<para>
This is the rpm command, not the rpmbuild command.
</para>
<para>
This command accepts the options shown in Table 12-3 to turn off
checking for certain types of signatures.
</para>
<para>
Table 12-3 Options to turn off signature checking
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
Option
</para>
</entry>
<entry>
<para>
Usage
</para>
</entry>
</row>
<row>
<entry>
<para>
--nogpg
</para>
</entry>
<entry>
<para>
Don���t check for GPG signatures
</para>
</entry>
</row>
<row>
<entry>
<para>
--nomd5
</para>
</entry>
<entry>
<para>
Don���t check for MD5 signatures
</para>
</entry>
</row>
<row>
<entry>
<para>
--nopgp
</para>
</entry>
<entry>
<para>
Don���t check for PGP signatures
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
You can also use the --checksig option, which is the same as -K.
When you run this command on a package that has a verifiable
key, you will see output like the following:
</para>
<para>
# rpm -K xtoolwait-1.3-3.src.rpm
</para>
<para>
xtoolwait-1.3-3.src.rpm: (sha1) dsa sha1 md5 gpg OK
</para>
<para>
This verifies that the package has not been changed from when it
was first signed. It also verifies that the signature matches
the public key from the vendor of the package. This goes a long
ways toward verifying that the package is indeed legitimate.
</para>
<para>
To get more information, add a -v (verbose) option. For example:
</para>
<para>
$ rpm -Kv vixie-cron-3.0.1-69.src.rpm
</para>
<para>
vixie-cron-3.0.1-69.src.rpm:
</para>
<para>
Header V3 DSA signature: OK, key ID db42a60e
</para>
<para>
Header SHA1 digest: OK
(ecbb244ab022ecd23114bb1d6c9bdeb74f8d9520)
</para>
<para>
MD5 digest: OK (fb0a75eca1d526d391c36dc956c23bdd)
</para>
<para>
V3 DSA signature: OK, key ID db42a60e
</para>
<para>
If you run this command on a package that does not verify,
you���ll see an error like the following:
</para>
<para>
# rpm --checksig xtoolwait-1.3-3.src.rpm
</para>
<para>
xtoolwait-1.3-3.src.rpm: (SHA1) DSA sha1 md5 (GPG) NOT OK
(MISSING KEYS: GPG#db42a60e)
</para>
<para>
Items that fail are listed in uppercase, such as DSA, while
items that succeed appear in lowercase. In this example, the
sha1 and md5 tests succeeded, while the DSA test failed. This
failure does not necessarily mean that the package is not
legitimate. This failure can mean one of three things:
</para>
<para>
1.The package was not properly signed in the first place. That
is, it is a legitimate package but the package author did not
properly sign the RPM.
</para>
<para>
2.The package has been modified in some way. That is, the
package is not legitimate.
</para>
<para>
3.The RPM system has not been initialized with the public key
from the package vendor.
</para>
<para>
From this error, you don���t yet know whether the package is
legitimate or not. The first step, though, is to check that you
have imported the proper public key from the package vendor.
</para>
</sect2>
<sect2>
<title>Importing public keys</title>
<para>
The --import option to the rpm command imports the public key
from a given vendor. The format for this key follows:
</para>
<para>
The following public key can be used to verify RPM packages
built and
</para>
<para>
signed by Red Hat, Inc. using `rpm -K' using the GNU GPG
package.
</para>
<para>
Questions about this key should be sent to security(a)redhat.com.
</para>
<para/>
<para>
-----BEGIN PGP PUBLIC KEY BLOCK-----
</para>
<para>
Version: GnuPG v1.0.0 (GNU/Linux)
</para>
<para>
Comment: For info see http://www.gnupg.org
</para>
<para/>
<para>
mQGiBDfqVEqRBADBKr3Bl6PO8BQ0H8sJoD6p9U7Yyl7pjtZqioviPwXP+DCWd4u8
</para>
<para>
HQzcxAZ57m8ssA1LK1Fx93coJhDzM130+p5BG9mYSPShLabR3N1KXdXAYYcowTOM
</para>
<para>
GxdwYRGr1Spw8QydLhjVfU1VSl4xt6bupPbFJbyjkg5Z3P7BlUOUJmrx3wCgobNV
</para>
<para>
EDGaWYJcch5z5B1of/41G8kEAKii6q7Gu/vhXXnLS6m15oNnPVybyngiw/23dKjS
</para>
<para>
ti/PYrrL2J11P2ed0x7zm8v3gLrY0cue1iSba+8glY+p31ZPOr5ogaJw7ZARgoS8
</para>
<para>
BwjyRymXQp+8Dete0TELKOL2/itDOPGHW07SsVWOR6cmX4VlRRcWB5KejaNvdrE5
</para>
<para>
4XFtOd04NMgWI63uqZc4zkRa+kwEZtmbz3tHSdWCCE+Y7YVP6IUf/w6YPQFQriWY
</para>
<para>
FiA6fD10eB+BlIUqIw80EqjsBKmCwvKkn4jg8kibUgj4/TzQSx77uYokw1EqQ2wk
</para>
<para>
OZoaEtcubsNMquuLCMWijYhGBBgRAgAGBQI36lRyAAoJECGRgM3bQqYOhyYAnj7h
</para>
<para>
VDY/FJAGqmtZpwVp9IlitW5tAJ4xQApr/jNFZCTksnI+4O1765F7tA==
</para>
<para>
=3AHZ
</para>
<para>
-----END PGP PUBLIC KEY BLOCK-----
</para>
<para>
Note
</para>
<para>
For reasons of space, this is not a complete key.
</para>
<para>
You need to pass the name of the text file that holds the key to
the rpm --import command, as shown following:
</para>
<para>
rpm --import key_file
</para>
<para>
Note
</para>
<para>
You must be logged in as the root user to import keys.
</para>
<para>
For example:
</para>
<para>
# rpm --checksig xtoolwait-1.3-3.src.rpm
</para>
<para>
xtoolwait-1.3-3.src.rpm: (SHA1) DSA sha1 md5 (GPG) NOT OK
(MISSING KEYS: GPG#db42a60e)
</para>
<para/>
<para>
# rpm --import RPM-GPG-KEY
</para>
<para/>
<para>
# rpm --checksig xtoolwait-1.3-3.src.rpm
</para>
<para>
xtoolwait-1.3-3.src.rpm: (sha1) dsa sha1 md5 gpg OK
</para>
<para>
This example shows an error message when trying to verify the
key. Then, after importing the Red Hat public key, the
verification works.
</para>
<para>
If, after importing this key, you still have problems, you can
assume there are problems with the package. Many administrators
will refuse to install such packages.
</para>
<para>
Warning
</para>
<para>
You should be careful with packages that have signatures that do
not verify.
</para>
<para>
To list the available keys, use a command like the following:
</para>
<para>
$ rpm -qa | grep -i gpg
</para>
<para>
gpg-pubkey-db42a60e-37ea5438
</para>
<para>
This example shows one key installed.
</para>
<para>
Note
</para>
<para>
You can erase this key as if it were a package, using the rpm -e
command.
</para>
</sect2>
<sect2>
<title>Getting the Red Hat public key</title>
<para>
Strangely enough, the Red Hat public key is not installed when
you install Red Hat Linux 8.0. If you need the key, the Red Hat
public key is available on the root directory of all Red Hat
Linux CD-ROMs, as shown in the following listing:
</para>
<para>
$ ls /mnt/cdrom/
</para>
<para>
EULA GPL README RedHat/ RPM-GPG-KEY SRPMS/ TRANS.TBL
</para>
<para>
Simply copy the RPM-GPG-KEY file to get the public key. Then use
the rpm --import command with this key file.
</para>
<para>
Note
</para>
<para>
You can also download this key file from the Red Hat FTP site,
at ftp://ftp.redhat.com/pub/redhat/linux/8.0/en/os/i386/.
</para>
</sect2>
</sect1>
<sect1>
<title>Summary</title>
<para>
This chapter covers options for the rpmbuild command that allow
you to achieve a finer grain of control over how the command
works. For example, the --short-circuit option tells the rpmbuild
command to build just the stages you ask for. This helps when you
have problems in one area of building an RPM and don���t want to
start over each time you try to see if the problem is solved.
</para>
<para>
The rpmbuild command also supports a set of -t options that work
like the -b options, except the -t options try to build an RPM
from a tar archive of sources (a tarball) instead of an RPM spec
file. In this case, the rpmbuild command tries to work without a
spec file.
</para>
<para>
The --rebuild option tells the rpmbuild command to install a
source RPM, build the binary RPM, and clean out the installed
source RPM. This provides quite a shortcut for installing binary
RPMs from source RPMs.
</para>
<para>
RPMs should be signed to provide an extra level of authentication.
This system isn���t perfect, but it helps you verify that a
package is from the person it says it is from and that the package
has not been modified. You can check the signature on RPM packages
you download. You can also, with some configuration, sign the
packages you create.
</para>
<para/>
</sect1>
</chapter>
<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide-en.xml" "book" "chapter")
fill-column: 72
End:
-->
Author: elliss
Update of /cvs/docs/rpm-guide
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv918
Added Files:
rpm-guide-programming-python-en.xml
Log Message:
--- NEW FILE rpm-guide-programming-python-en.xml ---
<!-- $Id: -->
<chapter id="ch-rpm-programming-python">
<title>Programming RPM with Python</title>
<para>
Copyright (c) 2005 by Eric Foster-Johnson. This material may be
distributed only subject to the terms and conditions set forth in
the Open Publication License, v1.0 or later (the latest version is
presently available at http://www.opencontent.org/openpub/)
</para>
<para/>
<para>
In This Chapter
</para>
<para>
*Using the RPM with Python
</para>
<para>
*Installing the necessary modules
</para>
<para>
*Programming with the RPM database
</para>
<para>
*Programming with RPM files
</para>
<para>
*Installing packages programmatically
</para>
<para>
P
</para>
<sect1>
<title>Setting Up a Python Development Environment</title>
<para>
Setting up a Python development environment is much the same as
setting up a C programming environment. You need to install a set
of packages for general Python development, install a package that
provides the Python API to the RPM system, and choose a program
for editing your Python scripts.
</para>
<para>
Cross Reference
</para>
<para>
Appendix H covers Linux text editors and development tools.
</para>
<para>
If you want to make a graphical user interface in your Python
programs, you need to install a separate Python package.
</para>
<sect2>
<title>Installing the base Python packages</title>
<para>
The base Python package needed for developing applications is
python. For RPM usage, you should install Python 2.2, not Python
1.5. That���s because the RPM bindings for Python are moving to
support only 2.2 and higher releases.
</para>
<para>
The Python package for RPM access is rpm-python. Install these
as you would any other packages.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 4 covers installing packages.
</para>
</sect2>
<sect2>
<title>Using Python for graphics</title>
<para>
Python supports a number of different toolkits for creating
graphical user interfaces. You need one of these toolkits if you
want to create Python applications that sport a user interface
instead of command-line tools. Among the most popular toolkits
are PyGKT, PyQt, and Tkinter.
</para>
<para>
*PyGTK is a binding between Python and the GTK+ toolkit used by
the GNOME desktop, one of two main desktop environments for
Linux. (KDE is the other main desktop environment.) The Red Hat
redhat-config-packages program uses PyGTK and sports a very
good-looking user interface.
</para>
<para>
PyGTK provides full access to the GTK+ widgets such as menus,
dialog windows, and buttons. Install the pygtk2 module for
PyGTK. For more on PyGTK, see www.daa.com.au/~james/pygtk/.
</para>
<para>
*PyQt connects Python scripts to the Qt C++ user interface
toolkit. Qt forms the base library used by the KDE desktop
environment and KDE applications. As with PyGTK, PyQt allows you
to access the rich widget set provided by the library.
</para>
<para>
Install the PyQt package for PyQt. For more on PyQt, see
www.riverbankcomputing.co.uk/pyqt/.
</para>
<para>
*Tkinter is considered a standard part of Python and is based on
the Tk (pronounced teekay) toolkit from the Tcl scripting
language. The main advantages of Tkinter are that it is
considered part of Python, meaning users are more likely to have
it, and Tkinter works on multiple platforms, including Windows.
</para>
<para>
The main drawback of Tkinter is that the widget sets are not as
rich as PyQt or PyGTK. For more on Tkinter, see
www.python.org/topics/tkinter/.
</para>
<para>
After you���ve set up your environment and installed all the
necessary packages, the next step is to start working with the
Python API for RPM.
</para>
</sect2>
</sect1>
<sect1>
<title>The Python API Hierarchy</title>
<para>
The RPM Python API provides a high-level abstraction into RPM
functionality divided into logical areas. Table 17-1 lists the
main RPM types. In most cases, you need to begin with rpm and
create a transaction set.
</para>
<para>
Table 17-1 Python types for RPM usage
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
Class
</para>
</entry>
<entry>
<para>
Covers
</para>
</entry>
</row>
<row>
<entry>
<para>
rpm
</para>
</entry>
<entry>
<para>
RPM base module into RPM API
</para>
</entry>
</row>
<row>
<entry>
<para>
rpmts
</para>
</entry>
<entry>
<para>
Transaction sets
</para>
</entry>
</row>
<row>
<entry>
<para>
rpmte
</para>
</entry>
<entry>
<para>
Transaction elements, a package in a transaction set
</para>
</entry>
</row>
<row>
<entry>
<para>
rpmmi
</para>
</entry>
<entry>
[...2692 lines suppressed...]
# rpm -q jikes
</para>
<para>
jikes-1.17-1
</para>
<para/>
<para>
# python rpmupgrade.py jikes-1.18-1.i386.rpm
</para>
<para>
Upgrading jikes-1.18-1
</para>
<para>
This upgrade will install:
</para>
<para>
jikes-1.18-1
</para>
<para>
jikes-1.17-1
</para>
<para>
Running transaction (final step)...
</para>
<para>
Opening file. 4 0 0 jikes-1.18-1.i386.rpm 1
</para>
<para>
Closing file. 2 0 2854204 jikes-1.18-1.i386.rpm 1
</para>
<para/>
<para>
# rpm -q jikes
</para>
<para>
jikes-1.18-1
</para>
<para>
This example shows that the package was upgraded after running
the rpmupgrade.py script. Note that with an upgrade, the
original package, jikes-1.17-1 in this case, is also added to
the transaction set. With an install, this is not the case.
That���s because the original package is removed as part of
the transaction.
</para>
<para>
If you run this script as a non-root user, you will likely see
an error like the following:
</para>
<para>
$ python rpmupgrade.py jikes-1.18-1.i386.rpm
</para>
<para>
Upgrading jikes-1.18-1
</para>
<para>
This upgrade will install:
</para>
<para>
jikes-1.18-1
</para>
<para>
jikes-1.17-1
</para>
<para>
Running transaction (final step)...
</para>
<para>
error: cannot get exclusive lock on /var/lib/rpm/Packages
</para>
<para>
error: cannot open Packages index using db3 - Operation not
permitted (1)
</para>
<para>
error: cannot open Packages database in /var/lib/rpm
</para>
<para>
If a package has a dependency on a file such as a shared
library, you will see output like the following:
</para>
<para>
# python rpmupgrade.py jikes-1.17-glibc2.2-1.i386.rpm
jpilot-0_97-1_i386.rpm
</para>
<para>
Upgrading jikes-1.17-1
</para>
<para>
Upgrading jpilot-0.97-1
</para>
<para>
Must find file [ libpisock.so.3 ]
</para>
<para>
Error: Unresolved dependencies, transaction failed.
</para>
<para>
(('jpilot', '0.97', '1'), ('libpisock.so.3', None), 0, None,
0)
</para>
<para>
If a package has a dependency on another package, you will see
output like the following:
</para>
<para>
# python rpmupgrade.py eruby-devel-0.9.8-2.i386.rpm
</para>
<para>
Upgrading eruby-devel-0.9.8-2
</para>
<para>
Must find package [ eruby-libs - 0.9.8 ]
</para>
<para>
Error: Unresolved dependencies, transaction failed.
</para>
<para>
(('eruby-devel', '0.9.8', '2'), ('eruby-libs', '0.9.8'), 8,
None, 0)
</para>
</sect3>
</sect2>
</sect1>
<sect1>
<title>Where to Go from Here</title>
<para>
The RPM bindings for Python are documented along with the C
programming API. On a Red Hat Linux system, look in the file
/usr/share/doc/rpm-devel-4.1/apidocs/html/group__python.html to
see the start of the Python-specific documentation.
</para>
<para>
Note that much of this online documentation covers the C functions
that provide the Python bindings, not the Python API itself. But,
if you examine the online information on objects listed as
classes, such as rpmts, you can find the Python-specific
documentation.
</para>
<para>
Furthermore, if you look into the .c files that make up the Python
bindings, you can find PyMethodDef structure tables. These tables
provide useful glimpses into the Python API.
</para>
<para>
To learn more about programming in Python, install the python-docs
package. The python-docs package has a large set of online
documentation for Python, including the official Python Tutorial.
With Red Hat Linux, start at
/usr/share/doc/python-docs-2.2.1/html/tut/tut.html.
</para>
<para>
Cross Reference
</para>
<para>
Other tutorials are available at http://diveintopython.org for the
Dive Into Python tutorial for experienced programmers, and at
http://py.vaults.ca/parnassus/apyllo.py/935043691.636055170 for
the Vaults of Parnassus listing of tutorials.
</para>
</sect1>
<sect1>
<title>Summary</title>
<para>
This chapter introduces the high-level RPM API for Python
programming. You can use this API from Python scripts to perform
RPM functionality, just as you can write C programs using the RPM
C API covered in Chapter 16.
</para>
<para>
In general, the Python API is simpler and requires fewer code
statements than the corresponding functionality in the C API.
</para>
<para>
Just about all of your work with the Python API requires a
transaction set, which you can get by calling rpm.TransactionSet.
</para>
<para>
To query the RPM database, call dbMatch on the transaction set
object. To install or upgrade packages, call addInstall, check,
order, and run on the transaction set.
</para>
<para>
The next chapter switches to another language for accessing the
RPM system: Perl. With the rich set of APIs, you can write your
RPM programs in C, Python, Perl, or any language that can call on
code written in one of these languages.
</para>
</sect1>
</chapter>
<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide-en.xml" "book" "chapter")
fill-column: 72
End:
-->
Author: elliss
Update of /cvs/docs/rpm-guide
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv889
Added Files:
rpm-guide-programming-perl-en.xml
Log Message:
--- NEW FILE rpm-guide-programming-perl-en.xml ---
<!-- $Id: -->
<chapter id="ch-programming-perl">
<title>Programming RPM with Perl</title>
<para>
Copyright (c) 2005 by Eric Foster-Johnson. This material may be
distributed only subject to the terms and conditions set forth in
the Open Publication License, v1.0 or later (the latest version is
presently available at http://www.opencontent.org/openpub/)
</para>
<para/>
<para>
In This Chapter
</para>
<para>
*Using the RPM2 module to access information on package files
</para>
<para>
*Querying the RPM database from Perl
</para>
<para>
*Cross-referencing capabilities by the packages that provide and
require capabilities
</para>
<para>
*Extracting information on packages
</para>
<para>
Perl is one of the most popular scripting languages. Used by system
administrators, software developers, and a host of other users, Perl
runs on many operating systems including Linux, UNIX, and Windows.
Perl stands for Practical Extraction and Report Language, or
sometimes Pathologically Eclectic Rubbish Lister.
</para>
<para>
Note
</para>
<para>
In the same vein, LISP stands for Lots of Irritating Single
Parenthesis and COBOL for Completely Obnoxious Business Oriented
Language.
</para>
<para>
I began my book Cross-Platform Perl (John Wiley & Sons, 2000) by
mentioning that when I first started learning Perl, I thought it was
an evil plot. I still do. But it is a very practical evil plot. You
can get a lot of work done with Perl, and quickly.
</para>
<para>
Because of a long history of text processing, Perl is especially
popular among system administrators. Perl also supports add-on
packages, called modules. You can find thousands of add-on modules
for text processing, networking, and a plethora of other tasks.
There are so many modules available that some people who don���t
like the Perl syntax script with Perl anyway, because the available
modules save a lot of time.
</para>
<para>
Cross Reference
</para>
<para>
See search.cpan.org, the Comprehensive Perl Archive Network, for a
listing of many Perl modules.
</para>
<para>
This chapter covers working with RPM files and the RPM database
using Perl. You can combine RPM usage with other Perl usage, such as
generating HTML files or downloading RPMs over a network link.
</para>
<para>
Cross Reference
</para>
<para>
Many of the RPM tools covered in Chapter 8 are written in Perl.
</para>
<sect1>
<title>Getting and Using the Perl RPM Modules</title>
<para>
A number of Perl RPM modules are available. No one module provides
all the features you need, although with time, the Perl modules
will consolidate into a few modules that most everyone uses. As of
this writing, the RPM2 module, by Chip Turner of Red Hat, provides
the most recent approach to working with the RPM system from Perl.
This chapter covers the RPM2 module.
</para>
<para>
Red Hat Linux 8.0 comes with a perl-RPM2 package, which you need
to install to use this module. Otherwise, you can download the
module from www.cpan.org. Install this module, as well as the perl
module, which provides the Perl language interpreter. Once you
have this module installed and the perl package installed, you are
ready to go.
</para>
<para>
Note
</para>
<para>
The version of the perl-RPM2 package that ships with Red Hat Linux
8.0 has a bug in that it will not open package files that were
created with the version of rpm that ships with Red Hat Linux 8.0.
That is, the Perl module cannot read package files that ship with
Red Hat Linux. You can read older package files, though. This
problem only affects attempts to read .rpm files, not installed
packages. The bug is related to reading signed packages but not
having the GPG keys in the keyring. The latest version on
search.cpan.org fixes this problem.
</para>
<para>
The RPM2 module contains Perl methods to work on two types of RPM
objects: RPM files and installed packages.
</para>
</sect1>
<sect1>
<title>Working with RPM Files</title>
<para>
The RPM2 module provides a top-level object, RPM2, that acts as an
entry point into the module. From the RPM2 object, you either open
the RPM database, covered in the "Programming with the RPM
Database" section, or open an RPM package file, covered here.
</para>
<para>
The first step in working with an RPM file is to open the file
inside a Perl script.
</para>
<sect2>
<title>Opening package files</title>
<para>
The open_package subroutine opens an RPM package file and
returns a header object (an RPM2::Header). The basic syntax
follows:
</para>
<para>
my $header = RPM2->open_package( $filename );
</para>
<para>
For example:
</para>
<para>
my $header =
RPM2->open_package("jikes-1.14-1-glibc-2.2.i386.rpm");
</para>
<para>
After you���ve opened a package, you can perform a number of
query operations on the header object returned by the
open_package subroutine.
</para>
</sect2>
<sect2>
<title>Listing tags from the package</title>
<para>
Each RPM package has information stored under a variety of tags,
such as the package name under the NAME tag and the package long
description under the DESCRIPTION tag.
</para>
<para>
Cross Reference
</para>
<para>
These are the same tags introduced with the --queryformat option
to the rpm command discussed in Chapter 5.
</para>
<para>
The tag subroutine returns the value of a given tag. For
example, to get the name of the package, use the NAME tag:
</para>
<para>
use RPM2;
</para>
<para/>
<para>
my $header =
RPM2->open_package("jikes-1.14-1-glibc-2.2.i386.rpm" );
</para>
<para/>
<para>
print $header->tag("NAME"), "\n";
</para>
<para>
Pulling this together, Listing 18-1 shows example script that
lists the name and one-line short summary of a package file.
</para>
<para>
Listing 18-1: rpmsum.pl
</para>
<para>
#!/usr/bin/perl
</para>
<para/>
<para>
#
</para>
<para>
# Lists summary from an RPM package file
</para>
<para>
# Usage:
</para>
<para>
# rpmsum.pl package_name.rpm
</para>
<para>
#
</para>
<para>
use strict;
</para>
<para>
use RPM2;
</para>
<para/>
<para>
my $header = RPM2->open_package( $ARGV[0] );
</para>
<para/>
<para>
print $header->tag("NAME"), ": ", $header->tag("SUMMARY"),
"\n";
</para>
<para>
Enter this script and name the file rpmsum.pl.
</para>
<para>
When you run this script, you need to pass the name of a package
file on the command line. For example:
</para>
<para>
$ ./rpmsum.pl jikes-1.14-1-glibc-2.2.i386.rpm
</para>
<para>
jikes: java source to bytecode compiler
</para>
</sect2>
<sect2>
<title>Convenience methods</title>
<para>
The RPM2 module includes convenience methods for all RPM tags.
This means you can use the method name in place of tag("NAME").
For example:
</para>
<para>
print $header->name(), ": ", $header->summary(), "\n";
</para>
</sect2>
<sect2>
<title>Listing the name and version</title>
<para>
The RPM2 module provides a handy subroutine for getting the
NAME, VERSION, RELEASE, and EPOCH tags, often abbreviated as
NVRE. The subroutine, as_nvre, returns a single string with
these values in the standard format, with the values separated
by minus signs.
</para>
<para>
Note
</para>
<para>
Usually, the EPOCH tag has no value. If there is an EPOCH value,
you will see it output first, and then a colon, and then the
name, version, and release values. For example:
</para>
<para>
5:redhat-config-httpd-1.0.1-13
</para>
<para>
In this case, the EPOCH value is 5.
</para>
<para>
You can call this subroutine on any header object, or any
package object to get the full name of the package. For example:
</para>
<para>
print $header->as_nvre(), "\n";
</para>
</sect2>
<sect2>
<title>Checking whether the package is a source package</title>
<para>
Another handy subroutine tells you if an RPM file represents a
source RPM or a binary RPM. The is_source_package subroutine
returns a true value if the package is a source package, and a
false value otherwise.
</para>
<para>
The rpmpkg.pl script, shown in Listing 18-2, shows how to use
the as_nvre and is_source_package subroutines.
</para>
<para>
Listing 18-2: rpmpkg.pl
</para>
<para>
#!/usr/bin/perl
</para>
<para/>
<para>
#
</para>
<para>
# Queries RPM package file and prints
</para>
<para>
# out name and whether this is a source pkg.
</para>
<para>
# Usage:
</para>
<para>
# rpmpkg.pl package_name
</para>
<para>
#
</para>
<para>
use strict;
</para>
<para>
use RPM2;
</para>
<para/>
<para>
my $header = RPM2->open_package( $ARGV[0] );
</para>
<para/>
<para>
if ( $header->is_source_package() ) {
</para>
<para>
print "Source package ", $header->as_nvre(), "\n";
</para>
<para>
} else {
</para>
<para>
print $header->as_nvre(), "\n";
</para>
<para>
}
</para>
</sect2>
</sect1>
<sect1>
<title>Programming with the RPM Database</title>
<para>
In addition to providing query routines for RPM files, you can
also access the RPM database with the RPM2 package.
</para>
<para>
To access the RPM database, your Perl script must first open the
database.
</para>
<sect2>
<title>Opening the database</title>
<para>
Open the RPM database with a call to open_rpm_db on the RPM2
object. For example:
</para>
<para>
my $rpm_db = RPM2->open_rpm_db();
</para>
<para>
You can also specify the directory where the RPM database
resides. This is most useful for accessing a database in a
non-standard location. For example:
</para>
<para>
my $rpm_db = RPM2->open_rpm_db( "-path" => "/var/lib/rpm"
);
</para>
<para>
Note
</para>
<para>
The -path is normally used as a Perl bareword but is shown here
as a string.
</para>
<para>
Once you have an RPM database object, you can call one of the
find subroutines to find packages in most of the same ways as
supported by the rpm ���q command.
</para>
</sect2>
<sect2>
<title>Finding packages</title>c<para>
The find_by_name subroutine finds a package or packages by name.
It returns a Perl list of the entries found. For example, if you
installed more than one version of a package, find_by_name would
return a list of all the packages at the different versions.
</para>
<para>
Similar to find_by_name, find_by_name_iter returns an iterator
to iterate over the packages that match the query. The iterator
approach is usually more efficient.
</para>
</sect2>
<sect2>
<title>Iterating over packages</title>
<para>
Iterators are important in the RPM2 package because they provide
a more efficient interface to potentially large sets of
packages, and because iterators more closely match the
underlying C API. Furthermore, iterators are very easy to use.
Simply call the next subroutine to move ahead to the next
element, that is, the next package.
</para>
<para>
For example:
</para>
<para>
my $pkg_iter = $rpm_db->find_by_name_iter( "kernel" );
</para>
<para/>
<para>
while (my $pkg = $pkg_iter->next() ) {
</para>
<para/>
<para>
# Do something ...
</para>
<para>
}
</para>
<para>
Listing 18-3 shows a script that acts much like the rpm ���q
command, without any other command-line options.
</para>
<para>
Listing 18-3: rpmname.pl
</para>
<para>
#!/usr/bin/perl
</para>
<para/>
<para>
#
</para>
<para>
# Queries RPM database for given package.
</para>
<para>
# Usage:
</para>
<para>
# rpmname.pl package_name
</para>
<para>
#
</para>
<para>
use strict;
</para>
<para>
use RPM2;
</para>
<para/>
<para>
my $rpm_db = RPM2->open_rpm_db( "�������path" =>
"/var/lib/rpm" );
</para>
<para/>
<para>
my $pkg_iter = $rpm_db->find_by_name_iter( $ARGV[0] );
</para>
<para/>
<para>
while (my $pkg = $pkg_iter->next() ) {
</para>
<para/>
<para>
print $pkg->tag("NAME"), "-", $pkg->tag("VERSION"), "\n";
</para>
<para>
}
</para>
<para/>
<para>
$rpm_db->close_rpm_db();
</para>
<para>
When you run this script, you need to pass the name of a package
to query. For example:
</para>
<para>
$ ./rpmname.pl kernel
</para>
<para>
kernel-2.4.18
</para>
</sect2>
<sect2>
<title>Additional query subroutines</title>
<para>
The find_by_name_iter subroutine finds a package by its name.
The RPM2 module also supports a number of other query routines,
listed in Table 18-1.
</para>
<para>
Table 18-1 RPM2 module query routines
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
Routine
</para>
</entry>
<entry>
<para>
Usage
</para>
</entry>
</row>
<row>
<entry>
<para>
find_all()
</para>
</entry>
<entry>
<para>
Returns a list with all the packages in the database
</para>
</entry>
</row>
<row>
<entry>
<para>
find_all_iter()
</para>
</entry>
<entry>
<para>
Returns an iterator over all the packages in the
database
</para>
</entry>
</row>
<row>
<entry>
<para>
find_by_file($filename)
</para>
</entry>
<entry>
<para>
Finds all packages that own the given file, returning
a list
</para>
</entry>
</row>
<row>
<entry>
<para>
find_by_file_iter($filename)
</para>
</entry>
<entry>
<para>
Finds all packages that own the given file, returning
an iterator
</para>
</entry>
</row>
<row>
<entry>
<para>
find_by_name($package_name)
</para>
</entry>
<entry>
<para>
Finds all packages with the given name, returning a
list
</para>
</entry>
</row>
<row>
<entry>
<para>
find_by_name_iter($package_name)
</para>
</entry>
<entry>
<para>
Finds all packages with the given name, returning an
iterator
</para>
</entry>
</row>
<row>
<entry>
<para>
find_by_provides($capability)
</para>
</entry>
<entry>
<para>
Finds all packages that provide the given capability,
returning a list
</para>
</entry>
</row>
<row>
<entry>
<para>
find_by_provides_iter($capability)
</para>
</entry>
<entry>
<para>
Finds all packages that provide the given capability,
returning an iterator
</para>
</entry>
</row>
<row>
<entry>
<para>
find_by_requires($capability)
</para>
</entry>
<entry>
<para>
Finds all packages that require the given capability,
returning a list
</para>
</entry>
</row>
<row>
<entry>
<para>
find_by_requires_iter($capability)
</para>
</entry>
<entry>
<para>
Finds all packages that require the given capability,
returning an iterator
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
To verify the find routines, you can try the following script
and compare the results with the rpm command. Listing 18-4 shows
the script that finds what package provides a capability and
also which packages require the capability.
</para>
<para>
Listing 18-4: rpmprovides.pl
</para>
<para>
#!/usr/bin/perl
</para>
<para/>
<para>
#
</para>
<para>
# Queries RPM database for given package,
</para>
<para>
# listing what it provides and what other
</para>
<para>
# packages require the capability.
</para>
<para>
#
</para>
<para>
# Usage:
</para>
<para>
# rpmprovides.pl package_name
</para>
<para>
#
</para>
<para>
use strict;
</para>
<para>
use RPM2;
</para>
<para/>
<para>
my $rpm_db = RPM2->open_rpm_db();
</para>
<para/>
<para>
my $pkg_iter = $rpm_db->find_by_provides_iter( $ARGV[0] );
</para>
<para/>
<para>
print "Provides: ", $ARGV[0], "\n";
</para>
<para/>
<para>
while (my $pkg = $pkg_iter->next() ) {
</para>
<para>
print "\t", $pkg->as_nvre(), "\n";
</para>
<para>
}
</para>
<para/>
<para/>
<para>
# Now, what packages require this capability.
</para>
<para/>
<para>
my $pkg_iter2 = $rpm_db->find_by_requires_iter( $ARGV[0] );
</para>
<para/>
<para>
print "Requires: ", $ARGV[0], "\n";
</para>
<para>
while (my $pkg2 = $pkg_iter2->next() ) {
</para>
<para>
print "\t", $pkg2->as_nvre(), "\n";
</para>
<para>
}
</para>
<para/>
<para>
$rpm_db->close_rpm_db();
</para>
<para>
When you run this script with the name of a capability, you'll
see output like the following:
</para>
<para>
$ ./rpmprovides.pl httpd
</para>
<para>
Provides: httpd
</para>
<para>
httpd-2.0.40-8
</para>
<para>
Requires: httpd
</para>
<para>
mod_perl-1.99_05-3
</para>
<para>
5:redhat-config-httpd-1.0.1-13
</para>
<para>
mod_python-3.0.0-10
</para>
<para>
1:mod_ssl-2.0.40-8
</para>
<para>
Note
</para>
<para>
The 5: in 5:redhat-config-httpd-1.0.1-13 and 1: in
1:mod_ssl-2.0.40-8 represent the EPOCH tag value.
</para>
<para>
To verify this script, run the rpm -q command to see if you get
the same packages listed. For example:
</para>
<para>
$ rpm -q --whatprovides httpd
</para>
<para>
httpd-2.0.40-8
</para>
<para/>
<para>
$ rpm -q --whatrequires httpd
</para>
<para>
mod_perl-1.99_05-3
</para>
<para>
redhat-config-httpd-1.0.1-13
</para>
<para>
mod_python-3.0.0-10
</para>
<para>
mod_ssl-2.0.40-8
</para>
<para>
In both cases, you see the same packages listed. You can use
this technique to verify your scripts.
</para>
<para>
Note
</para>
<para>
The find_by_provides_iter subroutine requires the name of a
package, such as bash. You cannot pass a file name, such as
/bin/bash, to get the name of the package that provides this
capability (a file, really).
</para>
</sect2>
<sect2>
<title>Getting information on packages</title>ng information on packages<para>
The tag, as_nvre, and is_source_package subroutines that worked
on header objects read from RPM files, shown previously, also
work with package entries returned from the RPM database.
</para>
<para>
For example, Listing 18-5 shows a script, rpminfo.pl, that
prints out descriptive information about a given package.
</para>
<para>
Listing 18-5: rpminfo.pl
</para>
<para>
#!/usr/bin/perl
</para>
<para/>
<para>
#
</para>
<para>
# Queries RPM database for given package and prints info.
</para>
<para>
# Usage:
</para>
<para>
# rpminfo.pl package_name
</para>
<para>
#
</para>
<para>
use strict;
</para>
<para>
use RPM2;
</para>
<para/>
<para>
my $rpm_db = RPM2->open_rpm_db( "-path" => "/var/lib/rpm"
);
</para>
<para/>
<para>
my $pkg_iter = $rpm_db->find_by_name_iter( $ARGV[0] );
</para>
<para/>
<para>
while (my $pkg = $pkg_iter->next() ) {
</para>
<para/>
<para>
printInfo( $pkg );
</para>
<para>
}
</para>
<para/>
<para>
$rpm_db->close_rpm_db();
</para>
<para/>
<para/>
<para>
# Prints info on one package.
</para>
<para>
sub printInfo {
</para>
<para>
my($pkg) = shift;
</para>
<para/>
<para>
print $pkg->as_nvre(), ", ", $pkg->tag("ARCH"), ", ",
</para>
<para>
$pkg->tag("OS"), ", ", $pkg->tag("PLATFORM"), "\n";
</para>
<para/>
<para>
print $pkg->tag("SUMMARY"), "\n";
</para>
<para>
print "Group: ", $pkg->tag("GROUP"), "\n";
</para>
<para>
print $pkg->tag("DESCRIPTION"), "\n";
</para>
<para>
print "Vendor: ", $pkg->tag("VENDOR"), ", ",
$pkg->tag("URL"), "\n";
</para>
<para>
print "Size: ", $pkg->tag("SIZE"), "\n";
</para>
<para>
}
</para>
<para>
When you run this script, you���ll see output like the
following:
</para>
<para>
$ ./rpminfo.pl XFree86
</para>
<para>
XFree86-4.2.0-72, i386, linux, i386-redhat-linux-gnu
</para>
<para>
The basic fonts, programs and docs for an X workstation.
</para>
<para>
Group: User Interface/X
</para>
<para>
XFree86 is an open source implementation of the X Window System.
It
</para>
<para>
provides the basic low level functionality which full fledged
</para>
<para>
graphical user interfaces (GUIs) such as GNOME and KDE are
designed
</para>
<para>
upon.
</para>
<para>
Vendor: Red Hat, Inc., http://www.xfree86.org
</para>
<para>
Size: 30552239
</para>
<sect3>
<title>Listing the Installed Date</title>
<para>
The installed date is a number value representing the number
of seconds since the start of the UNIX epoch, January 1, 1970,
which predates the start of the Linux epoch by about 20 years.
So, when you get the value of the INSTALLTIME tag, you���ll
see a meaningless number.
</para>
<para>
To make sense of this number, pass the value to the Perl
localtime function. Listing 18-6 shows an example of this.
</para>
<para>
Listing 18-6: rpmdate.pl
</para>
<para>
#!/usr/bin/perl
</para>
<para/>
<para>
#
</para>
<para>
# Queries RPM database for given package,
</para>
<para>
# prints out name, vendor, and date installed.
</para>
<para>
# Usage:
</para>
<para>
# rpmdate.pl package_name
</para>
<para>
#
</para>
<para>
use strict;
</para>
<para>
use RPM2;
</para>
<para/>
<para>
my $rpm_db = RPM2->open_rpm_db();
</para>
<para/>
<para>
my $pkg_iter = $rpm_db->find_by_name_iter( $ARGV[0] );
</para>
<para/>
<para>
while (my $pkg = $pkg_iter->next() ) {
</para>
<para/>
<para>
printDate( $pkg );
</para>
<para>
}
</para>
<para/>
<para>
$rpm_db->close_rpm_db();
</para>
<para/>
<para/>
<para/>
<para>
# Prints installation data for one package.
</para>
<para>
sub printDate {
</para>
<para>
my($pkg) = shift;
</para>
<para/>
<para>
my $date = localtime( $pkg->tag("INSTALLTIME") );
</para>
<para/>
<para>
printf("%-20s %-17s %s\n", $pkg->as_nvre(),
$pkg->tag("VENDOR"), $date);
</para>
<para>
}
</para>
<para>
Note
</para>
<para>
The printf function in this script can do something the rpm
command cannot do. Even with the --queryformat option, you
cannot group multiple items and then set the size; with Perl,
you can. Simply assign the multiple values to a string, or use
the handy as_nvre subroutine, which gathers up to four tags
together into one string.
</para>
<para>
When you pass the name of a package to this script, you���ll
see the date the package was installed. For example:
</para>
<para>
$ ./rpmdate.pl kernel
</para>
<para>
kernel-2.4.18-14 Red Hat, Inc. Sat Oct 5 12:29:58 2002
</para>
</sect3>
<sect3>
<title>Handling String Array Tags</title>
<para>
Not only is the date stored in a format that adds complication
to your script. A number of tags are string arrays, not scalar
strings. This means you may see output that is all mashed
together.
</para>
<para>
To help deal with this, the following subroutine takes in an
array of strings and returns a string that is built using a
passed-in delimiter:
</para>
<para>
sub arrayToString {
</para>
<para>
my($sep) = shift;
</para>
<para>
my(@array) = @_;
</para>
<para>
my($str);
</para>
<para/>
<para>
$str = $array[0];
</para>
<para/>
<para>
for ( $i = 1; $i < $#array; $i++ )
</para>
<para>
{
</para>
<para>
$str = $str . $sep . $array[$i];
</para>
<para>
}
</para>
<para/>
<para>
return $str;
</para>
<para>
}
</para>
<para>
Note
</para>
<para>
Show your Perl expertise and earn extra points by implementing
the arrayToString subroutine as a single Perl statement that
uses the join function.
</para>
<para>
The following list shows the tags that are an array of
strings:
</para>
<para>
*BASENAMES
</para>
<para>
*CHANGELOGNAME
</para>
<para>
*CHANGELOGTEXT
</para>
<para>
*DIRNAMES
</para>
<para>
*FILEGROUPNAME
</para>
<para>
*FILELANGS
</para>
<para>
*FILELINKTOS
</para>
<para>
*FILEMD5S
</para>
<para>
*FILEUSERNAME
</para>
<para>
*OLDFILENAMES
</para>
<para>
*PROVIDENAME
</para>
<para>
*PROVIDEVERSION
</para>
<para>
*REQUIRENAME
</para>
<para>
*REQUIREVERSION
</para>
<para>
Cross Reference
</para>
<para>
Chapter 5 covers more on these tags.
</para>
</sect3>
<sect3>
<title>Listing the Files In A Package</title>
<para>
The files subroutine provides a list of all the files in a
package. Listing 18-7 shows how to access this list.
</para>
<para>
Listing 18-7: rpmfiles.pl
</para>
<para>
#!/usr/bin/perl
</para>
<para/>
<para>
#
</para>
<para>
# Queries RPM database for given package,
</para>
<para>
# prints out the files in the package.
</para>
<para>
# Usage:
</para>
<para>
# rpmfiles.pl package_name
</para>
<para>
#
</para>
<para>
use strict;
</para>
<para>
use RPM2;
</para>
<para/>
<para>
my $rpm_db = RPM2->open_rpm_db();
</para>
<para/>
<para>
my $pkg_iter = $rpm_db->find_by_name_iter( $ARGV[0] );
</para>
<para/>
<para>
while (my $pkg = $pkg_iter->next() ) {
</para>
<para/>
<para>
printFiles( $pkg );
</para>
<para>
}
</para>
<para/>
<para>
$rpm_db->close_rpm_db();
</para>
<para/>
<para/>
<para/>
<para>
# Prints installation data for one package.
</para>
<para>
sub printFiles {
</para>
<para>
my($pkg) = shift;
</para>
<para/>
<para>
my $files = arrayToString("\n", $pkg->files() );
</para>
<para/>
<para>
print "Files:\n", $files, "\n";
</para>
<para>
}
</para>
<para/>
<para>
sub arrayToString {
</para>
<para>
my($sep) = shift;
</para>
<para>
my(@array) = @_;
</para>
<para>
my($str);
</para>
<para/>
<para>
$str = $array[0];
</para>
<para/>
<para>
for ( my $i = 1; $i < $#array; $i++ )
</para>
<para>
{
</para>
<para>
$str = $str . $sep . $array[$i];
</para>
<para>
}
</para>
<para/>
<para>
return $str;
</para>
<para>
}
</para>
<para>
When you run this script, you���ll see output like the
following:
</para>
<para>
$ ./rpmfiles.pl jikes
</para>
<para>
Files:
</para>
<para>
/usr/bin/jikes
</para>
<para>
/usr/doc/jikes-1.17/license.htm
</para>
</sect3>
</sect2>
<sect2>
<title>Comparing versions</title>
<para>
The RPM2 module overrides the spaceship operator, <=>, to
perform version comparisons between packages. The script in
Listing 18-8 shows how to compare all local RPM files against
the newest installed version of the same package, if the package
is installed.
</para>
<para>
Listing 18-8: rpmver.pl
</para>
<para>
#!/usr/bin/perl -w
</para>
<para/>
<para>
#
</para>
<para>
# Compare versions of all *.rpm files against the
</para>
<para>
# latest packages installed (if installed)
</para>
<para>
#
</para>
<para>
# Usage:
</para>
<para>
# rpmver.pl
</para>
<para>
# This script looks for all *.rpm files.
</para>
<para>
#
</para>
<para>
use strict;
</para>
<para>
use RPM2;
</para>
<para/>
<para>
my $rpm_db = RPM2->open_rpm_db();
</para>
<para/>
<para>
for my $filename (<*.rpm>) {
</para>
<para>
my $h = RPM2->open_package( $filename );
</para>
<para/>
<para>
# Ensure we compare against the newest
</para>
<para>
# package of the given name.
</para>
<para>
my ($installed) =
</para>
<para>
sort { $b <=> $a } $rpm_db->find_by_name($h->name);
</para>
<para/>
<para>
if (not $installed) {
</para>
<para>
printf "Package %s not installed.\n", $h->as_nvre;
</para>
<para>
} else {
</para>
<para>
my ($result) = ($h <=> $installed);
</para>
<para/>
<para>
if ($result < 0) {
</para>
<para>
printf "Installed package %s newer than file %s\n",
</para>
<para>
$installed->as_nvre,
</para>
<para>
$h->as_nvre;
</para>
<para>
} else {
</para>
<para>
printf "File %s newer than installed package %s\n",
</para>
<para>
$h->as_nvre,
</para>
<para>
$installed->as_nvre;
</para>
<para>
}
</para>
<para>
}
</para>
<para>
}
</para>
<para>
The sort { $a <=> $b } in front of the find_by_name call
sorts all the packages of that name by the version number, so
that the comparison is performed against the newest installed
version of the package. The ($h <=> $installed) compares
the header from the RPM file on disk against the newest
installed version of the package.
</para>
<para>
When you run this script, you���ll see output like the
following, depending on which RPM files you have in the local
directory:
</para>
<para>
$ perl rpmver.pl
</para>
<para>
Package acroread-4.0-0 not installed.
</para>
<para>
Package canvas-7.0b2.0-1 not installed.
</para>
<para>
Installed package jikes-1.18-1 newer than file jikes-1.14-1
</para>
<para>
Installed package SDL-1.2.4-5 newer than file SDL-0.9.9-4
</para>
<para>
Package ted-2.8-1 not installed.
</para>
</sect2>
<sect2>
<title>Closing the database</title>
<para>
When you are done with the RPM database, call close_rpm_db, as
shown following:
</para>
<para>
$rpm_db->close_rpm_db();
</para>
<para>
Note that this call is not necessary, as the RPM2 module will
close the database when the object, in this case $rpm_db, goes
out of scope.
</para>
</sect2>
</sect1>
<sect1>
<title>Where to Go from Here</title>
<para>
One of the strengths of Perl is that there are so many add-on
packages available. In addition, Perl is really strong in text
processing. You can combine these strengths to provide cleaner
output for RPM database queries, for example, avoiding the complex
syntax for the --queryformat option to the rpm command. Perl can
do more than the --queryformat option allows. For example, you can
combine multiple values together into a Perl string and then
format the output. The --queryformat option only allows formatting
on each value individually, not groups of values.
</para>
<para>
In addition, you can combine one of the Perl templating modules,
such as Text::Template or HTML::Template, to create an HTML page
for a given package. You could use Perl to create formatted HTML
pages for all the installed packages on your system, with HTML
links to cross-reference all the dependencies.
</para>
<para>
Cross Reference
</para>
<para>
Download these modules from the CPAN site, www.cpan.org.
</para>
<para>
This chapter covers the RPM2 module. Right now, the RPM2 module
supports only querying packages and the RPM database. Future
versions will likely add the ability to install, update, and
remove packages.
</para>
<para>
In addition to this module, you can find an RPM module with
RPM::Header and RPM::Database classes. Another module,
RPM::Specfile, provides the ability to turn Perl modules, such as
those stored on CPAN, into RPM packages. The RPM::Specfile module
helps create an RPM spec file for a Perl module.
</para>
<para>
The Perl-RPM-Perlonly bundle provides an alternative version of
the RPM::Header module written entirely in Perl with no usage of
the C rpm library. This makes RPM access much easier on platforms
for which you don���t have the RPM system.
</para>
<para>
The RPM-Tools bundle includes RPM::Update, which compares the
packages installed on your system (listed by calling rpm ���qa)
with the packages available on another system, that may be
available only with a network link. This module can also update
packages that are older than the designated master system.
RPM::Make, also part of the RPM-Tools bundle, helps create RPM
packages from a Perl script. This module does not support all the
spec file options described in Chapter 10, but it can help you
make simple packages.
</para>
<para>
You can download all these modules from the CPAN site.
</para>
</sect1>
<sect1>
<title>Summary</title>
<para>
This chapter introduces the RPM2 add-on module to allow Perl
scripts to access information on RPM package files and in the RPM
database. To access an RPM file and query information about that
file, you need to call the open_package subroutine. Once you���ve
opened the file, you can call the tag, as_nvre, is_source_package,
and files subroutines on the header object to query data about the
package.
</para>
<para>
To access the RPM database, call open_rpm_db. Once you���ve opened
the database, you can call one of the find subroutines, such as
find_by_name or find_by_name_iter, to search for packages. The
subroutines that have names ending with _iter, such as
find_by_name_iter, return an iterator object to iterate over the
packages found. The other find subroutines, such as find_by_name,
return a Perl list of the packages found.
</para>
<para>
You can then call the tag, as_nvre, and files subroutines on the
package objects to query information about the packages.
</para>
<para>
When you are done with the RPM database, call close_rpm_db.
</para>
</sect1>
</chapter>
<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide-en.xml" "book" "chapter")
fill-column: 72
End:
-->
Author: elliss
Update of /cvs/docs/rpm-guide
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv860
Added Files:
rpm-guide-programming-c-en.xml
Log Message:
--- NEW FILE rpm-guide-programming-c-en.xml ---
<!-- $Id: -->
<chapter id="ch-programming-c">
<title>Programming RPM with C</title>
<para>
Copyright (c) 2005 by Eric Foster-Johnson. This material may be
distributed only subject to the terms and conditions set forth in
the Open Publication License, v1.0 or later (the latest version is
presently available at http://www.opencontent.org/openpub/)
</para>
<para/>
<para>
In This Chapter
</para>
<para>
*Using the RPM C library
</para>
<para>
*Setting up a development environment
</para>
<para>
*Programming with the RPM C library
</para>
<para>
*The power of popt for command-line argument processing
</para>
<para>
*Comparing package files to installed packages
</para>
<para>
The RPM C library allows you to perform all the operations of the
rpm command from within your own C or C++ programs.
</para>
<para>
The reason is simple: The rpm command was created using the RPM
libraries. These same libraries are available for you to use in your
own programs.
</para>
<para>
The rpm command itself is quick and, for the most part, simple. So,
why would you want to write RPM programs?
</para>
<para>
There are many reasons, some of which are listed here:
</para>
<para>
*Speed: If you need to perform a task on many RPM files such as
verifying a large set of files, then performing the task from one
program will be a lot faster than launching the rpm command for each
file.
</para>
<para>
*Custom options: If you need to do something the rpm command doesn't
offer, or doesn't make easy, then you may want to write your own
program.
</para>
<para>
*Convenience: If you need to make many packages quickly, with custom
options, your best bet may be to create a program suited for your
tasks. Before doing this, though, be sure to look into whether
writing a shell script will handle your task adequately. You'll find
writing RPM shell scripts goes much faster than writing whole
programs.
</para>
<para>
*Installation programs: The Windows world has standardized on
graphical installation programs such as InstallShield or
InstallAnywhere. The RPM system, on the other hand, has focused on
automated installation with the rpm command. You can combine the
best of both worlds by writing a graphical installation program on
top of the RPM system.
</para>
<para>
*Integration with environments: You may want to better integrate RPM
with a Linux desktop environment such as GNOME or KDE.
</para>
<para>
*Working with other languages: This book covers programming RPM with
C, the core language for the library, as well as the Python and Perl
scripting languages. You can use the RPM library, though, to help
bind with other languages such as Tcl, Ruby, or even C# (especially
one of the C# implementations for Linux).
</para>
<para>
This chapter and the next cover RPM programming. This chapter covers
the RPM C programming library, which provides low-level access to
RPM functionality. The next chapter covers the RPM Python
programming library, which provides a much higher-level of
abstraction. If you are attempting to write a complex RPM program,
your best bet is to try the Python API first. Even so, there is a
lot you can do with the RPM C library.
</para>
<sect1>
<title>Programming with the C Library</title>
<para>
RPM C programs are C programs that call on functions in the RPM
library, often called rpmlib. To use the rpmlib, you need to set
up a C programming environment and install the rpm-devel package.
</para>
<sect2>
<title>Setting Up a C Programming Environment</title>
<para>
At the very least, you���ll need a C compiler, gcc, and a text
editor. The easiest way to get the C compiler is to install the
packages grouped under Software Development with the Red Hat
package management tool.
</para>
<para>
Cross Reference
</para>
<para>
See Chapter 8 for more on the Red Hat package management tool.
</para>
<para>
The gcc package requires a number of capabilities. Make sure you
install all the necessary packages. Just about every Linux
distribution includes gcc and everything you need to develop C
programs, so this should not be a problem.
</para>
<para>
For text editors, you can use the vi or emacs text editors, or
any of a number of graphical editors such as gedit.
</para>
<para>
Cross Reference
</para>
<para>
Appendix F covers Linux text editors and development tools.
</para>
<para>
Once you have a C programming environment set up, you next need
to get the RPM library for an RPM development environment.
</para>
</sect2>
<sect2>
<title>Setting Up the RPM Programming Environment</title>
<para>
To program with the RPM library, you need to install the
rpm-devel package. You must have a version of rpm-devel that
matches your version of the rpm package. If you have Red Hat
Linux, your installation CDs will also have the version of the
RPM development package that corresponds to your system.
</para>
<para>
Your program should link against the same libraries that are
used by the rpm command itself in order to insure compatibility,
so make sure that the version of the rpm-devel package matches
the rpm package itself. In most cases, the best bet is to use
the RPM programs and libraries that come with your version of
Linux.
</para>
<para>
Cross Reference
</para>
<para>
You can also download the rpm packages from
ftp://ftp.rpm.org/pub/rpm/dist/. This site includes versions of
the RPM libraries going back to 1996, ancient history in terms
of Linux.
</para>
<para>
The package you need is rpm-devel. If you installed Red Hat
Linux 8.0, the package is rpm-devel-4.1-1.06. This package
includes header files, documentation, and libraries.
</para>
</sect2>
<sect2>
<title>Using the RPM Library</title>
<para>
All C programs using the RPM library need to include the file
rpmlib.h, which defines the core data structures, constants, and
functions. One thing you���ll quickly note is that the RPM C
library accesses RPM data at a very low level. This is one
reason why many developers are moving to Python for their RPM
programs, since the Python RPM API presents a higher level of
abstraction.
</para>
<para>
Cross Reference
</para>
[...3592 lines suppressed...]
<para/>
<para>
ts = rpmtsCreate();
</para>
<para/>
<para>
/* Check for query mode. */
</para>
<para>
if (qva->qva_mode == 'q') {
</para>
<para>
/* Make sure there's something to do. */
</para>
<para>
if (qva->qva_source != RPMQV_ALL &&
!poptPeekArg(context)) {
</para>
<para>
fprintf(stderr, "no arguments given for --query");
</para>
<para>
exit(EXIT_FAILURE);
</para>
<para>
}
</para>
<para/>
<para>
ec = rpmcliQuery(ts, qva, (const char **) poptGetArgs(context));
</para>
<para>
}
</para>
<para>
/* Check for verify mode. */
</para>
<para>
else if (qva->qva_mode == 'V') {
</para>
<para>
rpmVerifyFlags verifyFlags = VERIFY_ALL;
</para>
<para/>
<para>
/* Verify flags are negated from query flags. */
</para>
<para>
verifyFlags &= ~qva->qva_flags;
</para>
<para>
qva->qva_flags = (rpmQueryFlags) verifyFlags;
</para>
<para/>
<para>
/* Make sure there's something to do. */
</para>
<para>
if (qva->qva_source != RPMQV_ALL &&
!poptPeekArg(context)) {
</para>
<para>
fprintf(stderr, "no arguments given for --verify");
</para>
<para>
exit(EXIT_FAILURE);
</para>
<para>
}
</para>
<para/>
<para>
ec = rpmcliVerify(ts, qva, (const char **) poptGetArgs(context));
</para>
<para>
}
</para>
<para>
else {
</para>
<para>
poptPrintUsage(context, stderr, 0);
</para>
<para>
exit(EXIT_FAILURE);
</para>
<para>
}
</para>
<para/>
<para>
ts = rpmtsFree(ts);
</para>
<para/>
<para>
context = rpmcliFini(context);
</para>
<para/>
<para>
return ec;
</para>
<para>
}
</para>
<para>
There is not a lot of code in rpmq.c, as this program is mostly
calling the high-level functions for the rpm command-line
interface.
</para>
<para>
When you run the rpmq program, it performs the same tasks as the
rpm command with the --query (or -q) and --verify (or -V)
command-line options.
</para>
<para>
For example, rpmq supports query formats:
</para>
<para>
$ ./rpmq -q --qf "%{NAME} %{INSTALLTID:date}\n" jikes
</para>
<para>
jikes Fri 25 Oct 2002 06:49:38 PM CDT
</para>
</sect1>
<sect1>
<title>Where to Go from Here</title>
<para>
There is a lot more you can do with the RPM library; you're
limited only by your imagination. The best way to get started is
to follow the examples in this chapter and then try out some RPM
programs on your own. After working with the RPM library for a
while, you can delve into other RPM topics.
</para>
<para>
The RPM Web site, at www.rpm.org, has most of the available
documentation on the RPM system. This site also includes official
RPM released software.
</para>
<para>
One of the best ways to help find out about how to perform RPM
tasks is to look at the source code for the rpm program itself.
For this, download the rpm-src source RPM, too. To see the rpm
command-line interface functions in action, look especially at
tools/rpmcache.c and tools/rpmgraph.c, two relatively short RPM
files that show how to take advantage of a number of short cuts.
The source code for the Python and Perl bindings can also provide
extra hints about the purposes of the RPM API calls.
</para>
<para>
The RPM Web site also has a cross-referenced set of HTML pages on
the RPM programming API. The pages for version 4.1 of RPM are
available at www.rpm.org/rpmapi-4.1/. A good starting page is
www.rpm.org/rpmapi-4.1/modules.html, which lists a number of
modules within the overall RPM library. This extra level of
organization can help you locate the functions you need.
</para>
</sect1>
<sect1>
<title>Summary</title>
<para>
Everything you can do with RPM you can program in C. That���s
because the source code for the entire RPM system is available. In
addition, the rpm and rpmbuild programs make use of a published
API, called rpmlib, to access RPM functionality. You can use this
library yourself.
</para>
<para>
The popt library, short for parse options, provides a lot of handy
utilities for parsing very complex command-line options. You can
use popt inside your own programs, even if you don���t use the
rest of the RPM functionality.
</para>
<para>
Most RPM programs start up by calling rpmcliInit, which sets up
RPM variables for the large set of command-line options supported
by most RPM commands.
</para>
<para>
Call rpmReadPackageFile to read in the Header object from a
package file. You can also get Header objects for the packages
installed in a system by initializing an iterator to iterate over
a set of packages that meet a certain criteria.
</para>
<para>
This chapter covers a fairly low level of access to RPM
functionality. The next chapter, on Python programming, shows a
higher level of abstraction for working with RPM.
</para>
</sect1>
</chapter>
<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide-en.xml" "book" "chapter")
fill-column: 72
End:
-->
Author: elliss
Update of /cvs/docs/rpm-guide
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv831
Added Files:
rpm-guide-packaging-guidelines-en.xml
Log Message:
--- NEW FILE rpm-guide-packaging-guidelines-en.xml ---
<!-- $Id: -->
<chapter id="ch-packaging-guidelines">
<title>Packaging Guidelines</title>
<para>
Copyright (c) 2005 by Eric Foster-Johnson. This material may be
distributed only subject to the terms and conditions set forth in
the Open Publication License, v1.0 or later (the latest version is
presently available at http://www.opencontent.org/openpub/)
</para>
<para/>
<para>
In This Chapter
</para>
<para>
*Avoiding common mistakes
</para>
<para>
*Following good practices
</para>
<para>
RPM is a complex system that helps manage thousands of packages for
a complex operating system. Furthermore, RPM is very, very flexible.
This flexibility makes it important that you follow the rules to
create packages the proper way. Otherwise, you���ll face a host of
problems with your RPMs. Following some best practices guidelines
will help you avoid future problems as you release RPM updates.
</para>
<para>
This chapter covers ways to avoid common problems as well as
best-practice guidelines for creating your own RPMs.
</para>
<sect1>
<title>Avoiding Common Problems</title>
<para>
Developers creating RPMs seem to hit many of the same roadblocks.
This section covers some of the most common problems faced by RPM
users and package builders.
</para>
<para>
Warning
</para>
<para>
Never, never, never build RPMs logged in as the root user. See the
section on Building for details.
</para>
<sect2>
<title>Scan the mailing lists</title>
<para>
Many people have tried to solve a lot of serious problems that
arise when using RPM, so if you are facing difficulties, chances
are someone else has tackled those issues before. The RPM
mailing list provides a technical forum for discussing RPM
issues and problems. In many, if not most, cases, you can find
answers to problems by scanning the mailing list archives.
</para>
<para>
You can also sign up for the mailing list so that you can send
in requests and see the responses.
</para>
<para>
Cross Reference
</para>
<para>
For details on viewing the RPM mailing list archives and signing
up for the list, see www.rpm.org/mailing_list/. See
<ulink url="http://groups.yahoo.com/group/rpm-list/messages">http://groups.yahoo.com/group/rpm-list/messages</ulink>
for an archive of the list.
</para>
<para>
If you are working with RPMs and pushing the envelope for other
operating systems or complicated packages, this list is
definitely worth a look.
</para>
<para>
Before sending any messages, though, be sure to look through the
message archives to see if the message has already been
answered. You will save time waiting for a response if you can
get an archived response right away.
</para>
<para>
You should also ask any questions in a way that will generate
the most helpful responses. This includes:
</para>
<para>
Do your homework first. Check to see if your question has
already been answered by looking at the mailing list or
newsgroup archives. In the end, this saves you the most time, as
you don���t have to wait for answers.
</para>
<para>
Describe the problem and the symptoms as clearly as possible.
After all, this is what you want help with.
</para>
<para>
Use clear subject headers. This is the first part of your
message that people will read. If you are not clear, the key
people who could answer your questions may never even read your
message. And, if they don���t read the message, you will never
get an answer.
</para>
<para>
Send your message in plain text, not HTML. Do not include a
separate HTML copy of your message. This just makes it harder to
read, especially for people who read collected digests of
mailing lists.
</para>
<para>
Make it easy for people to reply to you. Include your email
address in your message. You might want to include a line that
states something like ���Please send your reply to me at��� and
then provide your email address.
</para>
<para>
Cross Reference
</para>
<para>
These tips on asking questions come from the Internet document
on How to Ask Questions the Smart Way by Eric Steven Raymond and
Rick Moen, available at multiple sites, including
www.owlriver.com/tips/smart.
</para>
<para>
In addition to the RPM mailing list, there is also a Usenet
newsgroup, named linux.redhat.rpm. You can read this newsgroup
with any newsreading program.
</para>
<para>
Note
</para>
<para>
Newsgroups are sometimes called discussion groups.
</para>
</sect2>
<sect2>
<title>Use rpmbuild</title>
<para>
In older versions of RPM, you called the rpm ���ba command to
build RPMs. With RPM 4.1, you must use the rpmbuild command. If
you have the rpmbuild command available, even if you are running
an older version of RPM, run rpmbuild instead of rpm to build
your RPMs.
</para>
<para>
You���d be surprised at how such a simple item is one of the
most-asked questions on the RPM mailing list. That���s because
the rpm ���ba command, and the other ���b options, no longer
work in RPM 4.1. These options are supported by the rpmbuild
command.
</para>
</sect2>
<sect2>
<title>Don���t try to defeat the system</title>
<para>
If you are finding your spec files getting more and more
complex, and that you are trying to disable RPM features,
chances are you are trying to defeat the system. This is not a
good idea.
</para>
<para>
The RPM system works in a certain way. You may not always agree
with the way it works, but if you try to make it work in
contrary ways, in most cases you���ll end up fighting RPM to no
avail.
</para>
<para>
There are certain rules, and more importantly certain
conventions that RPMs should follow. The previous chapters in
this section on building RPMs have outlined those conventions.
Follow them. When you go against these conventions, you are
really trying to defeat how the RPM system works.
</para>
</sect2>
<sect2>
<title>Turn off automatic dependency generation</title>
<para>
When you build an RPM, the rpmbuild command will automatically
generate dependencies on Linux shared libraries and other system
commands. You can turn this off if you need to, using a number
of means.
</para>
<para>
You can disable the automatic generation of dependencies by
placing the following directive in your spec file:
</para>
<para>
Autoreq: 0
</para>
<para>
A better approach, though, is to override the %{__find_requires}
and %{__find_provides} macros, or just one of these as needed.
You can null out either of these macros by adding commands like
the following to your spec file:
</para>
<para>
%define __find_requires %{nil}
</para>
<para>
This approach is better because it allows you to override only
the requires checks. In addition, you can get more specific and
simply change how the automatic dependency checks are performed.
For example, you can also change the definitions of these macros
to perform normal dependency generation except for any
problematic files or packages. These two macros resolve to shell
scripts that perform the automated dependency checks, as you can
see with the rpm --eval command:
</para>
<para>
$ rpm --eval "%__find_provides"
</para>
<para>
/usr/lib/rpm/find-provides
</para>
<para>
rpm --eval "%__find_requires"
</para>
<para>
/usr/lib/rpm/find-requires
</para>
<para>
You can override these scripts to filter out any dependencies
that cause problems for your packages.
</para>
</sect2>
<sect2>
<title>Don't list directories in %files</title>
<para>
Unless you really mean it, don���t list directories in your
%files section in your spec files. That is because the rpmbuild
program will automatically add all files in that directory to
your RPM. If this is a system directory, such as /usr/bin, your
RPM has now claimed ownership for all the files, regardless of
the source package.
</para>
<para>
To avoid all files in the directory becoming part of the
package, list the files explicitly, perhaps generating the list
of files as the program builds.
</para>
<para>
If you do need a directory installed as part of your package,
use the %dir directive, described in Chapter 10.
</para>
</sect2>
<sect2>
<title>Handling circular dependencies</title>
<para>
If two packages each depend on the other, you don���t want each
package���s spec file to list the other in a Requires section.
If this occurs, the packages won���t install without one of the
force options, since each package will require the other to be
installed first.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 4 covers how to install or upgrade packages while
ignoring dependency checks. In general, you do not want to
ignore these checks.
</para>
<para>
You can work around this issue by using the PreReq directive
instead of Requires. For example, if package A depends on B and
package B depends on A, you can place the following in the
package B spec file:
</para>
<para>
PreReq: A
</para>
<para>
In addition, you can install both packages at the same time to
avoid some of the problems with circular dependencies. Simply
include both packages on the rpm ���Uvh command line.
</para>
</sect2>
</sect1>
<sect1>
<title>Following Good Practices</title>
<para>
Working through problems is one thing. It���s best, however, to
set up an environment to help avoid problems all together. The
following sections cover what are considered the best practices
for creating RPMs.
</para>
<para>
Before you make an RPM, you should plan out what you intend to
build and how it will be structured. As you build the RPM, you
want to watch out for things that can go wrong, and work from a
known clean environment.
</para>
<sect2>
<title>Preparation</title>
<para>
Before you start to make an RPM, you need to follow a few steps
to ensure you have everything ready.
</para>
<sect3>
<title>Create a Source RPM</title>
<para>
Having a source RPM allows you to transfer all the sources for
a package from one system to another, along with all the
instructions coded in the spec file for actually building the
binary package. This is very handy for keeping track of
software, and it is also very important since you can
regenerate the binary RPM at any time from the source RPM. In
other words, make the generation of RPMs follow the RPM
conventions and fit this into your normal software build
process.
</para>
<para>
This means that for each RPM you want to build, you really
need two: a source and a binary RPM. This isn���t that hard to
do, since you can easily make a source RPM into a binary RPM
with the rpmbuild command.
</para>
</sect3>
<sect3>
<title>Start with Pristine Sources</title>
<para>
In addition to planning on making a source RPM, you should
also start with pristine, unmodified sources for the
application you plan to package as an RPM. Starting with
pristine sources means you can reproduce the entire process
and recreate the RPM from scratch if necessary. (Quality
control and configuration management people really appreciate
this.)
</para>
<para>
The pristine sources should be exactly the sources you got
when you downloaded the application, or acquired it in house.
This doesn���t mean that you won���t have to modify the
sources eventually. For that, you create patches. The key is
just to start the process with unmodified sources.
</para>
<para>
Some RPMs have nearly 100 patches that the rpmbuild command
applies when building the RPM. That is a lot of patches, too
many for most applications. Even so, the process is the same.
Create a patch or patches for all the changes you need to
make. You can easily specify patches in the spec file.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 10 covers the spec file.
</para>
<para>
Keeping your patches separate from the original sources makes
it easier to reproduce the RPM from scratch, and makes it
easier to integrate a new version of the base software, since
your code, in the form of patches, is separated from the base
software code.
</para>
</sect3>
<sect3>
<title>Decide What Goes In Each Package</title>
<para>
You don���t have to stuff all your software into one RPM.
Instead, you can often simplify your RPM by dividing it into
two or three separate (but likely dependent) RPMs.
</para>
<para>
For example, the RPM system itself has one RPM for the basic
system, rpm, one for developers of the RPM system, rpm-devel,
and one for those building RPMs, rpm-build. Yet another RPM
provides the Python programming API, rpm-python.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 17 covers Python programming.
</para>
<para>
This last division is important. The Python RPM draws in as a
dependency the Python system itself. Adding this into, say,
the core RPM package would needlessly complicate the
dependencies for that package.
</para>
<para>
When dividing your software into RPMs, keep two main issues in
mind:
</para>
<para>
*You want to divide the software into RPMs that fit the model
for users of the system.
</para>
<para>
*You want to divide the software into RPMs such that the
separate RPMs are simpler to create and manage.
</para>
<para>
The RPM system follows these guidelines, especially the first.
Few users will extend the RPM system itself, which allows RPM
team to shed this functionality from the core RPM and contain
it in rpm-devel. Those who build RPMs fit into a different
category than those who use RPMs since just about everybody
needs to use RPMs to install packages, but few users actually
build RPMs. Again, the separation works from a user���s
perspective.
</para>
<para>
You also want your package divisions to make each package
easier to specify. You can break particularly tough
dependencies into smaller units and simplify things. If the
package division doesn���t simplify things, then it may not be
a good idea.
</para>
</sect3>
<sect3>
<title>Create a Test RPM Database</title>
<para>
You don���t always have to work with the system RPM database.
In fact, while developing RPMs, you probably don���t want to
change the system database.
</para>
<para>
If you have a test RPM database, you can install your RPMs
into this test database. To do so, use the --justdb, --dbpath,
--prefix, and --badreloc options. These options allow you to
install an RPM into just the database, using a different
database, with a different root file location (into a test
directory, for example) and handle all files that were not
marked for relocation, respectively.
</para>
<para>
Note
</para>
<para>
The --test option when installing also allows you to just test
the install, not actually perform it.
</para>
<para>
Combined, all these options mean you can use an RPM database
just set up for testing and that problems won���t impact your
working Linux systems. To make this work, though, you need a
test RPM database.
</para>
<para>
To be rigorous, you should create the test RPM database from
scratch from a known set of packages. This will allow you to
exactly verify the behavior of your RPM under different system
configurations. This is the best choice since you should
install the packages under a known, and non-root, directory
hierarchy to avoid having file problems with the working
system.
</para>
<para>
If you want to cheat, you can copy your real RPM database to
another directory and use that. Note that in this case, the
file paths in the database will point to the real file
locations on disk.
</para>
<para>
Regardless of how you create a test database, recreate the
database each time you run a test, so that you are sure of a
known starting state. Usually this is as simple as copying a
master test RPM database into a directory you use for running
tests.
</para>
</sect3>
</sect2>
<sect2>
<title>Building</title>
<para>
Building RPMs isn���t as easy as it should be. You���ll often
need to try again and again to get the rpmbuild command to
create a working RPM. This section covers best practices to
follow when performing the actual build of the RPM.
</para>
<sect3>
<title>Use Tools</title>
<para>
Using tools can help speed up the RPM-making process, as well
as give you a head start in learning how RPMs work.
RPM-building tools such as the Red Hat plugin for the Eclipse
Integrated Development Environment have proven really helpful.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 13 covers RPM-building tools. Appendix F covers the
Eclipse Integrated Development Environment.
</para>
<para>
Even though so-called real Linux hackers can make a working
virtual memory system with just the cat command, don���t scoff
at tools. Your time is too valuable.
</para>
<para>
Another useful tool is the gendiff program that comes with the
RPM release. The gendiff program makes it easier to create
patches by avoiding the need to keep a separate directory of
the original sources, The gendiff program also works on all
changed files within a directory, making a patch for
everything you modified.
</para>
<para>
To work with gendiff, you need to first save a backup copy of
each file you intend to edit prior to editing. Use a
consistent file-name extension for the saved copies of the
files, such as .orig, short for original. After you edit some
files, run the gendiff command as follows:
</para>
<para>
$ gendiff directory_name .saved_extension >
patch_name.patch
</para>
<para>
For example, if you saved the original files to a .orig
extension, you can create a patch in a directory named src
(short for sources) with a command like the following:
</para>
<para>
$gendiff src .orig > mypatch.patch
</para>
<para>
The patch file mypatch.patch will contain all the differences
detected for all files in the given directory.
</para>
</sect3>
<sect3>
<title>Never Build RPMs as Root</title>
<para>
Never, never, never build RPMs logged in as the root user.
Always build your RPMS while logged in as a normal user. This
is hard to remember since you must be logged in as root to
install an RPM. And you���ll want to test each RPM you create
to see if it can install cleanly.
</para>
<para>
Even so, never build RPMs logged in as the root user. The RPM
spec file has a number of scripts and commands. An error in
any of these could cause damage to your system. This includes
modifying files, removing files, or copying new contents on
top of system files. The root user has permission to perform
all these operations.
</para>
<para>
To avoid all this, build your RPMs while logged in as a normal
user. Any problematic scripts should generate errors.
</para>
</sect3>
<sect3>
<title>Create a Digital Signature</title>
<para>
RPM 4.1 and later revisions place more importance on signing
your packages. The rpm command will, by default, verify
signatures on each package it reads.
</para>
<para>
Therefore, you should create a digital signature for your
packages, if only to meet user expectations. In addition, you
should place a copy of your digital signature on your
organization���s Web site and public key servers. Having
multiple copies in multiple locations helps prevent malicious
users from impersonating your keys.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 12 covers signing packages.
</para>
</sect3>
<sect3>
<title>Copy Smartly</title>
<para>
Your Linux distribution probably includes more than one CD-ROM
chock full of RPMs. Each of these RPMs has a spec file. You
can examine these spec files and see how others choose to
build their RPMs. Rather than starting from scratch, you can
copy declarations from these spec files into your spec file.
</para>
<para>
Not all these packages were made smartly. Some spec files, as
you will see, are a large mess. Obviously, don���t copy these.
Look for clean spec files with clear directives.
</para>
</sect3>
<sect3>
<title>Set Up the BuildRoot</title>
<para>
A BuildRoot directive sets the location where your code will
be built. The convention is for you to define a subdirectory
beneath the _tmppath directory. For example:
</para>
<para>
BuildRoot: %{_tmppath}/%{name}-buildroot
</para>
<para>
Once set, rpmbuild defines the RPM_BUILD_ROOT environment
variable to the value specified for the BuildRoot.
</para>
<para>
With the rpmbuild command, you can use the --buildroot option
to specify a directory to use to override the BuildRoot
directive in the spec file.
</para>
<para>
Using a BuildRoot set to a directory that normal users have
write access to allows you to build the package logged in as a
normal user. It also helps separate the contents of your
package from those of other RPMs.
</para>
<para>
Always define a BuildRoot.
</para>
</sect3>
<sect3>
<title>Add changelog entries for each new version</title>
<para>
Each time you create a new version in RPM format, you should
add an entry to the change log. This allows administrators to
get a better idea about what changed from the previous
version.
</para>
<para>
The change log can help people decide whether or not to
upgrade a package. A log entry about a security fix, for
example, provides useful information to users.
</para>
</sect3>
<sect3>
<title>Define the Group For Your Package</title>
<para>
Packages are categorized into groups. These group names, while
not always the best, appear in the graphical tools such as the
Red Hat package manager. If your application is a Linux shell
program, then users will expect to find it in the System
Environment/Shells group and not the Development/Languages or
System Environment/Daemons groups. This is a rather small
detail, but it helps users find your package in the huge array
of Linux RPMs.
</para>
<para>
The official list of RPM groups is located in
/usr/share/doc/rpm-4.1/GROUPS for RPM 4.1, and similarly-named
directories for other RPM versions.
</para>
</sect3>
</sect2>
</sect1>
<sect1>
<title>Summary</title>
<para>
This chapter covers guidelines for avoiding problems when creating
RPMs and following best practices to avoid future problems as
well.
</para>
<para>
When trying to avoid common problems, your best starting point is
the RPM mailing list and newsgroup.
</para>
<para>
For best practices, you should start at the very beginning when
you are planning what to build into an RPM. Always start with
pristine sources and then patch as needed. Your RPM should include
the pristine sources and any necessary patches. You should always
create a source RPM, so that you can reproduce your RPM anywhere.
</para>
<para>
When building RPMs, copy good examples of spec files, as this will
get you going far more quickly than any other technique. Use tools
to help automate parts of your RPM-building process.
</para>
<para>
Never build RPMs when logged in as the root user.
</para>
<para>
This chapter ends the section on building RPMs. The next section
covers programming to the RPM APIs.
</para>
</sect1>
</chapter>
<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide-en.xml" "book" "chapter")
fill-column: 72
End:
-->
Author: elliss
Update of /cvs/docs/rpm-guide
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv802
Added Files:
rpm-guide-package-structure-en.xml
Log Message:
--- NEW FILE rpm-guide-package-structure-en.xml ---
<!-- $Id: -->
<chapter id="ch-package-structure">
<title>RPM Package File Structure</title>
<para>
Copyright (c) 2005 by Eric Foster-Johnson. This material may be
distributed only subject to the terms and conditions set forth in
the Open Publication License, v1.0 or later (the latest version is
presently available at http://www.opencontent.org/openpub/)
</para>
<para/>
<para>
In This Appendix
</para>
<para>
*RPM package file structure
</para>
<para>
*RPM header entry formats
</para>
<para>
*Payload format
</para>
<para>
This appendix describes the format of RPM package files. You can
combine this information with C, Perl, or Python data structures to
access the information. In all cases, you should access elements in
an RPM file using one of the available programming libraries. Do not
attempt to access the files directly, as you may inadvertently
damage the RPM file.
</para>
<para>
Cross Reference
</para>
<para>
Chapters 16, 17, and 18 cover programming with C, Python, and Perl,
respectively.
</para>
<para>
The RPM package format described here has been standardized as part
of the Linux Standards Base, or LSB, version 1.3.
</para>
<para>
Cross Reference
</para>
<para>
The LSB 1.3 section on package file formats is available at
www.linuxbase.org/spec/refspecs/LSB_1.3.0/gLSB/gLSB.html#PACKAGEFMT.
</para>
<sect1>
<title>The Package File</title>
<para>
RPM packages are delivered with one file per package. All RPM
files have the following basic format of four sections:
</para>
<para>
*A lead or file identifier
</para>
<para>
*A signature
</para>
<para>
*Header information
</para>
<para>
*Archive of the payload, the files to install
</para>
<para>
All values are encoded in network byte order, for portability to
multiple processor architectures.
</para>
<sect2>
<title>The file identifier</title>
<para>
Also called the lead or the rpmlead, the identifier marks that
this file is an RPM file. It contains a magic number that the
file command uses to detect RPM files. It also contains version
and architecture information.
</para>
<para>
The start of the identifier is the so-called magic number. The
file command reads the first few bytes of a file and compares
the values found with the contents of /usr/share/magic
(/etc/magic on many UNIX systems), a database of magic numbers.
This allows the file command to quickly identify files.
</para>
<para>
The identifier includes the RPM version number, that is, the
version of the RPM file format used for the package. The
identifier also has a flag that tells the type of the RPM file,
whether the file contains a binary or source package. An
architecture flag allows RPM software to double-check that you
are not trying to install a package for a non-compatible
architecture.
</para>
</sect2>
<sect2>
<title>The signature</title>
<para>
The signature appears after the lead or identifier section. The
RPM signature helps verify the integrity of the package, and
optionally the authenticity.
</para>
<para>
The signature works by performing a mathematical function on the
header and archive section of the file. The mathematical
function can be an encryption process, such as PGP (Pretty Good
Privacy), or a message digest in MD5 format.
</para>
</sect2>
<sect2>
<title>The header</title>
<para>
The identifier section no longer contains enough information to
describe modern RPMs. Furthermore, the identifier section is
nowhere near as flexible as today���s packages require. To
counter these deficiencies, the header section was introduced to
include more information about the package.
</para>
<para>
The header structure contains three parts:
</para>
<para>
*Header record
</para>
<para>
*One or more header index record structures
</para>
<para>
*Data for the index record structures
</para>
<para>
The header record identifies this as the RPM header. It also
contains a count of the number of index records and the size of
the index record data.
</para>
<para>
Each index record uses a structure that contains a tag number
for the data it contains. This includes tag IDs for the
copyright message, name of the package, version number, and so
on. A type number identifies the type of the item. An offset
indicates where in the data section the data for this header
item begins. A count indicates how many items of the given type
are in this header entry. You can multiply the count by the size
of the type to get the number of bytes used for the header
entry.
</para>
<para>
Table D-1 lists the type identifiers.
</para>
<para>
Table D-1 Header type identifiers
</para>
<informaltable frame="all">
<tgroup cols="3">
<tbody>
<row>
<entry>
<para>
Constant
</para>
</entry>
<entry>
<para>
Value
</para>
</entry>
<entry>
<para>
Size in Bytes
</para>
</entry>
</row>
<row>
<entry>
<para>
RPM_NULL_TYPE
</para>
</entry>
<entry>
<para>
0
</para>
</entry>
<entry>
<para>
No size
[...2175 lines suppressed...]
1.3
</para>
</entry>
<entry>
<para>
The package conforms to the Linux Standards Base RPM
format.
</para>
</entry>
</row>
<row>
<entry>
<para>
rpmlib(VersionedDependencies)
</para>
</entry>
<entry>
<para>
3.0.3-1
</para>
</entry>
<entry>
<para>
The package holds dependencies or prerequisites that
have versions associated with them.
</para>
</entry>
</row>
<row>
<entry>
<para>
rpmlib(PayloadFilesHavePrefix)
</para>
</entry>
<entry>
<para>
4.0-1
</para>
</entry>
<entry>
<para>
File names in the archive have a ���.��� prepended
on the names.
</para>
</entry>
</row>
<row>
<entry>
<para>
rpmlib(CompressedFileNames)
</para>
</entry>
<entry>
<para>
3.0.4-1
</para>
</entry>
<entry>
<para>
The package uses the RPMTAG_DIRINDEXES,
RPMTAG_DIRNAME and RPMTAG_BASENAMES tags for
specifying file names.
</para>
</entry>
</row>
<row>
<entry>
<para>
/bin/sh
</para>
</entry>
<entry>
<para>
NA
</para>
</entry>
<entry>
<para>
Indicates a requirement for the Bourne shell to run
the installation scripts.
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect3>
</sect2>
<sect2>
<title>The payload</title>
<para>
The payload, or archive, section contains the actual files used
in the package. These are the files that the rpm command
installs when you install the package. To save space, data in
the archive section is compressed in GNU gzip format.
</para>
<para>
Once uncompressed, the data is in cpio format, which is how the
rpm2cpio command can do its work. In cpio format, the payload is
made up of records, one per file. Table D-10 lists the record
structure.
</para>
<para>
Table D-10 cpio file record structure
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
Element
</para>
</entry>
<entry>
<para>
Holds
</para>
</entry>
</row>
<row>
<entry>
<para>
cpio header
</para>
</entry>
<entry>
<para>
Information on the file, such as the file mode
(permissions)
</para>
</entry>
</row>
<row>
<entry>
<para>
File name
</para>
</entry>
<entry>
<para>
NULL-terminated string
</para>
</entry>
</row>
<row>
<entry>
<para>
Padding
</para>
</entry>
<entry>
<para>
0 to 3 bytes, as needed, to align the next element on
a 4-byte boundary
</para>
</entry>
</row>
<row>
<entry>
<para>
File data
</para>
</entry>
<entry>
<para>
The contents of the file
</para>
</entry>
</row>
<row>
<entry>
<para>
Padding
</para>
</entry>
<entry>
<para>
0 to 3 bytes, as needed, to align the next file record
on a 4-byte boundary
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
The information in the cpio header duplicates that of the RPM
file-information header elements.
</para>
</sect2>
</sect1>
</chapter>
<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide-en.xml" "book" "chapter")
fill-column: 72
End:
-->
Author: elliss
Update of /cvs/docs/rpm-guide
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv773
Added Files:
rpm-guide-other-os-en.xml
Log Message:
--- NEW FILE rpm-guide-other-os-en.xml ---
<!-- $Id: -->
<chapter id="ch-other-os">
<title>RPM on Other Operating Systems</title>
<para>
Copyright (c) 2005 by Eric Foster-Johnson. This material may be
distributed only subject to the terms and conditions set forth in
the Open Publication License, v1.0 or later (the latest version is
presently available at http://www.opencontent.org/openpub/)
</para>
<para/>
<para>
In This Chapter
</para>
<para>
*Running RPM on other operating systems
</para>
<para>
*Bootstrapping RPM on other operating systems
</para>
<para>
*Setting up the RPM environment
</para>
<para>
*Creating non-Linux RPMs
</para>
<para>
*Setting up an RPM build environment
</para>
<para>
*Cross-building packages
</para>
<para>
RPM was originally designed on Linux and for most of its life has
been a Linux-centric package management system. But most Linux
programs are portable to most versions of Unix or Unix -like
operating systems. Linux is, after all, a Unix-workalike operating
system.
</para>
<para>
The RPM system is no exception. It has been ported to a number of
operating systems, including quite a few Unix variants. The source
code is freely available, so you can port RPM to other systems as
well.
</para>
<para>
This chapter covers running RPM on non-Linux operating systems,
including getting the RPM system in the first place, bootstrapping
an RPM environment, and creating packages for other operating
systems.
</para>
<para>
The first step is to get RPM for your system, or port RPM if it
isn���t already available.
</para>
<sect1>
<title>Running RPM on Other Operating Systems</title>
<para>
The RPM system, made up of mostly the rpm and rpmbuild commands,
have been ported to a number of operating systems. There is
nothing stopping you from running the RPM system on other
platforms.
</para>
<para>
Other operating systems have their own native package management
software. You may prefer the way RPM works, or merely want to
standardize on RPM across all platforms you manage. There will
always be a few issues, however, when running RPM on other
operating systems. For example, operating system patches and
updates are likely to be distributed in the operating system���s
native package management format, not RPM. Many applications will
be updated also using the system���s native package management
format.
</para>
<para>
You will need to always keep in mind that there are two package
management schemes in use: RPM and the native one. This issue has
not stopped a great many people from using RPM on other systems,
though, as shown by the list of platforms RPM has been ported to
(see Table 20-1 for the list).
</para>
<para>
On the plus side, package management has always been one of the
main areas where versions of Linux, Unix, and other operating
systems differ, sometimes quite a lot. By using RPM, you can
transfer your knowledge of package management from one system to
another, saving valuable time and hassles. You will be able to
update systems in the same manner, a big plus if you manage a
diverse set of systems.
</para>
<para>
Another reason to use RPM on other operating systems is that in
most cases, RPM provides far more capabilities than the native
package management software. Following the RPM philosophy, each
package can be separately verified, checked, and updated. Each
package lists the other packages it depends on, and also lists the
capabilities it provides. You can automate the installation and
upgrade processes with RPM. You can also perform a lot of version
and signature comparisons. All of this leads to a more secure,
more robust system.
</para>
<para>
Many operating systems don���t include these capabilities in the
native package management software. This is why many users run RPM
on other operating systems.
</para>
<para>
Cross Reference
</para>
<para>
See Chapter 2 for more on the philosophy behind RPM.
</para>
<para>
If you decide to use RPM on a non-Linux system, the first step is
getting RPM for your system, if it is available.
</para>
<sect2>
<title>Getting RPM for your system</title>
<para>
The first step to using RPM on non-Linux platforms is getting
the RPM system for your platform. In most cases, this is a
relatively easy step, as RPM has been ported to a great many
platforms, as listed on the main RPM Web site.
</para>
<para>
Cross Reference
</para>
<para>
Links to RPM versions for various platforms are listed at
www.rpm.org/platforms/.
</para>
<para>
Go to this site and download the versions for the platforms you
need. Table 20-1 lists the platforms RPM has been ported to, as
reported by the RPM site.
</para>
<para>
Table 20-1 Available Platforms for RPM
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
Platform
</para>
</entry>
<entry>
<para>
Notes
</para>
</entry>
</row>
<row>
<entry>
<para>
AIX
</para>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para>
AmigaOS
</para>
</entry>
<entry>
<para>
With GeekGadgets
</para>
</entry>
</row>
<row>
<entry>
<para>
BeOS
</para>
</entry>
<entry>
<para>
With GeekGadgets
</para>
</entry>
</row>
<row>
<entry>
<para>
FreeBSD
</para>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para>
HP-UX
</para>
</entry>
<entry>
<para>
10.20+, 9.04
</para>
</entry>
</row>
<row>
<entry>
<para>
IRIX
</para>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para>
Linux
</para>
</entry>
<entry>
<para>
Multiple platforms including Alpha, Intel, Motorola
68000, SGI MIPS, PowerPC, and SPARC
</para>
</entry>
</row>
<row>
<entry>
<para>
LynxOS
</para>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para>
MachTen
</para>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para>
MacOS X
</para>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para>
Mint
</para>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para>
NCS System V
</para>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para>
NetBSD
</para>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para>
OS/2
</para>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para>
OSF/1
</para>
</entry>
<entry>
<para>
3.2+
</para>
</entry>
</row>
<row>
<entry>
<para>
SCO OpenServer
</para>
</entry>
<entry>
<para>
5.0.2+
</para>
</entry>
</row>
<row>
<entry>
<para>
Sinix
</para>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para>
Solaris
</para>
</entry>
<entry>
<para>
Solaris for SPARC 2.4 and 8+, Solaris for Intel
</para>
</entry>
</row>
<row>
<entry>
<para>
SunOS 4.1.3
</para>
</entry>
<entry>
<para/>
</entry>
</row>
<row>
<entry>
<para>
Windows
</para>
</entry>
<entry>
<para>
Under Cygwin
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
Note that RPM has likely been ported to even more platforms.
These are just the ones reported to the rpm.org site.
</para>
<para>
Note
</para>
<para>
If you fix a bug in RPM on a non-Linux system, or if you port
RPM to a new system, please report this to the rpm.org site
maintainers, as well as make your work available for others. You
never know, but someone else may fix a problem you���re facing.
</para>
<para>
If Table 20-1 does not cover the platforms you need, you must
compile and bootstrap the RPM environment for your platforms, as
covered in the "Bootstrapping RPM on Other Operating Systems"
section, following.
</para>
<para>
Note
</para>
<para>
Don���t expect to find RPMs of the RPM system for these other
platforms. If you did, there would be no way to install RPM.
Instead, you���ll find RPM packaged in a variety of formats,
typically using a native bundling format for a given system, or
at least a supported format. Compressed tar files are very
common. RPM for IRIX systems come in IRIX tardist format.
</para>
<para>
If RPM is available for your system, download the package and
follow any installation instructions that come with the package.
For example, RPM for Solaris 8 requires the libiconv library, as
well as the Solaris packages SUNWzlib and SUNWbzip. You must
install these packages prior to installing RPM.
</para>
<para>
Each operating system will have similar requirements. Windows
systems have a few extra requirements due to the fact that
Windows is very different from Linux or Unix-like systems.
</para>
</sect2>
<sect2>
<title>Running RPM on Windows</title>
<para>
The version of RPM for Windows requires cygwin, originally the
Cygnus port of many Unix tools to Windows. Now part of Red Hat,
you can download the cygwin environment from the main cygwin
site.
</para>
<para>
Cross Reference
</para>
<para>
Download cygwin from www.cygwin.com.
</para>
<para>
You can download a setup.exe program to install the environment
on Windows. After installation, you can download the RPM system
for Windows.
</para>
<para>
After you have RPM installed, you can set up your RPM system. If
RPM wasn���t already ported to your operating systems, however,
you will need to bootstrap RPM on your platforms.
</para>
</sect2>
</sect1>
<sect1>
<title>Bootstrapping RPM On Other Operating Systems</title>
<para>
If you cannot find a version of RPM that has been ported to your
platform, you can port it yourself. The RPM system usually isn���t
that hard to port to any platform that can appear like Unix or
Linux systems, such as any platform that supports POSIX system
calls or something like these system calls.
</para>
<para>
Don���t be dismayed by the sheer size of the RPM package. Much of
the RPM system was carefully designed to run across multiple
platforms, so file access is abstracted to special portability
routines. For example, RPM has been ported to both AmigaOS and
BeOS, two non-Unix operating systems.
</para>
<sect2>
<title>Downloading the RPM software</title>
<para>
To bootstrap RPM on another operating system, download the RPM
source code from the main RPM site.
</para>
<para>
Cross Reference
</para>
<para>
You can download the RPM source code from
ftp://ftp.rpm.org/pub/rpm/dist/.
</para>
<para>
Note that you probably do not want to download an RPM of the
sources, since your platform won���t have RPM available. In most
cases, you���ll want to download a tarred compressed archive,
such as rpm-4.1.tar.gz for RPM version 4.1.
</para>
</sect2>
<sect2>
<title>Extracting the software</title>
<para>
If the system you plan to port RPM doesn���t have the tar and
gzip commands available, or something that supports these
formats, then you need to find a way to extract the software.
</para>
<para>
Note
</para>
<para>
Programs such as WinZip on Windows support extracting .tar.gz
files. Your platform may have a similar program.
</para>
<para>
One way is to port the gzip and tar commands to your platform.
</para>
<para>
Cross Reference
</para>
<para>
You can download the sources for tar and gzip from www.gnu.org.
</para>
<para>
Another way is to extract the sources on a platform with these
commands available, such as a Linux platform. Then, create a
file using a format supported by your operating system and
transfer the files to the other system.
</para>
<para>
Once you have the RPM source code available on your target
system, and all the files are extracted, you are ready to start
porting. The first step is really simple: read.
</para>
</sect2>
<sect2>
<title>Reading the INSTALL file</title>
<para>
In the main RPM source directory, you will see two very
important files: README and INSTALL. Read them both. (You would
be surprised at how many times people need to be told this.)
</para>
<para>
Of the two, the INSTALL file has much more detailed information
on installing RPM on a new system. The INSTALL file describes
the libraries required by RPM, provides tips on compiling RPM,
and describes some of the set up work necessary after compiling
the RPM system.
</para>
<para>
Some of the hardest parts of the RPM system to port, though, may
be in the database, compression, and encryption calls, used as
libraries by the RPM system.
</para>
</sect2>
<sect2>
<title>Libraries required by RPM</title>
<para>
Rather than invent everything from scratch, the RPM system makes
use of a number of libraries, including those listed in Table
20-2.
</para>
<para>
Table 20-2 Libraries used by RPM
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
Library
</para>
</entry>
<entry>
<para>
Purpose
</para>
</entry>
</row>
<row>
<entry>
<para>
Berkeley DB
</para>
</entry>
<entry>
<para>
RPM database, using db1 and db3
</para>
</entry>
</row>
<row>
<entry>
<para>
bzip2
</para>
</entry>
<entry>
<para>
Compression
</para>
</entry>
</row>
<row>
<entry>
<para>
gettext
</para>
</entry>
<entry>
<para>
International text lookup
</para>
</entry>
</row>
<row>
<entry>
<para>
gpg
</para>
</entry>
<entry>
<para>
For digital signatures
</para>
</entry>
</row>
<row>
<entry>
<para>
gzip
</para>
</entry>
<entry>
<para>
Compression
</para>
</entry>
</row>
<row>
<entry>
<para>
popt
</para>
</entry>
<entry>
<para>
Processing command-line options
</para>
</entry>
</row>
<row>
<entry>
<para>
zlib
</para>
</entry>
<entry>
<para>
Compression
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
Read through the INSTALL file to find out where you can download
versions of these libraries. You may find that each library has
its own set of dependencies, all of which you need to port to
your target platform.
</para>
</sect2>
<sect2>
<title>Tools for building RPM</title>
<para>
In addition to the libraries listed in Table 20-2, RPM requires
a number of GNU utilities for building RPM, including those
listed in Table 20-3.
</para>
<para>
Table 20-3 Tools used to build RPM
</para>
<informaltable frame="all">
<tgroup cols="2">
<tbody>
<row>
<entry>
<para>
Tool
</para>
</entry>
<entry>
<para>
Usage
</para>
</entry>
</row>
<row>
<entry>
<para>
Autoconf
</para>
</entry>
<entry>
<para>
Builds configure scripts
</para>
</entry>
</row>
<row>
<entry>
<para>
Automake
</para>
</entry>
<entry>
<para>
Used with autoconf
</para>
</entry>
</row>
<row>
<entry>
<para>
GNU make
</para>
</entry>
<entry>
<para>
Used to control building the sources
</para>
</entry>
</row>
<row>
<entry>
<para>
Libtool
</para>
</entry>
<entry>
<para>
Used by the autogen.sh script
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
In addition to all this, RPM works best with the GNU C compiler,
GCC, and the GNU make program, gnumake, or simply gmake.
</para>
<para>
Cross Reference
</para>
<para>
The source code for all the GNU tools is available at
www.gnu.org.
</para>
</sect2>
<sect2>
<title>Compiling RPM</title>
<para>
After downloading the RPM sources, extracting all the files and
installing all the prerequisite libraries, you are ready to
start compiling RPM.
</para>
<para>
RPM includes quite a few subsystems, such as popt for parsing
command-line options. Each of these subsystems requires some
configuration. Most of this configuration is automated through
the use of the autogen.sh script and the autoconf/automake tool
used to create configure scripts.
</para>
<para>
The autogen.sh script is a Bourne shell script that checks for
specific versions of necessary tools and libraries. After
checking dependencies, the autogen.sh script calls different
autogen.sh scripts in the beecrypt, libelf, popt, and zlib
directories. When done with that task, the autogen.sh script
calls configure.
</para>
<para>
Pass a command-line option of --noconfigure to disable the call
to configure.
</para>
<para>
Edit the autogen.sh script if you are using different versions
of the necessary tools. The autogen.sh script is coded to
require the specific versions of these tools as were used
originally to build the RPM package. In addition, your system
may have libraries stored in different locations than those
expected by the autogen.sh, so it's a good idea to edit this
script and verify all the assumptions.
</para>
<para>
Note
</para>
<para>
One really big assumption in this script is that you have a
Unix-like operating system. If not, you will need to determine
how to set up the Makefiles manually. This requires a lot of
trial and error while you edit the Makefiles and then see if you
can build the software. Fix each problem that arises and try
again.
</para>
<para>
When you are done with the autogen.sh script, you can use the
following basic commands to create system-specific Makefiles,
compile RPM and install the commands:
</para>
<para>
$ ./configure
</para>
<para>
$ make
</para>
<para>
$ make install
</para>
<para>
The configure script takes the Makefile.in files and uses these
files as templates to create custom versions of Makefile.in
files, tuned to your system. (The automake system starts with a
Makefile.am file, creates an expanded Makefile.in file, and
finally results in a Makefile tuned to your system.) If all else
fails, you can copy each Makefile.in file to Makefile and then
edit the Makefile to make one that will work on your system.
</para>
<para>
Cross Reference
</para>
<para>
See the GNU site, at www.gnu.org, for more on the autoconf and
automake tools.
</para>
<para>
If the make install step fails, you can manually copy the RPM
executables and scripts to a directory for system commands.
</para>
</sect2>
<sect2>
<title>Handling problems</title>
<para>
If RPM fails to compile or install, you can still work around
many issues. The key is to find out what went wrong, fix the
problem, and try again. You may go through this loop many times
before RPM successfully compiles and installs.
</para>
<para>
Most problems can be solved by changing the configuration
settings. If possible, change the inputs to the configure
command to specify C compiler options, and so on, that you
discover you need. You can then run the basic commands to build
RPM again, but with any special options you discovered are
necessary:
</para>
<para>
$ ./configure ���any_options_set_here
</para>
<para>
$ make
</para>
<para>
$ make install
</para>
<para>
If you take this approach, you avoid having to edit a number of
Makefiles (one in each source code subdirectory) by hand. You
also have an easier time of switching to different command-line
options as you determine more solutions to the compilation
problems.
</para>
<para>
If this won���t work, though, you can edit the Makefile.am file
or the generated Makefile directly to add whatever settings are
needed. For example, you may need to specify additional
directories for libraries, or some C compiler compatibility
option.
</para>
<para>
As you discover problems, remember you are not alone in porting
RPM. Check the RPM mailing list, where the question of getting
RPM going on other platforms comes up frequently.
</para>
<para>
Cross Reference
</para>
<para>
For details on viewing the RPM mailing list archives and signing
up for the list, see www.rpm.org/mailing_list/.
</para>
</sect2>
</sect1>
<sect1>
<title>Setting Up the RPM System</title>
<para>
Once you have RPM available on your platform, you need to set up
the RPM system. This includes setting up the RPM database and
creating an RPM environment.
</para>
<sect2>
<title>Setting up the RPM database</title>
<para>
After you have the RPM system available on your platform, you
need to set up the RPM database. This usually involves two
steps:
</para>
<para>
*Initializing an empty RPM database
</para>
<para>
*Populating the database with packages, especially for
dependencies
</para>
<para>
Both steps are necessary.
</para>
<sect3>
<title>Initializing an Empty RPM Database</title>
<para>
After you have the RPM system installed on your platform, the
next big step is to create an RPM database for your platform.
You can make an empty database with the rpm --initdb command,
as shown following:
</para>
<para>
# mkdir /var/lib/rpm
</para>
<para>
# rpm --initdb
</para>
<para>
The first command creates the default directory for the RPM
database.
</para>
<para>
You may need to pass command-line options to specify a
non-default location of the RPM database, such as the
following:
</para>
<para>
# rpm --dbpath /location/of/your/rpm/database --initdb
</para>
<para>
Use a command like this one if you don���t want to place the
RPM database in its default location.
</para>
<para>
In addition, use the ���v option to add more verbose output.
This is very useful if errors occur. Use the --root option to
specify a different root directory for RPM operations. Use the
--rcfile option to specify a non-default set of rc files and
the --macros option to specify a non-default set of macros.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 21 covers RPM customization.
</para>
<para>
Initializing the RPM database creates the necessary structure
for an empty database. You can then fill, or populate, the
database with packages. In most cases, all you need to do is
install packages to populate the RPM database, as each
installed package gets added to the database.
</para>
</sect3>
<sect3>
<title>Handling Dependencies for Packages Installed Without RPM</title>
<para>
Each time you install a package, you populate the RPM
database. This works well, as long as you have already
installed all the dependencies for the packages you want to
install.
</para>
<para>
On an operating system that is based on RPM, such as Red Hat
Linux, all packages (except for some bootstrapping code) are
installed with RPM. That means nearly everything on the system
is defined in the RPM database. The RPM database then has a
full knowledge of what you have installed and can properly
handle dependencies. Thus, a failure to find a dependency
means that you have not installed the requisite package that
provides the needed capability.
</para>
<para>
On an operating system that is not based on RPM, however, such
as Solaris or IRIX, most packages have already been installed
by some means other than RPM.. That���s because these
operating systems use different native package-management
techniques and different package formats.
</para>
<para>
It is very likely that RPM packages you want to install have
dependencies that come from non-RPM packages. For example, the
rpm program on Windows depends on the cygwin environment, yet
this environment needs to be installed with a Windows
setup.exe program, not with the rpm command.
</para>
<para>
To get around this problem, you need to populate the new RPM
database with a package or packages that reflect the current
system in order to properly handle dependencies. The main way
to do this is to set up a virtual package.
</para>
</sect3>
<sect3>
<title>Setting Up A Virtual Package</title>
<para>
You can get around the problem of pre-existing software by
building a virtual package that lists the system
libraries@mdinstalled without RPM@mdin an RPM package. This
way, the rpm command will find that the dependencies are
installed, even if they were not really installed with RPM.
You need to do this for all capabilities and system libraries
installed outside of RPM control.
</para>
<para>
To help create such a virtual package, use the
vpkg-provides.sh script from the scripts directory. The
vpkg-provides.sh script searches a list of directories for
shared libraries and interpreters (such as shells). The
vpkg-provides.sh script then creates a spec file that lists
all the files found, files that are managed outside of RPM.
You can use this spec file to create an RPM and install the
RPM using the rpm command to populate the RPM database.
</para>
<para>
The RPM spec file created by the vpkg-provides.sh doesn���t
really install any files, as all the files are already
installed. Instead it makes a package that claims ownership
for all these files so that RPM dependencies can function
properly.
</para>
<para>
The vpkg-provides.sh script accepts three main command-line
options: --spec_header, --ignore_dirs, and --no_verify.
</para>
<para>
The --spec_header option tells the script the name of the RPM
spec file it should use as a header for the spec file it will
produce. You need to provide the path to the file. For
example:
</para>
<para>
# sh vpkg-provides.sh --spec_header /path/to/spec/file
</para>
<para>
You need to provide a spec file header to make a complete spec
file. This header should contain the Summary, Name, Version,
and Release settings, at least. Chapter 10 covers these spec
file tags.
</para>
<para>
The --ignore_dirs option tells the vpkg-provides.sh script to
ignore certain directories. You need to pass a list of egrep
search patterns that identify the directories to ignore.
Separate each pattern with a pipe character, |.
</para>
<para>
Note
</para>
<para>
The egrep command may not be available on your system. It may
be easier to edit the vpkg-provides.sh script and manually
specify the directories to ignore.
</para>
<para>
The --no_verify option tells the vpkg-provides.sh script to
skip the step of creating a script to verify checksums of all
files in the package.
</para>
<para>
In addition to these main command-line options, you can also
pass the following options to the vpkg-provides.sh script.
</para>
<para>
The --shlib_dirs option tells the vpkg-provides.sh script the
directories to look for shared libraries. Pass a
colon-delimited list of directories. For example:
</para>
<para>
# sh vpkg-provides.sh --spec_header /path/to/spec/file \
</para>
<para>
--shlib_dirs "/bin:/usr/bin:/sbin:/usr/sbin:/usr/ucb:/usr/bsd"
</para>
<para>
The --interp_dirs option tells the vpkg-provides.sh script
which directories to look in to find interpreters such as sh,
bash, perl, wish (Tcl/Tk), and awk. The --interps option tells
the vpkg-provides.sh script the names of the interpreter
commands. Both these options expect a colon-delimited list.
</para>
<para>
The --find_provides option tells the vpkg-provides.sh script
the name of the find-provides script to use, defaulting to
/usr/lib/rpm/find-provides.
</para>
<para>
The vpkg-provides.sh script defines specific directories to
look in for shared libraries and interpreters under various
operating systems. You will most likely need to edit this
section.
</para>
<para>
In fact, if you are working with a non-Unix system, or if you
experience problems running the vpkg-provides.sh script, you
can edit the file to remove the problematic commands. You can
also create a new script in a scripting language supported on
your system. The vpkg-provides.sh script is a Linux shell
script. Linux and Unix systems should be able to run the
script, but non-Unix systems likely won���t have the commands
and may also not support shell scripts at all. In an effort to
be generic, the vpkg-provides.sh script does a lot of work.
You can limit this by explicitly specifying directories and
commands, for example. And, if all else fails, you can create
a virtual package manually (covered in the following section).
</para>
<para>
When complete, the vpkg-provides.sh script outputs a spec
file, using the header you provided, and outputs a set of
Provides: lines to specify what the package provides. It then
outputs some empty definitions for the prep, build, install,
and clean sections of the spec file.
</para>
<para>
For example, you can run the vpkg-provides.sh script with a
command like the following:
</para>
<para>
$ sh ./vpkg-provides.sh --spec_header my_header.spec
--find_provides ./find-provides --no_verify
</para>
<para>
Note
</para>
<para>
If you run this script as a non-root user, you may get a
number of permission errors as the vpkg-provides.sh script
searches through system directories.
</para>
<para>
The script will then output your spec file header along with
output like that shown in Listing 20-1.
</para>
<para>
Listing 20-1: Output from the vpkg-provides.sh script
</para>
<para>
Provides: /bin/sh
</para>
<para>
Provides: /bin/csh
</para>
<para>
Provides: /bin/ksh
</para>
<para>
Provides: /bin/perl
</para>
<para>
Provides: /bin/awk
</para>
<para>
Provides: /bin/nawk
</para>
<para>
Provides: /bin/oawk
</para>
<para>
Provides: /usr/bin/sh
</para>
<para>
Provides: /usr/bin/csh
</para>
<para>
Provides: /usr/bin/ksh
</para>
<para>
Provides: /usr/bin/perl
</para>
<para>
Provides: /usr/bin/awk
</para>
<para>
Provides: /usr/bin/nawk
</para>
<para>
Provides: /usr/bin/oawk
</para>
<para>
Provides: /sbin/sh
</para>
<para>
Provides: /usr/dt/bin/dtksh
</para>
<para>
Provides: /usr/xpg4/bin/sh
</para>
<para>
Provides: /usr/xpg4/bin/awk
</para>
<para>
%prep
</para>
<para>
# nothing to do
</para>
<para>
%build
</para>
<para>
# nothing to do
</para>
<para>
%install
</para>
<para>
# nothing to do
</para>
<para>
%clean
</para>
<para>
# nothing to do
</para>
<para>
%files
</para>
<para>
# no files in a virtual package
</para>
<para>
The vpkg-provides.sh script also outputs a package description
that explains how the package was created. This is important
so that you know this is a virtual package.
</para>
<para>
When done, use the rpmbuild command to create an RPM from the
generated spec file.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 9 covers how to run the rpmbuild command, and Chapter
10 covers spec files in detail.
</para>
</sect3>
<sect3>
<title>Creating a Virtual Package Manually</title>
<para>
Even on Unix-like systems you may experience troubles with the
vpkg-provides.sh script. That���s simply because the
vpkg-provides.sh script assumes a number of Unix and GNU
utilities are available. In most cases, it will work best if
you can fix what went wrong and run the vpkg-provides.sh
script again.
</para>
<para>
If all else fails, though, you can create a virtual package
spec file manually. Create a spec file starting with the
Summary, Name, Version, and Release settings.
</para>
<para>
Looking at the output shown in Listing 20-1, you can create a
Provides: statement for each shared library on your system,
and each interpreter, such as shells. Add each statement to
your spec file. For example:
</para>
<para>
Provides: libgen.so
</para>
<para>
Copy the prep, build, install, and clean sections exactly as
they are in Listing 20-1. You can now run the rpmbuild command
to create a virtual package. Install this package.
</para>
</sect3>
</sect2>
<sect2>
<title>Creating the RPM environment</title>
<para>
The RPM environment is made up of a large number of RPM settings
and macro definitions. Run the rpm --showrc command to see the
current environment settings on Linux:
</para>
<para>
$ rpm ���showrc
</para>
<para>
ARCHITECTURE AND OS:
</para>
<para>
build arch : i386
</para>
<para>
compatible build archs: i686 i586 i486 i386 noarch
</para>
<para>
build os : Linux
</para>
<para>
compatible build os's : Linux
</para>
<para>
install arch : i686
</para>
<para>
install os : Linux
</para>
<para>
compatible archs : i686 i586 i486 i386 noarch
</para>
<para>
compatible os's : Linux
</para>
<para/>
<para>
RPMRC VALUES:
</para>
<para>
macrofiles :
/usr/lib/rpm/macros:/usr/lib/rpm/i686-linux/macros:/etc/
</para>
<para>
rpm/macros.specspo:/etc/rpm/macros.db1:/etc/rpm/macros.cdb:/etc/rpm/macros:/etc/
</para>
<para>
rpm/i686-linux/macros:~/.rpmmacros
</para>
<para>
optflags : -O2 -march=i686
</para>
<para>
This output was truncated for space. As you can see, there are a
lot of expected settings. You need to set up these same settings
and macros, but with the proper values for the new system on
which you are running RPM.
</para>
<para>
The files rpmrc.in and macros.in serve as the default templates
used to create the rc and macro settings, respectively. These
files are modified by the configure script to include values
specific to the local operating system. You can edit these files
as needed for your system, prior to installing RPM. That is,
edit these files between calling the make command and the make
install command.
</para>
<para>
Cross Reference
</para>
<para>
Chapter 21 covers how to customize the RPM settings and macros,
along with the popt aliases.
</para>
<para>
The INSTALL file in the RPM sources also describes some
modifications you may want to make to the macros.
</para>
</sect2>
</sect1>
<sect1>
<title>Creating Non-Linux RPMS</title>
<para>
Once you have RPM set up on a system, you should be able to create
RPMs using the rpmbuild command on that system.
</para>
<para>
Warning
</para>
<para>
Do not build RPM packages logged in as a root or Administrator
user. If something goes wrong, rpmbuild could destroy files in
your system. Remember that spec files can define a number of
commands and shell scripts. Any of these could have an error that
could cause major damage when run as a root user.
</para>
<para>
Before building RPMs with the rpmbuild command, though, you may
want to customize the build environment to better reflect your
system. You may also find it is too difficult to build most RPMs
on the non-Linux system and instead focus on cross-building
packages, should the rpmbuild command not work on the target
systems.
</para>
<para>
This section covers topics related to building RPMs on or for
non-Linux systems.
</para>
<sect2>
<title>Setting up a build environment</title>
<para>
In RPM terms, your build environment consists of the directories
where you build RPMs, as well as the rc and macro settings that
define all of the variables in an RPM-based system. To set up
your build environment, you need to ensure that all the rc and
macro settings reflect the true environment on your non-Linux
system.
</para>
<para>
The rpm --showrc command, discussed previously in the "Creating
the RPM Environment" section, lists the settings for your
system. You can use this command to verify all the settings.
</para>
<para>
You may want to change some settings, such as the top directory
where RPMs are built. By default, this setting is something like
the following:
</para>
<para>
_topdir %{_usrsrc}/redhat
</para>
<para>
Cross Reference
</para>
<para>
See Chapter 21 for more on how to customize the rc and macro
settings.
</para>
<para>
In most cases the _topdir setting on Red Hat Linux systems map
to the /usr/src/redhat directory. Your system may not even have
a /usr/src directory. Also you may not want to build RPMs in a
redhat directory, which may cause confusion if you are building
on a non-Red Hat Linux system.
</para>
<para>
Cross Reference
</para>
<para>
See Chapter 19 for more information on setting up a build
environment for RPMs. Chapter 19 focuses on other Linux systems,
but many of the same techniques apply.
</para>
<para>
With a build environment set up, you should be able to create
RPMs with the rpmbuild command. If this doesn���t work, or is
too difficult, then you can try cross-building packages.
</para>
</sect2>
<sect2>
<title>Cross-building packages</title>
<para>
You may find that it is too difficult to create RPMs on a given
platform. It may be easier to build the RPMs on another
platform, such as a Linux system, as if it were on the target
platform. This is called cross-building packages, since you are
building a package on one system specifically designed for
another.
</para>
<para>
In most cases, the target platform is quite different from the
system where you cross-build packages. Otherwise, you would
likely just build the RPMs on the target platform.
</para>
<para>
The key issues with cross-building are the following:
</para>
<para>
*You must compile any executables with a cross compiler for the
proper target platform.
</para>
<para>
*You must set the target platform in the RPMs you build.
</para>
<para>
*You must manage dependencies, and likely need to turn off the
automatic generation of dependencies.
</para>
<para>
Note
</para>
<para>
Setting up a cross-building environment is oftentimes more work
than it is worth. If you can compile applications and build
packages on the target system, do that. The cross-building
option should be used only if you really cannot build packages
on the target system. For example, many handheld or small-format
computers lack the processor performance or memory to compile
applications. These are good candidates for cross-building.
</para>
<para>
To compile executables for another platform, especially a
platform with a different processor architecture, you need a
cross compiler. A cross compiler runs on one system and produces
executables for another.
</para>
<para>
Note
</para>
<para>
Cross compilers are heavily used when working with embedded and
small device systems. The embedded system may not have the
processor power to compile applications, or it may simply be
inconvenient to compile applications on the embedded system.
</para>
<para>
The Linux gcc compiler can act as a cross compiler if you
install the right gcc add-on packages. See the GNU site for more
on the gcc compiler.
</para>
<para>
Cross Reference
</para>
<para>
You can download GCC and other GNU software from www.gnu.org.
</para>
<para>
In addition to compiling for the target platform, you need to
ensure that the RPM is marked as being for the target
architecture. If not, the rpm command will fail when trying to
install the RPM on the target system.
</para>
<para>
You can set the target architecture with the --target option to
the rpmbuild command. For example:
</para>
<para>
rpmbuild ���bi --target arm-sharp-linux
</para>
<para>
This specifies a target CPU architecture of ARM, the vendor
Sharp (which just happens to make an ARM-based Linux device) and
the operating system of Linux. The basic format is:
</para>
<para>
cpu-vendor-os
</para>
<para>
Cross Reference
</para>
<para>
See Chapter 12 for more on using the --target option to the
rpmbuild command.
</para>
<para>
You must also turn off or correct any automatically generated
dependencies in RPMs you build for other platforms. That is, any
dependencies based on the operating system or architecture of
the system you are cross-building on will likely not be found,
or be found in a different location or format, on the target
platform.
</para>
<para>
This is where the handy RPM feature of automatically building
the dependencies does not work to your advantage. You can turn
off this feature, however.
</para>
<para>
Cross Reference
</para>
<para>
See Chapter 19 for information on how to turn off the automatic
generation of dependencies.
</para>
<para>
You should turn off the automatically building of dependencies
for any packages you cross build.
</para>
<para>
Using these techniques, you can build packages on one system for
use on another, very different system. Due to the difficulties,
you should only go this route if it becomes too difficult to use
the rpmbuild command on the target systems.
</para>
</sect2>
</sect1>
<sect1>
<title>Summary</title>
<para>
With its superior package-management capabilities, especially for
automated installations and upgrades, you may want to use RPM on
non-Linux platforms. As the experience of many developers has
shown, you can indeed use RPM on non-Linux platforms.
</para>
<para>
The rpm.org site maintains a listing of operating systems where
developers have ported RPM. If you are lucky, you can download RPM
for your operating system and start working right away. If you are
not lucky, you will need to port RPM to your target system.
</para>
<para>
If RPM has been ported to your architecture, download the package
and follow the installation instructions. If RPM has not been
ported to your architecture, download the RPM sources and all
prerequisite libraries. You may need to port each library to your
architecture before you can even begin to port RPM.
</para>
<para>
The RPM sources use a configured build process that also requires
some prerequisite tools. You need to get or port these to your
architecture as well. Whew.
</para>
<para>
Once everything is in place, you can start the port of RPM. In
many cases, you just need to figure out how to get RPM to compile
and everything will fall into place. In other cases, you will need
to work on each RPM subsystem to get it to build and run.
</para>
<para>
After you have RPM for your system, you need to initialize the RPM
database with the rpm --initdb command. You can then start to
populate your RPM database. Because a large number of libraries
have already been installed on your system, you may need to create
a virtual package that claims to provide these files. Installing
such a virtual package will allow you to install other RPMs that
may be dependent on system libraries.
</para>
<para>
Much of porting RPM to another platform depends on the RPM
environment and how you need to customize that environment. The
next chapter shows how to customize your RPM environment, on Linux
or on other operating systems.
</para>
</sect1>
</chapter>
<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide-en.xml" "book" "chapter")
fill-column: 72
End:
-->