Библиотека сайта rus-linux.net
Maximum RPM: Taking the Red Hat Package Manager to the Limit | ||
---|---|---|
Prev | Chapter 5. Getting Information About Packages | Next |
The Parts of an RPM Query
It becomes easy to construct a query command once you understand the individual parts. First is the -q (You can also use --query, if you like). After all, you need to tell RPM what function to perform, right? The rest of a query command consists of two distinct parts: package selection (or what packages you'd like to query), and information selection (or what information you'd like to see). Let's take a look at package selection first:
Query Commands, Part One: Package Selection
The first thing you'll need to decide when issuing an RPM query is what package (or packages) you'd like to query. RPM has several ways to specify packages, so you have quite an assortment to choose from.
The Package Label
In earlier chapters, we discussed RPM's package label, a string that uniquely identifies every installed package. Every label contains three pieces of information:
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.
|
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.
|
|
As you can see, RPM is case sensitive about package names and cannot
match partial names, version numbers, or release numbers. Nor can
it use the wildcard characters we've come to know and love. As
we've seen, however, RPM can perform the query when more than one
field of the package label is present. In the above case,
rpm -q libc-5.2.18, or even rpm -q
libc-5.2.18-1 would have found the package,
libc-5.2.18-1
.
Querying based on package labels may seem a bit restrictive. After all, you need to know the exact name of a package in order to perform a query on it. But there are other ways of specifying packages…
-a — Query All Installed Packages
|
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.
|
SysVinit
package, even though we didn't have
the complete package name, or capitalization.
-f <file>
— Query the Package Owning
<file>
/bin
(Okay, it
is a contrived example). Wonder what package
installed it? Simple!
|
|
A Tricky Detail
|
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.
|
/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/xterm
f: /usr/X11/bin/xterm d / d usr l X11 -> X11R6 d X11R6 d bin - xterm
#
It's pretty easy to see theX11
toX11R6
symlink. Using this approach you can enter the non-symlinked path and get the desired results:#
rpm -qf /usr/X11R6/bin/xterm
XFree86-3.1.2-5
#
- Change your directory to the one holding the file you want to query. Even if you use a symlinked path to get there, querying the file should then work as you'd expect:
#
cd /usr/X11/bin
#
rpm -qf xterm
XFree86-3.1.2-5
#
-p <file>
— Query a Specific RPM Package File
Up to now, every means of specifying a package to an RPM query focused on packages that had already been installed. While it's certainly very useful to be able to dredge up information about packages that are already on your system, what about packages that haven't yet been installed? The -p option can do that for you.
|
The -p option can also use Uniform Resource Locators to specify package files. See the section called URLs — Another Way to Specify Package Files in Chapter 2 for more information on using URLs.
|
-g <group>
: Query
Packages Belonging To Group
<group>
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:
|
--whatprovides <x>
:
Query the Packages That Provide Capability
<x>
RPM provides extensive support for dependencies between packages. The basic mechanism used is that a package may require what another package provides. The thing that is required and provided can be a shared library's soname. It can also be a character string chosen by the package builder. In any case, it's important to be able to display which packages provide a given capability.
|
module-info
capability is
kernel-2.0.18-5
.
--whatrequires <x>
:
Query the Packages That Require Capability
<x>
module-info
capability:
|
module-info
—
kernelcfg-0.3-2
.
Query Commands, Part Two: Information Selection
After specifying the package (or packages) you wish to query, you'll need to figure out just what information you'd like RPM to retrieve. As we've seen, by default, RPM only returns the complete package label. But there's much more to a package than that. Here, we'll explore every information selection option available to us.
-i — Display Package Information
|
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. [2]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.
-l — Display the Package's File List
Adding -l to rpm -q tells RPM to display the list of files that are installed by the specified package or packages. If you've used ls before, you won't be surprised by RPM's file list.
adduser
:
|
adduser
package consists of only one file,
so there's only one filename displayed.
-v — Display Additional Information
|
-c — Display the Package's List of Configuration Files
XFree86
:
|
|
-d — Display a List of the Package's Documentation
|
Let's take that alphabet soup set of options, one letter at a time:
q — Perform a query.
d — List all documentation files.
c — List all config files.
f — Query the package that owns the specified file (
/sbin/dump
, in this case).
/sbin/dump
.
-s — Display the State of Each File in the Package
Unlike the past three sections, which dealt with a list of files of one type or another, adding -s to a query will list the state of the files that comprise one or more packages. I can hear you out there; you're saying, "What is the state of a file?" For every file that RPM installs, there is an associated state. There are four possible states:
normal
— A file in thenormal
state has not been modified by installing another package on the system.replaced
— Files in thereplaced
state have been modified by installing another package on the system.not installed
— A file is classified asnot 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 benot installed
.net shared
— Thenet 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. Thenet 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 thenet shared
state when two things happen:The netsharedpath
rpmrc
file entry has been changed from its default (null) value. [3]The file is to be installed in a directory within a net shared path.
|
normal
at the start of the
line is the state, followed by the file name)
The file state is one of the tools RPM uses to determine the most appropriate action to take when packages are installed or erased.
Now would the average person need to check the states of files? Not really. But if there should be problems, this kind of information can help get things back on track.
--provides: Display Capabilities Provided by the Package
|
|
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:
|
/lib
, capabilities are a property of the
package, not a file contained in the package!
--requires: Display Capabilities Required by the Package
|
|
|
bother
package is required by
blather
; specifically, a version of
bother
greater than or equal to 3.1.
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:
|
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
:
|
bother
package provides, we come up dry:
|
The reason for the lack of output is that all packages, by default, "provide" their package name (and version).
--dump: Display All Verifiable Information for Each File
|
What does all this stuff mean? Let's go through it, item-by-item:
The
/usr/sbin/adduser
is simple: it's the name of the file being dump'ed.4442
is the size of the file, in bytes.How about
841083888
? It's the time the file was last modified, in seconds past the Unix zero date of January 1, 1970.The
ca5fa53dc74952aa5b5e3a5fa5d8904b
is the MD5 checksum of the file's contents, all 128 bits of it.If you guessed
0100755
was the file's mode, you'd be right.The first
root
represents the file's owner.The second
root
is the file's group.We'll take the next part (
0 0
) in one chunk. The first zero shows whether the file is a config file. If zero, as in this case, then the file is not a config file. The next zero shows whether the file is documentation. Again, since there is a zero here, this file isn't documentation, either.The final
0
represents the file's major and minor numbers. These are set only for device special files. Otherwise, it will be zero.If the file were a symlink, the spot taken by the
X
would contain a path pointing to the linked file.
Normally, the --dump option is used by people that want to extract the file-related information from RPM and process it somehow.
--scripts — Show Scripts Associated With a Package
|
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. [4]
Is this something you'll need very often? As in the case of displaying file states, not really. But when you need it, you really need it!
--queryformat — Construct a Custom Query Response
OK, say you're still not satisfied. You'd like some additional information, or you think a different format would be easier on the eyes. Maybe you want to take some information on the packages you've installed and run it through a script for some specialized processing. You can do it, using the --queryformat option. In fact, if you look back at the output of the -i option, RPM was using --queryformat internally. Here's how it works:
On the RPM command line, include --queryformat.
Right after that, enter a format string, enclosed in single quotes
"'
".
The format string can consist of a number of different components:
Literal text, including escape sequences.
Tags, with optional field width, formatting, and iteration information.
Array Iterators.
Let's look at each of these components.
Literal text
|
The RPM command might look a little unusual, but if you take out
the --queryformat option, along with its format
string, you'll see this is just an ordinary query of the
rpm
package. When the
--queryformat option is present, RPM will use
the text immediately following the option as a format string. In
our case, the format string is 'This is a
test!'. The single quotes are required. Otherwise,
it's likely your shell will complain about some of the characters
contained in the average format string.
The output of this command appears on the second line. As we can see, the literal text from the format string was printed exactly as it was entered.
Carriage Control Escape Sequences
Wait a minute. What is that #
doing at the end of the output? Well, that's our shell prompt.
You see, we didn't direct RPM to move to a new line after
producing the output, so the shell prompt ended up being tacked to
the end of our output.
Is there a way to fix that? Yes, there is. We need to use an escape sequence. An escape sequence is a sequence of characters that starts with a backslash (\). Escape sequences add carriage control information to a format string. The following escape sequences can be used:
\a — Produces a bell or similar alert.
\b — Backspaces one character.
\f — Outputs a form-feed character.
\n — Outputs a newline character sequence.
\r — Outputs a carriage return character.
\t — Causes a horizontal tab.
\v — Causes a vertical tab.
\\ — Displays a backslash character.
|
Tags
The most important parts of a format string are the tags. Each tag specifies what information is to be displayed and can optionally include field-width, as well as justification and data formatting instructions. [5] 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.
|
|
Field Width and Justification
|
|
Now the version is printed at the far left of the output field. You might be wondering what would happen if the field width specification didn't leave enough room for the data being printed. The field width specification can be considered the minimum width the field will take. If the data being printed is wider, the field will expand to accommodate the data.
Modifiers — Making Data More Readable
|
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.
|
Here's a list of the available modifiers:
The :date modifier displays dates in human-readable form. It transforms
846027549
intoTue 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, ad
if the file has been marked as being a documentation file, and blank otherwise. Thus,2
becomesd
.
Array Iterators
Until now, we've been using tags that represent single data items. There is, for example, only one package name or installation date for each package. However, there are other tags that can represent many different pieces of data. One such tag is FILENAMES, which can be used to display the names of every file contained in a package.
adduser
package first,
since it contains only one file:
|
|
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.
|
|
|
|
Iterating Single-Entry Tags
|
In Case You Were Wondering…
|
%{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.
Getting a lot more information with -vv
|
The lines starting with D:
have been
added by using -vv. We can see where the RPM
database is located and what record number contains information on the
rpm-2.3-1
package. Following that is the usual
output.
In the vast majority of cases, it will not be necessary to use -vv. It is normally used by software engineers working on RPM itself, and the output can change without notice. However, it's a handy way to gain insights into RPM's inner workings.
--root <path>
: Use
<path>
As An
Alternate Root
Adding --root <path>
to a query command forces RPM to assume that the directory specified
by <path>
is actually
the "root" directory. In addition, RPM expects its database to reside
in the directory specified by the dbpath
rpmrc
file entry, relative to
<path>
.
[6]
Normally this option is only used during an initial system install, or when a system has been booted off a "rescue disk", and some packages need to be re-installed in order to restore normal operation.
--rcfile <rcfile>
: Use
<rcfile>
As An
Alternate rpmrc
File
The --rcfile option is used to specify a file
containing default settings for RPM. Normally, this option is not
needed. By default, RPM uses /etc/rpmrc
and a
file named .rpmrc
, located in your login
directory.
This option would be used if there was a need to switch between
several sets of RPM options. Software developer and package builders
will be the people using --rcfile. For more
information on rpmrc
files, see Appendix B.
--dbpath <path>
: Use
<path>
To Find RPM
Database
In order for RPM to do its handiwork, it needs access to an RPM
database. Normally, this database exists in the directory specified
by the rpmrc
file entry,
dbpath. By default, dbpath is
set to /var/lib/rpm
.
Although the dbpath entry can be modified in the
appropriate rpmrc
file, the
--dbpath option is probably a better choice when
the database path needs to be changed temporarily. An example of a
time the --dbpath option would come in handy is
when it's necessary to examine an RPM database copied from another
system. Granted, it's not a common occurrence, but it's difficult to
handle any other way.
Notes
[1] | On most Linux systems, the file command can be used to obtain similar information. See Appendix A for details on how to add this capability to your system's file command. |
[2] | Note to software packagers: Choose your build machine names wisely! A silly or offensive name might be embarrassing… |
[3] | For more information on |
[4] | For more information on package verification, please see the section called rpm -V — What Does it Do? in Chapter 6. |
[5] | RPM uses |
[6] | For more information on |