Maximum RPM

Taking the RPM Package Manager to the Limit

Edward C. Bailey

Red Hat, Inc.

%ghost description: Paul Nasrat

Start of updates, epoch, rpmbuild, etc: Matthias Saou

Various typo fixes, %check section, documentation on --recompil: Ville Skyttä

Copyright © 2000 by Red Hat, Inc. 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/).

Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.

Revision History
Revision 1.0 17-February-1997
First edition (Produced/printed by Red Hat Software)
Revision 1.1 ??-???-1997
Revised for production by Sams Publishing
Revision 1.2 29-February-2000
Translated into DocBook
Revision 1.3 05-March-2003
Start of the update process

Table of Contents

Preface
Linux and RPM — A Brief History
Parts of the book, and who they're for
Acknowledgements
I. RPM and Computer Users — How to Use RPM to Effectively Manage Your Computer
1. An Introduction to Package Management
What are Packages, and Why Manage Them?
Enter the Package
Manage Your Packages, or They Will Manage You
Package Management: How to Do It?
Ancestors of RPM
RPM Design Goals
Make it easy to get packages on and off the system
Make it easy to verify a package was installed correctly
Make it easy for the package builder
Make it start with the original source code
Make it work on different computer architectures
What's in a package?
RPM's Package Labels
Labels And Names: Similar, But Distinct
Package-wide Information
Per-file Information
Let's Get Started
2. Using RPM to Install Packages
rpm -i — What does it do?
Performing dependency checks:
Checking for conflicts:
Performing any tasks required before the install:
Deciding what to do with config files:
Unpacking files from the package and putting them in the proper place:
Performing any tasks required after the install:
Keeping track of what it did:
Performing an Install
URLs — Another Way to Specify Package Files
A warning message you might never see
Two handy options
Getting a bit more feedback with -v
-h: Perfect for the Impatient
Additional options to rpm -i
Getting a lot more information with -vv
--test: Perform Installation Tests Only
--replacepkgs: Install the Package Even If Already Installed
--replacefiles: Install the Package Even If It Replaces Another Package's Files
--nodeps: Do Not Check Dependencies Before Installing Package
--force: The Big Hammer
--excludedocs: Do Not Install Documentation For This Package
--includedocs: Install Documentation For This Package
--prefix <path>: Relocate the package to <path>, if possible
--noscripts: Do Not Execute Pre- and Post-install Scripts
--percent: Not Meant for Human Consumption
--rcfile <rcfile>: Use <rcfile> As An Alternate rpmrc File
--root <path>: Use <path> As An Alternate Root
--dbpath <path>: Use <path> To Find RPM Database
--ftpport <port>: Use <port> In FTP-based Installs
--ftpproxy <host>: Use <host> As Proxy In FTP-based Installs
--ignorearch: Do Not Verify Package Architecture
--ignoreos: Do Not Verify Package Operating System
3. Using RPM to Erase Packages
rpm -e — What Does it Do?
Erasing a Package
Getting More Information With -vv
Additional Options
--test — Go Through the Process of Erasing the Package, But Do Not Erase It
--nodeps: Do Not Check Dependencies Before Erasing Package
--noscripts — Do Not Execute Pre- and Post-uninstall Scripts
--rcfile <rcfile> — Read <rcfile> For RPM Defaults
--root <path> — Use <path> As the Root
--dbpath <path>: Use <path> To Find RPM Database
rpm -e and Config files
Watch Out!
4. Using RPM to Upgrade Packages
rpm -U — What Does it Do?
Config file magic
Upgrading a Package
rpm -U's Dirty Little Secret
They're Nearly Identical…
--oldpackage: Upgrade To An Older Version
--force: The Big Hammer
--noscripts: Do Not Execute Install and Uninstall Scripts
5. Getting Information About Packages
rpm -q — What does it do?
The Parts of an RPM Query
Query Commands, Part One: Package Selection
Query Commands, Part Two: Information Selection
Getting a lot more information with -vv
--root <path>: Use <path> As An Alternate Root
--rcfile <rcfile>: Use <rcfile> As An Alternate rpmrc File
--dbpath <path>: Use <path> To Find RPM Database
A Few Handy Queries
Finding Config Files Based on a Program Name
Learning More About an Uninstalled Package
Finding Documentation for a Specific Package
Finding Similar Packages
Finding Recently Installed Packages, Part I
Finding Recently Installed Packages, Part II
Finding the Largest Installed Packages
6. Using RPM to Verify Installed Packages
rpm -V — What Does it Do?
What Does it Verify?
When Verification Fails — rpm -V Output
Other Verification Failure Messages
Selecting What to Verify, and How
The Package Label — Verify an Installed Package Against the RPM Database
-a — Verify All Installed Packages Against the RPM Database
-f <file> — Verify the Package Owning <file> Against the RPM Database
-p <file> — Verify Against a Specific Package File
-g <group> — Verify Packages Belonging To <group>
--nodeps: Do Not Check Dependencies During Verification
--noscripts: Do Not Execute Verification Script
--nofiles: Do Not Verify File Attributes
-v — Display Additional Information
-vv — Display Debugging Information
--dbpath <path>: Use <path> To Find RPM Database
--root <path>: Set Alternate Root to <path>
--rcfile <rcfile>: Set Alternate rpmrc file to <rcfile>
We've Lied to You…
RPM Controls What Gets Verified
7. Using RPM to Verify Package Files
rpm -K — What Does it Do?
Pretty Good Privacy: RPM's Assistant
Configuring PGP for rpm -K
Using rpm -K
-v — Display Additional Information
When the Package is Not Signed
When You Are Missing the Correct Public Key
When a Package Just Doesn't Verify
--nopgp — Do Not Verify Any PGP Signatures
-vv — Display Debugging Information
--rcfile <rcfile>: Use <rcfile> As An Alternate rpmrc File
8. Miscellanea
Other RPM Options
--rebuilddb — Rebuild RPM database
--initdb — Create a New RPM Database
--quiet — Produce as little output as possible
--help — Display a help message
--version — Display the current RPM version
Using rpm2cpio
rpm2cpio — What does it do?
A more real-world example — Listing the files in a package file
Extracting one or more files from a package file
Source Package Files and How To Use Them
A gentle introduction to source code
Do you really need more information than this?
So what can I do with it?
Stick with us!
II. RPM and Developers — How to Distribute Your Software More Easily With RPM
9. The Philosophy Behind RPM
Pristine Sources
Easy Builds
Reproducible Builds
Unattended Builds
Multi-architecture/operating system Support
Easier For Your Users
Easy Upgrades
Intelligent Configuration File Handling
Powerful Query Capabilities
Easy Package Verification
To Summarize…
10. The Basics of Developing With RPM
The Inputs
The Sources
The Patches
The Spec File
The Engine: RPM
The Outputs
The Source Package File
The Binary RPM
And Now…
11. Building Packages: A Simple Example
Creating the Build Directory Structure
Getting the Sources
Creating the Spec File
The Preamble
The %prep Section
The %build Section
The %install Section
The %files Section
The Missing Spec File Sections
Starting the Build
When Things Go Wrong
Problems During the Build
Testing Newly Built Packages
12. rpmbuild Command Reference
rpmbuild — What Does it Do?
rpmbuild -bp — Execute %prep
rpmbuild -bc — Execute %prep, %build
rpmbuild -bi — Execute %prep, %build, %install, %check
rpmbuild -bb — Execute %prep, %build, %install, %check, package (bin)
rpmbuild -ba — Execute %prep, %build, %install, %check, package (bin, src)
rpmbuild -bl — Check %files list
--short-circuit — Force build to start at particular stage
--buildarch <arch> — Perform Build For the <arch> Architecture
--buildos <os> — Perform Build For the <os> Operating System
--sign — Add a Digital Signature to the Package
--test — Create, Save Build Scripts For Review
--clean — Clean up after build
--buildroot <path> — Execute %install using <path> as the root
--timecheck <secs> — Print a warning if files to be packaged are over <secs> old
-vv — Display debugging information
--quiet — Produce as Little Output as Possible
--rcfile <rcfile> — Set alternate rpmrc file to <rcfile>
Other Build-related Commands
rpmbuild --recompile — What Does it Do?
rpmbuild --rebuild — What Does it Do?
13. Inside the Spec File
Comments: Notes Ignored by RPM
Tags: Data Definitions
Package Naming Tags
Descriptive Tags
Dependency Tags
Architecture- and Operating System-Specific Tags
Directory-related Tags
Source and Patch Tags
Scripts: RPM's Workhorse
Build-time Scripts
Install/Erase-time Scripts
Verification-Time Script — The %verifyscript Script
Macros: Helpful Shorthand for Package Builders
The %setup Macro
The %patch Macro
The %files List
Directives For the %files list
File-related Directives
Directory-related Directives
The Lone Directive: %package
-n <string> — Use <string> As the Entire Subpackage Name
Conditionals
The %ifarch Conditional
The %ifnarch Conditional
The %ifos Conditional
The %ifnos Conditional
The %else Conditional
The %endif Conditional
14. Adding Dependency Information to a Package
An Overview of Dependencies
Automatic Dependencies
The Automatic Dependency Scripts
Automatic Dependencies: An Example
The autoreqprov, autoreq, and autoprov Tags — Disable Automatic Dependency Processing
Manual Dependencies
The Requires Tag
The Conflicts Tag
The Provides Tag
To Summarize…
15. Making a Relocatable Package
Why relocatable packages?
The prefix tag: Relocation Central
Relocatable Wrinkles: Things to Consider
%files List Restrictions
Relocatable Packages Must Contain Relocatable Software
The Relocatable Software Is Referenced By Other Software
Building a Relocatable Package
Tying Up the Loose Ends
Test-Driving a Relocatable Package
16. Making a Package That Can Build Anywhere
Using Build Roots in a Package
Some Things to Consider
Having RPM Use a Different Build Area
Setting up a Build Area
Directing RPM to Use the New Build Area
Performing a Build in a New Build Area
Specifying File Attributes
%attr — How Does It Work?
Betcha Thought We Forgot…
17. Adding PGP Signatures to a Package
Why Sign a Package?
Getting Ready to Sign
Preparing PGP: Creating a Key Pair
Preparing RPM
Signing Packages
--sign — Sign a Package At Build-Time
--resign — Replace a Package's Signature(s)
--addsign — Add a Signature To a Package
18. Creating Subpackages
What Are Subpackages?
Why Are They Needed?
Our Example Spec File: Subpackages Galore!
Spec File Changes For Subpackages
The Subpackage's "Preamble"
The %files List
Install- and Erase-time Scripts
Build-Time Scripts: Unchanged For Subpackages
Our Spec File: One Last Look…
Building Subpackages
Giving Subpackages the Once-Over
19. Building Packages for Multiple Architectures and Operating Systems
Architectures and Operating Systems: A Primer
Let's Just Call Them Platforms
What Does RPM Do To Make Multi-Platform Packaging Easier?
Automatic Detection of Build Platform
Automatic Detection of Install Platform
Platform-Dependent Tags
Platform-Dependent Conditionals
Build and Install Platform Detection
Platform-Specific rpmrc Entries
Overriding Platform Information At Build-Time
Overriding Platform Information At Install-Time
optflags — The Other rpmrc File Entry
Platform-Dependent Tags
The excludexxx Tag
The exclusivexxx Tag
Platform-Dependent Conditionals
Common Features of All Conditionals
%ifxxx
%ifnxxx
Hints and Kinks
20. Real-World Package Building
An Overview of Amanda
Initial Building Without RPM
Setting Up A Test Build Area
Getting Software to build
Installing and testing
Initial Building With RPM
Generating patches
Making a first-cut spec file
Getting the original sources unpacked
Getting patches properly applied
Letting RPM do the Building
Letting RPM do the Installing
Testing RPM's Handiwork
Package Building
Creating the %files list
Testing those first packages
Finishing Touches
21. A Guide to the RPM Library API
An Overview of rpmlib
rpmlib Functions
Error Handling
Getting Package Information
Variable Manipulation
rpmrc-Related Information
RPM Database Manipulation
RPM Database Traversal
RPM Database Search
Package Manipulation
Package And File Verification
Dependency-Related Operations
Diagnostic Output Control
Signature Verification
Header Manipulation
Header Entry Manipulation
Header Iterator Support
Example Code
Example #1
Example #2
Example #3
III. Appendixes
A. Format of the RPM File
RPM File Naming Convention
RPM File Format
Parts of an RPM File
The Lead
Wanted: A New RPM Data Structure
The Signature
The Header
The Archive
Tools For Studying RPM Files
Identifying RPM files with the file(1) command
B. The rpmrc File
Using the --showrc Option
Different Places an rpmrc File Resides
/usr/lib/rpmrc
/etc/rpmrc
.rpmrc in the user's login directory
File indicated by the --rcfile option
rpmrc File Syntax
rpmrc File Entries
arch_canon
os_canon
buildarchtranslate
buildostranslate
arch_compat
os_compat
builddir
buildroot
cpiobin
dbpath
defaultdocdir
distribution
excludedocs
ftpport
ftpproxy
messagelevel
netsharedpath
optflags
packager
pgp_name
pgp_path
require_distribution
require_icon
require_vendor
rpmdir
signature
sourcedir
specdir
srcrpmdir
timecheck
tmppath
topdir
vendor
C. Concise RPM Command Reference
Global Options
Informational Options
Query Mode
Package Specification Options To Query Mode
Information Selection Options To Query Mode
Verify Mode
Options To Verify Mode
Install Mode
Options To Install Mode
Upgrade Mode
Options To Upgrade Mode
Erase Mode
Options To Erase Mode
Build Mode
Build Mode Stages
Options To Build Mode
Rebuild Mode
Options To Rebuild Mode
Recompile Mode
Options To Recompile Mode
Resign Mode
Options To Resign Mode
Add Signature Mode
Options To Add Signature Mode
Check Signature Mode
Options To Check Signature Mode
Initialize Database Mode
Options to Initialize database Mode
Rebuild Database Mode
Options to Rebuild Database Mode
D. Available Tags For --queryformat
List of --queryformat Tags
The NAME Tag
The VERSION Tag
The RELEASE Tag
The EPOCH Tag
The SUMMARY Tag
The DESCRIPTION Tag
The BUILDTIME Tag
The BUILDHOST Tag
The INSTALLTIME Tag
The SIZE Tag
The DISTRIBUTION Tag
The VENDOR Tag
The GIF Tag
The XPM Tag
The LICENSE Tag
The PACKAGER Tag
The GROUP Tag
The CHANGELOG Tag
The SOURCE Tag
The PATCH Tag
The URL Tag
The OS Tag
The ARCH Tag
The PREIN Tag
The POSTIN Tag
The PREUN Tag
The POSTUN Tag
The FILENAMES Tag
The FILESIZES Tag
The FILESTATES Tag
The FILEMODES Tag
The FILEUIDS Tag
The FILEGIDS Tag
The FILERDEVS Tag
The FILEMTIMES Tag
The FILEMD5S Tag
The FILELINKTOS Tag
The FILEFLAGS Tag
The ROOT Tag
The FILEUSERNAME Tag
The FILEGROUPNAME Tag
The EXCLUDE Tag
The EXCLUSIVE Tag
The ICON Tag
The SOURCERPM Tag
The FILEVERIFYFLAGS Tag
The ARCHIVESIZE Tag
The PROVIDES Tag
The REQUIREFLAGS Tag
The REQUIRENAME Tag
The REQUIREVERSION Tag
The NOSOURCE Tag
The NOPATCH Tag
The CONFLICTFLAGS Tag
The CONFLICTNAME Tag
The CONFLICTVERSION Tag
The DEFAULTPREFIX Tag
The BUILDROOT Tag
The INSTALLPREFIX Tag
The EXCLUDEARCH Tag
The EXCLUDEOS Tag
The EXCLUSIVEARCH Tag
The EXCLUSIVEOS Tag
The AUTOREQPROV, AUTOREQ, and AUTOPROV Tags
The RPMVERSION Tag
The TRIGGERSCRIPTS Tag
The TRIGGERNAME Tag
The TRIGGERVERSION Tag
The TRIGGERFLAGS Tag
The TRIGGERINDEX Tag
The VERIFYSCRIPT Tag
E. Concise Spec File Reference
Comments
The Preamble
Package Naming Tags
Descriptive Tags
Dependency Tags
Architecture- and Operating System-Specific Tags
Directory-related Tags
Source and Patch Tags
Scriptlets
Build Scriptlets
Install/Erase Scriptlets
%verifyscript Directive
Macros
The %setup Macro
The %patch Macro
The %files List
Directives For the %files list
File-related Directives
Directory-related Directives
%package Directive
The %package -n Option
Conditionals
The %ifarch Conditional
The %ifnarch Conditional
The %ifos Conditional
The %ifnos Conditional
The %else Conditional
The %endif Conditional
F. RPM-related Resources
Where to Get RPM
FTP Sites
What Do I Need?
Where to Talk About RPM
The rpm-list Mailing List
The redhat-list Mailing List
The redhat-digest Mailing List
RPM On the World Wide Web
RPM's License
GNU GENERAL PUBLIC LICENSE
Preamble
GNU GENERAL PUBLIC LICENSE
How to Apply These Terms to Your New Programs
G. An Introduction to PGP
PGP — Privacy for Regular People
Keys your Locksmith Wouldn't Understand
Are RPM Packages Encrypted?
Do All RPM Packages Have Digital Signatures?
So Much to Cover, So Little Time
Installing PGP for RPM's Use
Obtaining PGP
Building PGP
Ready to Go!
Index

List of Tables

2.1. rpm -i Command Syntax
3.1. rpm -e Command Syntax
4.1. rpm -U Command Syntax
5.1. rpm -q Command Syntax
6.1. rpm -V Command Syntax
6.2. Verification Versus File Types
7.1. rpm -K Command Syntax
12.1. rpmbuild Command Syntax

Preface

Linux and RPM — A Brief History

Welcome! This is a book about the Red Hat Package Manager, or RPM Package Manager, known to its friends as simply RPM. The history of RPM is inextricably linked to the history of GNU/Linux, so a bit of GNU/Linux history may be in order. GNU/Linux is a full-featured implementation of a UNIX-like operating system, and has taken the computing world by storm.

And for a good reason — When choosing GNU/Linux, an Intel-based personal computer that had previously been prisoner of the dreaded Windows hourglass is transformed into a fully multitasking, network capable, personal workstation. All for the cost of the time required to download, install, and configure the software.

Of course, if you're not the type to tinker with downloaded software, many companies have created CDROMs containing GNU/Linux and associated software. The amount of tinkering required with these distributions has varied widely. The phrase "You get what you pay for" is never more true than in the area of GNU/Linux distributions.

One distribution bears the curious name "Red Hat Linux". Produced by a company of the same name, this GNU/Linux distribution was different. One of the key decisions a new Linux user needs to make is which of the many different parts of the distribution to install on their system. Most distributions use some sort of menu, making it easy to pick and choose. Red Hat Linux is no different.

But what is different about Red Hat Linux is that the creators of the distribution wanted their customers to have the the ability to make the same choices long after the installation process was over. Some commercial UNIX systems have this capability (called "package management"), and a few GNU/Linux distributors were trying to come up with something similar, but none had at the time the extensive scope present in RPM.

Over time, Red Hat Linux has become the most popular distribution available today. For it to edge out the previous leader (Slackware) in just two years is amazing. There has to be a reason for this kind of success, and a good part of the reason is RPM. But until the first edition of this book, there had been precious little in terms of RPM documentation. You could say that RPM's ease of use has made detailed instructions practically unnecessary, and you'd be right.

However, there are always people that want to know more about their computers, and given the popularity of Red Hat Linux, this alone would have made a book on RPM worthwhile. But there's more to the story than that.

There is a truism in the world of Free Software, that goes something like this: If there's a better solution freely available, use it! RPM is no exception to the rule. Put under the terms of the GNU General Public License (Meaning: RPM cannot be made proprietary by anyone, not even Bill Gates), RPM started to attract the attention of others in the Linux, Unix, and free software communities.

At present, RPM is used by several commercial software companies producing Linux applications. They find that RPM makes it easier to get their products into the hands of their customers. They also find that it can even make the process of building their software easier. (Those of you that develop software for fun and profit, stick around — the second half of this book will show you everything you need to know to get your software "RPM-ized")

People have also ported RPM to several commercial UNIX systems, including DEC's Digital Unix, IBM's AIX, and Silicon Graphics' IRIX. Why? The simple answer is that it makes it easier to install, upgrade, and de-install software. If all these people are using RPM, shouldn't you?

Parts of the book, and who they're for

This book is divided into two major sections. The first section is for anyone that needs to know how to use RPM on their system. Given the state of the GNU/Linux arena today, this could mean just about anyone, including people that are new to GNU/Linux, or even UNIX. So those of you that think that

ls -FAl !* | less
        

is serious magic (or maybe even a typing error), relax — we'll explain everything you'll need to know in the first section.

In the book's second half, we'll be covering all there is to know about building packages using RPM. Since software engineering on GNU/Linux and UNIX systems requires in-depth knowledge of the operating system, available tools, and basic programming concepts, we're going to assume that the reader has sufficient background in these areas. Feel free to browse through the second half, but don't hesitate to seek additional sources of information if you find the going a bit tough.

Acknowledgements

Writing a book is similar to entering a long-term relationship with an obsessive partner. Throughout the nine months it took to write this book, life went on: job changes, births, deaths, and even a hurricane. Throughout it all, the book demanded constant attention. Therefore, I'd like to thank the people that made it possible to focus on the book to the exclusion of nearly everything else. My wife, Deb and son, Matt supported and encouraged me throughout, even when I was little more than a reclusive houseguest hunched over the computer in the study. Additionally, Deb acted as my editor and indexer, eventually reading the book completely three times! Thank you both.

Thanks also to Marc Ewing and Erik Troan, RPM architects extraordinaire. Without their programming savvy, RPM wouldn't be the elegant tool it is. Without their boundless patience, my many questions would have gone unanswered, and this book would have been much less than it is now. I hope you find this book a worthy companion to your programming handiwork.

Rik Faith provided some much-needed information about PMS and PM, two of RPM's ancestors. Thank you!

Finally a great big thank you goes to Jessica and the gang at L'il Dinos, Jennifer and her crew at the Cary Barnes & Noble coffee shop, and Mom and her "kids" at Schlotzsky's Deli in Durham. If all of you hadn't let me sit around for hours writing, this book wouldn't be nearly as fat as it is. And neither would I!

February, 1997 Cary, North Carolina

RPM and Computer Users — How to Use RPM to Effectively Manage Your Computer

Table of Contents

1. An Introduction to Package Management
What are Packages, and Why Manage Them?
Enter the Package
Manage Your Packages, or They Will Manage You
Package Management: How to Do It?
Ancestors of RPM
RPM Design Goals
Make it easy to get packages on and off the system
Make it easy to verify a package was installed correctly
Make it easy for the package builder
Make it start with the original source code
Make it work on different computer architectures
What's in a package?
RPM's Package Labels
Labels And Names: Similar, But Distinct
Package-wide Information
Per-file Information
Let's Get Started
2. Using RPM to Install Packages
rpm -i — What does it do?
Performing dependency checks:
Checking for conflicts:
Performing any tasks required before the install:
Deciding what to do with config files:
Unpacking files from the package and putting them in the proper place:
Performing any tasks required after the install:
Keeping track of what it did:
Performing an Install
URLs — Another Way to Specify Package Files
A warning message you might never see
Two handy options
Getting a bit more feedback with -v
-h: Perfect for the Impatient
Additional options to rpm -i
Getting a lot more information with -vv
--test: Perform Installation Tests Only
--replacepkgs: Install the Package Even If Already Installed
--replacefiles: Install the Package Even If It Replaces Another Package's Files
--nodeps: Do Not Check Dependencies Before Installing Package
--force: The Big Hammer
--excludedocs: Do Not Install Documentation For This Package
--includedocs: Install Documentation For This Package
--prefix <path>: Relocate the package to <path>, if possible
--noscripts: Do Not Execute Pre- and Post-install Scripts
--percent: Not Meant for Human Consumption
--rcfile <rcfile>: Use <rcfile> As An Alternate rpmrc File
--root <path>: Use <path> As An Alternate Root
--dbpath <path>: Use <path> To Find RPM Database
--ftpport <port>: Use <port> In FTP-based Installs
--ftpproxy <host>: Use <host> As Proxy In FTP-based Installs
--ignorearch: Do Not Verify Package Architecture
--ignoreos: Do Not Verify Package Operating System
3. Using RPM to Erase Packages
rpm -e — What Does it Do?
Erasing a Package
Getting More Information With -vv
Additional Options
--test — Go Through the Process of Erasing the Package, But Do Not Erase It
--nodeps: Do Not Check Dependencies Before Erasing Package
--noscripts — Do Not Execute Pre- and Post-uninstall Scripts
--rcfile <rcfile> — Read <rcfile> For RPM Defaults
--root <path> — Use <path> As the Root
--dbpath <path>: Use <path> To Find RPM Database
rpm -e and Config files
Watch Out!
4. Using RPM to Upgrade Packages
rpm -U — What Does it Do?
Config file magic
Upgrading a Package
rpm -U's Dirty Little Secret
They're Nearly Identical…
--oldpackage: Upgrade To An Older Version
--force: The Big Hammer
--noscripts: Do Not Execute Install and Uninstall Scripts
5. Getting Information About Packages
rpm -q — What does it do?
The Parts of an RPM Query
Query Commands, Part One: Package Selection
Query Commands, Part Two: Information Selection
Getting a lot more information with -vv
--root <path>: Use <path> As An Alternate Root
--rcfile <rcfile>: Use <rcfile> As An Alternate rpmrc File
--dbpath <path>: Use <path> To Find RPM Database
A Few Handy Queries
Finding Config Files Based on a Program Name
Learning More About an Uninstalled Package
Finding Documentation for a Specific Package
Finding Similar Packages
Finding Recently Installed Packages, Part I
Finding Recently Installed Packages, Part II
Finding the Largest Installed Packages
6. Using RPM to Verify Installed Packages
rpm -V — What Does it Do?
What Does it Verify?
When Verification Fails — rpm -V Output
Other Verification Failure Messages
Selecting What to Verify, and How
The Package Label — Verify an Installed Package Against the RPM Database
-a — Verify All Installed Packages Against the RPM Database
-f <file> — Verify the Package Owning <file> Against the RPM Database
-p <file> — Verify Against a Specific Package File
-g <group> — Verify Packages Belonging To <group>
--nodeps: Do Not Check Dependencies During Verification
--noscripts: Do Not Execute Verification Script
--nofiles: Do Not Verify File Attributes
-v — Display Additional Information
-vv — Display Debugging Information
--dbpath <path>: Use <path> To Find RPM Database
--root <path>: Set Alternate Root to <path>
--rcfile <rcfile>: Set Alternate rpmrc file to <rcfile>
We've Lied to You…
RPM Controls What Gets Verified
7. Using RPM to Verify Package Files
rpm -K — What Does it Do?
Pretty Good Privacy: RPM's Assistant
Configuring PGP for rpm -K
Using rpm -K
-v — Display Additional Information
When the Package is Not Signed
When You Are Missing the Correct Public Key
When a Package Just Doesn't Verify
--nopgp — Do Not Verify Any PGP Signatures
-vv — Display Debugging Information
--rcfile <rcfile>: Use <rcfile> As An Alternate rpmrc File
8. Miscellanea
Other RPM Options
--rebuilddb — Rebuild RPM database
--initdb — Create a New RPM Database
--quiet — Produce as little output as possible
--help — Display a help message
--version — Display the current RPM version
Using rpm2cpio
rpm2cpio — What does it do?
A more real-world example — Listing the files in a package file
Extracting one or more files from a package file
Source Package Files and How To Use Them
A gentle introduction to source code
Do you really need more information than this?
So what can I do with it?
Stick with us!

Chapter 1. An Introduction to Package Management

What are Packages, and Why Manage Them?

To answer that question, let's go back to the basics for a moment. Computers process information. In order for this to happen, there are some prerequisites:

  • A computer (Obviously!).

  • Some information to process (Also obvious!).

  • A program to do the processing (Still pretty obvious!).

Unless these three things come together very little is going to happen, information processing-wise. But each of these items have their own requirements that need to be satisfied before things can get exciting.

Take the computer, for example. While it needs things like electricity and a cool, dry place to operate, it also needs access to the other two items — information and programs — in order to do its thing. The way to get information and programs into a computer is to place them in the computer's mass storage. These days, mass storage invariably means a disk drive. Putting information and programs on the disk drive means that they are stored as files. So much for the computer's part in this.

OK, let's look at the information. Does information have any particular needs? Well, it needs sufficient space on the disk drive, but more importantly, it needs to be in the proper format for the program that will be processing it. That's it for information.

Finally, we have the program. What does it need? Like the information, it needs sufficient disk space on the disk drive. But there are many other things that it may need:

  • It may need information to process, in the correct format, named properly, and in the appropriate area on a disk drive somewhere.

  • It may need one or more configuration files. These are files that control the program's behavior and permit some level of customization. Like the information, these files must be in the proper format, named properly, and in the appropriate area on a disk. We'll be referring to them by their other name — config files — throughout the book.

  • It may need work areas on a disk, named properly, and located in the appropriate area.

  • It may even need other programs, each with their own requirements.

  • Although not strictly required by the program itself, the program may come with one or more files containing documentation. These files can be very handy for the humans trying to get the program to do their bidding!

As you can imagine, this can get pretty complicated. It's not so bad once everything is set up properly, but how do things get set up properly in the first place? There are two possibilities:

  1. After reading the documentation that comes with the program you'd like to use, you copy the various programs, configuration files, and information onto your computer, making sure they are all named correctly, are located in the proper place, and that there is sufficient disk space to hold them all. You make the appropriate changes to the configuration file(s). Finally, you run any setup programs that are necessary, giving them whatever information they require to do their job.

  2. You let the computer do it.

If it seems like the first choice isn't so bad, consider how many files you'll need to keep track of. On a typical Linux system, it's not unusual to have over 20,000 different files. That's a lot of documentation reading, file copying, and configuring! And what happens when you want a newer version of a program? More of the same!

Some people think the second alternative is easier. RPM was made for them.

Enter the Package

When you consider that computers are very good at keeping track of large amounts of data, the idea of giving your computer the job of riding herd over 20,000 files seems like a good one. And that's exactly what package management software does. But what is a "package"?

A package in the computer sense is very similar to a package in the physical sense. Both are methods of keeping related objects together in the same place. Both need to be opened before the contents can be used. Both can have a "packing slip" taped to the side, identifying the contents.

Normally, package management systems take all the various files containing programs, data, documentation, and configuration information, and place them in one specially formatted file — a package file. In the case of RPM, the package file is sometimes called a "package", a ".rpm file", or even an "RPM". All mean the same thing — a package containing software meant to be installed using RPM.

What types of software are normally found in a package? There are no hard and fast rules, but normally a package's contents consist of one of the following types of software:

  • A collection of one or more programs that perform a single well-defined task. This is normally what people think of as an "application". Word processors and programming languages would fit into this category.

  • A specific part of an operating system. Examples might be system initialization scripts, a particular command shell, or the software required to support a web server, for example.

Advantages of a Package

One of the most obvious benefits to having a package is that the package is one easily manageable chunk. If you move it from one place to another, there's no risk of any part getting left behind. But although this is the most obvious advantage, it's not the biggest one.

The biggest advantage is that the package can contain the knowledge about what it takes to install itself on your computer. And if the package contains the steps required to install itself, the package can also contain the steps required to uninstall itself. What used to be a painful manual process is now a straightforward procedure. What used to be a mass of 20,000 files becomes a couple hundred packages.

Manage Your Packages, or They Will Manage You

A couple hundred? Even though the use of packages has decreased the complexity of managing a system by an order of magnitude, it hasn't yet gotten to the level of being a "no-brainer". It's still necessary to keep track of what packages are installed on your system. And if there are some packages that require other packages in order to install or operate correctly, these should be tracked as well.

Packages Lead Active Lives

If you start looking at a computer system as a collection of packages, you'll find that a distinct set of operations will take place on those packages time and time again:

  • New packages are installed. Maybe it's a spreadsheet you'll use to keep track of expenses, or the latest shoot-em-up game, but in either case it's new and you want it.

  • Old packages are replaced with newer versions. Whoever wrote the word processor you use daily, comes out with a new version. You'll probably want to install the new version and remove the old one.

  • Packages are removed entirely. Perhaps that over-hyped strategy game just didn't cut it. You have better things to do with that disk space, so get rid of it!

With this much activity going on, it's easy to lose track of things. What types of package information should be available to keep you informed?

Keeping Track of Packages

Just as there are certain operations that are performed on packages, there are also certain types of information that will make it easier to make sense of the packages installed on your system:

  • Certainly you'd like to be able to see what packages are installed. It's easy to forget if that fax program you tried a few months ago is still installed or not.

  • It would be nice to be able to get more detailed information on a specific package. This might consist of anything from the date the package was installed, to a list of files it installed on your system.

  • Being able to access this information in a variety of ways can be helpful, too. Instead of simply finding out what files a package installed, it might be handy to be able to name a particular file and find out which package installed it.

  • If this amount of detail is possible, then it should be possible to see if the way a package is presently installed varies from the way it was originally installed. It's not at all unusual to make a mistake and delete one file — or a hundred. Being able to tell if one or more packages are missing files could greatly simplify the process of getting an ailing system back on its feet again.

  • Files containing configuration information can be a real headache. If it were possible to pay extra attention to these files and make sure any changes made to them weren't lost, life would certainly be a lot easier.

Package Management: How to Do It?

Well, all that sounds great — easy install, upgrade, and deletion of packages; getting package information presented several different ways; making sure packages are installed correctly; and even tracking changes to config files. But how do you do it?

As mentioned above, the obvious answer is to let the computer do it. Many groups have tried to create package management software. There are two basic approaches:

  1. Some package management systems concentrate on the specific steps required to manipulate a package.

  2. Other package management systems take a different approach, keeping track of the files on the system and manipulating packages by concentrating on the files involved.

Each approach has its good and bad points. In the first method, it's easy to install new packages, somewhat difficult to remove old ones, and almost impossible to obtain any meaningful information about installed packages.

The second method makes it easy to obtain information about installed packages, and fairly easy to install and remove packages. The main problem using this method is that there may not be a well-defined way to execute any commands required during the installation or removal process.

In practice, no package management system uses one approach or the other — all are a mixture of the two. The exact mix and design goals will dictate how well a particular package management system meets the needs of the people using it. At the time Red Hat started work on their Linux distribution, there were a number of package management systems in use, each with a different approach to making package management easier.

Ancestors of RPM

Since this is a book on the Red Hat Package Manager, a good way to see what RPM is all about is to look at the package management software that preceded RPM.

RPP

RPP was used in the first Red Hat Linux distributions. Many of RPP's features would be recognizable to anyone who has worked with RPM. Some of these innovative features are:

  • Simple, one command installation and uninstallation of packages.

  • Scripts that can run before and after installation and uninstallation of packages.

  • Package verification. The files of individual packages can be checked to see that they haven't been modified since they were installed.

  • Powerful querying. The database of packages can be queried for information about installed packages, including file lists, descriptions and more.

While RPP possessed several of the features that were important enough to continue on as parts of RPM today, it had some weaknesses, too:

  • It didn't use "pristine sources". Every program is made up of programming language statements stored in files. This source code is later translated into a binary language that the computer can execute. In the case of RPP, its packages were based on source code that had been modified specifically for RPP, hence the sources weren't pristine. This is a bad idea for a number of fairly technical reasons. Not using pristine sources made it difficult for package developers to keep things straight, particularly if they were building hundreds of different packages.

  • It couldn't guarantee executables were built from packaged sources. The process of building a package for RPP was such that there was no way to ensure the executable programs were built from the source code contained in an RPP source package. Once again, this was a problem for the package builder, especially those who had large numbers of packages to build.

  • It had no support for multiple architectures. As people started using RPP, it became obvious that the package managers that were unable to simplify the process of building packages for more than one architecture, or type of computer, were going to be at a disadvantage. This was a problem, particularly for Red Hat, as they were starting to look at the possibility of creating Linux distributions for other architectures, such as the Digital Alpha.

Even with these problems, RPP was one of the things that made the first Red Hat Linux distributions unique. Its ability to simplify the process of installing software was a real boon to many of Red Hat's customers, particularly those with little experience in Linux.

PMS

While Red Hat was busy with RPP, another group of Linux devotees were hard at work with their package management system. Known as PMS, its development, lead by Rik Faith, attacked the problem of package management from a slightly different viewpoint.

Like RPP, PMS was used to package a Linux distribution. This distribution was known as the BOGUS distribution, and all the software in it was built from original unmodified sources. Any changes that were required were patched in during the processing of building the software. This is the concept of "pristine sources" and is PMS's most important contribution to RPM. The importance of pristine sources can not be overstated. It allows the packager to quickly release new version of software, and to immediately see what changes were made to the software.

The chief disadvantages of PMS were weak querying ability, no package verification, no multiple architecture support, and poor database design.

PM

Later, Rik Faith and Doug Hoffman, working under contract for Red Hat, produced PM. The design combined all the important features of RPP and PM, including one command installation and uninstallation, scripts run before and after installation and uninstallation, package verification, advanced querying, and pristine sources. However it retained RPP's and PM's chief disadvantages: weak database design and no support for multiple architectures.

PM was very close to a viable package management system, but it wasn't quite ready for prime time. It was never used in a commercially available product.

RPM Version 1

With two major forays into package management behind them, Marc Ewing and Erik Troan went to work on a third attempt. This one would be called the Red Hat Package Manager, or RPM.

Although it built on the experiences of PM, PMS, and RPP, RPM was quite different under the hood. Written in the Perl programming language for fast development, the creation of RPM version 1 focused on addressing the flaws of its ancestors. In some cases, the flaws were eliminated, while in others, the problems remained.

Some of the successes of RPM version 1 were:

  • Automatic handling of configuration files. The contents of config files are often changed from what they were in the original package, making it hard for a package manager to know how a particular config file should be handled during installs, upgrades, and erasures. PM made an attempt at config file handling, but in RPM it was improved further. In many respects, this feature is the key to RPM's power and flexibility.

  • Ease of rebuilding large numbers of packages. By making it easy for people who were trying to create a Linux distribution consisting of several hundred packages, RPM was a step in the right direction.

  • It was easy to use. Many of the concepts used in RPP had withstood the test of time and were used in RPM. For instance, the ability to verify the installation of a package was one of the features that set RPP apart. It was adapted and expanded in RPM version 1.

But RPM version 1 wasn't perfect. There were a number of flaws, some of them major:

  • It was slow. While the use of Perl made RPM's development proceed more quickly, it also meant that RPM wouldn't run as quickly as it would have, had it been written in C.

  • Its database design was fragile. Unfortunately, under RPM version 1 it was not unusual for there to be problems with the database. While the approach of dedicating a database to package management was a good idea, the implementation used in RPM version 1 left a lot to be desired.

  • It was big. This is another artifact of using Perl. Normally, RPM's size requirements were not an issue, except for one area. When performing an initial system install, RPM was run from a small, floppy-based system environment. The need to have Perl available meant space on the boot floppies was always a problem.

  • It didn't support multiple architectures (types of computers) well. The need to have a package manager support more than one type of computer hadn't been acknowledged before. With RPM version 1, an initial stab was taken at the problem, but the implementation was incomplete. Nonetheless, RPM had been ported to a number of other computer systems. It was becoming obvious that the issue of multi-architecture support was not going away and had to be addressed.

  • The package file format wasn't extensible. This made it very difficult to add functionality, since any change to the file format would cause older versions of RPM to break.

Even though their Linux distribution was a success, and RPM was much of the reason for it, Marc and Erik knew that some changes were going to be necessary to carry RPM to the next level.

The RPM of Today: Version 2

Looking back on their experiences with RPM version 1, Marc and Erik made a major change to RPM's design: They rewrote it entirely in C. This did wonderful things to RPM's speed and size. Querying the database was quicker now, and there was no need to have Perl around just to do package management.

In addition, the database format was redesigned to improve both performance and reliability. Displaying package information can take as little as a tenth of the time spent in RPM version 1, for example.

Realizing RPM's potential in the non-Linux arena, they also created rpmlib, a library of RPM routines that allow the use of RPM functionality in other programs. RPM's ability to function on more than one architecture was also enhanced. Finally, the package file format was made more extensible, clearing the way for future enhancements to RPM.

So is RPM perfect? No program can ever reach perfection, and RPM is no exception. But as a package manager that can run on several different types of systems, RPM has a lot to offer, and it will only get better. Let's take a look at the design criteria that drove the development of RPM.

RPM Design Goals

The design goals of RPM could best be summed up with the phrase "something for everyone". While the main reason for the existence of RPM was to make it easier for Red Hat to build the several hundred packages that comprised their Linux distribution, it was not the only reason RPM was created. Let's take a look at the various requirements the Red Hat team used in their design of RPM:

Make it easy to get packages on and off the system

As we've seen earlier in this chapter, the act of installing a package can involve many complex steps. Entrusting these steps to a person who may not have the necessary experience is a strategy for failure. So the goal for RPM was to make it as easy as possible for anyone to install packages. The same holds true for removing packages. It is a complex and error-prone operation, and one that RPM should handle for the user.

The other side of this issue is that RPM should give the package builder almost total control in terms of how the package is installed. The reason for this is simple: if the package builders do their homework, their package should install and uninstall properly.

Make it easy to verify a package was installed correctly

Because software problems are a fact of life, the ability to verify the proper installation of a package is vital. If done properly, it should be possible to catch a variety of problems, including things such as missing or modified files.

Make it easy for the package builder

While we're dedicating an entire book to package management, in reality it should be a small portion of the package builder's job. Why? They've got better things to do! If they are the people that are actually creating the software to be packaged, that's where they should be spending the majority of their time.

Even if the package builder isn't actually writing software, they still have better things to do than worry about building packages. For instance, they may be responsible for building many packages. The less time spent on building an individual package translates to more packages that can be built.

Make it start with the original source code

Delving a bit more into the package builder's world, it was deemed important that RPM start with the original, unmodified source code. Why is this so important?

Using the original sources makes it possible to separate the changes required to build the package from any changes implemented to fix bugs, add new features, or anything else. This is a good thing for package builders, since many of them are not the original authors of the programs they package.

This separation makes it easy, months down the road, to know exactly what changes were made in order to get the package to build. This is important when a new version of the packaged software becomes available. Many times it's only necessary to apply the original "package building" changes to the newer software. At worst, the changes provide a starting point to determine what sorts of things might need to be changed in the new version.

Make it work on different computer architectures

One of the tougher things for a package builder to do is to take a program, make it run on more than one type of computer, and distribute packages for each. Because RPM makes it easy to take a program's original source code, add the changes necessary to get it to build, and produce a package for each architecture in one step, it can be pretty handy.

What's in a package?

With all the magical things we've claimed that package management software in general (and RPM in particular) can do, you'd think there was a tiny computer guru bundled in every package. However, the reality is not that magical. Here's a quick overview of the more important parts of an RPM package [1] .

RPM's Package Labels

Every package built for RPM has to have a specific set of information that uniquely identifies it. We call this information a package label. Here are two sample package labels:

  • nls-1.0-1

  • perl-5.001m-4

While these labels look like they have very little in common, in fact they all follow RPM's package labeling convention. There are three different components in every package label. Let's look at each one in order:

Component #1: The Software's Name

Every package label begins with the name of the software. The name may be derived from the name of the application packaged, or it may be a name describing a group of related programs bundled together by the package builder. The software names in the packages listed above are: nls and perl. As you can see, the software name is separated from the rest of the package label by a dash.

Component #2: The Software's Version

Next in the package label is an identifier that describes the version of the software being packaged. If the package builder bundled a number of related programs together, the software version is probably a number of their own choosing. However, if the package consists of one major application, the software version normally comes directly from the application's developer. The actual version specification is quite flexible, as can be seen in the examples above. The versions shown are: 1.0 and 5.001m. A dash separates the software version from the remainder of the package label.

Component #3: The Package's Release

The package release is the most unambiguous part of a package label. It is a number chosen by the package builder. It reflects the number of times the package has been rebuilt using the same version software. Normally, the rebuilds are due to bugs uncovered after the package has been in use for a while. By tradition, the package release starts at 1. The package releases in the example above are: 1 and 4.

Labels And Names: Similar, But Distinct

Package labels are used internally by RPM. For example, if you ask RPM to list every installed package, it will respond with a list of package labels. When a package file is created, part of the filename consists of the package label. There is no technical requirement for this, but it does make it easier to keep track of things.

However, a package file may be renamed, and the new filename won't confuse RPM in the least. That's because the package label is contained within the file. For a fairly technical view of the inside of a package file, refer to Appendix A, Format of the RPM File.

Package-wide Information

Some of the information contained in a package is general in nature. This information includes such items as:

  • The date and time the package was built.

  • A description of the package's contents.

  • The total size of all the files installed by the package.

  • Information that allows the package to be grouped with similar packages.

  • A digital "signature" that can be used to verify the authenticity and integrity of the package. [2]

Per-file Information

Each package also contains information about every file contained in the package. The information includes:

  • The name of every file and where it is to be installed.

  • Each file's permissions.

  • Each file's owner and group specifications.

  • The MD5 checksum of each file. [3]

  • The file's contents.

Let's Get Started

To summarize, a package management system uses the computer to keep track of all the various bits and pieces that comprise an application or an entire operating system. Most package management systems use a specially formatted file to keep everything together in a single, easily manageable entity, or package. Additionally, package management systems tend to provide one or more of the following functions:

  • Installing new packages.

  • Removing old packages.

  • Upgrading from an old package to a new one.

  • Obtaining information about installed packages.

RPM has been designed with Red Hat's past package management experiences in mind. PM and RPP provided most of these functions with varying degrees of success. Marc Ewing and Erik Troan have worked hard to make RPM better than its predecessors in every way. Now it's time to see how they did, and learn how to use RPM!



[1] See Appendix A, Format of the RPM File for complete details on the contents of a .rpm file.

[2] For more information on RPM's signature checking capability, refer to the section called “rpm -K — What Does it Do?”.

[3] We'll discuss MD5 checksums in greater detail in the section called “MD5 Checksum”.

Chapter 2. Using RPM to Install Packages

Table 2.1. rpm -i Command Syntax

rpm -i (or --install) options file1.rpmfileN.rpm
Parameters
file1.rpmfileN.rpm One or more RPM package files (URLs OK)
Install-specific Options Page
-h (or --hash) Print hash marks ("#") during install the section called “-h: Perfect for the Impatient”
--test Perform installation tests only the section called “--test: Perform Installation Tests Only”
--percent Print percentages during install the section called “--percent: Not Meant for Human Consumption”
--excludedocs Do not install documentation the section called “ --excludedocs: Do Not Install Documentation For This Package ”
--includedocs Install documentation the section called “--includedocs: Install Documentation For This Package”
--replacepkgs Replace a package with a new copy of itself the section called “--replacepkgs: Install the Package Even If Already Installed”
--replacefiles Replace files owned by another package the section called “--replacefiles: Install the Package Even If It Replaces Another Package's Files”
--force Ignore package and file conflicts the section called “--force: The Big Hammer”
--noscripts Do not execute pre- and post-install scripts the section called “--noscripts: Do Not Execute Pre- and Post-install Scripts”
--prefix <path> Relocate package to <path> if possible the section called “ --prefix <path>: Relocate the package to <path>, if possible ”
--ignorearch Do not verify package architecture the section called “ --ignorearch: Do Not Verify Package Architecture ”
--ignoreos Do not verify package operating system the section called “ --ignoreos: Do Not Verify Package Operating System ”
--nodeps Do not check dependencies the section called “ --nodeps: Do Not Check Dependencies Before Installing Package ”
--ftpproxy <host> Use <host> as the FTP proxy the section called “ --ftpproxy <host>: Use <host> As Proxy In FTP-based Installs ”
--ftpport <port> Use <port> as the FTP port the section called “ --ftpport <port>: Use <port> In FTP-based Installs ”
General Options Page
-v Display additional information the section called “Getting a bit more feedback with -v
-vv Display debugging information the section called “Getting a lot more information with -vv
--root <path> Set alternate root to <path> the section called “ --root <path>: Use <path> As An Alternate Root ”
--rcfile <rcfile> Set alternate rpmrc file to <rcfile> the section called “ --rcfile <rcfile>: Use <rcfile> As An Alternate rpmrc File ”
--dbpath <path> Use <path> to find the RPM database the section called “ --dbpath <path>: Use <path> To Find RPM Database ”

rpm -i — What does it do?

Of the many things RPM can do, probably the one that people think of first is the installation of software. As mentioned earlier, installing new software is a complex, error-prone job. RPM turns that process into a single command.

rpm -i (--install is equivalent) installs software that's been packaged into an RPM package file. It does this by:

  • Performing dependency checks.

  • Checking for conflicts.

  • Performing any tasks required before the install.

  • Deciding what to do with config files.

  • Unpacking files from the package and putting them in the proper place.

  • Performing any tasks required after the install.

  • Keeping track of what it did.

Let's go through each of these steps in a bit more detail.

Performing dependency checks:

Some packages will not operate properly unless some other package is installed, too. RPM makes sure that the package being installed will have its dependency requirements met. It will also insure that the package's installation will not cause dependency problems for other already-installed packages.

Checking for conflicts:

RPM performs a number of checks during this phase. These checks look for things like attempts to install an already installed package, attempts to install an older package over a newer version, or the possibility that a file may be overwritten.

Performing any tasks required before the install:

There are cases where one or more commands must be given prior to the actual installation of a package. RPM performs these commands exactly as directed by the package builder, thus eliminating a common source of problems during installations.

Deciding what to do with config files:

One of the features that really sets RPM apart from other package managers, is the way it handles configuration files. Since these files are normally changed to customize the behavior of installed software, simply overwriting a config file would tend to make people angry — all their customizations would be gone! Instead, RPM analyzes the situation and attempts to do "the right thing" with config files, even if they weren't originally installed by RPM! [4]

Unpacking files from the package and putting them in the proper place:

This is the step most people think of when they think about installing software. Each package file contains a list of files that are to be installed, as well as their destination on your system. In addition, many other file attributes, such as permissions and ownerships, are set correctly by RPM.

Performing any tasks required after the install:

Very often a new package requires that one or more commands be executed after the new files are in place. An example of this would be running ldconfig to make new shared libraries accessible.

Keeping track of what it did:

Every time RPM installs a package on your system, it keeps track of the files it installed, in its database. The database contains a wealth of information necessary for RPM to do its job. For example, RPM uses the database when it checks for possible conflicts during an install.

Performing an Install

Let's have RPM install a package. The only thing necessary is to give the command (rpm -i) followed by the name of the package file:

# rpm -i eject-1.2-2.i386.rpm
#
        

At this point, all the steps outlined above have been performed. The package is now installed. Note that the file name need not adhere to RPM's file naming convention:

# mv eject-1.2-2.i386.rpm baz.txt
# rpm -i baz.txt
#
        

In this case, we changed the name of the package file eject-1.2-2.i386.rpm to baz.txt and then proceeded to install the package. The result is identical to the previous install, that is, the eject-1.2-2 package successfully installed. The name of the package file, although normally incorporating the package label, is not used by RPM during the installation process. RPM uses the contents of the package file, which means that even if the file was placed on a DOS floppy and the name truncated, the installation would still proceed normally.

URLs — Another Way to Specify Package Files

If you've surfed the World Wide Web, you've no doubt noticed the way web pages are identified:

http://www.redhat.com/support/docs/rpm/RPM-HOWTO/RPM-HOWTO.html
          

This is called a Uniform Resource Locator, or URL. RPM can also use URLs, although they look a little bit different. Here's one:

ftp://ftp.redhat.com/pub/redhat/code/rpm/rpm-2.3-1.i386.rpm
          

The ftp: signifies that this URL is a File Transfer Protocol URL. As the name implies, this type of URL is used to move files around. The section containing ftp.redhat.com specifies the hostname, or the name of the system where the package file resides.

The remainder of the URL (/pub/redhat/code/rpm/rpm-2.3-1.i386.rpm) specifies the path to the package file, followed by the package file itself.

RPM's use of URLs gives us the ability to install a package located on the other side of the world, with a single command:

# rpm -i ftp://ftp.gnomovision.com/pub/rpms/foobar-1.0-1.i386.rpm
#
          

This command would use anonymous FTP to obtain the foobar version 1.0 package file and install it on your system. Of course, anonymous FTP (no username and password required) is not always available. Therefore, the URL may also contain a username and password preceding the hostname:

ftp://smith:mypass@ftp.gnomovision.com/pub/rpms/foobar-1.0-1.i386.rpm
          

However, entering a password where it can be seen by anyone looking at your screen is a bad idea. So try this format:

ftp://smith@ftp.gnomovision.com/pub/rpms/foobar-1.0-1.i386.rpm
          

RPM will prompt you for your password, and you'll be in business:

# rpm -i ftp://smith@ftp.gnomovision.com/pub/rpms/apmd-2.4-1.i386.rpm
Password for smith@ftp.gnomovision.com: mypass (not echoed)
#
          

After entering a valid password, RPM installs the package.

On some systems, the FTP daemon doesn't run on the standard port 21. Normally this is done for the sake of enhanced security. Fortunately, there is a way to specify a non-standard port in a URL:

ftp://ftp.gnomovision.com:1024/pub/rpms/foobar-1.0-1.i386.rpm
          

This URL will direct the FTP request to port 1024. The --ftpport option is another way to specify the port. This option is discussed later, in the section called “ --ftpport <port>: Use <port> In FTP-based Installs ”.

A warning message you might never see

Depending on circumstances, the following message might be rare or very common. While performing an ordinary install, RPM prints a warning message:

# rpm -i cdp-0.33-100.i386.rpm
warning: /etc/cdp-config saved as /etc/cdp-config.rpmorig
#
          

What does it mean? It has to do with RPM's handling of config files. In the example above, RPM found a file (/etc/cdp-config) that didn't belong to any RPM-installed package. Since the cdp-0.33-100 package contains a file of the same name that is to be installed in the same directory, there is a problem.

RPM solves this the best way it can. It performs two steps:

  1. It renames the original file to cdp-config.rpmorig.

  2. It installs the new cdp-config file that came with the package.

Continuing our example, if we look in /etc, we see that this is exactly what has happened:

# ls -al /etc/cdp*

-rw-r--r--   1 root     root      119 Jun 23 16:00 /etc/cdp-config
-rw-rw-r--   1 root     root       56 Jun 14 21:44 /etc/cdp-config.rpmorig

#
          

This is the best possible solution to a tricky problem. The package is installed with a config file that is known to work. After all, the original file may be for an older, incompatible version of the software. However, the original file is saved so that it can be studied by the system administrator, who can decide whether the original file should be put back into service or not.

Two handy options

There are two options to rpm -i that work so well, and are so useful, you might think they should be RPM's default behavior. They aren't, but using them only requires that you type an extra two characters:

Getting a bit more feedback with -v

Even though rpm -i is doing many things, it's not very exciting, is it? When performing installs, RPM is pretty quiet, unless something goes wrong. However, we can ask for a bit more output by adding -v to the command:

# rpm -iv eject-1.2-2.i386.rpm
Installing eject-1.2-2.i386.rpm
#
          

By adding -v, RPM displayed a simple status line. Using -v is a good idea, particularly if you're going to use a single command to install more than one package:

# rpm -iv *.rpm

Installing eject-1.2-2.i386.rpm
Installing iBCS-1.2-3.i386.rpm
Installing logrotate-1.0-1.i386.rpm

#
          

In this case, there were three .rpm files in the directory. By using a simple wildcard, it's as easy to install one package as it is to install one hundred!

-h: Perfect for the Impatient

Sometimes a package can be quite large. Other than watching the disk activity light flash, there's no assurance that RPM is working, and if it is, how far along it is. If you add -h, RPM will print fifty hash marks ("#") as the install proceeds:

# rpm -ih eject-1.2-2.i386.rpm
##################################################
#
          

Once all fifty hash marks are printed, the package is completely installed. Using -v with -h results in a very nice display, particularly when installing more than one package:

# rpm -ivh *.rpm

eject          ##################################################
iBCS           ##################################################
logrotate      ##################################################

#
          

Additional options to rpm -i

Normally rpm -i, perhaps with the -v and -h, is all you'll need. However, there may be times when a basic install is not going to get the job done. Fortunately, RPM has a wealth of install options to make the tough times a little easier. As with any other powerful tool, you should understand these options before putting them to use. Let's take a look at them:

Getting a lot more information with -vv

Sometimes it's necessary to have even more information than we can get with -v. By adding another v, we can start to see more of RPM's inner workings:

# rpm -ivv eject-1.2-2.i386.rpm

D: installing eject-1.2-2.i386.rpm
Installing eject-1.2-2.i386.rpm
D: package: eject-1.2-2 files test = 0
D: running preinstall script (if any)
D: setting file owners and groups by name (not id)
D: ///usr/bin/eject owned by root (0), group root (0) mode 755
D: ///usr/man/man1/eject.1 owned by root (0), group root (0) mode 644
D: running postinstall script (if any)

#
          

The lines starting with D: have been added by using -vv. The line ending with "files test = 0", means that RPM is actually going to install the package. If the number were non-zero, it would mean that the --test option was present, and RPM would not actually perform the installation. For more information on using --test with rpm -i, see the section called “--test: Perform Installation Tests Only”.

Continuing with the above example, we see that RPM next executes a pre-install script (if there is one), followed by the actual installation of the files in the package. There is one line for each file being installed, and that line shows the filename, ownership, group membership, and permissions (or mode) applied to the file. With larger packages, the output from -vv can get quite lengthy! Finally, RPM runs a post-install script, if one exists for the package. We'll be discussing pre- and post-install scripts in more detail in the section called “--noscripts: Do Not Execute Pre- and Post-install Scripts”.

In the vast majority of cases, it will not be necessary to use -vv. It is normally used by software engineers working on RPM itself, and the output can change without notice. However, it's a handy way to gain insights into RPM's inner workings.

--test: Perform Installation Tests Only

There are times when it's more appropriate to take it slow and not try to install a package right away. RPM provides the --test option for that. As the names implies, it performs all the checks that RPM normally does during an install, but stops short of actually performing the steps necessary to install the package:

# rpm -i --test eject-1.2-2.i386.rpm
#
          

Once again, there's not very much output. This is because the test succeeded; had there been a problem, the output would have been a bit more interesting. In this example, there are some problems:

# rpm -i --test rpm-2.0.11-1.i386.rpm

/bin/rpm conflicts with file from rpm-2.3-1
/usr/bin/gendiff conflicts with file from rpm-2.3-1
/usr/bin/rpm2cpio conflicts with file from rpm-2.3-1
/usr/bin/rpmconvert conflicts with file from rpm-2.3-1
/usr/man/man8/rpm.8 conflicts with file from rpm-2.3-1
error: rpm-2.0.11-1.i386.rpm cannot be installed

#
          

If you'll note the version numbers, we're trying to install an older version of RPM (2.0.11) "on top of" a newer version(2.3). RPM faithfully reported the various file conflicts and summarized with a message saying that the install would not have proceeded, even if --test had not been on the command line.

The --test option will also catch dependency-related problems:

# rpm -i --test blather-7.9-1.i386.rpm

failed dependencies:
        bother >= 3.1 is needed by blather-7.9-1

#
          

Here's a tip for all you script-writers out there: RPM will return a non-zero status if the --test option detects problems…

--replacepkgs: Install the Package Even If Already Installed

The --replacepkgs option is used to force RPM to install a package that it believes to be installed already. This option is normally used if the installed package has been damaged somehow and needs to be fixed up.

To see how the --replacepkgs option works, let's first install some software:

# rpm -iv cdp-0.33-2.i386.rpm

Installing cdp-0.33-2.i386.rpm

#
          

OK, now that we have cdp-0.33-2 installed, let's see what happens if we try to install the same version "on top of" itself:

# rpm -iv cdp-0.33-2.i386.rpm

Installing cdp-0.33-2.i386.rpm
package cdp-0.33-2 is already installed
error: cdp-0.33-2.i386.rpm cannot be installed

#
          

That didn't go very well. Let's see what adding --replacepkgs will do :

# rpm -iv --replacepkgs cdp-0.33-2.i386.rpm

Installing cdp-0.33-2.i386.rpm

#
          

Much better. The original package was replaced by a new copy of itself.

--replacefiles: Install the Package Even If It Replaces Another Package's Files

While the --replacepkgs option permitted a package to be installed "on top of" itself, --replacefiles is used to allow a package to overwrite files belonging to a different package. Sounds strange? Let's go over it in a bit more detail.

One thing that sets RPM apart from many other package managers is that it keeps track of all the files it installs in a database. Each file's database entry contains a variety of information about the file, including a means of summarizing the file's contents. [5] By using these summaries, known as MD5 checksums, RPM can determine if a particular file is going to be replaced by a file with the same name, but different contents. Here's an example:

Package "A" installs a file (we'll call it /bin/foo.bar). Once Package A is installed, foo.bar resides happily in the /bin directory. In the RPM database, there is an entry for /bin/foo.bar, including the file's MD5 checksum.

However, there is a another package, "B". Package B also has a file called foo.bar that it wants to install in /bin. There can't be two files in the same directory with the same name. The files are different; their MD5 checksums do not match. What happens if Package B is installed? Let's find out. Here, we've installed a package:

# rpm -iv cdp-0.33-2.i386.rpm

Installing cdp-0.33-2.i386.rpm

#
          

OK, no problem there. But we have another package to install. In this case, it is a new release of the cdp package. It should be noted that RPM's detection of file conflicts does not depend on the two packages being related. It is strictly based on the name of the file, the directory in which it resides, and the file's MD5 checksum. Here's what happens when we try to install the package:

# rpm -iv cdp-0.33-3.i386.rpm

Installing cdp-0.33-3.i386.rpm
/usr/bin/cdp conflicts with file from cdp-0.33-2
error: cdp-0.33-3.i386.rpm cannot be installed

#
          

What's happening? The package cdp-0.33-2 has a file, /usr/bin/cdp, that it installed. Sure enough, there it is. Let's highlight the size and creation date of the file for future reference:

# ls -al /usr/bin/cdp

-rwxr-xr-x   1 root     root        34460 Feb 25 14:27 /usr/bin/cdp

#
          

The package we just tried to install, cdp-0.33-3 (note the different release), also installs a file cdp in /usr/bin. Since there is a conflict, that means that the two package's cdp files must be different — their checksums don't match. Because of this, RPM won't let the second package install. But with --replacefiles, we can force RPM to let the /usr/bin/cdp from cdp-0.33-3 replace the /usr/bin/cdp from cdp-0.33-2:

# rpm -iv --replacefiles cdp-0.33-3.i386.rpm

Installing cdp-0.33-3.i386.rpm

#
          

Taking a closer look at /usr/bin/cdp, we find that they certainly are different, both in size and creation date:

# ls -al /usr/bin/cdp

-rwxr-xr-x   1 root     root        34444 Apr 24 22:37 /usr/bin/cdp

#
          

File conflicts should be a relatively rare occurrence. They only happen when two packages attempt to install files with the same name but different contents. There are two possible reasons for this to happen:

  • Installing a newer version of a package without erasing the older version. A newer version of a package is a wonderful source of file conflicts against older versions — the filenames remain the same, but the contents change. We used it in our example because it's an easy way to show what happens when there are file conflicts. However, it is usually a bad idea when it comes to doing this as a way to upgrade packages. RPM has a special option for this (rpm -U) that is discussed in Chapter 4, Using RPM to Upgrade Packages.

  • Installing two unrelated packages that each install a file with the same name. This may happen because of poor package design (hence the file residing in more than one package), or a lack of coordination between the people building the packages.

--replacefiles and Config Files

What happens if a conflicting file is a config file that you've sweated over and worked on until it's just right? Will issuing a --replacefiles on a package with a conflicting config file blow all your changes away?

No! RPM won't cook your goose. [6]

It will save any changes you've made, to a config file called <file>.rpmsave. Let's give it a try:

As system administrator, you want to make sure your new users have a rich environment the first time they log in. So you've come up with a really nifty .bashrc file that will be executed whenever they log in. Knowing that everyone will enjoy your wonderful .bashrc file, you place it in /etc/skel. That way, every time a new account is created, your .bashrc will be copied into the new user's login directory.

Not realizing that the .bashrc file you modified in /etc/skel is listed as a config file in a package called (strangely enough) etcskel, you decide to experiment with RPM using the etcskel package. First you try to install it:

# rpm -iv etcskel-1.0-100.i386.rpm

etcskel       /etc/skel/.bashrc conflicts with file from etcskel-1.0-3
error: etcskel-1.0-100.i386.rpm cannot be installed

#
            

Hmmm. That didn't work. Wait a minute! I can add --replacefiles to the command and it should install just fine:

# rpm -iv --replacefiles etcskel-1.0-100.i386.rpm

Installing etcskel-1.0-100.i386.rpm
warning: /etc/skel/.bashrc saved as /etc/skel/.bashrc.rpmsave

#
            

Wait a minute… That's my customized .bashrc! Was it really saved?

# ls -al /etc/skel/

total 8
-rwxr-xr-x   1 root     root          186 Oct 12  1994 .Xclients
-rw-r--r--   1 root     root         1126 Aug 23  1995 .Xdefaults
-rw-r--r--   1 root     root           24 Jul 13  1994 .bash_logout
-rw-r--r--   1 root     root          220 Aug 23  1995 .bash_profile
-rw-r--r--   1 root     root          169 Jun 17 20:02 .bashrc
-rw-r--r--   1 root     root          159 Jun 17 20:46 .bashrc.rpmsave
drwxr-xr-x   2 root     root         1024 May 13 13:18 .xfm
lrwxrwxrwx   1 root     root            9 Jun 17 20:46 .xsession -> .Xclients

# cat /etc/skel/.bashrc.rpmsave

# .bashrc
# User specific aliases and functions
# Modified by the sysadmin
uptime
# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

#
            

Whew! You heave a sigh of relief, and study the new .bashrc to see if the changes need to be integrated into your customized version.

--replacefiles Can Mean Trouble Down the Road

While --replacefiles can make today's difficult install go away, it can mean big headaches in the future. When the time comes for erasing the packages involved in a file conflict, bad things can happen.

What bad things? Well, files can be deleted. Here's how, in three easy steps:

  1. Two packages are installed. When the second package is installed, there is a conflict with a file installed by the first package. Therefore, the --replacefiles option is used to force RPM to replace the conflicting file with the one from the second package.

  2. At some point in the future, the second package is erased.

  3. The conflicting file is gone!

Let's look at an example. First, we install a new package. Next, we take a look at a file it installed, noting the size and creation date.

# rpm -iv cdp-0.33-2.i386.rpm

Installing cdp-0.33-2.i386.rpm

# ls -al /usr/bin/cdp

-rwxr-xr-x   1 root     root        34460 Feb 25 14:27 /usr/bin/cdp

#
            

Next, we try to install a newer release of the same package. It fails:

# rpm -iv cdp-0.33-3.i386.rpm

Installing cdp-0.33-3.i386.rpm
/usr/bin/cdp conflicts with file from cdp-0.33-2
error: cdp-0.33-3.i386.rpm cannot be installed

#
            

So, we use --replacefiles to convince the newer package to install. We note that the newer package installed a file on top of the file originally installed:

# rpm -iv --replacefiles cdp-0.33-3.i386.rpm

Installing cdp-0.33-3.i386.rpm

# ls -al /usr/bin/cdp

-rwxr-xr-x   1 root     root        34444 Apr 24 22:37 /usr/bin/cdp

#
            

The original cdp file, 34,460 bytes long, and dated February 25th, has been replaced with a file with the same name, but 34,444 bytes long from the 24th of April. The original file is long gone.

Next, we erased the package we just installed. [7] Finally, we tried to find the file:

# rpm -e cdp-0.33-3
# ls -al /usr/bin/cdp

ls: /usr/bin/cdp: No such file or directory

#
            

The file is gone. Why is this? The reason is that /usr/bin/cdp from the first package was replaced when the second package was installed using the --replacefiles option. Then, when the second package was erased, the /usr/bin/cdp file was removed, since it belonged to the second package. If the first package had been erased first, there would have been no problem, since RPM would have realized that the first package's file had already been deleted, and would have left the file in place.

The only problem with this state of affairs is that the first package is still installed, except for /usr/bin/cdp. So now there's a partially installed package on the system. What to do? Perhaps it's time to exercise your new-found knowledge by issuing an rpm -i --replacepkgs command to fix up the first package…

--nodeps: Do Not Check Dependencies Before Installing Package

One day it'll happen. You'll be installing a new package, when suddenly, the install bombs:

# rpm -i blather-7.9-1.i386.rpm

failed dependencies:
        bother >= 3.1 is needed by blather-7.9-1

#
          

What happened? The problem is that the package you're installing requires another package to be installed in order for it to work properly. In our example, the blather package won't work properly unless the bother package (and more specifically, bother version 3.1 or later) is installed. Since our system doesn't have an appropriate version of bother installed at all, RPM aborted the installation of blather.

Now, 99 times out of 100, this exactly the right thing for RPM to do. After all, if the package doesn't have everything it needs to work properly, why try to install it? Well, as with everything else in life, there are exceptions to the rule. And that is why there is a --nodeps option.

Adding the --nodeps options to an install command directs RPM to ignore any dependency-related problems and to complete the package installation. Going back to our example above, let's add the --nodeps option to the command line and see what happens:

# rpm -i --nodeps blather-7.9-1.i386.rpm
#
          

The package was installed without a peep. Whether it will work properly is another matter, but it is installed. In general, it's not a good idea to use --nodeps to get around dependency problems. The package builders included the dependency requirements for a reason, and it's best not to second-guess them.

--force: The Big Hammer

Adding --force to an install command is a way of saying "Install it anyway!" In essence, it adds --replacepkgs and --replacefiles to the command. Like a big hammer, --force is an irresistible force [8] that makes things happen. In fact, the only thing that will prevent a --force'ed install from proceeding is a dependency conflict.

And like a big hammer, it pays to fully understand why you need to use --force before actually using it.

--excludedocs: Do Not Install Documentation For This Package

RPM has a number of good features. One of them is the fact that RPM classifies the files it installs into one of three categories:

  1. Config files.

  2. Files containing documentation.

  3. All other files.

RPM uses the --excludedocs option to prevent files classified as documentation from being installed. In the following example, we know that the package contains documentation: specifically, the man page, /usr/man/man1/cdp.1. Let's see how --excludedocs keeps it from being installed:

# rpm -iv --excludedocs cdp-0.33-3.i386.rpm

Installing cdp-0.33-3.i386.rpm

# ls -al /usr/man/man1/cdp.1

ls: /usr/man/man1/cdp.1: No such file or directory

#
          

The primary reason to use --excludedocs is to save on disk space. The savings can be sizeable. For example, on an RPM-installed Linux system, there can be over 5,000 documentation files, using nearly 50 megabytes.

If you like, you can make --excludedocs the default for all installs. To do this, simply add the following line to /etc/rpmrc, .rpmrc in your login directory, or the file specified with the --rcfile (which is discussed in the section called “ --rcfile <rcfile>: Use <rcfile> As An Alternate rpmrc File ”) option:

excludedocs: 1

After that, every time an rpm -i command is run, it will not install any documentation files. [9]

--includedocs: Install Documentation For This Package

As the name implies, --includedocs directs RPM to install any files marked as being documentation. This option is normally not required, unless the rpmrc file entry "excludedocs: 1" is included in the referenced rpmrc file. Here's an example. Note that in this example, /etc/rpmrc contains "excludedocs: 1", which directs RPM not to install documentation files:

# ls /usr/man/man1/cdp.1

ls: /usr/man/man1/cdp.1: No such file or directory

# rpm -iv cdp-0.33-3.i386.rpm

Installing cdp-0.33-3.i386.rpm

# ls /usr/man/man1/cdp.1

ls: /usr/man/man1/cdp.1: No such file or directory

#
          

Here we've checked to make sure that the cdp man page did not previously exist on the system. Then after installing the cdp package, we find that the "excludedocs: 1" in /etc/rpmrc did its job: the man page wasn't installed. Let's try it again, this time adding the --includedocs option:

# ls /usr/man/man1/cdp.1

ls: /usr/man/man1/cdp.1: No such file or directory

# rpm -iv --includedocs cdp-0.33-3.i386.rpm

Installing cdp-0.33-3.i386.rpm

# ls /usr/man/man1/cdp.1

-rw-r--r--   1 root     root         4550 Apr 24 22:37 /usr/man/man1/cdp.1

#
          

The --includedocs option overrode the rpmrc file's "excludedocs: 1" entry, causing RPM to install the documentation file.

--prefix <path>: Relocate the package to <path>, if possible

Some packages give the person installing them flexibility in determining where on their system they should be installed. These are known as relocatable packages. A relocatable package differs from a package that cannot be relocated, in only one way — the definition of a default prefix. Because of this, it takes a bit of additional effort to determine if a package is relocatable. But here's an RPM command that can be used to find out: [10]

rpm -qp --queryformat "%{defaultprefix}\n" <packagefile>
          

Just replace <packagefile> with the name of the package file you want to check out. If the package is not relocatable, you'll only see the word (none). If, on the other hand, the command displays a path, that means the package is relocatable. Unless specified otherwise, every file in the package will be installed somewhere below the path specified by the default prefix.

What if you want to specify otherwise? Easy: just use the --prefix option. Let's give it a try:

# rpm -qp --queryformat "%{defaultprefix}\n" cdplayer-1.0-1.i386.rpm

/usr/local

# rpm -i --prefix /tmp/test cdplayer-1.0-1.i386.rpm
#
          

Here we've used our magic query command to determine that the cdplayer package is relocatable. It normally installs below /usr/local, but we wanted to move it around. By adding the --prefix option, we were able to make the package install in /tmp/test. If we take a look there, we'll see that RPM created all the necessary directories to hold the package's files:

# ls -lR /tmp/test/

total 2
drwxr-xr-x   2 root     root         1024 Dec 16 13:21 bin/
drwxr-xr-x   3 root     root         1024 Dec 16 13:21 man/

/tmp/test/bin:
total 41
-rwxr-xr-x   1 root     root        40739 Oct 14 20:25 cdp*
lrwxrwxrwx   1 root     root           17 Dec 16 13:21 cdplay -> /tmp/test/bin/cdp*

/tmp/test/man:
total 1
drwxr-xr-x   2 root     root         1024 Dec 16 13:21 man1/

/tmp/test/man/man1:
total 5
-rwxr-xr-x   1 root     root         4550 Oct 14 20:25 cdp.1*

#
          

--noscripts: Do Not Execute Pre- and Post-install Scripts

Before we talk about the --noscripts option, we need to cover a bit of background. In the section called “Getting a lot more information with -vv, we saw some output from an install using the -vv option. As can be seen, there are two lines that mention pre-install and post-install scripts. When some packages are installed, they may require that certain programs be executed before, after, or before and after the package's files are copied to disk. [11]

The --noscripts option prevents these scripts from being executed during an install. This is a very dangerous thing to do! The --noscripts option is really meant for package builders to use during the development of their packages. By preventing the pre- and post-install scripts from running, a package builder can keep a buggy package from bringing down their development system. Once the bugs are found and eliminated, the --noscripts option is no longer necessary.

--percent: Not Meant for Human Consumption

An option that will probably never be very popular is --percent. This option is meant to be used by programs that interact with the user, perhaps presenting a graphical user interface for RPM. When the --percent option is used, RPM displays a series of numbers. Each number is a percentage that indicates how far along the install is. When the number reaches 100%, the installation is complete.

# rpm -i --percent iBCS-1.2-3.i386.rpm

%f iBCS:1.2:3
%% 0.002140
%% 1.492386
%% 5.296632
%% 9.310026
%% 15.271010
%% 26.217846
%% 31.216000
%% 100.000000
%% 100.000000

#
          

The list of percentages will vary depending on the number of files in the package, but every package ends at 100% when completely installed.

--rcfile <rcfile>: Use <rcfile> As An Alternate rpmrc File

The --rcfile option is used to specify a file containing default settings for RPM. Normally, this option is not needed. By default, RPM uses /etc/rpmrc and a file named .rpmrc located in your login directory.

This option would be used if there was a need to switch between several sets of RPM defaults. Software developers and package builders will normally be the only people using the --rcfile option. For more information on rpmrc files, see Appendix B, The rpmrc File.

--root <path>: Use <path> As An Alternate Root

Adding --root <path> to an install command forces RPM to assume that the directory specified by <path> is actually the "root" directory. The --root option affects every aspect of the install process, so pre- and post-install scripts are run with <path> as their root directory (using chroot(2), if you must know). In addition, RPM expects its database to reside in the directory specified by the dbpath rpmrc file entry, relative to <path>. [12]

Normally this option is only used during an initial system install, or when a system has been booted off a "rescue disk" and some packages need to be re-installed.

--dbpath <path>: Use <path> To Find RPM Database

In order for RPM to do its handiwork, it needs access to an RPM database. Normally, this database exists in the directory specified by the rpmrc file entry, dbpath. By default, dbpath is set to /var/lib/rpm.

Although the dbpath entry can be modified in the appropriate rpmrc file, the --dbpath option is probably a better choice when the database path needs to be changed temporarily. An example of a time the --dbpath option would come in handy is when it's necessary to examine an RPM database copied from another system. Granted, it's not a common occurrence, but it's difficult to handle any other way.

--ftpport <port>: Use <port> In FTP-based Installs

Back in the section called “URLs — Another Way to Specify Package Files” we showed how RPM can access package files by the use of a URL. We also mentioned that some systems may not use the standard FTP port. In those cases, it's necessary to give RPM the proper port number to use. As we mentioned above, one approach is to embed the port number in the URL itself.

Another approach is to use the --ftpport option. RPM will access the desired port when this option, along with the port number, is added to the command line. In cases where the desired port seldom changes, it may be entered in an rpmrc file by using the ftpport entry. [13]

--ftpproxy <host>: Use <host> As Proxy In FTP-based Installs

Many companies and Internet Service Providers (ISPs) employ various methods to protect their network connections against misuse. One of these methods is to use a system that will process all FTP requests on behalf of the other systems on the company or ISP network. By having a single computer act as a proxy for the other systems, it serves to protect the other systems against any FTP-related misuse.

When RPM is employed on a network with an FTP proxy system, it will be necessary for RPM to direct all its FTP requests to the FTP proxy. RPM will send its FTP requests to the specified proxy system when the --ftpproxy option, along with the proxy hostname, is added to the command line.

In cases where the proxy host seldom changes, it may be entered in an rpmrc file by using the ftpproxy entry. [14]

--ignorearch: Do Not Verify Package Architecture

When a package file is created, RPM specifies the architecture, or type of computer hardware, for which the package was created. This is a good thing, as the architecture is one of the main factors in determining whether a package written for one computer is going to be compatible with another computer.

When a package is installed, RPM uses the arch_compat rpmrc entries in order to determine what are normally considered compatible architectures. Unless you're porting RPM to a new architecture, you shouldn't make any changes to these entries. [15] While RPM attempts to make the right decisions regarding package compatibility, there are times when it errs on the side of conservatism. In those cases, it's necessary to override RPM's decision. The --ignorearch option is used in those cases. When added to the command line, RPM will not perform any architecture-related checking.

Unless you really know what you're doing, you should never use --ignorearch!

--ignoreos: Do Not Verify Package Operating System

When a package file is created, RPM specifies the operating system for which the package was created. This is a good thing as the operating system is one of the main factors in determining whether a package written for one computer is going to be compatible with another computer.

When a package is installed, RPM uses the os_compat rpmrc entries to determine what are normally considered compatible operating systems. Unless you're porting RPM to a new operating system, you shouldn't make any changes to these entries. [16] While RPM attempts to make the right decisions regarding package compatibility, there are times when it errs on the side of conservatism. In those cases, it's necessary to override RPM's decision. The --ignoreos option is used in those cases. When added to the command line, RPM will not perform any operating system-related checking.

Unless you really know what you're doing, you should never use --ignoreos!



[4] Are you interested in what exactly "the right thing" means? the section called “Config file magic” has all the details.

[5] We'll get more into this aspect of RPM in the section called “rpm -V — What Does it Do?” when we discuss rpm -V.

[6] You'll have to do that yourself!

[7] For more information on erasing packages with rpm -e, see Chapter 3, Using RPM to Erase Packages.

[8] No pun intended.

[9] For more information on rpmrc files, refer to Appendix B, The rpmrc File.

[10] We discuss RPM's query commands in Chapter 5, Getting Information About Packages.

[11] It's possible to use RPM's query command to see if a package has pre- or post-install scripts. See the section called “ --scripts — Show Scripts Associated With a Package ” for more information.

[12] For more information on rpmrc file entries, see Appendix B, The rpmrc File.

[13] The use of rpmrc files is described in Appendix B, The rpmrc File.

[14] The use of rpmrc files is described in Appendix B, The rpmrc File.

[15] If you are porting RPM, you'll find more on arch_compat in the section called “ xxx_compat — Define Compatible Architectures ”.

[16] If you are porting RPM, you'll find more on os_compat in the section called “ xxx_compat — Define Compatible Architectures ”.

Chapter 3. Using RPM to Erase Packages

Table 3.1. rpm -e Command Syntax

rpm -e (or --erase) options pkg1pkgN
Parameters
pkg1pkgN One or more installed packages
Erase-specific Options Page
--test Perform erase tests only the section called “ --test — Go Through the Process of Erasing the Package, But Do Not Erase It ”
--noscripts Do not execute pre- and post-uninstall scripts the section called “ --noscripts — Do Not Execute Pre- and Post-uninstall Scripts ”
--nodeps Do not check dependencies the section called “ --nodeps: Do Not Check Dependencies Before Erasing Package ”
General Options Page
-vv Display debugging information the section called “Getting More Information With -vv
--root <path> Set alternate root to <path> the section called “ --root <path> — Use <path> As the Root ”
--rcfile <rcfile> Set alternate rpmrc file to <rcfile> the section called “ --rcfile <rcfile> — Read <rcfile> For RPM Defaults ”
--dbpath <path> Use <path> to find the RPM database the section called “ --dbpath <path>: Use <path> To Find RPM Database ”

rpm -e — What Does it Do?

The rpm -e command (--erase is equivalent) removes, or erases, one or more packages from the system. RPM performs a series of steps whenever it erases a package:

  • It checks the RPM database to make sure that no other packages depend on the package being erased.

  • It executes a pre-uninstall script (if one exists).

  • It checks to see if any of the package's config files have been modified. If so, it saves copies of them.

  • It reviews the RPM database to find every file listed as being part of the package, and if they do not belong to another package, deletes them.

  • It executes a post-uninstall script (if one exists).

  • It removes all traces of the package (and the files belonging to it) from the RPM database.

That's quite a bit of activity for a single command. No wonder RPM can be such a time-saver!

Erasing a Package

The most basic erase command is:

# rpm -e eject
#
        

In this case, the eject package was erased. There isn't much in the way of feedback, is there? Could we get more if we add -v?

# rpm -ev eject
#
        

Still nothing. However, there's another option that can be counted on to give a wealth of information. Let's give it a try:

Getting More Information With -vv

By adding -vv to the command line, we can often get a better feel for what's going on inside RPM. The -vv option was really meant for the RPM developers, and its output may change, but it is a great way to gain insight into RPM's inner workings. Let's try it with rpm -e:

# rpm -evv eject

D: uninstalling record number 286040
D: running preuninstall script (if any)
D: removing files test = 0
D: /usr/man/man1/eject.1 - removing
D: /usr/bin/eject - removing
D: running postuninstall script (if any)
D: removing database entry
D: removing name index
D: removing group index
D: removing file index for /usr/bin/eject
D: removing file index for /usr/man/man1/eject.1

#
          

Although -v had no effect on RPM's output, -vv gave us a torrent of output. But what does it tell us?

First, RPM displays the package's record number. The number is normally of use only to people that work on RPM's database code.

Next, RPM executes a "pre-uninstall" script, if one exists. This script can execute any commands required to remove the package before any files are actually deleted.

The "files test = 0" line indicates that RPM is to actually erase the package. If the number had been non-zero, RPM would only be performing a test of the package erasure. This happens when the --test option is used. Refer to the section called “ --test — Go Through the Process of Erasing the Package, But Do Not Erase It ” for more information on the use of the --test option with rpm -e.

The next two lines log the actual removal of the files comprising the package. Packages with many files can result in a lot of output when using -vv!

Next, RPM executes a "post-uninstall" script, if one exists. Like the pre-uninstall script, this script is used to perform any processing required to cleanly erase the package. Unlike the pre-uninstall script, however, the post-uninstall script runs after all the package's files have been removed.

Finally, the last five lines show the process RPM uses to remove every trace of the package from its database. From the messages, we can see that the database contains some per-package data, followed by information on every file installed by the package.

Additional Options

If you're interested in a complex command with lots of options, rpm -e is not the place to look. There just aren't that many different ways to erase a package! But there are a few options you should know about.

--test — Go Through the Process of Erasing the Package, But Do Not Erase It

If you're a bit gun-shy about erasing a package, you can use the --test option first to see what rpm -e would do:

# rpm -e --test bother

removing these packages would break dependencies:
        bother >= 3.1 is needed by blather-7.9-1

#
          

It's pretty easy to see that the blather package wouldn't work very well if bother were erased. To be fair, however, RPM wouldn't have erased the package in this example unless we used the --nodeps option, which we'll discuss shortly.

However, if there are no problems erasing the package, you won't see very much:

# rpm -e --test eject
#
          

We know, based on previous experience, that -v doesn't give us any additional output with rpm -e. However, we do know that -vv works wonders. Let's see what it has to say:

# rpm -evv --test eject

D: uninstalling record number 286040
D: running preuninstall script (if any)
D: would remove files test = 1
D: /usr/man/man1/eject.1 - would remove
D: /usr/bin/eject - would remove
D: running postuninstall script (if any)
D: would remove database entry

#
          

As you can see, the output is similar to that of a regular erase command using the -vv option, with the following exceptions:

  • The "would remove files test = 1" line ends with a non-zero number. This is because --test has been added. If the command hadn't included --test, the number would have been 0, and the package would have been erased.

  • There is a line for each file that RPM would have removed, each one ending with "would remove" instead of "removing".

  • There is only one line at the end, stating: "would remove database entry", versus the multi-line output showing the cleanup of the RPM database during an actual erase.

By using --test in conjunction with -vv, it's easy to see exactly what RPM would do during an actual erase.

--nodeps: Do Not Check Dependencies Before Erasing Package

It's likely that one day while erasing a package, you'll see something like this:

# rpm -e bother

removing these packages would break dependencies:
        bother >= 3.1 is needed by blather-7.9-1

#
          

What happened? The problem is that one or more of the packages installed on your system require the package you're trying to erase. Without it, they won't work properly. In our example, the blather package won't work properly unless the bother package (and more specifically, bother version 3.1 or later) is installed. Since we're trying to erase bother, RPM aborted the erasure.

Now, 99 times out of 100, this is exactly the right thing for RPM to do. After all, if the package is needed by other packages, why try to erase it? As with everything else in life, there are exceptions to the rule. And that is why there is a --nodeps option.

Adding the --nodeps options to an erase command directs RPM to ignore any dependency-related problems, and to erase the package. Going back to our example above, let's add the --nodeps option to the command line and see what happens:

# rpm -e --nodeps bother
#
          

The package was erased without a peep. Whether the blather package will work properly is another matter. In general, it's not a good idea to use --nodeps to get around dependency problems. The package builders included the dependency requirements for a reason, and it's best not to second-guess them.

--noscripts — Do Not Execute Pre- and Post-uninstall Scripts

In the section called “Getting More Information With -vv, we used the -vv option to see what RPM was actually doing when it erased a package. We noted that there were two scripts, a pre-uninstall and a post-uninstall, that were used to execute commands required during the process of erasing a package.

The --noscripts option prevents these scripts from being executed during an erase. This is a very dangerous thing to do! The --noscripts option is really meant for package builders to use during the development of their packages. By preventing the pre- and post-uninstall scripts from running, a package builder can keep a buggy package from bringing down their development system. Once the bugs are found and eliminated, there's very little need to prevent these scripts from running; in fact, doing so can cause problems!

--rcfile <rcfile> — Read <rcfile> For RPM Defaults

The --rcfile option is used to specify a file containing default settings for RPM. Normally, this option is not needed. By default, RPM uses /etc/rpmrc and a file named .rpmrc located in your login directory.

This option would be used if there was a need to switch between several sets of RPM defaults. Software developers and package builders will normally be the only people using the --rcfile option. For more information on rpmrc files, see Appendix B, The rpmrc File.

--root <path> — Use <path> As the Root

Adding --root <path> to an install command forces RPM to assume that the directory specified by <path> is actually the "root" directory. The --root option affects every aspect of the install process, so pre- and post-install scripts are run with <path> as their root directory (using chroot(2), if you must know). In addition, RPM expects its database to reside in the directory specified by the dbpath rpmrc file entry, relative to <path>. [17]

Normally this option is only used during an initial system install, or when a system has been booted off a "rescue disk" and some packages need to be re-installed.

--dbpath <path>: Use <path> To Find RPM Database

In order for RPM to do its handiwork, it needs access to an RPM database. Normally, this database exists in the directory specified by the rpmrc file entry, dbpath. By default, dbpath is set to /var/lib/rpm.

Although the dbpath entry can be modified in the appropriate rpmrc file, the --dbpath option is probably a better choice when the database path needs to be changed temporarily. An example of a time the --dbpath option would come in handy is when it's necessary to examine an RPM database copied from another system. Granted, it's not a common occurrence, but it's difficult to handle any other way.

rpm -e and Config files

If you've made changes to a configuration file that was originally installed by RPM, your changes won't be lost if you erase the package. Say, for example, that we've made changes to /etc/skel/.bashrc (a config file), which was installed as part of the etcskel package. Later, we remove etcskel:

# rpm -e etcskel
#
        

But if we take a look in /etc/skel, look what's there:

# ls -al

total 5
drwxr-xr-x   3 root     root         1024 Jun 17 22:01 .
drwxr-xr-x   8 root     root         2048 Jun 17 19:01 ..
-rw-r--r--   1 root     root          152 Jun 17 21:54 .bashrc.rpmsave
drwxr-xr-x   2 root     root         1024 May 13 13:18 .xfm

#
        

Sure enough: .bashrc.rpmsave is a copy of your modified .bashrc file! Remember, however, that this feature only works with config files. Not sure how to determine which files RPM thinks are config files? Chapter 5, Getting Information About Packages will show you how.

Watch Out!

RPM takes most of the work out of removing software from your system, and that's great. As with everything else in life, however, there's a downside. RPM also makes it easy to erase packages that are critical to your system's continued operation. Here are some examples of packages not to erase:

  • RPM: RPM will happily uninstall itself. No problem — you'll just re-install it with rpm -i… Oops!

  • Bash: The Bourne-again Shell may not be the shell you use, but certain parts of many Linux systems (like the scripts executed during system startup and shutdown) use /bin/sh, which is a symbolic link to /bin/bash. No /bin/bash, no /bin/sh. No /bin/sh, no system!

In many cases, RPM's dependency processing will prevent inadvertent erasures from causing massive problems. However, if you're not sure, use rpm -q to get more information about the package you'd like to erase. [18]



[17] For more information on rpmrc file entries, see Appendix B, The rpmrc File.

[18] See Chapter 5, Getting Information About Packages for more information on rpm -q.

Chapter 4. Using RPM to Upgrade Packages

Table 4.1. rpm -U Command Syntax

rpm -U (or --upgrade)options file1.rpmfileN.rpm
Parameters
file1.rpmfileN.rpm One or more RPM package files (URLs OK)
Upgrade-specific Options Page
-h (or --hash) Print hash marks ("#") during upgrade[a] the section called “-h: Perfect for the Impatient”
--oldpackage Permit "upgrading" to an older package the section called “ --oldpackage: Upgrade To An Older Version ”
--test Perform upgrade tests only[a] the section called “--test: Perform Installation Tests Only”
--excludedocs Do not install documentation[a] the section called “ --excludedocs: Do Not Install Documentation For This Package ”
--includedocs Install documentation[a] the section called “--includedocs: Install Documentation For This Package”
--replacepkgs Replace a package with a new copy of itself[a] the section called “--replacepkgs: Install the Package Even If Already Installed”
--replacefiles Replace files owned by another package[a] the section called “--replacefiles: Install the Package Even If It Replaces Another Package's Files”
--force Ignore package and file conflicts the section called “--force: The Big Hammer”
--percent Print percentages during upgrade[a] the section called “--percent: Not Meant for Human Consumption”
--noscripts Do not execute pre- and post-install scripts the section called “ --noscripts: Do Not Execute Install and Uninstall Scripts ”
--prefix <path> Relocate package to <path> if possible[a] the section called “ --prefix <path>: Relocate the package to <path>, if possible ”
--ignorearch Do not verify package architecture[a] the section called “ --ignorearch: Do Not Verify Package Architecture ”
--ignoreos Do not verify package operating system[a] the section called “ --ignoreos: Do Not Verify Package Operating System ”
--nodeps Do not check dependencies[a] the section called “ --nodeps: Do Not Check Dependencies Before Installing Package ”
--ftpproxy <host> Use <host> as the FTP proxy[a] the section called “ --ftpproxy <host>: Use <host> As Proxy In FTP-based Installs ”
--ftpport <port> Use <port> as the FTP port[a] the section called “ --ftpport <port>: Use <port> In FTP-based Installs ”
General Options Page
-v Display additional information[a] the section called “Getting a bit more feedback with -v
-vv Display debugging information[a] the section called “Getting a lot more information with -vv
--root <path> Set alternate root to <path>[a] the section called “ --root <path>: Use <path> As An Alternate Root ”
--rcfile <rcfile> Set alternate rpmrc file to <rcfile>[a] the section called “ --rcfile <rcfile>: Use <rcfile> As An Alternate rpmrc File ”
--dbpath <path> Use <path> to find the RPM database [a] the section called “ --dbpath <path>: Use <path> To Find RPM Database ”

[a] This option behaves identically to the same option used with rpm -i. Please see Chapter 2, Using RPM to Install Packages for more information on this option.

rpm -U — What Does it Do?

If there was one RPM command that could win over friends, it would be RPM's upgrade command. After all, anyone who has ever tried to install a newer version of any software knows what a traumatic experience it can be. With RPM, though, this process is reduced to a single command: rpm -U. The rpm -U command (--upgrade is equivalent) performs two distinct operations:

  1. Installs the desired package.

  2. Erases all older versions of the package, if any exist.

If it sounds to you like rpm -U is nothing more than an rpm -i command (see Chapter 2, Using RPM to Install Packages) followed by the appropriate number of rpm -e commands, (see Chapter 3, Using RPM to Erase Packages) you'd be exactly right. In fact, we'll be referring back to those chapters as we discuss rpm -U, so if you haven't skimmed those chapters yet, you might want to do that now.

While some people might think it's a "cheap shot" to claim that RPM performs an upgrade when in fact it's just doing the equivalent of a couple of other commands, in fact, it's a very smart thing to do. By carefully crafting RPM's package installation and erasure commands to do the work required during an upgrade, it makes RPM more tolerant of misuse by preserving important files even if an upgrade isn't being done.

If RPM had been written with a very "smart" upgrade command, and the install and erase commands couldn't handle upgrade situations at all, installing a package could overwrite a modified configuration file. Likewise, erasing a package would also mean that config files could be erased. Not a good situation! However, RPM's approach to upgrades makes it possible to handle even the most tricky situation — having multiple versions of a package install simultaneously.

Config file magic

While the rpm -i and rpm -e commands each do their part to keep config files straight, it is with rpm -U that the full power of RPM's config file handling shows through. There are no less than six different scenarios that RPM takes into account when handling config files.

In order to make the appropriate decisions, RPM needs information. The information used to decide how to handle config files is a set of three large numbers known as MD5 checksums. An MD5 checksum is produced when a file is used as the input to a complex series of mathematical operations. The resulting checksum has a unique property, in that any change to the file's contents will result in a change to the checksum of that file. [19] Therefore, MD5 checksums are a powerful tool for quickly determining whether two different files have the same contents or not.

In the previous paragraph, we stated that RPM uses three different MD5 checksums to determine what should be done with a config file. The three checksums are:

  1. The MD5 checksum of the file when it was originally installed. We'll call this the original file.

  2. The MD5 checksum of the file as it exists at upgrade time. We'll call this the current file.

  3. The MD5 checksum of the corresponding file in the new package. We'll call this the new file.

Let's take a look at the various combinations of checksums, see what RPM will do because of them, and discuss why. In the following examples, we'll use the letters X, Y, and Z in place of lengthy MD5 checksums.

Original file = X, Current file = X, New file = X

In this case, the file originally installed was never modified. [20] The file in the new version of the package is identical to the file on disk.

In this case, RPM installs the new file, overwriting the original. You may be wondering why go to the trouble of installing the new file if it's just the same as the existing one. The reason is that aspects of the file other than its name and contents might have changed. The file's ownership, for example, might be different in the new version.

Original file = X, Current file = X, New file = Y

The original file has not been modified, but the file in the new package is different. Perhaps the difference represents a bug-fix, or a new feature. It makes no difference to RPM.

In this case, RPM installs the new file, overwriting the original. This makes sense. If it didn't, RPM would never permit newer, modified versions of software to be installed! The original file is not saved, since it had not been changed. A lack of changes here means that no site-specific modifications were made to the file.

Original file = X, Current file = Y, New file = X

Here we have a file that was changed at some point. However, the new file is identical to the existing file prior to the local modifications.

In this case, RPM takes the viewpoint that since the original file and the new file are identical, the modifications made to the original version must still be valid for the new version. It leaves the existing, modified file in place.

Original file = X, Current file = Y, New file = Y

At some point the original file was modified, and those modifications happen to make the file identical to the new file. Perhaps the modification was made to fix a security problem, and the new version of the file has the same fix applied to it.

In this case, RPM installs the new version, overwriting the modified original. The same philosophy used in the first scenario applies here — although the file has not changed, perhaps some other aspect of the file has, so the new version is installed.

Original file = X, Current file = Y, New file = Z

Here the original file was modified at some point. The new file is different from both the original and the modified versions of the original file.

RPM is not able to analyze the contents of the files, and determine what is going on. In this instance, it takes the best possible approach. The new file is known to work properly with the rest of the software in the new package — at least the people building the new package should have insured that it does. The modified original file is an unknown: it might work with the new package, it might not. So RPM installs the new file.

BUT… The existing file was definitely modified. Someone made an effort to change the file, for some reason. Perhaps the information contained in the file is still of use. Therefore, RPM saves the modified file, naming it <file>.rpmsave, and prints a warning, so the user knows what happened:


warning: /etc/skel/.bashrc saved as /etc/skel/.bashrc.rpmsave

            

These five scenarios cover just about every possible circumstance, save one. The missing scenario?

Original file = none, Current file = ??, New file = ??

While RPM doesn't use checksums in this particular case, we'll describe it in those terms, for the sake of consistency. In this instance, RPM had not installed the file originally, so there is no original checksum.

Because the file had not originally been installed as part of a package, there is no way for RPM to determine if the file currently in place had been modified. Therefore, the checksums for the current file and the new file are irrelevant; they cannot be used to clear up the mystery.

When this happens, RPM renames the file to <file>.rpmorig, prints a warning, and installs the new file. This way, any modifications contained in the original file are saved. The system administrator can review the differences between the original and the newly installed files and determine what action should be taken.

As you can see, in the majority of cases RPM will automatically take the proper course of action when performing an upgrade. It is only when config files have been modified and are to be overwritten, that RPM leaves any post-upgrade work for the system administrator. Even in those cases, many times the modified files are not worth saving and can be deleted.

Upgrading a Package

The most basic version of the rpm -U command is simply "rpm -U", followed by the name of a .rpm package file:

# rpm -U eject-1.2-2.i386.rpm
#
        

Here, RPM performed all the steps necessary to upgrade the eject-1.2-2 package, faster than could have been done by hand. As in RPM's install command, Uniform Resource Locators, or URLs, can also be used to specify the package file. [21]

rpm -U's Dirty Little Secret

Well, in the example above, we didn't tell the whole story. There was no older version of the eject package installed. Yes, it's true — rpm -U works just fine as a replacement for the normal install command rpm -i.

This is another, more concrete example of the strength of RPM's method of performing upgrades. Since RPM's install command is smart enough to handle upgrades, RPM's upgrade command is really just another way to specify an install. Some people never even bother to use RPM's install command; they always use rpm -U. Maybe the "-U" should stand for, "Uh, do the right thing"…

They're Nearly Identical…

Given the fact that rpm -U can be used as a replacement to rpm -i, it follows that most of the options available for rpm -U are identical to those used with rpm -i. Therefore, to keep the duplication to a minimum, we'll discuss only those options that are unique to rpm -U, or that behave differently from the same option when used with rpm -i. The table on Table 4.1, “rpm -U Command Syntax” at the start of this chapter shows all valid options to RPM's upgrade command, and indicates which are identical to those used with rpm -i.

--oldpackage: Upgrade To An Older Version

This option might be used a bit more by people that like to stay on the "bleeding edge" of new versions of software, but eventually, everyone will probably need to use it. Usually, the situation plays out like this:

  • You hear about some new software that sounds pretty nifty, so you download the .rpm file and install it.

  • The software is great! It does everything you ask for, and more. You end up using it every day for the next few months.

  • You hear that a new version of your favorite software is available. You waste no time in getting the package. You upgrade the software by using rpm -U. No problem!

  • Fingers arched in anticipation, you launch the new version. Your computer's screen goes blank!

Looks like a bug in the new version. Now what do you do? Hmmm. Maybe you can just "upgrade" to the older version. Let's try to go back to release 2 of cdp-0.33 from release 3:

# rpm -Uv cdp-0.33-2.i386.rpm

Installing cdp-0.33-2.i386.rpm
package cdp-0.33-3 (which is newer) is already installed
error: cdp-0.33-2.i386.rpm cannot be installed

#
          

That didn't work very well. At least it told us just what the problem was — we were trying to upgrade to an older version of a package that is already installed. Fortunately, there's a special option for just this situation: --oldpackage. Let's give it a try:

# rpm -Uv --oldpackage cdp-0.33-2.i386.rpm

Installing cdp-0.33-2.i386.rpm

#
          

By using the --oldpackage option, release 3 of cdp-0.33 is history, and has been replaced by release 2.

--force: The Big Hammer

Adding --force to an upgrade command is a way of saying "Upgrade it anyway!" In essence, it adds --replacepkgs, --replacefiles, and --oldpackage to the command. Like a big hammer, --force is an irresistible force [22] that makes things happen. In fact, the only thing that will prevent a --force'ed upgrade from proceeding is a dependency conflict.

And like a big hammer, it pays to fully understand why you need to use --force before actually using it.

--noscripts: Do Not Execute Install and Uninstall Scripts

The --noscripts option prevents a package's pre- and post-install scripts from being executed. This is no different than the option's behavior when used with RPM's install command. However, there is an additional point to consider when the option is used during an upgrade. The following example uses specially-built packages that display messages when their scripts are executed by RPM:

# rpm -i bother-2.7-1.i386.rpm

This is the bother 2.7 preinstall script
This is the bother 2.7 postinstall script

#
          

In this case, a package has been installed. As expected, its scripts are executed. Next, let's upgrade this package:

# rpm -U bother-3.5-1.i386.rpm

This is the bother 3.5 preinstall script
This is the bother 3.5 postinstall script
This is the bother 2.7 preuninstall script
This is the bother 2.7 postuninstall script

#
          

This is a textbook example of the sequence of events during an upgrade. The new version of the package is installed (as shown by the pre- and post-install scripts being executed). Finally, the previous version of the package is removed (showing the pre- and post-uninstall scripts being executed).

There are really no surprises there — it worked just the way it was meant to. This time, let's use the --noscripts option when the time comes to perform the upgrade:

# rpm -i bother-2.7-1.i386.rpm

This is the bother 2.7 preinstall script
This is the bother 2.7 postinstall script

#
          

Again, the first package is installed, and its scripts are executed. Now let's try the upgrade using the --noscripts option:

# rpm -U --noscripts bother-3.5-1.i386.rpm

This is the bother 2.7 preuninstall script
This is the bother 2.7 postuninstall script

#
          

The difference here is that the --noscripts option prevented the new package's scripts from executing. The scripts from the package being erased were still executed.



[19] Actually, there's a one in 2128 chance a change will go undetected, but for all practical purposes, it's as close to perfect as we can get.

[20] Or, as some sticklers for detail may note, it may have been modified, and subsequently those modifications were undone.

[21] For more information on RPM's use of URLs, please see the section called “URLs — Another Way to Specify Package Files”.

[22] Pun intended.

Chapter 5. Getting Information About Packages

Table 5.1. rpm -q Command Syntax

rpm -q (or --query) options
Package Selection Options Page
pkg1pkgN Query installed package(s) the section called “The Package Label”
-p <file>(or "-") Query package file <file> (URLs OK) the section called “ -p <file> — Query a Specific RPM Package File ”
-f <file> Query package owning <file> the section called “ -f <file> — Query the Package Owning <file>
-a Query all installed packages the section called “-a — Query All Installed Packages”
--whatprovides <x> Query packages providing capability <x> the section called “ --whatprovides <x>: Query the Packages That Provide Capability <x>
-g <group> Query packages belonging to group <group> the section called “ -g <group>: Query Packages Belonging To Group <group>
--whatrequires <x> Query packages requiring capability <x> the section called “ --whatrequires <x>: Query the Packages That Require Capability <x>
Information Selection Options Page
<null> Display full package label the section called “The Package Label”
-i Display summary package information the section called “-i — Display Package Information”
-l Display list of files in package the section called “-l — Display the Package's File List”
-c Display list of configuration files the section called “ -c — Display the Package's List of Configuration Files ”
-d Display list of documentation files the section called “ -d — Display a List of the Package's Documentation ”
-s Display list of files in package, with state the section called “ -s — Display the State of Each File in the Package ”
--scripts Display install, uninstall, verify scripts the section called “ --scripts — Show Scripts Associated With a Package ”
--queryformat (or --qf) Display queried data in custom format the section called “ --queryformat — Construct a Custom Query Response ”
--dump Display all verifiable information for each file the section called “ --dump: Display All Verifiable Information for Each File ”
--provides Display capabilities package provides the section called “ --provides: Display Capabilities Provided by the Package ”
--requires (or -R) Display capabilities package requires the section called “ --requires: Display Capabilities Required by the Package ”
General Options Page
-v Display additional information the section called “ -v — Display Additional Information ”
-vv Display debugging information the section called “ Getting a lot more information with -vv
--root <path> Set alternate root to <path> the section called “ --root <path>: Use <path> As An Alternate Root ”
--rcfile <rcfile> Set alternate rpmrc file to <rcfile> the section called “ --rcfile <rcfile>: Use <rcfile> As An Alternate rpmrc File ”
--dbpath <path> Use <path> to find the RPM database the section called “ --dbpath <path>: Use <path> To Find RPM Database ”

rpm -q — What does it do?

One of the nice things about using RPM is that the packages you manage don't end up going into some kind of black hole. Nothing would be worse than to install, upgrade, and erase several different packages and not have a clue as to what's on your system. In fact, RPM's query function can help you get out of sticky situations like:

  • You're poking around your system, and you come across a file that you just can't identify. Where did it come from?

  • Your friend sends you a package file, and you have no idea what the package does, what it installs, or where it originally came from.

  • You know that you installed XFree86 a couple months ago, but you don't know what version, and you can't find any documentation on it.

The list could go on, but you get the idea. The rpm -q command is what you need. If you're the kind of person that doesn't like to have more options than you know what to do with, rpm -q might look imposing. But fear not. Once you have a handle on the basic structure of an RPM query, it'll be a piece of cake.

The Parts of an RPM Query

It becomes easy to construct a query command once you understand the individual parts. First is the -q (You can also use --query, if you like). After all, you need to tell RPM what function to perform, right? The rest of a query command consists of two distinct parts: package selection (or what packages you'd like to query), and information selection (or what information you'd like to see). Let's take a look at package selection first:

Query Commands, Part One: Package Selection

The first thing you'll need to decide when issuing an RPM query is what package (or packages) you'd like to query. RPM has several ways to specify packages, so you have quite an assortment to choose from.

The Package Label

In earlier chapters, we discussed RPM's package label, a string that uniquely identifies every installed package. Every label contains three pieces of information:

  1. The name of the packaged software.

  2. The version of the packaged software.

  3. The package's release number.

When issuing a query command using package labels, you must always include the package name. You can also include the version and even the release, if you like. The only restrictions are that each part of the package label specified must be complete, and that if any parts of the package label are missing, all parts to the right must be omitted as well. This second restriction is just a long way of saying that if you specify the release, you must also specify the version as well. Let's look at a few examples.

Say, for instance, you've recently installed a new version of the C libraries, but you can't remember the version number:

# rpm -q libc

libc-5.2.18-1

#
            

In this type of query, RPM returns the complete package label for all installed packages that match the given information. In the example above, if version 5.2.17 of the C libraries was also installed, its package label would have been displayed, too.

In this example, we've included the version as well as the package name:

# rpm -q rpm-2.3

rpm-2.3-1

#
            

Note, however, that RPM is a bit picky about specifying package names. Here are some queries for the C library that won't work:

# rpm -q LibC

package LibC is not installed

#
# rpm -q lib

package lib is not installed

#
# rpm -q "lib*"

package lib* is not installed

#
# rpm -q libc-5

package libc-5 is not installed

#
# rpm -q libc-5.2.1

package libc-5.2.1 is not installed

#
            

As you can see, RPM is case sensitive about package names and cannot match partial names, version numbers, or release numbers. Nor can it use the wildcard characters we've come to know and love. As we've seen, however, RPM can perform the query when more than one field of the package label is present. In the above case, rpm -q libc-5.2.18, or even rpm -q libc-5.2.18-1 would have found the package, libc-5.2.18-1.

Querying based on package labels may seem a bit restrictive. After all, you need to know the exact name of a package in order to perform a query on it. But there are other ways of specifying packages…

-a — Query All Installed Packages

Want lots of information fast? Using the -a option, you can query every package installed on your system. For example:

# rpm -qa

ElectricFence-2.0.5-2
ImageMagick-3.7-2
…
tetex-xtexsh-0.3.3-8
lout-3.06-4

#
            

(On a system installed using RPM, the number of packages can easily number 200 or more; we've deleted most of the output.)

The -a option can produce mountains of output, which makes it a prime candidate for piping through the many Linux/UNIX commands available. One of the prime candidates would be a pager such as more, so that the list of installed packages could be viewed a screenful at a time.

Another handy command to pipe rpm -qa's output through is grep. In fact, using grep, it's possible to get around RPM's lack of built-in wildcard processing:

# rpm -qa | grep -i sysv

SysVinit-2.64-2

#
            

In this example, we were able to find the SysVinit package, even though we didn't have the complete package name, or capitalization.

-f <file> — Query the Package Owning <file>

How many times have you found a program sitting on your system and wondered "what does it do?" Well, if the program was installed by RPM as part of a package, it's easy to find out. Simply use the -f option. Example: You find a strange program called ls in /bin (Okay, it is a contrived example). Wonder what package installed it? Simple!

# rpm -qf /bin/ls

fileutils-3.12-3

#
            

If you happen to point RPM at a file it didn't install, you'll get a message similar to the following:

# rpm -qf .cshrc

file /home/ed/.cshrc is not owned by any package

#
            

A Tricky Detail

It's possible that you'll get the "not owned by any package" message in error. Here's an example of how it can happen:

# rpm -qf /usr/X11/bin/xterm

file /usr/X11/bin/xterm is not owned by any package

#
              

As you can see, we're trying to find out what package the xterm program is part of. The first example failed, which might lead one to believe that xterm really isn't owned by any package.

However, let's look at a directory listing:

# ls -lF /usr

…
lrwxrwxrwx   1 root     root            5 May 13 12:46 X11 -> X11R6/
drwxrwxr-x   7 root     root         1024 Mar 21 00:21 X11R6/
…

#
              

(We've truncated the list; normally /usr is quite a bit more crowded than this.)

The key here is the line ending with "X11 -> X11R6/". This is known as a "symbolic link". It's a way of referring to a file (here, a directory file) by another name. In this case, if we used the path /usr/X11, or /usr/X11R6, it shouldn't make a difference. It certainly doesn't make a difference to programs that simply want access to the file. But it does make a difference to RPM, because RPM doesn't use the filename to access the file. RPM uses the filename as a key into its database. It would be very difficult, if not impossible, to keep track of all the symlinks on a system and try every possible path to a file during a query.

What to do? There are two options:

  1. Make sure you always specify a path free of symlinks. This can be pretty tough, though. An alternative approach is to use namei to track down symlinks:

    # namei /usr/X11/bin/xterm
    
    f: /usr/X11/bin/xterm
     d /
     d usr
     l X11 -> X11R6
       d X11R6
     d bin
     - xterm
    
    #
                        

    It's pretty easy to see the X11 to X11R6 symlink. Using this approach you can enter the non-symlinked path and get the desired results:

    # rpm -qf /usr/X11R6/bin/xterm
    
    XFree86-3.1.2-5
    
    #
                        

  2. Change your directory to the one holding the file you want to query. Even if you use a symlinked path to get there, querying the file should then work as you'd expect:

    # cd /usr/X11/bin
    # rpm -qf xterm
    
    XFree86-3.1.2-5
    
    #
                        

So if you get a "not owned by any package" error, and you think it may not be true, try one of the approaches above.

-p <file> — Query a Specific RPM Package File

Up to now, every means of specifying a package to an RPM query focused on packages that had already been installed. While it's certainly very useful to be able to dredge up information about packages that are already on your system, what about packages that haven't yet been installed? The -p option can do that for you.

One situation where this capability would help, occurs when the name of a package file has been changed. Since the name of the file containing a package has nothing to do with the name of the package (though, by tradition it's nice to name package files consistently), we can use this option to find out exactly what package a file contains:

# rpm -qp foo.bar

rpm-2.3-1

#
            

With one command RPM gives you the answer. [23]

The -p option can also use Uniform Resource Locators to specify package files. See the section called “URLs — Another Way to Specify Package Files” for more information on using URLs.

There's one last trick up -p's sleeve — it can also perform a query by reading a package from standard input. Here's an example:

# cat bother-3.5-1.i386.rpm | rpm -qp -

bother-3.5-1

#
            

We piped the output of cat into RPM. The dash at the end of the command line directs RPM to read the package from standard input.

-g <group>: Query Packages Belonging To Group <group>

When a package is built, the package builder must classify the package, grouping it with other packages that perform similar functions. RPM gives you the ability to query installed packages based on their groups. For example, there is a group known as Base. This group consists of packages that provide low-level structure for a Linux distribution. Let's see what installed packages make up the Base group:

# rpm -qg Base

setup-1.5-1
pamconfig-0.50-5
filesystem-1.2-1
crontabs-1.3-1
dev-2.3-1
etcskel-1.1-1
initscripts-2.73-1
mailcap-1.0-3
pam-0.50-17
passwd-0.50-2
redhat-release-4.0-1
rootfiles-1.3-1
termcap-9.12.6-5

#
            

One thing to keep in mind is that group specifications are case-sensitive. Issuing the command rpm -qg base won't produce any output.

--whatprovides <x>: Query the Packages That Provide Capability <x>

RPM provides extensive support for dependencies between packages. The basic mechanism used is that a package may require what another package provides. The thing that is required and provided can be a shared library's soname. It can also be a character string chosen by the package builder. In any case, it's important to be able to display which packages provide a given capability.

This is just what the --whatprovides option does. When the option, followed by a capability, is added to a query command, RPM will select those packages that provide the capability. Here's an example:

# rpm -q --whatprovides module-info

kernel-2.0.18-5

#
            

In this case, the only package that provides the module-info capability is kernel-2.0.18-5.

--whatrequires <x>: Query the Packages That Require Capability <x>

The --whatrequires option is the logical complement to the --whatprovides option described above. It is used to display which packages require the specified capability. Expanding on the example we started with --whatprovides, let's see which packages require the module-info capability:

# rpm -q --whatrequires module-info

kernelcfg-0.3-2

#
            

There's only one package that requires module-infokernelcfg-0.3-2.

Query Commands, Part Two: Information Selection

After specifying the package (or packages) you wish to query, you'll need to figure out just what information you'd like RPM to retrieve. As we've seen, by default, RPM only returns the complete package label. But there's much more to a package than that. Here, we'll explore every information selection option available to us.

-i — Display Package Information

Adding -i to rpm -q tells RPM to give you some information on the package or packages you've selected. For the sake of clarity, let's take a look at what it gives you and explain what you're looking at:

# rpm -qi rpm

Name        : rpm                    Distribution: Red Hat Linux Vanderbilt
Version     : 2.3                          Vendor: Red Hat Software
Release     : 1                        Build Date: Tue Dec 24 09:07:59 1996
Install date: Thu Dec 26 23:01:51 1996 Build Host: porky.redhat.com
Group       : Utilities/System         Source RPM: rpm-2.3-1.src.rpm
Size        : 631157
Summary     : Red Hat Package Manager
Description :
RPM is a powerful package manager, which can be used to build, install,
query, verify, update, and uninstall individual software packages. A
package consists of an archive of files, and package information, including
name, version, and description.

# 
            

There's quite a bit of information here, so let's go through it entry by entry:

  • Name — The name of the package you queried. Usually (but not always) it bears some resemblance to the name of the underlying software.

  • Version — The version number of the software, as specified by the software's original creator.

  • Release — The number of times a package consisting of this software has been packaged. If the version number should change, the release number should start over again at "1".

As you've probably noticed, these three pieces of information comprise the package label we've come to know and love. Continuing, we have:

  • Install date — This is the time when the package was installed on your system.

  • Group — In our example, this looks suspiciously like a path. If you went searching madly for a directory tree by that name, you'd come up dry — it isn't a set of directories at all.

    When a package builder starts to create a new package, they enter a list of words that describe the software. The list, which goes from least specific to most specific, attempts to categorize the software in a concise manner. The primary use for the group is to enable graphically oriented package managers based on RPM to present packages grouped by function. Red Hat Linux's glint command does this.

  • Size — This is the size (in bytes) of every file in this package. It might make your decision to erase an unused package easier if you see six or more digits here.

  • Summary — This is a concise description of the packaged software.

  • Description — This is a verbose description of the packaged software. Some descriptions might be more, well, descriptive than others, but hopefully it will be enough to clue you in as to the software's role in the greater scheme of things.

  • Distribution — The word "distribution" is really not the best name for this field. "Product" might be a better choice. In any case, this is the name of the product this package is a part of.

  • Vendor — The organization responsible for building this package.

  • Build Date — The time the package was created.

  • Build Host — The name of the computer system that built the package. [24]

  • Source RPM — The process of building a package results in two files:

    1. The package file used to install the packaged software. This is sometimes called the binary package.

    2. The package file containing the source code and other files used to create the binary package file. This is known as the source RPM package file. This is the filename that is displayed in this field.

    Unless you want to make changes to the software, you probably won't need to worry about source packages. But if you do, stick around, because the second part of this book is for you…

-l — Display the Package's File List

Adding -l to rpm -q tells RPM to display the list of files that are installed by the specified package or packages. If you've used ls before, you won't be surprised by RPM's file list.

Here's a look at one of the smaller packages on Red Hat Linux — adduser:

# rpm -ql adduser

/usr/sbin/adduser

#
            

The adduser package consists of only one file, so there's only one filename displayed.

-v — Display Additional Information

In some cases, the -v option can be added to a query command for additional information. The -l option we've been discussing is an example of just such a case. Note how the -v option adds verbosity:

# rpm -qlv adduser

-rwxr-xr-x-     root     root       3894 Feb 25 13:45 /usr/sbin/adduser

#
              

Looks a lot like the output from ls, doesn't it? Looks can be deceiving. Everything you see here is straight from RPM's database. However, the format is identical to ls, so it's more easily understood. If this is Greek to you, consult the ls man page.

-c — Display the Package's List of Configuration Files

When -c is added to an rpm -q command, RPM will display the configuration files that are part of the specified package or packages. As mentioned earlier in the book, config files are important, because they control the behavior of the packaged software. Let's take a look at the list of config files for XFree86:

# rpm -qc XFree86

/etc/X11/fs/config
/etc/X11/twm/system.twmrc
/etc/X11/xdm/GiveConsole
/etc/X11/xdm/TakeConsole
/etc/X11/xdm/Xaccess
/etc/X11/xdm/Xresources
/etc/X11/xdm/Xservers
/etc/X11/xdm/Xsession
/etc/X11/xdm/Xsetup_0
/etc/X11/xdm/chooser
/etc/X11/xdm/xdm-config
/etc/X11/xinit/xinitrc
/etc/X11/xsm/system.xsm
/usr/X11R6/lib/X11/XF86Config

#
            

These are the files you'd want to look at first if you were looking to customize XFree86 for your particular needs. Just like -l, we can also add v for more information:

# rpm -qcv XFree86

-r--r--r---  root  root    423 Mar 21 00:17 /etc/X11/fs/config
…
lrwxrwxrwx-  root  root     30 Mar 21 00:29 /usr/X11R6/lib/X11/XF86Config -> ../../../../etc/X11/XF86Config

#
            

(Note that last file: RPM will display symbolic links, as well.)

-d — Display a List of the Package's Documentation

When -d is added to a query, we get a list of all files containing documentation for the named package or packages. This is a great way to get up to speed when you're having problems with unfamiliar software. As with -c and -l, you'll see either a simple list of filenames, or (if you've added -v) a more comprehensive list. Here's an example that might look daunting at first, but really isn't:

# rpm -qdcf /sbin/dump

/etc/dumpdates
/usr/doc/dump-0.3-5
/usr/doc/dump-0.3-5/CHANGES
/usr/doc/dump-0.3-5/COPYRIGHT
/usr/doc/dump-0.3-5/INSTALL
/usr/doc/dump-0.3-5/KNOWNBUGS
/usr/doc/dump-0.3-5/THANKS
/usr/doc/dump-0.3-5/dump-0.3.announce
/usr/doc/dump-0.3-5/dump.lsm
/usr/doc/dump-0.3-5/linux-1.2.x.patch
/usr/man/man8/dump.8
/usr/man/man8/rdump.8
/usr/man/man8/restore.8
/usr/man/man8/rmt.8
/usr/man/man8/rrestore.8

#
            

Let's take that alphabet soup set of options, one letter at a time:

  • q — Perform a query.

  • d — List all documentation files.

  • c — List all config files.

  • f — Query the package that owns the specified file (/sbin/dump, in this case).

The list of files represents all the documentation and config files that apply to the package owning /sbin/dump.

-s — Display the State of Each File in the Package

Unlike the past three sections, which dealt with a list of files of one type or another, adding -s to a query will list the state of the files that comprise one or more packages. I can hear you out there; you're saying, "What is the state of a file?" For every file that RPM installs, there is an associated state. There are four possible states:

  1. normal — A file in the normal state has not been modified by installing another package on the system.

  2. replaced — Files in the replaced state have been modified by installing another package on the system.

  3. not installed — A file is classified as not installed when it, er, isn't installed! This state is normally seen only if the package was partially installed. An example of a partially installed package would be one that was installed with the --excludedocs option. Using this option, no documentation files would be installed. The RPM database would still contain entries for these missing files, but their state would be not installed.

  4. net shared — The net shared state is used to support client systems that NFS mount portions of their filesystems from a server. Since the server most likely exports filesystems to more than one client, if a client erased a package that contained files on a shared filesystem, other client systems would have incompletely installed packages. The net shared state is used to alert RPM to the fact that a file is on a shared filesystem and should not be erased. Files will be in the net shared state when two things happen:

    1. The netsharedpath rpmrc file entry has been changed from its default (null) value. [25]

    2. The file is to be installed in a directory within a net shared path.

Here's an example showing how file states appear:

# rpm -qs adduser

normal        /usr/sbin/adduser

#
            

(That normal at the start of the line is the state, followed by the file name)

The file state is one of the tools RPM uses to determine the most appropriate action to take when packages are installed or erased.

Now would the average person need to check the states of files? Not really. But if there should be problems, this kind of information can help get things back on track.

--provides: Display Capabilities Provided by the Package

By adding --provides to a query command, we can see the capabilities provided by one or more packages. If the package doesn't provide any capabilities, the --provides option produces no output:

# rpm -q --provides rpm
#
            

However, if a package does provide capabilities, they will be displayed:

# rpm -q --provides foonly

index

#
            

It's important to remember that capabilities are not filenames. In the above example, the foonly package contains no file called index; it's just a character string the package builder chose. This is no different from the following example:

# rpm -q --provides libc

libm.so.5
libc.so.5

#
            

While there might be symlinks by those names in /lib, capabilities are a property of the package, not a file contained in the package!

--requires: Display Capabilities Required by the Package

The --requires option (-R is equivalent) is the logical complement to the --provides option. It displays the capabilities required by the specified package(s). If a package has no requirements, there's no output:

# rpm -q --requires adduser
#
            

In cases where there are requirements, they are displayed as follows:

# rpm -q --requires rpm

libz.so.1
libdb.so.2
libc.so.5

#
            

It's also possible that you'll come across something like this:

# rpm -q --requires blather

bother >= 3.1

#
            

Packages may also be built to require another package. This requirement can also include specific versions. In the example above, the bother package is required by blather; specifically, a version of bother greater than or equal to 3.1.

Here's something worth understanding. Let's say we decide to track down the bother that blather says it requires. If we use RPM's query capabilities, we could use the --whatprovides package selection option to try to find it:

# rpm -q --whatprovides bother

no package provides bother

#
            

No dice. This might lead you to believe that the blather package has a problem. The moral of this story is that, when trying to find out what package fulfills another package's requirements, it's a good idea to also try a simple query using the requirement as a package name. Continuing our example above, let's see if there's a package called bother:

# rpm -q bother

bother-3.5-1

#
            

Bingo! However, if we see what capabilities the bother package provides, we come up dry:

# rpm -q --provides bother
#
            

The reason for the lack of output is that all packages, by default, "provide" their package name (and version).

--dump: Display All Verifiable Information for Each File

The --dump option is used to display every piece of information RPM has on one or more files listed in its database. The information is listed in a very concise fashion. Since the --dump option displays file-related information, the list of files must be chosen by using the -l, -c, or -d options (or some combination thereof):

# rpm -ql --dump adduser

/usr/sbin/adduser 4442 841083888 ca5fa53dc74952aa5b5e3a5fa5d8904b 0100755
root root 0 0 0 X

#
            

What does all this stuff mean? Let's go through it, item-by-item:

  • The /usr/sbin/adduser is simple: it's the name of the file being dump'ed.

  • 4442 is the size of the file, in bytes.

  • How about 841083888? It's the time the file was last modified, in seconds past the Unix zero date of January 1, 1970.

  • The ca5fa53dc74952aa5b5e3a5fa5d8904b is the MD5 checksum of the file's contents, all 128 bits of it.

  • If you guessed 0100755 was the file's mode, you'd be right.

  • The first root represents the file's owner.

  • The second root is the file's group.

  • We'll take the next part (0 0) in one chunk. The first zero shows whether the file is a config file. If zero, as in this case, then the file is not a config file. The next zero shows whether the file is documentation. Again, since there is a zero here, this file isn't documentation, either.

  • The final 0 represents the file's major and minor numbers. These are set only for device special files. Otherwise, it will be zero.

  • If the file were a symlink, the spot taken by the X would contain a path pointing to the linked file.

Normally, the --dump option is used by people that want to extract the file-related information from RPM and process it somehow.

--scripts — Show Scripts Associated With a Package

If you add --scripts (that's two dashes) to a query, you get to see a little bit more of RPM's underlying magic:

# rpm -q --scripts XFree86

preinstall script:
(none)

postinstall script:
/sbin/ldconfig
/sbin/pamconfig --add --service=xdm --password=none --sesslist=none

preuninstall script:
(none)

postuninstall script:
/sbin/ldconfig
if [ "$1" = 0 ] ; then
  /sbin/pamconfig --remove --service=xdm --password=none --sesslist=none
fi

verify script:
(none)


#
            

In this particular case, the XFree86 package has two scripts: one labeled postinstall, and one labeled postuninstall. As you might imagine, the postinstall script is executed just after the package's files have been installed; the postuninstall script is executed just after the package's files have been erased.

Based on the labels in this example, you'd probably imagine that a package can have as many as five different scripts. You'd be right:

  1. The preinstall script, which is executed just before the package's files are installed.

  2. The postinstall script, which is executed just after the package's files are installed.

  3. The preuninstall script, which is executed just before the package's files are removed.

  4. The postuninstall script, which is executed just after the package's files are removed.

  5. And finally, the verify script. While it's easy to figure out the other scripts' functions based on their name, what does a script called verify do? Well, we haven't gotten to it yet, but packages can also be verified for proper installation. This script is used during verification. [26]

Is this something you'll need very often? As in the case of displaying file states, not really. But when you need it, you really need it!

--queryformat — Construct a Custom Query Response

OK, say you're still not satisfied. You'd like some additional information, or you think a different format would be easier on the eyes. Maybe you want to take some information on the packages you've installed and run it through a script for some specialized processing. You can do it, using the --queryformat option. In fact, if you look back at the output of the -i option, RPM was using --queryformat internally. Here's how it works:

On the RPM command line, include --queryformat. Right after that, enter a format string, enclosed in single quotes "'".

The format string can consist of a number of different components:

  • Literal text, including escape sequences.

  • Tags, with optional field width, formatting, and iteration information.

  • Array Iterators.

Let's look at each of these components.

Literal text

Any part of a format string that is not associated with tags or array iterators will be treated as literal text. Literal text is just that: It's text that is printed just as it appears in the format string. In fact, a format string can consist of nothing but literal text, although the output wouldn't tell us much about the packages being queried. Let's give the --queryformat option a try, using a format string with nothing but literal text:

# rpm -q --queryformat 'This is a test!' rpm

This is a test!#
              

The RPM command might look a little unusual, but if you take out the --queryformat option, along with its format string, you'll see this is just an ordinary query of the rpm package. When the --queryformat option is present, RPM will use the text immediately following the option as a format string. In our case, the format string is 'This is a test!'. The single quotes are required. Otherwise, it's likely your shell will complain about some of the characters contained in the average format string.

The output of this command appears on the second line. As we can see, the literal text from the format string was printed exactly as it was entered.

Carriage Control Escape Sequences

Wait a minute. What is that # doing at the end of the output? Well, that's our shell prompt. You see, we didn't direct RPM to move to a new line after producing the output, so the shell prompt ended up being tacked to the end of our output.

Is there a way to fix that? Yes, there is. We need to use an escape sequence. An escape sequence is a sequence of characters that starts with a backslash (\). Escape sequences add carriage control information to a format string. The following escape sequences can be used:

  • \a — Produces a bell or similar alert.

  • \b — Backspaces one character.

  • \f — Outputs a form-feed character.

  • \n — Outputs a newline character sequence.

  • \r — Outputs a carriage return character.

  • \t — Causes a horizontal tab.

  • \v — Causes a vertical tab.

  • \\ — Displays a backslash character.

Based on this list, it seems that a \n escape sequence at the end of the format string will put our shell prompt on the next line:

# rpm -q --queryformat 'This is a test!\n' rpm

This is a test!

#
              

Much better…

Tags

The most important parts of a format string are the tags. Each tag specifies what information is to be displayed and can optionally include field-width, as well as justification and data formatting instructions. [27] But for now, let's look at the basic tag. In fact, let's look at three — the tags that print the package name, version, and release.

Strangely enough, these tags are called NAME, VERSION, and RELEASE. In order to be used in a format string, the tag names must be enclosed in curly braces and preceded by a percent sign. Let's give it a try:

# rpm -q --queryformat '%{NAME}%{VERSION}%{RELEASE}\n' rpm

rpm2.31

#
              

Let's add a dash between the tags and see if that makes the output a little easier to read:

# rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}\n' rpm

rpm-2.3-1

#
              

Now our format string outputs standard package labels.

Field Width and Justification

Sometimes it's desirable to allocate fields of a particular size for a tag. This is done by putting the desired field width between the tag's leading percent sign, and the opening curly brace. Using our package-label-producing format string, let's allocate a 20-character field for the version:

# rpm -q --queryformat '%{NAME}-%20{VERSION}-%{RELEASE}\n' rpm

rpm-                 2.3-1

#
                

The result is a field of 20 characters: 17 spaces, followed by the three characters that make up the version.

In this case, the version field is right justified; that is, the data is printed at the far right of the output field. We can left justify the field by preceding the field width specification with a dash:

# rpm -q --queryformat '%{NAME}-%-20{VERSION}-%{RELEASE}\n' rpm

rpm-2.3                 -1

#
                

Now the version is printed at the far left of the output field. You might be wondering what would happen if the field width specification didn't leave enough room for the data being printed. The field width specification can be considered the minimum width the field will take. If the data being printed is wider, the field will expand to accommodate the data.

Modifiers — Making Data More Readable

While RPM does its best to appropriately display the data from a --queryformat, there are times when you'll need to lend a helping hand. Here's an example. Say we want to display the name of each installed package, followed by the time the package was installed. Looking through the available tags, we see INSTALLTIME. Great! Looks like this will be simple:

# rpm -qa --queryformat '%{NAME} was installed on %{INSTALLTIME}\n'

setup was installed on 845414601
pamconfig was installed on 845414602
filesystem was installed on 845414607
…
rpm was installed on 851659311
pgp was installed on 846027549

#
                

Well, that's a lot of output, but not very useful. What are those numbers? RPM didn't lie -- they're the time the packages were installed. The problem is, the times are being displayed in their numeric form used internally by the operating system, and humans like to see the day, month, year, and so on.

Fortunately, there's a modifier for just this situation. The name of the modifier is :date, and it follows the tag name. Let's try our example again, this time using :date:

# rpm -qa --queryformat '%{NAME} was installed on %{INSTALLTIME:date}\n'

setup was installed on Tue Oct 15 17:23:21 1996
pamconfig was installed on Tue Oct 15 17:23:22 1996
filesystem was installed on Tue Oct 15 17:23:27 1996
…
rpm was installed on Thu Dec 26 23:01:51 1996
pgp was installed on Tue Oct 22 19:39:09 1996

#
                

That sure is a lot easier to understand, isn't it?

Here's a list of the available modifiers:

  • The :date modifier displays dates in human-readable form. It transforms 846027549 into Tue Oct 22 19:39:09 1996.

  • The :perms modifier displays file permissions in an easy-to-read format. It changes -32275 to -rwxr-xr-x-.

  • The :depflags modifier displays the version comparison flags used in dependency processing, in human-readable form. It turns 12 into >=.

  • The :fflags modifier displays a c if the file has been marked as being a configuration file, a d if the file has been marked as being a documentation file, and blank otherwise. Thus, 2 becomes d.

Array Iterators

Until now, we've been using tags that represent single data items. There is, for example, only one package name or installation date for each package. However, there are other tags that can represent many different pieces of data. One such tag is FILENAMES, which can be used to display the names of every file contained in a package.

Let's put together a format string that will display the package name, followed by the name of every file that package contains. We'll try it on the adduser package first, since it contains only one file:

# rpm -q --queryformat '%{NAME}: %{FILENAMES}\n' adduser

adduser: /usr/sbin/adduser

#
              

Hey, not bad — got it on the first try. Now let's try it on a package with more than one file:

# rpm -q --queryformat '%{NAME}: %{FILENAMES}\n' etcskel

etcskel: (array)

#
              

Hmmm. What went wrong? It worked before… Well, it worked before because the adduser package contained only one file. The FILENAMES tag points to an array of names, so when there is more than one file in a package, there's a problem.

But there is a solution. It's called an iterator. An iterator can step through each entry in an array, producing output as it goes. Iterators are created when square braces enclose one or more tags and literal text. Since we want to iterate through the FILENAMES array, let's enclose that tag in the iterator:

# rpm -q --queryformat '%{NAME}: [%{FILENAMES}]\n' etcskel

etcskel: /etc/skel/etc/skel/.Xclients/etc/skel/.Xdefaults/etc/skel/.ba

#
              

There was more output — it went right off the screen in one long line. The problem? We didn't include a newline escape sequence inside the iterator. Let's try it again:

# rpm -q --queryformat '%{NAME}: [%{FILENAMES}\n]' etcskel

etcskel: /etc/skel
/etc/skel/.Xclients
/etc/skel/.Xdefaults
/etc/skel/.bash_logout
/etc/skel/.bash_profile
/etc/skel/.bashrc
/etc/skel/.xsession

#
              

That's more like it. If we wanted, we could put another file-related tag inside the iterator. If we included the FILESIZES tag, we'd be able to see the name of each file, as well as how big it was:

# rpm -q --queryformat '%{NAME}: [%{FILENAMES} (%{FILESIZES} bytes)\n]' etcskel

etcskel: /etc/skel (1024 bytes)
/etc/skel/.Xclients (551 bytes)
/etc/skel/.Xdefaults (3785 bytes)
/etc/skel/.bash_logout (24 bytes)
/etc/skel/.bash_profile (220 bytes)
/etc/skel/.bashrc (124 bytes)
/etc/skel/.xsession (9 bytes)

#
              

That's pretty nice. But it would be even nicer if the package name appeared on each line, along with the filename and size. Maybe if we put the NAME tag inside the iterator:

# rpm -q --queryformat '[%{NAME}: %{FILENAMES} \
?  (%{FILESIZES} bytes)\n]' etcskel

etcskel: /etc/skel(parallel array size mismatch)#
              

The error message says it all. The FILENAMES and FILESIZES arrays are the same size. The NAME tag isn't even an array. Of course the sizes don't match!

Iterating Single-Entry Tags

If a tag only has one piece of data, it's possible to put it in an iterator and have its one piece of data displayed with every iteration. This is done by preceding the tag name with an equal sign. Let's try it out on our current example:

# rpm -q --queryformat '[%{=NAME}: %{FILENAMES} (%{FILESIZES} bytes)\n]' etcskel

etcskel: /etc/skel (1024 bytes)
etcskel: /etc/skel/.Xclients (551 bytes)
etcskel: /etc/skel/.Xdefaults (3785 bytes)
etcskel: /etc/skel/.bash_logout (24 bytes)
etcskel: /etc/skel/.bash_profile (220 bytes)
etcskel: /etc/skel/.bashrc (124 bytes)
etcskel: /etc/skel/.xsession (9 bytes)

#
                

That's about all there is to format strings. Now, if RPM's standard output doesn't give you what you want, you have no reason to complain. Just --queryformat it!

In Case You Were Wondering…

What's that? You say you don't know what tags are available? You can use RPM's --querytags option. When used as the only option (ie, rpm --querytags), it produces a list of available tags. It should be noted that RPM displays the complete tag name. For instance, RPMTAG_ARCH is the complete name, yet you'll only need to use ARCH in your format string. Here's a partial example of the --querytags option in action:

# rpm --querytags

RPMTAG_NAME
RPMTAG_VERSION
RPMTAG_RELEASE
…
RPMTAG_VERIFYSCRIPT

#
              

Be forewarned: the full list is quite lengthy. At the time this book was written, there were over 70 tags! You'll notice that each tag is printed in uppercase, and is preceded with RPMTAG_. If we were to use that last tag, RPMTAG_VERIFYSCRIPT, in a format string, it could be specified in any of the following ways:


%{RPMTAG_VERIFYSCRIPT}

%{RPMTAG_VerifyScript}

%{RPMTAG_VeRiFyScRiPt}

%{VERIFYSCRIPT}

%{VerifyScript}

%{VeRiFyScRiPt}

              

The only hard-and-fast rule regarding tags is that if you include the RPMTAG_ prefix, it must be all uppercase. The fourth example above shows the traditional way of specifying a tag — prefix omitted, all uppercase. The choice, however, is yours.

One other thing to keep in mind is that not every package will have every type of tagged information available. In cases where the requested information is not available, RPM will display (none) or (unknown). There are also a few tags that, for one reason or another, will not produce useful output when using in a format string. For a comprehensive list of queryformat tags, please see Appendix D, Available Tags For --queryformat.

Getting a lot more information with -vv

Sometimes it's necessary to have even more information than we can get with -v. By adding another v, we can start to see more of RPM's inner workings:

# rpm -qvv rpm

D: opening database in //var/lib/rpm/
D: querying record number 2341208
rpm-2.3-1

#
          

The lines starting with D: have been added by using -vv. We can see where the RPM database is located and what record number contains information on the rpm-2.3-1 package. Following that is the usual output.

In the vast majority of cases, it will not be necessary to use -vv. It is normally used by software engineers working on RPM itself, and the output can change without notice. However, it's a handy way to gain insights into RPM's inner workings.

--root <path>: Use <path> As An Alternate Root

Adding --root <path> to a query command forces RPM to assume that the directory specified by <path> is actually the "root" directory. In addition, RPM expects its database to reside in the directory specified by the dbpath rpmrc file entry, relative to <path>. [28]

Normally this option is only used during an initial system install, or when a system has been booted off a "rescue disk", and some packages need to be re-installed in order to restore normal operation.

--rcfile <rcfile>: Use <rcfile> As An Alternate rpmrc File

The --rcfile option is used to specify a file containing default settings for RPM. Normally, this option is not needed. By default, RPM uses /etc/rpmrc and a file named .rpmrc, located in your login directory.

This option would be used if there was a need to switch between several sets of RPM options. Software developer and package builders will be the people using --rcfile. For more information on rpmrc files, see Appendix B, The rpmrc File.

--dbpath <path>: Use <path> To Find RPM Database

In order for RPM to do its handiwork, it needs access to an RPM database. Normally, this database exists in the directory specified by the rpmrc file entry, dbpath. By default, dbpath is set to /var/lib/rpm.

Although the dbpath entry can be modified in the appropriate rpmrc file, the --dbpath option is probably a better choice when the database path needs to be changed temporarily. An example of a time the --dbpath option would come in handy is when it's necessary to examine an RPM database copied from another system. Granted, it's not a common occurrence, but it's difficult to handle any other way.

A Few Handy Queries

Below are some examples of situations you might find yourself in, and ways you can use RPM to get the information you need. Keep in mind that these are just examples. Don't be afraid to experiment!

Finding Config Files Based on a Program Name

You're setting up a new system, and you'd like to implement some system-wide aliases for people using the Bourne Again SHell, bash. The problem is you just can't remember the name of the system-wide initialization file used by bash, or where it resides:

# rpm -qcf /bin/bash

/etc/bashrc

#
          

Rather than spending time trying to hunt down the file, RPM finds it for you in seconds.

Learning More About an Uninstalled Package

Practically any option can be combined with -qp to extract information from a .rpm file. Let's say you have an unknown .rpm file, and you'd like to know a bit more before installing it:

# rpm -qpil foo.bar

Name        : rpm                  Distribution: Red Hat Linux Vanderbilt
Version     : 2.3                        Vendor: Red Hat Software
Release     : 1                      Build Date: Tue Dec 24 09:07:59 1996
Install date: (none)                 Build Host: porky.redhat.com
Group       : Utilities/System       Source RPM: rpm-2.3-1.src.rpm
Size        : 631157
Summary     : Red Hat Package Manager
Description :
RPM is a powerful package manager, which can be used to build, install,
query, verify, update, and uninstall individual software packages. A
package consists of an archive of files, and package information,
including name, version, and description.
/bin/rpm
/usr/bin/find-provides
/usr/bin/find-requires
/usr/bin/gendiff
/usr/bin/rpm2cpio
/usr/doc/rpm-2.3-1
…
/usr/src/redhat/SOURCES
/usr/src/redhat/SPECS
/usr/src/redhat/SRPMS

# 
          

By displaying the package information, we know that we have a package file containing RPM version 2.3. We can then peruse the file list, and see exactly what it would install before installing it.

Finding Documentation for a Specific Package

Picking on bash some more, you realize that your knowledge of the software is lacking. You'd like to see when it was installed on your system, and what documentation is available for it:

# rpm -qid bash

Name        :bash                   Distribution: Red Hat Linux (Picasso)
Version     :1.14.6                       Vendor: Red Hat Software
Release     :2                        Build Date: Sun Feb 25 13:59:26 1996
Install date:Mon May 13 12:47:22 1996 Build Host: porky.redhat.com
Group       :Shells                   Source RPM: bash-1.14.6-2.src.rpm
Size        :486557
Description :GNU Bourne Again Shell (bash)
/usr/doc/bash-1.14.6-2
/usr/doc/bash-1.14.6-2/NEWS
/usr/doc/bash-1.14.6-2/README
/usr/doc/bash-1.14.6-2/RELEASE
/usr/info/bash.info.gz
/usr/man/man1/bash.1

#
          

You never realized that there could be so much documentation for a shell!

Finding Similar Packages

Looking at bash's information, we see that it belongs to the group "Shells". You're not sure what other shell packages are installed on your system. If you can find other packages in the "Shells" group, you'll have found the other installed shells:

# rpm -qa --queryformat '%10{NAME} %20{GROUP}\n' | grep -i shells

       ash               Shells
      bash               Shells
       csh               Shells
        mc               Shells
      tcsh               Shells

#
          

Now you can query each of these packages, and learn more about them, too. [29]

Finding Recently Installed Packages, Part I

You remember installing a new package a few days ago. All you know for certain is that the package installed a new command in the /bin directory. Let's try to find the package:

# find /bin -type f -mtime -14 | rpm -qF

rpm-2.3-1

#
          

Looks like RPM version 2.3 was installed sometime in the last two weeks.

Finding Recently Installed Packages, Part II

Another way to see which packages were recently installed is to use the --queryformat option:

# rpm -qa --queryformat '%{installtime} %{name}-%{version}-%{release} %{installtime:date}\n' | sort -nr +1 | sed -e 's/^[^ ]* //'

rpm-devel-2.3-1 Thu Dec 26 23:02:05 1996
rpm-2.3-1 Thu Dec 26 23:01:51 1996
pgp-2.6.3usa-2 Tue Oct 22 19:39:09 1996
…
pamconfig-0.50-5 Tue Oct 15 17:23:22 1996
setup-1.5-1 Tue Oct 15 17:23:21 1996

#
          

By having RPM include the installation time in numeric form, it was simple to sort the packages and then use sed to remove the user-unfriendly numeric time.

Finding the Largest Installed Packages

Let's say that you're running low on disk space, and you'd like to see what packages you have installed, along with the amount of space each package takes up. You'd also like to see the largest packages first, so you can get back as much disk space as possible:

# rpm -qa --queryformat '%{name}-%{version}-%{release} %{size}\n' | sort -nr +1

kernel-source-2.0.18-5  20608472
tetex-0.3.4-3  19757371
emacs-el-19.34-1  12259914
…
rootfiles-1.3-1  3494
mkinitrd-1.0-1  1898
redhat-release-4.0-1  22

#
          

If you don't build custom kernels, or use TeX, it's easy to see how much space could be reclaimed by removing those packages.



[23] On most Linux systems, the file command can be used to obtain similar information. See Appendix A, Format of the RPM File for details on how to add this capability to your system's file command.

[24] Note to software packagers: Choose your build machine names wisely! A silly or offensive name might be embarrassing…

[25] For more information on rpmrc file entries, please refer to Appendix B, The rpmrc File.

[26] For more information on package verification, please see the section called “rpm -V — What Does it Do?”.

[27] RPM uses printf to do --queryformat formatting. Therefore, you can use any of the printf format modifiers discussed in the printf(3) man page.

[28] For more information on rpmrc file entries, see Appendix B, The rpmrc File.

[29] Did you see this example and say to yourself, "Hey, they could've used the -g option to query for that group directly"? If you did, you've been paying attention. This is a more general way of searching the RPM database for information: we just happened to search by group in this example.

Chapter 6. Using RPM to Verify Installed Packages

Table 6.1. rpm -V Command Syntax

rpm -V or (--verify, or -y) options
Package Selection Options Page
pkg1pkgN Verify named package(s) the section called “ The Package Label — Verify an Installed Package Against the RPM Database ”
-p <file> Verify against package file <file> the section called “ -p <file> — Verify Against a Specific Package File ”
-f <file> Verify package owning <file> the section called “ -f <file> — Verify the Package Owning <file> Against the RPM Database ”
-a Verify all installed packages the section called “ -a — Verify All Installed Packages Against the RPM Database ”
-g <group> Verify packages belonging to group <group> the section called “ -g <group> — Verify Packages Belonging To <group>
Verify-specific Options Page
--noscripts Do not execute verification script the section called “ --noscripts: Do Not Execute Verification Script ”
--nodeps Do not verify dependencies the section called “ --nodeps: Do Not Check Dependencies During Verification ”
--nofiles Do not verify file attributes the section called “ --nofiles: Do Not Verify File Attributes ”
General Options Page
-v Display additional information the section called “-v — Display Additional Information”
-vv Display debugging information the section called “-vv — Display Debugging Information”
--root <path> Set alternate root to <path> the section called “ --root <path>: Set Alternate Root to <path>
--rcfile <rcfile> Set alternate rpmrc file to <rcfile> the section called “ --rcfile <rcfile>: Set Alternate rpmrc file to <rcfile>
--dbpath <path> Use <path> to find the RPM database the section called “ --dbpath <path>: Use <path> To Find RPM Database ”

rpm -V — What Does it Do?

From time to time, it's necessary to make sure that everything on your system is "OK". Are you sure the packages you've installed are still configured properly? Have there been any changes made that you don't know about? Did you mistakenly start a recursive delete in /usr and now have to assess the damage?

RPM can help. It can alert you to changes made to any of the files installed by RPM. Also, if a package requires capabilities provided by another package, it can make sure the other package is installed, too.

The command rpm -V (The options -y and --verify are equivalent) verifies an installed package. Before we see how this is done, let's take a step back and look at the big picture.

Every time a package is installed, upgraded, or erased, the changes are logged in RPM's database. It's necessary for RPM to keep track of this information; otherwise it wouldn't be able to perform these operations correctly. You can think of the RPM database (and the disk space it consumes) as being the "price of admission" for the easy package management that RPM provides. [30]

The RPM database reflects the configuration of the system on which it resides. When RPM accesses the database to see how files should be manipulated during an install, upgrade, or erase, it is using the database as a mirror of the system's configuration.

However, we can also use the system configuration as a mirror of the RPM database. What does this "backward" view give us? What purpose would be served?

The purpose would be to see if the system configuration accurately reflects the contents of the RPM database. If the system configuration doesn't match the database, then we can reach one of two conclusions:

  1. The RPM database has become corrupt. The system configuration is unchanged.

  2. The RPM database is intact. The system configuration has changed.

While it would be foolish to state that an RPM database has never become corrupt, it is a sufficiently rare occurrence that the second conclusion is much more likely. So RPM gives us a powerful verification tool, essentially for free.

What Does it Verify?

It would be handy if RPM did nothing more than verify that every file installed by a package actually exists on your system. In reality, RPM does much more. It makes sure that if a package depends on other packages to provide certain capabilities, the necessary packages are, in fact, installed. If the package builder created one, RPM will also run a special verification script that can verify aspects of the package's installation that RPM cannot.

Finally, every file installed by RPM is examined. No less than nine different attributes of each file can be checked. Here is the list of attributes:

  • Owner

  • Group

  • Mode

  • MD5 Checksum

  • Size

  • Major Number

  • Minor Number

  • Symbolic Link String

  • Modification Time

Let's take a look at each of these attributes and why they are good things to check:

File Ownership

Most operating systems today keep track of each file's creator. This is done primarily for resource accounting. Linux and UNIX also use file ownership to help determine access rights to the file. In addition, some files, when executed by a user, can temporarily change the user's ID, normally to a more privileged ID. Therefore, any change of file ownership may have far reaching effects on data security and system availability.

File Group

In a similar manner to file ownership, a "group" specification is attached to each file. Primarily used for determining access rights, a file's group specification can also become a user's group ID, should that user execute the file's contents. Therefore, any changes in a file's group specification are important, and should be monitored.

File Mode

Encompassing the file's "permissions", the mode is a set of bits that specifies permitted access for the file's owner, group members, and everyone else. Even more important are two additional bits that determine whether a user's group or user ID should be changed if they execute the program contained in the file. Since these little bombshells can let any user become root for the duration of the program, it pays to be extra careful with a file's permissions.

MD5 Checksum

The MD5 checksum of a file is simply a 128-bit number that is mathematically derived from the contents of the file. The MD5 algorithm was designed by Ron Rivest, the "R" in the popular RSA public-key encryption algorithm. The "MD" in "MD5" stands for Message Digest, which is a pretty accurate description of what it does.

Unlike literary digests, an MD5 checksum conveys no information about the contents of the original file. However, it possesses one unique trait:

  • Any change to the file, no matter how small, results in a change to the MD5 checksum. [31]

RPM creates MD5 checksums of all files it manipulates, and stores them in its database. For all intents and purposes, if one of these files is changed, the MD5 checksum will change, and RPM will detect it.

File Size

As if the use of MD5 isn't enough, RPM also keeps track of file sizes. A difference of even one byte more or less will not go unnoticed.

Major Number

Device character and block files possess a major number. The major number is used to communicate information to the device driver associated with the special file. For instance, under Linux the special files for SCSI disk drives should have a major number of 8, while the major number for an IDE disk drive's special file would be 3. As you can imagine, any change to a file's major number can have disastrous effects, and is tracked by RPM.

Minor Number

A file's minor number is similar in concept to the major number, but conveys different information to the device driver. In the case of disk drives, this information can consist of a unit identifier. Should the minor number change, RPM will detect it.

Symbolic Link

If the file in question is really a symbolic link, the text string containing the name of the linked-to file is checked.

Modification Time

Most operating systems keep track of the date and time that a file was last modified. RPM uses this to its advantage by keeping modification times in its database.

When Verification Fails — rpm -V Output

When verifying a package, RPM produces output only if there is a verification failure. When a file fails verification, the format of the output is a bit cryptic, but it packs all the information you need into one line per file. Here is the format:


SM5DLUGT c <file>

        

Where:

  • S is the file size.

  • M is the file's mode.

  • 5 is the MD5 checksum of the file.

  • D is the file's major and minor numbers.

  • L is the file's symbolic link contents.

  • U is owner of the file.

  • G is the file's group.

  • T is the modification time of the file.

  • c appears only if the file is a configuration file. This is handy for quickly identifying config files, as they are very likely to change, and therefore, very unlikely to verify successfully.

  • <file> is the file that failed verification. The complete path is listed to make it easy to find.

It's unlikely that every file attribute will fail to verify, so each of the eight attribute flags will only appear if there is a problem. Otherwise, a "." will be printed in that flag's place. Let's look at an example or two:


.M5....T   /usr/X11R6/lib/X11/fonts/misc/fonts.dir

        

In this case, the mode, MD5 checksum, and modification time for the specified file have failed to verify. The file is not a config file (Note the absence of a "c" between the attribute list and the filename).


S.5....T c /etc/passwd

        

Here, the size, checksum, and modification time of the system password file have all changed. The "c" indicates that this is a config file.


missing    /var/spool/at/spool

        

This last example illustrates what RPM does when a file, that should be there, is missing entirely.

Other Verification Failure Messages

When rpm -V finds other problems, the output is a bit easier to understand:

# rpm -V blather

Unsatisfied dependencies for blather-7.9-1: bother >= 3.1

#
          

It's pretty easy to see that the blather package requires at least version 3.1 of the bother package.

The output from a package's verification script is a bit harder to categorize, as the script's contents, as well as its messages, are entirely up to the package builder.

Selecting What to Verify, and How

There are several ways to verify packages installed on your system. If you've taken a look at RPM's query command, you'll find that many of them are similar. Let's start with the simplest method of specifying packages — the package label.

The Package Label — Verify an Installed Package Against the RPM Database

You can simply follow the rpm -V command with all or part of a package label. As with every other RPM command that accepts package labels, you'll need to carefully specify each part of the label you include. Keep in mind that package names are case-sensitive, so rpm -V PackageName and rpm -V packagename are not the same. Let's verify the initscripts package:

# rpm -V initscripts
# 
          

While it looks like RPM didn't do anything, the following steps were performed:

  • For every file in the package, RPM checked the nine file attributes that were discussed above.

  • If the package was built with dependencies, the RPM database was searched to ensure the packages that satisfy those dependencies were installed.

  • If the package was built with a verification script, that script was executed.

In our example, each of these steps was performed without error — the package verified successfully. Remember, with rpm -V you'll only see output if a package fails to verify.

-a — Verify All Installed Packages Against the RPM Database

If you add -a to rpm -V, you can easily verify every installed package on your system. It might take a while, but when it's done, you'll know exactly what's been changed on your system:

# rpm -Va

.M5....T   /usr/X11R6/lib/X11/fonts/misc/fonts.dir
missing    /var/spool/at/.lockfile
missing    /var/spool/at/spool
S.5....T   /usr/lib/rhs/glint/icon.pyc
..5....T c /etc/inittab
..5.....   /usr/bin/loadkeys

#
          

Don't be too surprised if rpm -Va turns up a surprising number of files that failed verification. RPM's verification process is very strict! In many cases, the changes flagged don't indicate problems — they are only an indication of your system's configuration being different than what the builders of the installed packages had on their system. Also, some attributes change during normal system operation. However, it would be wise to check into each verification failure, just to make sure.

-f <file> — Verify the Package Owning <file> Against the RPM Database

Imagine this: you're hard at work when a program you've used a million times before suddenly stops working. What do you do? Well, before using RPM, you probably tried to find other files associated with that program and see if they had changed recently.

Now you can let RPM do at least part of that sleuthing for you. Simply direct RPM to verify the package owning the ailing program:

% rpm -Vf /sbin/cardmgr

S.5....T c /etc/sysconfig/pcmcia

% 
          

Hmmmm. Looks like a config file was recently changed.

This isn't to say that using RPM to verify a package will always get you out of trouble, but it's such a quick step it should be one of the first things you try. Here's an example of rpm -Vf not working out as well:

% rpm -Vf /etc/blunder

file /etc/blunder is not owned by any package

% 
          

(Note that the issue surrounding RPM and symbolic links mentioned in the section called “A Tricky Detail” also applies to rpm -Vf. Watch those symlinks!)

-p <file> — Verify Against a Specific Package File

Unlike the previous options to rpm -V, each of which verified one or more packages against RPM's database, the -p option performs the same verification, but against a package file. Why on earth would you want to do this when the RPM database is sitting there just waiting to be used?

Well, what if you didn't have an RPM database? While it isn't a common occurrence, power failures, hardware problems, and inadvertent deletions (along with non-existent backups) can leave your system "sans database". Then your system hiccups — what do you do now?

This is where a CD full of package files can be worth its weight in gold. Simply mount the CD and verify to your heart's content:

# rpm -Vp /mnt/cdrom/RedHat/RPMS/i386/adduser-1.1-1.i386.rpm
#
          

Whatever else might be wrong with this system, at least we can add new users. But what if you have many packages to verify? It would be a very slow process doing it one package at a time. That's where the next option comes in handy…

-g <group> — Verify Packages Belonging To <group>

When a package is built, the package builder must classify the package, grouping it with other packages that perform similar functions. RPM gives you the ability to verify installed packages based on their groups. For example, there is a group known as Shells. This group consists of packages that contain, strangely enough, shells. Let's verify the proper installation of every shell-related package on the system:

# rpm -Vg Shells

missing    /etc/bashrc

#
          

One thing to keep in mind is that group specifications are case-sensitive. Issuing the command rpm -Vg shells wouldn't verify many packages:

# rpm -Vg shells

group shells does not contain any packages

#
          

--nodeps: Do Not Check Dependencies During Verification

When the --nodeps option is added to a verify command, RPM will bypass its dependency verification processing. In this example, we've added the -vv option to so we can watch RPM at work:

# rpm -Vvv rpm

D: opening database in //var/lib/rpm/
D: verifying record number 2341208
D: dependencies: looking for libz.so.1
D: dependencies: looking for libdb.so.2
D: dependencies: looking for libc.so.5

#
          

As we can see, there are three different capabilities that the rpm package requires:

  • libz.so.1

  • libdb.so.2

  • libc.so.5

If we add the --nodeps option, the dependency verification of the three capabilities is no longer performed:

# rpm -Vvv --nodeps rpm

D: opening database in //var/lib/rpm/
D: verifying record number 2341208

#
          

The line D: verifying record number 2341208 indicates that RPM's normal file-based verification proceeded normally.

--noscripts: Do Not Execute Verification Script

Adding the --noscripts option to a verify command prevents execution of the verification scripts of each package being verified. In the following example, the package verification script is executed:

# rpm -Vvv bother

D: opening database in //var/lib/rpm/
D: verifying record number 616728
D: verify script found - running from file /var/tmp/rpm-321.vscript
+ PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin
+ export PATH
+ echo This is the bother 3.5 verification script
This is the bother 3.5 verification script

#
          

While the actual script is not very interesting, it did execute when the package was being verified. In the next example, we'll use the --noscripts option to prevent its execution:

# rpm -Vvv --noscripts bother

D: opening database in //var/lib/rpm/
D: verifying record number 616728

#
          

As expected, the output is identical to the prior example — minus the lines dealing with the verification script, of course.

--nofiles: Do Not Verify File Attributes

The --nofiles option disables RPM's file-related verification processing. When this option is used, only the verification script and dependency verification processing are performed. In this example, the package has a file-related verification problem:

# rpm -Vvv bash

D: opening database in //var/lib/rpm/
D: verifying record number 279448
D: dependencies: looking for libc.so.5
D: dependencies: looking for libtermcap.so.2
missing    /etc/bashrc

#
          

When the --nofiles option is added, the missing file doesn't cause a message any more:

# rpm -Vvv --nofiles bash

D: opening database in //var/lib/rpm/
D: verifying record number 279448
D: dependencies: looking for libc.so.5
D: dependencies: looking for libtermcap.so.2

#
          

This is not to say that the missing file problem is solved, just that no file verification was performed.

-v — Display Additional Information

Although RPM won't report an error with the command syntax if you include the -v option, you won't see much in the way of additional output:

# rpm -Vv bash
#
          

Even if there are verification errors, adding -v won't change the output:

# rpm -Vv apmd

S.5....T   /etc/rc.d/init.d/apm
S.5....T   /usr/X11R6/bin/xapm

#
          

The only time that the -v option will produce output is when the package being verified has a verification script. Any normal output from the script won't be displayed by RPM, when run without -v: [32]

# rpm -V bother
#
          

But when -v is added, the script's non-error-related output is displayed:

# rpm -Vv bother

This is the bother 3.5 verification script

#
          

If you're looking for more insight into RPM's inner workings, you'll have to try the next option:

-vv — Display Debugging Information

Sometimes it's necessary to have even more information than we can get with -v. By adding another v, that's just what we'll get:

# rpm -Vvv rpm

D: opening database in //var/lib/rpm/
D: verifying record number 2341208
D: dependencies: looking for libz.so.1
D: dependencies: looking for libdb.so.2
D: dependencies: looking for libc.so.5

#
          

The lines starting with D: have been added by using -vv. We can see where the RPM database is located and what record number contains information on the rpm-2.3-1 package. Following that is the list of dependencies that the rpm package requires.

In the vast majority of cases, it will not be necessary to use -vv. It is normally used by software engineers working on RPM itself, and the output can change without notice. However, it's a handy way to gain insights into RPM.

--dbpath <path>: Use <path> To Find RPM Database

In order for RPM to do its handiwork, it needs access to an RPM database. Normally, this database exists in the directory specified by the rpmrc file entry, dbpath. By default, dbpath is set to /var/lib/rpm.

Although the dbpath entry can be modified in the appropriate rpmrc file, the --dbpath option is probably a better choice when the database path needs to be changed temporarily. An example of a time the --dbpath option would come in handy is when it's necessary to examine an RPM database copied from another system. Granted, it's not a common occurrence, but it's difficult to handle any other way.

--root <path>: Set Alternate Root to <path>

Adding --root <path> to a verify command forces RPM to assume that the directory specified by <path> is actually the "root" directory. In addition, RPM expects its database to reside in the directory specified by the dbpath rpmrc file entry, relative to <path>. [33]

Normally this option is only used during an initial system install, or when a system has been booted off a "rescue disk", and some packages need to be re-installed in order to restore normal operation.

--rcfile <rcfile>: Set Alternate rpmrc file to <rcfile>

The --rcfile option is used to specify a file containing default settings for RPM. Normally, this option is not needed. By default, RPM uses /etc/rpmrc and a file named .rpmrc, located in your login directory.

This option would be used if there was a need to switch between several sets of RPM options. Software developer and package builders will be the people using --rcfile. For more information on rpmrc files, see Appendix B, The rpmrc File.

We've Lied to You…

Not really; we just omitted a few details until you've had a chance to see rpm -V in action. Here are the details:

RPM Controls What Gets Verified

Depending on the type of file being verified, RPM will not verify every possible attribute. Here is a table showing the attributes checked for each of the different file types:

Table 6.2. Verification Versus File Types

File Type File Size Mode MD5 Checksum Major Number Minor Number Symlink String Owner Group Modification Time
Directory File - X - -