Copyright © 2000 Red Hat, Inc.
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
<path>:
Relocate the package to
<path>, if possible
<rcfile>: Use
<rcfile> As An
Alternate rpmrc File
<path>: Use
<path> As An Alternate
Root
<path>: Use
<path> To Find RPM
Database
<port>: Use
<port> In FTP-based
Installs
<host>: Use
<host> As Proxy In
FTP-based Installs
<rcfile>
— Read
<rcfile> For RPM
Defaults
<path>
— Use <path>
As the Root
<path>: Use
<path> To Find RPM
Database
<file> —
Verify the Package Owning
<file> Against the
RPM Database
<file> —
Verify Against a Specific Package File
<group> —
Verify Packages Belonging To
<group>
<path>:
Use <path> To Find
RPM Database
<path>: Set
Alternate Root to
<path>
<rcfile>:
Set Alternate rpmrc file to
<rcfile>
<arch>
— Perform Build For the
<arch>
Architecture
<os>
— Perform Build For the
<os> Operating
System
<path>
— Execute %install using
<path> as the root
<secs>
— Print a warning if files to be packaged are over
<secs> old
<rcfile>
— Set alternate rpmrc file to
<rcfile>
rpmrc-Related Informationrpmrc Filerpmrc File Residesrpmrc File Syntaxrpmrc File EntriesList of Tables
Table of Contents
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?
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.
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
Table of Contents
<path>:
Relocate the package to
<path>, if possible
<rcfile>: Use
<rcfile> As An
Alternate rpmrc File
<path>: Use
<path> As An Alternate
Root
<path>: Use
<path> To Find RPM
Database
<port>: Use
<port> In FTP-based
Installs
<host>: Use
<host> As Proxy In
FTP-based Installs
<rcfile>
— Read
<rcfile> For RPM
Defaults
<path>
— Use <path>
As the Root
<path>: Use
<path> To Find RPM
Database
<file> —
Verify the Package Owning
<file> Against the
RPM Database
<file> —
Verify Against a Specific Package File
<group> —
Verify Packages Belonging To
<group>
<path>:
Use <path> To Find
RPM Database
<path>: Set
Alternate Root to
<path>
<rcfile>:
Set Alternate rpmrc file to
<rcfile>
Table of Contents
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:
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.
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.
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.
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.
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.
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?
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.
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:
Some package management systems concentrate on the specific steps required to manipulate a package.
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.
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 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.
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.
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.
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.
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.
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:
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.
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.
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.
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.
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.
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] .
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:
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.
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.
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.
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.
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]
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.
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”.
Table of Contents
<path>:
Relocate the package to
<path>, if possible
<rcfile>: Use
<rcfile> As An
Alternate rpmrc File
<path>: Use
<path> As An Alternate
Root
<path>: Use
<path> To Find RPM
Database
<port>: Use
<port> In FTP-based
Installs
<host>: Use
<host> As Proxy In
FTP-based Installs
Table 2.1. rpm -i Command Syntax
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:
Let's go through each of these steps in a bit more detail.
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.
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.
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.
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]
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.
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.
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.
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.
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.rpmPassword 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
”.
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.rpmwarning: /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:
It renames the original file to
cdp-config.rpmorig.
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.
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:
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.rpmInstalling 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 *.rpmInstalling 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!
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 *.rpmeject ################################################## iBCS ################################################## logrotate ###################################################
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:
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.rpmD: 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.
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.rpmfailed 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…
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.rpmInstalling 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.rpmInstalling 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.rpmInstalling cdp-0.33-2.i386.rpm#
Much better. The original package was replaced by a new copy of itself.
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.rpmInstalling 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.rpmInstalling 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 root34460Feb 25 14:27/usr/bin/cdp#
The package we just tried to install,
cdp-0.33- (note the
different release), also installs a file 3cdp 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.rpmInstalling 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 root34444Apr 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.
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
.
Let's give it a try:
<file>.rpmsave
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.rpmetcskel /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.rpmInstalling 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.rpmsavedrwxr-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.
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:
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.
At some point in the future, the second package is erased.
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.rpmInstalling cdp-0.33-2.i386.rpm#ls -al /usr/bin/cdp-rwxr-xr-x 1 root root34460Feb 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.rpmInstalling 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.rpmInstalling 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/cdpls: /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…
One day it'll happen. You'll be installing a new package, when suddenly, the install bombs:
#rpm -i blather-7.9-1.i386.rpmfailed 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.
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.
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:
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.rpmInstalling cdp-0.33-3.i386.rpm#ls -al /usr/man/man1/cdp.1ls: /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]
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.1ls: /usr/man/man1/cdp.1: No such file or directory#rpm -iv cdp-0.33-3.i386.rpmInstalling cdp-0.33-3.i386.rpm#ls /usr/man/man1/cdp.1ls: /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.1ls: /usr/man/man1/cdp.1: No such file or directory#rpm -iv --includedocs cdp-0.33-3.i386.rpmInstalling 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.
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
with
the name of the package file you want to check out. If the package is
not relocatable, you'll only see the word
<packagefile>(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*#
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.
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.
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.
Adding --root <path>
to an install command forces RPM to assume that the directory
specified by
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 <path>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
.
[12]
<path>
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 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.
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]
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]
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!
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
”.
Table of Contents
<rcfile>
— Read
<rcfile> For RPM
Defaults
<path>
— Use <path>
As the Root
<path>: Use
<path> To Find RPM
Database
Table 3.1. rpm -e Command Syntax
rpm -e (or --erase)
options pkg1 …
pkg
| ||
| Parameters | ||
pkg1 …
pkg
| 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
”
|
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!
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:
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 ejectD: 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.
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.
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 botherremoving 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 ejectD: 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.
It's likely that one day while erasing a package, you'll see something like this:
#rpm -e botherremoving 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.
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!
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.
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.
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.
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 -altotal 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.rpmsavedrwxr-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.
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.
Table of Contents
Table 4.1. rpm -U Command Syntax
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:
Installs the desired package.
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.
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:
The MD5 checksum of the file when it was originally installed. We'll call this the original file.
The MD5 checksum of the file as it exists at upgrade time. We'll call this the current file.
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.
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.
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.
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.
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.
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
,
and prints a warning, so the user knows what happened:
<file>.rpmsave
warning: /etc/skel/.bashrc saved as /etc/skel/.bashrc.rpmsave
These five scenarios cover just about every possible circumstance, save one. The missing scenario?
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
,
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.
<file>.rpmorig
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.
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]
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"…
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.
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.rpmInstalling 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.rpmInstalling 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.
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.
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.rpmThis 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.rpmThis 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.rpmThis 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.rpmThis 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.
Table 5.1. rpm -q Command Syntax
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.
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:
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.
In earlier chapters, we discussed RPM's package label, a string that uniquely identifies every installed package. Every label contains three pieces of information:
The name of the packaged software.
The version of the packaged software.
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 libclibc-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.3rpm-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 LibCpackage LibC is not installed##rpm -q libpackage lib is not installed##rpm -q "lib*"package lib* is not installed##rpm -q libc-5package libc-5 is not installed##rpm -q libc-5.2.1package 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…
Want lots of information fast? Using the -a option, you can query every package installed on your system. For example:
#rpm -qaElectricFence-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 sysvSysVinit-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.
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/lsfileutils-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 .cshrcfile /home/ed/.cshrc is not owned by any package#
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/xtermfile /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:
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/xtermf: /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/xtermXFree86-3.1.2-5#
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 xtermXFree86-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.
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.barrpm-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.
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 Basesetup-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.
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-infokernel-2.0.18-5#
In this case, the only package that provides the
module-info capability is
kernel-2.0.18-5.
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-infokernelcfg-0.3-2#
There's only one package that requires
module-info —
kernelcfg-0.3-2.
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.
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 rpmName : 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:
The package file used to install the packaged software. This is sometimes called the binary package.
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…
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.
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.
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.)
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:
The list of files represents all the documentation and config files
that apply to the package owning /sbin/dump.
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:
normal — A file in the
normal state has not been
modified by installing another package on the system.
replaced — Files in the
replaced state have been
modified by installing another package on the system.
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.
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:
The netsharedpath
rpmrc file entry has been changed
from its default (null) value.
[25]
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 addusernormal /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.
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 foonlyindex#
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 libclibm.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!
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 rpmlibz.so.1 libdb.so.2 libc.so.5#
It's also possible that you'll come across something like this:
#rpm -q --requires blatherbother >= 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 botherno 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 botherbother-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).
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.
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 XFree86preinstall 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:
The preinstall script, which is executed just before the package's files are installed.
The postinstall script, which is executed just after the package's files are installed.
The preuninstall script, which is executed just before the package's files are removed.
The postuninstall script, which is executed just after the package's files are removed.
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!
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.
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!' rpmThis 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.
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' rpmThis is a test!#
Much better…
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' rpmrpm2.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' rpmrpm-2.3-1#
Now our format string outputs standard package labels.
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' rpmrpm- 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' rpmrpm-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.
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.
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' adduseradduser: /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' etcskeletcskel: (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' etcskeletcskel: /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]' etcskeletcskel: /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]' etcskeletcskel: /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]' etcskeletcskel: /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!
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]' etcskeletcskel: /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!
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 --querytagsRPMTAG_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.
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 rpmD: 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.
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.
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.
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.
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!
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.
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.barName : 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.
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 bashName :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!
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 shellsash Shells bash Shells csh Shells mc Shells tcsh Shells#
Now you can query each of these packages, and learn more about them, too. [29]
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 -qFrpm-2.3-1#
Looks like RPM version 2.3 was installed sometime in the last two weeks.
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.
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 +1kernel-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.
Table of Contents
<file> —
Verify the Package Owning
<file> Against the
RPM Database
<file> —
Verify Against a Specific Package File
<group> —
Verify Packages Belonging To
<group>
<path>:
Use <path> To Find
RPM Database
<path>: Set
Alternate Root to
<path>
<rcfile>:
Set Alternate rpmrc file to
<rcfile>
Table 6.1. rpm -V Command Syntax
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:
The RPM database has become corrupt. The system configuration is unchanged.
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.
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:
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.
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.
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.
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.
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.
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.
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.
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.
is the file that failed verification. The complete path is listed
to make it easy to find.
<file>
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.
When rpm -V finds other problems, the output is a bit easier to understand:
#rpm -V blatherUnsatisfied 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.
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.
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.
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.
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/cardmgrS.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/blunderfile /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!)
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…
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 Shellsmissing /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 shellsgroup shells does not contain any packages#
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 rpmD: 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 rpmD: 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.
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 botherD: 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 botherD: 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.
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 bashD: 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 bashD: 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.
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 apmdS.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 botherThis 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:
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 rpmD: 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.
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.
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.
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.