rpm-guide/en_US rpm-guide-advanced-packaging.xml, NONE, 1.1 rpm-guide-command-reference.xml, NONE, 1.1 rpm-guide-creating-rpms.xml, NONE, 1.1 rpm-guide-customizing-rpm.xml, NONE, 1.1 rpm-guide-dependencies.xml, NONE, 1.1 rpm-guide-development-tools.xml, NONE, 1.1 rpm-guide-extra-packaging-tools.xml, NONE, 1.1 rpm-guide-intro-packaging.xml, NONE, 1.1 rpm-guide-intro-rpm.xml, NONE, 1.1 rpm-guide-licensing.xml, NONE, 1.1 rpm-guide-management-software.xml, NONE, 1.1 rpm-guide-online-resources.xml, NONE, 1.1 rpm-guide-other-linuxes.xml, NONE, 1.1 rpm-guide-other-os.xml, NONE, 1.1 rpm-guide-package-structure.xml, NONE, 1.1 rpm-guide-packaging-guidelines.xml, NONE, 1.1 rpm-guide-programming-c.xml, NONE, 1.1 rpm-guide-programming-perl.xml, NONE, 1.1 rpm-guide-programming-python.xml, NONE, 1.1 rpm-guide-rpm-evolution.xml, NONE, 1.1 rpm-guide-rpm-overview.xml, NONE, 1.1 rpm-guide-rpmbuild.xml, NONE, 1.1 rpm-guide-scripting.xml, NONE, 1.1 rpm-guide-specfile-syntax.xml, NONE, 1.1 rpm-guide-specfiles.xml, NONE, 1.1 rpm-guide-tr! ansactions.xml, NONE, 1.1 rpm-guide-using-rpm-db.xml, NONE, 1.1 rpm-guide-using-rpm.xml, NONE, 1.1 rpm-guide.xml, NONE, 1.1

Paul W. Frields (pfrields) fedora-docs-commits at redhat.com
Tue May 9 21:31:32 UTC 2006


Author: pfrields

Update of /cvs/docs/rpm-guide/en_US
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv24265/en_US

Added Files:
	rpm-guide-advanced-packaging.xml 
	rpm-guide-command-reference.xml rpm-guide-creating-rpms.xml 
	rpm-guide-customizing-rpm.xml rpm-guide-dependencies.xml 
	rpm-guide-development-tools.xml 
	rpm-guide-extra-packaging-tools.xml 
	rpm-guide-intro-packaging.xml rpm-guide-intro-rpm.xml 
	rpm-guide-licensing.xml rpm-guide-management-software.xml 
	rpm-guide-online-resources.xml rpm-guide-other-linuxes.xml 
	rpm-guide-other-os.xml rpm-guide-package-structure.xml 
	rpm-guide-packaging-guidelines.xml rpm-guide-programming-c.xml 
	rpm-guide-programming-perl.xml 
	rpm-guide-programming-python.xml rpm-guide-rpm-evolution.xml 
	rpm-guide-rpm-overview.xml rpm-guide-rpmbuild.xml 
	rpm-guide-scripting.xml rpm-guide-specfile-syntax.xml 
	rpm-guide-specfiles.xml rpm-guide-transactions.xml 
	rpm-guide-using-rpm-db.xml rpm-guide-using-rpm.xml 
	rpm-guide.xml 
Log Message:
Move XML files to proper naming conventions


--- NEW FILE rpm-guide-advanced-packaging.xml ---
<!-- $Id: -->

<chapter id="ch-advanced-packaging">
  <title>Advanced RPM Packaging</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Defining package dependency information
      </para>
    </listitem>
    <listitem>
      <para>
        Setting triggers
      </para>
    </listitem>
    <listitem>
      <para>
        Writing verification scripts
      </para>
    </listitem>
    <listitem>
      <para>
        Creating subpackages
      </para>
    </listitem>
    <listitem>
      <para>
        Creating relocatable packages
      </para>
    </listitem>
    <listitem>
      <para>
        Defining conditional builds
      </para>
    </listitem>
  </itemizedlist>
  <para>
    The previous chapter introduced the RPM spec file, which controls
    how RPM packages are built and installed. This chapter delves into
    advanced spec file topics such as using conditional commands and
    making relocatable packages, starting with how to specify package
    dependencies.
  </para>
  <sect1>
    <title>Defining Package Dependencies</title>
    <para>
      Dependencies are one of the most important parts of the RPM
      system. The RPM database tracks dependencies between packages to
      better allow you to manage your system. A dependency occurs when
      one package depends on another. The RPM system ensures that
      dependencies are honored when upgrading, installing, or removing
      packages. From that simple concept, RPM supports four types of
      dependencies:
    </para>
    <para>
      *Requirements, where one package requires a capability provided by
      another
    </para>
    <para>
      *Provides, a listing of the capabilities your package provides
    </para>
    <para>
      *Conflicts, where one package conflicts with a capability provided
      by another
    </para>
    <para>
      *Obsoletes, where one package obsoletes capabilities provided by
      another, usually used when a package changes name and the new
      package obsoletes the old name
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      <xref linkend="ch-dependencies"/>  covers more on dependencies. The Obsoletes dependencies
      are usually only used when a package is renamed, such as the
      apache package becoming the httpd package, starting in &RH;
      Linux 8.0. The httpd package obsoletes the apache package.
    </para>
    <para>
      You can list all of these dependencies in your spec file. The most
      commonly used dependency information, though, is what a package
      requires.
    </para>
    <sect2>
      <title>Naming dependencies</title>
      <para>
        In your spec files, you can name the dependencies for your
        package. The basic syntax is:
      </para>
      <para>
        Requires: capability
      </para>
      <para>
        In most cases, the capability should be the name of another
        package. This example sets up a requires dependency. This means
        that the package requires the given capability. Use a similar
        syntax for the other kinds of dependencies:
      </para>
      <para>
        Provides: capability
      </para>
      <para>
        Obsoletes: capability
      </para>
      <para>
        Conflicts: capability
      </para>
      <para>
        You can put more than one capability on the dependency line. For
        example:
      </para>
      <para>
        Requires: bash perl
      </para>
      <para>
        You can use spaces or commas to separate the capabilities. For
        example:
      </para>
      <para>
        Requires: bash, perl
      </para>
      <sect3>
        <title>Specifying the Version of the Dependencies</title>
        <para>
          You can also add version information, for example:
        </para>
        <para>
          Requires: bash >= 2.0
        </para>
        <para>
          This states that the package requires the capability bash (a
          package) at version 2.0 or higher. The same logic applies to
          the other types of dependencies. For example:
        </para>
        <para>
          Conflicts: bash >= 2.0
        </para>
        <para>
          This example states that the package conflicts with all
          versions of bash 2.0 or higher.
        </para>
        <para>
          Table 11-1 lists the version comparisons you can use.
        </para>
        <para>
          Table 11-1 Dependency version comparisons
        </para>
        <informaltable frame="all">
          <tgroup cols="2">
            <tbody>
              <row>
                <entry>
                  <para>
                    Comparison
                  </para>
                </entry>
                <entry>
                  <para>
                    Meaning
                  </para>
                </entry>
              </row>
              <row>
                <entry>
                  <para>
                    package < version
                  </para>
                </entry>
                <entry>
                  <para>
                    A package with a version number less than version
                  </para>
                </entry>
              </row>
              <row>
                <entry>
                  <para>
                    package > version
                  </para>
                </entry>
                <entry>
                  <para>
                    A package with a version number greater than version
                  </para>
                </entry>
              </row>
              <row>
                <entry>
                  <para>
                    package >= version
                  </para>
                </entry>
                <entry>
                  <para>
                    A package with a version number greater than or
                    equal to version
                  </para>
                </entry>
              </row>
              <row>
                <entry>
                  <para>
                    package <= version
                  </para>
                  <para/>
                </entry>
                <entry>
                  <para>
                    A package with a version number less than or equal
                    to version
                  </para>
                </entry>
              </row>
              <row>
                <entry>
                  <para>
                    package = version
                  </para>
                </entry>
                <entry>
                  <para>
                    A package with a version number equal to version
                  </para>
                </entry>
              </row>
              <row>
                <entry>
                  <para>
                    package
                  </para>
                </entry>
                <entry>
                  <para>
                    A package at any version number
                  </para>
                </entry>
              </row>
            </tbody>
          </tgroup>
        </informaltable>
        <para>
          RPM supports an extended version number syntax for
          comparisons. The full format follows:
        </para>
        <para>
          Epoch:Version-Release
        </para>
        <para>
          For example:
        </para>
        <para>
          1:5.6.0-17
        </para>
        <para>
          In this case, the epoch is 1, the version 5.6.0, and the
          release is 17. In most cases, you will need just the version
          number. The epoch allows for handling hard-to-compare version
          numbers. The release number is almost never used. This makes
          sense, in that it ties a dependency to a particular build of
          the RPM package, rather than a version of the software itself.
          This type of dependency would only be useful if you
          drastically changed the way you build a package.
        </para>
      </sect3>
      <sect3>
        <title>Creating Virtual CAPABILITIES</title>
        <para>
          Dependencies are based on capabilities, most of which are
          packages. You can create virtual capabilities, which are just
          names you define. For example, the sendmail package provides a
          virtual capability named smtpdaemon. For example:
        </para>
        <para>
          Provides: smtpdaemon
        </para>
        <para>
          This capability refers to the general SMTP Internet service
          for sending e-mail messages. There is no file of this name.
          Instead, it is just a capability, arbitrary text. Other
          packages require this capability, such as the fetchmail
          mail-retrieval and forwarding application, and mutt, an e-mail
          client program.
        </para>
        <para>
          By using a virtual capability, other packages can provide the
          capability, and most importantly, client applications can
          require the capability without worrying which package provides
          the ability to send e-mail messages. For example, the exim and
          postfix packages, mail transport agents like sendmail, can
          provide the same capability.
        </para>
        <para>
          Note
        </para>
        <para>
          Of course, you want to ensure that these packages specify that
          they conflict with each other.
        </para>
      </sect3>
      <sect3>
        <title>Naming Dependencies on Script Engines and Modules</title>
        <para>
          Scripting languages such as Perl and Tcl allow for add-on
          modules. Your package may require some of these add-on
          modules. RPM uses a special syntax with parenthesis to
          indicate script module dependencies. For example:
        </para>
        <para>
          Requires: perl(Carp) >= 3.2
        </para>
        <para>
          This indicates a requirement for the Carp add-on module for
          Perl, greater than or equal to version 3.2.
        </para>
      </sect3>
    </sect2>
    <sect2>
      <title>Setting prerequisites</title>
      <para>
        A prerequisite is similar to a require dependency, except that a
        prerequisite must be installed prior to a given package. Specify
        a prerequisite as follows:
      </para>
      <para>
        PreReq: capability
      </para>
      <para>
        You can include version-number dependencies, such as:
      </para>
      <para>
        PreReq: capability >= version
      </para>
      <para>
        In most usage, a PreReq: acts just like Requires:, in fact, the
        PreReq: directive exists just to allow for a manual order to
        dependencies. RPM guarantees that the PreReq: package will be
        installed prior to the package that names the PreReq:
        dependency.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-packaging-guidelines"/>  covers a common problem of handling circular
        dependencies using prerequisites.
      </para>
    </sect2>
    <sect2>
      <title>Naming build dependencies</title>
      <para>
        Your package, once built, has a set of dependencies. These
        dependencies are important for anyone installing the package.
        But there are also dependency issues when trying to build
        packages. Build dependencies allow you to specify what is
        necessary to build the package. While you may think this would
        be the same as what is needed to install a package, this is
        normally not true. Linux distributions tend to divide up
        software into runtime and development packages. For example, the
        python package contains the runtime for executing scripts
        written in Python. The python-devel package provides the ability
        to write extensions to the Python language.
      </para>
      <para>
        RPM allows you to define build-time dependencies in your spec
        files using the following directives:
      </para>
      <para>
        BuildRequires:
      </para>
      <para>
        BuildConflicts:
      </para>
      <para>
        BuildPreReq:
      </para>
      <para>
        These directives act like Requires:, Conflicts:, and PreReq:,
        respectively, except that the dependencies are needed to build
        the package, not install it. For example, your package may
        require a C compiler to build, or may need a special build tool
        or developer library.
      </para>
    </sect2>
    <sect2>
      <title>Generating dependencies automatically</title>
      <para>
        Because so many dependencies are related to shared libraries,
        the RPM system will automatically generate provide dependencies
        for any file in your packages that is a shared object, or .so,
        file. RPM will also automatically generate require dependencies
        for all files in the %files list that require shared libraries.
        To do this, RPM uses the ldd command, which determines the
        shared libraries used by an application.
      </para>
      <para>
        In addition, the find-requires and find-provides scripts in
        /usr/lib/rpm can determine Perl, Python and Tcl script
        dependencies and other dependencies, such as Java package
        dependencies, automatically. The find-requires script determines
        requires dependencies automatically, and the find-provides
        script determines provides dependencies.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-packaging-guidelines"/>  covers how to turn off the automatic generation of
        dependencies.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Setting Triggers</title>
    <para>
      Triggers provide a way for one package to take action when the
      installed status of another package changes. A trigger is a script
      you define in your package’s spec file that gets run by the RPM
      system when the status of another named package changes. If your
      package depends in some way on another package, a trigger can
      allow your package to deal with changes to the other package.
    </para>
    <para>
      Triggers are not a replacement for package dependencies. Instead,
      triggers are useful when you need to change a package’s
      installation based on other packages installed on the system. For
      example, if your package is a mail client program, your package
      will need to have a mail transfer agent, or MTA. Linux supports a
      number of different mail transfer agents, such as sendmail, vmail,
      exim, qmail, and postfix.
    </para>
    <para>
      Typically a system will have one mail transfer agent installed. In
      most cases, a mail client won’t care which MTA is installed, as
      long as one is installed. (In fact, most of these packages should
      be marked that they conflict with one another, ensuring that a
      given system can only have one.)
    </para>
    <para>
      The %triggerin script is run when a given target package is
      installed or upgraded. The %triggerin script is also run when your
      package is installed or upgraded, should the target package be
      already installed. Similarly, the %triggerun script is run if the
      target package is removed. It is also run if your package is
      removed and the target package is installed. The %triggerpostun
      script is run after the target package has been removed. It is not
      run if your package is removed.
    </para>
    <para>
      To define one of these scripts, you need to list the name of the
      target package; for example:
    </para>
    <para>
      %triggerin -- tcsh
    </para>
    <para>
      script commands...
    </para>
    <para>
      This example sets up a trigger for the tcsh package. If the tcsh
      package is installed or upgraded, RPM will run the script. If your
      package is installed or upgraded and the tcsh package is presently
      installed, RPM will also run the script.
    </para>
    <para>
      Define the %triggerun script similarly:
    </para>
    <para>
      %triggerun -- tcsh
    </para>
    <para>
      script commands...
    </para>
    <para>
      You can also use version numbers in the trigger script definition
      to only run the script in the case of a particular version. For
      example:
    </para>
    <para>
      %triggerpostun -- vixie-cron < 3.0.1-56
    </para>
    <para>
      /sbin/chkconfig --del crond
    </para>
    <para>
      /sbin/chkconfig --add crond
    </para>
    <para>
      This example, from the vixie-cron scheduling package, runs a
      post-uninstall trigger for the same package, but for older
      versions. To define trigger scripts for particular versions, use
      the same syntax as for requires dependencies for naming the
      version number and comparisons.
    </para>
    <para>
      Triggers are run through /bin/sh, the most commonly used shell
      script engine. With the -p option, though, you can specify a
      different script interpreter. For example, to write a Perl script,
      define your trigger like the following:
    </para>
    <para>
      %triggerpostun -p /usr/bin/perl -- vixie-cron < 3.0.1-56
    </para>
    <para>
      system("/sbin/chkconfig --del crond");
    </para>
    <para>
      system("/sbin/chkconfig --add crond");
    </para>
    <para>
      With subpackages, defined following, you can use a -n option to
      tie the trigger script to a subpackage. For example:
    </para>
    <para>
      %triggerpostun -n subpackage_name -- vixie-cron < 3.0.1-56
    </para>
    <para>
      /sbin/chkconfig --del crond
    </para>
    <para>
      /sbin/chkconfig --add crond
    </para>
    <para>
      Inside your trigger scripts, $1, the first command-line argument,
      holds the number of instances of your package that will remain
      after the operation has completed. The second argument, $2, holds
      the number of instances of the target package that will remain
      after the operation. Thus, if $2 is 0, the target package will be
      removed.
    </para>
    <para>
      The anonftp package, mentioned in <xref linkend="ch-dependencies"/> , has a lot of
      triggers. Many of these set up a number of commands to be locally
      available to the anonftp package. This networking package is also
      closely tied to the version of the C library, glibc, as shown in
      Listing 11-1
    </para>
    <para>
      Listing 11-1: Anonftp package trigger scripts.
    </para>
    <para>
      %triggerin -- glibc
    </para>
    <para>
      copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
      2>/dev/null |
    </para>
    <para>
      | cp -df "$file" "$2"; }
    </para>
    <para>
      # Kill off old versions
    </para>
    <para>
      rm -f /var/ftp/lib/ld-* /var/ftp/lib/libc* /var/ftp/lib/libnsl*
      /var/ftp/lib/lib
    </para>
    <para>
      nss_files* &>/dev/null || :
    </para>
    <para>
      # Copy parts of glibc, needed by various programs in bin.
    </para>
    <para>
      LIBCVER=`basename $(ls --sort=time /lib/libc-*.so |head -n 1) .so
      |cut -f2- -d-`
    </para>
    <para>
      copy /lib/ld-${LIBCVER}.so /var/ftp/lib
    </para>
    <para>
      copy /lib/libc-${LIBCVER}.so /var/ftp/lib
    </para>
    <para>
      copy /lib/libnsl-${LIBCVER}.so /var/ftp/lib
    </para>
    <para>
      copy /lib/libnss_files-${LIBCVER}.so /var/ftp/lib
    </para>
    <para>
      md5sum /var/ftp/lib/lib*-*.so /var/ftp/lib/libtermcap.so.*.*.*
      2>/dev/null >/var
    </para>
    <para>
      /ftp/lib/libs.md5
    </para>
    <para>
      chmod 0400 /var/ftp/lib/libs.md5
    </para>
    <para>
      # Use ldconfig to build symlinks and whatnot.
    </para>
    <para>
      [ ! -e /var/ftp/etc/ld.so.conf ] && touch
      /var/ftp/etc/ld.so.conf
    </para>
    <para>
      /sbin/ldconfig -r /var/ftp
    </para>
    <para/>
    <para>
      %triggerin -- fileutils
    </para>
    <para>
      copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
      2>/dev/null |
    </para>
    <para>
      | cp -df "$file" "$2"; }
    </para>
    <para>
      copy /bin/ls /var/ftp/bin
    </para>
    <para>
      md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
      >/var/ftp/bin/bin.md5
    </para>
    <para>
      chmod 0400 /var/ftp/bin/bin.md5
    </para>
    <para/>
    <para>
      %triggerin -- cpio
    </para>
    <para>
      copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
      2>/dev/null |
    </para>
    <para>
      | cp -df "$file" "$2"; }
    </para>
    <para>
      copy /bin/cpio /var/ftp/bin
    </para>
    <para>
      md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
      >/var/ftp/bin/bin.md5
    </para>
    <para>
      chmod 0400 /var/ftp/bin/bin.md5
    </para>
    <para/>
    <para>
      %triggerin -- tar
    </para>
    <para>
      copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
      2>/dev/null |
    </para>
    <para>
      | cp -df "$file" "$2"; }
    </para>
    <para>
      copy /bin/tar /var/ftp/bin
    </para>
    <para>
      md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
      >/var/ftp/bin/bin.md5
    </para>
    <para>
      chmod 0400 /var/ftp/bin/bin.md5
    </para>
    <para/>
    <para>
      %triggerin -- gzip
    </para>
    <para>
      copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
      2>/dev/null |
    </para>
    <para>
      | cp -df "$file" "$2"; }
    </para>
    <para>
      copy /bin/gzip /var/ftp/bin
    </para>
    <para>
      ln -sf gzip /var/ftp/bin/zcat
    </para>
    <para>
      md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
      >/var/ftp/bin/bin.md5
    </para>
    <para>
      chmod 0400 /var/ftp/bin/bin.md5
    </para>
    <para/>
    <para>
      %triggerin -- libtermcap
    </para>
    <para>
      copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
      2>/dev/null |
    </para>
    <para>
      | cp -df "$file" "$2"; }
    </para>
    <para>
      rm -f /var/ftp/lib/libtermcap.so.*.*.* &>/dev/null || :
    </para>
    <para>
      copy '/lib/libtermcap.so.*.*.*' /var/ftp/lib
    </para>
    <para>
      md5sum /var/ftp/lib/lib*-*.so /var/ftp/lib/libtermcap.so.*.*.*
      2>/dev/null >/var
    </para>
    <para>
      /ftp/lib/libs.md5
    </para>
    <para>
      chmod 0400 /var/ftp/lib/libs.md5
    </para>
    <para>
      # Use ldconfig to build symlinks and whatnot.
    </para>
    <para>
      [ ! -e /var/ftp/etc/ld.so.conf ] && touch
      /var/ftp/etc/ld.so.conf
    </para>
    <para>
      /sbin/ldconfig -r /var/ftp
    </para>
    <para/>
    <para>
      %triggerin -- ncompress
    </para>
    <para>
      copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
      2>/dev/null |
    </para>
    <para>
      | cp -df "$file" "$2"; }
    </para>
    <para>
      copy /usr/bin/compress /var/ftp/bin
    </para>
    <para>
      md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
      >/var/ftp/bin/bin.md5
    </para>
    <para>
      chmod 0400 /var/ftp/bin/bin.md5
    </para>
    <para/>
    <para>
      %triggerpostun -- anonftp 4.0
    </para>
    <para>
      if [ "$2" != 1 ] ; then
    </para>
    <para>
      # The user has multiple glibc packages installed. We can't read
      the
    </para>
    <para>
      # user's mind, so don't do anything.
    </para>
    <para>
      exit 0
    </para>
    <para>
      fi
    </para>
    <para>
      copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
      2>/dev/null |
    </para>
    <para>
      | cp -df "$file" "$2"; }
    </para>
    <para>
      # Kill off old versions
    </para>
    <para>
      rm -f /var/ftp/lib/ld-* /var/ftp/lib/libc* /var/ftp/lib/libnsl*
      /var/ftp/lib/lib
    </para>
    <para>
      nss_files* &>/dev/null || :
    </para>
    <para>
      # Copy parts of glibc, needed by various programs in bin.
    </para>
    <para>
      LIBCVER=`basename /lib/libc-*.so .so | cut -f2- -d-`
    </para>
    <para>
      copy /lib/ld-${LIBCVER}.so /var/ftp/lib
    </para>
    <para>
      copy /lib/libc-${LIBCVER}.so /var/ftp/lib
    </para>
    <para>
      copy /lib/libnsl-${LIBCVER}.so /var/ftp/lib
    </para>
    <para>
      copy /lib/libnss_files-${LIBCVER}.so /var/ftp/lib
    </para>
    <para>
      copy /bin/ls /var/ftp/bin
    </para>
    <para>
      copy /bin/cpio /var/ftp/bin
    </para>
    <para>
      copy /bin/tar /var/ftp/bin
    </para>
    <para>
      copy /bin/gzip /var/ftp/bin
    </para>
    <para>
      ln -sf gzip /var/ftp/bin/zcat
    </para>
    <para>
      copy /usr/bin/compress /var/ftp/bin
    </para>
    <para>
      rm -f /var/ftp/lib/libtermcap.so.*.*.* &>/dev/null || :
    </para>
    <para>
      copy '/lib/libtermcap.so.*.*.*' /var/ftp/lib
    </para>
    <para>
      # Use ldconfig to build symlinks and whatnot.
    </para>
    <para>
      [ ! -e /var/ftp/etc/ld.so.conf ] && touch
      /var/ftp/etc/ld.so.conf
    </para>
    <para>
      /sbin/ldconfig -r /var/ftp
    </para>
    <para>
      # Generate md5sums for verifyscript
    </para>
    <para>
      md5sum /var/ftp/lib/lib*-*.so /var/ftp/lib/libtermcap.so.*.*.*
      2>/dev/null >/var
    </para>
    <para>
      /ftp/lib/libs.md5
    </para>
    <para>
      chmod 0400 /var/ftp/lib/libs.md5
    </para>
    <para>
      md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
      >/var/ftp/bin/bin.md5
    </para>
    <para>
      chmod 0400 /var/ftp/bin/bin.md5
    </para>
  </sect1>
  <sect1>
    <title>Writing Verification Scripts</title>
    <para>
      RPM automatically handles package verification, checking to see
      that the proper files are installed, and testing the files
      themselves for the proper size and other attributes. You may need
      to do more in your package, though, to ensure everything is
      properly set up. With RPM, you can:
    </para>
    <para>
      *Control the tests used to verify each file, as described in
      <xref linkend="ch-specfiles"/> 
    </para>
    <para>
      *Create a verify script that performs other tests
    </para>
    <para>
      If you need to perform some other test to verify your package,
      such as check that a configuration file has a particular setting
      (and that the setting is valid), you can fill in the %verifyscript
      in the spec file. The %verifyscript acts much like the %pre or
      %post scripts, except that the %verifyscript gets executed during
      package verification. Fill in a %verifyscript as follows:
    </para>
    <para>
      %verifyscript
    </para>
    <para>
      your script commands ....
    </para>
    <para>
      Common %verifyscript actions are to check for an entry in a system
      configuration file, such as an init-time startup script or
      /etc/shells (which lists the available shells). These are files
      owned by other packages that may need to be properly modified for
      a package to be properly installed. If your package has a similar
      circumstance, write a %verifyscript. In your script, send all
      error output to stderr.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      See <xref linkend="ch-using-rpm-db"/>  for more on package verification.
    </para>
  </sect1>
  <sect1>
    <title>Creating Subpackages</title>
    <para>
      A spec file may define more than one package. This type of
      additional package is called a subpackage. Subpackages exist to
      handle cases where you don’t want to associate one spec file
      with one package. Instead, you can define multiple packages within
      the spec file, as needed. For example, you may want to build the
      runtime and developer packages together, or the client and server
      portions of an application using subpackages. Splitting large
      documentation sets into separate subpackages is also common.
    </para>
    <para>
      With subpackages, you get:
    </para>
    <para>
      *One spec file
    </para>
    <para>
      *One source RPM
    </para>
    <para>
      *One set of build commands
    </para>
    <para>
      *Multiple binary RPMs, one per package or subpackage
    </para>
    <para>
      In most cases, subpackages are created just as a means to
      partition the files produced by a package into separate packages.
      For example, you will often see development libraries and header
      files split into a separate package from the main application
      package. Sometimes documentation is split out into a separate
      package, or client and server applications are divided into
      separate packages. In the end, though, this usually results in
      shifting files into subpackages and nothing more.
    </para>
    <para>
      To define a subpackage within a spec file, you start with the
      %package directive. For example:
    </para>
    <para>
      %package sub_package_name
    </para>
    <para>
      By default, the name of the subpackage will be the name of the
      package, a dash, and the subpackage name provided with the
      %package directive. For example:
    </para>
    <para>
      %package server
    </para>
    <para>
      This example names a subpackage server, which is a real subpackage
      inside the telnet package. In this case, the name for the server
      subpackage will be telnet-server, that is, the naming format is
      package-subpackage.
    </para>
    <para>
      If you don’t want this naming format, you can use the –n
      option to the %package directive to define an entirely new name,
      using the following syntax:
    </para>
    <para>
      %package -n new_sub_package_name
    </para>
    <para>
      For example:
    </para>
    <para>
      %package –n my-telnet-server
    </para>
    <para>
      With the –n option, you specify the full name for the
      subpackage. The RPM system will not prefix the name with the
      enclosing package name.
    </para>
    <sect2>
      <title>Providing information for subpackages</title>
      <para>
        When you define a subpackage, you need to provide as many of the
        package information directives as you need, including at the
        least Summary:, Group:, and %description directives. Anything
        not specified will use the parent package’s value, such as the
        version. Place these directives after the %package directive.
        For example:
      </para>
      <para>
        %package server
      </para>
      <para>
        Requires: xinetd
      </para>
      <para>
        Group: System Environment/Daemons
      </para>
      <para>
        Summary: The server program for the telnet remote login
        protocol.
      </para>
      <para>
        The %description directive for subpackages requires the name of
        the subpackage using the following syntax:
      </para>
      <para>
        %description subpackage
      </para>
      <para>
        For example:
      </para>
      <para>
        %description server
      </para>
      <para>
        Telnet is a popular protocol for logging into remote systems
      </para>
      <para>
        over the Internet. The telnet-server package includes a telnet
        daemon that supports remote logins into the host machine. The
      </para>
      <para>
        telnet daemon is enabled by default. You may disable the telnet
      </para>
      <para>
        daemon by editing /etc/xinetd.d/telnet.
      </para>
      <para>
        If you used the –n option with the %package directive, you
        need to repeat the –n option with the %description directive.
        For example:
      </para>
      <para>
        %description –n my-telnet-server
      </para>
      <para>
        Telnet is a popular protocol for logging into remote systems
      </para>
      <para>
        over the Internet. The telnet-server package includes a telnet
        daemon that supports remote logins into the host machine. The
      </para>
      <para>
        telnet daemon is enabled by default. You may disable the telnet
      </para>
      <para>
        daemon by editing /etc/xinetd.d/telnet.
      </para>
      <para>
        The same concept works for the %files section. You need a
        separate %files section for each subpackage. For example:
      </para>
      <para>
        %files server
      </para>
      <para>
        %defattr(-,root,root)
      </para>
      <para>
        %{_sbindir}/in.telnetd
      </para>
      <para>
        %{_mandir}/man5/issue.net.5*
      </para>
      <para>
        %{_mandir}/man8/in.telnetd.8*
      </para>
      <para>
        %{_mandir}/man8/telnetd.8*
      </para>
      <para>
        Again, if you used the –n option with the %package directive,
        you need to repeat the –n option with the %files section. For
        example:
      </para>
      <para>
        %files –n my-telnet-server
      </para>
      <para>
        %defattr(-,root,root)
      </para>
      <para>
        %{_sbindir}/in.telnetd
      </para>
      <para>
        %{_mandir}/man5/issue.net.5*
      </para>
      <para>
        %{_mandir}/man8/in.telnetd.8*
      </para>
      <para>
        %{_mandir}/man8/telnetd.8*
      </para>
    </sect2>
    <sect2>
      <title>Defining scripts for subpackages</title>
      <para>
        Much as you define separate %files and %description sections for
        subpackages, you can also define install and uninstall scripts
        for subpackages. The syntax is similar to that for the %files
        and %description sections:
      </para>
      <para>
        %pre subpackage
      </para>
      <para>
        For example, Listing 11-2 shows the scripts from the VNC
        package.
      </para>
      <para>
        Listing 11-2: VNC package install and uninstall scripts.
      </para>
      <para>
        %post server
      </para>
      <para>
        if [ "$1" = 1 ]; then
      </para>
      <para>
        /sbin/chkconfig --add vncserver
      </para>
      <para>
        fi
      </para>
      <para/>
      <para>
        %preun server
      </para>
      <para>
        if [ "$1" = 0 ]; then
      </para>
      <para>
        /sbin/service vncserver stop >/dev/null 2>&1
      </para>
      <para>
        /sbin/chkconfig --del vncserver
      </para>
      <para>
        fi
      </para>
      <para/>
      <para>
        %postun server
      </para>
      <para>
        if [ "$1" -ge "1" ]; then
      </para>
      <para>
        /sbin/service vncserver condrestart >/dev/null 2>&1
      </para>
      <para>
        fi
      </para>
    </sect2>
    <sect2>
      <title>Building subpackages</title>
      <para>
        The build sections in the spec file serve double duty. These
        sections are used for building the main package as well as
        subpackages. This is one reason why there are so many options on
        the %setup macro.
      </para>
      <para>
        The %setup macro allows for selectively unpacking the sources,
        rather than the default option of unpacking all the sources. For
        example, the following %setup macro definition gives rpmbuild
        specific instructions for unpacking one source file:
      </para>
      <para>
        %setup –D- T –a 1
      </para>
      <para>
        In this example, the –D option disables the automatic deletion
        of the directory where the sources will be unpacked. This means
        any previous contents of this directory, perhaps for other
        subpackages, will be left alone. The –T option disables the
        automatic unpacking of the source files, and the –a 1 option
        specifies to only unpack the first source file. You may need to
        use options like these when working with subpackages. Though, in
        most cases, subpackages are just means to partition the package
        files into separate packages. In cases like this, you will
        likely not need any of these special %setup options.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-specfiles"/>  covers the %setup macro and lists the available
        options.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Creating Relocatable Packages</title>
    <para>
      A relocatable package allows a user to specify where to install
      the package. For example, if you build a package for &RH;
      Linux, the normal directory for binary executable programs is
      /usr/bin. Other versions of Linux, though, may place executable
      programs into /opt/bin, for example. If your package forces the
      use of /usr/bin, then your package won’t work on these other
      systems.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      <xref linkend="ch-other-linuxes"/>  covers using RPM on other versions of Linux.
    </para>
    <para>
      With a relocatable package, though, you allow the user to redefine
      the top-level directories for your package, such as changing from
      /usr/bin to /opt/bin in the previous example. Making relocatable
      packages is generally considered a good thing, as you make the
      user’s life easier.
    </para>
    <para>
      To set up a relocatable package, you need to:
    </para>
    <para>
      *Set up the prefix directives for the top-level directories
    </para>
    <para>
      *Define the files under the prefix directories
    </para>
    <sect2>
      <title>Setting up the prefixes</title>
      <para>
        The Prefix: directive names a top-level directory as a prefix
        you can relocate to another directory. For example:
      </para>
      <para>
        Prefix: /usr
      </para>
      <para>
        This states that all files under /usr can be relocated to other
        directories by simply mapping /usr to some other directory, such
        as /opt, on the rpm command line when installing or upgrading
        the package.
      </para>
      <para>
        Note
      </para>
      <para>
        You can define more than one Prefix: directive to list more than
        one top-level directory.
      </para>
    </sect2>
    <sect2>
      <title>Define the files section</title>
      <para>
        When you use a Prefix: directive in your spec file, all files in
        the %files section must be under the directory named with the
        Prefix: directive. For example, from the jikes compiler package:
      </para>
      <para>
        Prefix: /usr
      </para>
      <para/>
      <para>
        ...
      </para>
      <para/>
      <para>
        %files
      </para>
      <para>
        %defattr(-,root,root)
      </para>
      <para>
        /usr/bin/jikes
      </para>
      <para>
        %doc /usr/doc/jikes-%{version}/license.htm
      </para>
      <para>
        %doc /usr/man/man1/jikes.1*
      </para>
      <para>
        In this example, all the files are under the /usr directory. All
        files in the %files section must be located under one of the
        Prefix: directories. If you have more than one top-level
        directory, such as /usr and /etc, define more than one Prefix:
        directive. For example:
      </para>
      <para>
        Prefix: /usr
      </para>
      <para>
        Prefix: /etc
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-using-rpm"/>  covers how to install or upgrade packages into
        different directories using the --relocate and --prefix options.
      </para>
    </sect2>
    <sect2>
      <title>Problems creating relocatable packages</title>
      <para>
        Not all packages work well as relocatable packages. Some
        packages have files that simply must go into a certain location
        and are therefore not relocatable. Some packages have programs
        that are hard-coded to look for files in a particular location
        and therefore cannot be relocated elsewhere. Other packages have
        symbolic links that also may not be relocatable. Furthermore,
        your package may provide software that is referenced by other
        packages, in the known directories. Relocating such a package
        will disable other software packages, packages you may not even
        know about.
      </para>
      <para>
        If your packages face any of these problems, chances are that
        making the package relocatable is not a good idea.
      </para>
      <para>
        In addition, if you use the %doc directive with local file
        names, remember that RPM will make a package-specific
        documentation directory, normally under /usr/doc. For example:
      </para>
      <para>
        %doc README NEWS
      </para>
      <para>
        This may defeat your attempts to create a relocatable package,
        unless you have a Prefix: directive with /usr, because the
        normal location is under /usr/doc, and all files in the %files
        section must start with one of the directories named with
        Prefix: directives.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Defining Conditional Builds</title>
    <para>
      With the ability to define macros inside spec files, and also to
      use macros defined elsewhere, you gain a lot of control over how
      your package gets built. You can go further, though, and use
      special directives to perform only certain commands based on
      certain conditions. This adds a powerful capability to your spec
      files, and also makes it much easier to do things like build for
      multiple versions of Linux or other operating systems, as well as
      handle various backwards-compatibility issues.
    </para>
    <para>
      To define conditional build commands, you need to create
      conditional constructs in your package’s spec file. In addition,
      you need to define macros that the conditional constructs use to
      determine whether or not to execute a set of spec file directives.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      See <xref linkend="ch-customizing-rpm"/> for more on macro file locations, and <xref linkend="ch-other-linuxes"/> and <xref linkend="ch-other-os"/> for more on using RPM on other versions of Linux and other operating systems, respectively.
    </para>
    <para>
      RPM supports a number of ways to make parts of your spec file
      enabled or disabled based on certain conditions. These include
      conditional macros, conditional blocks, and special directives
      based on the system architecture.
    </para>
    <sect2>
      <title>Defining conditional macros</title>
      <para>
        You can use a special syntax to test for the existence of
        macros. For example:
      </para>
      <para>
        %{?macro_to_test: expression}
      </para>
      <para>
        This syntax tells RPM to expand the expression if the macro
        macro_to_test exists. If the macro macro_to_test does not exist,
        nothing will be output. You can also reverse this test. A
        leading exclamation point, !, tests for the non-existence of a
        macro:
      </para>
      <para>
        %{!?macro_to_test: expression}
      </para>
      <para>
        In this example, if the macro_to_test macro does not exist, RPM
        will expand the expression.
      </para>
      <para>
        If you want, you can omit the expression and just test for the
        existence of the macro. If it exists, RPM will use the value of
        the macro. If the macro does not exist, RPM will use nothing.
        For example:
      </para>
      <para>
        %build
      </para>
      <para>
        ./configure %{?_with_ldap}
      </para>
      <para>
        make
      </para>
      <para>
        In this case, if the _with_ldap macro exists, the value of that
        macro will get passed on the command line to the configure
        script. If the _with_ldap macro does not exist, nothing extra
        will be passed on the command line to the configure script. This
        is very important when creating commands to build or install
        packages.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        Many of the macros you will test this way are set up with the
        --with command-line parameter. See <xref linkend="ch-other-linuxes"/>  for details.
      </para>
    </sect2>
    <sect2>
      <title>Using conditional blocks</title>
      <para>
        The %if macro enables all the directives up to the %endif
        directive, if the condition is true. This is much like scripting
        languages. For example:
      </para>
      <para>
        %if %{old_5x}
      </para>
      <para>
        %define b5x 1
      </para>
      <para>
        %undefine b6x
      </para>
      <para>
        %endif
      </para>
      <para>
        In this case, if the %old_5x macro has a value, the test will be
        true and all the directives inside the block will get executed.
      </para>
      <para>
        A %else allows you to specify what to do if the test is not
        successful. For example:
      </para>
      <para>
        %if %{old_5x}
      </para>
      <para>
        %define b5x 1
      </para>
      <para>
        %undefine b6x
      </para>
      <para>
        %else
      </para>
      <para>
        %define b6x 1
      </para>
      <para>
        %undefine b5x
      </para>
      <para>
        %endif
      </para>
      <para>
        In this case, if the %old_5x macro has a value, then all the
        directives up to the %else will get executed. Otherwise, if the
        %old_5x macro has no value, the directives from the %else to the
        %endif will get executed.
      </para>
      <para>
        Again, use an exclamation point to negate the test. For example:
      </para>
      <para>
        %if ! %{old_5x}
      </para>
      <para>
        %define b5x 1
      </para>
      <para>
        %undefine b6x
      </para>
      <para>
        %endif
      </para>
      <para>
        You can use a && for an AND test. For example:
      </para>
      <para>
        %if %{old_5x} && %{old_6x}
      </para>
      <para>
        %{error: You cannot build for .5x and .6x at the same time}
      </para>
      <para>
        %quit
      </para>
      <para>
        %endif
      </para>
    </sect2>
    <sect2>
      <title>Using architecture-based conditionals</title>
      <para>
        In addition to the general-purpose %if conditional directive,
        you can use special directives that test for processor
        architecture and operating system.
      </para>
      <para>
        The %ifarch directive enables all the directives up to the
        %endif directive, if the processor architecture matches the
        values you pass to the %ifarch directive. For example:
      </para>
      <para>
        %ifarch sparc
      </para>
      <para>
        %define b5x 1
      </para>
      <para>
        %undefine b6x
      </para>
      <para>
        %endif
      </para>
      <para>
        This block will only get executed if the processor architecture
        is SPARC.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-customizing-rpm"/>  covers RPM architecture and operating system names.
      </para>
      <para>
        You can pass more than one architecture name, separated by
        commas or spaces. For example:
      </para>
      <para>
        %ifarch sparc alpha
      </para>
      <para>
        %define b5x 1
      </para>
      <para>
        %undefine b6x
      </para>
      <para>
        %endif
      </para>
      <para>
        This example tests if the processor architecture is SPARC or
        Alpha.
      </para>
      <para>
        As with the %if directive, you can also use an %else, to cover
        all cases where the test is not true. For example:
      </para>
      <para>
        %ifarch sparc alpha
      </para>
      <para>
        %define b5x 1
      </para>
      <para>
        %undefine b6x
      </para>
      <para>
        %else
      </para>
      <para>
        %define b6x 1
      </para>
      <para>
        %undefine b5x
      </para>
      <para>
        %endif
      </para>
      <para>
        This example tests if the processor architecture is SPARC or
        Alpha. If so, the directives from the %ifarch to the %else are
        executed. If not, the directives from the %else to the %endif
        are executed.
      </para>
      <para>
        The %ifnarch directive reverses the %ifarch test. That is,
        %ifnarch tests if the architecture is not one of the values
        listed. The following example tests if the processor
        architecture is not an i386 or an Alpha.
      </para>
      <para>
        %ifnarch i386 alpha
      </para>
      <para>
        %define b5x 1
      </para>
      <para>
        %undefine b6x
      </para>
      <para>
        %endif
      </para>
      <para/>
      <para>
        The %ifos directive tests for the operating system. For example:
      </para>
      <para>
        %ifos linux
      </para>
      <para>
        %define b5x 1
      </para>
      <para>
        %undefine b6x
      </para>
      <para>
        %endif
      </para>
      <para>
        This example tests if the operating system is Linux. You can
        reverse the test with the %ifnos directive. For example:
      </para>
      <para>
        %ifnos irix
      </para>
      <para>
        %define b5x 1
      </para>
      <para>
        %undefine b6x
      </para>
      <para>
        %endif
      </para>
      <para>
        This example tests if the operating system is not Irix.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      This chapter covers advanced topics in creating packages.
      Dependencies are very important. You need to specify which
      packages or capabilities your package requires, so the RPM system
      can ensure that all requirements are met before allowing users to
      install the package. If you do not specify the dependencies
      properly, then you are defeating the integrity of the RPM system.
    </para>
    <para>
      In addition to specifying what your package requires, it is also
      important to specify other dependency information. For example, if
      your package conflicts with another package, you need to very
      clearly state this. E-mail and Web server packages often conflict
      with other servers of the same type.
    </para>
    <para>
      You can specify both package dependencies as well as build
      dependencies. For example, you may need certain developer
      libraries to build your package, but not to install it. These are
      build dependencies.
    </para>
    <para>
      To help manage dependencies between packages and system
      configuration issues, you can set up trigger scripts. A trigger is
      a script in your package that gets executed when another package
      is installed or removed. If your package, for example, is an
      e-mail client program, it may need to execute a script should the
      e-mail server package change. This is a great usage for triggers.
    </para>
    <para>
      If your package has a complicated installation, the normal RPM
      verification won’t be sufficient. To help the RPM system ensure
      the integrity of all the packages, you can write a verify script
      in your spec file to perform any extra commands necessary to
      verify your package has been properly installed.
    </para>
    <para>
      Relocatable packages allow users to install your packages in
      different locations than originally planned. This is very useful
      when working with more than one version of Linux, or with other
      operating systems. For example, most Linux commands are stored in
      /usr/bin, at least for &RHL;. Other Linux distributions,
      or other operating systems may specify that programs added to the
      original set should be stored in /opt/bin and not /usr/bin, for
      example. Making your package relocatable helps users in these
      situations.
    </para>
    <para>
      Conditional directives in your spec file allow you to control the
      build on different processor architectures and operating systems.
      The %if directive tests if a value is set. If so, then all the
      directives up to the %endif directive are executed. If you need to
      execute a different set of directives, use %else. In this case, if
      the %if test is true, RPM executes the directives up to the %else.
      If the test is not true, RPM executes the directives up to the
      %endif.
    </para>
    <para>
      Once you have your spec file defined, the next step is to start
      building packages. The next chapter covers options for the
      rpmbuild command and how you can use rpmbuild to make your
      packages.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-command-reference.xml ---
<!-- $Id: -->

<chapter id="ch-command-reference">
  <title>RPM Command Reference</title>
  <para>
    This appendix covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        rpm command
      </para>
    </listitem>
    <listitem>
      <para>
        rpmbuild command
      </para>
    </listitem>
  </itemizedlist>
  <para>
    This appendix covers the syntax of the command-line options for the
    rpm and rpmbuild commands.
  </para>
  <sect1>
    <title>The rpm Command</title>
    <para>
      The rpm command is the workhorse of the RPM system. The following
      sections cover options for the major operations with the rpm
      command.
    </para>
    <para>
      Table A-1 lists the query options for the rpm command.
    </para>
    <para>
      Table A-1 rpm query options with –q or --query
    </para>
    <informaltable frame="all">
      <tgroup cols="2">
        <tbody>
          <row>
            <entry>
              <para>
                Option
              </para>
            </entry>
            <entry>
              <para>
                Usage
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                -a, --all
              </para>
            </entry>
            <entry>
              <para>
                Query all packages
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                -c, --configfiles
              </para>
            </entry>
            <entry>
              <para>
                List configuration files
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                --changelog
              </para>
            </entry>
            <entry>
              <para>
                List changelog entries
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                --conflicts
              </para>
            </entry>
            <entry>
              <para>
                List capabilities this package conflicts with
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                -d, --docfiles
              </para>
            </entry>
            <entry>
              <para>
                List documentation files
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                --dump
              </para>
            </entry>
            <entry>
              <para>
                Dump out extra information on files.
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                -f, --file filename
              </para>
            </entry>
            <entry>
              <para>
                Query for packages owning given file
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                --filesbypapkg
              </para>
            </entry>
            <entry>
              <para>
                List all files in each selected package
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                --fileid md5_id
              </para>
            </entry>
            <entry>
              <para>
                Query for the package with the given MD5 digest
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                -g, --group group_name
              </para>
            </entry>
            <entry>
              <para>
                Query packages in the given group
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                --hdrid sha1_header_id
              </para>
            </entry>
            <entry>
              <para>
                Query for the package with the given header identifier
                number, in SHA1 format
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                -i, --info
              </para>
            </entry>
            <entry>
              <para>
                Display a lot of package information including
                description
              </para>
            </entry>
          </row>
          <row>
            <entry>
[...1919 lines suppressed...]
              </entry>
              <entry>
                <para>
                  Read the given colon-separated files as the macro
                  files to define RPM macros; only the first file must
                  exist
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --nobuild
                </para>
              </entry>
              <entry>
                <para>
                  Don't really build anything, which really tests the
                  spec file
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --pipe command
                </para>
              </entry>
              <entry>
                <para>
                  Pipe the output of the rpm command to the given
                  command
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --quiet
                </para>
              </entry>
              <entry>
                <para>
                  Provide less output, normally show only errors
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --rcfile file:file:file
                </para>
              </entry>
              <entry>
                <para>
                  Read the given colon-separated files as the rc files
                  to define RPM settings; only the first file must exist
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --rmsource
                </para>
              </entry>
              <entry>
                <para>
                  Remove the sources after the build
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --rmspec
                </para>
              </entry>
              <entry>
                <para>
                  Remove the spec file after the build
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --root directory
                </para>
              </entry>
              <entry>
                <para>
                  Use directory as the top-level directory instead of /
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --short-circuit
                </para>
              </entry>
              <entry>
                <para>
                  With the -bc or -bi options, jumps directly to the
                  given stage and just executes that stage
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --showrc
                </para>
              </entry>
              <entry>
                <para>
                  Print the rpmrc and macro configuration and exit
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --sign
                </para>
              </entry>
              <entry>
                <para>
                  Sign the package with a GPG signature
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --target platform
                </para>
              </entry>
              <entry>
                <para>
                  Build for the given platform. May not work if you
                  don't have the other platform build commands, such as
                  cross compilers, set up. Can work for Intel platforms
                  with i386, i686, and so on.
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  -v, --verbose
                </para>
              </entry>
              <entry>
                <para>
                  Provide more verbose output
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  -vv
                </para>
              </entry>
              <entry>
                <para>
                  Provide even more verbose output, including debugging
                  information
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --version
                </para>
              </entry>
              <entry>
                <para>
                  Print the RPM version and exit
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
      <para/>
    </sect2>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-creating-rpms.xml ---
<!-- $Id: -->

<chapter id="ch-creating-rpms">
  <title>Creating RPMs: An Overview</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Preparing to build RPMs
      </para>
    </listitem>
    <listitem>
      <para>
        Planning for RPMs
      </para>
    </listitem>
    <listitem>
      <para>
        Explaining the build process
      </para>
    </listitem>
    <listitem>
      <para>
        Using build files
      </para>
    </listitem>
    <listitem>
      <para>
        Seeing the results
      </para>
    </listitem>
    <listitem>
      <para>
        Verifying your RPMs
      </para>
    </listitem>
  </itemizedlist>
  <para>
    Thus far in this book, all the commands presented have been used to
    manage or query packages. With this chapter, though, you start
    creating RPMs of your own. Even if you do not produce applications
    on your own, you may want to create RPM packages out of software you
    use, if only for the ease of management that the RPM system
    provides.
  </para>
  <para>
    Creating RPMs allows you to create a consistent set of applications
    for use on all systems in your organization and easily manage those
    applications. You may create RPMs of applications developed in house
    or RPMs of applications developed elsewhere that you need to
    customize for your environment. Making RPMs of the customized
    applications reduces work and makes the customizations consistent.
  </para>
  <para>
    This chapter introduces the RPM system from the point of view of
    creating RPMs and demonstrates the steps and planning necessary to
    make your own packages. As such, this chapter introduces the
    RPM-building topics covered in depth in the remaining chapters in
    this part.
  </para>
  <sect1>
    <title>Preparing to Build RPMs</title>
    <para>
      The RPM-building task starts with gathering all the material you
      want to bundle into an RPM package and then defining the RPM
      directives to make your package. The final steps are to build and
      test an RPM. This sounds easy, and for the most part it is fairly
      straightforward.
    </para>
    <para>
      The main problems arise when you try to define the many RPM
      directives for your package. In addition, some of the elements in
      an RPM can be complex, such as upgrade scripts.
    </para>
    <para>
      The main tasks in building RPMs are:
    </para>
    <para>
      1.Planning what you want to build
    </para>
    <para>
      2.Gathering the software to package
    </para>
    <para>
      3.Patching the software as needed
    </para>
    <para>
      4.Creating a reproducible build of the software
    </para>
    <para>
      5.Planning for upgrades
    </para>
    <para>
      6.Outlining any dependencies
    </para>
    <para>
      7.Building the RPMs
    </para>
    <para>
      8.Testing the RPMs
    </para>
    <para>
      The sections in this chapter cover the initial planning stages and
      provide an overview of the process of building RPMs. The remaining
      chapters in Part II go in depth into the process of building RPMs.
    </para>
    <sect2>
      <title>Planning what you want to build</title>
      <para>
        The first step in the entire RPM-building process is simply to
        decide exactly what you want to make into an RPM. Is this an
        application, a programming library, a set of system
        configuration files, or a documentation package? If this is an
        application, is it customized or patched? Think these issues
        over and decide what you want to package as an RPM.
      </para>
      <para>
        In most cases, you want to create both a source package and a
        binary package containing the built sources. You need a binary
        package because that holds the RPM you want to install on other
        systems. You need the source package so you can recreate the
        binary package at any time. And, if the sources get updated, you
        can quickly make a new binary RPM from the updated sources if
        you have already defined a source RPM.
      </para>
      <para>
        Most packages start with a source RPM, although you have the
        option to skip making a source RPM. It is a good idea to make
        the source RPM, however, because it makes it easier to reproduce
        the final binary RPM. Once of the key goals of the RPM system is
        to allow for reproducible builds, and making source RPMs is just
        one step to help towards this goal.
      </para>
      <para>
        Creating a source RPM also allows you to transfer the entire set
        of sources for a package to another system, since the source RPM
        is just one file and it contains all the program sources along
        with the instructions, called a spec file, for building the
        binary RPM. Furthermore, creating a source RPM makes it easier
        to create binary RPMs on different processor architectures or
        different versions of Linux.
      </para>
      <para>
        Note
      </para>
      <para>
        Not all programs are portable to multiple-processor
        architectures. But many Linux programs can simply be recompiled
        on another architecture to make a binary program for that
        architecture. That's because there are a lot of common APIs for
        Linux applications and because most programs are not processor
        dependent. This is not true of all programs, so your mileage may
        vary.
      </para>
      <para>
        Source packages are not that hard to make, and they provide a
        single package, and single file, that holds all the sources
        necessary to build your binary package. In addition, once you
        have a source RPM, it is very easy to build a binary RPM.
      </para>
      <para>
        Binary packages are likely the real reason you want to make an
        RPM. You can package an application, a programming library, or
        almost anything you want. Armed with a binary RPM, you can
        transfer one file to another machine and install the application
        there, taking full advantage of the RPM system.
      </para>
    </sect2>
    <sect2>
      <title>Gathering the software to package</title>
      <para>
        Whether you are writing your own software or merely packaging
        software found elsewhere, the next step is to gather the
        software you want to bundle into an RPM. This includes the
        applications or libraries you want to package, as well as the
        program source code.
      </para>
      <para>
        In general, you’ll be doing one of three things:
      </para>
      <para>
        *Packaging your own software
      </para>
      <para>
        *Packaging someone else’s software
      </para>
      <para>
        *Packaging someone else’s stuff after first customizing or
        patching the software
      </para>
      <para>
        In all cases, you need to gather the software together and
        decide whether you want everything to go into one bundle or a
        number of bundles.
      </para>
      <para>
        As covered in <xref linkend="ch-intro-rpm"/> , a major tenet of the philosophy behind
        RPM is to start with pristine—unmodified--sources. You may
        need to patch or customize the sources for your environment, but
        you can always go back to the original sources.
      </para>
      <para>
        Starting with pristine sources provides a number of advantages,
        including the following:
      </para>
      <para>
        *You clearly separate any changes you have made to the software
        from the original software.
      </para>
      <para>
        *You make it easier to get an upgrade of the original sources,
        since your changes are cleanly separated from the original
        sources. With each new release of the software, you can
        determine which of your changes, if any, are still needed. This
        is especially important if you are packaging an application
        created by another organization into an RPM.
      </para>
      <para>
        *You have a reproducible way to recreate everything in the
        package. Since you start with unmodified sources, you can always
        go back to the beginning of the process and start again. Thus,
        your RPMs don’t depend on any actions taken beforehand, such
        as patching, that you may later forget to do because the steps
        are not automated as part of the RPM-building process.
      </para>
      <para>
        Start with pristine sources; then patch as needed. A patch is an
        automated set of modifications to the source code. Use the diff
        command to build a patch and the patch command to apply the
        patch (that is, to modify the source code). Keep the original
        sources separate from any patches you need to make the software
        work in your environment.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        See the online manual pages for the patch and diff commands for
        more information on how to create and apply a patch.
      </para>
    </sect2>
    <sect2>
      <title>Creating a reproducible build of the software</title>
      <para>
        The RPM system will automate the steps to create an application,
        as long as you configure the RPM with the proper steps, such as
        which make targets to run. Unfortunately, configuring the proper
        steps is not always easy. So before trying to make an RPM, you
        need to figure out how to build the application or library you
        plan to package into an RPM. Once you have figured out how to
        build the application or library, you can set up a reproducible
        build. The RPM system can then automate this build.
      </para>
      <para>
        To build the software, you’ll need to use a variety of Linux
        tools. The specific tools you need depend largely on where the
        original software came from. The following sections outline some
        of the more common techniques for preparing and building Linux
        software.
      </para>
      <sect3>
        <title>Unpacking Software</title>
        <para>
          Many applications are downloaded in compressed tar format,
          often called a tarball. A tarball is merely an archive file
          built by the tar command that has been compressed, usually
          using the gzip command.
        </para>
        <para>
          In most cases, these files have a name such as the following:
        </para>
        <para>
          filename.tar.gz
        </para>
        <para>
          filename.tgz
        </para>
        <para>
          filename.tar.Z
        </para>
        <para>
          For the first two cases, use the gunzip command to unzip the
          file; then use the tar command to extract the file, for
          example:
        </para>
        <para>
          $ gunzip filename.tgz
        </para>
        <para>
          $ tar xf filename.tar
        </para>
        <para>
          Note
        </para>
        <para>
          In the case of a file name ending in .Z, use the uncompress
          program instead of gunzip.
        </para>
        <para>
          Once you have unpacked the sources, start looking around at
          the files.
        </para>
      </sect3>
      <sect3>
        <title>Reading the README</title>
        <para>
          Many applications come with a very handy file named README, or
          something similar, such as README.txt. As the name implies,
          you should read this file. The README file answers some of the
          most common questions about a particular application.
        </para>
        <para>
          Note
        </para>
        <para>
          You really should read any file named README or any variant of
          README.
        </para>
        <para>
          Other useful files include those named INSTALL or some close
          variant. Read these files, too. Usually, the README or the
          INSTALL file will tell you what you need to do to build the
          software.
        </para>
        <para>
          Once you have extracted the source code files and read all the
          available documentation, the next step is to build, usually
          compile, the application or library.
        </para>
      </sect3>
      <sect3>
        <title>Building Programs with Linux Build Tools</title>
        <para>
          Most applications or libraries need to be built into
          executable programs or compiled archived libraries. This
          process of building can be as simple as just compiling, but is
          usually more involved. Most Linux applications and libraries
          use a build tool called make to manage the building of the
          source code and creation of the executable programs. The make
          command uses a file, normally named Makefile, that contains
          the rules for building the software. You will usually find a
          Makefile in each directory in the source code
        </para>
        <para>
          Each Makefile contains a set of targets that define things
          that make can build. Each target defines the commands to run
          to build a particular thing (make targets are purely
          arbitrary, although some conventions are usually followed).
          Some combination of the targets results in a built
          application. The make program runs the targets that you
          specify on the command line, or the Makefile rules indicate it
          needs to run based on the targets you specify on the command
          line.
        </para>
        <para>
          You need to tell make the target to build the application or
          library you want to package into an RPM. Each target is
          defined within the Makefile. The conventional make targets to
          build and install a program are:
        </para>
        <para>
          make
        </para>
        <para>
          make install
        </para>
        <para>
          When you call the make command without the name of a target,
          make builds the default target, named all. This target usually
          compiles the program or library. The install target should
          install the program.
        </para>
        <para>
          Note
        </para>
        <para>
          The names of these make targets are conventions shared by many
          but not all programs. Other common targets include clean,
          which should clean up any files built.
        </para>
        <para/>
        <para>
          The commands in the Makefile may be specific to a given
          system. For example, the traditional command for compiling C
          programs is cc, short for C Compiler. You may have the gcc
          command (GNU C Compiler) instead. The options passed to the C
          compiler may differ depending on the architecture of the
          system. Other commands may exist but be located in different
          locations. SUSE Linux, for example, puts a lot of programs in
          /opt.
        </para>
        <para>
          Note
        </para>
        <para>
          These system-dependent issues mostly apply to various versions
          of Unix. Most modern Linux systems are fairly similar. Because
          many packages, such as sendmail, have a long UNIX history,
          you’ll find all sorts of complications in the Makefiles or
          many Makefiles provided with many applications. If we could
          just convince everyone to give up all non-Linux operating
          systems, this task would be much simpler.
        </para>
        <para>
          Because the Makefiles are platform specific, a number of tools
          have been developed to create the proper Makefile, usually by
          running a program that knows about your system's architecture.
          The simplest of these tools is the manual approach. You may
          download a program and find files such as Makefile.amiga,
          Makefile.solaris, and Makefile.linux. You need to copy the
          file for your system architecture to the name Makefile.
        </para>
        <para>
          The following sections discuss other tools for creating
          Makefiles.
        </para>
        <para/>
        <sect4>
          <title>imake</title>
          <para>
            A program called imake is used mostly for X Window graphical
            applications, and typically older X Window applications. The
            imake command uses a file named Imakefile that contains
            rules used to build a platform-specific Makefile. This
            allows X Window applications, which run on many
            architectures and operating systems, to come with fairly
            generic build scripts.
          </para>
          <para>
            When you see an Imakefile, use the following general set of
            commands to compileand install an application:
          </para>
          <para>
            $ xmkmf
          </para>
          <para>
            $ make
          </para>
          <para>
            $ make install
          </para>
          <para>
            These commands work for most X Window applications. The
            xmkmf command is a script that runs the imake command to
            create a Makefile. If the xmkmf command is not available or
            if this command does not work, you may need to run a command
            such as the following:
          </para>
          <para>
            make Makefile
          </para>
          <para>
            Or, if there are multiple directories of source code, try
            the following command:
          </para>
          <para>
            make Makefiles
          </para>
          <para>
            Cross Reference
          </para>
          <para>
            For more on imake, see www.dubois.ws/software/imake-stuff/.
          </para>
        </sect4>
        <sect4>
          <title>The configure script</title>
          <para>
            Most Linux programs, especially server-side or command-line
            programs, use a script called configure. The configure
            script outputs a platform-specific Makefile.
          </para>
          <para>
            If you see a script named configure in the source files, try
            the following commands to build and install the program:
          </para>
          <para>
            $ ./configure
          </para>
          <para>
            $ make
          </para>
          <para>
            $ make install
          </para>
          <para>
            The ./configure command runs the script in the local
            directory, which outputs a Makefile configured for your
            system. The make command builds the program and the make
            install command installs the program.
          </para>
          <para>
            The configure script is created by a set of tools including
            automake and autoconf, which use generic files usually named
            configure.in and makefile.am, among other files, to create
            the generic configure script.
          </para>
          <para>
            In many cases, you’ll need to pass parameters to the
            configure script. One of the most common parameters is
            --prefix, which tells the configure script the name of the
            starting directory from which to base all other paths. This
            is the root directory for building the application.
          </para>
          <para>
            Cross Reference
          </para>
          <para>
            For more on the configure system, autoconf, and automake,
            see www.airs.com/ian/configure/.
          </para>
        </sect4>
        <sect4>
          <title>Building Perl modules</title>
          <para>
            Perl is a scripting language used heavily on Linux systems,
            especially by administrators. Most Perl modules and packages
            use the following set of commands to create a
            system-specific Makefile and to build the module:
          </para>
          <para>
            $ perl Makefile.PL
          </para>
          <para>
            $ make
          </para>
          <para>
            $ make test
          </para>
          <para>
            $ make install
          </para>
          <para>
            If you see a file named Makefile.PL, chances are these are
            the commands to run to build the application or module.
          </para>
          <para>
            The goal of all these steps is to figure out how to make a
            reproducible build of the application or library you want to
            package in RPM format. Once you have a build, the next step
            is to plan for upgrades.
          </para>
        </sect4>
      </sect3>
    </sect2>
    <sect2>
      <title>Planning for Upgrades</title>
      <para>
        Any application or library you package in RPM format is likely
        to get upgraded sometime. When this happens, you’ll need to
        make a new RPM. This new RPM must handle not only installing the
        package, but also handling any upgrade issues. You need to think
        about the following issues:
      </para>
      <para>
        *How to install the RPM for the new version of the software. Are
        there any necessary install scripts?
      </para>
      <para>
        *How to remove the previous RPM package. If your package has an
        install script, then you may need an uninstall script to cleanly
        remove any changes made to the system by the install script. The
        RPM system handles the removal of the files in the package. You
        need to handle the task of undoing any changes made to the
        system during installation.
      </para>
      <para>
        At this point in time, the main effort is to keep these issues
        in mind and plan ahead, since these issues will come up with any
        upgrade.
      </para>
    </sect2>
    <sect2>
      <title>Outlining Any Dependencies</title>
      <para>
        Often, the hardest task is getting make to build a program
        properly. One potential problem is assuring that all the
        dependencies are included. As you work with make, keep track of
        any other libraries that the program you are trying to build
        requires. These libraries will become dependencies when you get
        to the stage of making the RPM.
      </para>
      <para>
        In most cases you do not want to include the dependencies in
        your RPM. Instead, each dependency should have its own RPM for
        each necessary library. In many cases, you should be able to
        find RPMs for these dependencies. Keep track of the packages
        that provide the dependencies.
      </para>
      <para>
        After you have built the application, planned for upgrades and
        outlined dependencies, you can make an RPM.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Building RPMs</title>
    <para>
      In previous chapters, just about everything you want to do with
      RPMs is accomplished with the rpm command. Building RPMs is one
      exception. Just about everything you want to do to build an RPM is
      done by the rpmbuild command, often with a single command.
    </para>
    <para>
      Warning
    </para>
    <para>
      Older RPM manuals refer to using the –b option to the rpm
      command to create RPMs. Don’t use that option. Instead, always
      use the rpmbuild command. The reason for this change is that
      starting with version 4.1, RPM no longer maps the rpm -b command
      to the real command, rpmbuild.
    </para>
    <para>
      When building RPMs, go through the following steps:
    </para>
    <para>
      1.Set up the directory structure.
    </para>
    <para>
      2.Place the sources in the right directory.
    </para>
    <para>
      3.Create a spec file that tells the rpmbuild command what to do.
    </para>
    <para>
      4.Build the source and binary RPMs.
    </para>
    <para>
      The following sections provide details for these steps.
    </para>
    <sect2>
      <title>Setting up the directory structure</title>
      <para>
        The RPM system expects five directories, as listed in Table 9-1.
      </para>
      <para>
        Table 9-1 RPM directories
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  Directory
                </para>
              </entry>
              <entry>
                <para>
                  Usage
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  BUILD
                </para>
              </entry>
              <entry>
                <para>
                  The rpmbuild command builds software in this
                  directory.
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  RPMS
                </para>
              </entry>
              <entry>
                <para>
                  The rpmbuild command stores binary RPMs it creates in
                  this directory.
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  SOURCES
                </para>
              </entry>
              <entry>
                <para>
                  You should put the sources for the application in this
                  directory.
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  SPECS
                </para>
              </entry>
              <entry>
                <para>
                  You should place the spec file for each RPM you plan
                  to make in this directory.
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  SRPMS
                </para>
              </entry>
              <entry>
                <para>
                  The rpmbuild command places source RPMs in this
                  directory.
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
      <para>
        The RPMS directory usually has a number of architecture-specific
        subdirectories, such as the following (on an Intel architecture
        system):
      </para>
      <para>
        $ ls RPMS
      </para>
      <para>
        athlon
      </para>
      <para>
        i386
      </para>
      <para>
        i486
      </para>
      <para>
        i586
      </para>
      <para>
        i686
      </para>
      <para>
        noarch
      </para>
      <para>
        By default, &RHL; systems expect RPMs to be built in the
        /usr/src/redhat directory.
      </para>
      <para>
        Note
      </para>
      <para>
        This directory is obviously specific to &RHL;. On other
        Linux distributions, you'll likely see other directories.
      </para>
      <para>
        Within the /usr/src/redhat directory, you’ll see the
        subdirectories listed in Table 9-1, as follows:
      </para>
      <para>
        $ ls /usr/src/redhat
      </para>
      <para>
        BUILD
      </para>
      <para>
        RPMS
      </para>
      <para>
        SOURCES
      </para>
      <para>
        SPECS
      </para>
      <para>
        SRPMS
      </para>
      <para>
        At first, it seems rather odd to be using a system directory to
        build RPMs. But remember that the RPM system was originally
        built to create Linux distributions. You can also change the
        default directories by modifying your rpmrc settings.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        See <xref linkend="ch-customizing-rpm"/>  for more on the use of the rpmrc settings.
      </para>
      <para>
        For now, it is easiest to just change to the /usr/src/redhat
        directory and work from this location. To start, you will need
        to change ownership or permissions on these files so you can
        build RPMs while logged in as a normal user.
      </para>
      <para>
        Warning
      </para>
      <para>
        Do not build RPMs while logged in as root. Mistakes in building
        packages can have serious consequences if you are logged in as
        root.
      </para>
      <para>
        To build RPMs, you really need only two things:
      </para>
      <para>
        *Your sources in the SOURCES directory
      </para>
      <para>
        *Your spec file in the SPECS directory
      </para>
    </sect2>
    <sect2>
      <title>Placing your sources into the directory structure</title>
      <para>
        You can place all the source files directly in the
        /usr/src/redhat/SOURCES directory. In most cases, however, it is
        easier to create a tarball of the sources you want to build and
        place the tarball file in the /usr/src/redhat/SOURCES directory.
        The RPM specifications for commands necessary to extract the
        sources from such a file are trivial. Furthermore, the tarball,
        when extracted, should create a subdirectory specific to your
        package. This keeps your source code separate from other
        packages that also have source code in the SOURCES directory.
      </para>
      <para>
        The best strategy is to start in a directory of your own making,
        create the tarball file from the sources, and then copy the
        tarball file to the /usr/src/redhat/SOURCES directory.
      </para>
      <para>
        The convention for these tarball files is
        package-version.tar.gz. For example:
      </para>
      <para>
        jikes-1.17.tar.gz
      </para>
      <para>
        Place a file like this into the /usr/src/redhat/SOURCES
        directory. This file should include all the sources, all the
        build scripts, and any documentation you want to install as part
        of the package.
      </para>
    </sect2>
    <sect2>
      <title>Creating the spec file</title>
      <para>
        The spec file, short for specification file, defines all the
        actions the rpmbuild command should take to build your
        application, as well as all the actions necessary for the rpm
        command to install and remove the application. Each source RPM
        should have the necessary spec file for building a binary RPM.
      </para>
      <para>
        The spec file is a text file. The normal naming convention is to
        name the file with the package name and a .spec filename
        extension. For example, the jikes package spec file would be
        named jikes.spec.
      </para>
      <para>
        Inside the spec file, format the information on the package
        using a special syntax. This syntax defines how to build the
        package, version numbers, dependency information, and everything
        else you can query about a package. This syntax differs slightly
        depending on the sections in the spec file. The following
        sections describe these spec file sections and the necessary
        syntax in each section.
      </para>
      <sect3>
        <title>The introduction section</title>
        <para>
          The introduction section contains information about the
          package, the type of information shown with the rpm -qi
          command. For example:
        </para>
        <para>
          Summary: java source to bytecode compiler
        </para>
        <para>
          %define version 1.17
        </para>
        <para>
          Copyright: IBM Public License,
          http://ibm.com/developerworks/oss/license10.html
        </para>
        <para>
          Group: Development/Languages
        </para>
        <para>
          Name: jikes
        </para>
        <para>
          Prefix: /usr
        </para>
        <para>
          Provides: jikes
        </para>
        <para>
          Release: 1
        </para>
        <para>
          Source: jikes-%{version}.tar.gz
        </para>
        <para>
          URL: http://ibm.com/developerworks/opensource/jikes
        </para>
        <para>
          Version: %{version}
        </para>
        <para>
          Buildroot: /tmp/jikesrpm
        </para>
        <para/>
        <para>
          %description
        </para>
        <para>
          The IBM Jikes compiler translates Java source files to
          bytecode. It
        </para>
        <para>
          also supports incremental compilation and automatic makefile
          generation,
        </para>
        <para>
          and is maintained by the Jikes Project:
        </para>
        <para>
          http://ibm.com/developerworks/opensource/jikes/
        </para>
        <para>
          In this example, you can see the Source: definition of a
          compressed tar archive associated with a particular version
          number. This also names a Buildroot: setting that defines
          where the files will get built into a working program. You can
          see the description of the package that will get printed with
          the rpm –qi command.
        </para>
        <para>
          Note
        </para>
        <para>
          You can further divide this first section into the preamble
          and other areas. For simplicity, I grouped all introductary
          parts of a spec file into one introduction section.
        </para>
        <para>
          This example comes from a real-world RPM spec file. It does
          not follow all the rules for creating RPMs. This example:
        </para>
        <para>
          *Should not explicitly provide jikes, the name of the package.
        </para>
        <para>
          *Should not include a Copyright tag, as this tag is
          deprecated.
        </para>
        <para>
          *Uses a %define for the version when the rpmbuild command can
          create a version macro for you.
        </para>
      </sect3>
      <sect3>
        <title>The prep section</title>
        <para>
          The prep section, short for prepare, defines the commands
          necessary to prepare for the build. If you are starting with a
          compressed tar archive (a tarball) of the sources, the prep
          section needs to extract the sources.
        </para>
        <para>
          For example:
        </para>
        <para>
          %prep
        </para>
        <para>
          %setup -q
        </para>
        <para>
          The prep section starts with a %prep statement.
        </para>
        <para>
          This example uses the %setup RPM macro, which knows about tar
          archives, to extract the files. In most cases, this will be
          all you need in your spec file prep section.
        </para>
      </sect3>
      <sect3>
        <title>The build section</title>
        <para>
          The spec file build section contains the commands to build the
          software. Usually, this will include just a few commands,
          since most of the real instructions appear in the Makefile.
          For example:
        </para>
        <para>
          %build
        </para>
        <para>
          ./configure CXXFLAGS=-O3 --prefix=$RPM_BUILD_ROOT/usr
        </para>
        <para>
          make
        </para>
        <para>
          The build section starts with a %build statement.
        </para>
        <para>
          The commands shown for this build section run the configure
          script, covered in the previous section on Linux build tools,
          and then run the make command with the default maketarget. If
          things unfold as they should, this procedure builds the
          software.
        </para>
      </sect3>
      <sect3>
        <title>The install section</title>
        <para>
          The spec file install section holds the commands necessary to
          install the newly built application or library. In most cases,
          your install section should clean out the Buildroot directory
          and run the make install command. For example:
        </para>
        <para>
          %install
        </para>
        <para>
          rm -fr $RPM_BUILD_ROOT
        </para>
        <para>
          make install
        </para>
        <para>
          The install section starts with an %install statement.
        </para>
      </sect3>
      <sect3>
        <title>The clean section</title>
        <para>
          The clean section cleans up the files that the commands in the
          other sections create:
        </para>
        <para>
          %clean
        </para>
        <para>
          rm -rf $RPM_BUILD_ROOT
        </para>
        <para>
          The clean section starts with a %clean statement
        </para>
      </sect3>
      <sect3>
        <title>The files section</title>
        <para>
          Finally, the files section lists the files to go into the
          binary RPM, along with the defined file attributes. For
          example:
        </para>
        <para>
          %files
        </para>
        <para>
          %defattr(-,root,root)
        </para>
        <para>
          /usr/bin/jikes
        </para>
        <para>
          %doc /usr/doc/jikes-%{version}/license.htm
        </para>
        <para>
          %doc /usr/man/man1/jikes.1*
        </para>
        <para>
          The files section starts with a %files statement
        </para>
        <para>
          The %doc macro marks certain files as documentation. This
          allows the RPM to distinguish the files holding documentation
          from the other files in the RPM.
        </para>
        <para>
          Cross Reference
        </para>
        <para>
          This example skips the install and uninstall script sections,
          as well as a verification section. There are also no triggers
          defined in this RPM spec file. All of these topics are covered
          in <xref linkend="ch-specfiles"/> and <xref linkend="ch-advanced-packaging"/>.
        </para>
        <para>
          Once you have written your spec file, and placed the files in
          the SOURCES and SPECS directories under /usr/src/redhat,
          you’ll see files like the following:
        </para>
        <para>
          $ ls –CF /usr/src/redhat/*
        </para>
        <para>
          /usr/src/redhat/BUILD:
        </para>
        <para/>
        <para>
          /usr/src/redhat/RPMS:
        </para>
        <para>
          athlon/ i386/ i486/ i586/ i686/ noarch/
        </para>
        <para/>
        <para>
          /usr/src/redhat/SOURCES:
        </para>
        <para>
          jikes-1.17.tar.gz
        </para>
        <para/>
        <para>
          /usr/src/redhat/SPECS:
        </para>
        <para>
          jikes.spec
        </para>
        <para/>
        <para>
          /usr/src/redhat/SRPMS:
        </para>
        <para>
          That is, with a clean system and no other RPMs being built,
          you'll see a spec file in /usr/src/redhat/SPECS and the
          sources in /usr/src/redhat/SOURCES. In this example, the
          sources are in a compressed tar archive. (For this, the RPM
          spec file, jikes.spec needs to have a command in the prep
          section to extract the files.)
        </para>
        <para>
          You should now be ready to build an RPM.
        </para>
      </sect3>
    </sect2>
    <sect2>
      <title>Building RPMs with the rpmbuild command</title>
      <para>
        To build RPMs with the rpmbuild command, use the following basic
        syntax:
      </para>
      <para>
        rpmbuild -bBuildStage spec_file
      </para>
      <para>
        The -b option tells rpmbuild to build an RPM. The extra
        BuildStage option is a special code that tells the rpmbuild
        command how far to go when building. Table 9-2 lists these
        options:
      </para>
      <para>
        Table 9-2 Options for building with rpmbuild
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  Option
                </para>
              </entry>
              <entry>
                <para>
                  Usage
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  -ba
                </para>
              </entry>
              <entry>
                <para>
                  Build all, both a binary and source RPM
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  -bb
                </para>
              </entry>
              <entry>
                <para>
                  Build a binary RPM
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  -bc
                </para>
              </entry>
              <entry>
                <para>
                  Build (compile) the program but do not make the full
                  RPM, stopping just after the %build section
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  -bp
                </para>
              </entry>
              <entry>
                <para>
                  Prepare for building a binary RPM, and stop just after
                  the %prep section
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  -bi
                </para>
              </entry>
              <entry>
                <para>
                  Create a binary RPM and stop just after the %install
                  section
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  -bl
                </para>
              </entry>
              <entry>
                <para>
                  Check the listing of files for the RPM and generate
                  errors if the buildroot is missing any of the files to
                  be installed
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  -bs
                </para>
              </entry>
              <entry>
                <para>
                  Build a source RPM only
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
      <para>
        Note
      </para>
      <para>
        See chapter 12 for advanced options you can use with rpmbuild.
      </para>
      <para>
        For example, to set up all the necessary files and prepare for
        building, run the following command:
      </para>
      <para>
        rpmbuild –bp specfile
      </para>
      <para>
        This example runs through the %prep section, and stops
        immediately after this section. With the jikes package, for
        example, you’ll see a result like the following:
      </para>
      <para>
        $ rpmbuild -bp /usr/src/redhat/SPECS/jikes.spec
      </para>
      <para>
        Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.72435
      </para>
      <para>
        + umask 022
      </para>
      <para>
        + cd /usr/src/redhat/BUILD
      </para>
      <para>
        + LANG=C
      </para>
      <para>
        + export LANG
      </para>
      <para>
        + cd /usr/src/redhat/BUILD
      </para>
      <para>
        + rm -rf jikes-1.17
      </para>
      <para>
        + /usr/bin/gzip -dc /usr/src/redhat/SOURCES/jikes-1.17.tar.gz
      </para>
      <para>
        + tar -xf -
      </para>
      <para>
        + STATUS=0
      </para>
      <para>
        + '[' 0 -ne 0 ']'
      </para>
      <para>
        + cd jikes-1.17
      </para>
      <para>
        ++ /usr/bin/id -u
      </para>
      <para>
        + '[' 500 = 0 ']'
      </para>
      <para>
        ++ /usr/bin/id -u
      </para>
      <para>
        + '[' 500 = 0 ']'
      </para>
      <para>
        + /bin/chmod -Rf a+rX,g-w,o-w .
      </para>
      <para>
        + exit 0
      </para>
      <para>
        After running this command, the source files are extracted into
        the /usr/src/redhat/BUILD directory, under the jikes-1.17
        subdirectory. Using a subdirectory keeps the sources for this
        package from intermixing with the sources for other packages.
      </para>
      <para>
        Running a directory listing on the
        /usr/src/redhat/BUILD/jikes-1.17 subdirectory shows what the
        spec file %prep section commands have done. For example:
      </para>
      <para>
        $ ls -1 /usr/src/redhat/BUILD/jikes-1.17
      </para>
      <para>
        acinclude.m4
      </para>
      <para>
        aclocal.m4
      </para>
      <para>
        AUTHORS
      </para>
      <para>
        ChangeLog
      </para>
      <para>
        config.guess
      </para>
      <para>
        config.sub
      </para>
      <para>
        configure
      </para>
      <para>
        configure.in
      </para>
      <para>
        COPYING
      </para>
      <para>
        depcomp
      </para>
      <para>
        doc
      </para>
      <para>
        INSTALL
      </para>
      <para>
        install-sh
      </para>
      <para>
        jikes.spec
      </para>
      <para>
        Makefile.am
      </para>
      <para>
        Makefile.in
      </para>
      <para>
        missing
      </para>
      <para>
        mkinstalldirs
      </para>
      <para>
        NEWS
      </para>
      <para>
        README
      </para>
      <para>
        src
      </para>
      <para>
        TODO
      </para>
      <para>
        Note
      </para>
      <para>
        From these sources, you see a configure script. The configure
        script gives a good indication of how the software needs to be
        built. This example also shows a README file. You know what to
        do with these files.
      </para>
      <para>
        The actual source code is in the
        /usr/src/redhat/BUILD/jikes-1.17/src directory. The user
        documentation is stored in the
        /usr/src/redhat/BUILD/jikes-1.17/doc directory.
      </para>
      <para>
        To build a binary RPM, use the –bb option to the rpmbuild
        command. For example:
      </para>
      <para>
        $ rpmbuild -bb /usr/src/redhat/SPECS/jikes.spec
      </para>
      <para>
        Warning
      </para>
      <para>
        Don’t build packages when you are logged in as the root user.
        Log in as a normal user instead. This is to limit the damage
        caused to your system if the spec file or the Makefile contains
        errors that delete system files, for example. If you are logged
        in as the root user, you will have permission to perform these
        destructive acts. If you are logged in as a normal user, though,
        these RPM spec file and Makefile errors will fail to run,
        because you don’t have permission to modify system files.
      </para>
      <para>
        This command results in a lot of output, most coming from the
        configure script. (This script examines the C programming
        environment on your system.) When the rpmbuild command
        completes, you’ll see the binary RPM in the proper
        subdirectory of the RPMS directory. You can see the RPM with a
        directory listing, for example:
      </para>
      <para>
        $ls /usr/src/redhat/RPMS/i386:
      </para>
      <para>
        jikes-1.17-1.i386.rpm
      </para>
      <para>
        To stop execution just after the %install section, use a command
        like the following:
      </para>
      <para>
        rpmbuild –bi specfile
      </para>
      <para>
        For example:
      </para>
      <para>
        # rpmbuild -bi /usr/src/redhat/SPECS/jikes.spec
      </para>
      <para>
        To build a source RPM out of the files you have (in this case a
        tar archive of the sources and the spec file), use a command
        like the following:
      </para>
      <para>
        rpmbuild –bs specfile
      </para>
      <para>
        For example:
      </para>
      <para>
        $ rpmbuild -bs /usr/src/redhat/SPECS/jikes.spec
      </para>
      <para>
        When done, you’ll see the source RPM in the
        /usr/src/redhat/SRPMS directory:
      </para>
      <para>
        $ ls /usr/src/redhat/SRPMS
      </para>
      <para>
        jikes-1.17-1.src.rpm
      </para>
      <para>
        To clean out the files created by building these RPMs, use the
        --clean option to the rpmbuild command:
      </para>
      <para>
        rpmbuild --clean specfile
      </para>
      <para>
        For example:
      </para>
      <para>
        $ rpmbuild --clean /usr/src/redhat/SPECS/jikes.spec
      </para>
      <para>
        Executing(--clean): /bin/sh -e /var/tmp/rpm-tmp.21908
      </para>
      <para>
        + umask 022
      </para>
      <para>
        + cd /usr/src/redhat/BUILD
      </para>
      <para>
        + rm -rf jikes-1.17
      </para>
      <para>
        + exit 0
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-rpmbuild"/>  covers a number of addition options for the rpmbuild
        command that you can use to customize the build.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Verifying Your RPMS</title>
    <para>
      After you've built an RPM, you can use the techniques from <xref linkend="ch-using-rpm-db"/> to verify the RPM. You can also use the –bl option to the
      rpmbuild command to verify the list of files in the RPM. Use a
      command like the following:
    </para>
    <para>
      rpmbuild –bl spec_file
    </para>
    <para>
      For example:
    </para>
    <para>
      $ rpmbuild -bl /usr/src/redhat/SPECS/jikes.spec
    </para>
    <para>
      Processing files: jikes-1.17-1
    </para>
    <para>
      error: File not found: /tmp/jikesrpm/usr/bin/jikes
    </para>
    <para>
      error: File not found:
      /tmp/jikesrpm/usr/doc/jikes-1.17/license.htm
    </para>
    <para>
      error: File not found by glob: /tmp/jikesrpm/usr/man/man1/jikes.1*
    </para>
    <para>
      Provides: jikes
    </para>
    <para/>
    <para/>
    <para>
      RPM build errors:
    </para>
    <para>
      File not found: /tmp/jikesrpm/usr/bin/jikes
    </para>
    <para>
      File not found: /tmp/jikesrpm/usr/doc/jikes-1.17/license.htm
    </para>
    <para>
      File not found by glob: /tmp/jikesrpm/usr/man/man1/jikes.1*
    </para>
    <para>
      This example shows a number of errors. The -bl option checks that
      all the necessary files are located within the buildroot
      directory. The buildroot directory is a location that acts like
      the final installed root directory. From the previous example,
      this package was not properly built yet.
    </para>
    <para>
      In a situation like this, you can start over, or use the
      --short-circuit option to restart the build from a given section
      in the spec file. As you create an RPM, you will need to go back
      and forth restarting the build as you detect and fix errors.
    </para>
    <para/>
    <para>
      You can also use the rpm command with options such as –V for
      verification on a fully-built package. For example:
    </para>
    <para>
      $ rpm -Vp /usr/src/redhat/RPMS/i386/jikes-1.17-1.i386.rpm
    </para>
    <para>
      S.5....T /usr/bin/jikes
    </para>
    <para>
      .......T d /usr/doc/jikes-1.17/license.htm
    </para>
    <para>
      ..5....T d /usr/man/man1/jikes.1.gz
    </para>
    <para>
      In this case, you see some file sizes and times differ. These
      differences can be explained by the fact that the original package
      was compiled on a different system and older version of &RH;
      Linux than the version compiled locally.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      See the on "Verifying Installed RPM Packages" section in <xref linkend="ch-using-rpm-db"/> 
      for more on the -V option.
    </para>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      This chapter introduced the task of building RPMs, whether
      building RPMs from your own applications or from software you have
      gathered elsewhere. In both cases, the steps for building the RPMs
      are the same.
    </para>
    <para>
      In most cases, you should build an RPM of the sources for your
      application, an RPM that can be used to reproduce the build of the
      application. Create a second RPM that holds the binary
      application. Once you set up the commands and define the spec file
      for the binary RPM, making a source RPM is trivial.
    </para>
    <para>
      Use the rpmbuild command to create RPMs. This command uses an RPM
      spec file to define the commands and settings for creating the
      RPM.
    </para>
    <para>
      The next chapter delves into the spec files that define the RPM
      directives for your packages.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-customizing-rpm.xml ---
<!-- $Id: -->

<chapter id="ch-customizing-rpm">
  <title>Customizing RPM Behavior</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Defining RPM macros
      </para>
    </listitem>
    <listitem>
      <para>
        Configuring RPM settings
      </para>
    </listitem>
    <listitem>
      <para>
        Adding popt aliases
      </para>
    </listitem>
  </itemizedlist>
  <para>
    RPM provides a high degree of customization in the form of basic
    settings, such as where your RPM database is located and the path to
    common commands like setup or make, to the ability to define new
    macros and command-line aliases. This chapter covers the three main
    ways to customize RPM behavior: RPM macros, RPM rc settings, and
    popt aliases.
  </para>
  <sect1>
    <title>Customizing with RPM Macros</title>
    <para>
      Starting with RPM 3.0, RPM macros have replaced most RPM settings
      from the rpmrc files.
    </para>
    <para>
      An RPM macro defines a setting to the RPM system. A macro can be
      defined as a static value, such as the directory where the RPM
      database is installed. A macro can also be defined in terms of
      other macros. Furthermore, a macro can be defined with parameters.
    </para>
    <para>
      For example, the following defines two macros in a macro file:
    </para>
    <para>
      %_usr /usr
    </para>
    <para>
      %_usrsrc %{_usr}/src
    </para>
    <para>
      In this case, the macro %_usr names the /usr directory. The macro
      %_usrsrc names the /usr/src directory, showing how to set a macro
      in terms of another macro.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      The macro syntax is used in the query formats introduced in
      <xref linkend="ch-using-rpm-db"/> .
    </para>
    <sect2>
      <title>Defining macros</title>
      <para>
        RPM provides a number of places you can define macros, including
        inside spec files (probably the most common usage), in special
        macro initialization files, and on the command line.
      </para>
      <para>
        In each case, the syntax is slightly different.
      </para>
      <sect3>
        <title>Defining Macros in Spec Files</title>
        <para>
          You can define macros in most places in a spec file. With spec
          files, use the %define syntax to define a macro, which uses
          the following syntax:
        </para>
        <para>
          %define name(options) body
        </para>
        <para>
          The options are optional and can include the special values
          defined in Table 21-1.
        </para>
        <para>
          Table 21-1 Special options for macros
        </para>
        <informaltable frame="all">
          <tgroup cols="2">
            <tbody>
              <row>
                <entry>
                  <para>
                    Option
                  </para>
                </entry>
                <entry>
                  <para>
                    Holds
                  </para>
                </entry>
              </row>
              <row>
                <entry>
                  <para>
                    %0
                  </para>
                </entry>
                <entry>
                  <para>
                    The name of the macro
                  </para>
                </entry>
              </row>
              <row>
                <entry>
                  <para>
                    %1
                  </para>
                </entry>
                <entry>
                  <para>
                    The first argument, after processing with getopt
                  </para>
                </entry>
              </row>
              <row>
                <entry>
                  <para>
                    %2-%9
                  </para>
                </entry>
                <entry>
                  <para>
                    Additional arguments
                  </para>
                </entry>
              </row>
              <row>
                <entry>
                  <para>
                    %*
                  </para>
                </entry>
                <entry>
                  <para>
                    All arguments, except for flags that have been
                    processed
                  </para>
                </entry>
              </row>
              <row>
                <entry>
                  <para>
                    %#
                  </para>
                </entry>
                <entry>
                  <para>
                    Number of arguments
                  </para>
                </entry>
              </row>
            </tbody>
          </tgroup>
        </informaltable>
        <para>
          These options are similar to those for shell scripting.
        </para>
        <para>
          Cross Reference
        </para>
        <para>
          <xref linkend="ch-specfiles"/>  covers spec files.
        </para>
        <para>
          In addition to these options, you can use a syntax of %{-a} to
          hold –a if an option of –a was passed. The syntax of
          %{-a*} indicates the value passed after the –a option.
        </para>
        <para>
          You can assign a macro to the value returned by a shell
          command by using syntax like the following:
        </para>
        <para>
          %(shell_command)
        </para>
        <para>
          Note
        </para>
        <para>
          This is similar to the $(shell_command) syntax supported by
          bash.
        </para>
      </sect3>
      <sect3>
        <title>Defining Macros in Macro Initialization Files</title>
        <para>
          Inside a macro file, define macros with the following syntax:
        </para>
        <para>
          %macro_name value
        </para>
        <para>
          Macros defined for the RPM system start with an underscore.
          Some older macros are left without the leading underscore.
        </para>
        <para>
          Note
        </para>
        <para>
          The macros defined with an underscore are not exported into
          rpm headers.
        </para>
        <para>
          The %expand built-in macro will expand the value of something
          else, including executing a shell command. For example, the
          following sets the user’s home directory to the %home macro:
        </para>
        <para>
          %home %{expand:%%(cd; pwd)}
        </para>
        <para>
          Note that it is probably easier to simply set the %home macro
          in your per-user $HOME/.rpmmacros file to the name of your
          home directory rather than try to figure this out
          programmatically.
        </para>
      </sect3>
      <sect3>
        <title>Defining Macros on the Command Line</title>
        <para>
          The rpm command also lets you define macros with the --define
          option. The basic syntax is:
        </para>
        <para>
          $ rpm --define 'macro_name value'
        </para>
        <para>
          Note
        </para>
        <para>
          Do not place the leading percent sign, %, on the macro you
          define with --define.
        </para>
        <para>
          You can evaluate a macro or a macro expression with --eval.
          For example:
        </para>
        <para>
          $ rpm --eval %_usrsrc
        </para>
        <para>
          /usr/src
        </para>
      </sect3>
    </sect2>
    <sect2>
      <title>Customizing Macros</title>
      <para>
        You can add your own macro definitions, using the syntax shown
        in the “Defining Macros in Macro Initialization Files”
        section. These macros are read on each invocation of the rpm or
        rpmbuild commands.
      </para>
      <para>
        To add your custom macros, you must edit one of the macro
        definition files. Table 21-2 lists the macro definition files
        and their usage.
      </para>
      <para>
        Table 21-2 RPM macro files
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  File
                </para>
              </entry>
              <entry>
                <para>
                  Usage
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  /usr/lib/rpm/macros
                </para>
              </entry>
              <entry>
                <para>
                  Official RPM macros
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  /etc/rpm/macros
                </para>
              </entry>
              <entry>
                <para>
                  Per-system customizations
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  $HOME/.rpmmacros
                </para>
              </entry>
              <entry>
                <para>
                  Per-user customizations
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
      <para>
        Note
      </para>
      <para>
        Do not edit the /usr/lib/rpm/macros file, as this file gets
        overwritten when you upgrade to a new version of rpm.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Configuring RPM Settings</title>
    <para>
      RPM includes hundreds of settings based on your current system
      architecture, environment, and which version of the RPM system you
      have installed. The old settings, called rc or rpmrc settings, are
      gradually being phased out by the newer, more consistent and more
      powerful macros.
    </para>
    <para>
      You can still edit the rc settings, but in most cases you should
      edit macros instead.
    </para>
    <sect2>
      <title>Viewing the current settings</title>
      <para>
        To view the current settings, use the --showrc command-line
        option:
      </para>
      <para>
        $ rpm –showrc
      </para>
      <para>
        ARCHITECTURE AND OS:
      </para>
      <para>
        build arch : i386
      </para>
      <para>
        compatible build archs: i686 i586 i486 i386 noarch
      </para>
      <para>
        build os : Linux
      </para>
      <para>
        compatible build os's : Linux
      </para>
      <para>
        install arch : i686
      </para>
      <para>
        install os : Linux
      </para>
      <para>
        compatible archs : i686 i586 i486 i386 noarch
      </para>
      <para>
        compatible os's : Linux
      </para>
      <para/>
      <para>
        RPMRC VALUES:
      </para>
      <para>
        macrofiles :
        /usr/lib/rpm/macros:/usr/lib/rpm/i686-linux/macros:/etc/
      </para>
      <para>
        rpm/macros.specspo:/etc/rpm/macros.db1:/etc/rpm/macros.cdb:/etc/rpm/macros:/etc/
      </para>
      <para>
        rpm/i686-linux/macros:~/.rpmmacros
      </para>
      <para>
        optflags : -O2 -march=i686
      </para>
      <para>
        This command displays the architecture and operating system
        information first, and then lists all the rpmrc values, shown
        here truncated for space.
      </para>
    </sect2>
    <sect2>
      <title>Locating the rpmrc files</title>
      <para>
        The --showrc option reads in all the rpmrc files from the
        various locations. By default, this is /usr/lib/rpm/rpmrc,
        /etc/rpm/rpmrc, and a file named .rpmrc (with a leading period)
        in your home directory.
      </para>
      <para>
        These files are read in the order given, so that the later files
        can override settings in the earlier files.
      </para>
      <para>
        The uses for these files are listed in Table 21-3.
      </para>
      <para>
        Table 21-3 Uses for the rpmrc files
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  File
                </para>
              </entry>
              <entry>
                <para>
                  Holds
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  /usr/lib/rpm/rpmrc
                </para>
              </entry>
              <entry>
                <para>
                  RPM standard settings
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  /etc/rpm/rpmrc
                </para>
              </entry>
              <entry>
                <para>
                  Per-system configuration
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  $HOME/.rpmrc
                </para>
              </entry>
              <entry>
                <para>
                  Per-user configuration
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
      <para>
        Note
      </para>
      <para>
        The file /usr/lib/rpm/rpmrc gets overwritten each time you
        upgrade RPM. Do not customize this file.
      </para>
      <para>
        You can override this list of files by calling the rpm or
        rpmbuild commands with the --rcfile option. This option expects
        a semicolon at nddelimited list of files to read in, in order. For
        example, if you are working on a 686-architecture Intel
        platform, you can create a file with the following setting:
      </para>
      <para>
        optflags: i686 -g
      </para>
      <para>
        Note that this disables optimization, so it is not a good
        setting. (The use of this value will make the result more
        visible.)
      </para>
      <para>
        If you name this file .rpmnew and place it in your home
        directory, you can configure an alternate set of files with the
        --rcfile option and then evaluate the new optflags setting. For
        example:
      </para>
      <para>
        $ rpm --eval "%{optflags}"
      </para>
      <para>
        -O2 -march=i386 -mcpu=i686
      </para>
      <para>
        $ rpm --rcfile $HOME/.rpmnew --eval "%{optflags}"
      </para>
      <para>
        -g
      </para>
      <para>
        This example shows the value before and after changing the
        configuration files.
      </para>
      <para>
        When you use the --rcfile option, only the first file listed
        must exist. The rest of the files are optional. When you use the
        --rcfile option, however, the file /usr/lib/rpm/rpmrc is read
        first, and then the list of files you provide with the --rcfile
        option. The file /usr/lib/rpm/rpmrc is always used.
      </para>
    </sect2>
    <sect2>
      <title>Changing settings</title>
      <para>
        You can edit the per-user or per-system rc files to change the
        settings. The format of the rpmrc files is fairly simple but
        contains a few exceptions. The most basic format is:
      </para>
      <para>
        setting: value
      </para>
      <para>
        The settings get more complicated as the rpmrc syntax supports
        defining settings for multiple architectures at once. In that
        case, the typical format is:
      </para>
      <para>
        setting: uname: value
      </para>
      <para>
        The uname portion is replaced by a value that comes from the
        uname(2) system call, for example, i686 on a 686-class Intel
        architecture machine.
      </para>
      <para>
        Note
      </para>
      <para>
        In most cases, your best bet is to copy an existing setting and
        modify it, rather than remembering all the exceptions.
      </para>
      <sect3>
        <title>Setting the optflags</title>
        <para>
          One exception to the rule is the optflags setting, which
          controls C compiler options for optimization. The format for
          the optflags setting is:
        </para>
        <para>
          setting: arch value
        </para>
        <para>
          There is no colon after the architecture. For example:
        </para>
        <para>
          optflags: i686 -O2 -march=i686
        </para>
        <para>
          optflags: alphaev5 -O2 -mieee -mcpu=ev5
        </para>
        <para>
          This example sets the optimization flags for an i686 system to
          -O2 -march=i686 and an alphaev5 system to -O2 -mieee
          -mcpu=ev5. If your system is running on a 686-class processor,
          you will get one set of optimization flags. If your system is
          running on a V5 Alpha processor, you will get a different set.
        </para>
      </sect3>
      <sect3>
        <title>Setting the Architecture Values</title>
        <para>
          The arch_canon setting builds up a table of mappings between
          architecture names and the numbers used internally. The
          following example shows the Intel and SPARC architecture
          settings to 1 and 3 internally.
        </para>
        <para>
          arch_canon: athlon: athlon 1
        </para>
        <para>
          arch_canon: i686: i686 1
        </para>
        <para>
          arch_canon: i586: i586 1
        </para>
        <para>
          arch_canon: i486: i486 1
        </para>
        <para>
          arch_canon: i386: i386 1
        </para>
        <para/>
        <para>
          arch_canon: sparc: sparc 3
        </para>
        <para>
          arch_canon: sun4: sparc 3
        </para>
        <para>
          arch_canon: sun4m: sparc 3
        </para>
        <para>
          arch_canon: sun4c: sparc 3
        </para>
        <para>
          arch_canon: sun4d: sparc 3
        </para>
        <para>
          arch_canon: sparcv9: sparcv9 3
        </para>
        <para>
          The arch_compat setting builds a table of compatible
          architectures. The format is:
        </para>
        <para>
          arch_compat: arch: compatible_with
        </para>
        <para>
          This sets the given architecture arch as being compatible with
          another architecture.
        </para>
        <para>
          For example:
        </para>
        <para>
          arch_compat: athlon: i686
        </para>
        <para>
          This setting indicates that an athlon architecture is
          compatible with an i686. The table gets built up further with
          the following Intel-architecture compatibilities:
        </para>
        <para>
          arch_compat: i686: i586
        </para>
        <para>
          arch_compat: i586: i486
        </para>
        <para>
          arch_compat: i486: i386
        </para>
        <para>
          arch_compat: i386: noarch
        </para>
        <para>
          The os_canon setting defines a table of operating system
          labels and internal numeric values. The basic syntax is:
        </para>
        <para>
          os_canon: arch: name value
        </para>
        <para>
          The arch comes from the uname(2) call. The name provides an
          RPM name for that operating system, and the value defines an
          internal numeric ID for that OS, for example:
        </para>
        <para>
          os_canon: Linux: Linux 1
        </para>
        <para>
          os_canon: HP-UX: hpux10 6
        </para>
        <para>
          The buildarchtranslate setting defines the operating system
          settings to use as the build architecture. This value
          translates information from the uname(2) call to a value used
          by the arch_canon setting. For example:
        </para>
        <para>
          buildarchtranslate: athlon: i386
        </para>
        <para>
          buildarchtranslate: i686: i386
        </para>
        <para>
          buildarchtranslate: i586: i386
        </para>
        <para>
          buildarchtranslate: i486: i386
        </para>
        <para>
          buildarchtranslate: i386: i386
        </para>
        <para/>
        <para>
          buildarchtranslate: sun4c: sparc
        </para>
        <para>
          buildarchtranslate: sun4d: sparc
        </para>
        <para>
          buildarchtranslate: sun4m: sparc
        </para>
        <para>
          buildarchtranslate: sparcv9: sparc
        </para>
        <para>
          buildarchtranslate: sun4u: sparc64
        </para>
      </sect3>
    </sect2>
  </sect1>
  <sect1>
    <title>Adding Popt Aliases</title>
    <para>
      Popt provides a powerful library and RPM subsystem for handling
      the very complex RPM command-line options. You can customize your
      RPM usage by defining popt aliases for complex command-line
      arguments to the rpm or rpmbuild commands. A popt alias is a
      command-line option that expands to other command-line options.
    </para>
    <para>
      This technique is used internally to define quite a few
      command-line options to the rpm and rpmbuild commands in terms of
      other, more complex options. Many of these aliases define simple
      command-line options in place of more complex query format
      options.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      <xref linkend="ch-using-rpm-db"/>  covers the query format.
    </para>
    <para>
      For example, the following entry defines the --requires and –R
      command-line options to the rpm command:
    </para>
    <para>
      rpm alias --requires --qf \
    </para>
    <para>
      "[%{REQUIRENAME} %{REQUIREFLAGS:depflags} %{REQUIREVERSION}\n]" \
    </para>
    <para>
      --POPTdesc=$"list capabilities required by package(s)"
    </para>
    <para>
      rpm alias -R --requires
    </para>
    <para>
      These options are set in the file /usr/lib/rpm/rpmpopt-4.1.
    </para>
    <para>
      Note
    </para>
    <para>
      This is specific to RPM 4.1. Other releases of RPM use the same
      naming format but with the current RPM version number, such as 4.2
      and so on.
    </para>
    <sect2>
      <title>Defining aliases</title>
      <para>
        Defining aliases is pretty easy. The basic syntax is:
      </para>
      <para>
        command_name alias option expansion
      </para>
      <para>
        To create an alias for the rpm command, you use rpm for the
        command_name.
      </para>
      <para>
        Note
      </para>
      <para>
        The command_name must be the name passed to the C poptGetContext
        function, covered in <xref linkend="ch-programming-c"/> .
      </para>
      <para>
        Follow this with alias and then the option. You will need
        separate aliases for the long and short options. The expansion
        defines the alias in terms of other already-defined command-line
        parameters.
      </para>
      <para>
        You can define some complex aliases, such as the following one
        to display information about a package:
      </para>
      <para>
        rpm alias --info --qf 'Name : %-27{NAME} Relocations:
        %|PREFIXES?{[%{PREFIXES} ]}:{(not relocateable)}|\n\
      </para>
      <para>
        Version : %-27{VERSION} Vendor: %{VENDOR}\n\
      </para>
      <para>
        Release : %-27{RELEASE} Build Date: %{BUILDTIME:date}\n\
      </para>
      <para>
        Install date: %|INSTALLTIME?{%-27{INSTALLTIME:date}}:{(not
        installed) }| Build Host: %{BUILDHOST}\n\
      </para>
      <para>
        Group : %-27{GROUP} Source RPM: %{SOURCERPM}\n\
      </para>
      <para>
        Size : %-27{SIZE}%|LICENSE?{ License: %{LICENSE}}|\n\
      </para>
      <para>
        Signature :
        %|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|\n\
      </para>
      <para>
        %|PACKAGER?{Packager : %{PACKAGER}\n}|\
      </para>
      <para>
        %|URL?{URL : %{URL}\n}|\
      </para>
      <para>
        Summary : %{SUMMARY}\n\
      </para>
      <para>
        Description :\n%{DESCRIPTION}\n' \
      </para>
      <para>
        --POPTdesc=$"list descriptive information from package(s)"
      </para>
      <para>
        Popt aliases get evaluated into Linux commands, so you can use
        pipes and other aspects of Linux shells in your aliases.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        Look closely at the examples in the /usr/lib/rpm/rpmpopt-4.1
        file. This is the most complete set of popt alias examples for
        RPM commands.
      </para>
      <para>
        You can also define aliases that can set RPM macros, such as the
        following alias for setting the path to the RPM database:
      </para>
      <para>
        rpm alias --dbpath --define '_dbpath !#:+'
      </para>
      <para>
        In this example, !#:+ was defined to behave like a shell
        history-editing command. With popt, this means to grab the next
        command-line parameter and place it into the command defined for
        the alias.
      </para>
      <para>
        To support the --help and --usage options, you can define the
        --POPTdesc and --POPTargs options to the alias as shown in the
        previous examples. These options also support
        internationalization.
      </para>
      <para>
        All together, the popt alias setting is very close to the popt
        option table entries used with the C programming API.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-programming-c"/>  shows how to program with the popt library.
      </para>
    </sect2>
    <sect2>
      <title>Customizing popt aliases</title>
      <para>
        Like RPM macros and settings, popt aliases are defined in a
        cascading set of files. The official RPM aliases are defined in
        /usr/lib/rpm/rpmpopt-4.1 for rpm 4.1.
      </para>
      <para>
        Note
      </para>
      <para>
        Do not modify this file! The RPM system depends on this file for
        proper functioning. Incorrect changes might disable many options
        to the rpm command.
      </para>
      <para>
        Store per-system popt aliases in /etc/popt. Store per-user
        aliases in $HOME/.popt (with a leading period).
      </para>
      <para>
        Note
      </para>
      <para>
        These files are shared by all applications that use popt.
      </para>
      <para>
        For example, you can define an alias for rpm -qa that executes
        faster than the normal query all packages command, by turning
        off the tests for digest signature verification. To do so, add
        the following line to a file named .popt in your home directory:
      </para>
      <para>
        rpm alias --qall -qa --nodigest --nosignature
      </para>
      <para>
        Once you set up this alias, you can run the following command in
        place of rpm -qa:
      </para>
      <para>
        $ rpm --qall
      </para>
      <para>
        This should execute about one-third to one-half faster than the
        normal rpm -qa command.
      </para>
      <para>
        Warning
      </para>
      <para>
        Turning off the signature and digest tests means you are
        ignoring important information that pertains to the integrity of
        your system. That is why the alias shown here does not override
        the normal -qa option, and instead defines a new --qall option
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      This chapter shows the many ways you can customize RPM usage for
      your system or your own personal environment. You can define RPM
      macros, which is the preferred way to make RPM settings. Or you
      can set RPM values in the older rpmrc files, which are now mostly
      replaced by RPM macros.
    </para>
    <para>
      Using popt, the powerful command-line option parser, you can
      define aliases to add simple options that popt expands into
      whatever you define. Many of the rpm command-line options are
      defined this way.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-dependencies.xml ---
<!-- $Id: -->

<chapter id="ch-dependencies">
  <title>Package Dependencies</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Understanding dependencies
      </para>
    </listitem>
    <listitem>
      <para>
        Package capabilities
      </para>
    </listitem>
    <listitem>
      <para>
        Version dependencies
      </para>
    </listitem>
    <listitem>
      <para>
        Checking dependencies
      </para>
    </listitem>
    <listitem>
      <para>
        Triggers
      </para>
    </listitem>
  </itemizedlist>
  <para>
    Packages aren’t built in a vacuum. Web applications, for example,
    build on system networking libraries, system-encryption libraries,
    and system-file input and output libraries.
  </para>
  <para>
    This chapter covers dependencies between packages, along with ways
    to discover and manage those dependencies.
  </para>
  <sect1>
    <title>Understanding the Dependency Concept</title>
    <para>
      A dependency occurs when one package depends on another. You might
      think it would make for an easier-to-manage system if no package
      depended on any others, but you’d face a few problems, not the
      least of which would be dramatically increased disk usage.
    </para>
    <para>
      Packages on your Linux system depend on other packages. Just about
      every package with an application, for example, depends on the
      system C libraries, since these libraries provide common
      facilities that just about every program uses. Network
      applications typically depend on low-level networking libraries.
      These dependencies really work in your favor, since a security bug
      fix in the network libraries can update all applications that make
      use of the updated libraries.
    </para>
    <para>
      Furthermore, sharing software means that each package has less
      code to maintain and thus improved quality. Code sharing has been
      in the computer lexicon since the 1960s.
    </para>
    <para>
      Although quite a few packages depend on system-level libraries,
      some packages depend on applications defined in other packages.
      The Emacs text editor package, for example, depends on the Perl
      scripting language, specifically, the perl command. Database
      client programs usually depend on the database server
      applications.
    </para>
    <para>
      The RPM database tracks dependency information, so it can, for
      example, stop attempts to remove packages that other packages
      depend on or inform users of dependent packages upon installation.
    </para>
    <sect2>
      <title>Capabilities</title>
      <para>
        In RPM terminology, each package provides capabilities. A
        capability is simply a text string that the package claims it
        provides. In most cases, a capability names a file or a package.
        But the capability can be any arbitrary text string.
      </para>
      <para>
        Other packages can then depend on certain capabilities. (You can
        use this concept in building your own packages.) Each package
        lists the capabilities it requires as well as the capabilities
        it provides.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        Package dependencies and capabilities are very important when
        creating spec files for building your own RPM packages, the
        subject of <xref linkend="ch-specfiles"/> .
      </para>
      <para>
        When you install a package, the capability information is stored
        in the RPM database. When you remove a package, the rpm command
        checks the RPM database. If the package you are trying to remove
        provides a capability that another package needs, the command
        will generate an error. If you try to remove a package that
        other packages depend on, you'll see an error like the
        following:
      </para>
      <para>
        # rpm -e setup
      </para>
      <para>
        error: Failed dependencies:
      </para>
      <para>
        setup is needed by (installed) basesystem-8.0-1
      </para>
      <para>
        setup >= 2.0.3 is needed by (installed) initscripts-6.95-1
      </para>
      <para>
        setup >= 2.5.4-1 is needed by (installed) filesystem-2.1.6-5
      </para>
      <para>
        setup is needed by (installed) xinetd-2.3.7-2
      </para>
      <para>
        setup is needed by (installed) dump-0.4b28-4
      </para>
      <para>
        To verify that the package has not been removed, you can query
        for the package after trying to remove it, as shown following:
      </para>
      <para>
        # rpm -q setup
      </para>
      <para>
        setup-2.5.20-1
      </para>
      <para>
        This shows that the rpm command has not removed the setup
        package due to the errors.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-using-rpm"/>  covers ways to force the rpm command to do what you
        want, although this can cause problems if you try to force the
        issue and remove a crucial package. In virtually all cases, do
        not use any of the force options, as this can cause problems
        with the RPM system, since the force options are purposely
        ignoring safety checks performed by the rpm command.
      </para>
      <para>
        Many capabilities that packages require are system libraries,
        especially shared libraries. Shared libraries, which usually
        have a .so file extension (short for shared object), provide a
        memory-efficient means for applications to share program code.
        These libraries may also have a .so.number extension, such as
        libc.so.6.
      </para>
      <para>
        Note
      </para>
      <para>
        Shared libraries on Windows are called DLLs, short for Dynamic
        Link Libraries. The implementations differ, but the Windows DLL
        concept is similar to Linux and Unix shared objects.
      </para>
      <para>
        Shared libraries have been part of Linux for a long time and
        have nothing to do with the RPM system. Shared libraries
        accessed by a program, however, represent natural dependencies.
        Because so many programs depend on shared libraries, the RPM
        system can automatically handle many shared-library
        dependencies.
      </para>
      <para>
        Note
      </para>
      <para>
        To list the shared libraries that a program accesses, use the
        ldd command, for example:
      </para>
      <para>
        $ ldd /bin/grep
      </para>
      <para>
        libc.so.6 => /lib/i686/libc.so.6 (0x42000000)
      </para>
      <para>
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
      </para>
      <para>
        Other dependencies include version-specific dependencies.
      </para>
    </sect2>
    <sect2>
      <title>Version dependencies</title>
      <para>
        An application may depend on a capability provided by another
        package. It may also depend on the capability that a specific
        version of another package provides. For example, some add-ons
        to the Apache Web server depend on the version of Apache. The
        Apache 2.0 version made a number of changes that affect add-on
        packages. Some Apache add-on packages depend on version 1.3;
        others depend on version 2.0.
      </para>
      <para>
        Most package dependencies assume some level of compatibility and
        require a version at or above a given version number (for
        example, version 2.0 or later).
      </para>
      <para>
        Note
      </para>
      <para>
        You’ll see more version dependencies when applications make
        major changes, such as the change from 1.3 to 2.0 for the Apache
        Web server.
      </para>
    </sect2>
    <sect2>
      <title>Conflicts</title>
      <para>
        Some packages may provide capabilities that interfere with those
        in other packages. This is called a conflict. Installing
        conflicting packages is an error. For example, the httpd package
        (the Apache Web server) conflicts with the thttpd package. Both
        packages want to provide the primary Web server for a system.
      </para>
      <para>
        The RPM system will prevent you from installing packages that
        conflict with other packages. You can force the issue, using the
        techniques described in <xref linkend="ch-using-rpm"/> , and override the RPM system.
        But in most cases, you should not install packages that
        conflict.
      </para>
    </sect2>
    <sect2>
      <title>Obsoletes</title>
      <para>
        The RPM system supports one more type of dependency, called
        obsoletes. This refers to a capability that a package provides
        that makes another capability obsolete. For example, a new
        version of the perl interpreter may make an older version
        obsolete. In most cases, the obsoletes dependency should be used
        when the name of a package changes. For example, the apache Web
        server package became the httpd package. You would expect the
        new package, httpd, to obsolete the old package name, apache.
      </para>
      <para>
        This brings the total to four types of dependencies that the RPM
        system tracks:
      </para>
      <para>
        *Requires, which tracks the capabilities a package requires
      </para>
      <para>
        *Provides, which tracks the capabilities a package provides for
        other packages
      </para>
      <para>
        *Conflicts, which describes the capabilities that if installed,
        conflict with capabilities in a package
      </para>
      <para>
        *Obsoletes, which describes the capabilities that this package
        will make obsolete
      </para>
      <para>
        Packages advertise this dependency information. Each dependency
        holds the type, such as requires, a capability, such as a shared
        library or a package name, and optionally a version number, such
        as requiring the python package at a version number greater than
        or equal to 2.2 (python >= 2.2).
      </para>
      <para/>
      <para>
        You can check package dependencies by using, as you’d guess,
        the rpm command.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Checking for Dependencies</title>
    <para>
      The rpm –q command queries the RPM database or RPM package
      files. With the right options to this command, you can check for
      the four types of package dependencies as well. These options are
      based on the concept of capabilities introduced previously.
    </para>
    <para>
      You can query what capabilities a package requires. You can also
      query what capabilities a package provides. You can query for the
      obsoleting and conflicting information as well. Furthermore, given
      a capability, you can query which packages require this capability
      as well as which packages provide this capability.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      There are quite a few more options you can use with the rpm –q
      command for querying packages. See <xref linkend="ch-using-rpm-db"/>  for more on querying
      packages and package files.
    </para>
    <sect2>
      <title>Determining the capabilities a package requires</title>
      <para>
        The first and most important step is to determine what
        capabilities a package requires. If all the required
        capabilities are met, you can safely install the package
        (barring other things that can go wrong, such as conflicts). The
        requires dependencies are by far the most important.
      </para>
      <para>
        The --requires option to the rpm –q command lists the
        capabilities a given package requires. The basic syntax is:
      </para>
      <para>
        rpm –q query_options --requires packages
      </para>
      <para>
        For example:
      </para>
      <para>
        $ rpm -qp --requires sendmail-8.12.5-7.i386.rpm
      </para>
      <para>
        /usr/sbin/alternatives
      </para>
      <para>
        rpmlib(VersionedDependencies) <= 3.0.3-1
      </para>
      <para>
        chkconfig >= 1.3
      </para>
      <para>
        /usr/sbin/useradd
      </para>
      <para>
        /bin/mktemp
      </para>
      <para>
        fileutils
      </para>
      <para>
        gawk
      </para>
      <para>
        sed
      </para>
      <para>
        sh-utils
      </para>
      <para>
        procmail
      </para>
      <para>
        bash >= 2.0
      </para>
      <para>
        /bin/sh
      </para>
      <para>
        /bin/sh
      </para>
      <para>
        /bin/sh
      </para>
      <para>
        /bin/sh
      </para>
      <para>
        /bin/sh
      </para>
      <para>
        rpmlib(PayloadFilesHavePrefix) <= 4.0-1
      </para>
      <para>
        rpmlib(CompressedFileNames) <= 3.0.4-1
      </para>
      <para>
        /bin/bash
      </para>
      <para>
        libcrypto.so.2
      </para>
      <para>
        libcrypt.so.1
      </para>
      <para>
        libc.so.6
      </para>
      <para>
        libc.so.6(GLIBC_2.0)
      </para>
      <para>
        libc.so.6(GLIBC_2.1)
      </para>
      <para>
        libc.so.6(GLIBC_2.1.3)
      </para>
      <para>
        libc.so.6(GLIBC_2.2)
      </para>
      <para>
        libdb-4.0.so
      </para>
      <para>
        libgdbm.so.2
      </para>
      <para>
        libhesiod.so.0
      </para>
      <para>
        liblber.so.2
      </para>
      <para>
        libldap.so.2
      </para>
      <para>
        libnsl.so.1
      </para>
      <para>
        libnsl.so.1(GLIBC_2.0)
      </para>
      <para>
        libresolv.so.2
      </para>
      <para>
        libresolv.so.2(GLIBC_2.0)
      </para>
      <para>
        libresolv.so.2(GLIBC_2.2)
      </para>
      <para>
        libsasl.so.7
      </para>
      <para>
        libssl.so.2
      </para>
      <para>
        This example tests an RPM package file,
        sendmail-8.12.5-7.i386.rpm, for the requires dependency, in
        other words, what capabilities the package requires. The
        sendmail package depends on a lot of other parts of the system,
        as you can see in the response to the command shown previously.
        Most of the dependencies are for system libraries (all the
        dependencies ending in .so or .so.number). This package requires
        other capabilities (packages in this case). It also requires the
        chkconfig package at a specific version, version 1.3 or higher,
        and the bash package at version 2.0 or higher. The sendmail
        package also requires a particular version of the RPM system
        (the rpmlib dependency).
      </para>
      <para>
        Warning
      </para>
      <para>
        Always check what a package requires before installing the
        package. You can also use the --test option when trying to
        install the package to first test whether the installation can
        proceed. See <xref linkend="ch-using-rpm"/>  for details on installing packages and
        the --test option. The rpm command will perform all these checks
        for you anyway. Checking in advance, though, with the --test
        option, helps avoid dependency hell with circular dependencies.
      </para>
      <para>
        You can also check for what an installed package requires with
        the --requires option. For example:
      </para>
      <para>
        rpm -q --requires sendmail
      </para>
      <para>
        You can use the -R short option in place of the --requires
        option.
      </para>
      <para>
        This command returns the same data as the previous command but
        queries an installed package rather than an RPM package file.
      </para>
      <para>
        You might assume that applications have the most dependencies,
        which is true. But even source packages may depend on other
        packages, often the packages needed to build the sources into an
        application. For example, the following command lists the
        capabilities required by a source RPM:
      </para>
      <para>
        $ rpm -qp --requires telnet-0.17-23.src.rpm
      </para>
      <para>
        ncurses-devel
      </para>
      <para>
        Some packages require particular versions of other packages, for
        example:
      </para>
      <para>
        rpm -qp --requires xcdroast-0.98a9-18.src.rpm
      </para>
      <para>
        imlib-devel >= 1.9.13-9
      </para>
      <para>
        gtk+-devel >= 1.2.10
      </para>
      <para>
        desktop-file-utils >= 0.2.92
      </para>
      <para>
        rpmlib(CompressedFileNames) <= 3.0.4-1
      </para>
      <para>
        This example shows that the xcdroast source package requires the
        imlib-devel capability (in this case, a package) at version
        1.9.13-9 or higher, the gtk+-devel package at version 1.2.10 or
        higher, and the desktop-file-utils package at version 0.2.92 or
        higher. This is a more stringent requirement than just depending
        on the given packages being installed. This RPM is also an older
        RPM package, based on the requirement for the rpmlib to be prior
        or equal to 3.0.4-1.
      </para>
      <para>
        Some packages may require a particular version of the rpmlib, or
        RPM library. For example, the setup package contains special
        system configuration files, including the default password file,
        /etc/passwd.
      </para>
      <para>
        $ rpm -q --requires setup
      </para>
      <para>
        rpmlib(PayloadFilesHavePrefix) <= 4.0-1
      </para>
      <para>
        rpmlib(CompressedFileNames) <= 3.0.4-1
      </para>
      <para>
        As shown in this example, this package depends only on
        capabilities of the RPM system itself. The particular
        requirements shown here specify how the rpm command should treat
        the package payload, including how the files are listed in the
        package and what type of compression is used.
      </para>
    </sect2>
    <sect2>
      <title>Determining the capabilities a package provides</title>
      <para>
        Packages require capabilities, and they can provide capabilities
        for other packages to require. To list the capabilities a
        package provides, use the --provides option. These capabilities
        can be arbitrary names, shared libraries (.so files), and the
        package name itself. The basic syntax is:
      </para>
      <para>
        rpm –q query_options --provides packages
      </para>
      <para>
        For example, the tcsh shell package provides two capabilities,
        at a particular version number, as shown following:
      </para>
      <para>
        $ rpm -q --provides tcsh
      </para>
      <para>
        csh = 6.12
      </para>
      <para>
        tcsh = 6.12-2
      </para>
      <para>
        Other packages provide a lot more, including shared libraries.
        The httpd package provides a long list of capabilities, as shown
        following:
      </para>
      <para>
        $ rpm -q --provides httpd
      </para>
      <para>
        webserver
      </para>
      <para>
        httpd-mmn = 20020628
      </para>
      <para>
        libapr.so.0
      </para>
      <para>
        libaprutil.so.0
      </para>
      <para>
        mod_access.so
      </para>
      <para>
        mod_actions.so
      </para>
      <para>
        mod_alias.so
      </para>
      <para>
        mod_asis.so
      </para>
      <para>
        mod_auth_anon.so
      </para>
      <para>
        mod_auth_dbm.so
      </para>
      <para>
        mod_auth_digest.so
      </para>
      <para>
        mod_auth.so
      </para>
      <para>
        mod_autoindex.so
      </para>
      <para>
        mod_cern_meta.so
      </para>
      <para>
        mod_cgi.so
      </para>
      <para>
        mod_dav_fs.so
      </para>
      <para>
        mod_dav.so
      </para>
      <para>
        mod_deflate.so
      </para>
      <para>
        mod_dir.so
      </para>
      <para>
        mod_env.so
      </para>
      <para>
        mod_expires.so
      </para>
      <para>
        mod_headers.so
      </para>
      <para>
        mod_imap.so
      </para>
      <para>
        mod_include.so
      </para>
      <para>
        mod_info.so
      </para>
      <para>
        mod_log_config.so
      </para>
      <para>
        mod_mime_magic.so
      </para>
      <para>
        mod_mime.so
      </para>
      <para>
        mod_negotiation.so
      </para>
      <para>
        mod_proxy_connect.so
      </para>
      <para>
        mod_proxy_ftp.so
      </para>
      <para>
        mod_proxy_http.so
      </para>
      <para>
        mod_proxy.so
      </para>
      <para>
        mod_rewrite.so
      </para>
      <para>
        mod_setenvif.so
      </para>
      <para>
        mod_speling.so
      </para>
      <para>
        mod_status.so
      </para>
      <para>
        mod_suexec.so
      </para>
      <para>
        mod_unique_id.so
      </para>
      <para>
        mod_userdir.so
      </para>
      <para>
        mod_usertrack.so
      </para>
      <para>
        mod_vhost_alias.so
      </para>
      <para>
        httpd = 2.0.40-8
      </para>
    </sect2>
    <sect2>
      <title>Checking for conflicts</title>
      <para>
        Use the --conflicts option to check what conflicts with a given
        package. The basic syntax is:
      </para>
      <para>
        rpm –q query_options --conflicts packages
      </para>
      <para>
        For example:
      </para>
      <para>
        # rpm -q --conflicts httpd
      </para>
      <para>
        thttpd
      </para>
      <para>
        This command tells you that the httpd package (the Apache Web
        server) conflicts with the thttpd package. Both packages provide
        a similar capability. By marking the conflict, the httpd package
        tells you that you cannot normally install both the httpd and
        thttpd packages on a system. This information comes from the
        httpd package, which has an entry in the package that indicates
        the conflict. The conflict is not guaranteed. These packages may
        work together, but the creator of the httpd package felt that
        httpd would not work with the thttpd package and helpfully let
        us all know.
      </para>
      <para>
        The RPM system will report on the conflicts and indicate an
        error if you try to install conflicting packages. The idea of
        conflicts really gives package creators a way to alert users to
        potential problems and to tell us that one package likely
        won’t work with another.
      </para>
      <para>
        The force options discussed in <xref linkend="ch-using-rpm"/>  allow you to override
        conflicts, if absolutely necessary. In most cases, though, a
        conflict presents you with the choice to install one or the
        other of the packages, but not both.
      </para>
    </sect2>
    <sect2>
      <title>Determining which packages require a certain capability</title>
      <para>
        In addition to querying capabilities and requirements of a
        particular package, you can query the capabilities themselves.
        This function allows you to check which packages require a given
        capability.
      </para>
      <para>
        The --whatrequires option tells the rpm command to report on
        which packages in the RPM database require a certain capability.
        The basic syntax is:
      </para>
      <para>
        rpm –q query_options --whatrequires capability
      </para>
      <para>
        Some packages are not required by anything:
      </para>
      <para>
        $ rpm -q --whatrequires tcsh
      </para>
      <para>
        no package requires tcsh
      </para>
      <para>
        Note
      </para>
      <para>
        Don’t worry about the poor tcsh package being lonely. Because
        other packages do not require this package, you can easily
        remove the tcsh package without affecting the rest of your
        system.
      </para>
      <para>
        This example shows a package name as the capability. Shared
        libraries are also considered capabilities. You can query on
        these as well. For example:
      </para>
      <para>
        $ rpm -q --whatrequires librpm-4.1.so
      </para>
      <para>
        rpm-4.1-1.06
      </para>
      <para>
        net-snmp-5.0.1-6
      </para>
      <para>
        rpm-python-4.1-1.06
      </para>
      <para>
        rpm-devel-4.1-1.06
      </para>
      <para>
        rpm-build-4.1-1.06
      </para>
      <para>
        This example shows that the core RPM library is used by a number
        of RPM-related packages, along with, oddly enough, the net-snmp
        system-management package.
      </para>
      <para>
        The capability you query for must be an explicit capability. For
        example, you will get different results if you query for the
        bash package or the command, /bin/bash. If you query for the
        bash package, you will see the packages that explicitly require
        the capability bash. For example:
      </para>
      <para>
        $ rpm -q --whatrequires bash
      </para>
      <para>
        gpm-1.19.3-20
      </para>
      <para>
        info-4.0b-3
      </para>
      <para>
        initscripts-6.40-1
      </para>
      <para>
        sendmail-8.11.6-3
      </para>
      <para>
        sysklogd-1.4.1-4
      </para>
      <para>
        vixie-cron-3.0.1-63
      </para>
      <para>
        ypbind-1.8-1
      </para>
      <para>
        ypserv-1.3.12-2
      </para>
      <para>
        If you instead query for the capability /bin/bash, that is, the
        file /bin/bash, you will see a different list of packages. For
        example:
      </para>
      <para>
        $ rpm -q --whatrequires /bin/bash
      </para>
      <para>
        apmd-3.0final-34
      </para>
      <para>
        at-3.1.8-20
      </para>
      <para>
        autofs-3.1.7-21
      </para>
      <para>
        autofs-3.1.7-21
      </para>
      <para>
        bash-2.05-8
      </para>
      <para>
        bind-9.1.3-4
      </para>
      <para>
        cipe-1.4.5-6
      </para>
      <para>
        crontabs-1.10-1
      </para>
      <para>
        dialog-0.9a-5
      </para>
      <para>
        gpm-1.19.3-20
      </para>
      <para>
        hotplug-2001_04_24-11
      </para>
      <para>
        initscripts-6.40-1
      </para>
      <para>
        ipchains-1.3.10-10
      </para>
      <para>
        iproute-2.2.4-14
      </para>
      <para>
        kudzu-0.99.23-1
      </para>
      <para>
        logwatch-2.1.1-3
      </para>
      <para>
        man-1.5i2-6
      </para>
      <para>
        mkbootdisk-1.4.2-3
      </para>
      <para>
        mkinitrd-3.2.6-1
      </para>
      <para>
        mutt-1.2.5i-17
      </para>
      <para>
        openssh-server-3.1p1-2
      </para>
      <para>
        pine-4.44-1.72.0
      </para>
      <para>
        rpm-build-4.0.3-1.03
      </para>
      <para>
        rusers-server-0.17-12
      </para>
      <para>
        sendmail-8.11.6-3
      </para>
      <para>
        shapecfg-2.2.12-7
      </para>
      <para>
        sharutils-4.2.1-8
      </para>
      <para>
        sysklogd-1.4.1-4
      </para>
      <para>
        tetex-1.0.7-30
      </para>
      <para>
        ucd-snmp-4.2.1-7
      </para>
      <para>
        vixie-cron-3.0.1-63
      </para>
      <para>
        xinetd-2.3.3-1
      </para>
      <para>
        ypbind-1.8-1
      </para>
      <para>
        ypserv-1.3.12-2
      </para>
      <para>
        There is no short form for the --whatrequires option.
      </para>
      <para>
        Other capabilities, especially system-level shared libraries,
        are used by a large number of packages. For example:
      </para>
      <para>
        # rpm -q --whatrequires libcrypt.so.1 | sort
      </para>
      <para>
        autofs-3.1.7-21
      </para>
      <para>
        cvs-1.11.1p1-3
      </para>
      <para>
        cyrus-sasl-1.5.24-23
      </para>
      <para>
        cyrus-sasl-devel-1.5.24-23
      </para>
      <para>
        cyrus-sasl-plain-1.5.24-23
      </para>
      <para>
        fetchmail-5.9.0-1
      </para>
      <para>
        ircii-4.4Z-7
      </para>
      <para>
        krbafs-1.0.9-2
      </para>
      <para>
        nss_ldap-172-2
      </para>
      <para>
        openldap12-1.2.12-4
      </para>
      <para>
        openldap-2.0.11-13
      </para>
      <para>
        openldap-clients-2.0.11-13
      </para>
      <para>
        pam-0.75-19
      </para>
      <para>
        pam_krb5-1.46-1
      </para>
      <para>
        passwd-0.64.1-7
      </para>
      <para>
        perl-5.6.0-17
      </para>
      <para>
        pine-4.44-1.72.0
      </para>
      <para>
        pwdb-0.61.1-3
      </para>
      <para>
        python-1.5.2-35
      </para>
      <para>
        rsh-0.17-5
      </para>
      <para>
        rsh-server-0.17-5
      </para>
      <para>
        screen-3.9.9-3
      </para>
      <para>
        sendmail-8.11.6-3
      </para>
      <para>
        shadow-utils-20000902-4
      </para>
      <para>
        sh-utils-2.0.11-5
      </para>
      <para>
        SysVinit-2.78-19
      </para>
      <para>
        tcsh-6.10-6
      </para>
      <para>
        util-linux-2.11f-17
      </para>
      <para>
        vim-enhanced-5.8-7
      </para>
      <para>
        wu-ftpd-2.6.1-20
      </para>
      <para>
        xinetd-2.3.3-1
      </para>
      <para>
        ypserv-1.3.12-2
      </para>
      <para>
        yp-tools-2.5-1
      </para>
      <para>
        Quite a few packages require encryption and decryption (the
        purpose of this library), making this library crucial to
        operating the system. Many of the packages listed here are in
        turn depended on by even more packages.
      </para>
      <para>
        To help trace back capabilities, you can combine the queries.
        For example:
      </para>
      <para>
        $ rpm -q --provides sendmail
      </para>
      <para>
        smtpdaemon
      </para>
      <para>
        sendmail = 8.11.6-3
      </para>
      <para>
        $ rpm -q --whatrequires smtpdaemon
      </para>
      <para>
        fetchmail-5.9.0-1
      </para>
      <para>
        mutt-1.2.5i-17
      </para>
      <para>
        The first command lists the capabilities that the sendmail
        package provides, including the generic capability of
        smtpdaemon. You can then list which packages require this
        particular capability, as shown in the second command. This is a
        big help for wading through a mess of packages depending on
        packages depending on yet more packages.
      </para>
    </sect2>
    <sect2>
      <title>Determining which package provides a certain capability</title>
      <para>
        To complete the circle, you can query for which package provides
        a certain capability. This knowledge allows you to trace a
        requirement back to the package that provides it.
      </para>
      <para>
        The --whatprovides option tells the rpm command to list the
        capabilities a package provides. Use the --whatprovides option
        with the –q, or query, option to the rpm command. (There is no
        short form for the --whatrprovides option.)
      </para>
      <para>
        The basic syntax follows:
      </para>
      <para>
        rpm –q --whatprovides capability
      </para>
      <para>
        For example, to query what package provides the capability
        webserver, use the following command:
      </para>
      <para>
        $ rpm -q --whatprovides webserver
      </para>
      <para>
        httpd-2.0.40-8
      </para>
      <para>
        In this case, the capability is identified by an arbitrary
        string, webserver. This is a generic name for a given
        capability, serving Web pages.
      </para>
      <para>
        You can also trace individual files using the --whatprovides
        option. For example:
      </para>
      <para>
        $ rpm -q --whatprovides /etc/skel/.bashrc
      </para>
      <para>
        bash-2.05-8
      </para>
      <para>
        Note
      </para>
      <para>
        The rpm –qf command, covered in the last chapter, is an easier
        way to get to the same information when tracking which package
        provides a particular file. For example:
      </para>
      <para>
        rpm -qf /etc/skel/.bashrc
      </para>
      <para>
        bash-2.05-8
      </para>
      <para>
        If you are querying particular files, use rpm –qf. If you are
        querying capabilities, use --whatprovides.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Triggers</title>
    <para>
      A trigger is a script that gets run when a package is installed or
      uninstalled. Triggers allow packages that depend on other packages
      to properly configure themselves when those other packages are
      installed or removed.
    </para>
    <para>
      The --triggers option to the rpm command lists any trigger scripts
      in a given package. For example:
    </para>
    <para>
      $ rpm -q --triggers sendmail
    </para>
    <para>
      triggerpostun script (through /bin/sh) -- sendmail < 8.10.0
    </para>
    <para>
      /sbin/chkconfig --add sendmail
    </para>
    <para>
      This shows that the sendmail mail transfer agent (mail-sending
      program) provides a short trigger script.
    </para>
    <para>
      In contrast, the anonftp (anonymous file transfer) package has a
      fairly complex set of triggers, as shown following:
    </para>
    <para>
      $ rpm -q --triggers anonftp
    </para>
    <para>
      triggerin script (through /bin/sh) -- glibc
    </para>
    <para>
      copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
      2>/dev/null |
    </para>
    <para>
      | cp -df "$file" "$2"; }
    </para>
    <para>
      # Kill off old versions
    </para>
    <para>
      rm -f /var/ftp/lib/ld-* /var/ftp/lib/libc* /var/ftp/lib/libnsl*
      /var/ftp/lib/lib
    </para>
    <para>
      nss_files* &>/dev/null || :
    </para>
    <para>
      # Copy parts of glibc, needed by various programs in bin.
    </para>
    <para>
      LIBCVER=`basename $(ls --sort=time /lib/libc-*.so |head -n 1) .so
      |cut -f2- -d-`
    </para>
    <para>
      copy /lib/ld-${LIBCVER}.so /var/ftp/lib
    </para>
    <para>
      copy /lib/libc-${LIBCVER}.so /var/ftp/lib
    </para>
    <para>
      copy /lib/libnsl-${LIBCVER}.so /var/ftp/lib
    </para>
    <para>
      copy /lib/libnss_files-${LIBCVER}.so /var/ftp/lib
    </para>
    <para>
      md5sum /var/ftp/lib/lib*-*.so /var/ftp/lib/libtermcap.so.*.*.*
      2>/dev/null >/var
    </para>
    <para>
      /ftp/lib/libs.md5
    </para>
    <para>
      chmod 0400 /var/ftp/lib/libs.md5
    </para>
    <para>
      # Use ldconfig to build symlinks and whatnot.
    </para>
    <para>
      [ ! -e /var/ftp/etc/ld.so.conf ] && touch
      /var/ftp/etc/ld.so.conf
    </para>
    <para>
      /sbin/ldconfig -r /var/ftp
    </para>
    <para>
      triggerin script (through /bin/sh) -- fileutils
    </para>
    <para>
      copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
      2>/dev/null |
    </para>
    <para>
      | cp -df "$file" "$2"; }
    </para>
    <para>
      copy /bin/ls /var/ftp/bin
    </para>
    <para>
      md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
      >/var/ftp/bin/bin.md5
    </para>
    <para>
      chmod 0400 /var/ftp/bin/bin.md5
    </para>
    <para>
      triggerin script (through /bin/sh) -- cpio
    </para>
    <para>
      copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
      2>/dev/null |
    </para>
    <para>
      | cp -df "$file" "$2"; }
    </para>
    <para>
      copy /bin/cpio /var/ftp/bin
    </para>
    <para>
      md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
      >/var/ftp/bin/bin.md5
    </para>
    <para>
      chmod 0400 /var/ftp/bin/bin.md5
    </para>
    <para>
      triggerin script (through /bin/sh) -- tar
    </para>
    <para>
      copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
      2>/dev/null |
    </para>
    <para>
      | cp -df "$file" "$2"; }
    </para>
    <para>
      copy /bin/tar /var/ftp/bin
    </para>
    <para>
      md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
      >/var/ftp/bin/bin.md5
    </para>
    <para>
      chmod 0400 /var/ftp/bin/bin.md5
    </para>
    <para>
      triggerin script (through /bin/sh) -- gzip
    </para>
    <para>
      copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
      2>/dev/null |
    </para>
    <para>
      | cp -df "$file" "$2"; }
    </para>
    <para>
      copy /bin/gzip /var/ftp/bin
    </para>
    <para>
      ln -sf gzip /var/ftp/bin/zcat
    </para>
    <para>
      md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
      >/var/ftp/bin/bin.md5
    </para>
    <para>
      chmod 0400 /var/ftp/bin/bin.md5
    </para>
    <para>
      triggerin script (through /bin/sh) -- libtermcap
    </para>
    <para>
      copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
      2>/dev/null |
    </para>
    <para>
      | cp -df "$file" "$2"; }
    </para>
    <para>
      rm -f /var/ftp/lib/libtermcap.so.*.*.* &>/dev/null || :
    </para>
    <para>
      copy '/lib/libtermcap.so.*.*.*' /var/ftp/lib
    </para>
    <para>
      md5sum /var/ftp/lib/lib*-*.so /var/ftp/lib/libtermcap.so.*.*.*
      2>/dev/null >/var
    </para>
    <para>
      /ftp/lib/libs.md5
    </para>
    <para>
      chmod 0400 /var/ftp/lib/libs.md5
    </para>
    <para>
      # Use ldconfig to build symlinks and whatnot.
    </para>
    <para>
      [ ! -e /var/ftp/etc/ld.so.conf ] && touch
      /var/ftp/etc/ld.so.conf
    </para>
    <para>
      /sbin/ldconfig -r /var/ftp
    </para>
    <para>
      triggerin script (through /bin/sh) -- ncompress
    </para>
    <para>
      copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
      2>/dev/null |
    </para>
    <para>
      | cp -df "$file" "$2"; }
    </para>
    <para>
      copy /usr/bin/compress /var/ftp/bin
    </para>
    <para>
      md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
      >/var/ftp/bin/bin.md5
    </para>
    <para>
      chmod 0400 /var/ftp/bin/bin.md5
    </para>
    <para>
      triggerpostun script (through /bin/sh) -- anonftp 4.0
    </para>
    <para>
      if [ "$2" != 1 ] ; then
    </para>
    <para>
      # The user has multiple glibc packages installed. We can't read
      the
    </para>
    <para>
      # user's mind, so don't do anything.
    </para>
    <para>
      exit 0
    </para>
    <para>
      fi
    </para>
    <para>
      copy() { file="`ls --sort=time $1 |head -n 1`"; ln -f "$file" "$2"
      2>/dev/null |
    </para>
    <para>
      | cp -df "$file" "$2"; }
    </para>
    <para>
      # Kill off old versions
    </para>
    <para>
      rm -f /var/ftp/lib/ld-* /var/ftp/lib/libc* /var/ftp/lib/libnsl*
      /var/ftp/lib/lib
    </para>
    <para>
      nss_files* &>/dev/null || :
    </para>
    <para>
      # Copy parts of glibc, needed by various programs in bin.
    </para>
    <para>
      LIBCVER=`basename /lib/libc-*.so .so | cut -f2- -d-`
    </para>
    <para>
      copy /lib/ld-${LIBCVER}.so /var/ftp/lib
    </para>
    <para>
      copy /lib/libc-${LIBCVER}.so /var/ftp/lib
    </para>
    <para>
      copy /lib/libnsl-${LIBCVER}.so /var/ftp/lib
    </para>
    <para>
      copy /lib/libnss_files-${LIBCVER}.so /var/ftp/lib
    </para>
    <para>
      copy /bin/ls /var/ftp/bin
    </para>
    <para>
      copy /bin/cpio /var/ftp/bin
    </para>
    <para>
      copy /bin/tar /var/ftp/bin
    </para>
    <para>
      copy /bin/gzip /var/ftp/bin
    </para>
    <para>
      ln -sf gzip /var/ftp/bin/zcat
    </para>
    <para>
      copy /usr/bin/compress /var/ftp/bin
    </para>
    <para>
      rm -f /var/ftp/lib/libtermcap.so.*.*.* &>/dev/null || :
    </para>
    <para>
      copy '/lib/libtermcap.so.*.*.*' /var/ftp/lib
    </para>
    <para>
      # Use ldconfig to build symlinks and whatnot.
    </para>
    <para>
      [ ! -e /var/ftp/etc/ld.so.conf ] && touch
      /var/ftp/etc/ld.so.conf
    </para>
    <para>
      /sbin/ldconfig -r /var/ftp
    </para>
    <para>
      # Generate md5sums for verifyscript
    </para>
    <para>
      md5sum /var/ftp/lib/lib*-*.so /var/ftp/lib/libtermcap.so.*.*.*
      2>/dev/null >/var
    </para>
    <para>
      /ftp/lib/libs.md5
    </para>
    <para>
      chmod 0400 /var/ftp/lib/libs.md5
    </para>
    <para>
      md5sum `ls /var/ftp/bin/* |grep -v bin.md5`
      >/var/ftp/bin/bin.md5
    </para>
    <para>
      chmod 0400 /var/ftp/bin/bin.md5
    </para>
    <para>
      Reading through the scripts indicates that this package seems to
      be triggered by the glibc standard C programming library package.
      You can confirm this by using the --triggeredby option to the rpm
      command, as shown following:
    </para>
    <para>
      $ rpm -q --triggeredby glibc
    </para>
    <para>
      anonftp-4.0-9
    </para>
    <para>
      The anonftp package needs to be notified on changes to the glibc
      package, so that the anonftp package can properly set up its
      application. It actually uses part of glibc and is therefore
      highly susceptible to changes in the glibc package. Thus, the use
      of triggers provides essentially an extended form of dependencies.
      The anonftp package in this example depends so much on the glibc
      package that it needs to execute scripts whenever the glibc
      package changes.
    </para>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      Linux comes with many packages. Most of these packages depend on
      some other packages installed on your system. In RPM terms,
      packages provide capabilities and depend on capabilities that
      other packages provide. When the rpm command checks the RPM
      database for dependencies, it checks to ensure that all the
      capabilities that a given package requires are met by other
      installed packages.
    </para>
    <para>
      You can trace the capabilities a package requires with the
      --requires option to the rpm command. You can see what
      capabilities a package provides for others with the --provides
      option.
    </para>
    <para>
      Once you know a capability, you can query which package provides
      that capability with the --whatprovides option to the rpm command.
      And you can see which packages require that capability with the
      --whatrequires option.
    </para>
    <para>
      Triggers are an extended form of dependencies. A trigger is a
      script that gets executed when other packages are installed or
      removed. This allows a package with a high dependence on another
      package to track changes in that package and reconfigure itself as
      needed.
    </para>
    <para>
      The next chapter delves into transactions, which provide a safe
      means to install a set of packages. With transactions, either all
      the packages get installed, or none.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-development-tools.xml ---
<!-- $Id: -->

<chapter id="ch-development-tools">
  <title>Linux Text Editors and Development Tools</title>
  <para>
    This appendix covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        General text editors
      </para>
    </listitem>
    <listitem>
      <para>
        C-specific tools and integrated development environments
      </para>
    </listitem>
    <listitem>
      <para>
        Python-specific development tools
      </para>
    </listitem>
  </itemizedlist>
  <para>
    Linux includes a number of text editors and integrated development
    environments (IDEs), going from plain old text editors all the way
    up to sophisticated tools. These tools are suitable for shell
    scripting, C, Python, and Perl programming, along with a plethora of
    other uses. Linux makes extensive use of text files, especially for
    configuration data, so Linux has always included a number of text
    editors.
  </para>
  <para>
    This appendix lists a number of tools for those who have not yet set
    up an RPM development environment on Linux. Note that choosing an
    editor or IDE is mostly a matter of personal taste. Programmers will
    often engage in raging battles over the superiority of text editors
    and other programming tools. Before searching around too far, try
    out what you have installed on your system and see if that works for
    you.
  </para>
  <para>
    Note that Internet sites may change or disappear, so you may have to
    search to find these tools.
  </para>
  <sect1>
    <title>General Text Editors</title>
    <para>
      Linux distributions include a number of text editors with varying
      sets of features. The two most common editors are vi and emacs,
      which come with virtually all Linux distributions. These editors
      are good for UNIX- or Linux-savvy developers, but generally have a
      steep learning curve for developers used only to Windows.
    </para>
    <para>
      If you come from Windows, try gedit, kedit, or kate. These text
      editors open a graphical window on your desktop, making them
      appear more or less like the Windows Notepad.exe. All three offer
      more features than Notepad.exe, however.
    </para>
    <para>
      You may not have installed any of these editors, but all are
      available as part of &RHL;. You can install vi, emacs,
      gedit, kedit, or kate from the packages that come with your Linux
      distribution.
    </para>
    <para>
      To start one of the editors, enter a command like the following:
    </para>
    <para>
      $ gedit listrpmpkgs &
    </para>
    <para>
      The ampersand, &, launches the program in the background.
      Replace gedit with the editor you choose.
    </para>
  </sect1>
  <sect1>
    <title>Programming Text Editors</title>
    <para>
      In addition to general-purpose text editors, Linux sports a large
      number of text editors with special features for programming, such
      as syntax highlighting. The extended version of vi, called vim,
      includes a number of add-ons that can help you with C programming
      tasks. Emacs also includes a wide array of features to help
      programming. Both of these editors can act as development
      environments with a bit of configuration. As mentioned previously,
      both come with most Linux distributions.
    </para>
    <para>
      I also like an editor called nedit and another one called jedit.
      The jedit editor is written in Java, so that it runs the same on
      Windows and Linux, a big win if you must work on multiple
      platforms. (Emacs and vim have versions that work on Windows, too,
      along with Linux.) If you use jedit, you must have a Java runtime
      environment installed.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      Download nedit from www.nedit.org. Download jedit from
      www.jedit.org. Download Java runtime environments from Sun at
      http://java.sun.com/j2se/downloads.html or IBM at
      www.ibm.com/java/jdk/ and select the IBM Developer Kit for Linux.
    </para>
  </sect1>
  <sect1>
    <title>Integrated Development Environments for C Programming</title>
    <para>
      If you want more of a graphical environment, &RHL; ships
      with KDevelop, an IDE for C and C++ programming.
    </para>
    <para>
      Anjuta provides a GTK/GNOME-based IDE, an alternative to the
      KDE-based KDevelop. KDevelop, however, supports KDE, GNOME, Qt,
      and text-mode C and C++ applications.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      Download Anjuta from www.anjuta.org.
    </para>
    <para>
      The Eclipse IDE, while mostly used for Java development, has a C
      and C++ mode called CDT, for C/C++ Development Tools. Eclipse is
      important because &RH; provides an RPM-building plug-in to
      Eclipse.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      Download Anjuta from www.anjuta.org. Download Eclipse from
      www.eclipse.org and the Eclipse CDT from
      www.eclipse.org/tools/downloads.html.
    </para>
  </sect1>
  <sect1>
    <title>Integrated Development Environments for Python Programming</title>
    <para>
      As with C programs, Python scripts are made up of text files
      holding Python commands, so you need a text editor or some sort of
      development environment for creating Python programs. Any of the
      tools listed so far will work fine for developing Python
      applications. The key requirement is the ability to control tabs
      and indenting, since this is crucial to Python syntax.
    </para>
    <para>
      IDLE, a graphical console and editor, supports creating Python
      applications. This is considered part of Python. IDLE requires the
      Python-tools package.
    </para>
    <para>
      In addition, you can choose from Python-focused tools such as
      Bicycle Repair Man, a refactoring tool, or Boa Constructor and
      Black Adder, two Python IDEs.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      Boa Constructor is available from
      http://boa-constructor.sourceforge.net. Black Adder is a
      commercial tool available at www.thekompany.com.
    </para>
    <para>
      The Eclipse IDE, mentioned previously, supports a number of Python
      add-ons. Combined with the C and C++ tools, and plug-ins for
      building RPMs, Eclipse brings together most everything you need
      for Python development on Linux.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      Eclipse is available at www.eclipse.org, and Python add-ons at
      http://sourceforge.net/projects/pyeclipse,
      http://sourceforge.net/projects/pe4eclipse, or
      http://www.kalab.com/freeware/pythoneclipse/pythoneclipse.htm.
    </para>
    <para>
      This is really just the tip of the iceberg when it comes to Python
      tools. You can find many more available on the Internet.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      A large listing of Python editing tools appears at
      http://www.python.org/cgi-bin/moinmoin/PythonEditors.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-extra-packaging-tools.xml ---
<!-- $Id: -->

<chapter id="ch-extra-packaging-tools">
  <title>Supplemental Packaging Software</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Understanding packaging aids
      </para>
    </listitem>
    <listitem>
      <para>
        Manipulating packages
      </para>
    </listitem>
  </itemizedlist>
  <para>
    RPM is intended to make system management easier, both for system
    administrators and other users who do all the day-to-day work of
    installing and removing applications and for developers and other
    users who do all the work of preparing applications for
    installation. For RPM packagers, the work involved in preparing an
    application for installation has two phases: first, the software
    must be compiled (if it is not written in an interpreted language
    such as Perl) and otherwise configured for the system on which it
    will be installed; then the RPM package of the software must be
    prepared by creating a spec file that properly packages it into an
    RPM. In contrast, packagers who choose to package applications in a
    simpler format, such as gzipped tarballs (compressed tar archives),
    have less work ahead of them, since they need only concern
    themselves with the first step.
  </para>
  <para>
    After a packager has prepared an RPM package once, RPM makes the
    first step (compilation and configuration) easier when the packager
    has to package an updated version of the same software; RPM does a
    lot of work to track compilation commands, any needed patches, and
    any configuration modifications discovered to be necessary to
    prepare the software. Similarly, once an RPM spec file has been
    produced for an application, updating that spec file to support a
    newer version of that application is usually trivial. For these
    reasons, using RPM instead of a simpler, less end-user-friendly
    package format (such as gzipped tarballs) is a bit of a tradeoff for
    the packager; preparing an RPM of an application requires a little
    more initial time and work than preparing a gzipped tarball of that
    same application, but once created, the RPM package takes less time
    and effort to keep current than the gzipped tarball requires.
  </para>
  <sect1>
    <title>Packaging Aids</title>
    <para>
      However, several helper tools are also available for RPM
      packagers. These tools can be used at various stages in the
      process of producing a high-quality RPM package to simplify the
      tasks that an RPM packager must perform. These tools include
      syntax-highlighting modes for various text editors, making
      production and maintenance of spec files easier; macro packages
      for popular text editors, simplifying the generation and
      maintenance of spec files; tools that generate spec files,
      simplifying initial spec file creation; and debuggers that
      validate produced binary RPMs, helping ensure that the spec file
      used to create the packages is accurate and high quality.
    </para>
    <sect2>
      <title>Using VIM spec plugins to improve spec file editing</title>
      <para>
        Unix systems have traditionally shipped the legendary (or
        notorious, depending upon your point of view) vi editor
        (pronounced vee eye) as their default text editor. Vi was
        initially developed by Bill Joy in 1976 for BSD Unix. It
        eventually was incorporated in AT& T System V Unix as well
        and later was mandated by the POSIX 1003 standards (which define
        what an OS must have to be Unix-compatible), thereby conquering
        all facets of the Unix world.
      </para>
      <para>
        The original vi source code is no longer freely available, but
        several clones of the vi program have been created over the
        years. The most popular of these vi clones is probably Vi
        IMproved, or VIM (www.vim.org). VIM is the standard vi
        implementation (meaning that when you type vi at the command
        prompt, the program you really are running is vim) on many Linux
        distributions, including &RHL;. It is also freely
        available for most other Unixes and even for non-Unix systems
        such as Microsoft Windows.
      </para>
      <para>
        VIM is a fully backwards-compatible implementation of the
        original vi editor, although it also offers many additional
        features that vi did not support. One VIM feature that can be
        extremely useful when preparing spec files is colorized syntax
        highlighting. VIM has an extensible interface through which it
        can be told about the syntax used for files of various types.
        Once it understands a filetype's syntax, it can color the
        various syntactic structures of that file in different ways. For
        example, when editing a Bourne shell script using VIM, comments
        are typically blue, control statements (if, for, do, and so on)
        are yellow, variables are purple, and so forth. Many people find
        this feature very useful, since a single glance reveals the
        entire logical structure of the file. Furthermore, errors in the
        file (such as a missing done statement failing to close a do
        loop in a Bourne shell script) are often immediately obvious
        when using such a colorizing editor.
      </para>
      <para>
        Usually, VIM does not understand the structure of RPM spec
        files. When preparing a spec file, VIM displays all text in the
        same color. A spec.vim syntax file is available for VIM that
        makes VIM aware of the syntax used for RPM spec files. When this
        file is used, the various structural components (%define,
        preamble statements, %build, and so forth) are all colorized,
        making the logic of the spec file readily apparent.
      </para>
      <para>
        The spec.vim file that provides VIM with an understanding of
        spec-file syntax is bundled with newer versions of VIM, or it
        can be downloaded from the Internet. Most RPM-based Linux
        distributions, including &RHL;, ship this file with VIM
        as part of their distribution and even automatically configure
        VIM to load this syntax file any time an RPM spec file is being
        edited. When using VIM on a system that does not automatically
        load spec.vim whenever spec files are edited, you should
        download the spec.vim file (I tend to save such personal
        extensions in ~/etc/vim, but you can save it any place you
        prefer).
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        Download the spec.vim syntax file for VIM from
        http://pegasus.rutgers.edu/~elflord/vim/syntax/spec.vim.
      </para>
      <para>
        Once downloaded, configure VIM to load your new syntax file. You
        can do this by putting the following in your ~/.vimrc file
        (assuming you have saved the file as ~/etc/vim/spec.vim; adjust
        the path as necessary if you saved it elsewhere):
      </para>
      <para>
        augroup syntax
      </para>
      <para>
        au! BufNewFile,BufReadPost *.spec so ~/etc/vim/spec.vim
      </para>
      <para>
        au BufNewFile,BufReadPost *.spec so ~/etc/vim/spec.vim
      </para>
      <para>
        augroup END
      </para>
      <para>
        This statement will instruct VIM to load the syntax file
        whenever a file named with a .spec extension is edited. You can
        now even customize the colors which VIM uses, if you like, by
        editing ~/etc/vim/spec.vim!
      </para>
      <para>
        The VIM editor has hundreds of built-in commands for formatting
        text. If necessary, it can even be extended with new commands.
        Furthermore, these commands can be defined in FileType plugins,
        so that different commands are loaded depending upon the type of
        file being edited (just as different syntax matching can be used
        depending upon the type of file being edited). Gustavo Niemeyer
        has written a spec plugin, pi_spec, which defines various
        commands that can be used when working with RPM spec files.
        Currently, this plugin can be used to automate maintenance of
        the %changelog section of RPM spec files.
      </para>
      <para>
        By default, the spec plugin provides a macro, spec_chglog, which
        is mapped to the <LocalLeader>-c key. Normally, the
        LocalLeader key in VIM is mapped to "\", a backslash character.
        This means you press \c to load the spec_chglog macro. If
        desired, you can instead map spec_chglog to a different key by
        putting a statement like the following in your ~/.vimrc file.
      </para>
      <para>
        au FileType spec map <buffer> C <Plug>SpecChangelog
      </para>
      <para>
        In this case, that statement would map the macro to the "C" key,
        but you can map it to a different key by replacing the "C" in
        the statement with whichever key or key combination you prefer.
      </para>
      <para>
        The spec_chglog macro checks the %changelog in the spec file
        currently being edited and makes sure that the last entry in
        this %changelog was written today and was written by you. If it
        was, the macro adds a new item to the entry. If it was not
        written today, or was written today, but not by you, the macro
        adds an entirely new entry. Optionally, the macro also checks
        that the name, version, and release of the package are correct
        and will update the release if it is incorrect. In addition, the
        macro maps the percent key, %, making it usable in command mode
        in VIM to move quickly between sections within a spec file.
      </para>
      <para>
        To help spec_chglog, you can define a few variables in your
        ~/.vimrc file to customize its behavior. The variable
        spec_chglog_format defines what the macro uses for new
        %changelog entries. If you do not define this variable, the
        macro will ask you for an e-mail address and construct it for
        you the first time you use the macro. Alternatively, you can
        customize it yourself by adding an entry like the following to
        your ~/.vimrc file.
      </para>
      <para>
        let spec_chglog_format = "%a %b %d %Y Your Name
        <your at email.address>"
      </para>
      <para>
        The preceding format is what &RH;'s developers use for Red
        Hat Linux spec files and results in a %changelog entry that
        looks like the following, with the user name and e-mail address
        changed to protect the innocent:
      </para>
      <para>
        * Mon Apr 15 2002 Bob Marley <bob at marley.yow>
      </para>
      <para>
        The variables in the spec_chglog_format control the time format
        that is used. If you want different time formats in your
        %changelog entry, you can replace the variables (using %A
        instead of %a would cause the full weekday name, such as
        "Monday", to be printed) using the documentation in the
        strftime(3) man page as a guideline.
      </para>
      <para>
        By default, the macro will insert new entry items after existing
        items. For example, if I already have a %changelog entry for
        today that reads as follows:
      </para>
      <para>
        * Mon May 6 2002 Bob Marley <bob at marley.yow>
      </para>
      <para>
        - Updated to newest release
      </para>
      <para>
        Then, using the macro to add a new entry for an additional patch
        I added will, by default, result in an entry that reads:
      </para>
      <para>
        * Mon May 6 2002 Bob Marley <bob at marley.yow>
      </para>
      <para>
        - Updated to newest release
      </para>
      <para>
        - Added Solaris compile patch
      </para>
      <para>
        If I want, I can instead have new items inserted before existing
        items, so that my second entry instead looks like
      </para>
      <para>
        * Mon May 6 2002 Bob Marley <bob at marley.yow>
      </para>
      <para>
        - Added Solaris compile patch
      </para>
      <para>
        - Updated to newest release
      </para>
      <para>
        To have new items inserted before existing items, simply add the
        following line to your ~/.vimrc file:
      </para>
      <para>
        let spec_chglog_prepend = 1
      </para>
      <para>
        Optionally, the macro can track version and release numbers in
        the %changelog entries automatically. Adding the line
      </para>
      <para>
        let spec_chglog_release_info = 1
      </para>
      <para>
        results in the first item in every changelog entry automatically
        reflecting the version and release, so that my %changelog entry
        might instead look like the following:
      </para>
      <para>
        * Mon May 6 2002 Bob Marley <bob at marley.yow>
      </para>
      <para>
        + httpd-2.0.36-2
      </para>
      <para>
        - Updated to newest release
      </para>
      <para>
        - Added Solaris compile patch
      </para>
      <para>
        If this feature is enabled, the macro automatically checks the
        version and release information to make sure that they have
        increased. If they haven't, it will offer to update them for
        you. Add the following line to your ~/.vimrc file to disable
        this feature, if necessary.
      </para>
      <para>
        let spec_chglog_never_increase_release = 1
      </para>
      <para>
        This spec plugin ships with newer versions of VIM. Both it and
        the VIM spec syntax highlighting extensions can be very useful
        for speeding spec file editing and debugging, and are well worth
        trying out if you are a VIM user.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        You can find out more about vim at www.vim.org.
      </para>
    </sect2>
    <sect2>
      <title>Adding functions with emacs rpm-spec-mode</title>
      <para>
        Of course, not everyone in the world uses VIM. Another commonly
        used editor is the emacs editor originally developed by Richard
        M. Stallman. Unlike vi, emacs is not considered an essential
        Unix component and is not always found installed on a Unix
        system, although it is bundled with just about every Linux
        distribution.
      </para>
      <para>
        Over the years, two major emacs variants have emerged. GNU Emacs
        is produced by the Free Software Foundation and can be
        downloaded from www.gnu.org/software/emacs/emacs.html. XEmacs is
        based on GNU Emacs and is available from www.xemacs.org.
        Historically, the two differed in their user interfaces (XEmacs,
        as the name suggests, had an X Window interface, though GNU
        Emacs has one as well these days) and in some technical details
        of how they operated. Both are freely available under the terms
        of the GNU GPL, so you can download and try either or both if
        they are not already on your system.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        See <xref linkend="ch-licensing"/>  for more on the GNU GPL, or General Public
        License.
      </para>
      <para>
        &RHL; includes RPMs of both GNU Emacs and XEmacs as part
        of the distribution, and most other Linux distributions will
        include one or both as well.
      </para>
      <para>
        Like VIM, both GNU Emacs and XEmacs support syntax highlighting.
        They are also both extensible, having the ability to load mode
        files that add new commands and functions. Stig Bjørlykke has
        written a mode, rpm-spec-mode.el, which works with both GNU
        Emacs and with XEmacs to add many functions, making it easier to
        use when editing RPM spec files. &RHL; includes and
        enables this mode in both GNU Emacs and XEmacs, as do many other
        Linux distributions.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        You can download this emacs mode from
        http://tihlde.org/~stigb/rpm-spec-mode.el.
      </para>
      <para>
        After downloading, you will need to put the following lines in
        your ~/.emacs init files (for GNU Emacs) or ~/.xemacs init files
        (for XEmacs) to instruct emacs to load rpm-spec-mode whenever a
        file with a .spec extension is being edited:
      </para>
      <para>
        (autoload 'rpm-spec-mode "rpm-spec-mode.el" "RPM spec mode." t)
      </para>
      <para>
        (setq auto-mode-alist (append '(("\\.spec" . rpm-spec-mode))
        auto-mode-alist))
      </para>
      <para/>
      <para>
        Once installed, rpm-spec-mode will provide emacs with additional
        support for editing RPM spec files. Figure 13-1 shows this mode
        in GNU Emacs.
      </para>
      <para>
        54965-0 Fg1301.tiff here; needs to be cropped to just the
        central window
      </para>
      <para>
        Figure 13-1: Gnu Emacs using rpm-spec-mode
      </para>
      <para>
        Figure 13-2 shows this mode in XEmacs.
      </para>
      <para>
        54965-0 Fg1302.tiff here; needs to be cropped to just the
        central window
      </para>
      <para>
        Figure 13-2: XEmacs using rpm-spec-mode
      </para>
      <para>
        With this mode, emacs can do syntax highlighting of spec files,
        just like VIM. The mode file rpm-spec-mode.el contains the emacs
        instructions that specify what should be highlighted and what
        colors should be used for highlighting.
      </para>
      <para>
        Tip
      </para>
      <para>
        If you do not see syntax highlighting when you edit a spec file,
        your emacs session may or may not be currently configured to do
        syntax highlighting. First, make sure that the status bar at the
        bottom of your emacs window says (RPM-SPEC), indicating that
        rpm-spec-mode is being used. If it doesn't, double-check the
        rpm-spec-mode installation instructions. If the status bar does
        indicate that you are using rpm-spec-mode, also double-check
        that syntax highlighting (which, in emacs, is a global
        configuration option) has been enabled. In both GNU Emacs and
        XEmacs, the Options menu has a Syntax Highlighting option that
        must be enabled before emacs will colorize spec file syntactic
        structures.
      </para>
      <para>
        In addition to providing syntax colorization, rpm-spec-mode adds
        a variety of new functions to emacs that can be used to speed
        the process of creating or editing RPM spec files. These new
        functions appear on the RPM-Spec menu that is added to emacs by
        rpm-spec-mode. Many of the functions are similar to the
        functions added to VIM by the spec_chglog macro. Navigation
        functions to move quickly through a spec file are provided, so
        that Ctrl+C, Ctrl+N (press Ctrl+C followed by Ctrl+N) will move
        the cursor to the next major section of the spec file, while
        Ctrl+C, Ctrl+P will move the cursor to the prior major section
        of the spec file. Similarly, macros are also defined to
        increment the release tag (Ctrl+C, R) and the very handy option
        to add new %changelog entries (Ctrl+C, E). Like the VIM macros
        for adding %changelog entries, the rpm-spec-mode command checks
        to see if an entry already exists for today. If not, it adds a
        new entry, but if so, it just adds a new item to the existing
        entry. For %changelog entries to have the correct e-mail
        address, the emacs variable user-mail-address must be set
        correctly. If it is not set on your system, you can add the
        following line to your emacs initialization files:
      </para>
      <para>
        (setq user-mail-address "your at email.address")
      </para>
      <para>
        In addition to these basic functions, rpm-spec-mode offers more
        advanced spec file creation support. Opening a new buffer in
        emacs for a spec file that does not already exist automatically
        generates a skeleton spec file.
      </para>
      <para>
        To further speed things up, emacs offers a number of macros for
        the main tasks in writing an RPM spec file. Table 13-1 lists
        these macros.
      </para>
      <para>
        Table 13-1Macro commands for The RPM SPEC MODE IN EMacs
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  Command
                </para>
              </entry>
              <entry>
                <para>
                  Function
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Ctrl+C Tab
                </para>
              </entry>
              <entry>
                <para>
                  Adds a new tag to the spec file
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Ctrl+C Ctrl+F F
                </para>
              </entry>
              <entry>
                <para>
                  Adds a new file to the %files section
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Ctrl+C Ctrl+F C
                </para>
              </entry>
              <entry>
                <para>
                  Adds a new configuration file to the %files section
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Ctrl+C Ctrl+F D
                </para>
              </entry>
              <entry>
                <para>
                  Adds a new documentation file to the %files section
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Ctrl+C Ctrl+F G
                </para>
              </entry>
              <entry>
                <para>
                  Adds a new ghost file to the %files section
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Ctrl+C Ctrl+D D
                </para>
              </entry>
              <entry>
                <para>
                  Adds a new directory to the %files section
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Ctrl+C Ctrl+D O
                </para>
              </entry>
              <entry>
                <para>
                  Adds a new documentation directory to the %files
                  section
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Ctrl+C Ctrl+C U
                </para>
              </entry>
              <entry>
                <para>
                  Changes the umask in %defattr entries in %files
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Ctrl+C Ctrl+C O
                </para>
              </entry>
              <entry>
                <para>
                  Changes the owner in %defattr entries in %files
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Ctrl+C Ctrl+C G
                </para>
              </entry>
              <entry>
                <para>
                  Changes the group in %defattr entries in %files
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
      <para>
        Furthermore, rpm-spec-mode even adds macros to emacs that can be
        used to build RPMs from spec files without even having to exit
        emacs! Since the process of constructing spec files is often
        iterative (make new spec, build RPM from spec, find mistake,
        edit spec, build RPM from spec, find mistake, and so on), this
        capability of emacs to be used as an IDE for RPM package
        generation is extremely useful. Basic macros exist to do
        complete builds (Ctrl+C B to build a binary package, Ctrl+C S to
        build a source package, and Ctrl+C A to build both). Macros can
        also be used to execute various intermediate steps, such as the
        %prep stage (Ctrl+C P), the %build stage (Ctrl+C C), or the
        %install stage (Ctrl+C I). Various options of the build process
        can also be controlled, such as GPG-signing of generated
        packages.
      </para>
      <para>
        If you are a user of GNU Emacs or XEmacs, you should definitely
        take the time to learn to use rpm-spec-mode. Being able to build
        packages from within the editor where you are editing the spec
        file that builds those packages is a great productivity gain for
        many people.
      </para>
    </sect2>
    <sect2>
      <title>Validating and debugging spec files with rpmlint</title>
      <para>
        Both VIM and emacs extensions help with the process of initially
        creating spec files and with the maintenance of existing RPM
        spec files. After a spec file has been created, and RPMs have
        been created using that spec, the binary RPMs generated from the
        spec can be validated using the rpmlint command. The name
        rpmlint comes from lint, the traditional Unix utility that can
        "sanity-check" C source code, looking for certain classes of
        common C coding mistakes. The idea behind rpmlint is similar; it
        processes binary RPMs, checking for certain common mistakes made
        by RPM packagers.
      </para>
      <para>
        The rpmlint command currently ships with a wide variety of
        checks and is written using a modular interface so that
        additional checks can easily be added if needed. Currently,
        rpmlint can check that all binary files in the package are
        correct (making sure that a .noarch.rpm package does not contain
        binary files, that no binaries are being installed in /etc, that
        the binary file types in the package are appropriate for the
        package architecture, that shared libraries are configured
        correctly, and that all executables are stripped). It can also
        check the validity of files marked as configuration files in the
        RPM (ensuring that configuration files are only being installed
        in /etc, not in /usr) and that the package file complies with
        the distribution's policies for packages (checking things such
        as the compression of man pages and Info pages and the
        correctness of vendor and distribution fields in the package
        header).
      </para>
      <para>
        In addition, rpmlint performs a variety of checks to ensure that
        the package complies with the Filesystem Hierarchy Standard
        (verifying that files are installed in their standard locations
        on the system), the Linux Standards Base (verifying that
        package-file naming is LSB-compliant) and that files have
        correct ownerships and permissions. Init scripts are
        double-checked (for packages that have init scripts) to ensure
        that the basic structure of the init script is correct and that
        appropriate %post and %preun configuration directives are being
        run to configure the init script on the system. %post, %pre, and
        %preun scripts are also double-checked (ensuring that only valid
        interpreters are specified for scripts and that scripts are
        written in valid syntax). The validity of the package itself is
        also checked in various ways (ensuring that the package is
        GPG-signed, that the package's source RPM is correctly prepared,
        that the package spec file uses correct syntax, and that all
        tags used in the package header are valid).
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        To find out more about the Filesystem Hierarchy Standard, see
        www.pathname.com/fhs/. To find out more about the Linux
        Standards Base, see www.linuxbase.org.
      </para>
      <para>
        Download rpmlint from www.lepied.com/rpmlint. It is written
        entirely in Python, so a Python interpreter is necessary to run
        it.
      </para>
      <para>
        Once installed, rpmlint can be configured on a system-wide
        basis, using the /etc/rpmlint/config file, or on a per-user
        basis, using the $HOME/.rpmlintrc file. This file can specify
        checks to perform, check output that should be ignored, and
        configuration options. Configuration options can be specified,
        listing what entries are valid for various fields in the RPM
        header, such as the Vendor and Packager fields. By default, Red
        Hat Linux ships with this configuration file set to validate
        packages to make sure they are suitable for &RHL;; if
        packaging for a different distribution, this file might need to
        be modified.
      </para>
      <para>
        Once rpmlint has been installed and configured, it can be run
        against RPMs. For example, rpmlint helps with creating packages,
        such as tin (a popular Usenet client) for &RHL;, since
        it is not included with the distribution. After preparing a tin
        spec file, then building RPMs from that file, you can typically
        double-check them using rpmlint.
      </para>
      <para>
        For example, when running rpmlint on a source RPM, you’ll see
        output like the following:
      </para>
      <para>
        $ rpmlint tin-1.5.12-1.src.rpm
      </para>
      <para>
        E: tin no-packager-tag
      </para>
      <para>
        W: tin invalid-license distributable
      </para>
      <para>
        W: tin no-url-tag
      </para>
      <para>
        W: tin strange-permission tin-1.5.12.tar.bz2 0664
      </para>
      <para>
        W: tin obsolete-tag Copyright
      </para>
      <para>
        $
      </para>
      <para>
        For the most part, this package looks fine according to the
        rpmlint output. The permissions on the tin source code can be
        changed (0644 is the "preferred" permissions), and you might
        want to change my spec file to use the License tag instead of
        the now-obsolete Copyright tag. Similarly, you might want to add
        a URL tag to the package to point to the URL for the software.
      </para>
      <para>
        When running rpmlint on a binary RPM, you’ll see output like
        the following:
      </para>
      <para>
        $ rpmlint tin-1.5.12-1.i386.rpm
      </para>
      <para>
        W: tin invalid-vendor None
      </para>
      <para>
        W: tin invalid-distribution None
      </para>
      <para>
        E: tin no-packager-tag
      </para>
      <para>
        W: tin invalid-license distributable
      </para>
      <para>
        W: tin no-url-tag
      </para>
      <para>
        $
      </para>
      <para>
        With this output, the binary package looks fine. You should set
        a I don’t bother setting a vendor, distribution, and packager
        but you can ignore those warnings. Similarly, rpmlint warns
        because it does not recognize the license type used,
        "distributable". You can fix this, you can ignore this, or you
        can modify /etc/rpmlint/config so that rpmlint recognizes
        "distributable" as a valid license.
      </para>
      <para>
        The sorts of validity checks that rpmlint can do make it
        valuable for ensuring the quality and consistency of RPMs. Most
        RPM-based Linux distributions validate their entire distribution
        using rpmlint. Using it for packages you prepare is a good idea
        as well.
      </para>
    </sect2>
    <sect2>
      <title>Generating the %files section with RUST</title>
      <para>
        For the most part, maintaining RPM spec files is relatively
        straightforward. Creating spec files from scratch, however, can
        be a little bit more challenging. Tools like rpm-spec-mode for
        emacs can help with the process, generating skeleton spec file
        templates that can be filled in, but these sorts of tools do not
        address the step that most new RPM packagers seem to find most
        difficult: generating the %files section. Creating a complete,
        accurate list of all needed files supplied by an application can
        be difficult, particularly when it is an application with which
        you are unfamiliar. Most software supports installation to a
        temporary location; if the software you are packaging allows
        this, generation of %files is (almost) as simple as using
        BuildRoot to install the application to a temporary directory,
        then running an ls -lR command in that subdirectory to see all
        the installed files and directories. Even then, though, the
        output from ls -lR must be cleaned up and converted into %files
        format for adding to the spec file. All of this takes time.
      </para>
      <para>
        A couple of tools exist to reduce the amount of work needed for
        this stage of the process, automating the generation of the
        %files section of spec files. The most sophisticated of these
        toolsets is RUST.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        Download RUST from www.rusthq.com.
      </para>
      <para>
        RUST consists of two tools: crust and rust. The crust command
        provides a command-line tool that can create a chroot() jail, in
        which software can be built and installed, and then
        automatically generate a spec file that documents the files that
        were installed. This not only eliminates the need to generate a
        %files section for a spec file manually but also removes the
        need to modify software to support installation to a temporary
        location using BuildRoot, a sometimes difficult task.
      </para>
      <para>
        The rust command provides a graphical front end to the crust
        command, as shown in Figure 13-3.
      </para>
      <para>
        54965-0 Fg1303.tiff here
      </para>
      <para>
        Figure 13-3: rust, a drag-and-drop spec file generator
      </para>
      <para>
        The rust command provides a graphical interface that can be used
        to control crust and supports drag-and-drop creation of spec
        files. In the rust interface, two file trees are displayed. The
        left-hand tree displays the local file system, while the
        right-hand tree displays the file tree inside the crust chroot()
        jail. Files that should be packaged together can just be dragged
        from their current locations on the system (displayed in the
        left-hand tree) to their final destinations in the right-hand
        tree. You can then click the makeRPM choice to generate an RPM
        containing those files. Although not terribly useful for
        packages being generated from source code, this feature can
        greatly simplify creation of RPMs of applications that are only
        supplied in binary format (such as the Linux Adobe Acrobat
        reader).
      </para>
      <para>
        RUST's rust application can be useful in some circumstances
        (providing new developers a graphical tool that can be used to
        generate binary RPMs), and crust is more generally useful for
        packaging difficult-to-package software that needs to be built
        and installed in a chroot() jail. Unfortunately, development of
        RUST appears to have stopped, so extension of RUST to become a
        more generally useful IDE for RPM generation is not likely to
        happen. However, the project is licensed under the GNU GPL
        (<xref linkend="ch-licensing"/> ), so it might be resumed by another developer or
        team of developers.
      </para>
    </sect2>
    <sect2>
      <title>setup.sh and MakeRPM.pl</title>
      <para>
        Other tools that have been developed to simplify the process of
        creating an RPM spec file take an entirely different approach.
        Tools such as setup.sh, available from
        www.mmedia.is/~bre/programs/setup.sh, are intended to function
        as wrappers around the existing build commands (./configure and
        make) for software. These types of tools take the approach of
        using the standard build tools for software (since those tools
        must always be used to build the software, whether using RPM or
        compiling the software from a source tarball) and capturing the
        output to generate an RPM spec file automatically.
      </para>
      <para>
        The MakeRPM.pl Perl script, available from
        www.perl.com/CPAN/modules/by-authors/id/JWIED, is another
        example of such an approach. MakeRPM.pl is a more specialized
        tool than setup.sh, as MakeRPM.pl is intended only for producing
        RPMs from Perl modules packaged in CPAN (www.cpan.org). It is
        implemented as a wrapper around the standard commands (perl
        Makefile.PL ; make ; make test ; make install) used to install
        Perl CPAN software.
      </para>
      <para>
        MakeRPM.pl actually works quite well for its intended
        purpose at mdproducing packages of CPAN modules. The setup.sh
        script is currently viewable mainly as a proof of concept,
        rather than being a generally universal automatic spec file
        generator. In the future, when spec files are likely to be
        representable using a formal closed-syntax grammar, it is
        possible that more generalized spec file generation tools will
        be developed. Until that time, however, some of the previously
        mentioned tools, particularly the VIM and emacs extensions, can
        provide assistance when manually generating spec files.
      </para>
      <para>
        Cross-reference
      </para>
      <para>
        For more discussion of the future of RPM, you can turn to
        <xref linkend="ch-rpm-evolution"/> .
      </para>
    </sect2>
    <sect2>
      <title>Manipulating Package Files with rpm2cpio</title>
      <para>
        Normally, RPM packagers are concerned with taking source code or
        binary files, and producing an RPM that contains those files and
        can be used to install them on end-users' systems. Sometimes,
        packagers and end users find themselves in the opposite
        position, that of having a source or binary RPM package file and
        needing to extract its contents. An RPM can always be installed
        to access its contents (either source code, patches, and a spec
        file which get put under %_topdir for a source RPM, or software
        which gets put in system directories for a binary RPM), but that
        is often overkill. I frequently want to extract a single patch
        file, or the spec file, from a source RPM, but I don't really
        need to install the entire source RPM. Similarly, people often
        want to extract the contents of RPMs on systems that do not come
        with RPM, such as Solaris.
      </para>
      <para>
        Fortunately, tools are available that can process RPM package
        files into a format from which their content can be extracted.
        Structurally speaking, RPM package files are compressed cpio
        archives that have additional binary data added to the beginning
        containing various meta-data about the package (specifying its
        architecture and OS, for example), a GPG signature if the
        package is signed, and so forth. If this binary data is removed
        from the beginning of the RPM package file, the remainder is a
        System V Release 4-style cpio file that can be manipulated using
        any reasonably complete cpio command. Several different tools,
        each sporting the name rpm2cpio, are available which can do this
        binary data removal, converting an RPM package file into a
        standard cpio archive.
      </para>
      <para>
        RPM ships with an rpm2cpio utility that can be used to convert
        RPM package files to cpio files. (<xref linkend="ch-rpm-overview"/>  introduces the
        rpm2cpio utility.) For example, if you have a source RPM package
        file and want to extract its files without having to install it,
        you can process it through rpm2cpio. The rpm2cpio command takes
        as input an RPM package file, and produces a cpio file on
        standard output. For example, to redirect the output to a file,
        use a command like the following:
      </para>
      <para>
        $ rpm2cpio fluxbox-0.1.8-2.src.rpm > fluxbox-0.1.8-2.cpio
      </para>
      <para>
        $
      </para>
      <para>
        This command creates a cpio archive from the package. You can
        later use cpio commands on the output file. You can also pipe
        the output of rpm2cpio through the cpio command:
      </para>
      <para>
        $ rpm2cpio fluxbox-0.1.8-2.src.rpm | cpio -i -d
      </para>
      <para>
        656 blocks
      </para>
      <para>
        $
      </para>
      <para>
        This command extracts the contents of the package.
      </para>
      <para>
        This rpm2cpio command is bundled with RPM and is installed on
        most RPM-based Linux distributions, including &RHL;.
        However, it is less useful on systems that do not come with RPM,
        such as Solaris. This "standard" implementation of rpm2cpio is
        written in C, and so must be compiled before it can be used.
        Since most commercial Unix systems do not come with a C compiler
        by default (unlike Linux and other free Unixes, such as the BSD
        operating systems), compiling this rpm2cpio code can be a major
        undertaking.
      </para>
      <para>
        Fortunately, rpm2cpio implementations are also available in a
        couple of other languages, in more easy-to-install formats for
        other operating sytsems, including as a Bourne shell script or a
        Perl script. The Bourne shell syntax should work on any
        reasonably modern Unix system (and even a few non-Unix systems;
        it also works on Microsoft Windows under cygwin, for example).
        The script in Listing 13-1should be saved to a file named
        rpm2cpio.sh, marked executable, and copied to a directory in
        your path.
      </para>
      <para>
        Listing 13-1: rpm2cpio as a Bourne Shell script
      </para>
      <para>
        #!/bin/sh
      </para>
      <para/>
      <para>
        pkg=$1
      </para>
      <para>
        if [ "$pkg" = "" -o ! -e "$pkg" ]; then
      </para>
      <para>
        echo "no package supplied" 1>&2
      </para>
      <para>
        exit 1
      </para>
      <para>
        fi
      </para>
      <para/>
      <para>
        leadsize=96
      </para>
      <para>
        o=`expr $leadsize + 8`
      </para>
      <para>
        set `od -j $o -N 8 -t u1 $pkg`
      </para>
      <para>
        il=`expr 256 \* \( 256 \* \( 256 \* $2 + $3 \) + $4 \) + $5`
      </para>
      <para>
        dl=`expr 256 \* \( 256 \* \( 256 \* $6 + $7 \) + $8 \) + $9`
      </para>
      <para>
        # echo "sig il: $il dl: $dl"
      </para>
      <para/>
      <para>
        sigsize=`expr 8 + 16 \* $il + $dl`
      </para>
      <para>
        o=`expr $o + $sigsize + \( 8 - \( $sigsize \% 8 \) \) \% 8 + 8`
      </para>
      <para>
        set `od -j $o -N 8 -t u1 $pkg`
      </para>
      <para>
        il=`expr 256 \* \( 256 \* \( 256 \* $2 + $3 \) + $4 \) + $5`
      </para>
      <para>
        dl=`expr 256 \* \( 256 \* \( 256 \* $6 + $7 \) + $8 \) + $9`
      </para>
      <para>
        # echo "hdr il: $il dl: $dl"
      </para>
      <para/>
      <para>
        hdrsize=`expr 8 + 16 \* $il + $dl`
      </para>
      <para>
        o=`expr $o + $hdrsize`
      </para>
      <para/>
      <para>
        dd if=$pkg ibs=$o skip=1 2>/dev/null | gunzip
      </para>
      <para>
        After you have marked this file as executable and placed it in
        your command path, you can use the script just like the C
        language implementation of rpm2cpio. This script also takes an
        RPM package file as input and produces a cpio file on standard
        output, and so should be used in conjunction with redirection or
        a pipe:
      </para>
      <para>
        $ rpm2cpio.sh fluxbox-0.1.8-2.src.rpm | cpio -i -d
      </para>
      <para>
        656 blocks
      </para>
      <para>
        $
      </para>
      <para>
        In this case, I piped the output to cpio, directly extracting
        it. I could have redirected the output of rpm2cpio.sh to a file
        instead.
      </para>
      <para>
        In addition to the Bourne shell implementation of rpm2cpio, a
        version has been written in Perl by Roger Espel Llima. The Perl
        rpm2cpio implementation should work on any system that has a
        reasonably modern Perl interpreter. To use this version of
        rpm2cpio, the script in Listing 13-2 should be saved to a file
        named rpm2cpio.pl, marked executable, and copied to a directory
        in your path.
      </para>
      <para>
        Listing 13-2:The Perl version of rpm2cpio, rpm2cpio.pl
      </para>
      <para>
        #!/usr/bin/perl
      </para>
      <para/>
      <para>
        # Copyright (C) 1997,1998,1999, Roger Espel Llima
      </para>
      <para>
        #
      </para>
      <para>
        # Permission is hereby granted, free of charge, to any person
        obtaining a copy
      </para>
      <para>
        # of this software and any associated documentation files (the
        "Software"), to
      </para>
      <para>
        # deal in the Software without restriction, including without
        limitation the
      </para>
      <para>
        # rights to use, copy, modify, merge, publish, distribute,
        sublicense,
      </para>
      <para>
        # and/or sell copies of the Software, and to permit persons to
        whom the
      </para>
      <para>
        # Software is furnished to do so, subject to the following
        conditions:
      </para>
      <para>
        #
      </para>
      <para>
        # The above copyright notice and this permission notice shall be
        included in
      </para>
      <para>
        # all copies or substantial portions of the Software.
      </para>
      <para>
        #
      </para>
      <para>
        # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
        KIND, EXPRESS OR
      </para>
      <para>
        # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
        MERCHANTABILITY,
      </para>
      <para>
        # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
        EVENT SHALL THE
      </para>
      <para>
        # SOFTWARE'S COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM,
        DAMAGES OR OTHER
      </para>
      <para>
        # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
        OTHERWISE, ARISING FROM,
      </para>
      <para>
        # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
        DEALINGS IN
      </para>
      <para>
        # THE SOFTWARE
      </para>
      <para/>
      <para>
        # (whew, that's done!)
      </para>
      <para/>
      <para>
        # why does the world need another rpm2cpio? because the existing
        one
      </para>
      <para>
        # won't build unless you have half a ton of things that aren't
        really
      </para>
      <para>
        # required for it, since it uses the same library used to
        extract RPM's.
      </para>
      <para>
        # in particular, it won't build on the HPsUX box i'm on.
      </para>
      <para/>
      <para>
        # sw 2002-Mar-6 Don't slurp the whole file
      </para>
      <para/>
      <para>
        # add a path if desired
      </para>
      <para>
        $gzip = "gzip";
      </para>
      <para/>
      <para>
        sub printhelp {
      </para>
      <para>
        print <<HERE;
      </para>
      <para>
        rpm2cpio, perl version by orabidoo <odar\@pobox.com> +sw
      </para>
      <para>
        dumps the contents to stdout as a cpio archive
      </para>
      <para/>
      <para>
        use: rpm2cpio [file.rpm] > file.cpio
      </para>
      <para/>
      <para>
        Here's how to use cpio:
      </para>
      <para>
        list of contents: cpio -t -i < /file/name
      </para>
      <para>
        extract files: cpio -d -i < /file/name
      </para>
      <para>
        HERE
      </para>
      <para/>
      <para>
        exit 0;
      </para>
      <para>
        }
      </para>
      <para/>
      <para>
        if ($#ARGV == -1) {
      </para>
      <para>
        printhelp if -t STDIN;
      </para>
      <para>
        $f = "STDIN";
      </para>
      <para>
        } elsif ($#ARGV == 0) {
      </para>
      <para>
        open(F, "< $ARGV[0]") or die "Can't read file $ARGV[0]\n";
      </para>
      <para>
        $f = 'F';
      </para>
      <para>
        } else {
      </para>
      <para>
        printhelp;
      </para>
      <para>
        }
      </para>
      <para/>
      <para>
        printhelp if -t STDOUT;
      </para>
      <para/>
      <para>
        # gobble the file up
      </para>
      <para>
        ##undef $/;
      </para>
      <para>
        ##$|=1;
      </para>
      <para>
        ##$rpm = <$f>;
      </para>
      <para>
        ##close ($f);
      </para>
      <para/>
      <para>
        read $f,$rpm,96;
      </para>
      <para/>
      <para>
        ($magic, $major, $minor, $crap) = unpack("NCC C90", $rpm);
      </para>
      <para/>
      <para>
        die "Not an RPM\n" if $magic != 0xedabeedb;
      </para>
      <para>
        die "Not a version 3 or 4 RPM\n" if $major != 3 &&
        $major != 4;
      </para>
      <para/>
      <para>
        ##$rpm = substr($rpm, 96);
      </para>
      <para/>
      <para>
        while (!eof($f)) {
      </para>
      <para>
        $pos = tell($f);
      </para>
      <para>
        read $f,$rpm,16;
      </para>
      <para>
        $smagic = unpack("n", $rpm);
      </para>
      <para>
        last if $smagic eq 0x1f8b;
      </para>
      <para>
        # Turns out that every header except the start of the gzip one
        is
      </para>
      <para>
        # padded to an 8 bytes boundary.
      </para>
      <para>
        if ($pos & 0x7) {
      </para>
      <para>
        $pos += 7;
      </para>
      <para>
        $pos &= ~0x7;# Round to 8 byte boundary
      </para>
      <para>
        seek $f, $pos, 0;
      </para>
      <para>
        read $f,$rpm,16;
      </para>
      <para>
        }
      </para>
      <para>
        ($magic, $crap, $sections, $bytes) = unpack("N4", $rpm);
      </para>
      <para>
        die "Error: header not recognized\n" if $magic != 0x8eade801;
      </para>
      <para>
        $pos += 16;# for header
      </para>
      <para>
        $pos += 16 * $sections;
      </para>
      <para>
        $pos += $bytes;
      </para>
      <para>
        seek $f, $pos, 0;
      </para>
      <para>
        }
      </para>
      <para/>
      <para>
        if (eof($f)) {
      </para>
      <para>
        die "bogus RPM\n";
      </para>
      <para>
        }
      </para>
      <para/>
      <para>
        open(ZCAT, "|gzip -cd") || die "can't pipe to gzip\n";
      </para>
      <para>
        print STDERR "CPIO archive found!\n";
      </para>
      <para/>
      <para>
        print ZCAT $rpm;
      </para>
      <para/>
      <para>
        while (read($f, ($_=''), 16384) > 0) {
      </para>
      <para>
        print ZCAT;
      </para>
      <para>
        }
      </para>
      <para/>
      <para>
        close ZCAT;
      </para>
      <para>
        After set up, rpm2cpio.pl works much like the C and Bourne shell
        versions, so the following command can be used to generate a
        cpio archive from an RPM package file:
      </para>
      <para>
        $ rpm2cpio.pl fluxbox-0.1.8-2.src.rpm | cpio -i -d
      </para>
      <para>
        CPIO archive found!
      </para>
      <para>
        656 blocks
      </para>
      <para>
        $
      </para>
      <para/>
      <para>
        Depending upon the system you are on, one or more of these three
        rpm2cpio programs should work. All three are useful any time you
        want to extract a file or files from an RPM package file but do
        not actually need to install the RPM.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      Creating RPM spec files and maintaining those files can be a
      difficult chore. A number of tools and add-ons for text editors
      have sprung up to help make this less of a chore.
    </para>
    <para>
      Users of the two most common Linux text editors, vi and emacs, can
      use add-ons that understand the RPM spec file syntax. These
      add-ons help reduce errors and, though the use of macros, can
      speed development of spec files by automating some of the tasks.
    </para>
    <para>
      The RUST tool provides a graphical interface for creating spec
      files that can simplify a lot of the work normally required.
    </para>
    <para>
      Once you’ve created an RPM package, you can use the rpmlint
      command to flag missing, incomplete, or incorrect elements in your
      RPMs.
    </para>
    <para>
      Another tool, called rpm2cpio in its various incarnations, allows
      you to extract files from an RPM package by taking advantage of
      the fact that RPM files use the cpio format internally. The
      rpm2cpio tools can output RPM data into the cpio format directly;
      you can then pipe the output to the cpio command to extract.
    </para>
    <para>
      After all this help in making RPMs and spec files, the next
      chapter covers a set of best-practice guidelines to help avoid
      problems when making your RPMs.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-intro-packaging.xml ---
<!-- $Id: -->

<preface id="ch-intro-packaging">
  <title>Introducing Package Management</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Issues in software management
      </para>
    </listitem>
    <listitem>
      <para>
        Examining Linux management tools
      </para>
    </listitem>
    <listitem>
      <para>
        Introducing the package concept
      </para>
    </listitem>
  </itemizedlist>
  <para>
    In 1991, a young Finnish graduate student started a new personal
    hobby. He had acquired an Intel 386 computer and had spent a few
    weeks exploring it and playing early PC computer games. Eventually,
    however, he grew bored with the limitations of the MS-DOS
    environment that had come with his toy and decided that he wanted an
    operating system for it that he could use more productively. After
    exploring Minix, a feature-limited teaching operating system, he
    decided he needed a full-featured OS.
  </para>
  <para>
    At that time, no full-featured PC operating systems were freely
    available, so he decided to write his own operating system. Today,
    that small hobby OS that Linus Torvalds started almost as a whim has
    become Linux, a significant new variant of Unix that runs millions
    of the world's network servers and, increasingly, desktop computers
    and embedded processors.
  </para>
  <para>
    Linux has grown up, successfully making the transition from a
    one-man personal project to a functional, full-featured operating
    system used by many of the world's major corporations and deployed
    on millions of corporate and personal systems. Along the way, Linux
    has had to address many of the same issues any new operating system
    must face. One of these concerns is how software for Linux, and how
    the Linux operating system itself, should be installed. How can
    administrators safely remove software packages without affecting
    other installed packages? And how can you safely upgrade packages?
    Answering these questions is what this book is all about.
  </para>
  <sect1>
    <title>Installing, Removing, and Upgrading Applications</title>
    <para>
      Applications for most operating systems consist of multiple files
      that must be copied to specific locations on the computer's file
      system before each application can be run. This is true for common
      PC operating systems such as MS-DOS or Microsoft Windows, as well
      as for Unix and Linux.
    </para>
    <para>
      In the case of a Unix-like operating system such as Linux, other
      issues must also be considered. Unix and Linux are multiple-user
      systems, so they must track ownership of files. Furthermore, Unix
      and Linux use a system of file permissions. Administrators can
      grant some users access to files and can control how users may
      access those files, for example, allowing some users the
      permission to read only certain files. Administrators can deny
      other users access to the same files. So, installation of an
      application on Linux requires consideration of all these details.
      After files are copied into their appropriate locations, they must
      be granted correct permissions and correct ownerships.
    </para>
    <para>
      Similarly, administrators occasionally need to remove installed
      software from the computer. Maybe the program is no longer needed;
      maybe it does not work correctly for the needed task, or maybe the
      space it is using is needed for more important programs. In
      addition, installed software sometimes needs to be upgraded.
      Perhaps a new version of the software has come out and the
      currently installed version needs to be replaced with the
      presumably improved version. In most respects, software upgrades
      are the same as the removal of one application (the old version),
      followed by installation of another application (the new version).
      Upgrades do, however, have additional issues. Many applications
      must be configured before they can be used. Ideally, the upgrade
      for an installed application takes the current configuration into
      account, preserving old configuration information and applying it
      to the recently installed version.
    </para>
    <para>
      All these considerations make installation of a new application
      onto Unix or Linux a labor-intensive process. To further
      complicate matters, Unix applications have primarily been
      distributed as source code. To install a new application, such as
      the Apache Web server, you download the source code for that
      application—in this case, from the Apache Project's Web page
      (<ulink url="http://httpd.apache.org"/>). Typically, the source
      code is provided in some sort of archive (such as the Zip archival
      and compression format often used in the Windows world or the tar
      archive format typically used in the Unix world) that you must
      then unpack. After unpacking this source code, you have to
      configure it to support the options and systems you want,
      compiling it to produce an executable program that can run on your
      particular operating system (CPU combination).
    </para>
    <para>
      After compiling the source code, you still have to install the
      application by putting all of its components (executable programs,
      documentation, configuration files, and so forth) into the correct
      locations on your hard drive and setting correct permissions on
      all those files. You might also need to perform other steps to
      prepare the system for the software. In the case of Apache, for
      example, some space needs to be set aside for storage of
      Web-access logs, and a special user account needs to be created so
      that the Apache Web server can operate more securely. Finally, you
      are ready to try running the application you have spent so much
      time installing.
    </para>
    <para>
      To help with all these tasks, precompiled software is becoming
      increasingly prevalent in the Unix and Linux communities, so you
      might be able to find executable (precompiled binary) copies of
      the application you wish to install that are appropriate for your
      particular machine's CPU. In that case, download an archive of the
      compiled application and unpack it. Then skip the compilation
      step, since that has already been done for you. The other steps
      required to install the package (copying files into correct
      locations, setting file permissions, and doing any needed system
      or application configuration) are exactly the same as the steps
      performed to install that application from source code. Once those
      steps are finished, you are ready to test your freshly installed
      application.
    </para>
    <para>
      When you run your newly installed application, you might be
      thrilled, perhaps discovering that it is something you want to use
      regularly. On the other hand, you might discover that you have no
      use for the software you have just installed, deciding that you
      want to uninstall it.
    </para>
    <para>
      Uninstallation occurs by reversing the installation steps.
      Remember any special steps you have performed (such as adding a
      user account), and undo those. Then remember all the files you
      have installed and where you have installed them. Manually delete
      them. As you can see, this can become a pretty tedious exercise.
    </para>
    <para>
      If you like the application you have installed, you will likely
      find yourself wanting to upgrade it eventually. The Apache Web
      server, for example, like any network service, must be upgraded
      whenever security problems are found and fixed. If you find that
      you need to upgrade Apache, you need to back up your Apache
      configuration files and then uninstall Apache. The next step is to
      install a new version of Apache, applying your
      Apache-configuration customizations to your new installation of
      Apache.
    </para>
    <para>
      All of this is a big pain. There has to be a better way. And there
      is.
    </para>
  </sect1>
  <sect1>
    <title>Overcoming the Installation Obstacles</title>
    <para>
      None of the tasks you must perform to install, upgrade, or
      uninstall applications are especially difficult. However, these
      steps quickly become daunting when you consider all the files that
      must be managed. A full &RHL; 7.3 installation provides around
      3,000 executable commands and over 160,000 total files (some other
      Linux distributions are even larger!). Obviously, managing all
      these files by hand, although theoretically possible, is not
      technically feasible. On a smaller scale, even management of
      single applications is not practical. The Postfix e-mail server
      application, for example, consists of around 275 files scattered
      in a dozen or so different directories. Imagine trying to remember
      and manually remove all of those files (and only those files) to
      uninstall Postfix from your system!
    </para>
    <para>
      All the steps needed to manage software on Unix or Linux systems
      are hardly unique to Unix; all operating systems have similar
      procedures that must be followed to make software usable on the
      system. For this reason, many approaches have been adopted toward
      software installation, uninstallation, and upgrading.
    </para>
    <sect2>
      <title>Application-level utilities</title>
      <para>
        Some operating systems, such as MS-DOS, have supplied absolutely
        no built-in tools for software management. Installation of
        applications on such systems occurs in one of two ways: software
        is installed manually, using file-copy utilities to put all the
        application files in the appropriate places on the system, or
        software is installed using a custom-written installation
        application (as is usually the case for MS-DOS applications).
      </para>
      <para>
        Once installed, software can be uninstalled in one of two ways:
        you can manually delete each file installed for the application
        (assuming you can even remember them all), or the application
        might come with a custom uninstallation utility that can be run
        to remove the application. Upgrading an already installed
        application on such a system uses a similar procedure. If the
        application comes with an installation utility capable of
        handling application upgrades, you can use the utility to
        perform the upgrade. Otherwise, the software must be manually
        upgraded using the procedure described previously.
      </para>
      <note>
        <title>Current Windows Versions</title>

        <para>
          Current versions of Windows, such as Windows XP, have a
          central database of installed applications.
        </para>
      </note>
    </sect2>
    <sect2>
      <title>Built-in system utilities</title>
      <para>
        Other operating systems have come with built-in utilities that a
        system administrator can use to manage the system’s software.
        These utilities can be run to install the software on the
        system; typically, they take some of the work out of manually
        installing software, dealing with issues such as figuring out
        which files need to be put where on the system. Once installed,
        these utilities typically track the files that have been
        installed. This knowledge can usually be used to uninstall those
        applications automatically. Since the software knows which files
        are associated with the application, it can be told to uninstall
        the application, and it can find and delete all the files that
        belong to that application.
      </para>
      <para>
        These built-in utilities typically come in two different forms.
        One type focuses on managing the installation process, providing
        custom utilities that can be used to perform the otherwise
        manual tasks of compiling software and copying files into their
        final locations. The three major freely available Berkeley Unix,
        or BSD, operating systems, NetBSD, FreeBSD, and OpenBSD, for
        example, ship with a software-management system called,
        variously, ports (FreeBSD and OpenBSD) or packages (NetBSD).
      </para>
      <para>
        The ports system is composed of extensions to the normal Unix
        software-compilation utilities that help it automate and track
        many of the steps of a standard source-code compilation. When
        using ports, you still download source code, unarchive it,
        configure it, compile it, and install it, but the ports software
        automates many of these steps. Furthermore, the ports system
        does limited tracking of the files it installs. Although it does
        not offer more advanced features (such as an interface to search
        all installed files to see what application supplied that file)
        or the ability to upgrade installed applications, it does
        provide the ability to uninstall applications that are installed
        using ports. These sorts of limitations are typical of
        management applications that function as the ports system does,
        by enhancing the compilation and installation phases of
        application installation. The packages system on NetBSD has
        similar limitations.
      </para>
      <para>
        Other system-management utilities focus less attention on
        compiling an application for installation and more attention on
        the files that must be installed on the system after the
        application has been compiled.
      </para>
      <para>
        For example, the standard System V Unix package-management
        software supplied with most commercial Unix systems (Sun's
        Solaris, for example) devotes no attention to management of
        software compilation at all. Instead, it tracks the individual
        files associated with each application in a system database.
      </para>
      <para>
        To install software using the System V tools, you must compile
        the software. After compiling the software in the standard
        fashion, prepare a list of the files from that compilation that
        need to be installed on the system. Be certain to state where
        the files need to be installed and what permissions and
        ownerships they need to have once installed. Then run a series
        of commands that look at this list, find the files listed in it,
        and archive them into one file, along with a copy of this list
        that specifies where they should be installed and the ownerships
        and permissions. This single archive file can then be
        transferred to other machines, where a System V
        software-management command can be used to install it. This
        System V installation command (typically called
        <command>pkgadd</command>) unpacks the archive, copies the files
        into their final destinations based on the enclosed listing, and
        sets permissions and ownerships on the files as specified by the
        listing. Finally, this <command>pkgadd</command> command
        registers the list of freshly installed files into a system-wide
        database of installed files.
      </para>
      <para>
        Such a system offers several advantages over manual software
        installation. Software can now be installed and uninstalled
        easily, and the system-wide database of installed files can be
        readily searched to locate installed applications and files.
        However, this sort of system also has severe limitations; it is
        far less flexible in the software-configuration stages than
        software such as the FreeBSD ports system, which offers great
        control over the software-compilation stage of software
        installation.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Linux Software Management Tools: Packages</title>
    <para>
      Initially, Linux had neither type of software-management tool. In
      the early days of Linux, you installed Linux by cross-compiling it
      under a different operating system (Minix), then manually
      installing the compiled Linux programs into the appropriate
      locations to produce a working system. As Linux has matured,
      however, it has acquired software-management tools that have made
      software installation, removal, and upgrade significantly easier
      than in the early days. The exact software-management tool used on
      modern Linux systems varies from distribution to distribution, but
      both approaches to system management can be found in the tools
      used by various distributions.
    </para>
    <para>
      The Gentoo Linux (<ulink url="http://www.gentoo.org/"/>)
      distribution, for example, uses a software-management system
      called Portage, which is very similar to the FreeBSD ports system.
      Like ports, Portage provides great control over software
      compilation and installation, providing a collection of scripts
      that automate much of the basic work of downloading and compiling
      software.
    </para>
    <para>
      At the other end of the spectrum, the now-defunct deepLinux
      distribution used a software-management system called
      <command>deep-package</command> (still available from
      <ulink url="http://www2.cddc.vt.edu/linux/distributions/deeplinux/tools"/>).
      <command>deep-package</command> was intended to be a complete
      reimplementation of the Solaris <command>pkgadd</command> utility
      and its helpers. Like the Solaris <command>pkgadd</command>
      software, <command>deep-package</command> paid no attention to
      half of the question of how to manage software, focusing entirely
      on software installation and tracking issues while entirely
      ignoring the initial compilation of the software.
    </para>
    <para>
      More typically, however, Linux software-management tools use an
      approach somewhere between the two extremes represented by Portage
      and deep-package. Most Linux software-management tools provide
      software that manages the compilation of software, similarly to
      the FreeBSD ports tools. However, these software-management tools
      typically produce packages from the software they compile. Much
      like the archives produced by the System V software-management
      tools, packages are simply archive files that contain two things:
      a collection of related files, which together have a common use,
      and a script that provides all the metadata about those files
      necessary to install and manage those files.
    </para>
    <para>
      Typically, packages represent applications. For example, a Postfix
      package contains the 275 files that make up Postfix and a script
      that specifies where on the system those 275 files need to be
      placed, as well as what permissions and ownership those files
      need. A single command can then take this Postfix package file,
      extract its 275 archived files, and use the script to place those
      files correctly on the system.
    </para>
    <para>
      In addition, most Linux software-management tools have a database
      component that tracks files and applications that have been
      installed using the package-management software, helping the
      package manager do its job of easing the management of installed
      software.
    </para>
    <para>
      In the case of a full &RHL; 7.3 installation, this
      package-management software maintains a database of information
      regarding all 160,000 files on the system; as applications are
      installed on the system, this database is updated with information
      regarding the new application and the locations of its component
      files. This database is the key component, making it possible to
      manage the system. Since this database remembers which 275 files
      compose the Postfix application, it ensures that I can uninstall
      Postfix with a single command that accesses this database, without
      my having to remember the locations of all 275 files that make up
      the Postfix application.
    </para>
    <para>
      A wide variety of software-management tools are available for
      Linux to help lessen the work involved with installing, removing,
      and upgrading applications installed on the system. This book
      focuses on one of these tools, the RPM Package Management
      software, or RPM.
    </para>
    <note>
      <title>Change of Name</title>
<!-- SE: Don't replace "&RH;" with an entity here: we don't want the text to change -->
      <para>
        RPM was originally called Red Hat Package Manager. After
        adoption by other Linux distributions, the name has changed to
        simply the RPM Package Manager. The RPM initials remain the
        same.
      </para>
    </note>
    <para>
      As the original name implies, RPM was developed by &FORMAL-RHI;,
      the major Linux distributor in the United States. Even though the
      original name seems to point to a Red Hat-only solution, most Linux
      distributions use the RPM software. The RPM software provides a
      foundation needed by Linux system administrators throughout the
      world. You can even use RPM on other operating systems, both Linux
      and non-Linux, as covered in <xref linkend="ch-other-linuxes"/> and <xref linkend="ch-other-os"/>, respectively.
    </para>
    <para>
      The RPM system provides all of the features needed to manage
      applications, including a database of installed packages with
      their version numbers, the ability to install, remove, and update
      packages, and the ability to recompile an application from a
      source code RPM package.
    </para>
    <para>
      The remaining chapters in Part I go into depth on what you can do
      with RPM packages and the commands you need to work with the RPM
      system:
    </para>
    <orderedlist>
      <listitem>
        <para>
          <xref linkend="ch-intro-rpm"/> provides an overview of the RPM
          system, exploring what it was designed for and where it has
          weaknesses.
        </para>
      </listitem>
      <listitem>
        <para>
          <xref linkend="ch-rpm-overview" /> discusses the technical
          details of how the RPM system works, where the database of
          packages gets stored, and what commands should be available
          for working with RPM packages.
        </para>
      </listitem>
      <listitem>
        <para>
          <xref linkend="ch-using-rpm"/> continues the discussion by
          covering the three major tasks you need to perform with RPM
          packages: installing software, removing software, and
          upgrading software you have already installed.
        </para>
      </listitem>
      <listitem>
        <para>
          <xref linkend="ch-using-rpm-db" /> covers the RPM database,
          how it works, where it resides, and how you can use it to
          better manage your system.
        </para>
      </listitem>
      <listitem>
        <para>
          <xref linkend="ch-dependencies"/> delves into package
          dependencies, a very important concept. Most major
          applications depend on a number of other packages. Sometimes
          these dependencies get very complex, with one package
          depending on particular versions of other packages. With
          thousands of packages on your system, this can lead to a big
          mess. This chapter helps you to sort through the issues.
        </para>
      </listitem>
      <listitem>
        <para>
          <xref linkend="ch-transactions"/> covers the important issue
          of transactions, so that you can ensure your system gets
          updated in an orderly manner and so that you can roll back
          changes if something does not work out.
        </para>
      </listitem>
      <listitem>
        <para>
          <xref linkend="ch-management-software"/> introduces a host of
          tools that can help you find RPM packages as well as manage
          the packages on your system. This includes graphical
          interfaces on top of the RPM system and special Internet
          search sites devoted just to RPM packages.
        </para>
      </listitem>
    </orderedlist>
    <para>
      Later chapters cover creating RPM packages, programming with RPM,
      and extending the functionality provided by the base RPM system.
    </para>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      Modern operating systems have large complex sets of applications,
      resulting in thousands of files to keep track of for upgrades,
      installation, and removal of packages. All this complexity has
      lead Linux vendors to develop a variety of package-management
      tools.
    </para>
    <para>
      This chapter briefly introduced the RPM Package Manager, or RPM
      for short. The next chapter provides an overview of the RPM
      system, showing how all the parts fit together.
    </para>
  </sect1>
</preface>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "preface")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-intro-rpm.xml ---
<!-- $Id: -->

<chapter id="ch-intro-rpm">
  <title>Introduction to RPM</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Examining the history of package management
      </para>
    </listitem>
    <listitem>
      <para>
        Introducing RPM features
      </para>
    </listitem>
    <listitem>
      <para>
        Getting acquainted with RPM terminology
      </para>
    </listitem>
  </itemizedlist>
  <para>
    Several package managers are available for Linux to track and
    manipulate the applications installed on the system. The most widely
    used of these Linux package managers is the RPM Package Manager
    (formerly the &RH; Package Manager), or RPM for short, the
    subject of this book
  </para>
  <para>
    Although RPM was initially developed for &RHL;, a combination of
    technical features and good timing has resulted in RPM’s becoming
    the de facto standard for packaging software on most Linux
    distributions. The fact that &RH; released the source code to the
    RPM software under an open-source license also helped its adoption.
  </para>
  <para>
    More recently, the RPM package file format has been adopted as the
    official standard for Linux as part of the Linux Standards Base, or
    LSB. Described at <ulink url="http://www.linuxbase.org/"/>, the
    Linux Standards Base is an attempt to set a baseline that all Linux
    distributions should follow. Some vendors have been pulled in
    kicking and screaming, but the LSB for the most part has really
    helped the job of system administrators by providing some
    commonality across distributions, as in the location of certain
    files. The history of Linux package managers is largely intertwined
    with the history of Linux distributions.
  </para>
  <para>
    Strictly speaking, Linux refers to a single piece of software, the
    Unix-like kernel that Linus Torvalds and cohorts have scattered all
    over the Internet and have been developing since 1991. This Linux
    kernel is a marvelous piece of software, currently comprising over
    3.7 million lines of freely-licensed source code and accompanying
    documentation. Together, these factors provide a fast,
    full-featured, stable operating system kernel for use on more than
    30 different processor architectures, ranging from embedded systems
    such as watches and PDAs, to desktop and server systems, all the way
    up to mainframes and supercomputing clusters.
  </para>
  <sect1>
    <title>The Need for Linux Package Management Systems</title>
    <para>
      Although Linux is an excellent core component of an operating
      system suitable for a wide variety of real-world applications,
      this Linux kernel by itself is not sufficient for accomplishing
      most tasks. The technical definition of exactly what constitutes
      an operating system is a matter of debate.
    </para>
    <para>
      Despite this controversy, it is clear that most users of Linux
      require both the Linux kernel and a large suite of accompanying
      software (a shared C library; traditional Unix utilities such as
      <command>grep</command>, <command>awk</command>, and
      <command>sed</command>; an editor, such as <command>vi</command>;
      a shell, such as the Bourne-Again <command>bash</command> shell;
      and so forth) to complete the various tasks for which they
      typically employ Linux.
    </para>
    <para>
      Users expect Linux to include server software such as the Apache
      Web server, desktop software such as the OpenOffice.org office
      productivity suite, and a host of other packages. In fact, most
      Linux users don’t make the distinction between the kernel
      (technically the only part that is Linux) and all the extra
      packages (technically “everything else”) that comes with a
      Linux distribution. Most users simply refer to the whole thing as
      “Linux.”
    </para>
    <para>
      Some Linux distributions include thousands of packages on six or
      more CD-ROMs. This situation alone cries out for effective
      package-management software. And this doesn’t include the extra
      packages that don’t come with Linux distributions but which
      organizations need to create an effective working environment.
    </para>
    <para>
      Furthermore, the Linux kernel and these various software
      applications are typically made available by their developers in
      source code formats only, and they can be installed manually only
      after compiling them from source code.
    </para>
    <para>
      Most people do not have the technical skills necessary to
      cross-compile an entire operating system. Even if they do, they
      usually do not want to devote the time and effort required to
      bootstrap and compile an operating system just to be able to run
      Linux.
    </para>
    <para>
      Fortunately, the early Linux programmers quickly realized the
      impracticality of source-code only releases early in Linux's
      development and created what they called
      distributions—collections of precompiled binaries of the Linux
      kernel and other necessary software that users often wanted.
      Rather than installing Minix, compiling the Linux kernel and other
      required software applications under Minix, and installing those
      compiled binaries of the Linux kernel and essential Linux
      applications, users could just install these distributions,
      immediately having a functional Linux environment in which to
      work.
    </para>
    <para>
      Early distributions, such as MCC and SLS, initially represented
      little more than archived snapshots of their developer's hard
      drive. They offered the user performing the installation little or
      no control over what applications were put on the system. Whatever
      the distribution developer had on his hard drive was what the
      distribution installer got on her hard drive. Even this was much
      better than rolling your own distribution by hand. SLS, for
      example, stood for Soft Landing System, and was designed to make
      the experience of installing Linux easier, hence providing a
      “soft landing.” MCC Interim Linux, from the Manchester
      Computing Centre, was the first distribution to sport a combined
      boot/root disk, another attempt to make life easier for those
      adopting Linux.
    </para>
    <para>
      Distribution developers quickly realized, however, that more
      flexibility was needed and began looking for ways to provide
      choices both during and after installation. The Slackware
      distribution, for example, divided applications into several
      functional categories. All users installed the base distribution;
      users could then selectively install only the additional
      supplemental categories they needed. If networking support was
      desired, for example, the networking bundle could be installed.
      Similarly, if a graphical user interface was desired, the X bundle
      could be installed, making the X Window System available. This
      concept offered rudimentary control over what was installed but
      only at a very coarse level. Installing the X bundle put several
      applications (multiple X terminal emulators, several different
      window managers, and so forth) on the system, and all users who
      installed the bundle got all of those applications whether they
      wanted them all or not.
    </para>
    <para>
      The next logical step in distribution evolution was the
      development of more advanced tools to control what was installed.
      Several distributions independently developed the notion of
      application-level installation management. The developers of these
      distributions realized that Slackware and similar distributions
      were heading in the right direction, but simply had not made
      software management granular enough. Slackware allowed
      installation and uninstallation (after a fashion) of bundles of
      related applications, but what was really needed was installation
      and uninstallation on an application-by-application basis.
    </para>
<!-- SE: Note that "&RH;" should not replaced by entities when part of abbreviations -->
    <para>
      In late 1993, Rik Faith, Doug Hoffman, and Kevin Martin began
      releasing the first public betas of the BOGUS Linux distribution.
      BOGUS was notable for the package management system
      (<command>pms</command>) software that was used with it for
      installation and uninstallation of all software on an
      application-by-application basis. Shortly thereafter, in the
      summer of 1994, the first public betas of Red Hat Commercial Linux
      were released. &RH; initially used Red Hat Software Program
      Packages (RPP) as the basis of its Linux distribution. Like
      <command>pms</command>, RPP was a system-management tool that
      allowed for easy installation and uninstallation of applications.
      In late 1993, Ian Murdock founded the Debian Gnu/Linux
      distribution. He began seriously developing its
      <command>dpkg</command> application-management software by the
      summer of 1994. Like <command>pms</command> and RPP,
      <command>dpkg</command> made it possible to manage each
      application on the system.
    </para>
  </sect1>
  <sect1>
    <title>RPM Design Goals</title>
    <para>
      All of these early system-management tools took a similar
      approach. They provided the capability to install an entire
      application with a single command, to track the files it put on
      the system, and to remove those files by using another single
      command. As the preponderance of multiple early tools suggests,
      this approach to system management was popular. All of these early
      tools, however, had numerous technical or practical deficiencies.
      Some tools were designed only for Linux on 32-bit Intel-compatible
      hardware, even though Linux by this point was already running on
      other CPUs in addition to the IA32 family. As Linux was spreading
      to multiple architectures, a package-management system that could
      produce packages for multiple architectures was needed. Other
      tools had technical flaws in how they prepared packages, making it
      difficult to verify that packages had been prepared correctly or
      to see exactly how the software was prepared.
    </para>
    <para>
      Because of these concerns, after their initial releases of
      RPP-based distributions, &RH; looked closely at both their own RPP
      software and other software such as BOGUS's <command>pms</command>
      software. Developers at &RH;, particularly Marc Ewing and Erik
      Troan, set out to develop what they initially called the Red Hat
      Package Manager (RPM). Based on experiences with earlier Linux
      packaging software and knowledge about packaging tools used on
      other platforms, &RH; had several design goals in mind when they
      developed RPM. These design points include the following features:
    </para>
    <itemizedlist>
      <listitem>
        <para>
          Ease of use
        </para>
      </listitem>
      <listitem>
        <para>
          Package-oriented focus
        </para>
      </listitem>
      <listitem>
        <para>
          Upgradability of packages
        </para>
      </listitem>
      <listitem>
        <para>
          Tracking of package interdependencies
        </para>
      </listitem>
      <listitem>
        <para>
          Query capabilities
        </para>
      </listitem>
      <listitem>
        <para>
          Verification
        </para>
      </listitem>
      <listitem>
        <para>
          Support for multiple architectures
        </para>
      </listitem>
      <listitem>
        <para>
          Use of pristine sources
        </para>
      </listitem>
    </itemizedlist>
    <para>
      The following sections demonstrate how &RH; incorporated each of
      these design goals into RPM.
    </para>
    <sect2>
      <title>Ease of use</title>
      <para>
        Perhaps the primary design goal for RPM is that it must be easy
        to use. Manual software installation has been the primary method
        of putting software onto Unix boxes for over 30 years now and
        has worked very well for those three decades. To offer a
        compelling reason to use the new software, RPM must be
        significantly easier to use than other Linux package-management
        tools. For that reason, most tasks that can be handled using RPM
        were designed to be carried out via a single command. For
        example, software installation using RPM requires a single
        command (<userinput>rpm -U software_package</userinput>), while
        manual software installation using older manual methods
        typically requires at least six steps to complete the same task:
      </para>
      <orderedlist>
        <listitem>
          <para>
            <command>tar zxf
            <replaceable>software_package</replaceable></command>
          </para>
        </listitem>
        <listitem>
          <para>
            <command>cd
            <replaceable>software_package</replaceable></command>
          </para>
        </listitem>
        <listitem>
          <para>
            <command>./configure</command>
          </para>
        </listitem>
        <listitem>
          <para>
            <command>make</command>
          </para>
        </listitem>
        <listitem>
          <para>
            <command>su</command>
          </para>
        </listitem>
        <listitem>
          <para>
            <command>make install</command>
          </para>
        </listitem>
      </orderedlist>
      <para>
        Similarly, removal of applications installed using RPM requires
        a single command (<userinput>rpm -e
        <replaceable>software_package</replaceable></userinput>); manual
        removal of an installed application requires that each file
        associated with that application be manually deleted.
      </para>
    </sect2>
    <sect2>
      <title>Package-oriented focus</title>
      <para>
        Like its predecessors, RPM is intended to operate on a package
        level. Rather than operating on a single-file basis (as when you
        manually install software using Unix command-line tools like mv
        and cp) or on an entire system basis (as with many PC operating
        systems, which provide the ability to upgrade entire releases
        but not to upgrade individual components), RPM provides software
        that can manage hundreds or thousands of packages.
      </para>
      <para>
        Each package is a discrete bundle of related files and
        associated documentation and configuration information;
        typically, each package is a separate application. By focusing
        on the package as the managed unit, RPM makes installation and
        deletion of applications extremely straightforward.
      </para>
    </sect2>
    <sect2>
      <title>Package upgradability</title>
      <para>
        In addition to its package-oriented focus, RPM is designed to
        support upgrading packages. Once an application has been
        installed from an RPM package, a newer version of the same
        application can be installed using RPM. Doing so upgrades the
        existing application, removing its old files and replacing them
        with new files. In addition, however, RPM takes care to preserve
        any customizations that have been made to that application. The
        Apache Web server application, for example, is commonly
        installed on Linux machines that need the ability to serve Web
        pages.
      </para>
      <para>
        Apache's configuration information, which specifies things such
        as which files on the system should be made available as Web
        pages and who should be able to access those Web pages, is
        stored in a text file, typically
        <filename>/etc/httpd/conf/httpd.conf</filename>. Suppose Apache
        has been installed using RPM and that you have then customized
        <filename>httpd.conf</filename> to specify its configuration. If
        you upgrade Apache using RPM, as part of the upgrade procedure,
        the RPM application will take precautions to preserve the
        customizations you have made to the Apache configuration. In
        contrast, manual upgrades of applications often overwrite any
        existing configuration files, losing all site customizations the
        system administrator has made.
      </para>
    </sect2>
    <sect2>
      <title>Package interdependencies</title>
      <para>
        Software that manages the applications installed on the system
        on an application level (such as RPM) does have one potential
        drawback in comparison with system-wide software management
        systems (such as PC operating systems like Microsoft Windows or
        OS/2, which allow the entire system to be upgraded but do not
        generally allow individual components to be upgraded, added, or
        removed). Software applications often have interdependencies;
        some applications work only when other applications are
        installed.
      </para>
      <para>
        The Postfix and Sendmail mail transfer agent (MTA) applications
        that are commonly used on Linux boxes to serve e-mail, for
        example, can both be configured to require users to authenticate
        themselves (by submitting a correct user name and password)
        successfully before they can use the e-mail server. This feature
        is often used to prevent unauthorized access to the e-mail
        server, preventing unscrupulous advertisers from using the
        server as a tool to send unsolicited commercial e-mail (or UCE,
        popularly known as spam). For this optional feature of Postfix
        and Sendmail to work, however, additional software must be
        installed. Both applications use another application, Cyrus
        SASL, which provides the Simple Authentication and Security
        Layer (SASL) software that Postfix or Sendmail can use to check
        user names and passwords. In other words, Postfix and Sendmail
        depend on Cyrus SASL.
      </para>
      <para>
        For system-wide software management systems, logical
        interdependencies between system components such as these are
        easy to track. All required components are included as part of
        the system, and upgrading the system upgrades all these
        components, ensuring that all can still interoperate. On
        Microsoft Windows 2000, IIS (the application used on Windows to
        serve Web pages) requires several other applications such as
        <command>EventLog</command> (the Windows application that
        records system events, much like the Linux
        <command>syslogd</command> and <command>klogd</command>
        software) to be present. Since Windows is managed on a system
        level, not a package level, this dependency is guaranteed to be
        satisfied. On Linux systems using RPM, however, the situation is
        different. On Linux, for example, the Postfix application
        requires the <command>syslogd</command> application, which
        records system events. However, RPM provides the flexibility to
        install some applications but not install others or to uninstall
        others later. When you install Postfix, you have no guarantee
        that <command>syslogd</command> is already installed. If
        <command>syslogd</command> is not installed, Postfix will not
        work correctly.
      </para>
      <para>
        To avoid problems, &RH; developers realized that RPMs must also
        track dependency information about what software they require
        for correct functionality, and that the RPM install and
        uninstall applications must use this dependency information.
        Because of dependencies, installing Postfix using RPM on a
        system without <command>syslogd</command> installed generates a
        warning that <command>syslogd</command> must also be installed.
        Similarly, attempting to uninstall <command>syslogd</command>
        from a system that already has Postfix installed generates a
        warning that installed applications require the software that is
        being deleted. These warnings can be overridden if necessary,
        but by default RPM enforces these dependencies (refusing, for
        example, to let you uninstall <command>syslogd</command> without
        also uninstalling applications that require it, such as
        Postfix), preventing you from accidentally breaking applications
        by inadvertently uninstalling other software that they require
        to operate.
      </para>
    </sect2>
    <sect2>
      <title>Query capabilities</title>
      <para>
        As part of its implementation, the RPM software maintains a
        database on the system of all packages that have been installed,
        and documenting which files those packages have installed on the
        system. RPM is designed to be queried easily, making it possible
        for you to search this database to determine what applications
        have been installed on the system and to see which packages have
        supplied each file on the system. This feature makes RPM-based
        systems extremely easy to use, since a single RPM command can be
        used to view all installed applications on the system.
      </para>
    </sect2>
    <sect2>
      <title>Package verification</title>
      <para>
        RPM also maintains a variety of information about each installed
        file in this system database, such as what permissions each file
        should have and what size each file should be. &RH; developers
        designed this database to be useful for software verification.
        Over time, installed software will fail to work for reasons as
        mundane as the system administrator setting incorrect
        permissions on files or as exotic as nuclear decay of one of the
        computer's atoms releasing an alpha particle that can affect the
        computer's memory, corrupting that bit of memory and causing
        errors. Although RPM cannot prevent all errors that cause
        installed software to fail (obviously, there's not a single
        thing any software can do to prevent nuclear decay), it can be
        used to eliminate common errors. When an application fails, you
        can use the RPM database to make sure that all files associated
        with that application still have correct Unix file permissions
        and that no files associated with that application have become
        altered or corrupted.
      </para>
    </sect2>
    <sect2>
      <title>Multiple architectures</title>
      <para>
        Most of the RPM design goals mentioned so far are intended
        primarily to ease the life of system administrators and others
        who regularly install, remove, and upgrade applications or who
        need to see what is installed or verify that installed
        applications have been installed correctly. Some of the design
        goals for RPM are intended primarily not for those sorts of
        users of RPM but for users who must prepare software to be
        installed using RPM.
      </para>
      <para>
        One of the major limitations of early Linux package management
        utilities was that they could produce packages suitable only for
        installation on one type of computer: those that used 32-bit
        Intel-compatible CPUs. By 1994, Linux was beginning to support
        other CPUs in addition to the originally supported Intel CPUs.
        (Initially, Digital's Alpha processor and Motorola's 68000
        series of processors were among the first additional CPUs that
        Linux supported. These days, Linux supports dozens of CPU
        architectures.) This posed a problem for distribution developers
        such as &RH; and Debian, and for application vendors who desired
        to package their software for use on Linux. Because the
        available packaging methods could not produce packages for
        multiple architectures, packagers making software for multiple
        CPUs had to do extra work to prepare their packages.
      </para>
      <para>
        Furthermore, once the packagers had prepared packages, no method
        was available to indicate the architecture the packages
        targeted, making it difficult for end users to know on which
        machine types they could install the packages.
      </para>
      <para>
        &RH; decided to overcome these limitations by incorporating
        architecture support into RPM, adding features so that the basic
        setup a packager performs to create a package could be leveraged
        to produce packages that would run on various CPUs, and so that
        end users could look at a package and immediately identify for
        which types of systems it was intended.
      </para>
    </sect2>
    <sect2>
      <title>Pristine sources</title>
      <para>
        The BOGUS distribution's <command>pms</command> packaging system
        introduced the use of pristine source code to prepare packages.
        With &RH;'s early RPP package system and other similar early
        efforts, software packagers would compile software manually,
        then run commands to produce a package of that compiled
        software. Any changes made to the application's original source
        code were not recorded and would have to be recreated by the
        next person to package that software. Furthermore, end users
        wanting to know what changes had been made to the software they
        were running had no method of accessing that information.
      </para>
      <para>
        With RPM, &RH; developed a package system that produced two
        types of packages: binary and source. Binary packages are
        compiled software that can be installed and used. Source
        packages contain the source code for that software, along with a
        file documenting how that source code must be compiled to
        produce that binary package. This feature is probably the single
        most significant difference between modern Linux packaging
        software (such as RPM) and the packaging software used on other
        systems (such as the pkg format that commercial Unix systems
        use). Source packaging makes the job of software packager
        easier, since packagers can use old source packages as a
        reference when preparing new versions of those packages. Source
        packages are also convenient for the end user, because they make
        it easily possible to change options with which that software
        was compiled and to produce a new binary package that supports
        the features the user needs.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>RPM Terminology</title>
    <para>
      When working with RPM, understanding the package concept is key.
      RPM packages are provided as compressed archive files that contain
      one or more files, as well as instructions specifying installation
      information about those files, including the ownerships and
      permissions that should be applied to each file during
      installation. The instructions can also contain scripts to be run
      after installation or before uninstallation. These package files
      are extremely convenient; they provide a single file that can be
      easily transferred between machines for installation rather than
      having to transfer each file to be installed.
    </para>
    <para>
      To help in installation and management, all package files are
      labeled with highly identifiable names. Package files have
      four-part names, which typically look something like:
    </para>
    <itemizedlist>
      <listitem>
        <para>
          <filename>kernel-smp-2.4.18-3.athlon.rpm</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>kernel-smp-2.4.18-3.i586.rpm</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>kernel-smp-2.4.18-3.i686.rpm</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>kernel-source-2.4.18-3.i386.rpm</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>rootfiles-7.2-1.noarch.rpm</filename>
        </para>
      </listitem>
    </itemizedlist>
    <para>
      Here, the four parts of each name are separated from each other by
      dashes or periods. The structure of the package file name is
    </para>
    <para>
      <filename>name-version-release.architecture.rpm</filename>
    </para>
    <para>
      The name identifies what software is contained within the archive
      file. Typically, this is a name of an application or package that
      the archive installs on the system. For example,
      <filename>kernel-smp</filename> can be installed to provide a very
      important application, the SMP (symmetric multiprocessing, meaning
      it supports systems with more than one CPU in them) version of the
      Linux kernel, on the system. Sometimes, rather than an
      application, the software is a collection of other files needed on
      the system. The <filename>rootfiles</filename> package, for
      example, is not an application but is a collection of basic
      environmental configuration files for the
      <systemitem class="username">root</systemitem> user's account
      (such as <filename>/root/.bashrc</filename>, the
      <systemitem class="username">root</systemitem> user's Bash
      configuration file) that provides a usable, preconfigured working
      environment for the <systemitem class="username">root</systemitem>
      user.
    </para>
    <para>
      The second field in every package file's name is the version
      field. This field identifies the version number of the software
      that is contained in the package file. For example,
      <filename>kernel-smp-2.4.18</filename> indicates the RPM holds the
      2.4.18 release of the SMP version of the Linux kernel, and
      <filename>rootfiles-7.2</filename> is the 7.2 release of the
      <filename>rootfiles</filename> configuration files.
    </para>
    <para>
      Every package file name also has a third component: the release
      field. This field identifies which release of that version of the
      software the package file contains. Package files contain both
      software and instructions about how to install that software. As
      packages of a particular version of software are being prepared,
      mistakes are sometimes made in these instruction files, or bugs
      are sometimes fixed within a software version; more recent package
      files of that software version need to be prepared that correct
      the problem. The –1 in the <filename>rootfiles-7.2-1</filename>
      package shows this is the first release of the 7.2 version of the
      <filename>rootfiles</filename> software. The packager of
      <filename>rootfiles</filename> version 7.2 got everything right on
      the first try and had no need to prepare more than one release.
      The –3 in the <filename>kernel-smp-2.4.18-3</filename> package,
      on the other hand, is the third release of the 2.4.18 version of
      the SMP-capable Linux kernel. This release incorporates new
      patches to fix bugs present in older releases of the 2.4.18
      version of the Linux SMP kernel. The software packager increased
      the release number so that end users could distinguish the more
      recent, bug-fixed package file from the older, less bug-free
      package file.
    </para>
    <para>
      The final field in package file names is the architecture, which
      identifies the system types for which the package file is
      appropriate. For example, the
      <filename>kernel-smp-2.4.18-3.athlon</filename> package is
      intended for use on machines with an AMD Athlon CPU, and
      <filename>kernel-smp-2.4.18-3.i586</filename> is intended for use
      on machines with an i586 (Pentium-class) CPU or better. An
      architecture name of noarch indicates this is a special
      architecture such that the files in the package work on any
      architecture. Typically, this is because the files are all
      interpreted scripts, not binary executables, or are documentation.
    </para>
    <para>
      RPM supports various architectures. Table 2-1 presents the
      architectures available for different platforms as of RPM version
      4.1.
    </para>
    <para>
      Table 2-1 Supported Architectures
    </para>
    <informaltable frame="all">
      <tgroup cols="2">
        <tbody>
          <row>
            <entry>
              <para>
                Platform
              </para>
            </entry>
            <entry>
              <para>
                Architectures
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                Intel compatible 32-bit
              </para>
            </entry>
            <entry>
              <para>
                i386, i486, i586, i686, athlon
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                Intel compatible 64-bit
              </para>
            </entry>
            <entry>
              <para>
                ia64
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                HPAlpha (formerly Digital, Compaq)
              </para>
            </entry>
            <entry>
              <para>
                alpha, alphaev5, alphaev56, alphapca56, alphaev6,
                alphaev67
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                Sparc/Ultra Sparc (Sun)
              </para>
            </entry>
            <entry>
              <para>
                sparc, sparcv9, sparc64
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                ARM
              </para>
            </entry>
            <entry>
              <para>
                armv3l, armv4b, armv4l
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                MIPS
              </para>
            </entry>
            <entry>
              <para>
                mips, mipsel
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                Power PC
              </para>
            </entry>
            <entry>
              <para>
                ppc, ppciseries, ppcpseries, ppc64
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                Motorola 68000 series
              </para>
            </entry>
            <entry>
              <para>
                m68k, m68kmint
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                SGI MIPS
              </para>
            </entry>
            <entry>
              <para>
                Sgi
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                IBM RS6000
              </para>
            </entry>
            <entry>
              <para>
                rs6000
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                IBM S/390
              </para>
            </entry>
            <entry>
              <para>
                i370, s390x, s390
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                Platform independent
              </para>
            </entry>
            <entry>
              <para>
                noarch
              </para>
            </entry>
          </row>
        </tbody>
      </tgroup>
    </informaltable>
    <tip>
      <title>Architecture Compatibility</title>
      <para>
        When choosing an appropriate architecture for your machine, be
        aware that more recent architectures typically run software that
        targets older architectures within the same family; the reverse,
        however, is not true. For example, within the 32-bit
        Intel-compatible architectures, a 686-class (Pentium II / III /
        IV) machine runs files within i386, i486, i586, and i686 RPM
        package files, but a 386-class (80386) machine runs files within
        i386 RPM package files only. Similarly, for the Alpha
        architecture, more recent Alpha EV68 CPUs can run programs from
        RPM package files with alphaev67, alphaev6, alphaev56, alphaev5,
        and alpha architectures, but an older Alpha EV56 machine can run
        programs from RPM package files with alpha, alphaev5, or
        alphaev56 architectures only.
      </para>
    </tip>
    <para>
      Notice that the four fields in RPM package file names are
      separated from each other by punctuation, either a dash (-) or a
      period (.). Periods and dashes, however, are also allowed within
      fields. 7.2 is a valid version number, just as
      <filename>kernel-source</filename> is a valid software name.
      Finally, keep in mind that all RPM package files use an .rpm
      file-name extension to denote that they are RPMs.
    </para>
    <para>
      Once installed, package names are slightly different from package
      file names. Package files, which can be downloaded from the
      Internet, copied off of CDs, and otherwise easily transferred
      between machines, always have names that looks like
      name-version-release.architecture.rpm. Installed packages,
      however, have names that look like
      <filename>name-version-release</filename>. Once installed,
      packages are referred to without the architecture field and the
      .rpm extension. Furthermore, installed packages consist of lots of
      files, not a single RPM file. For example, the package file
      <filename>kernel-smp-2.4.18-3.i686.rpm</filename> after
      installation is referred to as
      <filename>kernel-smp-2.4.18-3</filename>. To simplify usage even
      further, installed packages can be referred to by their name field
      only, so this file would become simply
      <filename>kernel-smp</filename>.
    </para>
    <warning>
      <title>Software Names May Differ from Package Names</title>

      <para>
        Once installed, the name of the package does not have to be the
        same as the name portion of the original package file. By
        convention though, the package name matches the name, version,
        and release part of the file name.
      </para>
    </warning>
    <para>
      Usage of the name field by itself to name packages assumes that
      multiple versions or releases of that particular software are not
      installed. However, it is in some cases necessary to install
      different versions or releases of the same package. My desktop at
      home is a (by now, relatively old) dual Pentium-II system, so it
      uses an SMP-capable Linux kernel. On it, I have the following
      Linux SMP kernels installed:
    </para>
    <itemizedlist>
      <listitem>
        <para>
          kernel-smp-2.4.18-4
        </para>
      </listitem>
      <listitem>
        <para>
          kernel-smp-2.4.18-3
        </para>
      </listitem>
      <listitem>
        <para>
          kernel-smp-2.5.21-4
        </para>
      </listitem>
    </itemizedlist>
    <para>
      This example uses the <command>rpm <option>–q</option></command>
      command to query for all installed versions of the given package,
      <filename>kernel-smp</filename>.
    </para>
    <note>
      <title>The RPM Database</title>

      <para>
        <xref linkend="ch-using-rpm-db"/> covers querying the RPM
        database in depth.
      </para>
    </note>
    <para>
      I have two different package file releases (release 3 and release
      4) of the 2.4.18 version of the Linux kernel, and I have a
      development kernel, version 2.5.21, installed. On this system,
      since I have multiple packages installed of the
      <filename>kernel-smp</filename> software, I have to use the full
      package name (such as <filename>kernel-smp-2.4.18-4</filename>)
      whenever I want to work with my installed
      <filename>kernel-smp</filename> packages.
    </para>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      The RPM system wasn’t created to solve some theoretical problem.
      Instead, it is the result of years of hard-won practical
      experience in trying to manage systems with a large number of
      applications. RPM builds upon older systems that were created to
      solve some of the problems faced by system administrators. RPM
      goes further, though, and tries to provide a complete
      package-management solution. This includes the ability to deal
      with wrinkles that Linux faces but that many other operating
      systems do not need to address.
    </para>
    <para>
      For example, most other operating systems don’t support more
      than one or two processor architectures. Sun’s Solaris, for
      example, supports only the SPARC and Intel architectures. Linux
      supports these and more. Most other operating systems also don’t
      include nearly so many applications. From the OpenOffice.org
      office suite to the Apache Web server, Linux distributions are
      literally packed with applications. As a final point, most other
      operating systems provide mainly closed-source applications.
      Linux, on the other hand, includes thousands of open-source
      applications.
    </para>
    <para>
      From the perspective of the organizations making Linux
      distributions, these wrinkles make Linux harder to manage. Luckily
      for end users, the solution to these problems helps make the RPM
      system better able to manage user systems:
    </para>
    <orderedlist>
      <listitem>
        <para>
          Supports Multiple Architectures — The RPM system tags
          each package with the processor architecture.
        </para>
      </listitem>
      <listitem>
        <para>
          Permits Multiple Software Versions in Parallel — RPM
          allows for multiple versions of the same package to be
          installed on the same system.
        </para>
      </listitem>
      <listitem>
        <para>
          One File Per Program — RPM packs all of the files in a
          package into one file, called an RPM file, for easy transfer
          to other systems.
        </para>
      </listitem>
      <listitem>
        <para>
          Requires Only One Command Per Action — Most RPM
          operations such as installing or removing packages require
          only a single command to run.
        </para>
      </listitem>
      <listitem>
        <para>
          Uses Pristine Sourcecode — The RPM system supports
          building RPM packages from a pristine set of sources. This
          means you can reproduce the commands required to build an
          application, improving quality.
        </para>
      </listitem>
    </orderedlist>
    <para>
      This chapter introduced the RPM system and the history behind it.
      The next chapter delves into the RPM basics, including files,
      database, and commands.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-licensing.xml ---
<!-- $Id: -->

<chapter id="ch-licensing">
  <title>Licensing RPM</title>
  <para>
    When incorporating someone else's existing code into your software
    project, you should always examine the license of the code
    carefully, make sure you understand its implications, and make sure
    you are willing to abide by them. You also need to make sure you
    have the legal right to incorporate the other code in your project.
    This is true for commercial code and commercial projects, and it is
    equally true for freely licensed code and free software projects.
  </para>
  <para>
    RPM itself and most discussed helper applications (rpmlint,
    rpm-spec-mode, and so forth) are free software, meaning that the
    programs themselves are available without cost. In addition, most of
    these tools are considered open source software, which means the
    source code for the applications are also available.
  </para>
  <para>
    These facts do not mean that they are unlicensed software, or that
    their source code can be used in any desired fashion. RPM and these
    helper applications are made freely available in both source and
    binary formats under the terms of the GNU Project's General Public
    License (GPL). Parts of RPM are licensed under the LGPL, the Lesser
    General Public License. The terms of the GPL are reproduced here,
    and should be consulted before incorporating any source code or
    binaries licensed under the GPL into your projects. Essentially, the
    GPL states that you can use GPL'ed source code or binaries for any
    purpose, so long as you always give those same rights (including
    access to your program’s source code) to any users to whom you
    give software derived from GPL'ed source code (though a lawyer
    should be consulted to obtain an analysis of the implications of the
    GPL on your project, should you decide to use GPL'ed code in any
    commercially licensed project you might undertake).
  </para>
  <para/>
  <sect1>
    <title>The GNU General Public License</title>
    <para>
      Version 2, June 1991
    </para>
    <para/>
    <para>
      Copyright (C) 1989, 1991 Free Software Foundation, Inc.
    </para>
    <para>
      675 Mass Ave, Cambridge, MA 02139, USA
    </para>
    <para>
      Everyone is permitted to copy and distribute verbatim copies of
      this license document, but changing it is not allowed.
    </para>
    <para/>
    <para>
      Preamble
    </para>
    <para>
      The licenses for most software are designed to take away your
      freedom to share and change it. By contrast, the GNU General
      Public License is intended to guarantee your freedom to share and
      change free software--to make sure the software is free for all
      its users. This General Public License applies to most of the Free
      Software Foundation's software and to any other program whose
      authors commit to using it. (Some other Free Software Foundation
      software is covered by the GNU Library General Public License
      instead.) You can apply it to your programs, too.
    </para>
    <para/>
    <para>
      When we speak of free software, we are referring to freedom, not
      price. Our General Public Licenses are designed to make sure that
      you have the freedom to distribute copies of free software (and
      charge for this service if you wish), that you receive source code
      or can get it if you want it, that you can change the software or
      use pieces of it in new free programs; and that you know you can
      do these things.
    </para>
    <para/>
    <para>
      To protect your rights, we need to make restrictions that forbid
      anyone to deny you these rights or to ask you to surrender the
      rights. These restrictions translate to certain responsibilities
      for you if you distribute copies of the software, or if you modify
      it.
    </para>
    <para/>
    <para>
      For example, if you distribute copies of such a program, whether
      gratis or for a fee, you must give the recipients all the rights
      that you have. You must make sure that they, too, receive or can
      get the source code. And you must show them these terms so they
      know their rights.
    </para>
    <para/>
    <para>
      We protect your rights with two steps: (1) copyright the software,
      and (2) offer you this license which gives you legal permission to
      copy, distribute and/or modify the software.
    </para>
    <para/>
    <para>
      Also, for each author's protection and ours, we want to make
      certain that everyone understands that there is no warranty for
      this free software. If the software is modified by someone else
      and passed on, we want its recipients to know that what they have
      is not the original, so that any problems introduced by others
      will not reflect on the original authors' reputations.
    </para>
    <para/>
    <para>
      Finally, any free program is threatened constantly by software
      patents. We wish to avoid the danger that redistributors of a free
      program will individually obtain patent licenses, in effect making
      the program proprietary. To prevent this, we have made it clear
      that any patent must be licensed for everyone's free use or not
      licensed at all.
    </para>
    <para/>
    <para>
      The precise terms and conditions for copying, distribution and
      modification follow.
    </para>
    <para/>
    <para>
      TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
    </para>
    <para>
      0.This License applies to any program or other work which contains
      a notice placed by the copyright holder saying it may be
      distributed under the terms of this General Public License. The
      "Program", below, refers to any such program or work, and a "work
      based on the Program" means either the Program or any derivative
      work under copyright law: that is to say, a work containing the
      Program or a portion of it, either verbatim or with modifications
      and/or translated into another language. (Hereinafter, translation
      is included without limitation in the term "modification".) Each
      licensee is addressed as "you".
    </para>
    <para>
      Activities other than copying, distribution and modification are
      not covered by this License; they are outside its scope. The act
      of running the Program is not restricted, and the output from the
      Program is covered only if its contents constitute a work based on
      the Program (independent of having been made by running the
      Program). Whether that is true depends on what the Program does.
    </para>
    <para>
      1.You may copy and distribute verbatim copies of the Program's
      source code as you receive it, in any medium, provided that you
      conspicuously and appropriately publish on each copy an
      appropriate copyright notice and disclaimer of warranty; keep
      intact all the notices that refer to this License and to the
      absence of any warranty; and give any other recipients of the
      Program a copy of this License along with the Program.
    </para>
    <para>
      You may charge a fee for the physical act of transferring a copy,
      and you may at your option offer warranty protection in exchange
      for a fee.
    </para>
    <para>
      2.You may modify your copy or copies of the Program or any portion
      of it, thus forming a work based on the Program, and copy and
      distribute such modifications or work under the terms of Section 1
      above, provided that you also meet all of these conditions:
    </para>
    <para>
      a)You must cause the modified files to carry prominent notice
      stating that you changed the files and the date of any change.
    </para>
    <para>
      b)You must cause any work that you distribute or publish, that in
      whole or in part contains or is derived from the Program or any
      part thereof, to be licensed as a whole at no charge to all third
      parties under the terms of this License.
    </para>
    <para>
      c)If the modified program normally reads commands interactively
      when run, you must cause it, when started running for such
      interactive use in the most ordinary way, to print or display an
      announcement including an appropriate copyright notice and a
      notice that there is no warranty (or else, saying that you provide
      a warranty) and that users may redistribute the program under
      these conditions, and telling the user how to view a copy of this
      License. (Exception: if the Program itself is interactive but does
      not normally print such an announcement, your work based on the
      Program is not required to print an announcement.)
    </para>
    <para>
      These requirements apply to the modified work as a whole. If
      identifiable sections of that work are not derived from the
      Program, and can be reasonably considered independent and separate
      works in themselves, then this License, and its terms, do not
      apply to those sections when you distribute them as separate
      works. But when you distribute the same sections as part of a
      whole which is a work based on the Program, the distribution of
      the whole must be on the terms of this License, whose permissions
      for other licensees extend to the entire whole, and thus to each
      and every part regardless of who wrote it.
    </para>
    <para>
      Thus, it is not the intent of this section to claim rights or
      contest your rights to work written entirely by you; rather, the
      intent is to exercise the right to control the distribution of
      derivative or collective works based on the Program.
    </para>
    <para>
      In addition, mere aggregation of another work not based on the
      Program with the Program (or with a work based on the Program) on
      a volume of a storage or distribution medium does not bring the
      other work under the scope of this License.
    </para>
    <para>
      3.You may copy and distribute the Program (or a work based on it,
      under Section 2) in object code or executable form under the terms
      of Sections 1 and 2 above provided that you also do one of the
      following:
    </para>
    <para>
      a)Accompany it with the complete corresponding machine-readable
      source code, which must be distributed under the terms of Sections
      1 and 2 above on a medium customarily used for software
      interchange; or,
    </para>
    <para>
      b)Accompany it with a written offer, valid for at least three
      years, to give any third party, for a charge no more than your
      cost of physically performing source distribution, a complete
      machine-readable copy of the corresponding source code, to be
      distributed under the terms of Sections 1 and 2 above on a medium
      customarily used for software interchange; or,
    </para>
    <para>
      c)Accompany it with the information you received as to the offer
      to distribute corresponding source code. (This alternative is
      allowed only for noncommercial distribution and only if you
      received the program in object code or executable form with such
      an offer, in accord with Subsection b above.)
    </para>
    <para>
      The source code for a work means the preferred form of the work
      for making modifications to it. For an executable work, complete
      source code means all the source code for all modules it contains,
      plus any associated interface definition files, plus the scripts
      used to control compilation and installation of the executable.
      However, as a special exception, the source code distributed need
      not include anything that is normally distributed (in either
      source or binary form) with the major components (compiler,
      kernel, and so on) of the operating system on which the executable
      runs, unless that component itself accompanies the executable.
    </para>
    <para>
      If distribution of executable or object code is made by offering
      access to copy from a designated place, then offering equivalent
      access to copy the source code from the same place counts as
      distribution of the source code, even though third parties are not
      compelled to copy the source along with the object code.
    </para>
    <para>
      4.You may not copy, modify, sublicense, or distribute the Program
      except as expressly provided under this License. Any attempt
      otherwise to copy, modify, sublicense or distribute the Program is
      void, and will automatically terminate your rights under this
      License. However, parties who have received copies, or rights,
      from you under this License will not have their licenses
      terminated so long as such parties remain in full compliance.
    </para>
    <para>
      5.You are not required to accept this License, since you have not
      signed it. However, nothing else grants you permission to modify
      or distribute the Program or its derivative works. These actions
      are prohibited by law if you do not accept this License.
      Therefore, by modifying or distributing the Program (or any work
      based on the Program), you indicate your acceptance of this
      License to do so, and all its terms and conditions for copying,
      distributing or modifying the Program or works based on it.
    </para>
    <para>
      6.Each time you redistribute the Program (or any work based on the
      Program), the recipient automatically receives a license from the
      original licensor to copy, distribute or modify the Program
      subject to these terms and conditions. You may not impose any
      further restrictions on the recipients' exercise of the rights
      granted herein. You are not responsible for enforcing compliance
      by third parties to this License.
    </para>
    <para>
      7.If, as a consequence of a court judgment or allegation of patent
      infringement or for any other reason (not limited to patent
      issues), conditions are imposed on you (whether by court order,
      agreement or otherwise) that contradict the conditions of this
      License, they do not excuse you from the conditions of this
      License. If you cannot distribute so as to satisfy simultaneously
      your obligations under this License and any other pertinent
      obligations, then as a consequence you may not distribute the
      Program at all. For example, if a patent license would not permit
      royalty-free redistribution of the Program by all those who
      receive copies directly or indirectly through you, then the only
      way you could satisfy both it and this License would be to refrain
      entirely from distribution of the Program.
    </para>
    <para>
      If any portion of this section is held invalid or unenforceable
      under any particular circumstance, the balance of the section is
      intended to apply and the section as a whole is intended to apply
      in other circumstances.
    </para>
    <para>
      It is not the purpose of this section to induce you to infringe
      any patents or other property right claims or to contest validity
      of any such claims; this section has the sole purpose of
      protecting the integrity of the free software distribution system,
      which is implemented by public license practices. Many people have
      made generous contributions to the wide range of software
      distributed through that system in reliance on consistent
      application of that system; it is up to the author/donor to decide
      if he or she is willing to distribute software through any other
      system and a licensee cannot impose that choice.
    </para>
    <para>
      This section is intended to make thoroughly clear what is believed
      to be a consequence of the rest of this License.
    </para>
    <para>
      8.If the distribution and/or use of the Program is restricted in
      certain countries either by patents or by copyrighted interfaces,
      the original copyright holder who places the Program under this
      License may add an explicit geographical distribution limitation
      excluding those countries, so that distribution is permitted only
      in or among countries not thus excluded. In such case, this
      License incorporates the limitation as if written in the body of
      this License.
    </para>
    <para>
      9.The Free Software Foundation may publish revised and/or new
      versions of the General Public License from time to time. Such new
      versions will be similar in spirit to the present version, but may
      differ in detail to address new problems or concerns.
    </para>
    <para>
      Each version is given a distinguishing version number. If the
      Program specifies a version number of this License which applies
      to it and "any later version", you have the option of following
      the terms and conditions either of that version or of any later
      version published by the Free Software Foundation. If the Program
      does not specify a version number of this License, you may choose
      any version ever published by the Free Software Foundation.
    </para>
    <para>
      10.If you wish to incorporate parts of the Program into other free
      programs whose distribution conditions are different, write to the
      author to ask for permission. For software which is copyrighted by
      the Free Software Foundation, write to the Free Software
      Foundation; we sometimes make exceptions for this. Our decision
      will be guided by the two goals of preserving the free status of
      all derivatives of our free software and of promoting the sharing
      and reuse of software generally.
    </para>
    <para>
      NO WARRANTY
    </para>
    <para>
      11.BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
      WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
      LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS
      AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
      OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
      LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
      FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
      PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
      DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR
      OR CORRECTION.
    </para>
    <para>
      12.IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
      WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY
      MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
      LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
      INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
      INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
      DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU
      OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY
      OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN
      ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
    </para>
    <para>
      END OF TERMS AND CONDITIONS
    </para>
    <para/>
    <para>
      Appendix: How to Apply These Terms to Your New Programs
    </para>
    <para/>
    <para>
      If you develop a new program, and you want it to be of the
      greatest possible use to the public, the best way to achieve this
      is to make it free software which everyone can redistribute and
      change under these terms.
    </para>
    <para/>
    <para>
      To do so, attach the following notices to the program. It is
      safest to attach them to the start of each source file to most
      effectively convey the exclusion of warranty; and each file should
      have at least the "copyright" line and a pointer to where the full
      notice is found.
    </para>
    <para>
      <one line to give the program's name and a brief idea of what
      it does.> Copyright (C) 19yy <name of author>
    </para>
    <para>
      This program is free software; you can redistribute it and/or
      modify it under the terms of the GNU General Public License as
      published by the Free Software Foundation; either version 2 of the
      License, or (at your option) any later version.
    </para>
    <para>
      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      General Public License for more details.
    </para>
    <para>
      You should have received a copy of the GNU General Public License
      along with this program; if not, write to the Free Software
      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    </para>
    <para>
      Also add information on how to contact you by electronic and paper
      mail.
    </para>
    <para/>
    <para>
      If the program is interactive, make it output a short notice like
      this when it starts in an interactive mode:
    </para>
    <para>
      Gnomovision version 69, Copyright (C) 19yy name of author
      Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type
      `show w'. This is free software, and you are welcome to
      redistribute it under certain conditions; type `show c' for
      details.
    </para>
    <para/>
    <para>
      The hypothetical commands `show w' and `show c' should show the
      appropriate parts of the General Public License. Of course, the
      commands you use may be called something other than `show w' and
      `show c'; they could even be mouse-clicks or menu items--whatever
      suits your program.
    </para>
    <para/>
    <para>
      You should also get your employer (if you work as a programmer) or
      your school, if any, to sign a "copyright disclaimer" for the
      program, if necessary. Here is a sample; alter the names:
    </para>
    <para>
      Yoyodyne, Inc., hereby disclaims all copyright interest in the
      program `Gnomovision' (which makes passes at compilers) written by
      James Hacker.
    </para>
    <para>
      <signature of Ty Coon>, 1 April 1989Ty Coon, President of
      Vice
    </para>
    <para>
      This General Public License does not permit incorporating your
      program into proprietary programs. If your program is a subroutine
      library, you may consider it more useful to permit linking
      proprietary applications with the library. If this is what you
      want to do, use the GNU Library General Public License instead of
      this License.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-management-software.xml ---
<!-- $Id: -->

<chapter id="ch-management-software">
  <title>RPM Management Software</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Finding packages in RPM format
      </para>
    </listitem>
    <listitem>
      <para>
        Graphical tools to manage RPM packages
      </para>
    </listitem>
    <listitem>
      <para>
        Extending RPM management with additional tools
      </para>
    </listitem>
  </itemizedlist>
  <para>
    You can find a variety of software packages to ease the work of
    managing RPM-based systems. These utilities can help you find a
    specific software application packaged using RPM or search through a
    collection of RPM-packaged software to locate applications with
    specific features. Similarly, several utilities provide features to
    ease long-term system-management tasks. These applications provide
    features such as automatic updating of existing installed software
    with more recent versions or simplification of software installation
    by automating installation of any required software dependencies.
  </para>
  <para>
    This chapter covers a number of tools for finding packages in RPM
    format, as well as tools to help manage the RPMs on your system.
  </para>
  <sect1>
    <title>Locating RPMs</title>
    <para>
      RPM provides a powerful tool for managing software installed on a
      system. With a single command, an entire application can be
      installed on the system in a ready-to-run configuration. With a
      different command, the entire application can be removed without
      having manually to track down all of the associated files
      scattered throughout the hard drive. For RPM to work, however, the
      software being managed must be packaged in the proper RPM format.
      RPM packages can be easily prepared if necessary, but you can save
      time by using the wide variety of software already available in
      the RPM format. The only trick to using this RPM-packaged software
      is finding it.
    </para>
    <para>
      As you start to search for RPM packages on the Internet, you’ll
      find thousands of packages available. Many of these packages are
      built specifically for various Linux distributions, such as
      Conectiva, SUSE, &RH;, or Mandrake. In many cases, the Linux
      distribution won’t matter, but in general it's best to download
      packages built for your version of Linux, such as &RH;.
    </para>
    <para>
      Note
    </para>
    <para>
      Although the examples in this book assume &RHL; as a base,
      just about everything applies to all versions of Linux that use
      the RPM system, unless noted otherwise.
    </para>
    <para>
      Internet search engines are popular, but they aren’t very
      helpful for finding RPM packages, especially because lots of Web
      pages have the term rpm (including those covering revolutions per
      minute). A more efficient approach is to use one of the
      RPM-specific Internet search tools such as rpmfind.
    </para>
    <sect2>
      <title>rpmfind and rpm2html</title>
      <para>
        One popular free tool for locating RPMs is rpmfind, written by
        Daniel Veillard. This tool provides a command-line utility that
        can search for packages by name or description, displaying or
        optionally downloading any matching packages it finds. It can
        even provide a list of the dependencies that those matching
        packages require to run and can download those required
        dependencies as well.
      </para>
      <para>
        When searching for packages, rpmfind can search both the
        software already installed on the local system and remote
        databases, including the databases located at
        http://rpmfind.net/.
      </para>
      <para>
        Note
      </para>
      <para>
        The databases at http://rpmfind.net/ are, in turn, created by
        another utility: rpm2html. Both are covered in the sections
        following.
      </para>
      <para>
        Commonly, rpmfind is used to search for packages by name, though
        it can be used to search package descriptions for key words. For
        example, I might want to find new e-mail clients to install on
        my system. I happen to know that one popular Linux e-mail client
        is Ximian’s evolution, so I search for that.
      </para>
      <para>
        The basic syntax for rpmfind follows:
      </para>
      <para>
        rpmfind package_name
      </para>
      <para>
        For example, to search for evolution, use a command like the
        following:
      </para>
      <para>
        $ rpmfind evolution
      </para>
      <para>
        Resource evolution already installed
      </para>
      <para>
        $
      </para>
      <para>
        Before accessing the Internet, rpmfind searches my local system
        and finds that I already have evolution installed, so it does
        not even bother searching for copies to download. It looks like
        I’m forgetful, not remembering that I already have evolution
        installed. At this point, I might realize that I already have
        the software I need, or I might decide to search for a similar
        application, such as exmh, another popular Unix e-mail client.
      </para>
      <para>
        To search for exmh (which in this example has not been
        installed), use a command like the following:
      </para>
      <para>
        $ rpmfind exmh
      </para>
      <para>
        Installing exmh will require 7301 KBytes
      </para>
      <para/>
      <para>
        ### To Transfer:
      </para>
      <para>
        ftp://ftp.redhat.com/pub/redhat/linux/7.2/en/os/i386/RedHat/RPMS//nmh-1.0.4-9.i3
      </para>
      <para>
        86.rpm
      </para>
      <para>
        ftp://ftp.redhat.com/pub/redhat/linux/7.2/en/os/i386/RedHat/RPMS//exmh-2.4-2.noarch.rpm
      </para>
      <para>
        Do you want to download these files to /tmp [Y/n/a/i] ? : a
      </para>
      <para>
        transferring
      </para>
      <para>
        ftp://ftp.redhat.com/pub/redhat/linux/7.2/en/os/i386/RedHat/RPMS//nmh-1.0.4-9.i386.rpm
      </para>
      <para>
        saving to /tmp/nmh-1.0.4-9.i386.rpm
      </para>
      <para>
        transferring
      </para>
      <para>
        ftp://ftp.redhat.com/pub/redhat/linux/7.2/en/os/i386/RedHat/RPMS//exmh-2.4-2.noarch.rpm
      </para>
      <para>
        saving to /tmp/exmh-2.4-2.noarch.rpm
      </para>
      <para>
        rpm -U /tmp/nmh-1.0.4-9.i386.rpm /tmp/exmh-2.4-2.noarch.rpm
      </para>
      <para>
        $
      </para>
      <para>
        Here, rpmfind searches my local system for exmh. Since exmh is
        not installed there, rpmfind searches the databases at
        http://rpmfind.net/ and does two things: it finds exmh, and it
        learns that exmh depends upon another package: nmh. After
        double-checking and learning that nmh is not installed on my
        local system, rpmfind gives me a choice regarding whether I
        should download both of those packages; rpmfind gives me four
        possible answers:
      </para>
      <para>
        Do you want to download these files to /tmp [Y/n/a/i] ? : a
[...1719 lines suppressed...]
        These resource databases are essential for apt to operate. For
        this reason, apt can only be used to update systems from
        apt-capable repositories.
      </para>
      <para>
        Although apt was created by the Debian Project and designed for
        dpkg-format software packages, nothing about apt requires that
        it inherently be usable only with dpkg-format packages. Because
        of this, and because of its powerful capabilities, Conectiva, a
        Brazilian Linux distribution vendor (www.conectiva.com),
        extended apt to support management of RPM packages in addition
        to dpkg packages. Conectiva’s work, commonly referred to as
        apt-rpm, makes the apt client software available for use on any
        RPM-based Linux distribution. Conectiva also provides its
        customers with access to apt-capable FTP servers. A related
        project, apt4rpm (http://apt4rpm.sourceforge.net/), supplies the
        necessary utilities that can be used to make any RPM repository
        apt-capable. By creating apt-capable servers using apt4rpm and
        then installing apt-rpm on the client systems, any RPM-based
        distribution, such as &RHL;, Mandrake Linux, Caldera/SCO
        OpenLinux, or SUSE Linux, can then be easily managed using apt.
      </para>
      <para>
        Note
      </para>
      <para>
        The freshrpms.net site, mentioned previously, provides a touted
        apt repository.
      </para>
      <para>
        Administrators managing multiple dispersed machines as well as
        those used to Debian administration often find it useful to
        configure their machines to use apt; its dependency tracking is
        far better than any other tool, except for &RH;’s
        up2date/RHN combination. To use apt, administrators must install
        it on their machines and have access to an apt-capable RPM
        repository for the distribution they use. Several public FTP
        sites that support apt are now available for most of the major
        RPM-based distributions. Also, the administrator can create
        another apt-capable repository.
      </para>
      <para>
        Configuration of machines to use apt is simple. The apt and
        libapt RPMs simply need to be installed. Although binaries are
        sometimes available, the best success can usually be obtained by
        building binary RPMs from the latest Conectiva apt SRPM (source
        RPM), available at
        ftp://ftp.conectiva.com/pub/conectiva/EXPERIMENTAL/apt/.
      </para>
      <para>
        Once apt and libapt RPMs are installed, the sources.list file in
        /etc/apt needs to be modified to reference the apt-capable
        software site that will be used. For example, to configure a
        machine to access the apt-capable &RHL; 7.2 software
        distributed by the Tuxfamily.org server, the
        /etc/apt/sources.list file needs to list:
      </para>
      <para>
        rpm http://apt-rpm.tuxfamily.org/apt redhat-7.2-i386/redhat os
      </para>
      <para>
        rpm http://apt-rpm.tuxfamily.org/apt redhat-updates-7.2/redhat
        os
      </para>
      <para>
        These two lines, respectively, access the &RHL; 7.2 and
        &RHL; 7.2 errata RPMs being served by the system
        apt-rpm.tuxfamily.org. If you also want access to source RPMs,
        the following lines are necessary as well.
      </para>
      <para>
        rpm-src http://apt-rpm.tuxfamily.org/apt redhat-7.2-i386/redhat
        os
      </para>
      <para>
        rpm-src http://apt-rpm.tuxfamily.org/apt
        redhat-updates-7.2/redhat os
      </para>
      <para>
        In addition to, or instead of, using public apt-capable servers,
        many sites want to create their own apt servers. If apt is being
        used to manage all the machines in the enterprise, a custom apt
        server might be needed that contains apt-accessible RPMs of all
        the custom software used in the enterprise. This can be done
        using the tools provided by the apt4rpm package
        (http://apt4rpm.sourceforge.net).
      </para>
      <para>
        Once apt has been installed on clients, and the clients have
        been configured to access an apt-capable server, keeping systems
        updated is simple. The command apt-get update updates the client
        system’s apt database of available software, after which the
        command apt-get upgrade upgrades all currently installed
        software to the latest version available in the software
        repository. By listing a site that provides vendor errata
        updates in /etc/apt/sources.list and then setting up a nightly
        cron job to run the apt-get upgrade command, administrators can
        be sure that client systems always have the latest errata
        installed. You can use a similar technique to ensure that all
        client systems are always up to date with the latest custom
        in-house applications. To do this, set up your own apt server
        and ensure that the latest custom applications are placed on the
        apt server.
      </para>
      <para>
        In addition, apt simplifies interactive installation of RPMs on
        systems that are using it. The command apt-get install package
        retrieves the named RPM from the apt-capable software repository
        and installs it. If the package requires any dependencies that
        are not already resolved, apt will ask for confirmation, then
        download and install the package and all dependencies.
        Similarly, apt-get remove package uninstalls the named RPM. If
        any other packages depend on it, it will prompt for
        confirmation, then uninstall the named RPM and all of its
        dependencies.
      </para>
      <para>
        In addition to these command-line utilities, several graphical
        front-end tools for manipulating apt are currently being ported
        for use with apt-rpm. Because of its ease of use for automating
        installation of system errata and necessary custom software, and
        because of the excellent dependency tracking it provides for
        interactive installation and uninstallation of software, apt-rpm
        can be excellent for managing RPM-based systems.
      </para>
    </sect2>
    <sect2>
      <title>The poldek</title>
      <para>
        Also similar to the Debian apt tool, a utility called the poldek
        works like apt-get. The poldek was designed to quickly scan
        through dependencies and install a number of packages at once.
        You can specify all the packages to install in a file.
      </para>
      <para>
        The poldek automatically downloads any needed dependencies. The
        poldek can download files over the Internet and also help create
        the packages for storage on CD-ROMs. The poldek optimizes the
        set of packages to reduce the number of times users have to
        switch CDs.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        For more on the poldek, see poldek.pld.org.pl.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      This chapter has covered a number of tools for finding packages in
      RPM format, as well as tools to help manage the RPMs on your
      system. The rpm command does a great job of installing, removing,
      and upgrading packages. You can use it or choose from one of the
      many graphical RPM management tools shown in this chapter.
    </para>
    <para>
      The rpmfind utility helps find RPM packages on Internet servers.
      You can use rpmfind to find the latest version of the packages
      installed on your system.
    </para>
    <para>
      The Nautilus file manager allows you to browse files on disk, and
      it installs any RPM files you double-click.
    </para>
    <para>
      &RHL; 8 comes with a new package-management tool available
      from the System Settings menu. Be careful with this tool, though,
      as it automatically installs--and removes--dependent packages.
    </para>
    <para>
      AutoRPM and AutoUpdate provide utilites that you can run
      periodically to ensure that your systems are up to date. The Red
      Hat Network and up2date also provides this capability.
    </para>
    <para>
      The Debian GNU/Linux apt system provides many of the same
      capabilities as RPM, along with the network-updating capabilities
      of up2date and the &RHN;. You can use special apt
      packages that adapt apt for RPM-based Linux distributions and get
      the best of both the RPM system and the apt system.
    </para>
    <para>
      The next chapter starts the major section on creating RPMs. The
      RPM system reduces a lot of the burden of administering Linux
      systems. You can take advantage of this when building any sort of
      software for distribution--or even when managing your own system.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-online-resources.xml ---
<!-- $Id: -->

<chapter id="ch-online-resources">
  <title>RPM Resources</title>
  <para>
    This appendix covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Finding RPM sites on the Internet
      </para>
    </listitem>
    <listitem>
      <para>
        Accessing RPM newsgroups and mailing lists
      </para>
    </listitem>
  </itemizedlist>
  <para>
    This appendix covers the material available on the Internet for
    working with RPM.
  </para>
  <sect1>
    <title>Finding RPM Sites</title>
    <para>
      There is a wealth of RPM material online, although some of it is
      hard to find. The following sections list a number of RPM-related
      sites, divided by category. Note that as with any Internet sites,
      the sites listed my change or disappear.
    </para>
    <sect2>
      <title>The main rpm.org site</title>
      <para>
        The main RPM site is www.rpm.org. This site provides the
        official distributions of the RPM software, as well as a lot of
        documentation online.
      </para>
      <para>
        Table F-1 lists a number of useful links on this site.
      </para>
      <para>
        Table F-1 Links on the rpm.org site
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  Link
                </para>
              </entry>
              <entry>
                <para>
                  Holds
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  ftp://ftp.rpm.org/pub/rpm/dist/
                </para>
              </entry>
              <entry>
                <para>
                  RPM software downloads
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  ftp://ftp.rpm.org/pub/
                </para>
              </entry>
              <entry>
                <para>
                  rpm.org download site
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  www.rpm.org/cvs_help/
                </para>
              </entry>
              <entry>
                <para>
                  Instructions for accessing the RPM CVS repository
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  www.rpm.org/hintskinks/
                </para>
              </entry>
              <entry>
                <para>
                  Tips for working with RPM
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  www.rpm.org/hintskinks/bootstrap/
                </para>
              </entry>
              <entry>
                <para>
                  Good tips on bootstrapping RPM to new platforms
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  www.rpm.org/howto/
                </para>
              </entry>
              <entry>
                <para>
                  How-to documents for working with RPM
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  www.rpm.org/max-rpm/
                </para>
              </entry>
              <entry>
                <para>
                  Maximum RPM by Edward C. Bailey
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  www.rpm.org/RPM-HOWTO/
                </para>
              </entry>
              <entry>
                <para>
                  Good introductory tutorial
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  www.rpm.org/rpmapi-4.1/
                </para>
              </entry>
              <entry>
                <para>
                  API documentation
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
      <para>
        The main RPM FTP site, at ftp://ftp.rpm.org/pub/, includes the
        RPM distributions, as well as the Berkeley DB version 3 library,
        and the text of the book Maximum RPM. Download RPM software from
        ftp://ftp.rpm.org/pub/rpm/dist/.
      </para>
    </sect2>
    <sect2>
      <title>RPM locator sites</title>
      <para>
        A number of sites help you find RPMs for various applications.
        On the main sites, you can find specially built RPMs for a
        variety of Linux distributions. You can then download the RPMs
        made especially for your systems.
      </para>
      <para>
        The main RPM-finding site is rpmfind.net, which offers a search
        engine as well as software you can run on your site.
      </para>
      <para>
        The RPM PBone Search, at http://rpm.pbone.net/, is also very
        useful.
      </para>
      <para>
        The www.rpm.org/packagers/ site lists a number of places that
        package RPMs and provide them for downloading.
      </para>
      <para>
        Many Java libraries and packages are available in RPM format
        from www.jpackage.org/.
      </para>
      <para>
        Table F-2 lists a number of other RPM download sites.
      </para>
      <para>
        Table F-2 RPM download sites
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  Site
                </para>
              </entry>
              <entry>
                <para>
                  Holds
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  rpmfind.net
                </para>
              </entry>
              <entry>
                <para>
                  Links to a huge number of RPMs, many specific to
                  various Linux distributions
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  http://rpm.pbone.net/
                </para>
              </entry>
              <entry>
                <para>
                  RPM PBone search, useful for finding RPMs
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  www.rpm.org/packagers/
                </para>
              </entry>
              <entry>
                <para>
                  Lists a number of sites that provide RPMs for download
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  www.javapackage.org
                </para>
              </entry>
              <entry>
                <para>
                  Many Java packages in RPM format
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  http://plf.zarb.org/
                </para>
              </entry>
              <entry>
                <para>
                  The Penguin Liberation Front has RPMs that for legal
                  reasons cannot be included in the Mandrake Linux
                  distribution.
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  www.math.unl.edu/~rdieter/Projects
                </para>
              </entry>
              <entry>
                <para>
                  Rex Dieter’s RPM site
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  www.rpmhelp.net
                </para>
              </entry>
              <entry>
                <para>
                  Mandrake Linux RPMs
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  www.aucs.org/rpmcenter/
                </para>
              </entry>
              <entry>
                <para>
                  Edwin Chan's &RH; RPMs
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  www.owlriver.com/projects/links/
                </para>
              </entry>
              <entry>
                <para>
                  Owl River Company RPMs
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
    </sect2>
    <sect2>
      <title>RPM tools sites</title>
      <para>
        A large number of tools exist to help you work with RPMs. The
        following sites list some of the main tools:
      </para>
      <para>
        *For the vim text editor, you can download a spec.vim syntax
        file from
        http://pegasus.rutgers.edu/~elflord/vim/syntax/spec.vim.
      </para>
      <para>
        *For emacs, you can download an Emacs mode for spec files from
        http://tihlde.org/~stigb/rpm-spec-mode.el.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-development-tools"/>  lists links for a number of text editors.
      </para>
      <para>
        *The rpmlint tool mentioned in <xref linkend="ch-extra-packaging-tools"/>  is available at
        http://people.mandrakesoft.com/~flepied/projects/rpmlint/.
      </para>
      <para>
        Table F-3 lists a number of RPM-related tools and the sites you
        can find more information on the tools.
      </para>
      <para>
        Table F-3 RPM-related tools
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  Tool
                </para>
              </entry>
              <entry>
                <para>
                  Site
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  apt-rpm
                </para>
              </entry>
              <entry>
                <para>
                  ftp://ftp.conectiva.com/pub/conectiva/EXPERIMENTAL/apt/
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  apt4rpm
                </para>
              </entry>
              <entry>
                <para>
                  http://apt4rpm.sourceforge.net/
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  AutoRPM
                </para>
              </entry>
              <entry>
                <para>
                  www.autorpm.org
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  AutoUpdate
                </para>
              </entry>
              <entry>
                <para>
                  www.mat.univie.ac.at/~gerald/ftp/autoupdate
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  current
                </para>
              </entry>
              <entry>
                <para>
                  www.biology.duke.edu/computer/unix/current/
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  kpackage
                </para>
              </entry>
              <entry>
                <para>
                  www.kde.org
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  MakeRPM.pl
                </para>
              </entry>
              <entry>
                <para>
                  www.perl.com/CPAN/modules/by-authors/id/JWIED
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  poldek
                </para>
              </entry>
              <entry>
                <para>
                  http://poldek.pld.org.pl/
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  rpm2html
                </para>
              </entry>
              <entry>
                <para>
                  rpmfind.net/linux/rpm2html/
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  rpmfind
                </para>
              </entry>
              <entry>
                <para>
                  rpmfind.net
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  RUST
                </para>
              </entry>
              <entry>
                <para>
                  www.rusthq.com
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  setup.sh
                </para>
              </entry>
              <entry>
                <para>
                  www.mmedia.is/~bre/programs/setup.sh
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  urpmi
                </para>
              </entry>
              <entry>
                <para>
                  www.linux-mandrake.com/cooker/urpmi.html
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
    </sect2>
    <sect2>
      <title>Programming sites</title>
      <para>
        Only a few sites exist to help developers with programming for
        RPM. I maintain some quick links to RPM sites at
        www.pconline.com/~erc/rpm.htm. Most of these links are focused
        for programming with RPM.
      </para>
      <para>
        The best sites for programming RPM are the online API
        documentation at www.rpm.org/rpmapi-4.1/ for the RPM 4.1
        release, and the ftp.rpm.org/pub/rpm/dist/ site for downloading
        the RPM sources. There is a lot of documentation bundled with
        the source code.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-development-tools"/>  lists links for a number of Integrated Development
        Environments, or IDEs, aimed at programmers.
      </para>
    </sect2>
    <sect2>
      <title>Sites related to RPM</title>
      <para>
        If you try to make cross-platform RPMs, especially RPMs that
        should work for multiple versions of Linux, it is very important
        to follow the Linux standards for things like file placement and
        package formats.
      </para>
      <para>
        The Filesystem Hierarchy Standard, or FHS, covers Linux
        directory layout at www.pathname.com/fhs/.
      </para>
      <para>
        The Linux Standards Base is working on standardizing on the RPM
        package file format. See www.linuxbase.org for details.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Accessing RPM Mailing Lists and Newsgroups</title>
    <para>
      The RPM mailing list provides the best source of technical RPM
      information. You can post questions and get quick, useful
      responses. If you are working with RPM, you should subscribe to
      this mailing list. For details on viewing the RPM mailing list
      archives and signing up for the list, see
      www.rpm.org/mailing_list/.
    </para>
    <para>
      To help avoid unwanted commercial e-mail (in other words, spam),
      you need to register with a user name and password to subscribe to
      the mailing list or view the archives.
    </para>
    <para>
      A Usenet newsgroup, named linux.redhat.rpm, also provides a forum
      for asking RPM-related questions. You can read this newsgroup with
      any newsreading program.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-other-linuxes.xml ---
<!-- $Id: -->

<chapter id="ch-other-linuxes">
  <title>Using RPM on Non-&RHL;es</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Dealing with RPM issues on other versions of Linux
      </para>
    </listitem>
    <listitem>
      <para>
        RPM standardization
      </para>
    </listitem>
    <listitem>
      <para>
        Working around RPM differences when installing RPMs
      </para>
    </listitem>
    <listitem>
      <para>
        Working around RPM differences when building RPMs
      </para>
    </listitem>
    <listitem>
      <para>
        Dealing with non-RPM-based Linux distributions
      </para>
    </listitem>
  </itemizedlist>
  <para>
    Although its name was originally the Red Hat Package Manager, RPM
    has been adopted by most major Linux distributions. With this
    adoption, RPM has moved from its &RH; roots, and RPM now stands
    for the RPM Package Manager.
  </para>
  <para>
    In addition, the RPM package format is being adopted by the Linux
    Standards Base (LSB). The LSB defines a set of standards to help
    maintain compatibility for all Linux distributions.
  </para>
  <para>
    Cross Reference
  </para>
  <para>
    See www.linuxbase.org for more on the LSB.
  </para>
  <para>
    This chapter covers differences in how Linux distributions use RPM,
    ways to work around these differences, and also tools you can use
    for non-RPM distributions.
  </para>
  <sect1>
    <title>Troubleshooting RPM Installation Issues</title>
    <para>
      The main RPM issues when dealing with installing RPMs on other
      versions of Linux are:
    </para>
    <para>
      *Different versions of RPM itself
    </para>
    <para>
      *Different divisions of software into packages
    </para>
    <para>
      *Dealing with dependency issues
    </para>
    <para>
      *Different install locations
    </para>
    <para>
      The following sections expand on these issues.
    </para>
    <sect2>
      <title>Dealing with RPM versions</title>
      <para>
        &RHL; 8.0 ships with RPM version 4.1. Other
        distributions of Linux ship with other versions of RPM. Thus,
        one of the first commands you can run on another Linux
        distribution is the rpm --version command, to see what RPM
        version is in use and help identify any issues. For example:
      </para>
      <para>
        $ rpm --version
      </para>
      <para>
        RPM version 4.1
      </para>
      <para>
        Once you know the RPM version, you can plan for any issues that
        arise from installing RPMs made with a different RPM version.
        For example, RPM 4.0 and higher inserts dependency information
        automatically into RPMs. If your Linux distribution runs RPM
        3.x, you may need to disable some of the dependency checks, for
        example, if you want to install RPMs built under RPM 4.x onto an
        RPM 3.x system.
      </para>
      <para>
        On installing RPMs, you can disable the dependency checks with
        the --nodeps option. If you do this, though, you should manually
        check that the dependencies are really met by your Linux
        installation.
      </para>
      <para>
        On the other hand, if you want to install RPMs built on an RPM
        3.x system onto an RPM 4.x system, you may need to deal with
        package signatures. RPM 4.x versions also automatically check
        for signatures. When installing packages on an RPM 4.x system,
        you can disable this feature with the --nosignature option.
      </para>
      <para>
        Using these techniques, you should be able to install packages
        built with RPM 4.1 on systems that use RPM 3.x versions or vice
        versa.
      </para>
    </sect2>
    <sect2>
      <title>Dealing with divisions of software into packages</title>
      <para>
        There is no standardization as to how large applications are
        divided into packages on different Linux distributions. This
        means that dependencies between packages may differ.
      </para>
      <para>
        If your dependencies are for packages provided with the Linux
        distribution, which includes a huge number of packages, you must
        address this issue. The package an RPM depends on may not exist
        and may not even be needed, on a particular Linux distribution.
      </para>
      <para>
        If instead the dependencies are for files, especially shared
        libraries, you should be okay for the most part, unless the
        files are located in different directories.
      </para>
      <para>
        The only real solution to this problem is to turn off dependency
        checks on installing, with the --nodeps option. Then you must
        check manually that your system really does provide all the
        necessary dependencies. Use the techniques shown in <xref linkend="ch-dependencies"/>  to
        verify all the dependencies are met on your system.
      </para>
      <para>
        Warning
      </para>
      <para>
        Using the --nodeps option can lead to problems with your RPM
        database, because you are installing packages by defeating the
        RPM system's safeguards for dependencies. Only use the --nodeps
        option if you are really sure the dependencies are met on your
        system, even if from a different package than expected.
      </para>
    </sect2>
    <sect2>
      <title>Dealing with dependency issues</title>
      <para>
        One of the toughest areas to deal with is the problem of
        dependencies. This topic ranges from the very simple issue of
        installing a necessary package to complex issues of shared
        library versions or particular Perl modules.
      </para>
      <para>
        Start with the simple case and make certain that you haven’t
        failed to install a necessary RPM that provides the right
        dependency. In most cases, you can download a vendor-specific
        package from your Linux vendor, such as www.suse.com for SUSE
        Linux. Most Linux vendors provide HTTP or FTP sites with a large
        set of packages created for their distributions. If such a
        distribution-specific package solves a dependency issue, this is
        the easiest way around the problem.
      </para>
      <para>
        After you verify that you haven't simply omitted a necessary
        package, move on to other potential explanations. Another issue
        involves shared libraries and ELF, or Extended Linking Format,
        symbols. A package may require an older or newer version of a
        shared library. Applications that are tied to a particular
        version of a shared library can cause problems, since you may
        not want to install incompatible versions of a shared library.
      </para>
      <para>
        If the dependency is for a system-shared library, such as the
        shared C library, you can often recompile the package (rebuild
        from a source RPM) to get the package to use the newer or older
        version of the system library. This is possible because most
        Linux applications don’t call on version-specific features of
        system shared libraries (some do, but most don’t). If the
        dependency is for an application-shared library, this is more
        serious, since there were likely API changes that could impact
        the application. Install the package owning the
        application-shared library and again, try to rebuild the package
        from the source RPM.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        You can use the rpm -qf command to query which package owns a
        given file. You can use the rpm -q --whatprovides command to
        query for which package provides a given capability. <xref linkend="ch-dependencies"/> 
        covers more on dependencies.
      </para>
      <para>
        Some packages are considered developer packages. These usually
        depend on some base package. For example, the rpm-devel package
        depends on the rpm package. The rpm-python package depends on
        both the rpm package and the python package (at particular
        version numbers as well).
      </para>
      <para>
        This naming scheme of a base package and base-devel is used for
        &RHL; packages, but may not be used for other vendor
        packages. In any case, you can solve this type of dependency by
        finding the relevant base packages that the package you are
        trying to install depends on. Consult the manuals that come with
        your Linux distribution or browse the online RPM repositories to
        see what naming conventions are used for your Linux
        distribution.
      </para>
      <para>
        Many packages depend on scripting language interpreters, such as
        Perl. Sometimes the dependency is based on scripts used in a
        package, such as install or trigger scripts. You can have
        problems arise with the locations of these scripting
        interpreters. Perl, for example, is usually installed in
        /usr/bin/perl on most Linux systems. Another common location is
        /usr/local/bin/perl. In addition, packages may depend on
        particular add-on modules, especially Perl modules. With most
        versions of Linux released in the last few years, you should be
        able to override a Perl dependency with the --nodeps option as
        long as you have Perl installed.
      </para>
      <para>
        File paths may also cause problems. For example, a file that a
        package depends on may be in a different location or owned by a
        different package. For this case, you can try to find the
        package that owns the file and make sure that package is
        installed. If your Linux vendor provides a pre-built RPM
        database of all packages, such as the rpmdb-redhat package, you
        can query this database to find out which package owns the file
        for that version of Linux.
      </para>
      <para/>
    </sect2>
    <sect2>
      <title>Dealing with install locations</title>
      <para>
        Linux vendors can install software anywhere. For example, some
        distributions place a lot of software under /opt instead of the
        more common /usr. From an RPM perspective, this is mostly an
        issue with file dependencies and the install location for
        packages. Evolving file system standards also help limit this
        issue.
      </para>
      <para>
        You can attempt to relocate any package using the --badreloc
        option.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-using-rpm"/>  covers the --badreloc option.
      </para>
      <para>
        But, while the --badreloc option will relocate the files in a
        package, it will not modify the contents of those files. So, any
        file inside a package that references files and directory
        locations may not work properly, since it may have the old,
        invalid, paths.
      </para>
      <para>
        The only real way around this problem is to edit any script
        files that come with the package and contain hard-coded paths.
        If the paths reside inside binary executables, you need to get a
        source RPM for the package, patch the sources and then create a
        new RPM.
      </para>
    </sect2>
    <sect2>
      <title>When all else fails, rebuild from the source package</title>
      <para>
        When all of these techniques fail to install a package, you
        still have a fallback option. If you have the source RPM for a
        package, you can install the source RPM on the new system and
        then edit the spec file until you can rebuild a package that
        will install on your version of Linux.
      </para>
      <para>
        For example, a set of Build Root Policy (brp) helper scripts are
        run at the end of the %install section in an RPM. These scripts
        perform tasks such as compressing man pages. The Mandrake brp
        scripts use bzip2 compression. &RH; brp scripts use gzip
        compression. This is one case where rebuilding an RPM and then
        installing may work best.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Handling Problems Building RPMs</title>
    <para>
      Given all these differences, how can you create RPMs while
      avoiding problems? With some work setting things up, you can
      create an RPM build environment that solves most vendor issues.
      This depends on taking a methodical approach to building your
      packages and using techniques to avoid vendor issues wherever
      possible.
    </para>
    <para>
      When building RPMs, you will face many of the same problems@@mdand
      solutions@@mdas when installing RPMs. For example, due to the
      different ways Linux vendors divide software into packages, your
      RPMs will likely have issues defining the proper dependencies.
      There are also a number of issues that apply only when building
      RPMs.
    </para>
    <para>
      The following sections cover the main issues when building RPMs.
    </para>
    <sect2>
      <title>Writing distribution-specific packages</title>
      <para>
        One of the ways around all the differences between Linux
        distributions in RPM usage is to define distribution-specific
        packages. To do this, you create a separate package on each
        Linux distribution you support.
      </para>
      <para>
        That’s a lot of work. If possible, fit the differences into
        macros and use a single spec file to reduce some of this work.
        This technique works up to a point. Sometimes, your spec file
        becomes too complicated and you may decide that it is easier to
        create multiple spec files, one per Linux distribution.
      </para>
      <para>
        One way to help make vendor-specific packages, or to see which
        RPM macros are defined on a given Linux distribution, is to look
        for an RPM that contains the distribution-specific RPM
        configuration. For example, on &RHL; systems, the Red
        Hat RPM configuration is defined by the redhat-rpm-config
        package.
      </para>
      <para>
        You can list the files in this package to see where &RH;
        defines macros specific to their Linux distribution.
      </para>
      <para>
        $ rpm -ql redhat-rpm-config
      </para>
      <para>
        /usr/lib/rpm/redhat
      </para>
      <para>
        /usr/lib/rpm/redhat/brp-compress
      </para>
      <para>
        /usr/lib/rpm/redhat/brp-redhat
      </para>
      <para>
        /usr/lib/rpm/redhat/brp-sparc64-linux
      </para>
      <para>
        /usr/lib/rpm/redhat/brp-strip
      </para>
      <para>
        /usr/lib/rpm/redhat/brp-strip-comment-note
      </para>
      <para>
        /usr/lib/rpm/redhat/brp-strip-shared
      </para>
      <para>
        /usr/lib/rpm/redhat/find-lang.sh
      </para>
      <para>
        /usr/lib/rpm/redhat/find-provides
      </para>
      <para>
        /usr/lib/rpm/redhat/find-requires
      </para>
      <para>
        /usr/lib/rpm/redhat/macros
      </para>
      <para>
        /usr/lib/rpm/redhat/perl.prov
      </para>
      <para>
        /usr/lib/rpm/redhat/perl.req
      </para>
      <para>
        /usr/lib/rpm/redhat/rpmrc
      </para>
      <para>
        These files, such as /usr/lib/rpm/redhat/macros, show you what
        is specific to a given Linux distribution. You can then look at
        the macros defined in these files to identify settings for a
        particular distribution, in this case, &RH;. Armed with this
        knowledge, you can better create portable RPM spec files.
      </para>
    </sect2>
    <sect2>
      <title>Dealing with automatic dependency generation</title>
      <para>
        One of the features in RPM 4.x is the automatic generation of
        dependencies. For a variety of reasons including different
        package layouts, different directory structures, or different
        versions of RPM, you may need to disable some or all of
        automatic generation of dependencies.
      </para>
      <para>
        You can disable the automatic generation of dependencies by
        placing the following directive in your spec file:
      </para>
      <para>
        Autoreq: 0
      </para>
      <para>
        If you do so, you need to use the Requires: tag to manually
        define all requirements. This is not a good solution to the
        issue of automatic dependencies however. Most likely, you will
        need to override the %{__find_requires} and %{__find_provides}
        macros in order to filter out any unwanted dependencies.
      </para>
      <para>
        These two macros resolve to shell scripts that perform the
        automated dependency checks, as you can see with the rpm --eval
        command:
      </para>
      <para>
        $ rpm --eval "%__find_provides"
      </para>
      <para>
        /usr/lib/rpm/find-provides
      </para>
      <para>
        rpm --eval "%__find_requires"
      </para>
      <para>
        /usr/lib/rpm/find-requires
      </para>
      <para>
        You can override these scripts to filter out any dependencies
        that cause problems for your packages.
      </para>
    </sect2>
    <sect2>
      <title>Dealing with different macros</title>
      <para>
        Different Linux vendors define different macros in their RPM
        setup. This may mean not only different values for the macros,
        but different macro names as well. Because of this, it is best
        to define your own local set of macros when building RPMs.
      </para>
      <para>
        As much as possible, depend on your own RPM macros. You can
        define your macros in terms of vendor-specific macros using
        conditional statements in your spec files, a topic covered in
        <xref linkend="ch-advanced-packaging"/> . You can also read examples in the “Build
        Environment and Macros” section of this chapter.
      </para>
      <para>
        This really boils down to creating a disciplined RPM build
        environment.
      </para>
    </sect2>
    <sect2>
      <title>Making relocatable packages</title>
      <para>
        You should aim to make your packages relocatable so that users
        can install your packages into any directory. This makes it
        easier to deal with the locations chosen by different Linux
        distributions, such as /usr, /usr/local, or /opt, for installing
        add-on software.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-specfiles"/>  covers the spec file format. <xref linkend="ch-advanced-packaging"/>  covers making
        relocatable packages.
      </para>
      <para>
        You can use the %{_bindir} macro in your spec files, which will
        help create per-distribution packages using the right settings.
      </para>
      <para>
        In addition, you can define macros in your spec files that
        define the location for dependencies. You can then use the
        --define option to the rpmbuild command to define values for
        your macros that specify the locations for the dependencies.
      </para>
      <para>
        Note
      </para>
      <para>
        This technique of setting up Linux distribution-specific macros
        can help solve a lot of problems with cross-platform RPMs.
      </para>
    </sect2>
    <sect2>
      <title>Creating an RPM build environment</title>
      <para>
        If you start with the idea that you want to build RPMs for
        multiple versions of Linux, you can set up an RPM build
        environment that cleanly separates most vendor-specific issues.
      </para>
      <para>
        The key issues with the build environment are:
      </para>
      <para>
        *Detecting the vendors
      </para>
      <para>
        *Using macros to define a clean build process
      </para>
      <para>
        *Handling different dependencies
      </para>
      <sect3>
        <title>Detecting Vendors</title>
        <para>
          To make a clean build environment, you need to be able to
          detect the Linux vendor and make build settings based on this
          vendor. To help with this, many Linux vendors install a
          special file with the vendor name, or a special package with
          the vendor name. You can query for either of these.
        </para>
        <para>
          For files, the convention follows:
        </para>
        <para>
          /etc/vendor-release
        </para>
        <para>
          For example:
        </para>
        <para>
          $ more /etc/redhat-release
        </para>
        <para>
          &RHL; release 8.0 (Psyche)
        </para>
        <para>
          For packages, the convention is vendor-release for a package
          name. For example:
        </para>
        <para>
          $ rpm -q redhat-release
        </para>
        <para>
          redhat-release-8.0-8
        </para>
        <para>
          You can use either approach or simply define a macro for the
          vendor and use the --define option to set the macro. For
          example:
        </para>
        <para>
          # rpmbuild –ba --define 'linuxVendor suse'
        </para>
        <para>
          With this definition, you can use the macro %linuxVendor
          inside your spec files. It is generally easier, though, if
          your scripts can automatically detect the Linux vendor instead
          of having to define it manually. The manual approach works,
          though, if it becomes too much effort to detect the vendor
          automatically.
        </para>
      </sect3>
      <sect3>
        <title>Build environment and macros</title>
        <para>
          Once you can detect the Linux vendor, you can create macros
          based on the differences between Linux distributions that
          affect your applications.
        </para>
        <para>
          Cross Reference
        </para>
        <para>
          <xref linkend="ch-customizing-rpm"/>  covers RPM macros.
        </para>
        <para>
          The macros that specifically help you with platform
          differences include the %if .. %endif conditional. You can use
          this in combination with special macros you define. In
          addition, command-line options such as --with, --without, and
          --target allow you to control features and the build target
          within an RPM.
        </para>
        <para>
          The %if macro allows you to specify a condition within your
          spec file. For example:
        </para>
        <para>
          %if %{old_5x} && %{old_6x}
        </para>
        <para>
          %{error: You cannot build for .5x and .6x at the same time}
        </para>
        <para>
          %quit
        </para>
        <para>
          %endif
        </para>
        <para/>
        <para>
          %if %{old_5x}
        </para>
        <para>
          %define b5x 1
        </para>
        <para>
          %undefine b6x
        </para>
        <para>
          %endif
        </para>
        <para/>
        <para>
          %if %{old_6x}
        </para>
        <para>
          %define b6x 1
        </para>
        <para>
          %undefine b5x
        </para>
        <para>
          %endif
        </para>
        <para>
          You can also use %if to control settings such as the
          Requires:, as shown in the following example:
        </para>
        <para>
          %if %{build6x}
        </para>
        <para>
          Requires: util-linux, pam >= 0.66-5
        </para>
        <para>
          %else
        </para>
        <para>
          Requires: util-linux, pam >= 0.75-37,
          /etc/pam.d/system-auth
        </para>
        <para>
          %endif
        </para>
        <para/>
        <para>
          The --with command-line option defines a special macro
          starting with _with_. For example, the following command-line
          option defines a feature to use:
        </para>
        <para>
          $ rpmbuild –bc --with ssh filename.spec
        </para>
        <para>
          This example defines the macro _with_ssh to --with-ssh. This
          format was specially designed to work with GNU configure. You
          can use this for conditional builds for platform-dependent
          issues.
        </para>
        <para>
          The --without command-line option similarly defines a macro
          starting with _without_. The convention is that this option
          defines a feature the code should not use.
        </para>
        <para>
          You can combine --with and --without to turn on and off
          features referenced in your spec files. For example:
        </para>
        <para>
          ./configure %{?_with_ssh}
        </para>
        <para>
          This will pass the following command line if the _with_ssh
          macro is defined:
        </para>
        <para>
          ./configure --with-ssh
        </para>
        <para>
          If this option is not defined, the command will be:
        </para>
        <para>
          ./configure
        </para>
        <para>
          The --target option sets the spec file macros %_target,
          %_target_arch, and %_target_os . For example:
        </para>
        <para>
          $ rpmbuild -bc --target ppc-ibm-aix
          /usr/src/redhat/SPECS/jikes.spec
        </para>
      </sect3>
      <sect3>
        <title>Compatibility and Glue Packages</title>
        <para>
          Not all Linux distributions are the same. Macros alone won’t
          provide work-arounds for all the differences. You can, though,
          get a lot of mileage from compatibility and glue packages.
        </para>
        <para>
          A compatibility package provides a legacy API on newer systems
          that no longer support the legacy API. By convention,
          compatibility packages are named with a leading compat- to
          signify their purpose.
        </para>
        <para>
          For example:
        </para>
        <para>
          $ rpm -q --qf "%{description}" compat-libstdc++
        </para>
        <para>
          The compat-libstdc++ package contains compatibility Standard
          C++
        </para>
        <para>
          Using a compatibility package allows you to create programs
          that use a least-common-denominator approach, programming to
          the oldest but most common APIs. As some Linux distributions
          eliminate the old APIs, compatibility packages can provide the
          missing APIs.
        </para>
        <para>
          Similarly, a glue package provides a dependency that exists on
          some Linux distributions but not others. It glues together
          your package with the Linux distribution that is missing an
          essential capability.
        </para>
        <para>
          Note
        </para>
        <para>
          A key point in both of these approaches is to separate the
          compatibility and glue packages from your main application
          packages. The application packages should be as clean of
          vendor issues as possible. Instruct your users to install the
          compatibility or glue packages as needed (based on their Linux
          distribution) along with the main application package or
          packages.
        </para>
        <para>
          With all this discussion of RPM and Linux differences, you
          might think that Linux is one big mess. That’s not true.
          Linux maintains a high degree of compatibility among Linux
          distributions as well as among processor architectures. Most
          programs originally created for Linux on Intel-based
          architectures compile cleanly on Linux versions running on
          other processor architectures such as MIPS, SPARC, and ARM.
        </para>
        <para>
          The main differences lie in how Linux vendors split up the
          huge number of files associated with Linux into RPM packages
          as well as which versions of tools like C compilers the
          vendors ship.
        </para>
      </sect3>
      <sect3>
        <title>Dealing with Signatures</title>
        <para>
          With SUSE Linux, or any Linux based on UnitedLinux 1.0, the
          RPM packages are signed with OpenPGP version 4, not 3, as used
          in RPM 4.1. This means that you must use some other, non-RPM
          means to extract the signatures from an RPM package, and then
          verify these signatures with gpg.
        </para>
        <para/>
      </sect3>
    </sect2>
  </sect1>
  <sect1>
    <title>Dealing with Non-RPM-Based Linux Versions</title>
    <para>
      The main Linux distributions that don’t support RPM are the
      Debian GNU/Linux family and Slackware Linux. To help with these
      distributions, you can use a package-conversion tool called alien.
    </para>
    <sect2>
      <title/>
    </sect2>
    <sect2>
      <title>Handling non-RPM packages with alien</title>
      <para>
        Alien is a package that supports conversions between RPM and
        so-called alien package formats such as the dpkg (Debian
        GNU/Linux), slp (Stampede Linux), and tgz (Slackware Linux)
        formats.
      </para>
      <para>
        You can use alien on your RPM-based Linux system to convert RPMs
        to some other format, such as the Debian dpkg. You can also use
        alien to convert other package formats into RPMs, depending on
        which way you need to go.
      </para>
      <para/>
      <para/>
    </sect2>
  </sect1>
  <sect1>
    <title>Standardizing RPMs</title>
    <para>
      RPM is being considered as part of the Linux Standard Base, or
      LSB, 1.3. This will define a standard packaging format for Linux
      distributions, and over time reduce the RPM differences between
      distributions.
    </para>
    <para>
      In addition, other efforts are underway to help unify the diverse
      Linux distributions, including the Filesystem Hierarchy Standard
      and the adoption of RPM by many Linux vendors.
    </para>
    <sect2>
      <title>Filesystem Hierarchy Standard</title>
      <para>
        The FHS, or Filesystem Hierarchy Standard, defines the purpose
        of all the upper-level directories on Linux systems, such as
        /var and /usr/bin. This standard, along with the Linux Standard
        Base, or LSB, is driving Linux distributions to a greater degree
        of similarity.
      </para>
      <para>
        The FHS helps by specifying where applications should get
        installed and which directories should be left to local
        administrators to manage. The FHS also defines the purpose of
        all Linux directories, giving vendors and application writers a
        better idea of where they should install their packages.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        See www.linuxbase.org for more on the LSB. See
        www.pathname.com/fhs/ for more on the FHS.
      </para>
    </sect2>
    <sect2>
      <title>RPM adoption</title>
      <para>
        RPM has been adopted by a large number of Linux distributions.
        In addition, standardization efforts, both for RPM and for
        filesystem locations, are making Linux systems less varied.
      </para>
      <para>
        This means that over time, many of the RPM-related differences
        between Linux distributions will fade away, making it easier to
        create cross-platform RPMs.
      </para>
      <para/>
      <para/>
    </sect2>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      This chapter covers differences in RPM versions between various
      Linux distributions, and techniques you can use to get around
      these differences. Each Linux vendor packages software
      differently, even if the vendor uses RPM. This can cause problems
      unless you write your spec files carefully.
    </para>
    <para>
      Inside your RPM spec files, you can use conditional elements as
      well as platform-based macro definitions to help create RPMs for
      multiple packages.
    </para>
    <para>
      Some of the best conventions are to split the software in your
      applications from any compatibility or glue packages, separate
      packages that provide missing features for various flavors of
      Linux.
    </para>
    <para>
      Standardization efforts such as the Linux Standard Base and
      Filesystem Hierarchy Standard are bringing Linux vendors closer
      and closer together. Widespread adoption of RPM by most Linux
      distributions also helps.
    </para>
    <para>
      While this chapter covers RPM on other Linux distributions, the
      next chapter tackles RPM outside of Linux.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-other-os.xml ---
<!-- $Id: -->

<chapter id="ch-other-os">
  <title>RPM on Other Operating Systems</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Running RPM on other operating systems
      </para>
    </listitem>
    <listitem>
      <para>
        Bootstrapping RPM on other operating systems
      </para>
    </listitem>
    <listitem>
      <para>
        Setting up the RPM environment
      </para>
    </listitem>
    <listitem>
      <para>
        Creating non-Linux RPMs
      </para>
    </listitem>
    <listitem>
      <para>
        Setting up an RPM build environment
      </para>
    </listitem>
    <listitem>
      <para>
        Cross-building packages
      </para>
    </listitem>
  </itemizedlist>
  <para>
    RPM was originally designed on Linux and for most of its life has
    been a Linux-centric package management system. But most Linux
    programs are portable to most versions of Unix or Unix -like
    operating systems. Linux is, after all, a Unix-workalike operating
    system.
  </para>
  <para>
    The RPM system is no exception. It has been ported to a number of
    operating systems, including quite a few Unix variants. The source
    code is freely available, so you can port RPM to other systems as
    well.
  </para>
  <para>
    This chapter covers running RPM on non-Linux operating systems,
    including getting the RPM system in the first place, bootstrapping
    an RPM environment, and creating packages for other operating
    systems.
  </para>
  <para>
    The first step is to get RPM for your system, or port RPM if it
    isn’t already available.
  </para>
  <sect1>
    <title>Running RPM on Other Operating Systems</title>
    <para>
      The RPM system, made up of mostly the rpm and rpmbuild commands,
      have been ported to a number of operating systems. There is
      nothing stopping you from running the RPM system on other
      platforms.
    </para>
    <para>
      Other operating systems have their own native package management
      software. You may prefer the way RPM works, or merely want to
      standardize on RPM across all platforms you manage. There will
      always be a few issues, however, when running RPM on other
      operating systems. For example, operating system patches and
      updates are likely to be distributed in the operating system’s
      native package management format, not RPM. Many applications will
      be updated also using the system’s native package management
      format.
    </para>
    <para>
      You will need to always keep in mind that there are two package
      management schemes in use: RPM and the native one. This issue has
      not stopped a great many people from using RPM on other systems,
      though, as shown by the list of platforms RPM has been ported to
      (see Table 20-1 for the list).
    </para>
    <para>
      On the plus side, package management has always been one of the
      main areas where versions of Linux, Unix, and other operating
      systems differ, sometimes quite a lot. By using RPM, you can
      transfer your knowledge of package management from one system to
      another, saving valuable time and hassles. You will be able to
      update systems in the same manner, a big plus if you manage a
      diverse set of systems.
    </para>
    <para>
      Another reason to use RPM on other operating systems is that in
      most cases, RPM provides far more capabilities than the native
      package management software. Following the RPM philosophy, each
      package can be separately verified, checked, and updated. Each
      package lists the other packages it depends on, and also lists the
      capabilities it provides. You can automate the installation and
      upgrade processes with RPM. You can also perform a lot of version
      and signature comparisons. All of this leads to a more secure,
      more robust system.
    </para>
    <para>
      Many operating systems don’t include these capabilities in the
      native package management software. This is why many users run RPM
      on other operating systems.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      See <xref linkend="ch-intro-rpm"/>  for more on the philosophy behind RPM.
    </para>
    <para>
      If you decide to use RPM on a non-Linux system, the first step is
      getting RPM for your system, if it is available.
    </para>
    <sect2>
      <title>Getting RPM for your system</title>
      <para>
        The first step to using RPM on non-Linux platforms is getting
        the RPM system for your platform. In most cases, this is a
        relatively easy step, as RPM has been ported to a great many
        platforms, as listed on the main RPM Web site.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        Links to RPM versions for various platforms are listed at
        www.rpm.org/platforms/.
      </para>
      <para>
        Go to this site and download the versions for the platforms you
        need. Table 20-1 lists the platforms RPM has been ported to, as
        reported by the RPM site.
      </para>
      <para>
        Table 20-1 Available Platforms for RPM
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  Platform
                </para>
              </entry>
              <entry>
                <para>
                  Notes
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  AIX
                </para>
              </entry>
              <entry>
                <para/>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  AmigaOS
                </para>
              </entry>
              <entry>
                <para>
                  With GeekGadgets
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  BeOS
                </para>
              </entry>
              <entry>
                <para>
                  With GeekGadgets
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  FreeBSD
                </para>
              </entry>
              <entry>
                <para/>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  HP-UX
                </para>
              </entry>
              <entry>
                <para>
                  10.20+, 9.04
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  IRIX
                </para>
              </entry>
              <entry>
                <para/>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Linux
                </para>
              </entry>
              <entry>
                <para>
                  Multiple platforms including Alpha, Intel, Motorola
                  68000, SGI MIPS, PowerPC, and SPARC
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  LynxOS
                </para>
              </entry>
              <entry>
                <para/>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  MachTen
                </para>
              </entry>
              <entry>
                <para/>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  MacOS X
                </para>
              </entry>
              <entry>
                <para/>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Mint
                </para>
              </entry>
              <entry>
                <para/>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  NCS System V
                </para>
              </entry>
              <entry>
                <para/>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  NetBSD
                </para>
              </entry>
              <entry>
                <para/>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  OS/2
                </para>
              </entry>
              <entry>
                <para/>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  OSF/1
                </para>
              </entry>
              <entry>
                <para>
                  3.2+
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  SCO OpenServer
                </para>
              </entry>
              <entry>
                <para>
                  5.0.2+
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Sinix
                </para>
              </entry>
              <entry>
                <para/>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Solaris
                </para>
              </entry>
              <entry>
                <para>
                  Solaris for SPARC 2.4 and 8+, Solaris for Intel
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  SunOS 4.1.3
                </para>
              </entry>
              <entry>
                <para/>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Windows
                </para>
              </entry>
              <entry>
                <para>
                  Under Cygwin
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
      <para>
        Note that RPM has likely been ported to even more platforms.
        These are just the ones reported to the rpm.org site.
      </para>
      <para>
        Note
      </para>
      <para>
        If you fix a bug in RPM on a non-Linux system, or if you port
        RPM to a new system, please report this to the rpm.org site
        maintainers, as well as make your work available for others. You
        never know, but someone else may fix a problem you’re facing.
      </para>
      <para>
        If Table 20-1 does not cover the platforms you need, you must
        compile and bootstrap the RPM environment for your platforms, as
        covered in the "Bootstrapping RPM on Other Operating Systems"
        section, following.
      </para>
      <para>
        Note
      </para>
      <para>
        Don’t expect to find RPMs of the RPM system for these other
        platforms. If you did, there would be no way to install RPM.
        Instead, you’ll find RPM packaged in a variety of formats,
        typically using a native bundling format for a given system, or
        at least a supported format. Compressed tar files are very
        common. RPM for IRIX systems come in IRIX tardist format.
      </para>
      <para>
        If RPM is available for your system, download the package and
        follow any installation instructions that come with the package.
        For example, RPM for Solaris 8 requires the libiconv library, as
        well as the Solaris packages SUNWzlib and SUNWbzip. You must
        install these packages prior to installing RPM.
      </para>
      <para>
        Each operating system will have similar requirements. Windows
        systems have a few extra requirements due to the fact that
        Windows is very different from Linux or Unix-like systems.
      </para>
    </sect2>
    <sect2>
      <title>Running RPM on Windows</title>
      <para>
        The version of RPM for Windows requires cygwin, originally the
        Cygnus port of many Unix tools to Windows. Now part of &RH;,
        you can download the cygwin environment from the main cygwin
        site.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        Download cygwin from www.cygwin.com.
      </para>
      <para>
        You can download a setup.exe program to install the environment
        on Windows. After installation, you can download the RPM system
        for Windows.
      </para>
      <para>
        After you have RPM installed, you can set up your RPM system. If
        RPM wasn’t already ported to your operating systems, however,
        you will need to bootstrap RPM on your platforms.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Bootstrapping RPM On Other Operating Systems</title>
    <para>
      If you cannot find a version of RPM that has been ported to your
      platform, you can port it yourself. The RPM system usually isn’t
      that hard to port to any platform that can appear like Unix or
      Linux systems, such as any platform that supports POSIX system
      calls or something like these system calls.
    </para>
    <para>
      Don’t be dismayed by the sheer size of the RPM package. Much of
      the RPM system was carefully designed to run across multiple
      platforms, so file access is abstracted to special portability
      routines. For example, RPM has been ported to both AmigaOS and
      BeOS, two non-Unix operating systems.
    </para>
    <sect2>
      <title>Downloading the RPM software</title>
      <para>
        To bootstrap RPM on another operating system, download the RPM
        source code from the main RPM site.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        You can download the RPM source code from
        ftp://ftp.rpm.org/pub/rpm/dist/.
      </para>
      <para>
        Note that you probably do not want to download an RPM of the
        sources, since your platform won’t have RPM available. In most
        cases, you’ll want to download a tarred compressed archive,
        such as rpm-4.1.tar.gz for RPM version 4.1.
      </para>
    </sect2>
    <sect2>
      <title>Extracting the software</title>
      <para>
        If the system you plan to port RPM doesn’t have the tar and
        gzip commands available, or something that supports these
        formats, then you need to find a way to extract the software.
      </para>
      <para>
        Note
      </para>
      <para>
        Programs such as WinZip on Windows support extracting .tar.gz
        files. Your platform may have a similar program.
      </para>
      <para>
        One way is to port the gzip and tar commands to your platform.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        You can download the sources for tar and gzip from www.gnu.org.
      </para>
      <para>
        Another way is to extract the sources on a platform with these
        commands available, such as a Linux platform. Then, create a
        file using a format supported by your operating system and
        transfer the files to the other system.
      </para>
      <para>
        Once you have the RPM source code available on your target
        system, and all the files are extracted, you are ready to start
        porting. The first step is really simple: read.
      </para>
    </sect2>
    <sect2>
      <title>Reading the INSTALL file</title>
      <para>
        In the main RPM source directory, you will see two very
        important files: README and INSTALL. Read them both. (You would
        be surprised at how many times people need to be told this.)
      </para>
      <para>
        Of the two, the INSTALL file has much more detailed information
        on installing RPM on a new system. The INSTALL file describes
        the libraries required by RPM, provides tips on compiling RPM,
        and describes some of the set up work necessary after compiling
        the RPM system.
      </para>
      <para>
        Some of the hardest parts of the RPM system to port, though, may
        be in the database, compression, and encryption calls, used as
        libraries by the RPM system.
      </para>
    </sect2>
    <sect2>
      <title>Libraries required by RPM</title>
      <para>
        Rather than invent everything from scratch, the RPM system makes
        use of a number of libraries, including those listed in Table
        20-2.
      </para>
      <para>
        Table 20-2 Libraries used by RPM
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  Library
                </para>
              </entry>
              <entry>
                <para>
                  Purpose
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Berkeley DB
                </para>
              </entry>
              <entry>
                <para>
                  RPM database, using db1 and db3
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  bzip2
                </para>
              </entry>
              <entry>
                <para>
                  Compression
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  gettext
                </para>
              </entry>
              <entry>
                <para>
                  International text lookup
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  gpg
                </para>
              </entry>
              <entry>
                <para>
                  For digital signatures
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  gzip
                </para>
              </entry>
              <entry>
                <para>
                  Compression
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  popt
                </para>
              </entry>
              <entry>
                <para>
                  Processing command-line options
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  zlib
                </para>
              </entry>
              <entry>
                <para>
                  Compression
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
      <para>
        Read through the INSTALL file to find out where you can download
        versions of these libraries. You may find that each library has
        its own set of dependencies, all of which you need to port to
        your target platform.
      </para>
    </sect2>
    <sect2>
      <title>Tools for building RPM</title>
      <para>
        In addition to the libraries listed in Table 20-2, RPM requires
        a number of GNU utilities for building RPM, including those
        listed in Table 20-3.
      </para>
      <para>
        Table 20-3 Tools used to build RPM
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  Tool
                </para>
              </entry>
              <entry>
                <para>
                  Usage
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Autoconf
                </para>
              </entry>
              <entry>
                <para>
                  Builds configure scripts
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Automake
                </para>
              </entry>
              <entry>
                <para>
                  Used with autoconf
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  GNU make
                </para>
              </entry>
              <entry>
                <para>
                  Used to control building the sources
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Libtool
                </para>
              </entry>
              <entry>
                <para>
                  Used by the autogen.sh script
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
      <para>
        In addition to all this, RPM works best with the GNU C compiler,
        GCC, and the GNU make program, gnumake, or simply gmake.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        The source code for all the GNU tools is available at
        www.gnu.org.
      </para>
    </sect2>
    <sect2>
      <title>Compiling RPM</title>
      <para>
        After downloading the RPM sources, extracting all the files and
        installing all the prerequisite libraries, you are ready to
        start compiling RPM.
      </para>
      <para>
        RPM includes quite a few subsystems, such as popt for parsing
        command-line options. Each of these subsystems requires some
        configuration. Most of this configuration is automated through
        the use of the autogen.sh script and the autoconf/automake tool
        used to create configure scripts.
      </para>
      <para>
        The autogen.sh script is a Bourne shell script that checks for
        specific versions of necessary tools and libraries. After
        checking dependencies, the autogen.sh script calls different
        autogen.sh scripts in the beecrypt, libelf, popt, and zlib
        directories. When done with that task, the autogen.sh script
        calls configure.
      </para>
      <para>
        Pass a command-line option of --noconfigure to disable the call
        to configure.
      </para>
      <para>
        Edit the autogen.sh script if you are using different versions
        of the necessary tools. The autogen.sh script is coded to
        require the specific versions of these tools as were used
        originally to build the RPM package. In addition, your system
        may have libraries stored in different locations than those
        expected by the autogen.sh, so it's a good idea to edit this
        script and verify all the assumptions.
      </para>
      <para>
        Note
      </para>
      <para>
        One really big assumption in this script is that you have a
        Unix-like operating system. If not, you will need to determine
        how to set up the Makefiles manually. This requires a lot of
        trial and error while you edit the Makefiles and then see if you
        can build the software. Fix each problem that arises and try
        again.
      </para>
      <para>
        When you are done with the autogen.sh script, you can use the
        following basic commands to create system-specific Makefiles,
        compile RPM and install the commands:
      </para>
      <para>
        $ ./configure
      </para>
      <para>
        $ make
      </para>
      <para>
        $ make install
      </para>
      <para>
        The configure script takes the Makefile.in files and uses these
        files as templates to create custom versions of Makefile.in
        files, tuned to your system. (The automake system starts with a
        Makefile.am file, creates an expanded Makefile.in file, and
        finally results in a Makefile tuned to your system.) If all else
        fails, you can copy each Makefile.in file to Makefile and then
        edit the Makefile to make one that will work on your system.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        See the GNU site, at www.gnu.org, for more on the autoconf and
        automake tools.
      </para>
      <para>
        If the make install step fails, you can manually copy the RPM
        executables and scripts to a directory for system commands.
      </para>
    </sect2>
    <sect2>
      <title>Handling problems</title>
      <para>
        If RPM fails to compile or install, you can still work around
        many issues. The key is to find out what went wrong, fix the
        problem, and try again. You may go through this loop many times
        before RPM successfully compiles and installs.
      </para>
      <para>
        Most problems can be solved by changing the configuration
        settings. If possible, change the inputs to the configure
        command to specify C compiler options, and so on, that you
        discover you need. You can then run the basic commands to build
        RPM again, but with any special options you discovered are
        necessary:
      </para>
      <para>
        $ ./configure –any_options_set_here
      </para>
      <para>
        $ make
      </para>
      <para>
        $ make install
      </para>
      <para>
        If you take this approach, you avoid having to edit a number of
        Makefiles (one in each source code subdirectory) by hand. You
        also have an easier time of switching to different command-line
        options as you determine more solutions to the compilation
        problems.
      </para>
      <para>
        If this won’t work, though, you can edit the Makefile.am file
        or the generated Makefile directly to add whatever settings are
        needed. For example, you may need to specify additional
        directories for libraries, or some C compiler compatibility
        option.
      </para>
      <para>
        As you discover problems, remember you are not alone in porting
        RPM. Check the RPM mailing list, where the question of getting
        RPM going on other platforms comes up frequently.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        For details on viewing the RPM mailing list archives and signing
        up for the list, see www.rpm.org/mailing_list/.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Setting Up the RPM System</title>
    <para>
      Once you have RPM available on your platform, you need to set up
      the RPM system. This includes setting up the RPM database and
      creating an RPM environment.
    </para>
    <sect2>
      <title>Setting up the RPM database</title>
      <para>
        After you have the RPM system available on your platform, you
        need to set up the RPM database. This usually involves two
        steps:
      </para>
      <para>
        *Initializing an empty RPM database
      </para>
      <para>
        *Populating the database with packages, especially for
        dependencies
      </para>
      <para>
        Both steps are necessary.
      </para>
      <sect3>
        <title>Initializing an Empty RPM Database</title>
        <para>
          After you have the RPM system installed on your platform, the
          next big step is to create an RPM database for your platform.
          You can make an empty database with the rpm --initdb command,
          as shown following:
        </para>
        <para>
          # mkdir /var/lib/rpm
        </para>
        <para>
          # rpm --initdb
        </para>
        <para>
          The first command creates the default directory for the RPM
          database.
        </para>
        <para>
          You may need to pass command-line options to specify a
          non-default location of the RPM database, such as the
          following:
        </para>
        <para>
          # rpm --dbpath /location/of/your/rpm/database --initdb
        </para>
        <para>
          Use a command like this one if you don’t want to place the
          RPM database in its default location.
        </para>
        <para>
          In addition, use the –v option to add more verbose output.
          This is very useful if errors occur. Use the --root option to
          specify a different root directory for RPM operations. Use the
          --rcfile option to specify a non-default set of rc files and
          the --macros option to specify a non-default set of macros.
        </para>
        <para>
          Cross Reference
        </para>
        <para>
          <xref linkend="ch-customizing-rpm"/>  covers RPM customization.
        </para>
        <para>
          Initializing the RPM database creates the necessary structure
          for an empty database. You can then fill, or populate, the
          database with packages. In most cases, all you need to do is
          install packages to populate the RPM database, as each
          installed package gets added to the database.
        </para>
      </sect3>
      <sect3>
        <title>Handling Dependencies for Packages Installed Without RPM</title>
        <para>
          Each time you install a package, you populate the RPM
          database. This works well, as long as you have already
          installed all the dependencies for the packages you want to
          install.
        </para>
        <para>
          On an operating system that is based on RPM, such as &RH;
          Linux, all packages (except for some bootstrapping code) are
          installed with RPM. That means nearly everything on the system
          is defined in the RPM database. The RPM database then has a
          full knowledge of what you have installed and can properly
          handle dependencies. Thus, a failure to find a dependency
          means that you have not installed the requisite package that
          provides the needed capability.
        </para>
        <para>
          On an operating system that is not based on RPM, however, such
          as Solaris or IRIX, most packages have already been installed
          by some means other than RPM.. That’s because these
          operating systems use different native package-management
          techniques and different package formats.
        </para>
        <para>
          It is very likely that RPM packages you want to install have
          dependencies that come from non-RPM packages. For example, the
          rpm program on Windows depends on the cygwin environment, yet
          this environment needs to be installed with a Windows
          setup.exe program, not with the rpm command.
        </para>
        <para>
          To get around this problem, you need to populate the new RPM
          database with a package or packages that reflect the current
          system in order to properly handle dependencies. The main way
          to do this is to set up a virtual package.
        </para>
      </sect3>
      <sect3>
        <title>Setting Up A Virtual Package</title>
        <para>
          You can get around the problem of pre-existing software by
          building a virtual package that lists the system
          libraries at mdinstalled without RPM at mdin an RPM package. This
          way, the rpm command will find that the dependencies are
          installed, even if they were not really installed with RPM.
          You need to do this for all capabilities and system libraries
          installed outside of RPM control.
        </para>
        <para>
          To help create such a virtual package, use the
          vpkg-provides.sh script from the scripts directory. The
          vpkg-provides.sh script searches a list of directories for
          shared libraries and interpreters (such as shells). The
          vpkg-provides.sh script then creates a spec file that lists
          all the files found, files that are managed outside of RPM.
          You can use this spec file to create an RPM and install the
          RPM using the rpm command to populate the RPM database.
        </para>
        <para>
          The RPM spec file created by the vpkg-provides.sh doesn’t
          really install any files, as all the files are already
          installed. Instead it makes a package that claims ownership
          for all these files so that RPM dependencies can function
          properly.
        </para>
        <para>
          The vpkg-provides.sh script accepts three main command-line
          options: --spec_header, --ignore_dirs, and --no_verify.
        </para>
        <para>
          The --spec_header option tells the script the name of the RPM
          spec file it should use as a header for the spec file it will
          produce. You need to provide the path to the file. For
          example:
        </para>
        <para>
          # sh vpkg-provides.sh --spec_header /path/to/spec/file
        </para>
        <para>
          You need to provide a spec file header to make a complete spec
          file. This header should contain the Summary, Name, Version,
          and Release settings, at least. <xref linkend="ch-specfiles"/>  covers these spec
          file tags.
        </para>
        <para>
          The --ignore_dirs option tells the vpkg-provides.sh script to
          ignore certain directories. You need to pass a list of egrep
          search patterns that identify the directories to ignore.
          Separate each pattern with a pipe character, |.
        </para>
        <para>
          Note
        </para>
        <para>
          The egrep command may not be available on your system. It may
          be easier to edit the vpkg-provides.sh script and manually
          specify the directories to ignore.
        </para>
        <para>
          The --no_verify option tells the vpkg-provides.sh script to
          skip the step of creating a script to verify checksums of all
          files in the package.
        </para>
        <para>
          In addition to these main command-line options, you can also
          pass the following options to the vpkg-provides.sh script.
        </para>
        <para>
          The --shlib_dirs option tells the vpkg-provides.sh script the
          directories to look for shared libraries. Pass a
          colon-delimited list of directories. For example:
        </para>
        <para>
          # sh vpkg-provides.sh --spec_header /path/to/spec/file \
        </para>
        <para>
          --shlib_dirs "/bin:/usr/bin:/sbin:/usr/sbin:/usr/ucb:/usr/bsd"
        </para>
        <para>
          The --interp_dirs option tells the vpkg-provides.sh script
          which directories to look in to find interpreters such as sh,
          bash, perl, wish (Tcl/Tk), and awk. The --interps option tells
          the vpkg-provides.sh script the names of the interpreter
          commands. Both these options expect a colon-delimited list.
        </para>
        <para>
          The --find_provides option tells the vpkg-provides.sh script
          the name of the find-provides script to use, defaulting to
          /usr/lib/rpm/find-provides.
        </para>
        <para>
          The vpkg-provides.sh script defines specific directories to
          look in for shared libraries and interpreters under various
          operating systems. You will most likely need to edit this
          section.
        </para>
        <para>
          In fact, if you are working with a non-Unix system, or if you
          experience problems running the vpkg-provides.sh script, you
          can edit the file to remove the problematic commands. You can
          also create a new script in a scripting language supported on
          your system. The vpkg-provides.sh script is a Linux shell
          script. Linux and Unix systems should be able to run the
          script, but non-Unix systems likely won’t have the commands
          and may also not support shell scripts at all. In an effort to
          be generic, the vpkg-provides.sh script does a lot of work.
          You can limit this by explicitly specifying directories and
          commands, for example. And, if all else fails, you can create
          a virtual package manually (covered in the following section).
        </para>
        <para>
          When complete, the vpkg-provides.sh script outputs a spec
          file, using the header you provided, and outputs a set of
          Provides: lines to specify what the package provides. It then
          outputs some empty definitions for the prep, build, install,
          and clean sections of the spec file.
        </para>
        <para>
          For example, you can run the vpkg-provides.sh script with a
          command like the following:
        </para>
        <para>
          $ sh ./vpkg-provides.sh --spec_header my_header.spec
          --find_provides ./find-provides --no_verify
        </para>
        <para>
          Note
        </para>
        <para>
          If you run this script as a non-root user, you may get a
          number of permission errors as the vpkg-provides.sh script
          searches through system directories.
        </para>
        <para>
          The script will then output your spec file header along with
          output like that shown in Listing 20-1.
        </para>
        <para>
          Listing 20-1: Output from the vpkg-provides.sh script
        </para>
        <para>
          Provides: /bin/sh
        </para>
        <para>
          Provides: /bin/csh
        </para>
        <para>
          Provides: /bin/ksh
        </para>
        <para>
          Provides: /bin/perl
        </para>
        <para>
          Provides: /bin/awk
        </para>
        <para>
          Provides: /bin/nawk
        </para>
        <para>
          Provides: /bin/oawk
        </para>
        <para>
          Provides: /usr/bin/sh
        </para>
        <para>
          Provides: /usr/bin/csh
        </para>
        <para>
          Provides: /usr/bin/ksh
        </para>
        <para>
          Provides: /usr/bin/perl
        </para>
        <para>
          Provides: /usr/bin/awk
        </para>
        <para>
          Provides: /usr/bin/nawk
        </para>
        <para>
          Provides: /usr/bin/oawk
        </para>
        <para>
          Provides: /sbin/sh
        </para>
        <para>
          Provides: /usr/dt/bin/dtksh
        </para>
        <para>
          Provides: /usr/xpg4/bin/sh
        </para>
        <para>
          Provides: /usr/xpg4/bin/awk
        </para>
        <para>
          %prep
        </para>
        <para>
          # nothing to do
        </para>
        <para>
          %build
        </para>
        <para>
          # nothing to do
        </para>
        <para>
          %install
        </para>
        <para>
          # nothing to do
        </para>
        <para>
          %clean
        </para>
        <para>
          # nothing to do
        </para>
        <para>
          %files
        </para>
        <para>
          # no files in a virtual package
        </para>
        <para>
          The vpkg-provides.sh script also outputs a package description
          that explains how the package was created. This is important
          so that you know this is a virtual package.
        </para>
        <para>
          When done, use the rpmbuild command to create an RPM from the
          generated spec file.
        </para>
        <para>
          Cross Reference
        </para>
        <para>
          <xref linkend="ch-creating-rpms"/> covers how to run the rpmbuild command, and <xref linkend="ch-specfiles"/> covers spec files in detail.
        </para>
      </sect3>
      <sect3>
        <title>Creating a Virtual Package Manually</title>
        <para>
          Even on Unix-like systems you may experience troubles with the
          vpkg-provides.sh script. That’s simply because the
          vpkg-provides.sh script assumes a number of Unix and GNU
          utilities are available. In most cases, it will work best if
          you can fix what went wrong and run the vpkg-provides.sh
          script again.
        </para>
        <para>
          If all else fails, though, you can create a virtual package
          spec file manually. Create a spec file starting with the
          Summary, Name, Version, and Release settings.
        </para>
        <para>
          Looking at the output shown in Listing 20-1, you can create a
          Provides: statement for each shared library on your system,
          and each interpreter, such as shells. Add each statement to
          your spec file. For example:
        </para>
        <para>
          Provides: libgen.so
        </para>
        <para>
          Copy the prep, build, install, and clean sections exactly as
          they are in Listing 20-1. You can now run the rpmbuild command
          to create a virtual package. Install this package.
        </para>
      </sect3>
    </sect2>
    <sect2>
      <title>Creating the RPM environment</title>
      <para>
        The RPM environment is made up of a large number of RPM settings
        and macro definitions. Run the rpm --showrc command to see the
        current environment settings on Linux:
      </para>
      <para>
        $ rpm –showrc
      </para>
      <para>
        ARCHITECTURE AND OS:
      </para>
      <para>
        build arch : i386
      </para>
      <para>
        compatible build archs: i686 i586 i486 i386 noarch
      </para>
      <para>
        build os : Linux
      </para>
      <para>
        compatible build os's : Linux
      </para>
      <para>
        install arch : i686
      </para>
      <para>
        install os : Linux
      </para>
      <para>
        compatible archs : i686 i586 i486 i386 noarch
      </para>
      <para>
        compatible os's : Linux
      </para>
      <para/>
      <para>
        RPMRC VALUES:
      </para>
      <para>
        macrofiles :
        /usr/lib/rpm/macros:/usr/lib/rpm/i686-linux/macros:/etc/
      </para>
      <para>
        rpm/macros.specspo:/etc/rpm/macros.db1:/etc/rpm/macros.cdb:/etc/rpm/macros:/etc/
      </para>
      <para>
        rpm/i686-linux/macros:~/.rpmmacros
      </para>
      <para>
        optflags : -O2 -march=i686
      </para>
      <para>
        This output was truncated for space. As you can see, there are a
        lot of expected settings. You need to set up these same settings
        and macros, but with the proper values for the new system on
        which you are running RPM.
      </para>
      <para>
        The files rpmrc.in and macros.in serve as the default templates
        used to create the rc and macro settings, respectively. These
        files are modified by the configure script to include values
        specific to the local operating system. You can edit these files
        as needed for your system, prior to installing RPM. That is,
        edit these files between calling the make command and the make
        install command.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-customizing-rpm"/>  covers how to customize the RPM settings and macros,
        along with the popt aliases.
      </para>
      <para>
        The INSTALL file in the RPM sources also describes some
        modifications you may want to make to the macros.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Creating Non-Linux RPMS</title>
    <para>
      Once you have RPM set up on a system, you should be able to create
      RPMs using the rpmbuild command on that system.
    </para>
    <para>
      Warning
    </para>
    <para>
      Do not build RPM packages logged in as a root or Administrator
      user. If something goes wrong, rpmbuild could destroy files in
      your system. Remember that spec files can define a number of
      commands and shell scripts. Any of these could have an error that
      could cause major damage when run as a root user.
    </para>
    <para>
      Before building RPMs with the rpmbuild command, though, you may
      want to customize the build environment to better reflect your
      system. You may also find it is too difficult to build most RPMs
      on the non-Linux system and instead focus on cross-building
      packages, should the rpmbuild command not work on the target
      systems.
    </para>
    <para>
      This section covers topics related to building RPMs on or for
      non-Linux systems.
    </para>
    <sect2>
      <title>Setting up a build environment</title>
      <para>
        In RPM terms, your build environment consists of the directories
        where you build RPMs, as well as the rc and macro settings that
        define all of the variables in an RPM-based system. To set up
        your build environment, you need to ensure that all the rc and
        macro settings reflect the true environment on your non-Linux
        system.
      </para>
      <para>
        The rpm --showrc command, discussed previously in the "Creating
        the RPM Environment" section, lists the settings for your
        system. You can use this command to verify all the settings.
      </para>
      <para>
        You may want to change some settings, such as the top directory
        where RPMs are built. By default, this setting is something like
        the following:
      </para>
      <para>
        _topdir %{_usrsrc}/redhat
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        See <xref linkend="ch-customizing-rpm"/>  for more on how to customize the rc and macro
        settings.
      </para>
      <para>
        In most cases the _topdir setting on &RHL; systems map
        to the /usr/src/redhat directory. Your system may not even have
        a /usr/src directory. Also you may not want to build RPMs in a
        redhat directory, which may cause confusion if you are building
        on a non-&RHL; system.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        See <xref linkend="ch-other-linuxes"/>  for more information on setting up a build
        environment for RPMs. <xref linkend="ch-other-linuxes"/>  focuses on other Linux systems,
        but many of the same techniques apply.
      </para>
      <para>
        With a build environment set up, you should be able to create
        RPMs with the rpmbuild command. If this doesn’t work, or is
        too difficult, then you can try cross-building packages.
      </para>
    </sect2>
    <sect2>
      <title>Cross-building packages</title>
      <para>
        You may find that it is too difficult to create RPMs on a given
        platform. It may be easier to build the RPMs on another
        platform, such as a Linux system, as if it were on the target
        platform. This is called cross-building packages, since you are
        building a package on one system specifically designed for
        another.
      </para>
      <para>
        In most cases, the target platform is quite different from the
        system where you cross-build packages. Otherwise, you would
        likely just build the RPMs on the target platform.
      </para>
      <para>
        The key issues with cross-building are the following:
      </para>
      <para>
        *You must compile any executables with a cross compiler for the
        proper target platform.
      </para>
      <para>
        *You must set the target platform in the RPMs you build.
      </para>
      <para>
        *You must manage dependencies, and likely need to turn off the
        automatic generation of dependencies.
      </para>
      <para>
        Note
      </para>
      <para>
        Setting up a cross-building environment is oftentimes more work
        than it is worth. If you can compile applications and build
        packages on the target system, do that. The cross-building
        option should be used only if you really cannot build packages
        on the target system. For example, many handheld or small-format
        computers lack the processor performance or memory to compile
        applications. These are good candidates for cross-building.
      </para>
      <para>
        To compile executables for another platform, especially a
        platform with a different processor architecture, you need a
        cross compiler. A cross compiler runs on one system and produces
        executables for another.
      </para>
      <para>
        Note
      </para>
      <para>
        Cross compilers are heavily used when working with embedded and
        small device systems. The embedded system may not have the
        processor power to compile applications, or it may simply be
        inconvenient to compile applications on the embedded system.
      </para>
      <para>
        The Linux gcc compiler can act as a cross compiler if you
        install the right gcc add-on packages. See the GNU site for more
        on the gcc compiler.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        You can download GCC and other GNU software from www.gnu.org.
      </para>
      <para>
        In addition to compiling for the target platform, you need to
        ensure that the RPM is marked as being for the target
        architecture. If not, the rpm command will fail when trying to
        install the RPM on the target system.
      </para>
      <para>
        You can set the target architecture with the --target option to
        the rpmbuild command. For example:
      </para>
      <para>
        rpmbuild –bi --target arm-sharp-linux
      </para>
      <para>
        This specifies a target CPU architecture of ARM, the vendor
        Sharp (which just happens to make an ARM-based Linux device) and
        the operating system of Linux. The basic format is:
      </para>
      <para>
        cpu-vendor-os
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        See <xref linkend="ch-rpmbuild"/>  for more on using the --target option to the
        rpmbuild command.
      </para>
      <para>
        You must also turn off or correct any automatically generated
        dependencies in RPMs you build for other platforms. That is, any
        dependencies based on the operating system or architecture of
        the system you are cross-building on will likely not be found,
        or be found in a different location or format, on the target
        platform.
      </para>
      <para>
        This is where the handy RPM feature of automatically building
        the dependencies does not work to your advantage. You can turn
        off this feature, however.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        See <xref linkend="ch-other-linuxes"/>  for information on how to turn off the automatic
        generation of dependencies.
      </para>
      <para>
        You should turn off the automatically building of dependencies
        for any packages you cross build.
      </para>
      <para>
        Using these techniques, you can build packages on one system for
        use on another, very different system. Due to the difficulties,
        you should only go this route if it becomes too difficult to use
        the rpmbuild command on the target systems.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      With its superior package-management capabilities, especially for
      automated installations and upgrades, you may want to use RPM on
      non-Linux platforms. As the experience of many developers has
      shown, you can indeed use RPM on non-Linux platforms.
    </para>
    <para>
      The rpm.org site maintains a listing of operating systems where
      developers have ported RPM. If you are lucky, you can download RPM
      for your operating system and start working right away. If you are
      not lucky, you will need to port RPM to your target system.
    </para>
    <para>
      If RPM has been ported to your architecture, download the package
      and follow the installation instructions. If RPM has not been
      ported to your architecture, download the RPM sources and all
      prerequisite libraries. You may need to port each library to your
      architecture before you can even begin to port RPM.
    </para>
    <para>
      The RPM sources use a configured build process that also requires
      some prerequisite tools. You need to get or port these to your
      architecture as well. Whew.
    </para>
    <para>
      Once everything is in place, you can start the port of RPM. In
      many cases, you just need to figure out how to get RPM to compile
      and everything will fall into place. In other cases, you will need
      to work on each RPM subsystem to get it to build and run.
    </para>
    <para>
      After you have RPM for your system, you need to initialize the RPM
      database with the rpm --initdb command. You can then start to
      populate your RPM database. Because a large number of libraries
      have already been installed on your system, you may need to create
      a virtual package that claims to provide these files. Installing
      such a virtual package will allow you to install other RPMs that
      may be dependent on system libraries.
    </para>
    <para>
      Much of porting RPM to another platform depends on the RPM
      environment and how you need to customize that environment. The
      next chapter shows how to customize your RPM environment, on Linux
      or on other operating systems.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-package-structure.xml ---
<!-- $Id: -->

<chapter id="ch-package-structure">
  <title>RPM Package File Structure</title>
  <para>
    This appendix covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        RPM package file structure
      </para>
    </listitem>
    <listitem>
      <para>
        RPM header entry formats
      </para>
    </listitem>
    <listitem>
      <para>
        Payload format
      </para>
    </listitem>
  </itemizedlist>
  <para>
    This appendix describes the format of RPM package files. You can
    combine this information with C, Perl, or Python data structures to
    access the information. In all cases, you should access elements in
    an RPM file using one of the available programming libraries. Do not
    attempt to access the files directly, as you may inadvertently
    damage the RPM file.
  </para>
  <para>
    Cross Reference
  </para>
  <para>
    <xref linkend="ch-programming-c"/>, <xref linkend="ch-rpm-programming-python"/>, and <xref linkend="ch-programming-perl"/> cover programming with C, Python, and Perl, respectively.
  </para>
  <para>
    The RPM package format described here has been standardized as part
    of the Linux Standards Base, or LSB, version 1.3.
  </para>
  <para>
    Cross Reference
  </para>
  <para>
    The LSB 1.3 section on package file formats is available at
    www.linuxbase.org/spec/refspecs/LSB_1.3.0/gLSB/gLSB.html#PACKAGEFMT.
  </para>
  <sect1>
    <title>The Package File</title>
    <para>
      RPM packages are delivered with one file per package. All RPM
      files have the following basic format of four sections:
    </para>
    <para>
      *A lead or file identifier
    </para>
    <para>
      *A signature
    </para>
    <para>
      *Header information
    </para>
    <para>
      *Archive of the payload, the files to install
    </para>
    <para>
      All values are encoded in network byte order, for portability to
      multiple processor architectures.
    </para>
    <sect2>
      <title>The file identifier</title>
      <para>
        Also called the lead or the rpmlead, the identifier marks that
        this file is an RPM file. It contains a magic number that the
        file command uses to detect RPM files. It also contains version
        and architecture information.
      </para>
      <para>
        The start of the identifier is the so-called magic number. The
        file command reads the first few bytes of a file and compares
        the values found with the contents of /usr/share/magic
        (/etc/magic on many UNIX systems), a database of magic numbers.
        This allows the file command to quickly identify files.
      </para>
      <para>
        The identifier includes the RPM version number, that is, the
        version of the RPM file format used for the package. The
        identifier also has a flag that tells the type of the RPM file,
        whether the file contains a binary or source package. An
        architecture flag allows RPM software to double-check that you
        are not trying to install a package for a non-compatible
        architecture.
      </para>
    </sect2>
    <sect2>
      <title>The signature</title>
      <para>
        The signature appears after the lead or identifier section. The
        RPM signature helps verify the integrity of the package, and
        optionally the authenticity.
      </para>
      <para>
        The signature works by performing a mathematical function on the
        header and archive section of the file. The mathematical
        function can be an encryption process, such as PGP (Pretty Good
        Privacy), or a message digest in MD5 format.
      </para>
    </sect2>
    <sect2>
      <title>The header</title>
      <para>
        The identifier section no longer contains enough information to
        describe modern RPMs. Furthermore, the identifier section is
        nowhere near as flexible as today’s packages require. To
        counter these deficiencies, the header section was introduced to
        include more information about the package.
      </para>
      <para>
        The header structure contains three parts:
      </para>
      <para>
        *Header record
      </para>
      <para>
        *One or more header index record structures
      </para>
      <para>
        *Data for the index record structures
      </para>
      <para>
        The header record identifies this as the RPM header. It also
        contains a count of the number of index records and the size of
        the index record data.
      </para>
      <para>
        Each index record uses a structure that contains a tag number
        for the data it contains. This includes tag IDs for the
        copyright message, name of the package, version number, and so
        on. A type number identifies the type of the item. An offset
        indicates where in the data section the data for this header
        item begins. A count indicates how many items of the given type
        are in this header entry. You can multiply the count by the size
        of the type to get the number of bytes used for the header
        entry.
      </para>
      <para>
        Table D-1 lists the type identifiers.
      </para>
      <para>
        Table D-1 Header type identifiers
      </para>
      <informaltable frame="all">
        <tgroup cols="3">
          <tbody>
            <row>
              <entry>
                <para>
                  Constant
                </para>
              </entry>
              <entry>
                <para>
                  Value
                </para>
              </entry>
              <entry>
                <para>
                  Size in Bytes
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  RPM_NULL_TYPE
                </para>
              </entry>
              <entry>
                <para>
                  0
                </para>
              </entry>
              <entry>
                <para>
                  No size
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  RPM_CHAR_TYPE
                </para>
              </entry>
              <entry>
                <para>
                  1
[...2164 lines suppressed...]
                  </para>
                </entry>
                <entry>
                  <para>
                    The package conforms to the Linux Standards Base RPM
                    format.
                  </para>
                </entry>
              </row>
              <row>
                <entry>
                  <para>
                    rpmlib(VersionedDependencies)
                  </para>
                </entry>
                <entry>
                  <para>
                    3.0.3-1
                  </para>
                </entry>
                <entry>
                  <para>
                    The package holds dependencies or prerequisites that
                    have versions associated with them.
                  </para>
                </entry>
              </row>
              <row>
                <entry>
                  <para>
                    rpmlib(PayloadFilesHavePrefix)
                  </para>
                </entry>
                <entry>
                  <para>
                    4.0-1
                  </para>
                </entry>
                <entry>
                  <para>
                    File names in the archive have a “.” prepended
                    on the names.
                  </para>
                </entry>
              </row>
              <row>
                <entry>
                  <para>
                    rpmlib(CompressedFileNames)
                  </para>
                </entry>
                <entry>
                  <para>
                    3.0.4-1
                  </para>
                </entry>
                <entry>
                  <para>
                    The package uses the RPMTAG_DIRINDEXES,
                    RPMTAG_DIRNAME and RPMTAG_BASENAMES tags for
                    specifying file names.
                  </para>
                </entry>
              </row>
              <row>
                <entry>
                  <para>
                    /bin/sh
                  </para>
                </entry>
                <entry>
                  <para>
                    NA
                  </para>
                </entry>
                <entry>
                  <para>
                    Indicates a requirement for the Bourne shell to run
                    the installation scripts.
                  </para>
                </entry>
              </row>
            </tbody>
          </tgroup>
        </informaltable>
      </sect3>
    </sect2>
    <sect2>
      <title>The payload</title>
      <para>
        The payload, or archive, section contains the actual files used
        in the package. These are the files that the rpm command
        installs when you install the package. To save space, data in
        the archive section is compressed in GNU gzip format.
      </para>
      <para>
        Once uncompressed, the data is in cpio format, which is how the
        rpm2cpio command can do its work. In cpio format, the payload is
        made up of records, one per file. Table D-10 lists the record
        structure.
      </para>
      <para>
        Table D-10 cpio file record structure
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  Element
                </para>
              </entry>
              <entry>
                <para>
                  Holds
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  cpio header
                </para>
              </entry>
              <entry>
                <para>
                  Information on the file, such as the file mode
                  (permissions)
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  File name
                </para>
              </entry>
              <entry>
                <para>
                  NULL-terminated string
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Padding
                </para>
              </entry>
              <entry>
                <para>
                  0 to 3 bytes, as needed, to align the next element on
                  a 4-byte boundary
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  File data
                </para>
              </entry>
              <entry>
                <para>
                  The contents of the file
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  Padding
                </para>
              </entry>
              <entry>
                <para>
                  0 to 3 bytes, as needed, to align the next file record
                  on a 4-byte boundary
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
      <para>
        The information in the cpio header duplicates that of the RPM
        file-information header elements.
      </para>
    </sect2>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-packaging-guidelines.xml ---
<!-- $Id: -->

<chapter id="ch-packaging-guidelines">
  <title>Packaging Guidelines</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Avoiding common mistakes
      </para>
    </listitem>
    <listitem>
      <para>
        Following good practices
      </para>
    </listitem>
  </itemizedlist>
  <para>
    RPM is a complex system that helps manage thousands of packages for
    a complex operating system. Furthermore, RPM is very, very flexible.
    This flexibility makes it important that you follow the rules to
    create packages the proper way. Otherwise, you’ll face a host of
    problems with your RPMs. Following some best practices guidelines
    will help you avoid future problems as you release RPM updates.
  </para>
  <para>
    This chapter covers ways to avoid common problems as well as
    best-practice guidelines for creating your own RPMs.
  </para>
  <sect1>
    <title>Avoiding Common Problems</title>
    <para>
      Developers creating RPMs seem to hit many of the same roadblocks.
      This section covers some of the most common problems faced by RPM
      users and package builders.
    </para>
    <para>
      Warning
    </para>
    <para>
      Never, never, never build RPMs logged in as the root user. See the
      section on Building for details.
    </para>
    <sect2>
      <title>Scan the mailing lists</title>
      <para>
        Many people have tried to solve a lot of serious problems that
        arise when using RPM, so if you are facing difficulties, chances
        are someone else has tackled those issues before. The RPM
        mailing list provides a technical forum for discussing RPM
        issues and problems. In many, if not most, cases, you can find
        answers to problems by scanning the mailing list archives.
      </para>
      <para>
        You can also sign up for the mailing list so that you can send
        in requests and see the responses.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        For details on viewing the RPM mailing list archives and signing
        up for the list, see www.rpm.org/mailing_list/. See
        <ulink url="http://groups.yahoo.com/group/rpm-list/messages">http://groups.yahoo.com/group/rpm-list/messages</ulink>
        for an archive of the list.
      </para>
      <para>
        If you are working with RPMs and pushing the envelope for other
        operating systems or complicated packages, this list is
        definitely worth a look.
      </para>
      <para>
        Before sending any messages, though, be sure to look through the
        message archives to see if the message has already been
        answered. You will save time waiting for a response if you can
        get an archived response right away.
      </para>
      <para>
        You should also ask any questions in a way that will generate
        the most helpful responses. This includes:
      </para>
      <para>
        Do your homework first. Check to see if your question has
        already been answered by looking at the mailing list or
        newsgroup archives. In the end, this saves you the most time, as
        you don’t have to wait for answers.
      </para>
      <para>
        Describe the problem and the symptoms as clearly as possible.
        After all, this is what you want help with.
      </para>
      <para>
        Use clear subject headers. This is the first part of your
        message that people will read. If you are not clear, the key
        people who could answer your questions may never even read your
        message. And, if they don’t read the message, you will never
        get an answer.
      </para>
      <para>
        Send your message in plain text, not HTML. Do not include a
        separate HTML copy of your message. This just makes it harder to
        read, especially for people who read collected digests of
        mailing lists.
      </para>
      <para>
        Make it easy for people to reply to you. Include your email
        address in your message. You might want to include a line that
        states something like “Please send your reply to me at” and
        then provide your email address.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        These tips on asking questions come from the Internet document
        on How to Ask Questions the Smart Way by Eric Steven Raymond and
        Rick Moen, available at multiple sites, including
        www.owlriver.com/tips/smart.
      </para>
      <para>
        In addition to the RPM mailing list, there is also a Usenet
        newsgroup, named linux.redhat.rpm. You can read this newsgroup
        with any newsreading program.
      </para>
      <para>
        Note
      </para>
      <para>
        Newsgroups are sometimes called discussion groups.
      </para>
    </sect2>
    <sect2>
      <title>Use rpmbuild</title>
      <para>
        In older versions of RPM, you called the rpm –ba command to
        build RPMs. With RPM 4.1, you must use the rpmbuild command. If
        you have the rpmbuild command available, even if you are running
        an older version of RPM, run rpmbuild instead of rpm to build
        your RPMs.
      </para>
      <para>
        You’d be surprised at how such a simple item is one of the
        most-asked questions on the RPM mailing list. That’s because
        the rpm –ba command, and the other –b options, no longer
        work in RPM 4.1. These options are supported by the rpmbuild
        command.
      </para>
    </sect2>
    <sect2>
      <title>Don’t try to defeat the system</title>
      <para>
        If you are finding your spec files getting more and more
        complex, and that you are trying to disable RPM features,
        chances are you are trying to defeat the system. This is not a
        good idea.
      </para>
      <para>
        The RPM system works in a certain way. You may not always agree
        with the way it works, but if you try to make it work in
        contrary ways, in most cases you’ll end up fighting RPM to no
        avail.
      </para>
      <para>
        There are certain rules, and more importantly certain
        conventions that RPMs should follow. The previous chapters in
        this section on building RPMs have outlined those conventions.
        Follow them. When you go against these conventions, you are
        really trying to defeat how the RPM system works.
      </para>
    </sect2>
    <sect2>
      <title>Turn off automatic dependency generation</title>
      <para>
        When you build an RPM, the rpmbuild command will automatically
        generate dependencies on Linux shared libraries and other system
        commands. You can turn this off if you need to, using a number
        of means.
      </para>
      <para>
        You can disable the automatic generation of dependencies by
        placing the following directive in your spec file:
      </para>
      <para>
        Autoreq: 0
      </para>
      <para>
        A better approach, though, is to override the %{__find_requires}
        and %{__find_provides} macros, or just one of these as needed.
        You can null out either of these macros by adding commands like
        the following to your spec file:
      </para>
      <para>
        %define __find_requires %{nil}
      </para>
      <para>
        This approach is better because it allows you to override only
        the requires checks. In addition, you can get more specific and
        simply change how the automatic dependency checks are performed.
        For example, you can also change the definitions of these macros
        to perform normal dependency generation except for any
        problematic files or packages. These two macros resolve to shell
        scripts that perform the automated dependency checks, as you can
        see with the rpm --eval command:
      </para>
      <para>
        $ rpm --eval "%__find_provides"
      </para>
      <para>
        /usr/lib/rpm/find-provides
      </para>
      <para>
        rpm --eval "%__find_requires"
      </para>
      <para>
        /usr/lib/rpm/find-requires
      </para>
      <para>
        You can override these scripts to filter out any dependencies
        that cause problems for your packages.
      </para>
    </sect2>
    <sect2>
      <title>Don't list directories in %files</title>
      <para>
        Unless you really mean it, don’t list directories in your
        %files section in your spec files. That is because the rpmbuild
        program will automatically add all files in that directory to
        your RPM. If this is a system directory, such as /usr/bin, your
        RPM has now claimed ownership for all the files, regardless of
        the source package.
      </para>
      <para>
        To avoid all files in the directory becoming part of the
        package, list the files explicitly, perhaps generating the list
        of files as the program builds.
      </para>
      <para>
        If you do need a directory installed as part of your package,
        use the %dir directive, described in <xref linkend="ch-specfiles"/> .
      </para>
    </sect2>
    <sect2>
      <title>Handling circular dependencies</title>
      <para>
        If two packages each depend on the other, you don’t want each
        package’s spec file to list the other in a Requires section.
        If this occurs, the packages won’t install without one of the
        force options, since each package will require the other to be
        installed first.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-using-rpm"/>  covers how to install or upgrade packages while
        ignoring dependency checks. In general, you do not want to
        ignore these checks.
      </para>
      <para>
        You can work around this issue by using the PreReq directive
        instead of Requires. For example, if package A depends on B and
        package B depends on A, you can place the following in the
        package B spec file:
      </para>
      <para>
        PreReq: A
      </para>
      <para>
        In addition, you can install both packages at the same time to
        avoid some of the problems with circular dependencies. Simply
        include both packages on the rpm –Uvh command line.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Following Good Practices</title>
    <para>
      Working through problems is one thing. It’s best, however, to
      set up an environment to help avoid problems all together. The
      following sections cover what are considered the best practices
      for creating RPMs.
    </para>
    <para>
      Before you make an RPM, you should plan out what you intend to
      build and how it will be structured. As you build the RPM, you
      want to watch out for things that can go wrong, and work from a
      known clean environment.
    </para>
    <sect2>
      <title>Preparation</title>
      <para>
        Before you start to make an RPM, you need to follow a few steps
        to ensure you have everything ready.
      </para>
      <sect3>
        <title>Create a Source RPM</title>
        <para>
          Having a source RPM allows you to transfer all the sources for
          a package from one system to another, along with all the
          instructions coded in the spec file for actually building the
          binary package. This is very handy for keeping track of
          software, and it is also very important since you can
          regenerate the binary RPM at any time from the source RPM. In
          other words, make the generation of RPMs follow the RPM
          conventions and fit this into your normal software build
          process.
        </para>
        <para>
          This means that for each RPM you want to build, you really
          need two: a source and a binary RPM. This isn’t that hard to
          do, since you can easily make a source RPM into a binary RPM
          with the rpmbuild command.
        </para>
      </sect3>
      <sect3>
        <title>Start with Pristine Sources</title>
        <para>
          In addition to planning on making a source RPM, you should
          also start with pristine, unmodified sources for the
          application you plan to package as an RPM. Starting with
          pristine sources means you can reproduce the entire process
          and recreate the RPM from scratch if necessary. (Quality
          control and configuration management people really appreciate
          this.)
        </para>
        <para>
          The pristine sources should be exactly the sources you got
          when you downloaded the application, or acquired it in house.
          This doesn’t mean that you won’t have to modify the
          sources eventually. For that, you create patches. The key is
          just to start the process with unmodified sources.
        </para>
        <para>
          Some RPMs have nearly 100 patches that the rpmbuild command
          applies when building the RPM. That is a lot of patches, too
          many for most applications. Even so, the process is the same.
          Create a patch or patches for all the changes you need to
          make. You can easily specify patches in the spec file.
        </para>
        <para>
          Cross Reference
        </para>
        <para>
          <xref linkend="ch-specfiles"/>  covers the spec file.
        </para>
        <para>
          Keeping your patches separate from the original sources makes
          it easier to reproduce the RPM from scratch, and makes it
          easier to integrate a new version of the base software, since
          your code, in the form of patches, is separated from the base
          software code.
        </para>
      </sect3>
      <sect3>
        <title>Decide What Goes In Each Package</title>
        <para>
          You don’t have to stuff all your software into one RPM.
          Instead, you can often simplify your RPM by dividing it into
          two or three separate (but likely dependent) RPMs.
        </para>
        <para>
          For example, the RPM system itself has one RPM for the basic
          system, rpm, one for developers of the RPM system, rpm-devel,
          and one for those building RPMs, rpm-build. Yet another RPM
          provides the Python programming API, rpm-python.
        </para>
        <para>
          Cross Reference
        </para>
        <para>
          <xref linkend="ch-rpm-programming-python"/>  covers Python programming.
        </para>
        <para>
          This last division is important. The Python RPM draws in as a
          dependency the Python system itself. Adding this into, say,
          the core RPM package would needlessly complicate the
          dependencies for that package.
        </para>
        <para>
          When dividing your software into RPMs, keep two main issues in
          mind:
        </para>
        <para>
          *You want to divide the software into RPMs that fit the model
          for users of the system.
        </para>
        <para>
          *You want to divide the software into RPMs such that the
          separate RPMs are simpler to create and manage.
        </para>
        <para>
          The RPM system follows these guidelines, especially the first.
          Few users will extend the RPM system itself, which allows RPM
          team to shed this functionality from the core RPM and contain
          it in rpm-devel. Those who build RPMs fit into a different
          category than those who use RPMs since just about everybody
          needs to use RPMs to install packages, but few users actually
          build RPMs. Again, the separation works from a user’s
          perspective.
        </para>
        <para>
          You also want your package divisions to make each package
          easier to specify. You can break particularly tough
          dependencies into smaller units and simplify things. If the
          package division doesn’t simplify things, then it may not be
          a good idea.
        </para>
      </sect3>
      <sect3>
        <title>Create a Test RPM Database</title>
        <para>
          You don’t always have to work with the system RPM database.
          In fact, while developing RPMs, you probably don’t want to
          change the system database.
        </para>
        <para>
          If you have a test RPM database, you can install your RPMs
          into this test database. To do so, use the --justdb, --dbpath,
          --prefix, and --badreloc options. These options allow you to
          install an RPM into just the database, using a different
          database, with a different root file location (into a test
          directory, for example) and handle all files that were not
          marked for relocation, respectively.
        </para>
        <para>
          Note
        </para>
        <para>
          The --test option when installing also allows you to just test
          the install, not actually perform it.
        </para>
        <para>
          Combined, all these options mean you can use an RPM database
          just set up for testing and that problems won’t impact your
          working Linux systems. To make this work, though, you need a
          test RPM database.
        </para>
        <para>
          To be rigorous, you should create the test RPM database from
          scratch from a known set of packages. This will allow you to
          exactly verify the behavior of your RPM under different system
          configurations. This is the best choice since you should
          install the packages under a known, and non-root, directory
          hierarchy to avoid having file problems with the working
          system.
        </para>
        <para>
          If you want to cheat, you can copy your real RPM database to
          another directory and use that. Note that in this case, the
          file paths in the database will point to the real file
          locations on disk.
        </para>
        <para>
          Regardless of how you create a test database, recreate the
          database each time you run a test, so that you are sure of a
          known starting state. Usually this is as simple as copying a
          master test RPM database into a directory you use for running
          tests.
        </para>
      </sect3>
    </sect2>
    <sect2>
      <title>Building</title>
      <para>
        Building RPMs isn’t as easy as it should be. You’ll often
        need to try again and again to get the rpmbuild command to
        create a working RPM. This section covers best practices to
        follow when performing the actual build of the RPM.
      </para>
      <sect3>
        <title>Use Tools</title>
        <para>
          Using tools can help speed up the RPM-making process, as well
          as give you a head start in learning how RPMs work.
          RPM-building tools such as the &RH; plugin for the Eclipse
          Integrated Development Environment have proven really helpful.
        </para>
        <para>
          Cross Reference
        </para>
        <para>
          <xref linkend="ch-extra-packaging-tools"/>  covers RPM-building tools. <xref linkend="ch-development-tools"/>  covers the
          Eclipse Integrated Development Environment.
        </para>
        <para>
          Even though so-called real Linux hackers can make a working
          virtual memory system with just the cat command, don’t scoff
          at tools. Your time is too valuable.
        </para>
        <para>
          Another useful tool is the gendiff program that comes with the
          RPM release. The gendiff program makes it easier to create
          patches by avoiding the need to keep a separate directory of
          the original sources, The gendiff program also works on all
          changed files within a directory, making a patch for
          everything you modified.
        </para>
        <para>
          To work with gendiff, you need to first save a backup copy of
          each file you intend to edit prior to editing. Use a
          consistent file-name extension for the saved copies of the
          files, such as .orig, short for original. After you edit some
          files, run the gendiff command as follows:
        </para>
        <para>
          $ gendiff directory_name .saved_extension >
          patch_name.patch
        </para>
        <para>
          For example, if you saved the original files to a .orig
          extension, you can create a patch in a directory named src
          (short for sources) with a command like the following:
        </para>
        <para>
          $gendiff src .orig > mypatch.patch
        </para>
        <para>
          The patch file mypatch.patch will contain all the differences
          detected for all files in the given directory.
        </para>
      </sect3>
      <sect3>
        <title>Never Build RPMs as Root</title>
        <para>
          Never, never, never build RPMs logged in as the root user.
          Always build your RPMS while logged in as a normal user. This
          is hard to remember since you must be logged in as root to
          install an RPM. And you’ll want to test each RPM you create
          to see if it can install cleanly.
        </para>
        <para>
          Even so, never build RPMs logged in as the root user. The RPM
          spec file has a number of scripts and commands. An error in
          any of these could cause damage to your system. This includes
          modifying files, removing files, or copying new contents on
          top of system files. The root user has permission to perform
          all these operations.
        </para>
        <para>
          To avoid all this, build your RPMs while logged in as a normal
          user. Any problematic scripts should generate errors.
        </para>
      </sect3>
      <sect3>
        <title>Create a Digital Signature</title>
        <para>
          RPM 4.1 and later revisions place more importance on signing
          your packages. The rpm command will, by default, verify
          signatures on each package it reads.
        </para>
        <para>
          Therefore, you should create a digital signature for your
          packages, if only to meet user expectations. In addition, you
          should place a copy of your digital signature on your
          organization’s Web site and public key servers. Having
          multiple copies in multiple locations helps prevent malicious
          users from impersonating your keys.
        </para>
        <para>
          Cross Reference
        </para>
        <para>
          <xref linkend="ch-rpmbuild"/>  covers signing packages.
        </para>
      </sect3>
      <sect3>
        <title>Copy Smartly</title>
        <para>
          Your Linux distribution probably includes more than one CD-ROM
          chock full of RPMs. Each of these RPMs has a spec file. You
          can examine these spec files and see how others choose to
          build their RPMs. Rather than starting from scratch, you can
          copy declarations from these spec files into your spec file.
        </para>
        <para>
          Not all these packages were made smartly. Some spec files, as
          you will see, are a large mess. Obviously, don’t copy these.
          Look for clean spec files with clear directives.
        </para>
      </sect3>
      <sect3>
        <title>Set Up the BuildRoot</title>
        <para>
          A BuildRoot directive sets the location where your code will
          be built. The convention is for you to define a subdirectory
          beneath the _tmppath directory. For example:
        </para>
        <para>
          BuildRoot: %{_tmppath}/%{name}-buildroot
        </para>
        <para>
          Once set, rpmbuild defines the RPM_BUILD_ROOT environment
          variable to the value specified for the BuildRoot.
        </para>
        <para>
          With the rpmbuild command, you can use the --buildroot option
          to specify a directory to use to override the BuildRoot
          directive in the spec file.
        </para>
        <para>
          Using a BuildRoot set to a directory that normal users have
          write access to allows you to build the package logged in as a
          normal user. It also helps separate the contents of your
          package from those of other RPMs.
        </para>
        <para>
          Always define a BuildRoot.
        </para>
      </sect3>
      <sect3>
        <title>Add changelog entries for each new version</title>
        <para>
          Each time you create a new version in RPM format, you should
          add an entry to the change log. This allows administrators to
          get a better idea about what changed from the previous
          version.
        </para>
        <para>
          The change log can help people decide whether or not to
          upgrade a package. A log entry about a security fix, for
          example, provides useful information to users.
        </para>
      </sect3>
      <sect3>
        <title>Define the Group For Your Package</title>
        <para>
          Packages are categorized into groups. These group names, while
          not always the best, appear in the graphical tools such as the
          &RH; package manager. If your application is a Linux shell
          program, then users will expect to find it in the System
          Environment/Shells group and not the Development/Languages or
          System Environment/Daemons groups. This is a rather small
          detail, but it helps users find your package in the huge array
          of Linux RPMs.
        </para>
        <para>
          The official list of RPM groups is located in
          /usr/share/doc/rpm-4.1/GROUPS for RPM 4.1, and similarly-named
          directories for other RPM versions.
        </para>
      </sect3>
    </sect2>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      This chapter covers guidelines for avoiding problems when creating
      RPMs and following best practices to avoid future problems as
      well.
    </para>
    <para>
      When trying to avoid common problems, your best starting point is
      the RPM mailing list and newsgroup.
    </para>
    <para>
      For best practices, you should start at the very beginning when
      you are planning what to build into an RPM. Always start with
      pristine sources and then patch as needed. Your RPM should include
      the pristine sources and any necessary patches. You should always
      create a source RPM, so that you can reproduce your RPM anywhere.
    </para>
    <para>
      When building RPMs, copy good examples of spec files, as this will
      get you going far more quickly than any other technique. Use tools
      to help automate parts of your RPM-building process.
    </para>
    <para>
      Never build RPMs when logged in as the root user.
    </para>
    <para>
      This chapter ends the section on building RPMs. The next section
      covers programming to the RPM APIs.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-programming-c.xml ---
<!-- $Id: -->

<chapter id="ch-programming-c">
  <title>Programming RPM with C</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Using the RPM C library
      </para>
    </listitem>
    <listitem>
      <para>
        Setting up a development environment
      </para>
    </listitem>
    <listitem>
      <para>
        Programming with the RPM C library
      </para>
    </listitem>
    <listitem>
      <para>
        The power of <command>popt</command> for command-line argument
        processing
      </para>
    </listitem>
    <listitem>
      <para>
        Comparing package files to installed packages
      </para>
    </listitem>
  </itemizedlist>
  <para>
    The RPM C library allows you to perform all the operations of the
    rpm command from within your own C or C++ programs.
  </para>
  <para>
    The reason is simple: The rpm command was created using the RPM
    libraries. These same libraries are available for you to use in your
    own programs.
  </para>
  <para>
    The rpm command itself is quick and, for the most part, simple. So,
    why would you want to write RPM programs?
  </para>
  <para>
    There are many reasons, some of which are listed here:
  </para>
  <para>
    *Speed: If you need to perform a task on many RPM files such as
    verifying a large set of files, then performing the task from one
    program will be a lot faster than launching the rpm command for each
    file.
  </para>
  <para>
    *Custom options: If you need to do something the rpm command doesn't
    offer, or doesn't make easy, then you may want to write your own
    program.
  </para>
  <para>
    *Convenience: If you need to make many packages quickly, with custom
    options, your best bet may be to create a program suited for your
    tasks. Before doing this, though, be sure to look into whether
    writing a shell script will handle your task adequately. You'll find
    writing RPM shell scripts goes much faster than writing whole
    programs.
  </para>
  <para>
    *Installation programs: The Windows world has standardized on
    graphical installation programs such as InstallShield or
    InstallAnywhere. The RPM system, on the other hand, has focused on
    automated installation with the rpm command. You can combine the
    best of both worlds by writing a graphical installation program on
    top of the RPM system.
  </para>
  <para>
    *Integration with environments: You may want to better integrate RPM
    with a Linux desktop environment such as GNOME or KDE.
  </para>
  <para>
    *Working with other languages: This book covers programming RPM with
    C, the core language for the library, as well as the Python and Perl
    scripting languages. You can use the RPM library, though, to help
    bind with other languages such as Tcl, Ruby, or even C# (especially
    one of the C# implementations for Linux).
  </para>
  <para>
    This chapter and the next cover RPM programming. This chapter covers
    the RPM C programming library, which provides low-level access to
    RPM functionality. The next chapter covers the RPM Python
    programming library, which provides a much higher-level of
    abstraction. If you are attempting to write a complex RPM program,
    your best bet is to try the Python API first. Even so, there is a
    lot you can do with the RPM C library.
  </para>
  <sect1>
    <title>Programming with the C Library</title>
    <para>
      RPM C programs are C programs that call on functions in the RPM
      library, often called rpmlib. To use the rpmlib, you need to set
      up a C programming environment and install the rpm-devel package.
    </para>
    <sect2>
      <title>Setting Up a C Programming Environment</title>
      <para>
        At the very least, you’ll need a C compiler, gcc, and a text
        editor. The easiest way to get the C compiler is to install the
        packages grouped under Software Development with the &RH;
        package management tool.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        See <xref linkend="ch-management-software"/>  for more on the &RH; package management tool.
      </para>
      <para>
        The gcc package requires a number of capabilities. Make sure you
        install all the necessary packages. Just about every Linux
        distribution includes gcc and everything you need to develop C
        programs, so this should not be a problem.
      </para>
      <para>
        For text editors, you can use the vi or emacs text editors, or
        any of a number of graphical editors such as gedit.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-development-tools"/>  covers Linux text editors and development tools.
      </para>
      <para>
        Once you have a C programming environment set up, you next need
        to get the RPM library for an RPM development environment.
      </para>
    </sect2>
    <sect2>
      <title>Setting Up the RPM Programming Environment</title>
      <para>
        To program with the RPM library, you need to install the
        rpm-devel package. You must have a version of rpm-devel that
        matches your version of the rpm package. If you have &RH;
        Linux, your installation CDs will also have the version of the
        RPM development package that corresponds to your system.
      </para>
      <para>
        Your program should link against the same libraries that are
        used by the rpm command itself in order to insure compatibility,
        so make sure that the version of the rpm-devel package matches
        the rpm package itself. In most cases, the best bet is to use
        the RPM programs and libraries that come with your version of
        Linux.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        You can also download the rpm packages from
        ftp://ftp.rpm.org/pub/rpm/dist/. This site includes versions of
        the RPM libraries going back to 1996, ancient history in terms
        of Linux.
      </para>
      <para>
        The package you need is rpm-devel. If you installed &RH;
        Linux 8.0, the package is rpm-devel-4.1-1.06. This package
        includes header files, documentation, and libraries.
      </para>
    </sect2>
    <sect2>
      <title>Using the RPM Library</title>
      <para>
        All C programs using the RPM library need to include the file
        rpmlib.h, which defines the core data structures, constants, and
        functions. One thing you’ll quickly note is that the RPM C
        library accesses RPM data at a very low level. This is one
        reason why many developers are moving to Python for their RPM
        programs, since the Python RPM API presents a higher level of
        abstraction.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-rpm-programming-python"/>  covers programming RPM with Python.
      </para>
      <para>
        In addition to rpmlib.h, the header file rpmcli.h defines a
        high-level API based on the command-line options to the rpm
        command. (The cli in rpmcli stands for command-line interface.)
        Table 16-1 lists other important RPM header files that make up
        the major subsystems of the RPM system.
      </para>
      <para>
        Table 16-1 RPM sub-system header files
      </para>
[...3572 lines suppressed...]
      }
    </para>
    <para/>
    <para>
      ts = rpmtsCreate();
    </para>
    <para/>
    <para>
      /* Check for query mode. */
    </para>
    <para>
      if (qva->qva_mode == 'q') {
    </para>
    <para>
      /* Make sure there's something to do. */
    </para>
    <para>
      if (qva->qva_source != RPMQV_ALL &&
      !poptPeekArg(context)) {
    </para>
    <para>
      fprintf(stderr, "no arguments given for --query");
    </para>
    <para>
      exit(EXIT_FAILURE);
    </para>
    <para>
      }
    </para>
    <para/>
    <para>
      ec = rpmcliQuery(ts, qva, (const char **) poptGetArgs(context));
    </para>
    <para>
      }
    </para>
    <para>
      /* Check for verify mode. */
    </para>
    <para>
      else if (qva->qva_mode == 'V') {
    </para>
    <para>
      rpmVerifyFlags verifyFlags = VERIFY_ALL;
    </para>
    <para/>
    <para>
      /* Verify flags are negated from query flags. */
    </para>
    <para>
      verifyFlags &= ~qva->qva_flags;
    </para>
    <para>
      qva->qva_flags = (rpmQueryFlags) verifyFlags;
    </para>
    <para/>
    <para>
      /* Make sure there's something to do. */
    </para>
    <para>
      if (qva->qva_source != RPMQV_ALL &&
      !poptPeekArg(context)) {
    </para>
    <para>
      fprintf(stderr, "no arguments given for --verify");
    </para>
    <para>
      exit(EXIT_FAILURE);
    </para>
    <para>
      }
    </para>
    <para/>
    <para>
      ec = rpmcliVerify(ts, qva, (const char **) poptGetArgs(context));
    </para>
    <para>
      }
    </para>
    <para>
      else {
    </para>
    <para>
      poptPrintUsage(context, stderr, 0);
    </para>
    <para>
      exit(EXIT_FAILURE);
    </para>
    <para>
      }
    </para>
    <para/>
    <para>
      ts = rpmtsFree(ts);
    </para>
    <para/>
    <para>
      context = rpmcliFini(context);
    </para>
    <para/>
    <para>
      return ec;
    </para>
    <para>
      }
    </para>
    <para>
      There is not a lot of code in rpmq.c, as this program is mostly
      calling the high-level functions for the rpm command-line
      interface.
    </para>
    <para>
      When you run the rpmq program, it performs the same tasks as the
      rpm command with the --query (or -q) and --verify (or -V)
      command-line options.
    </para>
    <para>
      For example, rpmq supports query formats:
    </para>
    <para>
      $ ./rpmq -q --qf "%{NAME} %{INSTALLTID:date}\n" jikes
    </para>
    <para>
      jikes Fri 25 Oct 2002 06:49:38 PM CDT
    </para>
  </sect1>
  <sect1>
    <title>Where to Go from Here</title>
    <para>
      There is a lot more you can do with the RPM library; you're
      limited only by your imagination. The best way to get started is
      to follow the examples in this chapter and then try out some RPM
      programs on your own. After working with the RPM library for a
      while, you can delve into other RPM topics.
    </para>
    <para>
      The RPM Web site, at www.rpm.org, has most of the available
      documentation on the RPM system. This site also includes official
      RPM released software.
    </para>
    <para>
      One of the best ways to help find out about how to perform RPM
      tasks is to look at the source code for the rpm program itself.
      For this, download the rpm-src source RPM, too. To see the rpm
      command-line interface functions in action, look especially at
      tools/rpmcache.c and tools/rpmgraph.c, two relatively short RPM
      files that show how to take advantage of a number of short cuts.
      The source code for the Python and Perl bindings can also provide
      extra hints about the purposes of the RPM API calls.
    </para>
    <para>
      The RPM Web site also has a cross-referenced set of HTML pages on
      the RPM programming API. The pages for version 4.1 of RPM are
      available at www.rpm.org/rpmapi-4.1/. A good starting page is
      www.rpm.org/rpmapi-4.1/modules.html, which lists a number of
      modules within the overall RPM library. This extra level of
      organization can help you locate the functions you need.
    </para>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      Everything you can do with RPM you can program in C. That’s
      because the source code for the entire RPM system is available. In
      addition, the rpm and rpmbuild programs make use of a published
      API, called rpmlib, to access RPM functionality. You can use this
      library yourself.
    </para>
    <para>
      The popt library, short for parse options, provides a lot of handy
      utilities for parsing very complex command-line options. You can
      use popt inside your own programs, even if you don’t use the
      rest of the RPM functionality.
    </para>
    <para>
      Most RPM programs start up by calling rpmcliInit, which sets up
      RPM variables for the large set of command-line options supported
      by most RPM commands.
    </para>
    <para>
      Call rpmReadPackageFile to read in the Header object from a
      package file. You can also get Header objects for the packages
      installed in a system by initializing an iterator to iterate over
      a set of packages that meet a certain criteria.
    </para>
    <para>
      This chapter covers a fairly low level of access to RPM
      functionality. The next chapter, on Python programming, shows a
      higher level of abstraction for working with RPM.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-programming-perl.xml ---
<!-- $Id: -->

<chapter id="ch-programming-perl">
  <title>Programming RPM with Perl</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Using the RPM2 module to access information on package files
      </para>
    </listitem>
    <listitem>
      <para>
        Querying the RPM database from Perl
      </para>
    </listitem>
    <listitem>
      <para>
        Cross-referencing capabilities by the packages that provide and
        require capabilities
      </para>
    </listitem>
    <listitem>
      <para>
        Extracting information on packages
      </para>
    </listitem>
  </itemizedlist>
  <para>
    Perl is one of the most popular scripting languages. Used by system
    administrators, software developers, and a host of other users, Perl
    runs on many operating systems including Linux, UNIX, and Windows.
    Perl stands for Practical Extraction and Report Language, or
    sometimes Pathologically Eclectic Rubbish Lister.
  </para>
  <para>
    Note
  </para>
  <para>
    In the same vein, LISP stands for Lots of Irritating Single
    Parenthesis and COBOL for Completely Obnoxious Business Oriented
    Language.
  </para>
  <para>
    I began my book Cross-Platform Perl (John Wiley & Sons, 2000) by
    mentioning that when I first started learning Perl, I thought it was
    an evil plot. I still do. But it is a very practical evil plot. You
    can get a lot of work done with Perl, and quickly.
  </para>
  <para>
    Because of a long history of text processing, Perl is especially
    popular among system administrators. Perl also supports add-on
    packages, called modules. You can find thousands of add-on modules
    for text processing, networking, and a plethora of other tasks.
    There are so many modules available that some people who don’t
    like the Perl syntax script with Perl anyway, because the available
    modules save a lot of time.
  </para>
  <para>
    Cross Reference
  </para>
  <para>
    See search.cpan.org, the Comprehensive Perl Archive Network, for a
    listing of many Perl modules.
  </para>
  <para>
    This chapter covers working with RPM files and the RPM database
    using Perl. You can combine RPM usage with other Perl usage, such as
    generating HTML files or downloading RPMs over a network link.
  </para>
  <para>
    Cross Reference
  </para>
  <para>
    Many of the RPM tools covered in <xref linkend="ch-management-software"/>  are written in Perl.
  </para>
  <sect1>
    <title>Getting and Using the Perl RPM Modules</title>
    <para>
      A number of Perl RPM modules are available. No one module provides
      all the features you need, although with time, the Perl modules
      will consolidate into a few modules that most everyone uses. As of
      this writing, the RPM2 module, by Chip Turner of &RH;, provides
      the most recent approach to working with the RPM system from Perl.
      This chapter covers the RPM2 module.
    </para>
    <para>
      &RHL; 8.0 comes with a perl-RPM2 package, which you need
      to install to use this module. Otherwise, you can download the
      module from www.cpan.org. Install this module, as well as the perl
      module, which provides the Perl language interpreter. Once you
      have this module installed and the perl package installed, you are
      ready to go.
    </para>
    <para>
      Note
    </para>
    <para>
      The version of the perl-RPM2 package that ships with &RHL;
      8.0 has a bug in that it will not open package files that were
      created with the version of rpm that ships with &RHL; 8.0.
      That is, the Perl module cannot read package files that ship with
      &RHL;. You can read older package files, though. This
      problem only affects attempts to read .rpm files, not installed
      packages. The bug is related to reading signed packages but not
      having the GPG keys in the keyring. The latest version on
      search.cpan.org fixes this problem.
    </para>
    <para>
      The RPM2 module contains Perl methods to work on two types of RPM
      objects: RPM files and installed packages.
    </para>
  </sect1>
  <sect1>
    <title>Working with RPM Files</title>
    <para>
      The RPM2 module provides a top-level object, RPM2, that acts as an
      entry point into the module. From the RPM2 object, you either open
      the RPM database, covered in the "Programming with the RPM
      Database" section, or open an RPM package file, covered here.
    </para>
    <para>
      The first step in working with an RPM file is to open the file
      inside a Perl script.
    </para>
    <sect2>
      <title>Opening package files</title>
      <para>
        The open_package subroutine opens an RPM package file and
        returns a header object (an RPM2::Header). The basic syntax
        follows:
      </para>
      <para>
        my $header = RPM2->open_package( $filename );
      </para>
      <para>
        For example:
      </para>
      <para>
        my $header =
        RPM2->open_package("jikes-1.14-1-glibc-2.2.i386.rpm");
      </para>
      <para>
        After you’ve opened a package, you can perform a number of
        query operations on the header object returned by the
        open_package subroutine.
      </para>
    </sect2>
    <sect2>
      <title>Listing tags from the package</title>
      <para>
        Each RPM package has information stored under a variety of tags,
        such as the package name under the NAME tag and the package long
        description under the DESCRIPTION tag.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        These are the same tags introduced with the --queryformat option
        to the rpm command discussed in <xref linkend="ch-using-rpm-db"/> .
      </para>
      <para>
        The tag subroutine returns the value of a given tag. For
        example, to get the name of the package, use the NAME tag:
      </para>
      <para>
        use RPM2;
      </para>
      <para/>
      <para>
        my $header =
        RPM2->open_package("jikes-1.14-1-glibc-2.2.i386.rpm" );
      </para>
      <para/>
      <para>
        print $header->tag("NAME"), "\n";
      </para>
      <para>
        Pulling this together, Listing 18-1 shows example script that
        lists the name and one-line short summary of a package file.
      </para>
      <para>
        Listing 18-1: rpmsum.pl
      </para>
      <para>
        #!/usr/bin/perl
      </para>
      <para/>
      <para>
        #
      </para>
      <para>
        # Lists summary from an RPM package file
      </para>
      <para>
        # Usage:
      </para>
      <para>
        # rpmsum.pl package_name.rpm
      </para>
      <para>
        #
      </para>
      <para>
        use strict;
      </para>
      <para>
        use RPM2;
      </para>
      <para/>
      <para>
        my $header = RPM2->open_package( $ARGV[0] );
      </para>
      <para/>
      <para>
        print $header->tag("NAME"), ": ", $header->tag("SUMMARY"),
        "\n";
      </para>
      <para>
        Enter this script and name the file rpmsum.pl.
      </para>
      <para>
        When you run this script, you need to pass the name of a package
        file on the command line. For example:
      </para>
      <para>
        $ ./rpmsum.pl jikes-1.14-1-glibc-2.2.i386.rpm
      </para>
      <para>
        jikes: java source to bytecode compiler
      </para>
    </sect2>
    <sect2>
      <title>Convenience methods</title>
      <para>
        The RPM2 module includes convenience methods for all RPM tags.
        This means you can use the method name in place of tag("NAME").
        For example:
      </para>
      <para>
        print $header->name(), ": ", $header->summary(), "\n";
      </para>
    </sect2>
    <sect2>
      <title>Listing the name and version</title>
      <para>
        The RPM2 module provides a handy subroutine for getting the
        NAME, VERSION, RELEASE, and EPOCH tags, often abbreviated as
        NVRE. The subroutine, as_nvre, returns a single string with
        these values in the standard format, with the values separated
        by minus signs.
      </para>
      <para>
        Note
      </para>
      <para>
        Usually, the EPOCH tag has no value. If there is an EPOCH value,
        you will see it output first, and then a colon, and then the
        name, version, and release values. For example:
      </para>
      <para>
        5:redhat-config-httpd-1.0.1-13
      </para>
      <para>
        In this case, the EPOCH value is 5.
      </para>
      <para>
        You can call this subroutine on any header object, or any
        package object to get the full name of the package. For example:
      </para>
      <para>
        print $header->as_nvre(), "\n";
      </para>
    </sect2>
    <sect2>
      <title>Checking whether the package is a source package</title>
      <para>
        Another handy subroutine tells you if an RPM file represents a
        source RPM or a binary RPM. The is_source_package subroutine
        returns a true value if the package is a source package, and a
        false value otherwise.
      </para>
      <para>
        The rpmpkg.pl script, shown in Listing 18-2, shows how to use
        the as_nvre and is_source_package subroutines.
      </para>
      <para>
        Listing 18-2: rpmpkg.pl
      </para>
      <para>
        #!/usr/bin/perl
      </para>
      <para/>
      <para>
        #
      </para>
      <para>
        # Queries RPM package file and prints
      </para>
      <para>
        # out name and whether this is a source pkg.
      </para>
      <para>
        # Usage:
      </para>
      <para>
        # rpmpkg.pl package_name
      </para>
      <para>
        #
      </para>
      <para>
        use strict;
      </para>
      <para>
        use RPM2;
      </para>
      <para/>
      <para>
        my $header = RPM2->open_package( $ARGV[0] );
      </para>
      <para/>
      <para>
        if ( $header->is_source_package() ) {
      </para>
      <para>
        print "Source package ", $header->as_nvre(), "\n";
      </para>
      <para>
        } else {
      </para>
      <para>
        print $header->as_nvre(), "\n";
      </para>
      <para>
        }
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Programming with the RPM Database</title>
    <para>
      In addition to providing query routines for RPM files, you can
      also access the RPM database with the RPM2 package.
    </para>
    <para>
      To access the RPM database, your Perl script must first open the
      database.
    </para>
    <sect2>
      <title>Opening the database</title>
      <para>
        Open the RPM database with a call to open_rpm_db on the RPM2
        object. For example:
      </para>
      <para>
        my $rpm_db = RPM2->open_rpm_db();
      </para>
      <para>
        You can also specify the directory where the RPM database
        resides. This is most useful for accessing a database in a
        non-standard location. For example:
      </para>
      <para>
        my $rpm_db = RPM2->open_rpm_db( "-path" => "/var/lib/rpm"
        );
      </para>
      <para>
        Note
      </para>
      <para>
        The -path is normally used as a Perl bareword but is shown here
        as a string.
      </para>
      <para>
        Once you have an RPM database object, you can call one of the
        find subroutines to find packages in most of the same ways as
        supported by the rpm –q command.
      </para>
    </sect2>
    <sect2>
      <title>Finding packages</title>c<para>
        The find_by_name subroutine finds a package or packages by name.
        It returns a Perl list of the entries found. For example, if you
        installed more than one version of a package, find_by_name would
        return a list of all the packages at the different versions.
      </para>
      <para>
        Similar to find_by_name, find_by_name_iter returns an iterator
        to iterate over the packages that match the query. The iterator
        approach is usually more efficient.
      </para>
    </sect2>
    <sect2>
      <title>Iterating over packages</title>
      <para>
        Iterators are important in the RPM2 package because they provide
        a more efficient interface to potentially large sets of
        packages, and because iterators more closely match the
        underlying C API. Furthermore, iterators are very easy to use.
        Simply call the next subroutine to move ahead to the next
        element, that is, the next package.
      </para>
      <para>
        For example:
      </para>
      <para>
        my $pkg_iter = $rpm_db->find_by_name_iter( "kernel" );
      </para>
      <para/>
      <para>
        while (my $pkg = $pkg_iter->next() ) {
      </para>
      <para/>
      <para>
        # Do something ...
      </para>
      <para>
        }
      </para>
      <para>
        Listing 18-3 shows a script that acts much like the rpm –q
        command, without any other command-line options.
      </para>
      <para>
        Listing 18-3: rpmname.pl
      </para>
      <para>
        #!/usr/bin/perl
      </para>
      <para/>
      <para>
        #
      </para>
      <para>
        # Queries RPM database for given package.
      </para>
      <para>
        # Usage:
      </para>
      <para>
        # rpmname.pl package_name
      </para>
      <para>
        #
      </para>
      <para>
        use strict;
      </para>
      <para>
        use RPM2;
      </para>
      <para/>
      <para>
        my $rpm_db = RPM2->open_rpm_db( "−path" =>
        "/var/lib/rpm" );
      </para>
      <para/>
      <para>
        my $pkg_iter = $rpm_db->find_by_name_iter( $ARGV[0] );
      </para>
      <para/>
      <para>
        while (my $pkg = $pkg_iter->next() ) {
      </para>
      <para/>
      <para>
        print $pkg->tag("NAME"), "-", $pkg->tag("VERSION"), "\n";
      </para>
      <para>
        }
      </para>
      <para/>
      <para>
        $rpm_db->close_rpm_db();
      </para>
      <para>
        When you run this script, you need to pass the name of a package
        to query. For example:
      </para>
      <para>
        $ ./rpmname.pl kernel
      </para>
      <para>
        kernel-2.4.18
      </para>
    </sect2>
    <sect2>
      <title>Additional query subroutines</title>
      <para>
        The find_by_name_iter subroutine finds a package by its name.
        The RPM2 module also supports a number of other query routines,
        listed in Table 18-1.
      </para>
      <para>
        Table 18-1 RPM2 module query routines
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  Routine
                </para>
              </entry>
              <entry>
                <para>
                  Usage
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  find_all()
                </para>
              </entry>
              <entry>
                <para>
                  Returns a list with all the packages in the database
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  find_all_iter()
                </para>
              </entry>
              <entry>
                <para>
                  Returns an iterator over all the packages in the
                  database
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  find_by_file($filename)
                </para>
              </entry>
              <entry>
                <para>
                  Finds all packages that own the given file, returning
                  a list
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  find_by_file_iter($filename)
                </para>
              </entry>
              <entry>
                <para>
                  Finds all packages that own the given file, returning
                  an iterator
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  find_by_name($package_name)
                </para>
              </entry>
              <entry>
                <para>
                  Finds all packages with the given name, returning a
                  list
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  find_by_name_iter($package_name)
                </para>
              </entry>
              <entry>
                <para>
                  Finds all packages with the given name, returning an
                  iterator
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  find_by_provides($capability)
                </para>
              </entry>
              <entry>
                <para>
                  Finds all packages that provide the given capability,
                  returning a list
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  find_by_provides_iter($capability)
                </para>
              </entry>
              <entry>
                <para>
                  Finds all packages that provide the given capability,
                  returning an iterator
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  find_by_requires($capability)
                </para>
              </entry>
              <entry>
                <para>
                  Finds all packages that require the given capability,
                  returning a list
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  find_by_requires_iter($capability)
                </para>
              </entry>
              <entry>
                <para>
                  Finds all packages that require the given capability,
                  returning an iterator
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
      <para>
        To verify the find routines, you can try the following script
        and compare the results with the rpm command. Listing 18-4 shows
        the script that finds what package provides a capability and
        also which packages require the capability.
      </para>
      <para>
        Listing 18-4: rpmprovides.pl
      </para>
      <para>
        #!/usr/bin/perl
      </para>
      <para/>
      <para>
        #
      </para>
      <para>
        # Queries RPM database for given package,
      </para>
      <para>
        # listing what it provides and what other
      </para>
      <para>
        # packages require the capability.
      </para>
      <para>
        #
      </para>
      <para>
        # Usage:
      </para>
      <para>
        # rpmprovides.pl package_name
      </para>
      <para>
        #
      </para>
      <para>
        use strict;
      </para>
      <para>
        use RPM2;
      </para>
      <para/>
      <para>
        my $rpm_db = RPM2->open_rpm_db();
      </para>
      <para/>
      <para>
        my $pkg_iter = $rpm_db->find_by_provides_iter( $ARGV[0] );
      </para>
      <para/>
      <para>
        print "Provides: ", $ARGV[0], "\n";
      </para>
      <para/>
      <para>
        while (my $pkg = $pkg_iter->next() ) {
      </para>
      <para>
        print "\t", $pkg->as_nvre(), "\n";
      </para>
      <para>
        }
      </para>
      <para/>
      <para/>
      <para>
        # Now, what packages require this capability.
      </para>
      <para/>
      <para>
        my $pkg_iter2 = $rpm_db->find_by_requires_iter( $ARGV[0] );
      </para>
      <para/>
      <para>
        print "Requires: ", $ARGV[0], "\n";
      </para>
      <para>
        while (my $pkg2 = $pkg_iter2->next() ) {
      </para>
      <para>
        print "\t", $pkg2->as_nvre(), "\n";
      </para>
      <para>
        }
      </para>
      <para/>
      <para>
        $rpm_db->close_rpm_db();
      </para>
      <para>
        When you run this script with the name of a capability, you'll
        see output like the following:
      </para>
      <para>
        $ ./rpmprovides.pl httpd
      </para>
      <para>
        Provides: httpd
      </para>
      <para>
        httpd-2.0.40-8
      </para>
      <para>
        Requires: httpd
      </para>
      <para>
        mod_perl-1.99_05-3
      </para>
      <para>
        5:redhat-config-httpd-1.0.1-13
      </para>
      <para>
        mod_python-3.0.0-10
      </para>
      <para>
        1:mod_ssl-2.0.40-8
      </para>
      <para>
        Note
      </para>
      <para>
        The 5: in 5:redhat-config-httpd-1.0.1-13 and 1: in
        1:mod_ssl-2.0.40-8 represent the EPOCH tag value.
      </para>
      <para>
        To verify this script, run the rpm -q command to see if you get
        the same packages listed. For example:
      </para>
      <para>
        $ rpm -q --whatprovides httpd
      </para>
      <para>
        httpd-2.0.40-8
      </para>
      <para/>
      <para>
        $ rpm -q --whatrequires httpd
      </para>
      <para>
        mod_perl-1.99_05-3
      </para>
      <para>
        redhat-config-httpd-1.0.1-13
      </para>
      <para>
        mod_python-3.0.0-10
      </para>
      <para>
        mod_ssl-2.0.40-8
      </para>
      <para>
        In both cases, you see the same packages listed. You can use
        this technique to verify your scripts.
      </para>
      <para>
        Note
      </para>
      <para>
        The find_by_provides_iter subroutine requires the name of a
        package, such as bash. You cannot pass a file name, such as
        /bin/bash, to get the name of the package that provides this
        capability (a file, really).
      </para>
    </sect2>
    <sect2>
      <title>Getting information on packages</title>ng information on packages<para>
        The tag, as_nvre, and is_source_package subroutines that worked
        on header objects read from RPM files, shown previously, also
        work with package entries returned from the RPM database.
      </para>
      <para>
        For example, Listing 18-5 shows a script, rpminfo.pl, that
        prints out descriptive information about a given package.
      </para>
      <para>
        Listing 18-5: rpminfo.pl
      </para>
      <para>
        #!/usr/bin/perl
      </para>
      <para/>
      <para>
        #
      </para>
      <para>
        # Queries RPM database for given package and prints info.
      </para>
      <para>
        # Usage:
      </para>
      <para>
        # rpminfo.pl package_name
      </para>
      <para>
        #
      </para>
      <para>
        use strict;
      </para>
      <para>
        use RPM2;
      </para>
      <para/>
      <para>
        my $rpm_db = RPM2->open_rpm_db( "-path" => "/var/lib/rpm"
        );
      </para>
      <para/>
      <para>
        my $pkg_iter = $rpm_db->find_by_name_iter( $ARGV[0] );
      </para>
      <para/>
      <para>
        while (my $pkg = $pkg_iter->next() ) {
      </para>
      <para/>
      <para>
        printInfo( $pkg );
      </para>
      <para>
        }
      </para>
      <para/>
      <para>
        $rpm_db->close_rpm_db();
      </para>
      <para/>
      <para/>
      <para>
        # Prints info on one package.
      </para>
      <para>
        sub printInfo {
      </para>
      <para>
        my($pkg) = shift;
      </para>
      <para/>
      <para>
        print $pkg->as_nvre(), ", ", $pkg->tag("ARCH"), ", ",
      </para>
      <para>
        $pkg->tag("OS"), ", ", $pkg->tag("PLATFORM"), "\n";
      </para>
      <para/>
      <para>
        print $pkg->tag("SUMMARY"), "\n";
      </para>
      <para>
        print "Group: ", $pkg->tag("GROUP"), "\n";
      </para>
      <para>
        print $pkg->tag("DESCRIPTION"), "\n";
      </para>
      <para>
        print "Vendor: ", $pkg->tag("VENDOR"), ", ",
        $pkg->tag("URL"), "\n";
      </para>
      <para>
        print "Size: ", $pkg->tag("SIZE"), "\n";
      </para>
      <para>
        }
      </para>
      <para>
        When you run this script, you’ll see output like the
        following:
      </para>
      <para>
        $ ./rpminfo.pl XFree86
      </para>
      <para>
        XFree86-4.2.0-72, i386, linux, i386-redhat-linux-gnu
      </para>
      <para>
        The basic fonts, programs and docs for an X workstation.
      </para>
      <para>
        Group: User Interface/X
      </para>
      <para>
        XFree86 is an open source implementation of the X Window System.
        It
      </para>
      <para>
        provides the basic low level functionality which full fledged
      </para>
      <para>
        graphical user interfaces (GUIs) such as GNOME and KDE are
        designed
      </para>
      <para>
        upon.
      </para>
      <para>
        Vendor: &FORMAL-RHI;, http://www.xfree86.org
      </para>
      <para>
        Size: 30552239
      </para>
      <sect3>
        <title>Listing the Installed Date</title>
        <para>
          The installed date is a number value representing the number
          of seconds since the start of the UNIX epoch, January 1, 1970,
          which predates the start of the Linux epoch by about 20 years.
          So, when you get the value of the INSTALLTIME tag, you’ll
          see a meaningless number.
        </para>
        <para>
          To make sense of this number, pass the value to the Perl
          localtime function. Listing 18-6 shows an example of this.
        </para>
        <para>
          Listing 18-6: rpmdate.pl
        </para>
        <para>
          #!/usr/bin/perl
        </para>
        <para/>
        <para>
          #
        </para>
        <para>
          # Queries RPM database for given package,
        </para>
        <para>
          # prints out name, vendor, and date installed.
        </para>
        <para>
          # Usage:
        </para>
        <para>
          # rpmdate.pl package_name
        </para>
        <para>
          #
        </para>
        <para>
          use strict;
        </para>
        <para>
          use RPM2;
        </para>
        <para/>
        <para>
          my $rpm_db = RPM2->open_rpm_db();
        </para>
        <para/>
        <para>
          my $pkg_iter = $rpm_db->find_by_name_iter( $ARGV[0] );
        </para>
        <para/>
        <para>
          while (my $pkg = $pkg_iter->next() ) {
        </para>
        <para/>
        <para>
          printDate( $pkg );
        </para>
        <para>
          }
        </para>
        <para/>
        <para>
          $rpm_db->close_rpm_db();
        </para>
        <para/>
        <para/>
        <para/>
        <para>
          # Prints installation data for one package.
        </para>
        <para>
          sub printDate {
        </para>
        <para>
          my($pkg) = shift;
        </para>
        <para/>
        <para>
          my $date = localtime( $pkg->tag("INSTALLTIME") );
        </para>
        <para/>
        <para>
          printf("%-20s %-17s %s\n", $pkg->as_nvre(),
          $pkg->tag("VENDOR"), $date);
        </para>
        <para>
          }
        </para>
        <para>
          Note
        </para>
        <para>
          The printf function in this script can do something the rpm
          command cannot do. Even with the --queryformat option, you
          cannot group multiple items and then set the size; with Perl,
          you can. Simply assign the multiple values to a string, or use
          the handy as_nvre subroutine, which gathers up to four tags
          together into one string.
        </para>
        <para>
          When you pass the name of a package to this script, you’ll
          see the date the package was installed. For example:
        </para>
        <para>
          $ ./rpmdate.pl kernel
        </para>
        <para>
          kernel-2.4.18-14 &FORMAL-RHI; Sat Oct 5 12:29:58 2002
        </para>
      </sect3>
      <sect3>
        <title>Handling String Array Tags</title>
        <para>
          Not only is the date stored in a format that adds complication
          to your script. A number of tags are string arrays, not scalar
          strings. This means you may see output that is all mashed
          together.
        </para>
        <para>
          To help deal with this, the following subroutine takes in an
          array of strings and returns a string that is built using a
          passed-in delimiter:
        </para>
        <para>
          sub arrayToString {
        </para>
        <para>
          my($sep) = shift;
        </para>
        <para>
          my(@array) = @_;
        </para>
        <para>
          my($str);
        </para>
        <para/>
        <para>
          $str = $array[0];
        </para>
        <para/>
        <para>
          for ( $i = 1; $i < $#array; $i++ )
        </para>
        <para>
          {
        </para>
        <para>
          $str = $str . $sep . $array[$i];
        </para>
        <para>
          }
        </para>
        <para/>
        <para>
          return $str;
        </para>
        <para>
          }
        </para>
        <para>
          Note
        </para>
        <para>
          Show your Perl expertise and earn extra points by implementing
          the arrayToString subroutine as a single Perl statement that
          uses the join function.
        </para>
        <para>
          The following list shows the tags that are an array of
          strings:
        </para>
        <para>
          *BASENAMES
        </para>
        <para>
          *CHANGELOGNAME
        </para>
        <para>
          *CHANGELOGTEXT
        </para>
        <para>
          *DIRNAMES
        </para>
        <para>
          *FILEGROUPNAME
        </para>
        <para>
          *FILELANGS
        </para>
        <para>
          *FILELINKTOS
        </para>
        <para>
          *FILEMD5S
        </para>
        <para>
          *FILEUSERNAME
        </para>
        <para>
          *OLDFILENAMES
        </para>
        <para>
          *PROVIDENAME
        </para>
        <para>
          *PROVIDEVERSION
        </para>
        <para>
          *REQUIRENAME
        </para>
        <para>
          *REQUIREVERSION
        </para>
        <para>
          Cross Reference
        </para>
        <para>
          <xref linkend="ch-using-rpm-db"/>  covers more on these tags.
        </para>
      </sect3>
      <sect3>
        <title>Listing the Files In A Package</title>
        <para>
          The files subroutine provides a list of all the files in a
          package. Listing 18-7 shows how to access this list.
        </para>
        <para>
          Listing 18-7: rpmfiles.pl
        </para>
        <para>
          #!/usr/bin/perl
        </para>
        <para/>
        <para>
          #
        </para>
        <para>
          # Queries RPM database for given package,
        </para>
        <para>
          # prints out the files in the package.
        </para>
        <para>
          # Usage:
        </para>
        <para>
          # rpmfiles.pl package_name
        </para>
        <para>
          #
        </para>
        <para>
          use strict;
        </para>
        <para>
          use RPM2;
        </para>
        <para/>
        <para>
          my $rpm_db = RPM2->open_rpm_db();
        </para>
        <para/>
        <para>
          my $pkg_iter = $rpm_db->find_by_name_iter( $ARGV[0] );
        </para>
        <para/>
        <para>
          while (my $pkg = $pkg_iter->next() ) {
        </para>
        <para/>
        <para>
          printFiles( $pkg );
        </para>
        <para>
          }
        </para>
        <para/>
        <para>
          $rpm_db->close_rpm_db();
        </para>
        <para/>
        <para/>
        <para/>
        <para>
          # Prints installation data for one package.
        </para>
        <para>
          sub printFiles {
        </para>
        <para>
          my($pkg) = shift;
        </para>
        <para/>
        <para>
          my $files = arrayToString("\n", $pkg->files() );
        </para>
        <para/>
        <para>
          print "Files:\n", $files, "\n";
        </para>
        <para>
          }
        </para>
        <para/>
        <para>
          sub arrayToString {
        </para>
        <para>
          my($sep) = shift;
        </para>
        <para>
          my(@array) = @_;
        </para>
        <para>
          my($str);
        </para>
        <para/>
        <para>
          $str = $array[0];
        </para>
        <para/>
        <para>
          for ( my $i = 1; $i < $#array; $i++ )
        </para>
        <para>
          {
        </para>
        <para>
          $str = $str . $sep . $array[$i];
        </para>
        <para>
          }
        </para>
        <para/>
        <para>
          return $str;
        </para>
        <para>
          }
        </para>
        <para>
          When you run this script, you’ll see output like the
          following:
        </para>
        <para>
          $ ./rpmfiles.pl jikes
        </para>
        <para>
          Files:
        </para>
        <para>
          /usr/bin/jikes
        </para>
        <para>
          /usr/doc/jikes-1.17/license.htm
        </para>
      </sect3>
    </sect2>
    <sect2>
      <title>Comparing versions</title>
      <para>
        The RPM2 module overrides the spaceship operator, <=>, to
        perform version comparisons between packages. The script in
        Listing 18-8 shows how to compare all local RPM files against
        the newest installed version of the same package, if the package
        is installed.
      </para>
      <para>
        Listing 18-8: rpmver.pl
      </para>
      <para>
        #!/usr/bin/perl -w
      </para>
      <para/>
      <para>
        #
      </para>
      <para>
        # Compare versions of all *.rpm files against the
      </para>
      <para>
        # latest packages installed (if installed)
      </para>
      <para>
        #
      </para>
      <para>
        # Usage:
      </para>
      <para>
        # rpmver.pl
      </para>
      <para>
        # This script looks for all *.rpm files.
      </para>
      <para>
        #
      </para>
      <para>
        use strict;
      </para>
      <para>
        use RPM2;
      </para>
      <para/>
      <para>
        my $rpm_db = RPM2->open_rpm_db();
      </para>
      <para/>
      <para>
        for my $filename (<*.rpm>) {
      </para>
      <para>
        my $h = RPM2->open_package( $filename );
      </para>
      <para/>
      <para>
        # Ensure we compare against the newest
      </para>
      <para>
        # package of the given name.
      </para>
      <para>
        my ($installed) =
      </para>
      <para>
        sort { $b <=> $a } $rpm_db->find_by_name($h->name);
      </para>
      <para/>
      <para>
        if (not $installed) {
      </para>
      <para>
        printf "Package %s not installed.\n", $h->as_nvre;
      </para>
      <para>
        } else {
      </para>
      <para>
        my ($result) = ($h <=> $installed);
      </para>
      <para/>
      <para>
        if ($result < 0) {
      </para>
      <para>
        printf "Installed package %s newer than file %s\n",
      </para>
      <para>
        $installed->as_nvre,
      </para>
      <para>
        $h->as_nvre;
      </para>
      <para>
        } else {
      </para>
      <para>
        printf "File %s newer than installed package %s\n",
      </para>
      <para>
        $h->as_nvre,
      </para>
      <para>
        $installed->as_nvre;
      </para>
      <para>
        }
      </para>
      <para>
        }
      </para>
      <para>
        }
      </para>
      <para>
        The sort { $a <=> $b } in front of the find_by_name call
        sorts all the packages of that name by the version number, so
        that the comparison is performed against the newest installed
        version of the package. The ($h <=> $installed) compares
        the header from the RPM file on disk against the newest
        installed version of the package.
      </para>
      <para>
        When you run this script, you’ll see output like the
        following, depending on which RPM files you have in the local
        directory:
      </para>
      <para>
        $ perl rpmver.pl
      </para>
      <para>
        Package acroread-4.0-0 not installed.
      </para>
      <para>
        Package canvas-7.0b2.0-1 not installed.
      </para>
      <para>
        Installed package jikes-1.18-1 newer than file jikes-1.14-1
      </para>
      <para>
        Installed package SDL-1.2.4-5 newer than file SDL-0.9.9-4
      </para>
      <para>
        Package ted-2.8-1 not installed.
      </para>
    </sect2>
    <sect2>
      <title>Closing the database</title>
      <para>
        When you are done with the RPM database, call close_rpm_db, as
        shown following:
      </para>
      <para>
        $rpm_db->close_rpm_db();
      </para>
      <para>
        Note that this call is not necessary, as the RPM2 module will
        close the database when the object, in this case $rpm_db, goes
        out of scope.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Where to Go from Here</title>
    <para>
      One of the strengths of Perl is that there are so many add-on
      packages available. In addition, Perl is really strong in text
      processing. You can combine these strengths to provide cleaner
      output for RPM database queries, for example, avoiding the complex
      syntax for the --queryformat option to the rpm command. Perl can
      do more than the --queryformat option allows. For example, you can
      combine multiple values together into a Perl string and then
      format the output. The --queryformat option only allows formatting
      on each value individually, not groups of values.
    </para>
    <para>
      In addition, you can combine one of the Perl templating modules,
      such as Text::Template or HTML::Template, to create an HTML page
      for a given package. You could use Perl to create formatted HTML
      pages for all the installed packages on your system, with HTML
      links to cross-reference all the dependencies.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      Download these modules from the CPAN site, www.cpan.org.
    </para>
    <para>
      This chapter covers the RPM2 module. Right now, the RPM2 module
      supports only querying packages and the RPM database. Future
      versions will likely add the ability to install, update, and
      remove packages.
    </para>
    <para>
      In addition to this module, you can find an RPM module with
      RPM::Header and RPM::Database classes. Another module,
      RPM::Specfile, provides the ability to turn Perl modules, such as
      those stored on CPAN, into RPM packages. The RPM::Specfile module
      helps create an RPM spec file for a Perl module.
    </para>
    <para>
      The Perl-RPM-Perlonly bundle provides an alternative version of
      the RPM::Header module written entirely in Perl with no usage of
      the C rpm library. This makes RPM access much easier on platforms
      for which you don’t have the RPM system.
    </para>
    <para>
      The RPM-Tools bundle includes RPM::Update, which compares the
      packages installed on your system (listed by calling rpm –qa)
      with the packages available on another system, that may be
      available only with a network link. This module can also update
      packages that are older than the designated master system.
      RPM::Make, also part of the RPM-Tools bundle, helps create RPM
      packages from a Perl script. This module does not support all the
      spec file options described in <xref linkend="ch-specfiles"/> , but it can help you
      make simple packages.
    </para>
    <para>
      You can download all these modules from the CPAN site.
    </para>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      This chapter introduces the RPM2 add-on module to allow Perl
      scripts to access information on RPM package files and in the RPM
      database. To access an RPM file and query information about that
      file, you need to call the open_package subroutine. Once you’ve
      opened the file, you can call the tag, as_nvre, is_source_package,
      and files subroutines on the header object to query data about the
      package.
    </para>
    <para>
      To access the RPM database, call open_rpm_db. Once you’ve opened
      the database, you can call one of the find subroutines, such as
      find_by_name or find_by_name_iter, to search for packages. The
      subroutines that have names ending with _iter, such as
      find_by_name_iter, return an iterator object to iterate over the
      packages found. The other find subroutines, such as find_by_name,
      return a Perl list of the packages found.
    </para>
    <para>
      You can then call the tag, as_nvre, and files subroutines on the
      package objects to query information about the packages.
    </para>
    <para>
      When you are done with the RPM database, call close_rpm_db.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-programming-python.xml ---
<!-- $Id: -->

<chapter id="ch-rpm-programming-python">
  <title>Programming RPM with Python</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Using the RPM with Python
      </para>
    </listitem>
    <listitem>
      <para>
        Installing the necessary modules
      </para>
    </listitem>
    <listitem>
      <para>
        Programming with the RPM database
      </para>
    </listitem>
    <listitem>
      <para>
        Programming with RPM files
      </para>
    </listitem>
    <listitem>
      <para>
        Installing packages programmatically
      </para>
    </listitem>
  </itemizedlist>
  <sect1>
    <title>Setting Up a Python Development Environment</title>
    <para>
      Setting up a Python development environment is much the same as
      setting up a C programming environment. You need to install a set
      of packages for general Python development, install a package that
      provides the Python API to the RPM system, and choose a program
      for editing your Python scripts.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      <xref linkend="ch-development-tools"/>  covers Linux text editors and development tools.
    </para>
    <para>
      If you want to make a graphical user interface in your Python
      programs, you need to install a separate Python package.
    </para>
    <sect2>
      <title>Installing the base Python packages</title>
      <para>
        The base Python package needed for developing applications is
        python. For RPM usage, you should install Python 2.2, not Python
        1.5. That’s because the RPM bindings for Python are moving to
        support only 2.2 and higher releases.
      </para>
      <para>
        The Python package for RPM access is rpm-python. Install these
        as you would any other packages.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-using-rpm"/>  covers installing packages.
      </para>
    </sect2>
    <sect2>
      <title>Using Python for graphics</title>
      <para>
        Python supports a number of different toolkits for creating
        graphical user interfaces. You need one of these toolkits if you
        want to create Python applications that sport a user interface
        instead of command-line tools. Among the most popular toolkits
        are PyGKT, PyQt, and Tkinter.
      </para>
      <para>
        *PyGTK is a binding between Python and the GTK+ toolkit used by
        the GNOME desktop, one of two main desktop environments for
        Linux. (KDE is the other main desktop environment.) The &RH;
        redhat-config-packages program uses PyGTK and sports a very
        good-looking user interface.
      </para>
      <para>
        PyGTK provides full access to the GTK+ widgets such as menus,
        dialog windows, and buttons. Install the pygtk2 module for
        PyGTK. For more on PyGTK, see www.daa.com.au/~james/pygtk/.
      </para>
      <para>
        *PyQt connects Python scripts to the Qt C++ user interface
        toolkit. Qt forms the base library used by the KDE desktop
        environment and KDE applications. As with PyGTK, PyQt allows you
        to access the rich widget set provided by the library.
      </para>
      <para>
        Install the PyQt package for PyQt. For more on PyQt, see
        www.riverbankcomputing.co.uk/pyqt/.
      </para>
      <para>
        *Tkinter is considered a standard part of Python and is based on
        the Tk (pronounced teekay) toolkit from the Tcl scripting
        language. The main advantages of Tkinter are that it is
        considered part of Python, meaning users are more likely to have
        it, and Tkinter works on multiple platforms, including Windows.
      </para>
      <para>
        The main drawback of Tkinter is that the widget sets are not as
        rich as PyQt or PyGTK. For more on Tkinter, see
        www.python.org/topics/tkinter/.
      </para>
      <para>
        After you’ve set up your environment and installed all the
        necessary packages, the next step is to start working with the
        Python API for RPM.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>The Python API Hierarchy</title>
    <para>
      The RPM Python API provides a high-level abstraction into RPM
      functionality divided into logical areas. Table 17-1 lists the
      main RPM types. In most cases, you need to begin with rpm and
      create a transaction set.
    </para>
    <para>
      Table 17-1 Python types for RPM usage
    </para>
    <informaltable frame="all">
      <tgroup cols="2">
        <tbody>
          <row>
            <entry>
              <para>
                Class
              </para>
            </entry>
            <entry>
              <para>
                Covers
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                rpm
              </para>
            </entry>
            <entry>
              <para>
                RPM base module into RPM API
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                rpmts
              </para>
            </entry>
            <entry>
              <para>
                Transaction sets
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                rpmte
              </para>
            </entry>
            <entry>
              <para>
                Transaction elements, a package in a transaction set
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                rpmmi
              </para>
            </entry>
            <entry>
              <para>
                Match iterators, used for querying the RPM database
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
[...2678 lines suppressed...]
        </para>
        <para>
          # rpm -q jikes
        </para>
        <para>
          jikes-1.17-1
        </para>
        <para/>
        <para>
          # python rpmupgrade.py jikes-1.18-1.i386.rpm
        </para>
        <para>
          Upgrading jikes-1.18-1
        </para>
        <para>
          This upgrade will install:
        </para>
        <para>
          jikes-1.18-1
        </para>
        <para>
          jikes-1.17-1
        </para>
        <para>
          Running transaction (final step)...
        </para>
        <para>
          Opening file. 4 0 0 jikes-1.18-1.i386.rpm 1
        </para>
        <para>
          Closing file. 2 0 2854204 jikes-1.18-1.i386.rpm 1
        </para>
        <para/>
        <para>
          # rpm -q jikes
        </para>
        <para>
          jikes-1.18-1
        </para>
        <para>
          This example shows that the package was upgraded after running
          the rpmupgrade.py script. Note that with an upgrade, the
          original package, jikes-1.17-1 in this case, is also added to
          the transaction set. With an install, this is not the case.
          That’s because the original package is removed as part of
          the transaction.
        </para>
        <para>
          If you run this script as a non-root user, you will likely see
          an error like the following:
        </para>
        <para>
          $ python rpmupgrade.py jikes-1.18-1.i386.rpm
        </para>
        <para>
          Upgrading jikes-1.18-1
        </para>
        <para>
          This upgrade will install:
        </para>
        <para>
          jikes-1.18-1
        </para>
        <para>
          jikes-1.17-1
        </para>
        <para>
          Running transaction (final step)...
        </para>
        <para>
          error: cannot get exclusive lock on /var/lib/rpm/Packages
        </para>
        <para>
          error: cannot open Packages index using db3 - Operation not
          permitted (1)
        </para>
        <para>
          error: cannot open Packages database in /var/lib/rpm
        </para>
        <para>
          If a package has a dependency on a file such as a shared
          library, you will see output like the following:
        </para>
        <para>
          # python rpmupgrade.py jikes-1.17-glibc2.2-1.i386.rpm
          jpilot-0_97-1_i386.rpm
        </para>
        <para>
          Upgrading jikes-1.17-1
        </para>
        <para>
          Upgrading jpilot-0.97-1
        </para>
        <para>
          Must find file [ libpisock.so.3 ]
        </para>
        <para>
          Error: Unresolved dependencies, transaction failed.
        </para>
        <para>
          (('jpilot', '0.97', '1'), ('libpisock.so.3', None), 0, None,
          0)
        </para>
        <para>
          If a package has a dependency on another package, you will see
          output like the following:
        </para>
        <para>
          # python rpmupgrade.py eruby-devel-0.9.8-2.i386.rpm
        </para>
        <para>
          Upgrading eruby-devel-0.9.8-2
        </para>
        <para>
          Must find package [ eruby-libs - 0.9.8 ]
        </para>
        <para>
          Error: Unresolved dependencies, transaction failed.
        </para>
        <para>
          (('eruby-devel', '0.9.8', '2'), ('eruby-libs', '0.9.8'), 8,
          None, 0)
        </para>
      </sect3>
    </sect2>
  </sect1>
  <sect1>
    <title>Where to Go from Here</title>
    <para>
      The RPM bindings for Python are documented along with the C
      programming API. On a &RHL; system, look in the file
      /usr/share/doc/rpm-devel-4.1/apidocs/html/group__python.html to
      see the start of the Python-specific documentation.
    </para>
    <para>
      Note that much of this online documentation covers the C functions
      that provide the Python bindings, not the Python API itself. But,
      if you examine the online information on objects listed as
      classes, such as rpmts, you can find the Python-specific
      documentation.
    </para>
    <para>
      Furthermore, if you look into the .c files that make up the Python
      bindings, you can find PyMethodDef structure tables. These tables
      provide useful glimpses into the Python API.
    </para>
    <para>
      To learn more about programming in Python, install the python-docs
      package. The python-docs package has a large set of online
      documentation for Python, including the official Python Tutorial.
      With &RHL;, start at
      /usr/share/doc/python-docs-2.2.1/html/tut/tut.html.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      Other tutorials are available at http://diveintopython.org for the
      Dive Into Python tutorial for experienced programmers, and at
      http://py.vaults.ca/parnassus/apyllo.py/935043691.636055170 for
      the Vaults of Parnassus listing of tutorials.
    </para>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      This chapter introduces the high-level RPM API for Python
      programming. You can use this API from Python scripts to perform
      RPM functionality, just as you can write C programs using the RPM
      C API covered in <xref linkend="ch-programming-c"/> .
    </para>
    <para>
      In general, the Python API is simpler and requires fewer code
      statements than the corresponding functionality in the C API.
    </para>
    <para>
      Just about all of your work with the Python API requires a
      transaction set, which you can get by calling rpm.TransactionSet.
    </para>
    <para>
      To query the RPM database, call dbMatch on the transaction set
      object. To install or upgrade packages, call addInstall, check,
      order, and run on the transaction set.
    </para>
    <para>
      The next chapter switches to another language for accessing the
      RPM system: Perl. With the rich set of APIs, you can write your
      RPM programs in C, Python, Perl, or any language that can call on
      code written in one of these languages.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-rpm-evolution.xml ---
<!-- $Id: -->

<chapter id="ch-rpm-evolution">
  <title>RPM Feature Evolution</title>
  <para>
    Although RPM implementations are largely compatible from version to
    version, RPM packagers must remember that RPM is a still-evolving
    program and that its developers are adding features to it with each
    new version. When producing RPM package files, packagers must keep
    in mind the audience that will be using the final RPM package files.
    They must decide which versions of RPM they intend the package to be
    used with and must use only the lowest common denominator set of
    features implemented in the oldest of the RPM versions they are
    targeting. As a quick reference, keep in mind the RPM features noted
    here and the RPM version in which they are introduced. In
    considering these revisions of RPM, the main releases of interest
    are RPM 2.5, RPM 3.0.5, RPM 4.0.4, and RPM 4.1.
  </para>
  <para>
    RPM 2.5 is not widely used anymore; packages should target RPM 2.5
    only if the intention is for the RPM package to install using
    absolutely all RPM versions.
  </para>
  <para>
    RPM 3.0.5 is the final release of the 3.x series of RPM. It was the
    release of RPM shipped with &RHL; 6.2 and older releases. It
    is still in wide use by other vendors as well. Cobalt’s Linux
    distributions use an RPM implementation version based on RPM 3.0.5,
    for example. (&RHL; was upgraded to RPM 4 via an errata.)
  </para>
  <para>
    RPM 4.0.4 was used with the 7.x releases of &RHL;, and RPM
    4.1 first shipped with &RHL; 8.0. Packages produced
    targeting RPM 3.0.5 should work with nearly all implementations of
    RPM still in use today. Packages produced targeting RPM 4.0.4 or RPM
    4.1 will work only with recent RPM implementations.
  </para>
  <para>
    RPM 2.5 is the oldest version of RPM that can, by any stretch of the
    imagination, still be considered in use. With RPM 2.5, most of the
    basic RPM features were in place, as well as more advanced functions
    such as triggers and support for internationalization of Summary:,
    Description:, and Group: tags in the RPM file header. RPM 2.5 was
    also the first version of RPM to use the RPM version 3 RPM file
    format.
  </para>
  <para>
    RPM 2.5.3 added support for Epochs to the RPM header, implementing
    RPMTAG_EPOCH.
  </para>
  <para>
    RPM 2.5.4 introduced the %license and %readme file types, which can
    be used in the RPM spec file to indicate license and README files.
  </para>
  <para>
    RPM 2.5.6 added support for usage of the Epoch: keyword in the RPM
    spec file, allowing you to force an Epoch for your package. The
    Epoch: keyword replaced the older Serial: keyword, which
    semantically behaved similarly.
  </para>
  <para>
    RPM 2.5.7 enforced the previously implied standard that the "-"
    character should not be used within the Version or Release fields in
    the RPM spec file.
  </para>
  <para>
    RPM 2.90 introduced support for signing and verifying RPM package
    files using GPG, the GNU Privacy Guard.
  </para>
  <para>
    RPM 2.91 allowed the usage of Provides: directives that defined
    absolute paths to provided files. Prior to RPM 2.91, Provides: could
    be used only for listing provided capabilities, not for using
    statements like Provides: /path/to/file to indicate provided files.
  </para>
  <para>
    RPM 3.0.2 permitted usage of multiple Provides: lines for the first
    time, eliminating the need to combine all provided capabilities and
    files on the same line in the spec file.
  </para>
  <para>
    RPM 3.0.3 added support for versioned dependencies. Prior to RPM
    3.0.3, spec files could indicate that a package required another
    package or provided a specific capability, but they could not
    indicate the acceptable versions of the required package or which
    version of the capability the package provided.
  </para>
  <para>
    RPM 3.0.4 introduced CompressedFileNames support to RPM. Prior to
    RPM 3.0.4, RPM packaged the absolute paths of all archived files
    within the package file. Package file headers contained statements
    such as
  </para>
  <para>
    fileName #0: /usr/bin/ar
  </para>
  <para>
    fileName #1: /usr/bin/as
  </para>
  <para>
    fileName #2: /usr/bin/gasp
  </para>
  <para>
    fileName #3: /usr/bin/gprof
  </para>
  <para>
    With CompressedFileNames support, the RPM package file header
    instead stores the directory name, then just the base name of files
    within that directory. Package file headers now contain statements
    such as the following for a given directory with a number of files
    within that directory:
  </para>
  <para>
    dirName #0: /usr/bin
  </para>
  <para>
    baseName dirIndex
  </para>
  <para>
    #0 ar 0
  </para>
  <para>
    #1 as 0
  </para>
  <para>
    #2 gasp 0
  </para>
  <para>
    #3 gprof 0
  </para>
  <para>
    Each file entry now holds the file's base name within the directory,
    as well as an index number that refers to the directory entry. Since
    packages typically contain lots of files within the same directory,
    CompressedFileNames support results in significant memory savings
    when processing packages for installation.
  </para>
  <para>
    RPM 3.0.5 added PayloadIsBzip2 support to RPM, allowing the data
    payload of RPM package files to be compressed using bzip2 instead of
    gzip. Even though RPM now supports bzip2 compression of package
    files, this feature is rarely used in practice, since significantly
    more memory and time is required to install bzip2-compressed RPM
    package files than to install gzip-compressed RPM package files. RPM
    3.0.5 also added support to RPM for manipulating existing RPM
    version 4 file format packages; packages produced with RPM 3.0.5 can
    only be RPM version 3 file format, however.
  </para>
  <para>
    RPM 4.0 implemented several significant changes to RPM. RPM 4.0
    created package files using RPM version 4 package file format. RPM
    4.0 also switched from Berkeley db 1.85 to Berkeley db 3.1 as the
    database program used for creation and manipulation of the RPM
    database. The RPM package database file was renamed as well. The db3
    package database file is /var/lib/rpm/Packages, and the older db1
    package database file was /var/lib/rpm/packages.rpm. Changing the
    package database file name allowed old and new versions to co-exist
    if necessary, simplifying upgrades from older RPM releases to the
    new RPM 4.0 release. RPM 4.0 also introduced the
    PayloadFilesHavePrefix feature, changing the way archived files are
    named within the RPM package file. RPM package files contain a cpio
    archive of files. Prior to RPM 4.0, file names in the cpio archive
    were stored without a root prefix. With PayloadFilesHavePrefix, all
    file names within the cpio archive files now have a root prefix,
    such as ./usr/bin/ar. This modification made it possible for RPM
    package files to contain the root directory, “./”. Additional
    sanity-checking was added to the RPM 4.0 spec file parser; beginning
    with 4.0, RPM no longer allows dangling symbolic links that contain
    the BuildRoot. This change eliminates a class of common mistakes
    made when producing RPMs. Finally, RPM 4.0 implicitly generates
    Provides: directives; whenever a package header is read, the
    Provides: directive Provides: %{name} =
    %{epoch}:%{version}-%{release} is automatically generated, ensuring
    that all packages explicitly provide themselves as a capability and
    removing the need to provide self-capabilities within the package
    spec file.
  </para>
  <para>
    RPM 4.0.2 introduced the use of SHA-1 message digests to validate
    RPM header regions.
  </para>
  <para>
    RPM 4.0.3 added the %dev(type,major,minor) spec file directive,
    allowing creation of device nodes. In addition, the %configure spec
    file directive now supported --target and –host, simplifying cross
    compilation when using RPM. The %files directive was extended by
    adding the %exclude subdirective that could be used to exclude files
    from inclusion. Finally, RPM 4.0.3 switched back to creating package
    files in RPM version 3 package file format by default, although it
    still supports RPM version 4 package file format as well.
  </para>
  <para>
    RPM 4.0.4 provided PartialHardlinkSets support. RPM package files
    are sometimes created which contain multiple copies of the same
    file, stored as hard links to save space. Prior to RPM 4.0.4, RPM
    has always treated collections of hard links as an all-or-nothing
    proposition; all hard links were created, or else none were created.
    This behavior posed problems when some hard links in a set were
    tagged with attributes such as %doc or %lang, since rpm commands
    make it possible to install an RPM package file without installing
    any files with %doc attributes. Prior to RPM 4.0.4, doing so would
    break the hard link set, preventing creation of all hard links in
    the set. PartialHardlinkSet corrects this problem by allowing
    successful creation of subsets of the hard link set. RPM 4.0.4 also
    provided automatic generation of Perl module Requires: directives.
    find-requires now parses all packaged Perl scripts, generating any
    determined dependencies. In addition, RPM 4.0.4 provides transaction
    support for RPM.
  </para>
  <para>
    RPM 4.1 adds separate header DSA and RSA signatures, allowing
    verification of RPM package headers.
  </para>
  <para>
    Finally, when considering the RPM features required by your prepared
    package, remember that some required RPM features are specified
    manually within the package spec file, while others are
    automatically added by RPM during the RPM package file build
    process. For example, usage of versioned Requires: directives in a
    spec file will make the resulting RPM package file correctly
    installable only by RPM release 3.0.3 or later. Similarly, the
    preparation of any package using RPM release 4.0 or later will
    automatically produce RPM package files that can only be manipulated
    by releases of RPM that support the PayloadFilesHavePrefix feature.
    In the first case, you chose to produce packages that worked with
    RPM release 3.0.5 or later but not with RPM release 2.5 by including
    a new directive in the package spec file. In the second case,
    however, you did not explicitly produce packages that work only with
    recent RPM releases. The simple fact that you built your RPM package
    using RPM release 4.0 means that you automatically used features
    that only RPM 4.0 and later releases understand. These automatic
    internal requirements are quite common in the later versions; as a
    result, the best practice is to decide the oldest version of RPM
    that you wish to support, then to build all packages using that
    version of RPM, keeping its feature set in mind as you prepare and
    build the packages.
  </para>
</chapter>


--- NEW FILE rpm-guide-rpm-overview.xml ---
<!-- $Id: -->

<chapter id="ch-rpm-overview">
  <title>RPM Overview</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Understanding the package file
      </para>
    </listitem>
    <listitem>
      <para>
        Querying the RPM database
      </para>
    </listitem>
    <listitem>
      <para>
        Running RPM commands
      </para>
    </listitem>
  </itemizedlist>
  <para>
    Working with RPM packages, files, commands, and databases can be
    complicated. There are thousands of files, for hundreds if not
    thousands of packages, installed on your system. You need some way
    to manage it all. The RPM system can help you do that.
  </para>
  <para>
    This chapter provides an overview of the components that make up the
    RPM system for package management: package files, databases, and RPM
    commands.
  </para>
  <sect1>
    <title>Understanding the Package File</title>
    <para>
      RPM provides for installing, upgrading and removing packages.
      Typically, each package is an application and all the necessary
      files associated with that application. For example, the Apache
      Web server comes with a number of configuration files, a large set
      of documentation files, and the Apache server itself. All of this
      fits into one RPM package.
    </para>
    <para>
      One of the main advantages of the RPM system is that each .rpm
      file holds a complete package. For example, the following file
      holds the <filename>xcopilot</filename> package:
    </para>
    <para>
      <filename>xcopilot-0.6.6-3.i386.rpm</filename>
    </para>
    <para>
      Based on the naming conventions discussed in
      <xref linkend="ch-intro-rpm"/>, this package represents
      <filename>xcopilot</filename> package, version 0.6.6, third build
      of an RPM package, for i386 (Intel) architecture systems.
    </para>
    <para>
      With a single command, you can copy an .rpm file to another Linux
      system and install it, getting the complete contents of the
      package, or you can use other commands to remove or update the
      package.
    </para>
    <sect2>
      <title>RPM file format</title>
      <para>
        RPM files hold a number of tagged data items and a payload, the
        files to install on your system. The tagged data items describe
        the package and can contain optional features. For example, the
        NAME tag holds the package name. The optional PRE tag holds a
        pre-installation script, a script that the rpm command runs
        prior to installing the files in the package payload.
      </para>
      <para>
        Under the covers, RPM package files contain four sections. The
        first is a leading identification area that marks the file as an
        RPM package (created with a particular version of the RPM
        system). The remaining sections are the signature, the tagged
        data (called the header), and the payload. Each of these
        sections has important information about the package, although
        the payload section contains the actual content of the package.
      </para>
      <variablelist>
        <varlistentry>
          <term>Signature</term>
          <listitem>
            <para>
              The signature appears after the lead or identifier
              section, which marks the file as an RPM file. Like your
              signature when you sign a check, the RPM signature helps
              verify the integrity of the package. No, the signature
              doesn’t check for bugs in software applications.
              Instead, it ensures that you have downloaded a valid RPM
              archive.
            </para>
            <para>
              The signature works by performing a mathematical function
              on the header and archive sections of the file. The
              mathematical function can be an encryption process, such
              as PGP (Pretty Good Privacy), or a message digest in MD5
              format.
            </para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>Header</term>
          <listitem>
            <para>
              The header contains zero or more tagged blocks of data
              that pertain to the package. The header contains
              information such as copyright messages, version numbers,
              and package summaries.
            </para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>Payload</term>
          <listitem>
            <para>
              The payload section contains the actual files used in the
              package. These files are installed when you install the
              package. To save space, data in the archive section is
              compressed in GNU <command>gzip</command> format.
            </para>
          </listitem>
        </varlistentry>
      </variablelist>
      <para>
        Once uncompressed, the data is in <command>cpio</command>
        format, which is how the <command>rpm2cpio</command> command
        (introduced in the "Other RPM commands" section later in this
        chapter) can do its work.
      </para>
    </sect2>
    <sect2>
      <title>Binary RPMs and Source RPMs</title>
      <para>
        There are two main types of RPM packages: binary (or
        applications) and source. A binary RPM has been compiled for a
        particular architecture. For example, the Apache Web server
        compiled for an Intel Pentium, or i586, architecture won’t
        work on a Sharp Zaurus, which runs an Intel ARM processor. To
        run on both systems, you would need two separate packages: one
        for the Pentium i586 and one for the ARM.
      </para>
      <para>
        In addition to binary RPMs, you can get source code RPMs. These
        RPMs are packages that provide the source code for other
        packages. Sounds kind of circular, doesn’t it?
      </para>
      <sect3>
        <title>binary RPMs</title>
        <para>
          Binary RPMs hold complete applications or libraries of
          functions compiled for a particular architecture. Most binary
          RPMs contain complete applications, such as the Apache Web
          server or the AbiWord word processor. These application binary
          RPMs usually depend on a number of system libraries which are,
          in turn, also provided by binary RPMs.
        </para>
        <note>
          <title>Finding More Software</title>

          <para>
            <xref linkend="ch-management-software"/> covers a number of
            locations where you can find RPM applications galore. Your
            Linux installation CDs are also a great source for
            applications. Most Linux distributions come with more
            applications than you can imagine using.
          </para>
        </note>
        <para>
          Although most binary RPMs are complete applications, others
          provide libraries. For example, the Simple DirectMedia Layer
          library (SDL), which provides really cool graphics for many
          games, can be packaged as an RPM file. A number of programs,
          mostly games, use this library for enhanced multimedia such as
          rich graphics. RPMs that provide libraries allow multiple
          applications to share the same library. Typically, the
          libraries are packaged into separate RPMs from the
          applications.
        </para>
        <para>
          In addition to binary RPMs that hold applications or libraries
          compiled for a particular architecture, RPM supports the
          concept of platform-independent binary RPMs. These
          platform-independent RPMs, called noarch as a shorted form of
          “no architecture” dependencies, provide applications or
          libraries that are not dependent on any platform. Applications
          written in Perl, Python, or other scripting languages often do
          not depend on code compiled for a particular architecture. In
          addition, compiled Java applications are usually free of
          platform dependencies.
        </para>
      </sect3>
    </sect2>
    <sect2>
      <title>Source RPMs</title>
      <para>
        The <filename>xcopilot</filename> package, mentioned previously,
        contains the <filename>xcopilot</filename> application used for
        synchronization with Palm handheld devices. The source code used
        to create this application is stored in an
        <filename>xcopilot</filename> source RPM, for example:
      </para>
      <para>
        <filename>xcopilot-0.6.6-3.src.rpm</filename>
      </para>
      <para>
        By convention, source RPMs have a file name ending in .src.rpm.
      </para>
      <para>
        Source RPMs should contain all the commands, usually in scripts,
        necessary to recreate the binary RPM. Having a source RPM means
        that you can recreate the binary RPM at any time. This is a very
        important goal of the RPM system.
      </para>
      <note>
        <title>Source RPMs and Open Source Licencing</title>

        <para>
          Source RPMs have nothing to do with open-source software
          licenses. Linux is famous for being an open-source operating
          system. In RPM terms, that means the source code for the Linux
          kernel and most Linux applications are freely available as
          source RPMs. But you can also make source RPMs for proprietary
          programs. The key issue is that you are unlikely to distribute
          the source RPMs for proprietary packages.
        </para>

        <para>
          Furthermore, a number of open-source applications are not
          available as source RPMs. That's a shame, since source RPMs
          would make these applications easier to install.
        </para>
      </note>
      <para>
        While source RPMs hold the commands necessary to create the
        binary RPM, there may be differences in your Linux environment
        that would result in rebuilding a binary RPM that is different
        from the original binary RPM. For example, the compile scripts
        for some packages may add in optional code depending on which
        libraries or which versions of libraries are found on your
        system. <xref linkend="ch-packaging-guidelines"/> covers many
        issues in creating RPMs, and <xref linkend="ch-other-linuxes"/>
        and <xref linkend="ch-other-os"/> cover issues related to other
        versions of Linux and other operating systems, respectively. If
        you follow the guidelines when making your own RPMs, you should
        result in source RPMs that reproduce binary RPMs as consistently
        as possible.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Querying the RPM Database</title>
    <para>
      The RPM database holds information about all the RPM packages
      installed on your system. You can use this database to query what
      is installed, to help determine if you have the latest versions of
      software, and to verify that your system is properly set up, at
      least from a packaging point of view.
    </para>
    <para>
      The RPM database itself is stored in the directory
      <filename>/var/lib/rpm/</filename>, and should contain files like
      the following:
    </para>
    <itemizedlist>
      <listitem>
        <para>
          <filename>Basenames</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>Conflictname</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>__db.001</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>__db.002</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>__db.003</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>Dirnames</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>Filemd5s</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>Group</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>Installtid</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>Name</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>Packages</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>Providename</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>Provideversion</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>Pubkeys</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>Requirename</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>Requireversion</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>Sha1header</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>Sigmd5</filename>
        </para>
      </listitem>
      <listitem>
        <para>
          <filename>Triggername</filename>
        </para>
      </listitem>
    </itemizedlist>
    <note>
      <title>The RPM Database</title>

      <para>
        <xref linkend="ch-using-rpm-db"/> covers the database in more
        detail.
      </para>
    </note>
    <para>
      These files make up the RPM database. The file
      <filename>__db.001</filename> and similar files are lock files
      used by the RPM system. The other files are databases in Berkeley
      DB format. The most important file is
      <filename>Packages</filename>. The <filename>Packages</filename>
      file contains the header tag information for each package indexed
      by an index number for each package. This number slowly grows with
      time.
    </para>
    <para>
      The other files, such as <filename>Name</filename>,
      <filename>Providename</filename>, and <filename>Group</filename>,
      exist to speed access to particular types of information. Treat
      your RPM database with care. Back up the files, especially after
      upgrading, installing, or removing packages.
    </para>
    <note>
      <title>Recreating The RPM Database</title>

      <para>
        Only the <filename>Packages</filename> file is essential. You
        can recreate the rest of the files using the <command>rpm
        <option>--rebuilddb</option></command> command, introduced in
        <xref linkend="ch-using-rpm-db"/>.
      </para>
    </note>
  </sect1>
  <sect1>
    <title>Running RPM Commands</title>
    <para>
      The primary RPM command is simply <command>rpm</command>. One of
      the original goals of the RPM system is providing ease of use. In
      support of this goal, just about everything you want to do with
      the RPM system can be done with this one command. For most usage,
      the command-line parameters to the <command>rpm</command> command
      determine the actions it should take.
    </para>
    <sect2>
      <title>Working with the <command>rpm</command> command</title>
      <para>
        The <command>rpm</command> command performs the most common
        package-management functions, along with a host of uncommon
        functions as well. The table below lists the main operations you
        can perform with the <command>rpm</command> command and the
        command-line options to specify the given operations.
      </para>
      <table id="tb-rpm-operations">
        <title>The main <command>rpm</command> operations</title>
        <tgroup cols="3">
          <colspec colnum="1" colname="Operation"/>
          <colspec colnum="2" colname="Short Option"/>
          <colspec colnum="3" colname="Long Option"/>
          <thead>
            <row>
              <entry>Operation</entry>
              <entry>Short Option</entry>
              <entry>Long Option</entry>
            </row>
          </thead>
          <tbody>
            <row>
              <entry>
                  Upgrade/install
              </entry>
              <entry>
                  -U
              </entry>
              <entry>
                  --upgrade
              </entry>
            </row>
            <row>
              <entry>
                  Install
              </entry>
              <entry>
                  -I
              </entry>
              <entry>
                  --install
              </entry>
            </row>
            <row>
              <entry>
                  Remove
              </entry>
              <entry>
                  -e
              </entry>
              <entry>
                  --erase
              </entry>
            </row>
            <row>
              <entry>
                  Query
              </entry>
              <entry>
                  -q
              </entry>
              <entry>
                  --query
              </entry>
            </row>
            <row>
              <entry>
                  Verify
              </entry>
              <entry>-V
              </entry>
              <entry>
                  --verify
              </entry>
            </row>
            <row>
              <entry>
                  Check signature
              </entry>
              <entry>
                  -K
              </entry>
              <entry>
                  --checksig
              </entry>
            </row>
            <row>
              <entry>
                  Freshen (upgrade) already-installed package
              </entry>
              <entry>
                  -F
              </entry>
              <entry>
                  --freshen
              </entry>
            </row>
            <row>
              <entry>
                  Initialize database
              </entry>
              <entry>
                  None
              </entry>
              <entry>
                  --initdb
              </entry>
            </row>
            <row>
              <entry>
                  Rebuild database
              </entry>
              <entry>
                  None
              </entry>
              <entry>
                  --rebuilddb
              </entry>
            </row>
          </tbody>
        </tgroup>
      </table>
      <para>
        Using this table as a guide, you can explore the options to the
        <command>rpm</command> command. To install or upgrade a package,
        use the <option>-U</option> command-line option:
      </para>
<screen>
<userinput>rpm -U <replaceable>filename.rpm</replaceable></userinput>
</screen>
      <para>
        For example, to install the <filename>xcopilot</filename> RPM
        used as an example in this chapter, run the following command:
      </para>
<screen>
<userinput>rpm -U <replaceable>xcopilot-0.6.6-3.i386.rpm</replaceable></userinput>
</screen>
      <para>
        To get extra feedback, you can use a command like the following,
        with the <option>-h</option> and <option>-v</option> options in
        conjunction with the <option>–U</option> option:
      </para>
<screen>
<userinput>rpm -Uhv <replaceable>xcopilot-0.6.6-3.i386.rpm</replaceable></userinput>
</screen>
      <para>
        When you run this command you will see more output than the
        default, which is no output unless there are errors. With the
        <option>–h</option> option, the <command>rpm</command> command
        will print a series of hash marks, #, to provide feedback that
        the command is still running. With the <option>–v</option>
        option, the <command>rpm</command> command provides more verbose
        messages.
      </para>
      <note>
        <title>Installing a Package</title>

        <para>
          The most common command to install a package is:
        </para>
<screen>
<userinput>rpm -Uhv <replaceable>package_file.rpm</replaceable></userinput>
</screen>
        <para>
          This command upgrades a package with extra output. If the
          package has not been installed, this command installs the
          package. See <xref linkend="ch-using-rpm"/> for more on
          upgrading and installing.
        </para>
      </note>
      <para>
        To remove a package (called erase in RPM terminology), use the
        <option>–e</option> command-line option:
      </para>
<screen>
<userinput>rpm –e <replaceable>package_name</replaceable></userinput>
</screen>
      <note>
        <title>Using File Extensions</title>

        <para>
          Notice that you install a package file using the file name
          that ends in .rpm, but uninstall or erase a package without
          the .rpm extension. This is because you install RPM files, but
          once installed, you work with the installed packages. The file
          name and the package name do not have to correspond, but
          typically (and sanely) they have the same base name.
        </para>
      </note>
      <para>
        To list every RPM package installed on your system, use a
        command like the following.
      </para>
<screen>
<userinput>rpm –qa</userinput>
</screen>
      <para>
        Expect to wait while this command completes. Most Linux systems
        have numerous packages installed, which will result in many
        lines of output. To better see the output, you can pipe this
        command to the more command, as shown following:
      </para>
<screen>
<userinput>rpm –qa | more</userinput>
</screen>
      <para>
        You will then see the package listing one screen at a time.
      </para>
      <note>
        <title><command>rpm</command> Options</title>

        <para>
          <xref linkend="ch-command-reference"/> lists all the options
          for the <command>rpm</command> command.
        </para>
      </note>
    </sect2>
    <sect2>
      <title>Other RPM commands</title>
      <para>
        In addition to <command>rpm</command>, the RPM system includes a
        few more commands, including <command>rpmbuild</command> and
        <command>rpm2cpio</command>.
      </para>
      <para>
        The <command>rpmbuild</command> command helps build RPM
        packages. I describe its usage in depth in Part II of this book.
      </para>
      <para>
        The <command>rpm2cpio</command> command exports an RPM package
        file int the format that the <command>cpio</command> command
        expects. The <filename>cpio</filename> command works with many
        tape-backup packages. You can also take advantage of the fact
        that <filename>cpio</filename> can list the individual files in
        a <filename>cpio</filename> archive or extract files. To list
        the files in an RPM package, use a command like the following:
      </para>
<screen>
<userinput>rpm2cpio <replaceable>package_file.rpm</replaceable> | cpio –t</userinput>
</screen>
      <para>
        For example, the following command lists all the files in the
        <filename>xcopilot</filename> package:
      </para>
<screen>
<userinput>rpm2cpio <replaceable>xcopilot-0.6.6-3.i386.rpm</replaceable> | cpio –t</userinput>
</screen>
      <para>
        To display:
      </para>
<screen>
<computeroutput>
./etc/X11/applink/Applications/xcopilot.desktop
./usr/bin/xcopilot
./usr/doc/xcopilot-0.6.6
./usr/doc/xcopilot-0.6.6/README
./usr/include/X11/pixmaps/xcopilot.xpm
./usr/include/X11/pixmaps/xcopilot2.xpm
3120 blocks
</computeroutput>
</screen>
      <para>
        The <command>rpm2cpio</command> command can also help if you
        want to extract a single file from the RPM package, using the
        <command>cpio <option>–ivd</option></command> command-line
        options, as follows:
      </para>
<screen>
 <userinput>rpm2cpio <replaceable>xcopilot-0.6.6-3.i386.rpm</replaceable> | cpio –ivd
        <replaceable>usr/doc/xcopilot-0.6.6/README</replaceable></userinput>
</screen>
      <para>
        This command will output local
        <filename>usr/doc/xcopilot-0.6.6/</filename> subdirectories and
        the <filename>README</filename> file located under
        <filename>usr/doc/xcopilot-0.6.6/</filename>.
      </para>
      <para>
        The <option>–i</option> option tells <command>cpio</command>
        to extract files. The <option>–d</option> option tells
        <command>cpio</command> to make any local subdirectories as
        needed (<filename>usr/doc/xcopilot-0.6.6/</filename>, in this
        example), and the <option>–v</option> option asks
        <command>cpio</command> to politely output verbose messages
        about what it does. Of course, verbose is in the eye of the
        beholder; with many Unix and Linux commands, verbose output is
        still somewhat terse.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      The RPM files, the RPM database, and the RPM commands are the
      primary components that make up the RPM system. This chapter
      introduces you to the format and types of RPM files, the
      importance of maintaining the database, and the basic rpm command.
    </para>
    <para>
      The next chapter covers the most frequently used RPM commands.
      These commands allow you to install, uninstall, and update RPM
      packages.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-rpmbuild.xml ---
<!-- $Id: -->

<chapter id="ch-rpmbuild">
  <title>Controlling the Build with <command>rpmbuild</command></title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Building with the <command>rpmbuild</command> command
      </para>
    </listitem>
    <listitem>
      <para>
        Building RPMs without an external spec file
      </para>
    </listitem>
    <listitem>
      <para>
        Working with source RPMs
      </para>
    </listitem>
    <listitem>
      <para>
        Optimizing builds
      </para>
    </listitem>
    <listitem>
      <para>
        Signing built RPMs
      </para>
    </listitem>
  </itemizedlist>
  <para>
    The preceding chapters in this Part cover details on how to put
    together RPMs. This chapter rounds out the discussion by delving
    into more details on the rpmbuild command.
  </para>
  <para>
    You can customize how rpmbuild creates RPMs, and you can use RPM
    commands to test and debug your package.
  </para>
  <sect1>
    <title>Building RPMs with the rpmbuild Command</title>
    <para>
      The rpmbuild command provides a workhorse command for building
      RPMs in all sorts of ways. The basic syntax, as shown in <xref linkend="ch-creating-rpms"/>, is:
    </para>
    <para>
      rpmbuild -bBuildStage spec_file
    </para>
    <para>
      The BuildStage is a letter, such as c, to prepare and compile the
      application, executing through the %build section, or i, to
      execute through the %install section. This allows you a good deal
      of flexibility for building the entire RPM or stopping at some
      point prior to a full build.
    </para>
    <para>
      There’s more to the rpmbuild command, though. Quite a few
      additional options allow you to further customize the build.
    </para>
    <para>
      Note
    </para>
    <para>
      As mentioned in <xref linkend="ch-creating-rpms"/> , previous versions of the RPM system
      used the rpm command with a -b, for build, option. This option is
      no longer supported. Use the rpmbuild command to build RPMs.
    </para>
    <sect2>
      <title>Customizing the build</title>
      <para>
        You can customize the rpmbuild command with the options listed
        in Table 12-1.
      </para>
      <para>
        Table 12-1 Extra build options for the rpmbuild command
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  Option
                </para>
              </entry>
              <entry>
                <para>
                  Usage
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --buildroot directory
                </para>
              </entry>
              <entry>
                <para>
                  Override the default root directory for building with
                  directory, generally not very useful since most
                  packages already name a buildroot
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --clean
                </para>
              </entry>
              <entry>
                <para>
                  Remove the build tree after building
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --nobuild
                </para>
              </entry>
              <entry>
                <para>
                  Just test the spec file and do not run the build
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --rmsource
                </para>
              </entry>
              <entry>
                <para>
                  Remove the sources after the build
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --rmspec
                </para>
              </entry>
              <entry>
                <para>
                  Remove the spec file after the build
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --short-circuit
                </para>
              </entry>
              <entry>
                <para>
                  With the -bc or -bi options, jump directly to the
                  given stage and resume the build from that stage
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --sign
                </para>
              </entry>
              <entry>
                <para>
                  Sign the package with a GPG signature
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --target platform
                </para>
              </entry>
              <entry>
                <para>
                  Build for the given platform. May not work if you
                  don't have the other platform build commands, such as
                  cross compilers, set up. Can work for Intel platforms
                  with i386, i686, and so on.
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
    </sect2>
    <sect2>
      <title>Testing the build</title>
      <para>
        One of the most useful options is --nobuild, which tells the
        rpmbuild command to not build anything. This may seem silly, but
        the --nobuild option is very useful for testing whether your
        RPMs can be built. With the --nobuild option, the rpmbuild
        command parses the spec file and checks for errors, but does not
        run any of the build stages.
      </para>
      <para>
        The --buildroot allows you to specify a different top-level
        directory for building, overriding the BuildRoot tag in the spec
        file. This means you can build in a separate location, which is
        helpful in case there are mistakes. Using a separate directory
        means the build won’t get mixed with anything else in the
        build root directory.
      </para>
    </sect2>
    <sect2>
      <title>Debugging the build</title>
      <para>
        The --short-circuit option tells the rpmbuild command to restart
        at a particular location in the build. Rather than working its
        way through all the steps up to the build stage you ask for, the
        --short-circuit option allows the rpmbuild command to restart
        just at the step you ask for.
      </para>
      <para>
        Note
      </para>
      <para>
        This works with the -bc and -bi options only, as well as the -tc
        and -ti options covered later in this chapter.
      </para>
      <para>
        For example, if you run the rpmbuild -bc command to stop after
        the %build section, you can use the --short-circuit option to
        restart the build at the %build section. If you found a problem
        in the %build section and corrected it, you can quickly get
        going again by restarting the build at the %build section rather
        than extracting all the sources yet again.
      </para>
      <para>
        This option is most useful when you are compiling a package, hit
        an error, and fix that error. Without the --short-circuit
        option, you’ll likely end up spending a lot of time
        recompiling the code you have already compiled.
      </para>
      <para>
        During normal development of an RPM package, you will likely
        execute each build section, one at a time, stop, fix any errors
        and restart where you left off. You’ll go through this cycle a
        number of times before the RPM finally builds right.
      </para>
      <para>
        Warning
      </para>
      <para>
        Never distribute an RPM made with the --short-circuit option.
        Instead, once you have everything working, start from scratch
        and rebuild the RPM. This is to avoid any problems with a
        partially-created RPM.
      </para>
    </sect2>
    <sect2>
      <title>Cleaning up</title>
      <para>
        The --clean option tells the rpmbuild command to remove the
        build tree when complete. This helps ensure that the next time
        you run the rpmbuild command, you are starting from a known
        situation.
      </para>
      <para>
        For example:
      </para>
      <para>
        $ rpmbuild --clean /usr/src/redhat/SPECS/jikes.spec
      </para>
      <para>
        Executing(--clean): /bin/sh -e /var/tmp/rpm-tmp.98247
      </para>
      <para>
        + umask 022
      </para>
      <para>
        + cd /usr/src/redhat/BUILD
      </para>
      <para>
        + rm -rf jikes-1.17
      </para>
      <para>
        + exit 0
      </para>
      <para>
        You can use the --clean option alone, as shown previously, or in
        concert with another option such as -bi to build and install a
        binary RPM. In the latter case, the rpmbuild command will clean
        the built files after the rest of the command finishes.
      </para>
      <para>
        Similarly, the --rmsource option tells the rpmbuild command to
        remove the sources after completing the command. You can call
        this option with another option, such as -bi for building and
        installing a binary RPM (and then removing the sources), or
        alone on the command line to remove the sources only.
      </para>
      <para>
        For example:
      </para>
      <para>
        rpmbuild --rmsource jikes.spec
      </para>
      <para>
        Note
      </para>
      <para>
        The abbreviation rm is short for remove. It comes from the Linux
        rm command, used for removing files.
      </para>
      <para>
        The --rmspec option tells the rpmbuild command to remove the
        spec file when done with the command. As with the --rmsource
        option, you can use the --rmspec option in conjunction with
        another rpmbuild option or on its own to just remove the spec
        file.
      </para>
      <para>
        For example:
      </para>
      <para>
        rpmbuild --rmspec jikes.spec
      </para>
      <para>
        Warning
      </para>
      <para>
        The file you are removing with this command is the spec file you
        are passing to the command. Be careful, because you cannot undo
        this operation and you have now lost your spec file, except
        inside your source package.
      </para>
    </sect2>
    <sect2>
      <title>Building for other platforms</title>
      <para>
        The --target option tells the rpmbuild command to build a
        package for another platform. You need to pass the name of the
        platform. For example:
      </para>
      <para>
        rpmbuild -bi --target i486-redhat-linux
      </para>
      <para>
        The basic format is:
      </para>
      <para>
        cpu-vendor-os
      </para>
      <para>
        For example, i686-redhat-linux specifies a 686 CPU with &RH;
        Linux. Other CPUs include ppc for PowerPC and sparc for Sun
        SPARC.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        The --target option sets the target architecture at build time.
        <xref linkend="ch-using-rpm"/>  covers how you can use the --ignoreos and --ignorearch
        options when installing RPMs to ignore the operating system and
        architecture that is flagged within the RPM. Of course, this
        works only if you are installing on a compatible architecture.
      </para>
      <para>
        On the surface level, the --target option overrides some of the
        macros in the spec file, %_target, %_target_arch, and
        %_target_os. This flags the RPM for the new target platform.
      </para>
      <para>
        Under the covers, setting the architecture macros is not enough.
        You really cannot create a PowerPC executable, for example, on
        an Intel-architecture machine, unless you have a PowerPC cross
        compiler, a compiler that can make PowerPC executables.
      </para>
      <para>
        Warning
      </para>
      <para>
        Set the target with care. Make sure you can really build
        executable programs for that architecture.
      </para>
      <para>
        If you try to compile a system that uses the GNU configure
        system to configure the build, your target will likely be
        ignored. For example, if you try to build the aforementioned
        jikes package with a target of ppc-ibm-aix, to specify IBM’s
        UNIX, called AIX, on a PowerPC architecture, you will see the
        target ignored as the configure system detects that it's running
        on Linux on an i686 architecture.
      </para>
      <para>
        For example:
      </para>
      <para>
        $ rpmbuild -bc --target ppc-ibm-aix
        /usr/src/redhat/SPECS/jikes.spec
      </para>
      <para>
        Building target platforms: ppc-ibm-aix
      </para>
      <para>
        Building for target ppc-ibm-aix
      </para>
      <para>
        Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.94955
      </para>
      <para>
        + umask 022
      </para>
      <para>
        + cd /usr/src/redhat/BUILD
      </para>
      <para>
        + LANG=C
      </para>
      <para>
        + export LANG
      </para>
      <para>
        + cd /usr/src/redhat/BUILD
      </para>
      <para>
        + rm -rf jikes-1.17
      </para>
      <para>
        + /usr/bin/gzip -dc /usr/src/redhat/SOURCES/jikes-1.17.tar.gz
      </para>
      <para>
        + tar -xf -
      </para>
      <para>
        + STATUS=0
      </para>
      <para>
        + '[' 0 -ne 0 ']'
      </para>
      <para>
        + cd jikes-1.17
      </para>
      <para>
        ++ /usr/bin/id -u
      </para>
      <para>
        + '[' 500 = 0 ']'
      </para>
      <para>
        ++ /usr/bin/id -u
      </para>
      <para>
        + '[' 500 = 0 ']'
      </para>
      <para>
        + /bin/chmod -Rf a+rX,g-w,o-w .
      </para>
      <para>
        + exit 0
      </para>
      <para>
        Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.15710
      </para>
      <para>
        + umask 022
      </para>
      <para>
        + cd /usr/src/redhat/BUILD
      </para>
      <para>
        + cd jikes-1.17
      </para>
      <para>
        + LANG=C
      </para>
      <para>
        + export LANG
      </para>
      <para>
        + ./configure CXXFLAGS=-O3 --prefix=/tmp/jikesrpm/usr
      </para>
      <para>
        checking for a BSD-compatible install... /usr/bin/install -c
      </para>
      <para>
        checking whether build environment is sane... yes
      </para>
      <para>
        checking for gawk... gawk
      </para>
      <para>
        checking whether make sets ${MAKE}... yes
      </para>
      <para>
        checking whether to enable maintainer-specific portions of
        Makefiles... no
      </para>
      <para>
        checking build system type... i686-pc-linux-gnu
      </para>
      <para>
        checking host system type... i686-pc-linux-gnu
      </para>
      <para>
        checking for g++... g++
      </para>
      <para>
        As you can see, the command starts out with the target as the
        platform, but the configure script soon overrides that, as shown
        at the end of the truncated output.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Building RPMs Without an External Spec File</title>
    <para>
      Most of the options for the rpmbuild command require an RPM spec
      file. This file defines all the necessary parameters for the RPM
      to build. If you’ve downloaded an application, though, you may
      not have all the information needed to build a spec file. In
      addition, writing the spec file is the most time-consuming task
      when building RPMs. If you are lucky, the provider of a given
      application may have already created a spec file and included the
      spec file within the source distribution.
    </para>
    <sect2>
      <title>Options for working with tar archives</title>
      <para>
        A special set of options aims toward building RPMs with spec
        files stored in tar archives, also called tarballs. Tarballs are
        files combined with the tar (tape archiver) utility and then
        optionally compressed, usually with the gzip command. Because
        this format is used so often for UNIX and Linux software, you
        can use a set of -t options to the rpmbuild command that mimic
        the -b options.
      </para>
      <para>
        The basic syntax follows:
      </para>
      <para>
        rpmbuild -tBuildStage compressed_tar_archive
      </para>
      <para>
        The -t option is a lot like the -b option covered in <xref linkend="ch-creating-rpms"/> ,
        except -t tells rpmbuild to build an RPM from a compressed tar
        archive instead of from an RPM spec file. You still need a spec
        file. These commands just assume that the spec file is located
        within the tar archive. The extra BuildStage option is a special
        code that tells the rpmbuild command how far to go when
        building. Table 12-2 lists these options:
      </para>
      <para>
        Table 12-2 Options for building with rpmbuild with tar archives
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  Option
                </para>
              </entry>
              <entry>
                <para>
                  Usage
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  -ta
                </para>
              </entry>
              <entry>
                <para>
                  Build all, both a binary and source RPM
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  -tb
                </para>
              </entry>
              <entry>
                <para>
                  Build a binary RPM
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  -tc
                </para>
              </entry>
              <entry>
                <para>
                  Stop after the %build section
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  -tp
                </para>
              </entry>
              <entry>
                <para>
                  Stop after the %prep section
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  -ti
                </para>
              </entry>
              <entry>
                <para>
                  Stop after the %install section
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  -tl
                </para>
              </entry>
              <entry>
                <para>
                  Check the listing of files for the RPM
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  -ts
                </para>
              </entry>
              <entry>
                <para>
                  Build a source RPM only
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
      <para>
        Note
      </para>
      <para>
        These command-line options work with a tar archive or a
        compressed tar archive.
      </para>
    </sect2>
    <sect2>
      <title>The expected archive structure</title>
      <para>
        To build a package this way, the tar archive must have enough of
        an expected structure, such as a configure script and a Makefile
        with the expected make targets. The most crucial element is that
        the tar archive must have the package spec file.That’s because
        the rpmbuild command doesn’t know how to build every program
        in the universe. Instead, rpmbuild expects to find a spec file
        to tell it what to do. If you see an error like the following,
        then your tar archive likely is missing the spec file:
      </para>
      <para>
        $ rpmbuild -tc vixie-cron*tar.gz
      </para>
      <para>
        error: Name field must be present in package: (main package)
      </para>
      <para>
        error: Version field must be present in package: (main package)
      </para>
      <para>
        error: Release field must be present in package: (main package)
      </para>
      <para>
        error: Summary field must be present in package: (main package)
      </para>
      <para>
        error: Group field must be present in package: (main package)
      </para>
      <para>
        error: License field must be present in package: (main package)
      </para>
      <para>
        These errors show expected tags from the missing spec file.
      </para>
      <para/>
      <para/>
    </sect2>
  </sect1>
  <sect1>
    <title>Working with Source RPMs</title>
    <para>
      Most of your work with the rpmbuild command will likely be to
      create binary RPMs after you have the sources for an application
      and a spec file. You can also get a lot of mileage out of source
      RPMs, whether you build them or download them.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      <xref linkend="ch-specfiles"/>  covers the spec file in depth.
    </para>
    <para>
      Because they are RPMs themselves, source RPMs act like other RPMs.
      For example, you can use the rpm -i command to install a source
      RPM. This installs the sources provided by the source RPM, not the
      actual application. Normally, when you install a source RPM on a
      &RHL; system, the package gets installed into
      /usr/src/redhat.
    </para>
    <para>
      Note
    </para>
    <para>
      This directory is obviously specific to &RHL;. On other
      Linux distributions, you'll likely see directories such as
      /usr/src/OpenLinux for SCO (formerly Caldera) OpenLinux.
    </para>
    <para>
      Installing a source RPM is not exactly the same as installing a
      binary RPM. For example, the rpm command does not update the RPM
      database when you install a source RPM. In addition, listing the
      files in a source RPM only shows the relative paths, not the full
      paths.
    </para>
    <para>
      Once installation is complete, you can use the rpmbuild command to
      create a binary RPM from the sources in the source RPM, using the
      -b command-line options introduced in <xref linkend="ch-creating-rpms"/> . The next sections
      show more shortcuts with source RPMs.
    </para>
    <sect2>
      <title>Rebuilding binary RPMS from source RPMs</title>
      <para>
        As a shortcut, you do not have to install a source RPM to create
        a binary RPM. Instead, you can build the binary RPM directory
        using the --rebuild option.
      </para>
      <para>
        The --rebuild option tells the rpmbuild command to rebuild a
        binary RPM from a source RPM file. The basic syntax is:
      </para>
      <para>
        rpmbuild --rebuild package.src.rpm
      </para>
      <para>
        This command builds a binary RPM out of a source RPM with a
        minimum of fuss. For example:
      </para>
      <para>
        $ rpmbuild --rebuild unix2dos-2.2-17.src.rpm
      </para>
      <para>
        Installing unix2dos-2.2-17.src.rpm
      </para>
      <para>
        Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.15828
      </para>
      <para>
        + umask 022
      </para>
      <para>
        + cd /usr/src/redhat/BUILD
      </para>
      <para>
        + LANG=C
      </para>
      <para>
        + export LANG
      </para>
      <para>
        + cd /usr/src/redhat/BUILD
      </para>
      <para>
        + rm -rf unix2dos-2.2
      </para>
      <para>
        + /bin/mkdir -p unix2dos-2.2
      </para>
      <para>
        + cd unix2dos-2.2
      </para>
      <para>
        + /usr/bin/gzip -dc /usr/src/redhat/S
        OURCES/unix2dos-2.2.src.tar.gz
      </para>
      <para>
        + tar -xf -
      </para>
      <para>
        + STATUS=0
      </para>
      <para>
        + '[' 0 -ne 0 ']'
      </para>
      <para>
        ++ /usr/bin/id -u
      </para>
      <para>
        + '[' 500 = 0 ']'
      </para>
      <para>
        ++ /usr/bin/id -u
      </para>
      <para>
        + '[' 500 = 0 ']'
      </para>
      <para>
        + /bin/chmod -Rf a+rX,g-w,o-w .
      </para>
      <para>
        + echo 'Patch #0 (unix2dos-mkstemp.patch):'
      </para>
      <para>
        Patch #0 (unix2dos-mkstemp.patch):
      </para>
      <para>
        + patch -p1 -b --suffix .sec -s
      </para>
      <para>
        + echo 'Patch #1 (unix2dos-2.2-segfault.patch):'
      </para>
      <para>
        Patch #1 (unix2dos-2.2-segfault.patch):
      </para>
      <para>
        + patch -p1 -b --suffix .segf -s
      </para>
      <para>
        + echo 'Patch #2 (unix2dos-2.2-manpage.patch):'
      </para>
      <para>
        Patch #2 (unix2dos-2.2-manpage.patch):
      </para>
      <para>
        + patch -p1 -b --suffix .man -s
      </para>
      <para>
        + perl -pi -e 's,^#endif.*,#endif,g;s,^#else.*,#else,g'
        unix2dos.c unix2dos.h
      </para>
      <para>
        + exit 0
      </para>
      <para>
        Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.60650
      </para>
      <para>
        + umask 022
      </para>
      <para>
        + cd /usr/src/redhat/BUILD
      </para>
      <para>
        + cd unix2dos-2.2
      </para>
      <para>
        + LANG=C
      </para>
      <para>
        + export LANG
      </para>
      <para>
        + gcc -O2 -march=i386 -mcpu=i686 -ounix2dos unix2dos.c
      </para>
      <para>
        + exit 0
      </para>
      <para>
        Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.35128
      </para>
      <para>
        + umask 022
      </para>
      <para>
        + cd /usr/src/redhat/BUILD
      </para>
      <para>
        + cd unix2dos-2.2
      </para>
      <para>
        + LANG=C
      </para>
      <para>
        + export LANG
      </para>
      <para>
        + rm -rf /var/tmp/unix2dos-root
      </para>
      <para>
        + mkdir -p /var/tmp/unix2dos-root/usr/bin /var/tmp/unix2dos-
      </para>
      <para>
        root/usr/share/man/man1
      </para>
      <para>
        + install -m755 unix2dos /var/tmp/unix2dos-root/usr/bin
      </para>
      <para>
        + install -m444 unix2dos.1
        /var/tmp/unix2dos-root/usr/share/man/man1
      </para>
      <para>
        + /usr/lib/rpm/redhat/brp-compress
      </para>
      <para>
        + /usr/lib/rpm/redhat/brp-strip
      </para>
      <para>
        + /usr/lib/rpm/redhat/brp-strip-comment-note
      </para>
      <para>
        Processing files: unix2dos-2.2-17
      </para>
      <para>
        Executing(%doc): /bin/sh -e /var/tmp/rpm-tmp.12033
      </para>
      <para>
        + umask 022
      </para>
      <para>
        + cd /usr/src/redhat/BUILD
      </para>
      <para>
        + cd unix2dos-2.2
      </para>
      <para>
        + DOCDIR=/var/tmp/unix2dos-root/usr/share/doc/unix2dos-2.2
      </para>
      <para>
        + export DOCDIR
      </para>
      <para>
        + rm -rf /var/tmp/unix2dos-root/usr/share/doc/unix2dos-2.2
      </para>
      <para>
        + /bin/mkdir -p
        /var/tmp/unix2dos-root/usr/share/doc/unix2dos-2.2
      </para>
      <para>
        + cp -pr COPYRIGHT
        /var/tmp/unix2dos-root/usr/share/doc/unix2dos-2.2
      </para>
      <para>
        + exit 0
      </para>
      <para>
        Finding Provides: /usr/lib/rpm/find-provides
      </para>
      <para>
        Finding Requires: /usr/lib/rpm/find-requires
      </para>
      <para>
        PreReq: rpmlib(PayloadFilesHavePrefix) <= 4.0-1
        rpmlib(CompressedFileNames)
      </para>
      <para>
        <= 3.0.4-1
      </para>
      <para>
        Requires(rpmlib): rpmlib(PayloadFilesHavePrefix) <= 4.0-1
      </para>
      <para>
        rpmlib(CompressedFileNames) <= 3.0.4-1
      </para>
      <para>
        Requires: libc.so.6 libc.so.6(GLIBC_2.0) libc.so.6(GLIBC_2.1)
      </para>
      <para>
        Checking for unpackaged file(s): /usr/lib/rpm/check-files
        /var/tmp/unix2dos-root
      </para>
      <para>
        Wrote: /usr/src/redhat/RPMS/i386/unix2dos-2.2-17.i386.rpm
      </para>
      <para>
        Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.47653
      </para>
      <para>
        + umask 022
      </para>
      <para>
        + cd /usr/src/redhat/BUILD
      </para>
      <para>
        + cd unix2dos-2.2
      </para>
      <para>
        + rm -rf /var/tmp/unix2dos-root
      </para>
      <para>
        + exit 0
      </para>
      <para>
        Executing(--clean): /bin/sh -e /var/tmp/rpm-tmp.47653
      </para>
      <para>
        + umask 022
      </para>
      <para>
        + cd /usr/src/redhat/BUILD
      </para>
      <para>
        + rm -rf unix2dos-2.2
      </para>
      <para>
        + exit 0
      </para>
      <para>
        With the --rebuild option, the rpmbuild command installs the
        source RPM for you and then performs the preparation, compile,
        and installation stages of building a binary RPM. Unless there
        are errors, you should have a new binary RPM file.
      </para>
      <para>
        When complete, the rpmbuild --rebuild command cleans out the
        built files in the build directory, as if the --clean option
        were used. The rpmbuild --rebuild command also removes the
        installed sources and spec file upon completion.
      </para>
    </sect2>
    <sect2>
      <title>Recompiling binaries from source RPMs</title>
      <para>
        If you just want to recompile the files in a source RPM, you can
        use the --recompile option. The --recompile option tells the
        rpmbuild command to recompile the binary application from a
        source RPM.
      </para>
      <para>
        For example:
      </para>
      <para>
        rpmbuild --recompile package.src.rpm
      </para>
      <para>
        This is the same as installing the source RPM and then running
        rpmbuild -bc --clean with the package spec file.
      </para>
      <para>
        Note
      </para>
      <para>
        There is no difference between --recompile and --rebuild in RPM
        4.1. RPM 4.2 fixes this problem.
      </para>
      <para/>
      <para/>
    </sect2>
    <sect2>
      <title>SRPMS? Finding source RPMs</title>
      <para>
        Often, source RPMs are abbreviated as SRPMs. In fact, if you see
        a directory named SRPM or SRPMS, chances are the directory holds
        source RPMs. (&RH; uses this convention for its Linux
        distributions.)
      </para>
      <para>
        The SRPMS directories on &RH; CD-ROMs or on the &RH; FTP
        Internet site, ftp.redhat.com, indicate directories that hold
        source RPMs.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Signing Built RPMs</title>
    <para>
      Signing RPMs adds an extra level of trustworthiness to your RPMs.
      A digital signature helps establish that the package comes from
      you, really you, and not from someone masquerading as you.
      Unfortunately, the RPM system requires a bit of set up work before
      you can sign RPMs.
    </para>
    <sect2>
      <title>Checking that the GPG software is installed</title>
      <para>
        To sign packages, you need to ensure that you have the gpg
        command installed and configured. To check that this command is
        installed, use a command like the following:
      </para>
      <para>
        $ rpm -qf `which gpg`
      </para>
      <para>
        gnupg-1.0.7-6
      </para>
      <para>
        This shows that the command is available.
      </para>
      <para>
        GPG and PGP? Acronyms Explained
      </para>
      <para>
        The RPM documentation uses GPG and PGP pretty much
        interchangeably, so much so, in fact, that you may think these
        are typographical errors. Not so.
      </para>
      <para>
        PGP stands for Pretty Good Privacy. Invented by Phil Zimmerman,
        PGP was originally invented to encrypt e-mail to allow for
        private communication. Based on a public-key cryptography
        algorithm, PGP also supports encrypted digital signatures. These
        signatures allow you to verify that a package you have
        downloaded really comes from the vendor you think it does. You
        do this by using the vendor’s public key.
      </para>
      <para>
        GPG stands for GNU Privacy Guard, a free, open-source
        implementation of PGP from the GNU project. GPG aims to be
        compatible with the OpenPGP Internet standard as defined in RFC
        2440. It started when a number of developers wanted a free
        implementation. One such free implementation, GPG, allows Linux
        vendors such as &RH; to include PGP in their products. So, in
        a sense, GPG provides PGP.
      </para>
      <para>
        PGP has a long and somewhat troubled history as an open-source
        product and as a commercial product. See www.philzimmermann.com
        for background on PGP and its long history. See www.gnupg.org
        for more details on GPG.
      </para>
    </sect2>
    <sect2>
      <title>Configuring a signature</title>
      <para>
        To configure a signature, you first need to create a new key
        with the gpg command, using the --gen-key option, as shown
        following:
      </para>
      <para>
        $ gpg --gen-key
      </para>
      <para>
        gpg (GnuPG) 1.0.7; Copyright (C) 2002 Free Software Foundation,
        Inc.
      </para>
      <para>
        This program comes with ABSOLUTELY NO WARRANTY.
      </para>
      <para>
        This is free software, and you are welcome to redistribute it
      </para>
      <para>
        under certain conditions. See the file COPYING for details.
      </para>
      <para/>
      <para>
        gpg: Warning: using insecure memory!
      </para>
      <para>
        gpg: please see http://www.gnupg.org/faq.html for more
        information
      </para>
      <para>
        gpg: keyring `/home2/ericfj/.gnupg/secring.gpg' created
      </para>
      <para>
        gpg: keyring `/home2/ericfj/.gnupg/pubring.gpg' created
      </para>
      <para>
        Please select what kind of key you want:
      </para>
      <para>
        (1) DSA and ElGamal (default)
      </para>
      <para>
        (2) DSA (sign only)
      </para>
      <para>
        (4) ElGamal (sign and encrypt)
      </para>
      <para>
        (5) RSA (sign only)
      </para>
      <para>
        Your selection? 1
      </para>
      <para>
        DSA keypair will have 1024 bits.
      </para>
      <para>
        About to generate a new ELG-E keypair.
      </para>
      <para>
        minimum keysize is 768 bits
      </para>
      <para>
        default keysize is 1024 bits
      </para>
      <para>
        highest suggested keysize is 2048 bits
      </para>
      <para>
        What keysize do you want? (1024)
      </para>
      <para/>
      <para>
        Requested keysize is 1024 bits
      </para>
      <para>
        Please specify how long the key should be valid.
      </para>
      <para>
        0 = key does not expire
      </para>
      <para>
        <n> = key expires in n days
      </para>
      <para>
        <n>w = key expires in n weeks
      </para>
      <para>
        <n>m = key expires in n months
      </para>
      <para>
        <n>y = key expires in n years
      </para>
      <para>
        Key is valid for? (0)
      </para>
      <para/>
      <para>
        You need a User-ID to identify your key; the software constructs
        the user id
      </para>
      <para>
        from Real Name, Comment and Email Address in this form:
      </para>
      <para>
        "Heinrich Heine (Der Dichter) <heinrichh at duesseldorf.de>"
      </para>
      <para/>
      <para>
        Real name: Eric Foster-Johnson
      </para>
      <para>
        Email address: please_no_spam at nospam.com
      </para>
      <para>
        Comment: Example for &RH; RPM Guide
      </para>
      <para>
        You selected this USER-ID:
      </para>
      <para>
        "Eric Foster-Johnson (Example for &RH; RPM Guide)
        <erc at no_spam.com>"
      </para>
      <para>
        Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit?
      </para>
      <para>
        O
      </para>
      <para>
        You need a Passphrase to protect your secret key.
      </para>
      <para/>
      <para>
        Enter passphrase:
      </para>
      <para>
        We need to generate a lot of random bytes. It is a good idea to
        perform
      </para>
      <para>
        some other action (type on the keyboard, move the mouse, utilize
        the
      </para>
      <para>
        disks) during the prime generation; this gives the random number
      </para>
      <para>
        generator a better chance to gain enough entropy.
      </para>
      <para>
        ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      </para>
      <para>
        +++++++++++++++++++++++++++++++++++..+++++..++++++++++>++++++++++........+++++
      </para>
      <para>
        gpg: /home2/ericfj/.gnupg/trustdb.gpg: trustdb created
      </para>
      <para>
        public and secret key created and signed.
      </para>
      <para>
        key marked as ultimately trusted.
      </para>
      <para/>
      <para>
        pub 1024D/01681C24 2002-11-05 Eric Foster-Johnson (Example for
        &RH; RPM
      </para>
      <para>
        Guide) <please_no_spam at nospam.com>
      </para>
      <para>
        Key fingerprint = 8C14 A2E9 47D1 301B 2153 7CDF BEE5 9C10 0268
        1D24
      </para>
      <para>
        sub 1024g/1A15D6C8 2002-11-05
      </para>
      <para>
        You can choose the default options for most choices. You need to
        enter a real name, an e-mail address, and a pass phrase.
        Remember the pass phrase. You will need to enter the pass phrase
        every time you wish to sign a package.
      </para>
      <para>
        Once you have a key, the next step is to set up some RPM macros.
        There are a number of places you can do this, but using the
        .rpmmacros file in your home directory is one of the easiest.
        Edit this file as shown in the following example:
      </para>
      <para>
        %_signature gpg
      </para>
      <para>
        %_gpg_path /home2/ericfj/.gnupg
      </para>
      <para>
        %_gpg_name EricFJ (Eric Key) <erc at no_spam.com>
      </para>
      <para>
        %_gpgbin /usr/bin/gpg
      </para>
      <para>
        Add lines like these to the $HOME/.rpmmacros file. (Create this
        file if it does not exist.)
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        <xref linkend="ch-customizing-rpm"/>  covers RPM macros and the $HOME/.rpmmacros file.
      </para>
      <para>
        Inside the file, change the %gpg_path macro to the .gnupg
        directory under your home directory (or the root user’s home
        directory). Change the %_gpg_name macro to the name you have
        entered into the gpg program.
      </para>
    </sect2>
    <sect2>
      <title>Signing with the rpmbuild command</title>
      <para>
        The --sign option tells the rpmbuild command to sign the created
        package. You need to have configured the RPM system for your
        signature as shown in the previous sections.
      </para>
      <para>
        When you then build an RPM, you will be prompted for your pass
        phrase prior to the package build. For example, the following
        shows this prompt (and truncates the rest of the rpmbuild
        messages that follow):
      </para>
      <para>
        $ rpmbuild -bb --sign xtoolwait-1.2.spec
      </para>
      <para>
        Enter pass phrase:
      </para>
      <para>
        Pass phrase is good.
      </para>
    </sect2>
    <sect2>
      <title>Signing with the rpm command</title>
      <para>
        In addition to the --sign option for the rpmbuild command, you
        can sign packages that have already been created using the rpm
        command. The --addsign and --resign options generate new
        signatures and insert them into the passed-in package file. The
        basic syntax is:
      </para>
      <para>
        rpm --addsign package.rpm
      </para>
      <para>
        rpm --resign package.rpm
      </para>
      <para>
        The --addsign option adds another signature to the RPM. RPM
        versions prior to 4.1 allowed you to sign a package with
        multiple keys, which causes problems for automatic verification.
        Because of that, use the --resign option, which removes the old
        signature and inserts a new signature into the package.
      </para>
    </sect2>
    <sect2>
      <title>Verifying signatures</title>
      <para>
        You can verify the RPM signature to ensure that the package has
        not been modified since it has been signed. Verification also
        checks that the package is signed by the key that matches the
        claimed vendor.
      </para>
      <para>
        To verify the signature in an RPM, use the -K option to the rpm
        command. The basic syntax is:
      </para>
      <para>
        rpm -K package.rpm
      </para>
      <para>
        Note
      </para>
      <para>
        This is the rpm command, not the rpmbuild command.
      </para>
      <para>
        This command accepts the options shown in Table 12-3 to turn off
        checking for certain types of signatures.
      </para>
      <para>
        Table 12-3 Options to turn off signature checking
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  Option
                </para>
              </entry>
              <entry>
                <para>
                  Usage
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --nogpg
                </para>
              </entry>
              <entry>
                <para>
                  Don’t check for GPG signatures
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --nomd5
                </para>
              </entry>
              <entry>
                <para>
                  Don’t check for MD5 signatures
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  --nopgp
                </para>
              </entry>
              <entry>
                <para>
                  Don’t check for PGP signatures
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
      <para>
        You can also use the --checksig option, which is the same as -K.
        When you run this command on a package that has a verifiable
        key, you will see output like the following:
      </para>
      <para>
        # rpm -K xtoolwait-1.3-3.src.rpm
      </para>
      <para>
        xtoolwait-1.3-3.src.rpm: (sha1) dsa sha1 md5 gpg OK
      </para>
      <para>
        This verifies that the package has not been changed from when it
        was first signed. It also verifies that the signature matches
        the public key from the vendor of the package. This goes a long
        ways toward verifying that the package is indeed legitimate.
      </para>
      <para>
        To get more information, add a -v (verbose) option. For example:
      </para>
      <para>
        $ rpm -Kv vixie-cron-3.0.1-69.src.rpm
      </para>
      <para>
        vixie-cron-3.0.1-69.src.rpm:
      </para>
      <para>
        Header V3 DSA signature: OK, key ID db42a60e
      </para>
      <para>
        Header SHA1 digest: OK
        (ecbb244ab022ecd23114bb1d6c9bdeb74f8d9520)
      </para>
      <para>
        MD5 digest: OK (fb0a75eca1d526d391c36dc956c23bdd)
      </para>
      <para>
        V3 DSA signature: OK, key ID db42a60e
      </para>
      <para>
        If you run this command on a package that does not verify,
        you’ll see an error like the following:
      </para>
      <para>
        # rpm --checksig xtoolwait-1.3-3.src.rpm
      </para>
      <para>
        xtoolwait-1.3-3.src.rpm: (SHA1) DSA sha1 md5 (GPG) NOT OK
        (MISSING KEYS: GPG#db42a60e)
      </para>
      <para>
        Items that fail are listed in uppercase, such as DSA, while
        items that succeed appear in lowercase. In this example, the
        sha1 and md5 tests succeeded, while the DSA test failed. This
        failure does not necessarily mean that the package is not
        legitimate. This failure can mean one of three things:
      </para>
      <para>
        1.The package was not properly signed in the first place. That
        is, it is a legitimate package but the package author did not
        properly sign the RPM.
      </para>
      <para>
        2.The package has been modified in some way. That is, the
        package is not legitimate.
      </para>
      <para>
        3.The RPM system has not been initialized with the public key
        from the package vendor.
      </para>
      <para>
        From this error, you don’t yet know whether the package is
        legitimate or not. The first step, though, is to check that you
        have imported the proper public key from the package vendor.
      </para>
    </sect2>
    <sect2>
      <title>Importing public keys</title>
      <para>
        The --import option to the rpm command imports the public key
        from a given vendor. The format for this key follows:
      </para>
      <para>
        The following public key can be used to verify RPM packages
        built and
      </para>
      <para>
        signed by &FORMAL-RHI; using `rpm -K' using the GNU GPG
        package.
      </para>
      <para>
        Questions about this key should be sent to security at redhat.com.
      </para>
      <para/>
      <para>
        -----BEGIN PGP PUBLIC KEY BLOCK-----
      </para>
      <para>
        Version: GnuPG v1.0.0 (GNU/Linux)
      </para>
      <para>
        Comment: For info see http://www.gnupg.org
      </para>
      <para/>
      <para>
        mQGiBDfqVEqRBADBKr3Bl6PO8BQ0H8sJoD6p9U7Yyl7pjtZqioviPwXP+DCWd4u8
      </para>
      <para>
        HQzcxAZ57m8ssA1LK1Fx93coJhDzM130+p5BG9mYSPShLabR3N1KXdXAYYcowTOM
      </para>
      <para>
        GxdwYRGr1Spw8QydLhjVfU1VSl4xt6bupPbFJbyjkg5Z3P7BlUOUJmrx3wCgobNV
      </para>
      <para>
        EDGaWYJcch5z5B1of/41G8kEAKii6q7Gu/vhXXnLS6m15oNnPVybyngiw/23dKjS
      </para>
      <para>
        ti/PYrrL2J11P2ed0x7zm8v3gLrY0cue1iSba+8glY+p31ZPOr5ogaJw7ZARgoS8
      </para>
      <para>
        BwjyRymXQp+8Dete0TELKOL2/itDOPGHW07SsVWOR6cmX4VlRRcWB5KejaNvdrE5
      </para>
      <para>
        4XFtOd04NMgWI63uqZc4zkRa+kwEZtmbz3tHSdWCCE+Y7YVP6IUf/w6YPQFQriWY
      </para>
      <para>
        FiA6fD10eB+BlIUqIw80EqjsBKmCwvKkn4jg8kibUgj4/TzQSx77uYokw1EqQ2wk
      </para>
      <para>
        OZoaEtcubsNMquuLCMWijYhGBBgRAgAGBQI36lRyAAoJECGRgM3bQqYOhyYAnj7h
      </para>
      <para>
        VDY/FJAGqmtZpwVp9IlitW5tAJ4xQApr/jNFZCTksnI+4O1765F7tA==
      </para>
      <para>
        =3AHZ
      </para>
      <para>
        -----END PGP PUBLIC KEY BLOCK-----
      </para>
      <para>
        Note
      </para>
      <para>
        For reasons of space, this is not a complete key.
      </para>
      <para>
        You need to pass the name of the text file that holds the key to
        the rpm --import command, as shown following:
      </para>
      <para>
        rpm --import key_file
      </para>
      <para>
        Note
      </para>
      <para>
        You must be logged in as the root user to import keys.
      </para>
      <para>
        For example:
      </para>
      <para>
        # rpm --checksig xtoolwait-1.3-3.src.rpm
      </para>
      <para>
        xtoolwait-1.3-3.src.rpm: (SHA1) DSA sha1 md5 (GPG) NOT OK
        (MISSING KEYS: GPG#db42a60e)
      </para>
      <para/>
      <para>
        # rpm --import RPM-GPG-KEY
      </para>
      <para/>
      <para>
        # rpm --checksig xtoolwait-1.3-3.src.rpm
      </para>
      <para>
        xtoolwait-1.3-3.src.rpm: (sha1) dsa sha1 md5 gpg OK
      </para>
      <para>
        This example shows an error message when trying to verify the
        key. Then, after importing the &RH; public key, the
        verification works.
      </para>
      <para>
        If, after importing this key, you still have problems, you can
        assume there are problems with the package. Many administrators
        will refuse to install such packages.
      </para>
      <para>
        Warning
      </para>
      <para>
        You should be careful with packages that have signatures that do
        not verify.
      </para>
      <para>
        To list the available keys, use a command like the following:
      </para>
      <para>
        $ rpm -qa | grep -i gpg
      </para>
      <para>
        gpg-pubkey-db42a60e-37ea5438
      </para>
      <para>
        This example shows one key installed.
      </para>
      <para>
        Note
      </para>
      <para>
        You can erase this key as if it were a package, using the rpm -e
        command.
      </para>
    </sect2>
    <sect2>
      <title>Getting the &RH; public key</title>
      <para>
        Strangely enough, the &RH; public key is not installed when
        you install &RHL; 8.0. If you need the key, the &RH;
        public key is available on the root directory of all &RH;
        Linux CD-ROMs, as shown in the following listing:
      </para>
      <para>
        $ ls /mnt/cdrom/
      </para>
      <para>
        EULA GPL README RedHat/ RPM-GPG-KEY SRPMS/ TRANS.TBL
      </para>
      <para>
        Simply copy the RPM-GPG-KEY file to get the public key. Then use
        the rpm --import command with this key file.
      </para>
      <para>
        Note
      </para>
      <para>
        You can also download this key file from the &RH; FTP site,
        at ftp://ftp.redhat.com/pub/redhat/linux/8.0/en/os/i386/.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      This chapter covers options for the rpmbuild command that allow
      you to achieve a finer grain of control over how the command
      works. For example, the --short-circuit option tells the rpmbuild
      command to build just the stages you ask for. This helps when you
      have problems in one area of building an RPM and don’t want to
      start over each time you try to see if the problem is solved.
    </para>
    <para>
      The rpmbuild command also supports a set of -t options that work
      like the -b options, except the -t options try to build an RPM
      from a tar archive of sources (a tarball) instead of an RPM spec
      file. In this case, the rpmbuild command tries to work without a
      spec file.
    </para>
    <para>
      The --rebuild option tells the rpmbuild command to install a
      source RPM, build the binary RPM, and clean out the installed
      source RPM. This provides quite a shortcut for installing binary
      RPMs from source RPMs.
    </para>
    <para>
      RPMs should be signed to provide an extra level of authentication.
      This system isn’t perfect, but it helps you verify that a
      package is from the person it says it is from and that the package
      has not been modified. You can check the signature on RPM packages
      you download. You can also, with some configuration, sign the
      packages you create.
    </para>
    <para/>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-scripting.xml ---
<!-- $Id: -->

<chapter id="ch-scripting">
  <title>Automating RPM with Scripts</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Deciding when to program and when to script
      </para>
    </listitem>
    <listitem>
      <para>
        Examining RPM files with scripts
      </para>
    </listitem>
    <listitem>
      <para>
        Querying the RPM database with scripts
      </para>
    </listitem>
  </itemizedlist>
  <para>
    The rpm command provides a very high-level view of package
    management. Most of the operations you need to perform require only
    a single invocation. Some of the command-line options to the rpm
    command tend to get very complex, however, especially for detailed
    queries. That’s where scripting can help.
  </para>
  <para>
    This chapter covers scripting, specifically shell scripting, with
    the rpm command, especially for newcomers to Linux scripting
  </para>
  <sect1>
    <title>Scripting</title>
    <para>
      Scripting allows you to quickly write new commands in a language,
      called a scripting language, that can help automate your work.
      Used heavily by system administrators and lightly by software
      developers, scripts can help remove some of the tedium from your
      day-to-day tasks. Scripts can also hold the complex query formats
      used with the rpm command so you don’t have to remember them.
    </para>
    <para>
      Scripts start out as text files. These text files hold commands in
      the scripting language. Most of these script file commands run
      commands installed on your system, such as rpm. To run a script,
      invoke a command, called an interpreter, that reads in the script
      file and executes the commands inside the script.
    </para>
    <para>
      Programming is usually considered different from scripting, even
      though there are many similarities. Programs start out as text
      files. These text files hold commands in the programming language
      and sometimes, not often, calls to commands installed on your
      system. Programs generally involve more work than scripts and are
      generally larger, containing more commands.
    </para>
    <para>
      Furthermore, most programs need to be compiled. A separate command
      parses the program text files and generates some form of machine
      code. Multiple pieces of a program may be linked together to form
      a command you can call from your shell prompt.
    </para>
    <para>
      Some programming languages, such as Java or C#, are compiled to a
      generic bytecode format. A compiled Java program, for example, is
      the same no matter what the architecture. To run such a program,
      you need a runtime engine such as the java command provides.
      (Runtime engine is a fancy term for interpreter.)
    </para>
    <para>
      Such differences between scripting and programming sometimes get
      in the way of performing real work. For example, I once worked
      with a group of people who were convinced that they were not
      programmers. They felt that programming was an art that was far
      beyond them. Yet, they wrote hundreds of kilobytes of scripts to
      create a sophisticated graphical interface for a Computer-Aided
      Design system. In my mind, they were programming (and doing quite
      well at it). In their minds, though, there was a clear distinction
      between scripting at mdwhat they could do at mdand programming, which
      was beyond them, they thought.
    </para>
    <para>
      Don’t get caught up in this. Use the right tool for the job.
    </para>
  </sect1>
  <sect1>
    <title>Distinguishing Scripting Languages from Programming Languages</title>
    <para>
      Experts differ regarding what defines a scripting language and
      what defines a programming language. It’s clear that languages
      such as Python blur the old distinction between programming and
      scripting.
    </para>
    <para>
      Originally, scripting was writing small files of commands that
      invoked other system commands. For example, you could write a
      script that wraps the Linux file command. Scripts were executed by
      scripting-language interpreters that parsed each command one at a
      time and then executed the command.
    </para>
    <para>
      Modern scripting languages, such as Tcl, are parsed at runtime and
      compiled into an internal bytecode format. Once compiled, there is
      no real difference from a language associated with programming
      such as Java.
    </para>
    <para>
      With a scripting language
    </para>
    <para>
      *You generally don’t have to compile the script in advance. The
      scripting language interpreter may compile the program, often to
      an internal byte code, but you don’t have to invoke a compiler
      as a separate step.
    </para>
    <para>
      *The facilities of the language generally provide a higher level
      and more abstract level of interaction with the system than with
      programming languages. For example, writing socket-based
      networking code in Tcl requires a lot less code than writing the
      same code in a programming language such as C. Tcl provides a more
      abstract view of networking; therefore, your code is a lot
      simpler.
    </para>
    <para>
      *The commands in the scripting language are mostly the commands
      available to you on the command line. Scripting languages
      introduce their own commands, too.
    </para>
    <para>
      *The language is generally identified as a scripting language.
      This is more consensus than anything else. Forth is considered an
      interpreted programming language, while Perl is considered a
      scripting language.
    </para>
    <para>
      Table 15-1 lists some of the more common scripting and programming
      languages. Note that these are the generally-accepted categories
      for these languages, not hard and fast rules. This should not stop
      you, for example, from writing programs in Perl or Python. The
      distinctions between programming and scripting have blurred in
      recent years.
    </para>
    <para>
      Table 15-1 Common Scripting Languages and Common Programming
      Languages
    </para>
    <informaltable frame="all">
      <tgroup cols="2">
        <tbody>
          <row>
            <entry>
              <para>
                Scripting Languages
              </para>
            </entry>
            <entry>
              <para>
                Programming Languages
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                Bash (Bourne Again shell) Csh (C shell) JavaScript Ksh
                (Korn shell) Lua MS-DOS batch files Perl Python Ruby Sh
                (Bourne shell) Tcl
              </para>
            </entry>
            <entry>
              <para>
                Assembler BASIC C C++ C# FORTRAN Forth Java LISP
                Modula-2, Modula-3 Oberon Pascal
              </para>
            </entry>
          </row>
        </tbody>
      </tgroup>
    </informaltable>
  </sect1>
  <sect1>
    <title>Deciding When to Program and When to Script</title>
    <para>
      Just as the distinction between programming and scripting
      languages has blurred in the last few years, so have the
      guidelines for when you should program and when you should script.
      The simplest rule remains, though: Use whatever techniques make
      you productive. In the end, no one really cares if you call it a
      program or a script.
    </para>
    <para>
      Even so, these guidelines may help:
    </para>
    <para>
      *If you have to perform a lot of operations on a lot of RPMs, a
      program will likely perform much faster than a script that calls
      the rpm command over and over.
    </para>
    <para>
      *If the task is relatively simple, scripting generally works best.
    </para>
    <para>
      *If you are more experienced with a particular language, use it.
    </para>
    <para>
      *If you need to perform complex operations, perhaps involving
      transactions, a program is probably the right way to go.
    </para>
    <para>
      *In many cases, programming languages work better for creating
      graphical user interfaces, although Python and Perl offer
      graphical user interface toolkits, such as Perl/Tk or PyQt.
    </para>
    <para>
      There isn’t one right way to do it. Pick what works best for
      you.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      This chapter covers shell scripting. <xref linkend="ch-programming-c"/>  covers C
      programming. <xref linkend="ch-rpm-programming-python"/>  covers Python scripting and programming,
      and <xref linkend="ch-programming-perl"/>  covers Perl scripting.
    </para>
  </sect1>
  <sect1>
    <title>Shell Scripting Basics</title>
    <para>
      For newcomers to scripting, don’t worry. A script, in this case
      a shell script, is merely a text file with commands mostly the
      same as the commands you can type at the keyboard. I’ll point
      out the differences.
    </para>
    <para>
      The following sections quickly introduce scripting for those new
      to this venture.
    </para>
    <sect2>
      <title>Writing a script</title>
      <para>
        For your first venture, enter the following script into a text
        file:
      </para>
      <para>
        rpm -qa | grep rpm
      </para>
      <para>
        This script has a two-part command. The rpm –qa part queries
        all RPM packages, as covered in <xref linkend="ch-using-rpm"/> . The grep rpm part
        finds only packages with rpm in their names. This is a very
        simple script, but it can serve to show how to work with
        scripts.
      </para>
      <para>
        Save this file under the name listrpmpkgs, since this script
        lists RPM packages.
      </para>
      <para>
        Note
      </para>
      <para>
        If you’re new to Linux, you’ll notice there’s no program
        named Notepad.exe. There are, though, a plethora of Linux text
        editors to choose from. See <xref linkend="ch-development-tools"/>  for a listing of Linux
        text-editing tools.
      </para>
    </sect2>
    <sect2>
      <title>Running a script</title>
      <para>
        Once you’ve entered a script, you can run it with the sh
        command, as shown following, passing the name of your script to
        the sh command:
      </para>
      <para>
        $ sh listrpmpkgs
      </para>
      <para>
        librpm404-devel-4.0.4-8x.27
      </para>
      <para>
        librpm404-4.0.4-8x.27
      </para>
      <para>
        rpm404-python-4.0.4-8x.27
      </para>
      <para>
        rpm-4.1-1.06
      </para>
      <para>
        rpm-devel-4.1-1.06
      </para>
      <para>
        gnorpm-0.9-1
      </para>
      <para>
        rpm-python-4.1-1.06
      </para>
      <para>
        redhat-rpm-config-8.0-1
      </para>
      <para>
        rpm-build-4.1-1.06
      </para>
      <para>
        rpmrebuild-1.0-0
      </para>
      <para>
        Type the command you have placed in your script at the command
        line. There should be no difference in the output. For example:
      </para>
      <para>
        $ rpm -qa | grep rpm
      </para>
      <para>
        librpm404-devel-4.0.4-8x.27
      </para>
      <para>
        librpm404-4.0.4-8x.27
      </para>
      <para>
        rpm404-python-4.0.4-8x.27
      </para>
      <para>
        rpm-4.1-1.06
      </para>
      <para>
        rpm-devel-4.1-1.06
      </para>
      <para>
        gnorpm-0.9-1
      </para>
      <para>
        rpm-python-4.1-1.06
      </para>
      <para>
        redhat-rpm-config-8.0-1
      </para>
      <para>
        rpm-build-4.1-1.06
      </para>
      <para>
        rpmrebuild-1.0-0
      </para>
    </sect2>
    <sect2>
      <title>Problems running scripts</title>
      <para>
        The previous script example required the sh program, a Linux
        shell, to run the script. You also had to have the script file,
        such as listrpmpkgs, available. So, if you have stored the file
        in /home2/bin, to run the script, use the following command:
      </para>
      <para>
        $ sh /home2/bin/listrpmpkgs
      </para>
      <para>
        That’s not very convenient. Furthermore, you always have to
        remember where you stored the script file listrpmpkgs. To make
        this command work better, you can turn your script into a
        command.
      </para>
    </sect2>
    <sect2>
      <title>Turning a script into a command</title>
      <para>
        To turn a script into a command, do three simple things:
      </para>
      <para>
        1.Add a special magic comment to the start of the file so Linux
        recognizes your text file as a command script.
      </para>
      <para>
        2.Change the permissions on the file so that it is marked as
        executable.
      </para>
      <para>
        3.Copy the file to a directory located in your command path.
      </para>
      <para>
        Shell scripts use a # to indicate a comment, text intended for
        human readers that can help explain the purpose of the script.
        By convention, Linux shells use a #! comment in the first line
        of a script file as a special marker that indicates the file is
        a shell script. The text that comes after the #! holds the name
        of the command that should be used to run the script. In almost
        all cases, that command should be /bin/sh for a shell script.
      </para>
      <para>
        So edit the listrpmpkgs script again, and add the magic comment
        so that the file reads as follows:
      </para>
      <para>
        #!/bin/sh
      </para>
      <para>
        rpm -qa | grep rpm
      </para>
      <para>
        Make sure the #! comment starts at the beginning of the first
        line.
      </para>
      <para>
        Next, change the permissions on the script to mark it as an
        executable program. Use the chmod command to do this. The chmod
        command changes the file permissions. To see the permissions,
        run the ls –l command before changing the permissions:
      </para>
      <para>
        $ ls -l listrpmpkgs
      </para>
      <para>
        -rw-rw-r-- 1 ericfj ericfj 31 Nov 7 20:02 listrpmpkgs
      </para>
      <para>
        The first set of characters, the -rw-rw-r--, indicate the
        permissions in three batches: permissions for the file owner,
        the owner’s group of users, and world (everyone else). The rw
        means read and write, and the r alone means read only for
        everyone not the owner and not in the owner’s group.
      </para>
      <para>
        To add the permission to execute the file for the file owner
        only, use the following command:
      </para>
      <para>
        $ chmod u+x listrpmpkgs
      </para>
      <para>
        In this command, the u stands for the user who owns the file
        (for historical reasons, an o stands for others, not owner). The
        +x means add the x permission, short for execute permission.
      </para>
      <para>
        After running this command, you can see the revised permissions.
      </para>
      <para>
        $ ls -l listrpmpkgs
      </para>
      <para>
        -rwxrw-r-- 1 ericfj ericfj 31 Nov 7 20:02 listrpmpkgs
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        Use the man chmod command to see more information on this
        command.
      </para>
      <para>
        You now have a command you can run locally. For example:
      </para>
      <para>
        $ ./listrpmpkgs
      </para>
      <para>
        librpm404-devel-4.0.4-8x.27
      </para>
      <para>
        librpm404-4.0.4-8x.27
      </para>
      <para>
        rpm404-python-4.0.4-8x.27
      </para>
      <para>
        rpm-4.1-1.06
      </para>
      <para>
        rpm-devel-4.1-1.06
      </para>
      <para>
        gnorpm-0.9-1
      </para>
      <para>
        rpm-python-4.1-1.06
      </para>
      <para>
        redhat-rpm-config-8.0-1
      </para>
      <para>
        rpm-build-4.1-1.06
      </para>
      <para>
        rpmrebuild-1.0-0
      </para>
      <para>
        The next step is to copy the file to a directory in your system
        command path. To see which directories are in your path, run the
        following command:
      </para>
      <para>
        $ echo $PATH
      </para>
      <para>
        /usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/ericfj/bin:/usr/java/j2sdk1.4.0_01/bin
      </para>
      <para>
        Pick one of these directories. The /usr/local/bin directory is a
        common place to share locally created commands. If this is a
        personal command for your own use only, a directory under your
        home directory will be better. In this example, the
        /home/ericfj/bin is one such directory.
      </para>
      <para>
        Copy the script file to a directory in your command path, and
        you are ready to go.
      </para>
      <para>
        Note
      </para>
      <para>
        If you use the C shell, csh, or the T C shell, tcsh, you need to
        run the rehash command to tell the shell to look again at the
        set of commands available in your command path.
      </para>
      <para>
        Enter the following command:
      </para>
      <para>
        $ listrpmpkgs
      </para>
      <para>
        librpm404-devel-4.0.4-8x.27
      </para>
      <para>
        librpm404-4.0.4-8x.27
      </para>
      <para>
        rpm404-python-4.0.4-8x.27
      </para>
      <para>
        rpm-4.1-1.06
      </para>
      <para>
        rpm-devel-4.1-1.06
      </para>
      <para>
        gnorpm-0.9-1
      </para>
      <para>
        rpm-python-4.1-1.06
      </para>
      <para>
        redhat-rpm-config-8.0-1
      </para>
      <para>
        rpm-build-4.1-1.06
      </para>
      <para>
        rpmrebuild-1.0-0
      </para>
      <para>
        You have now extended the Linux command set with your own
        command.
      </para>
      <para>
        Note
      </para>
      <para>
        Windows users may be used to the convention that program file
        names end in .exe and scripts end in .bat or .cmd. When you run
        these programs or scripts, you don’t include the extension,
        exe, .bat, or .cmd. With Linux and UNIX, though, the full file
        name is important, so if you name your script rpminfo.bat, you
        must type rpminfo.bat each time you run the script. That’s why
        most Linux programs and scripts have no filename extension.
      </para>
      <para>
        If you want to share your script with others, you should give
        them the right to execute it as well. You can do that with the
        following command:
      </para>
      <para>
        $ chmod a+x listrpmpkgs
      </para>
      <para>
        In this case, the a stands for all users.
      </para>
    </sect2>
    <sect2>
      <title>Passing command-line options to your script</title>
      <para>
        The listrpmpkgs script used so far isn’t very useful. It
        performs one command and that’s it. We cannot customize it
        without writing a new script.
      </para>
      <para>
        One way to make a script more flexible is to allow it to use
        command-line options. Just like the rpm command accepts a
        zillion options, you can make your scripts accept options.
      </para>
      <para>
        Shells define special variables for the command-line options
        passed to the shell. Table 15-2 lists these options.
      </para>
      <para>
        Table 15-2: Shell variables for command-line options
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  Variable
                </para>
              </entry>
              <entry>
                <para>
                  Holds
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  $0
                </para>
              </entry>
              <entry>
                <para>
                  The name of the script itself, from the command line
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  $1
                </para>
              </entry>
              <entry>
                <para>
                  The first option
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  $2
                </para>
              </entry>
              <entry>
                <para>
                  The second option
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  $3
                </para>
              </entry>
              <entry>
                <para>
                  The third option
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  $4
                </para>
              </entry>
              <entry>
                <para>
                  The fourth option
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  $5
                </para>
              </entry>
              <entry>
                <para>
                  The fifth option
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  $6
                </para>
              </entry>
              <entry>
                <para>
                  The sixth option
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  $7
                </para>
              </entry>
              <entry>
                <para>
                  The seventh option
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  $8
                </para>
              </entry>
              <entry>
                <para>
                  The eighth option
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  $9
                </para>
              </entry>
              <entry>
                <para>
                  The ninth option
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  $*
                </para>
              </entry>
              <entry>
                <para>
                  All command-line options
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  $#
                </para>
              </entry>
              <entry>
                <para>
                  Holds the number of command-line options
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
      <para>
        Note
      </para>
      <para>
        Use $#argv in place of $# if you use the C shell to run your
        scripts.
      </para>
      <para>
        You can use these variables to allow the user to pass the text
        to search for, instead of always searching for rpm. With this
        addition, your new script, renamed rpmgrep, follows in Listing
        15-1:
      </para>
      <para>
        Listing 15-1: rpmgrep
      </para>
      <para>
        #!/bin/sh
      </para>
      <para/>
      <para>
        rpm -qa | grep $*
      </para>
      <para>
        This script now expects a command-line option that holds the
        text to search for. Mark this script as an executable; then you
        can run it as follows:
      </para>
      <para>
        $ ./rpmgrep python
      </para>
      <para>
        python-devel-2.2.1-17
      </para>
      <para>
        gnome-python2-gtkhtml2-1.99.11-8
      </para>
      <para>
        gnome-python2-canvas-1.99.11-8
      </para>
      <para>
        gnome-python2-1.99.11-8
      </para>
      <para>
        rpm404-python-4.0.4-8x.27
      </para>
      <para>
        orbit-python-1.99.0-4
      </para>
      <para>
        gnome-python2-bonobo-1.99.11-8
      </para>
      <para>
        gnome-python2-gconf-1.99.11-8
      </para>
      <para>
        libxslt-python-1.0.19-1
      </para>
      <para>
        libxml2-python-2.4.23-1
      </para>
      <para>
        python-optik-1.3-2
      </para>
      <para>
        python-2.2.1-17
      </para>
      <para>
        rpm-python-4.1-1.06
      </para>
      <para>
        mod_python-3.0.0-10
      </para>
      <para>
        python-tools-2.2.1-17
      </para>
      <para>
        If you want to make this command available, copy it to a
        directory in your command path as described in the preceding
        section.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Examining RPM Files</title>
    <para>
      When you work with a lot of RPM files, you’ll find that you run
      the same commands over and over again for each new package you
      get. For example, you may want to see what capabilities a package
      requires. You can type in the rpm command each time, or write a
      short shell script with the necessary command-line options.
      Listing 15-2 shows this script.
    </para>
    <para>
      Listing 15-2: rpmdepend
    </para>
    <para>
      #!/bin/sh
    </para>
    <para/>
    <para>
      rpm -qp --requires $*
    </para>
    <para>
      This script expects the name of an RPM package file. Run the
      command as follows:
    </para>
    <para>
      $ rpmdepend vim-common-6.1-14.i386.rpm
    </para>
    <para>
      rpmlib(PayloadFilesHavePrefix) <= 4.0-1
    </para>
    <para>
      rpmlib(CompressedFileNames) <= 3.0.4-1
    </para>
    <para>
      /bin/sh
    </para>
    <para>
      /usr/bin/awk
    </para>
    <para>
      libc.so.6
    </para>
    <para>
      libc.so.6(GLIBC_2.0)
    </para>
    <para>
      libc.so.6(GLIBC_2.1)
    </para>
    <para>
      Another common task I perform involves listing all the files in an
      RPM along with the descriptive information on the package. This
      can really help, since so many Linux packages have nondescriptive
      names such as dia and anaconda.
    </para>
    <para>
      Listing 15-3 shows the rpminfo script.
    </para>
    <para>
      Listing 15-3: rpminfo
    </para>
    <para>
      #!/bin/sh
    </para>
    <para/>
    <para>
      rpm -qilp $* | less
    </para>
    <para>
      This script lists a potentially long set of lines, so the script
      pipes the output to the less command. For example:
    </para>
    <para>
      $ ./rpminfo perl-XML-Dumper-0.4-22.noarch.rpm
    </para>
    <para>
      Name : perl-XML-Dumper Relocations: /usr
    </para>
    <para>
      Version : 0.4 Vendor: &FORMAL-RHI;
    </para>
    <para>
      Release : 22 Build Date: Tue 06 Aug 2002 01:53:30 PM CDT
    </para>
    <para>
      Install date: (not installed) Build Host: vegeta.devel.redhat.com
    </para>
    <para>
      Group : System Environment/Libraries Source RPM:
      perl-XML-Dumper-0.4-22.src.rpm
    </para>
    <para>
      Size : 10015 License: GPL
    </para>
    <para>
      Signature : DSA/SHA1, Tue 06 Aug 2002 02:11:39 PM CDT, Key ID
      fd372689897da07a
    </para>
    <para>
      Packager : &FORMAL-RHI;
      <http://bugzilla.redhat.com/bugzilla>
    </para>
    <para>
      URL : http://www.cpan.org
    </para>
    <para>
      Summary : Perl module for dumping Perl objects from/to XML
    </para>
    <para>
      Description :
    </para>
    <para>
      XML::Dumper dumps Perl data to XML format. XML::Dumper can also
      read
    </para>
    <para>
      XML data that was previously dumped by the module and convert it
      back
    </para>
    <para>
      to Perl. Perl objects are blessed back to their original
      packaging;
    </para>
    <para>
      if the modules are installed on the system where the perl objects
      are
    </para>
    <para>
      reconstituted from xml, they will behave as expected. Intuitively,
      if
    </para>
    <para>
      the perl objects are converted and reconstituted in the same
    </para>
    <para>
      environment, all should be well.
    </para>
    <para>
      /usr/lib/perl5/vendor_perl/5.8.0/XML/Dumper.pm
    </para>
    <para>
      /usr/share/man/man3/XML::Dumper.3pm.gz
    </para>
    <para>
      I use this script so that I know what files a package wants to
      install.
    </para>
  </sect1>
  <sect1>
    <title>Querying the RPM Database</title>
    <para>
      In addition to querying RPM files, you can script the commands you
      use to query the RPM database. This is most useful for the long
      commands with query formats, especially if you have a hard time
      remembering all the formats.
    </para>
    <sect2>
      <title>Querying for all packages installed at the same time</title>
      <para>
        If you want to list all the packages that were installed with
        the same transaction ID as a particular package, for example,
        you can use a script like rpmtran, in Listing 15-4.
      </para>
      <para>
        Listing 15-4: rpmtran
      </para>
      <para>
        #!/bin/sh
      </para>
      <para/>
      <para>
        tid=`rpm -q --qf "%{INSTALLTID}\n" $*`
      </para>
      <para/>
      <para>
        rpm -q --tid $tid
      </para>
      <para>
        This script uses the query format to get the transaction ID, or
        tid, for a particular package. It then passes this transaction
        ID to the rpm command to query for all packages installed with
        the same transaction ID.
      </para>
      <para>
        For example:
      </para>
      <para>
        $ ./rpmtran tcl
      </para>
      <para>
        itcl-3.2-74
      </para>
      <para>
        tclx-8.3-74
      </para>
      <para>
        tcl-8.3.3-74
      </para>
      <para>
        tix-8.2.0b1-74
      </para>
      <para>
        tkinter-2.2.1-17
      </para>
    </sect2>
    <sect2>
      <title>Reading HTML documentation for a package</title>
      <para>
        You can combine the rpm command with other commands as well. For
        example, the rpm –qd command lists the documentation files
        with a package. If this documentation is in HTML format, you can
        display this documentation in a Web browser such as Mozilla.
        Furthermore, by convention, the starting page for HTML
        documentation should be a file named index.html. Listing 15-5
        combines all these factors:
      </para>
      <para>
        Listing 15-5: rpmmoz
      </para>
      <para>
        #!/bin/sh
      </para>
      <para/>
      <para>
        html_file=`rpm -qd $* | grep index.html | head -n 1 `
      </para>
      <para/>
      <para>
        echo "Launching Web browser with $html_file"
      </para>
      <para/>
      <para>
        htmlview $html_file &
      </para>
      <para>
        This script searches for the documentation for a given package
        name, finds the first file named index.html, and launches the
        Web browser in the background to display this file, using the
        htmlview command which will likely run mozilla or your
        configured Web browser. When you run this command, you should
        see output like the following; then the Web browser should
        appear:
      </para>
      <para>
        $ ./rpmmoz rpm-devel
      </para>
      <para>
        Launching Web browser with
        /usr/share/doc/rpm-devel-4.1/apidocs/html/index.html
      </para>
      <para>
        Note
      </para>
      <para>
        This script does not check for errors. If there are no files
        named index.html, the script launches the Web browser anyway.
        You could fix this by changing the script to validate the
        html_file variable prior to launching the Web browser.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Where to Go From Here</title>
    <para>
      This chapter just introduces the basics for shell scripting. There
      are many more things you can do. The online manual pages for the
      bash or tcsh commands provide a wealth of reference information on
      these shells.
    </para>
    <para>
      A number of Web sites provide tutorials on bash, including
      http://pegasus.rutgers.edu/~elflord/unix/bash-tute.html and
      www.linuxorbit.com/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=459.
      In addition, the Linux Documentation Project at
      www.tldp.org/guides.html provides a bash scripting guide, along
      with a number of bash- and shell-related how-to documents at
      www.tldp.org/HOWTO/HOWTO-INDEX/howtos.html.
    </para>
    <para>
      Teach Yourself Linux, by Steve Oualline and Eric Foster-Johnson
      (John Wiley & Sons, 2000), introduces a number of Linux
      topics, including text editors and scripting, for those new to
      Linux. And Graphical Applications with Tcl and Tk (Hungry Minds,
      Inc., 1997) by Eric Foster-Johnson, covers another scripting
      language, Tcl/Tk.
    </para>
    <para>
      Use your imagination. Any command that you run often or that is
      hard to type can be scripted. Furthermore, you can write complex
      scripts that automate some of the more tedious tasks you need to
      perform.
    </para>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      Scripting is the art of writing a set of commands into text files
      to speed up your work. Programming is the art of writing a set of
      commands into text files, compiling the text files, and getting
      paid more. Choosing when to program and when to script isn’t
      always a clear-cut decision, but generally programs are move
      involved and complex, while scripts are shorter tools that
      automate your work. This chapter provides just a glimpse of all
      you can do with scripts and the RPM system.
    </para>
    <para>
      Scripts work very well for capturing obscure syntax options for
      the rpm command, especially the query formats. You can figure out
      a command once and then save the command as a script to save time
      in the future.
    </para>
    <para>
      Scripts aren’t the best choice for all tasks, though. In many
      cases, you need to write a program to accomplish your goals. The
      next chapter delves into the RPM C programming API, rpmlib.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-specfile-syntax.xml ---
<!-- $Id: -->

<chapter id="ch-specfile-syntax">
  <title>Spec File Syntax</title>
  <para>
    This appendix covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        The package information tags
      </para>
    </listitem>
    <listitem>
      <para>
        Build sections
      </para>
    </listitem>
  </itemizedlist>
  <para>
    The RPM spec file is divided into two main parts: the package
    information tags, such as the name of the package, and the build
    sections, such as the commands to compile the software.
  </para>
  <para>
    The following sections summarize the spec file syntax.
  </para>
  <sect1>
    <title>Package Information Tags</title>
    <para>
      The package information tags contain most of the header tags that
      you can query with the rpm command. First and foremost, this
      includes a name.
    </para>
    <para>
      The name-epoch-version-release tags, which form the NEVR used to
      identify packages, should all appear in your spec file, although
      you can skip the Epoch tag.
    </para>
    <para>
      Name: name
    </para>
    <para>
      # Epoch: 1
    </para>
    <para>
      Version: version_number
    </para>
    <para>
      Release: package_release_number
    </para>
    <para>
      The optional Epoch tag provides an ordering for the version
      numbers (replacing the deprecated Serial tag). Use this tag if RPM
      cannot figure out the ordering of which release comes after
      another.
    </para>
    <para>
      Epoch: 42
    </para>
    <para>
      A number of tags allow you to define who made the package and
      under what conditions has the package been released:
    </para>
    <para>
      Vendor: name_of_vendor
    </para>
    <para>
      URL: URL_to_package_home
    </para>
    <para>
      Copyright: package_copyright_message
    </para>
    <para>
      Distribution: Linux_or_product_distribution
    </para>
    <para>
      Packager: John Q. Smith <john.smith at somecompany.yow>
    </para>
    <para>
      Group: group_for_categorizing_package
    </para>
    <para>
      Use the Group tag to help users categorize your package.
    </para>
    <para>
      The Icon tag allows you to provide a desktop icon for the package:
    </para>
    <para>
      Icon: filename.xpm
    </para>
    <para>
      A one-line summary is essential to tell users what your package is
      for:
    </para>
    <para>
      Summary: one_line_description_of_package
    </para>
    <para>
      You should also include a longer description section, marked by
      %description:
    </para>
    <para>
      %description
    </para>
    <para>
      Tcsh is an enhanced but completely compatible version of csh, the
      C
    </para>
    <para>
      shell. Tcsh is a command language interpreter which can be used
      both
    </para>
    <para>
      as an interactive login shell and as a shell script command
      processor.
    </para>
    <para>
      Tcsh includes a command line editor, programmable word completion,
    </para>
    <para>
      spelling correction, a history mechanism, job control and a C
      language
    </para>
    <para>
      like syntax.
    </para>
    <para>
      In the description section, blank lines indicate paragraphs. Lines
      that start with a space are not formatted.
    </para>
    <sect2>
      <title>Comments</title>
      <para>
        To help document your work, you can include comments (to
        yourself and others reading the spec file). Any line starting
        with a hash character, #, holds a comment. RPM will ignore
        comments.
      </para>
      <para>
        # This is a comment.
      </para>
      <para>
        In spec files, comments are used mostly to help explain your
        syntax choices to yourself should you view the spec file later.
      </para>
      <para>
        Note
      </para>
      <para>
        Avoid percent signs, %, in comments, which may get interpreted
        as RPM macros. See <xref linkend="ch-specfiles"/>  for details.
      </para>
    </sect2>
    <sect2>
      <title>Build settings</title>
      <para>
        The BuildArchitectures tag names the architectures that a binary
        RPM will run on. See <xref linkend="ch-customizing-rpm"/>  for a description of the
        architecture settings. A special value of noarch indicates a
        package that is not dependent on a particular architecture, such
        as a Perl or Python script.
      </para>
      <para>
        The BuildPreReq tag lists any prerequisites for building. For
        example:
      </para>
      <para>
        BuildPreReq: ncurses-devel
      </para>
      <para>
        The Buildroot tag names the temporary directory in which to
        build the package. For example:
      </para>
      <para>
        Buildroot: %{_tmppath}/%{name}-root
      </para>
    </sect2>
    <sect2>
      <title>Dependency tags</title>
      <para>
        Dependency tags define all the dependencies for the package, as
        described in <xref linkend="ch-dependencies"/> .
      </para>
      <para>
        For each dependency, you can specify a capability name alone.
        For example:
      </para>
      <para>
        Provides: capability_name
      </para>
      <para>
        You can also provide a particular version number or indicate
        that your package has a dependency on a version larger or
        smaller than a given number. For example:
      </para>
      <para>
        Requires: capability_name >= version_number
      </para>
      <para>
        Requires: capability_name <= version_number
      </para>
      <para>
        Requires: capability_name > version_number
      </para>
      <para>
        Requires: capability_name < version_number
      </para>
      <para>
        Requires: capability_name == version_number
      </para>
      <para>
        Requires: capability_name = version_number
      </para>
      <para>
        The == and = act the same for dependencies. Both check for a
        version equal to the given number. You can provide multiple
        items, separated by commas. For example:
      </para>
      <para>
        Requires: python >= 1.3, perl
      </para>
      <para>
        For add-on modules for interpreters, especially Perl, you can
        use the following syntax to define capabilities:
      </para>
      <para>
        Provides: perl(MIME-Base64)
      </para>
      <para>
        This example provides the MIME-Base64 add-on Perl module.
      </para>
      <para>
        You can also use or to specify more than one possibility. For
        example:
      </para>
      <para>
        perl(IO-Wrap) == 4.5 or perl(IO-Wrap)-4.5
      </para>
      <para>
        The Provides, Requires, Obsoletes, and Conflicts dependency tags
        all work the same for capability names and version numbers.
      </para>
      <para>
        Note
      </para>
      <para>
        You can also specify BuildRequires tags for capabilities
        necessary to build the package, not to install it. A
        BuildConflicts tag names capabilities that conflict for
        building, such as a particular version of the gcc C compiler.
      </para>
    </sect2>
    <sect2>
      <title>Source files</title>
      <para>
        The source and patch tags identify the source files used to
        build the binary package. The patch tags identify any patches
        used to modify the sources.
      </para>
      <para>
        If you have more than one of a particular kind of tag, append a
        number. For example:
      </para>
      <para>
        Source0:
        ftp://ftp.uk.linux.org/pub/linux/telnet-%{telnet_version}.tar.gz
      </para>
      <para>
        Source2: telnet-client.tar.gz
      </para>
      <para>
        Source3: telnet-xinetd
      </para>
      <para>
        Source4: telnet.wmconfig
      </para>
      <para>
        Patch1: telnet-client-cvs.patch
      </para>
      <para>
        Patch5: telnetd-0.17.diff
      </para>
      <para>
        Patch6: telnet-0.17-env.patch
      </para>
      <para>
        Patch7: telnet-0.17-issue.patch
      </para>
      <para>
        Patch8: telnet-0.17-sa-01-49.patch
      </para>
      <para>
        Patch9: telnet-0.17-env-5x.patch
      </para>
      <para>
        Patch10: telnet-0.17-pek.patch
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Macros</title>
    <para>
      You can define macros in your spec files to help control how the
      package gets built. The following section describes these macros.
    </para>
    <sect2>
      <title>Variable definition macros</title>
      <para>
        The %define macro allows you to define new macros from within
        your spec file. A common usage is to define top-level
        directories with %define macros at the top of a spec file and
        then reference these directories throughout the file. For
        example:
      </para>
      <para>
        %define_bindir/bin
      </para>
      <para>
        This allows you to change the setting in one place, which is
        very handy for directory paths used throughout your spec files.
      </para>
      <para>
        Cross Reference
      </para>
      <para>
        See the section on Defining Macros in Spec Files in <xref linkend="ch-specfile-syntax"/> 
        for more on this subject.
      </para>
      <para>
        You can use this syntax for other things that may commonly
        change, such as version numbers. For example:
      </para>
      <para>
        %define major 2
      </para>
      <para>
        %define minor 2
      </para>
      <para>
        %define patchlevel 7
      </para>
      <para>
        Version: %{major}.%{minor}.%{patchlevel}
      </para>
      <para>
        Table B-1 lists more special macros used within spec files.
      </para>
      <para>
        Table B-1 Special spec file macros
      </para>
      <informaltable frame="all">
        <tgroup cols="2">
          <tbody>
            <row>
              <entry>
                <para>
                  Macro
                </para>
              </entry>
              <entry>
                <para>
                  Usage
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  %dump
                </para>
              </entry>
              <entry>
                <para>
                  Prints out macro values
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  %{echo:message}
                </para>
              </entry>
              <entry>
                <para>
                  Prints message to stderr
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  %{error:message}
                </para>
              </entry>
              <entry>
                <para>
                  Prints message to stderr and returns BADSPEC
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  %{expand:expression}
                </para>
              </entry>
              <entry>
                <para>
                  Like eval, expands expression
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  %{F:file_exp}
                </para>
              </entry>
              <entry>
                <para>
                  Expands file_exp to a file name
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  %global name value
                </para>
              </entry>
              <entry>
                <para>
                  Defines a global macro
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  %{P:patch_exp}
                </para>
              </entry>
              <entry>
                <para>
                  Expands patch_exp to a patch file name
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  %{S:source_exp}
                </para>
              </entry>
              <entry>
                <para>
                  Expands source_exp to a source file name
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  %trace
                </para>
              </entry>
              <entry>
                <para>
                  Toggles the printing of debugging information
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  %{uncompress:filename}
                </para>
              </entry>
              <entry>
                <para>
                  Tests if file filename is compressed. If so,
                  uncompresses and includes in the given context. If not
                  compressed, calls cat to include file in given
                  context.
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  %undefine macro
                </para>
              </entry>
              <entry>
                <para>
                  Undefines the given macro
                </para>
              </entry>
            </row>
            <row>
              <entry>
                <para>
                  %{warn:message}
                </para>
              </entry>
              <entry>
                <para>
                  Prints message to stderr
                </para>
              </entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>
    </sect2>
    <sect2>
      <title>Conditional macros</title>
      <para>
        You can use a special syntax to test for the existence of
        macros. For example:
      </para>
      <para>
        %{?macro_to_test: expression}
      </para>
      <para>
        This syntax tells RPM to expand the expression if macro_to_test
        exists, otherwise ignore. A leading exclamation point, !, tests
        for the non-existence of a macro:
      </para>
      <para>
        %{!?macro_to_test: expression}
      </para>
      <para>
        In this example, if the macro_to_test macro does not exist, then
        expand the expression.
      </para>
      <para>
        The %if macro performs an if test much like scripting languages.
        For example:
      </para>
      <para>
        %if %{old_5x}
      </para>
      <para>
        %define b5x 1
      </para>
      <para>
        %undefine b6x
      </para>
      <para>
        %endif
      </para>
      <para>
        A %else allows you to specify what to do if the test is not
        successful. For example:
      </para>
      <para>
        %if %{old_5x}
      </para>
      <para>
        %define b5x 1
      </para>
      <para>
        %undefine b6x
      </para>
      <para>
        %else
      </para>
      <para>
        %define b6x 1
      </para>
      <para>
        %undefine b5x
      </para>
      <para>
        %endif
      </para>
      <para>
        Again, use an exclamation point to negate the test. For example:
      </para>
      <para>
        %if ! %{old_5x}
      </para>
      <para>
        %define b5x 1
      </para>
      <para>
        %undefine b6x
      </para>
      <para>
        %endif
      </para>
      <para>
        You can use a && for an and test. For example:
      </para>
      <para>
        %if %{old_5x} && %{old_6x}
      </para>
      <para>
        %{error: You cannot build for .5x and .6x at the same time}
      </para>
      <para>
        %quit
      </para>
      <para>
        %endif
      </para>
    </sect2>
    <sect2>
      <title>Built-in macros</title>
      <para>
        The following macros are built into RPM and can help allow you
        to place your files in the right locations:
      </para>
      <para>
        %_prefix /usr
      </para>
      <para>
        %_exec_prefix %{_prefix}
      </para>
      <para>
        %_bindir %{_exec_prefix}/bin
      </para>
      <para>
        %_sbindir %{_exec_prefix}/sbin
      </para>
      <para>
        %_libexecdir %{_exec_prefix}/libexec
      </para>
      <para>
        %_datadir %{_prefix}/share
      </para>
      <para>
        %_sysconfdir %{_prefix}/etc
      </para>
      <para>
        %_sharedstatedir %{_prefix}/com
      </para>
      <para>
        %_localstatedir %{_prefix}/var
      </para>
      <para>
        %_libdir %{_exec_prefix}/lib
      </para>
      <para>
        %_includedir %{_prefix}/include
      </para>
      <para>
        %_oldincludedir /usr/include
      </para>
      <para>
        %_infodir %{_prefix}/info
      </para>
      <para>
        %_mandir %{_prefix}/man
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Build Sections</title>
    <para>
      After providing information about the package, you need to define
      the build stages, as described in <xref linkend="ch-specfiles"/> and <xref linkend="ch-rpmbuild"/>.
    </para>
    <sect2>
      <title>Build preparation</title>
      <para>
        The build preparation section sets the stage for the build.
        Usually this section has a %setup command. For example:
      </para>
      <para>
        %prep
      </para>
      <para>
        %setup -q
      </para>
    </sect2>
    <sect2>
      <title>Build</title>
      <para>
        The build section describes how to build the library or
        application. In most cases, the majority of the instructions are
        in the Makefile created by the prep section, leaving a build
        section something like the following:
      </para>
      <para>
        %build
      </para>
      <para>
        %configure
      </para>
      <para>
        make
      </para>
    </sect2>
    <sect2>
      <title>Installation</title>
      <para>
        After building, the installation section holds the commands to
        install the library or application. For example:
      </para>
      <para>
        %install
      </para>
      <para>
        rm -rf %{buildroot}
      </para>
      <para>
        %makeinstall
      </para>
    </sect2>
    <sect2>
      <title>Clean up</title>
      <para>
        The clean up section usually calls the make clean command to
        clean up the built files. For example:
      </para>
      <para>
        %clean
      </para>
      <para>
        rm -rf %{buildroot}
      </para>
    </sect2>
    <sect2>
      <title>Install and uninstall scripts</title>
      <para>
        RPM packages can run scripts prior to installation with %pre,
        and after installation with %post. You can also run scripts
        prior to an uninstall with %preun and after an uninstall with
        %postun. For example:
      </para>
      <para>
        %post
      </para>
      <para>
        /sbin/chkconfig --add ypbind
      </para>
      <para/>
      <para>
        %preun
      </para>
      <para>
        if [ "$1" = 0 ] ; then
      </para>
      <para>
        /sbin/service ypbind stop > /dev/null 2>&1
      </para>
      <para>
        /sbin/chkconfig --del ypbind
      </para>
      <para>
        fi
      </para>
      <para>
        exit 0
      </para>
      <para/>
      <para>
        %postun
      </para>
      <para>
        if [ "$1" -ge 1 ]; then
      </para>
      <para>
        /sbin/service ypbind condrestart > /dev/null 2>&1
      </para>
      <para>
        fi
      </para>
      <para>
        exit 0
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>File Tags</title>
    <para>
      The %files tag lists the files your package should install. For
      example:
    </para>
    <para>
      %files
    </para>
    <para>
      %defattr(-,root,root)
    </para>
    <para>
      /usr/X11R6/bin/xtoolwait
    </para>
    <para>
      /usr/X11R6/man/man1/xtoolwait.*
    </para>
    <para>
      You should mark configuration and documentation files with %config
      and %doc, respectively. For example:
    </para>
    <para>
      %files
    </para>
    <para>
      %defattr(-,root,root)
    </para>
    <para>
      /sbin/ypbind
    </para>
    <para>
      %{_mandir}/*/*
    </para>
    <para>
      %config /etc/rc.d/init.d/*
    </para>
    <para>
      %config /etc/yp.conf
    </para>
    <para>
      %dir /var/yp
    </para>
    <para>
      %dir /var/yp/binding
    </para>
    <para>
      %doc README NEWS
    </para>
    <sect2>
      <title>Making relocatable packages</title>
      <para>
        You can make a relocatable package by setting up one or more
        Prefix tags. For example:
      </para>
      <para>
        Prefix: /usr
      </para>
      <para>
        Prefix: /etc
      </para>
      <para>
        Each file in the %files section must then start with one of the
        prefixes you provided. With this, installers can easily relocate
        the package with a command like the following:
      </para>
      <para>
        # rpm --relocate /etc=/usr/etc file_name.rpm
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>The Change Log</title>
    <para>
      The change log usually appears at the end of a spec file. It holds
      messages for each significant change. For example:
    </para>
    <para>
      %changelog
    </para>
    <para>
      * Fri Jun 21 2002 Bob Marley <marley at redhat.com>
    </para>
    <para>
      - automated rebuild
    </para>
    <para/>
    <para>
      * Tue May 08 2001 Peter Tosh <tosh at redhat.com> 1.3-1
    </para>
    <para>
      - updated to 1.3
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-specfiles.xml ---
<!-- $Id: -->

<chapter id="ch-specfiles">
  <title>Working with Spec Files</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Writing spec files
      </para>
    </listitem>
    <listitem>
      <para>
        Defining package information
      </para>
    </listitem>
    <listitem>
      <para>
        Controlling the build
      </para>
    </listitem>
    <listitem>
      <para>
        Listing the files in the package
      </para>
    </listitem>
    <listitem>
      <para>
        Defining spec file macros
      </para>
    </listitem>
  </itemizedlist>
  <para>
    The previous chapter introduces the concepts of how to build RPMs,
    and briefly covered the spec file, which controls how RPM packages
    are built and installed. This chapter delves into how to create spec
    files and the next chapter covers advanced spec file topics such as
    using conditional commands and making relocatable packages.
  </para>
  <para>
    A spec file defines all the commands and values that are required
    for creating a package, everything from the name and version number
    to the actual commands used to build the program you are packaging.
  </para>
  <para>
    This chapter covers the spec file syntax and how to write spec
    files. In goes in depth into defining information about your
    package, controlling how the software will be built, defining what
    exactly should go into the package, and customizing your build with
    RPM macros.
  </para>
  <sect1>
    <title>Reading Spec Files</title>
    <para>
      The first step to learning more about spec files is to read
      through some of the huge number of spec files for the source RPMs
      that come with your Linux distribution. Looking at these files
      will show two things right away:
    </para>
    <para>
      *You will see that the spec file syntax is not really as
      complicated as it appears.
    </para>
    <para>
      *You will see how many others have solved problems similar to
      those you need to solve.
    </para>
    <para>
      I’ve used real-world examples throughout this book, to show how
      the RPMs you need to deal with actually work. Some of the more
      interesting packages include anything that has a client and a
      server component, anything with networking or e-mail, and anything
      that installs a system service. All these types of packages solve
      problems that you will commonly face. Some useful spec files to
      look at are those for anonftp, telnet, vnc, and sendmail. To get
      these spec files, you need to install the corresponding source
      RPMs for each of these packages.
    </para>
    <para>
      As you read through spec files, you’ll start to see common
      patterns in how packages are defined, named, the macros used, and
      common elements in the build sections of the spec files. You’ll
      also see how network services are installed on Linux, as well as
      example install and uninstall scripts. The next sections provide
      more information on the things to look for within spec files.
    </para>
    <para>
      Furthermore, even with the plethora of options RPM provides, if
      you know shell scripting basics and something about how C programs
      are normally built, with configure scripts and make commands, you
      will find most spec files relatively easy to understand.
    </para>
    <para>
      The following sections go into the details of writing your own
      spec files. Keep your example spec files handy as you read through
      these sections.
    </para>
  </sect1>
  <sect1>
    <title>Writing Spec Files</title>
    <para>
      Spec files are text files containing RPM directives. These
      directives use a simple syntax of a tag name, a colon, and a
      value:
    </para>
    <para>
      TagName: value
    </para>
    <para>
      For example:
    </para>
    <para>
      Version: 1.15
    </para>
    <para>
      This example sets the package version to 1.15. The name of the
      item is not case sensitive, so tag names of version, Version, or
      VERSION all set the same value. This syntax works for most
      settings, including Name, Release, and so on.
    </para>
    <para>
      In addition to this directive syntax, you can define macros using
      the RPM %define syntax. For example:
    </para>
    <para>
      %define major 2
    </para>
    <para>
      This example defines a macro named major with a value of 2. Once
      defined, you can access macros using the %{macro_name} or just
      %macro_name syntaxes. For example:
    </para>
    <para>
      source: %{name}-%{version}.tar.gz
    </para>
    <para>
      See the section "Defining Spec File Macros" later in this chapter
      for more options for macros.
    </para>
    <para>
      Major sections in the spec file are also delimited with % markers.
      For example, the build section starts with %build on a line by
      itself.
    </para>
    <para>
      Note
    </para>
    <para>
      The multiple uses of the % sign aren’t really that confusing in
      practice. Read through some spec files and you should find most of
      the commands are easily understood.
    </para>
    <para>
      Blank lines separate sections in the spec file, which makes sense
      for readability as well.
    </para>
    <sect2>
      <title>Comments</title>
      <para>
        To help document your work, you can include comments (to
        yourself and others reading the spec file). Any line starting
        with a hash character, #, holds a comment. RPM will ignore
        comments.
      </para>
      <para>
        # This is a comment.
      </para>
      <para>
        In spec files, comments are mostly to help explain your syntax
        choices to yourself should you view the spec file later.
        Comments are a good thing. You should comment heavily,
        especially for any choice that deviates from the norm. For
        example, if you provide special C compiler options for building
        the package, add comments to describe why you picked the options
        and how necessary they are. Such comments help immensely should
        you need to port the RPM to another architecture or modify how
        it was built.
      </para>
      <para>
        Tip
      </para>
      <para>
        Avoid single percent signs, %, in comments. For example:
      </para>
      <para>
        # Added new commands to %prep
      </para>
      <para>
        The rpmbuild command may report an error of a second %prep
        section. To get around this problem, use two percent signs, such
        as %%prep, in spec file comments.
      </para>
    </sect2>
    <sect2>
      <title>Storing spec files on disk</title>
      <para>
        As discussed in <xref linkend="ch-creating-rpms"/> , the
[...2521 lines suppressed...]
    <para>
      <require name="make" />
    </para>
    <para>
      </buildrequires>
    </para>
    <para/>
    <para>
      <!-- packages -->
    </para>
    <para>
      <package group="System/Base" autoreqprov="no">
    </para>
    <para>
      <requires>
    </para>
    <para>
      <require name="glibc" />
    </para>
    <para>
      </requires>
    </para>
    <para>
      <summary>The Bash package contains the bash
      program.</summary>
    </para>
    <para>
      <description>%{summary}
    </para>
    <para>
      Bash is the Bourne-Again SHell, which is a widely used command
      interpreter
    </para>
    <para>
      on Unix systems. Bash is a program that reads from standard input,
      the
    </para>
    <para>
      keyboard. A user types something and the program will evaluate
      what he has
    </para>
    <para>
      typed and do something with it, like running a
      program.</description>
    </para>
    <para>
      <files list="%{name}.files.lst" />
    </para>
    <para>
      </package>
    </para>
    <para/>
    <para>
      <package name="bash-doc" group="Documentation/System/Base"
      autoreqprov="no">
    </para>
    <para>
      <requires>
    </para>
    <para>
      <require name="%{name}" />
    </para>
    <para>
      </requires>
    </para>
    <para>
      <summary>Documentation for the bash package.</summary>
    </para>
    <para>
      <description>%{summary}</description>
    </para>
    <para>
      <pre script="%{name}-doc.pre.sh" />
    </para>
    <para>
      <files list="%{name}-doc.files.lst" />
    </para>
    <para>
      </package>
    </para>
    <para/>
    <para>
      <!-- scripts to create the package -->
    </para>
    <para>
      <prep script="%{name}.prep.sh">
    </para>
    <para>
      <setup />
    </para>
    <para>
      <script>echo &quot;Prep
      completed&quot;</script>
    </para>
    <para>
      </prep>
    </para>
    <para>
      <build script="%{name}.build.sh" />
    </para>
    <para>
      <install script="%{name}.install.sh" />
    </para>
    <para>
      <clean script="%{name}.clean.sh" />
    </para>
    <para/>
    <para>
      <!-- changelog -->
    </para>
    <para>
      <changelog>
    </para>
    <para>
      <changes date="Mon Aug 26 2002" version="2.05a-02test"
    </para>
    <para>
      author="" author-email="">
    </para>
    <para>
      <change>Added setup macro to extract files</change>
    </para>
    <para>
      <change>Initial version ready for jbj</change>
    </para>
    <para>
      </changes>
    </para>
    <para>
      </changelog>
    </para>
    <para>
      </spec>
    </para>
    <para>
      Note
    </para>
    <para>
      XML spec files are a very experimental feature. Future releases of
      RPM will likely provide more support for XML spec files. The
      format will likely change.
    </para>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      This chapter covers spec files, the files that define how to build
      packages. Start your spec file by defining package information,
      such as the name, version, and release number. You can also add a
      detailed description to help administrators decide whether to
      install your packages.
    </para>
    <para>
      You need to name all of the source and patch files used to build
      the package. In most cases, the source files are compressed tar
      archives. After naming all the sources and patches, you need to
      control how the rpmbuild command should build your package. This
      comes in four sections.
    </para>
    <para>
      The %prep section prepares for the build by extracting the source
      files and applying patches. The %build section defines the
      commands to build the software, normally something as simple as
      running a configure script and then the make command. The %install
      section contains the commands for installing the software. And,
      the %clean section provides commands to clean up after the build.
    </para>
    <para>
      For these sections, you can use handy RPM macros for common tasks,
      such as running the configure script or the make install command.
      You can also define scripts the rpm command should run before and
      after installing, as well as before and after removing the
      package.
    </para>
    <para>
      Spec files contain a listing of all the files that should go into
      the package, as well as where those files should be placed on the
      user’s hard disk.
    </para>
    <para>
      You can define RPM macros in your spec files to make commands that
      can work with different directory structures as well as simplify
      common commands.
    </para>
    <para>
      While it may seem that this chapter described a great many options
      for making spec files, there’s more to come. The next chapter
      covers advanced spec file topics such as triggers, conditional
      builds, and specifying dependencies.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-transactions.xml ---
<!-- $Id: -->

<chapter id="ch-transactions">
  <title>Transactions</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Understanding transactions
      </para>
    </listitem>
    <listitem>
      <para>
        Querying for packages based on transactions
      </para>
    </listitem>
    <listitem>
      <para>
        Rolling back transactions
      </para>
    </listitem>
    <listitem>
      <para>
        Saving old packages when upgrading
      </para>
    </listitem>
  </itemizedlist>
  <para>
    When packages depend on other packages, you may have to install
    multiple packages to add a single application. Some of the packages
    may install cleanly; others may not. But you have to install all of
    the packages to get the complete application. The designers of the
    RPM system understood this problem and added the concept of
    transactions to RPM.
  </para>
  <para>
    This chapter covers transactions and how they can help you cleanly
    install a set of dependent packages. But transactions won’t solve
    all your problems. You still have to resolve conflicts and
    dependencies by using the techniques provided in the last three
    chapters.
  </para>
  <sect1>
    <title>Understanding Transactions</title>
    <para>
      A transaction is a way to delimit a set of operations. All the
      operations can be undone, often called rolled back. Once rolled
      back, the system is back in the same state it was prior to the
      transaction. If all the operations succeed, though, the system
      will be in a new state. The key issue is that all of the
      operations must complete successfully, or you can roll back the
      entire transaction. The assumption is that if any of the
      operations fail, the system will be in an inconsistent or
      erroneous state. Transactions are a way to prevent that.
    </para>
    <para>
      Transactions are common when working with databases, but they are
      just as important when working with packages.
    </para>
    <para>
      Starting with RPM version 4.0.4, transactions and rollbacks became
      a workable part of any administrator's toolkit. With RPM, the rpm
      command sets up a transaction any time you attempt to install,
      remove, or upgrade more than one package. The rpm command
      automatically makes a transaction.
    </para>
    <sect2>
      <title>When do you need transactions?</title>
      <para>
        Whenever you install or remove packages, the RPM system assigns
        a transaction and a transaction ID to the set of packages. You
        can then perform operations on the packages that share the same
        ID, including rolling back the transaction.
      </para>
      <para>
        Note
      </para>
      <para>
        Rollbacks work only for package upgrades with the 4.1 version of
        the RPM system, not package installs
      </para>
      <para>
        The RPM system saves an image of the RPM package header for each
        package installed or removed. You can use this image, along with
        RPM transaction IDs, to back out of transactions should
        something go wrong when setting up your system.
      </para>
      <para>
        The main advantage of transactions with RPM, though, is the fact
        that the rpm command automatically sets up a transaction for all
        the packages on each command line and does not perform the
        operation if any package fails. This ability to automatically
        set up transactions for each call to the rpm command eliminates
        many errors when working with packages.
      </para>
      <para>
        Use a transaction when you need to be sure that a set of
        packages install properly.
      </para>
    </sect2>
    <sect2>
      <title>Backing out of transactions</title>
      <para>
        With RPM, backing out of a transaction involves two operations:
        rolling back the transaction and reinstalling the former
        packages to restore the previous system state. In the simplest
        case, the rpm command handles all the tasks for you. If you try
        to install, upgrade, or remove multiple packages and any package
        fails, the rpm command will restore the system state for you.
      </para>
      <para>
        This automatic support for transactions is a great help to
        system administrators, but it only applies when you first
        install, upgrade, or remove the packages. If you have upgraded
        your system and later discover problems, then you can also use
        the --rollback option to roll the system back from a set of
        upgrades, in a limited set of circumstances.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Transactions with the rpm Command</title>
    <para>
      To set up an RPM transaction, you don't have to do much. All you
      need to do is pass more than one RPM package on the rpm command
      line. For example, to set up a transaction for installing three
      packages, use a command like the following:
    </para>
    <para>
      rpm -ihv package1.rpm package2.rpm package3.rpm
    </para>
    <para>
      If any of the packages fail to install, the rpm command will not
      install any packages. All of the packages will be installed, or
      none.
    </para>
    <para>
      This way, if you have a number of packages that together perform
      some function, such as an Integrated Development Environment
      (IDE), along with program-language compilers and other
      software-development tools, you can ensure that all get installed.
    </para>
    <para>
      As an example, say you need to install the gnorpm package, which
      provides a graphical front end for the rpm command, and the
      rpmrebuild package, which allows you to create RPMs from
      already-installed packages.
    </para>
    <para>
      Cross Reference
    </para>
    <para>
      The gnorpm command is covered in
      <xref linkend="ch-management-software"/> . The rpmrebuild package
      is covered in the "Saving Old Packages" section in this chapter.
    </para>
    <para>
      You can install these packages with a transaction by using the
      following command:
    </para>
    <para>
      # rpm -ihv gnorpm-0.9-1.i386.rpm rpmrebuild-1.0-0.noarch.rpm
    </para>
    <para>
      Preparing... ########################################### [100%]
    </para>
    <para>
      package gnorpm-0.9-1 is already installed
    </para>
    <para>
      The rpmrebuild package can be installed. (We know this since the
      rpm command did not issue an error about this package.) But
      because it was on the same command line as the gnorpm package, the
      transaction failed. No packages were installed.
    </para>
    <para>
      To check that the rpmrebuild package was not installed (that is,
      to check that the transaction worked as expected), you can use the
      rpm –q command to see if the rpmrebuild package was installed or
      not. To do so, use a command like the following:
    </para>
    <para>
      # rpm -q rpmrebuild
    </para>
    <para>
      package rpmrebuild is not installed
    </para>
    <para>
      This shows that the rpmrebuild package was not installed, even
      though the package could be installed on its own. To check that
      the package could be installed, you can use the --test option, as
      shown following:
    </para>
    <para>
      # rpm -i --test rpmrebuild-1.0-0.noarch.rpm
    </para>
    <para>
      #
    </para>
    <para>
      This command shows that the rpmrebuild package would install
      successfully on its own. If there were problems, the rpm command
      would have issued an error message.
    </para>
    <para>
      This example shows that when you try to install multiple packages
      with the rpm command, should any fail, the rpm command will not
      install any.
    </para>
    <para>
      The rpm command works similarly for removing packages and
      upgrading packages. When removing packages, you’ll see an error
      like the following if any of the packages on the command line
      cannot be removed:
    </para>
    <para>
      # rpm -e setup jikes-1.17
    </para>
    <para>
      error: Failed dependencies:
    </para>
    <para>
      setup is needed by (installed) basesystem-8.0-1
    </para>
    <para>
      setup >= 2.0.3 is needed by (installed) initscripts-6.95-1
    </para>
    <para>
      setup >= 2.5.4-1 is needed by (installed) filesystem-2.1.6-5
    </para>
    <para>
      setup is needed by (installed) xinetd-2.3.7-2
    </para>
    <para>
      setup is needed by (installed) dump-0.4b28-4
    </para>
    <para>
      The setup package could not be removed because it had several
      capabilities needed by other packages. You can check that the
      jikes package was not removed by using the rpm –q command, even
      though it had no failed dependencies:
    </para>
    <para>
      # rpm -q jikes
    </para>
    <para>
      jikes-1.17-1
    </para>
    <para>
      This package was not removed because it appeared as part of the
      same command that failed, so none of the operations were
      performed.
    </para>
    <para>
      When upgrading, you will also see an error message if any of the
      package upgrades fail. For example:
    </para>
    <para>
      # rpm -Uhv jikes-1.14-1.i386.rpm autoupdate-3.1.5-1.noarch.rpm
    </para>
    <para>
      error: jikes-1.14-1.i386.rpm cannot be installed
    </para>
    <para>
      You can then check that the jikes package, in this example, was
      not downgraded to the earlier version with the rpm –q command:
    </para>
    <para>
      # rpm -q jikes
    </para>
    <para>
      jikes-1.17-1
    </para>
    <sect2>
      <title>Transaction IDs</title>
      <para>
        The rpm command gives every package installed a transaction ID.
        The transaction ID is a Unix time stamp (number of seconds since
        January 1, 1970). You can then perform some operations on
        packages based on the transaction ID.
      </para>
      <para>
        Note
      </para>
      <para>
        The fact that a transaction ID uses a Unix timestamp may change
        in the future.
      </para>
      <para>
        All the packages installed at the same time are given the same
        transaction ID. This means that you can perform operations on a
        set of packages, the packages that were installed together.
      </para>
      <para>
        But there’s also a downside to this. All the packages
        installed when you first installed or upgraded your Linux system
        are given the same transaction ID. This means you cannot
        selectively act on these packages using the transaction ID,
        because you will likely get far more packages than you want to
        work on.
      </para>
      <sect3>
        <title>Viewing RPM Transaction IDs</title>
        <para>
          To view the install transaction ID (a date code) for a given
          package, you can use a command like the following:
        </para>
        <para>
          $ rpm -q --qf "%-20{NAME} %-20{INSTALLTID}\n" jikes
        </para>
        <para>
          jikes 1035589778
        </para>
        <para>
          This command uses the --qf or --queryformat option to specify
          the data to return from the RPM query command. In this case,
          the command requests the name of the package as well as the
          transaction ID (TID) for installation.
        </para>
        <para>
          Cross Reference
        </para>
        <para>
          <xref linkend="ch-using-rpm-db"/> describes the --queryformat
          option.
        </para>
        <para>
          There is also a transaction ID for removal, the REMOVETID. You
          can also query for this ID. For example, if a package hasn't
          been removed, you'll see an entry like the following:
        </para>
        <para>
          $ rpm -qa --qf "%-20{NAME} %-20{REMOVETID}\n" termcap
        </para>
        <para>
          termcap (none)
        </para>
      </sect3>
      <sect3>
        <title>Viewing the Packages Associated with a Transaction ID</title>
        <para>
          Once you have a transaction ID, you can use the --tid option,
          short for transaction ID, to query for the package associated
          with a given transaction, using a command like the following:
        </para>
        <para>
          $ rpm -q --tid 1035589778
        </para>
        <para>
          jikes-1.17-1
        </para>
        <para>
          This example uses the transaction ID that the earlier query
          example returned. If you installed more than one package at
          the same time, you will see a listing of all the packages that
          share the transaction ID.
        </para>
        <para>
          For example, to see many packages with one transaction ID, you
          can query for packages installed when you installed or
          upgraded your version of Linux. First, query for the
          transaction ID of a package you know was installed with the
          Linux distribution, such as setup on a &RH; system:
        </para>
        <para>
          $ rpm -q --qf "%-20{NAME} %-20{INSTALLTID}\n" setup
        </para>
        <para>
          setup 1033838323
        </para>
        <para>
          Second, use this transaction ID and query for all packages
          with this ID, using code like the following:
        </para>
        <para>
          $ rpm -q --tid 1033838323 | more
        </para>
        <para>
          redhat-menus-0.26-1
        </para>
        <para>
          glibc-2.2.93-5
        </para>
        <para>
          cracklib-2.7-18
        </para>
        <para>
          gdbm-1.8.0-18
        </para>
        <para>
          gmp-4.1-4
        </para>
        <para>
          libacl-2.0.11-2
        </para>
        <para>
          libjpeg-6b-21
        </para>
        <para>
          linc-0.5.2-2
        </para>
        <para>
          pcre-3.9-5
        </para>
        <para>
          shadow-utils-20000902-12
        </para>
        <para>
          libtermcap-2.0.8-31
        </para>
        <para>
          freetype-2.1.2-7
        </para>
        <para>
          info-4.2-5
        </para>
        <para>
          fileutils-4.1.9-11
        </para>
        <para>
          psmisc-20.2-6
        </para>
        <para>
          ntp-4.1.1a-9
        </para>
        <para>
          mount-2.11r-10
        </para>
        <para>
          cracklib-dicts-2.7-18
        </para>
        <para>
          krb5-libs-1.2.5-6
        </para>
        <para>
          cyrus-sasl-2.1.7-2
        </para>
        <para>
          usermode-1.63-1
        </para>
        <para>
          Xft-2.0-1
        </para>
        <para>
          Note
        </para>
        <para>
          Be sure to replace the transaction ID shown here with the
          transaction ID obtained by querying your system.
        </para>
        <para>
          This example shows just a few of the packages installed when
          the &RHL; was installed.
        </para>
        <para>
          With these options, you can find the transaction IDs for given
          packages and can use the rpm command to install, remove, or
          otherwise modify the packages that share a transaction ID.
        </para>
      </sect3>
    </sect2>
    <sect2>
      <title>Rolling Back Transactions</title>
      <para>
        The --rollback option to the rpm command allows you to roll back
        upgrades based on a time. Use a command like the following:
      </para>
      <para>
        # rpm –U --rollback "3 months ago"
      </para>
      <para/>
      <para>
        The --rollback option is very limited in what it can do. The
        --rollback option works only for packages that have been
        upgraded. You cannot rollback the initial installation of a
        package. This is to prevent you from accidentally rolling back
        all packages.
      </para>
      <para>
        The --rollback option works best if you want to restore the
        system to a previous state, prior to performing any other RPM
        operations. That is, soon after you upgraded a package and
        decide that it isn’t working right. If you have modified the
        RPM system after performing the transaction you want to
        rollback, there may be unintended consequences if any new
        package depends on the packages you want to roll back. In
        addition, the --rollback option only works in limited situations
        but does not always report when these conditions are not met.
        The rpm command may simply do nothing, or it may remove packages
        you do not expect.
      </para>
      <para>
        Warning
      </para>
      <para>
        Before running the --rollback option, backup your RPM database
        as described in <xref linkend="ch-using-rpm-db"/> .
      </para>
      <para>
        Because of all these limitations, rollbacks do not work in all
        situations. In place of the --rollback option, you can use the
        query shortcuts introduced in <xref linkend="ch-using-rpm-db"/>
        and find the packages you have installed recently (if that is
        what you want to roll back). In this case, you can use the rpm
        command to remove the packages you want to get rid of and
        reinstall the packages you want to restore.
      </para>
      <para>
        In many cases, this manual approach is safest, and you will have
        a clearer understanding about what was installed or upgraded on
        your system.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Saving Old Packages</title>
    <para>
      When installing, removing, or upgrading, you can use the
      --repackage command-line option to save a version of something
      like the old package to a file, making a backup of the older
      package contents.
    </para>
    <para>
      Warning
    </para>
    <para>
      The package created by the --repackage option is not a complete
      RPM package. You can use the rpmbuild command to make it into a
      complete package, but by itself, it will not be a complete
      package. See <xref linkend="ch-specfiles"/>,
      <xref linkend="ch-advanced-packaging"/>, and
      <xref linkend="ch-rpmbuild"/> for more on building packages.
    </para>
    <para/>
    <para>
      You can later reinstall the old files, once they have been made
      into a complete package. This can be quite useful if something
      goes wrong or the upgraded package has bugs. You can fall back to
      the old package if needed.
    </para>
    <para>
      By default, the --repackage option puts the old package in the
      /var/spool/repackage directory. Other common directories are
      /var/spool/up2date or /var/tmp. Your RPM configuration determines
      the directory used by this option.
    </para>
    <para>
      Note
    </para>
    <para>
      The up2date name comes from the &RH; service for keeping a system
      up to date with regard to package versions.
    </para>
    <para>
      For example, say you have a package, jikes (a Java programming
      language compiler used in previous examples) that you want to
      upgrade. But you are worried that the new version may not work
      properly.
    </para>
    <para>
      First, check the version you have. For example:
    </para>
    <para>
      # rpm -q jikes
    </para>
    <para>
      jikes-1.14-1
    </para>
    <para>
      This shows you are at version 1.14 of the jikes Java compiler. You
      can then upgrade to version 1.17 while repackaging the old
      version, as shown following:
    </para>
    <para>
      # rpm -Uhv --repackage jikes-1.17-glibc2.2-1.i386.rpm
    </para>
    <para>
      Preparing... ########################################### [100%]
    </para>
    <para>
      Repackaging...
    </para>
    <para>
      1:jikes ########################################### [100%]
    </para>
    <para>
      Upgrading...
    </para>
    <para>
      1:jikes ########################################### [100%]
    </para>
    <para>
      This upgrade has kept a copy of the old package in the
      /var/spool/repackage directory. You can verify this with the
      following command:
    </para>
    <para>
      $ ls -l /var/spool/repackage/
    </para>
    <para>
      total 692
    </para>
    <para>
      -rw-r--r-- 1 root root 703037 Oct 25 18:49 jikes-1.14-1.i386.rpm
    </para>
    <para>
      You can see a version of the old package, with the old version
      number.
    </para>
    <para>
      Warning
    </para>
    <para>
      This is not the same as the original package. This is not a
      complete package.
    </para>
    <para>
      The repackaged RPM contains a snapshot of the package’s files as
      they were on your hard disk, not as they were when you originally
      installed the package. Thus, the contents may differ if the files
      have changed on your hard disk. In addition, the --repackage
      option may not properly sign the package as the original was.
    </para>
    <para>
      In addition to the --repackage option with the rpm command, you
      can use a free tool called rpmrebuild to make snapshots of any
      installed packages.
    </para>
    <para>
      Written by Eric Gerbier, rpmrebuild allows you to create an RPM
      from the installed, and perhaps modified, version of a package.
      You don’t have to upgrade, remove, or install a new package, as
      you do with the --repackage option.
    </para>
    <para>
      Download rpmrebuild from http://rpmrebuild.sourceforge.net/.
    </para>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      Transactions allow you to install multiple packages as a group and
      know that either all the packages will succeed in installing or
      none of them will. This is very important if you have a set of
      interlocking packages that you need to install.
    </para>
    <para>
      All the packages you install, remove, or upgrade on the same
      command line are automatically made part of a transaction. The rpm
      command will ensure that all packages can be installed, removed,
      or upgraded, and will not perform the operation unless all will
      succeed.
    </para>
    <para>
      All packages installed or removed are given a transaction ID,
      which uses a Unix timestamp (the number of seconds since January
      1, 1970). All packages installed or removed at the same time are
      given the same transaction ID. You can then query by transaction
      IDs to perform operations on all the packages installed together.
    </para>
    <para>
      The --repackage option tells the rpm command to make a backup RPM
      of the current package when you are installing or upgrading a more
      recent version or removing the package. By default, the backup RPM
      is placed in the /var/spool/repackage directory. Note that a
      package created this way is not exactly the same as the original
      package. Files may have changed on disk. In addition, packages
      created with the --repackage option are not real valid RPM
      packages. You cannot install these packages without performing
      extra operations to create a real RPM package from the repackaged
      data.
    </para>
    <para/>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-using-rpm-db.xml ---
<!-- $Id: -->

<chapter id="ch-using-rpm-db">
  <title>Using the RPM Database</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Querying the RPM database
      </para>
    </listitem>
    <listitem>
      <para>
        Getting information on RPM files
      </para>
    </listitem>
    <listitem>
      <para>
        Finding out which packages own files on your system
      </para>
    </listitem>
    <listitem>
      <para>
        Verifying installed packages
      </para>
    </listitem>
    <listitem>
      <para>
        Backing up the RPM database
      </para>
    </listitem>
    <listitem>
      <para>
        Repairing damaged RPM databases
      </para>
    </listitem>
  </itemizedlist>
  <para>
    Every package you install with RPM is recorded in the RPM database.
    The RPM system includes commands to query this database to find out
    which packages are installed and to provide quite a few details
    about these packages.
  </para>
  <para>
    This chapter covers querying both the RPM database and RPM package
    files. Both types of query are important:
  </para>
  <para>
    *Query the RPM database to see what is installed, or not installed,
    on your system.
  </para>
  <para>
    *Query package files to see what the files require, as well as what
    the files provide.
  </para>
  <para>
    In addition to querying the RPM database, you can use the database
    to verify packages. Since this database is so important to the
    management of your Linux system, this chapter covers how to back it
    up, as well as how to repair a damaged RPM database.
  </para>
  <sect1>
    <title>Querying the RPM Database</title>
    <para>
      In <xref linkend="ch-using-rpm"/> , you saw that the rpm command usually takes one major
      command-line option to tell it the operation to perform and a
      myriad of command-line options to customize the operation. The rpm
      command may also take the name of one or more RPM package files or
      the name of one or more installed packages. For example, the rpm
      –i command performs an installation operation, and the rpm –U
      command performs an upgrade.
    </para>
    <para>
      For querying the RPM database, the major command-line option is
      –q, short for query. This option tells the rpm command to query
      the RPM database. You can also use the long option --query.
    </para>
    <para>
      In the last few chapters, you've used the –q option with the rpm
      command to query just for the presence or absence of installed
      packages. You can expand the -q option to perform a wide array of
      queries to find out information about the packages installed on a
      Linux system.
    </para>
    <sect2>
      <title>Querying packages</title>
      <para>
        The basic format of the rpm –q command follows:
      </para>
      <para>
        rpm –q package_name
      </para>
      <para>
        You need to provide the name of a package to query. For example:
      </para>
      <para>
        rpm -q telnet-0.17
      </para>
      <para>
        This command returns the name of the package, if installed. For
        example:
      </para>
      <para>
        telnet-0.17-20
      </para>
      <para>
        If the package is not installed, you’ll see a message like the
        following:
      </para>
      <para>
        package telnet-0.17 is not installed
      </para>
      <para>
        You can provide the whole package name to the rpm command, which
        includes the name, the version, and the RPM package number, as
        discussed in <xref linkend="ch-rpm-overview"/> . You can also just provide the name and
        version number, as shown previously, or just the base name of
        the package.
      </para>
      <para>
        For example, the following command uses just the base name of
        the package:
      </para>
      <para>
        $ rpm -q telnet
      </para>
      <para>
        telnet-0.17-20
      </para>
      <para>
        Note
      </para>
      <para>
        The rpm –q command expects a package name. Although it
        supports some amount of customized queries, you really need to
        know which packages you want the rpm command to report on.
      </para>
      <para>
        You can provide more than one package name; the rpm command
        reports on each package, as shown following.
      </para>
      <para>
        $ rpm -q telnet telnet-server
      </para>
      <para>
        telnet-0.17-20
      </para>
      <para>
        telnet-server-0.17-20
      </para>
      <para/>
      <para>
        You need to change the way you query if you want to perform
        searches when you do not know the full package name in advance.
        The following sections cover options for creating various
        queries.
      </para>
    </sect2>
    <sect2>
      <title>Querying everything</title>
      <para>
        Up to now, we have used the rpm command to query only for
        specific packages. The –a option tells the rpm command to
        query for all packages. You can also use the longer option,
        --all, in place of –a.
      </para>
      <para>
        For example:
      </para>
      <para>
        rpm -qa
      </para>
      <para>
        This command returns every package installed on your system,
        quite a few packages. The packages are returned one per line, as
        shown following.
      </para>
      <para>
        words-2-17
      </para>
      <para>
        kudzu-0.99.23-1
      </para>
      <para>
        openldap-2.0.11-13
      </para>
      <para>
        rpm-4.0.3-1.03
      </para>
      <para>
        kernel-smp-2.4.7-10
      </para>
      <para>
        quota-3.01pre9-3
      </para>
      <para>
        expat-1.95.1-7
[...4109 lines suppressed...]
    </para>
    <para>
      Available from SleepyCat Software at www.sleepycat.com/, the
      Berkeley DB library provides a simple database API. This is not a
      traditional relational database. Instead, data values are stored
      in what amounts to a persistent hash table of name/value pairs.
      This type of database is very quick to look up a named entry (such
      as a package name) but is not so quick for iterating over all the
      entries.
    </para>
    <para>
      One of the nice things about this library is that it is available
      in an open-source format, and you can get programming API
      libraries for C, C++, Java, Python, Perl, and Tcl languages.
    </para>
    <para>
      The RPM database is really a number of Berkeley DB databases, each
      designed for a different type of query.
    </para>
    <para>
      If something goes wrong with your RPM database, you can first try
      to rebuild it. If that fails, you may need to initialize a new
      database, although that is generally not needed. First and
      foremost, however, you should back up this database.
    </para>
    <para/>
    <sect2>
      <title>Backing up the RPM database</title>
      <para>
        As mentioned before, the RPM database resides in the
        /var/lib/rpm. You can back up the RPM database by using commands
        such as the following:
      </para>
      <para>
        # cd /var/lib
      </para>
      <para>
        # tar cvf rpmdb.tar ./rpm
      </para>
      <para>
        # gzip rpmdb.tar
      </para>
      <para>
        These commands create a tar archive from the contents of the rpm
        directory (where the RPM database is stored) and compress the
        file with the gzip command.
      </para>
      <para>
        Note
      </para>
      <para>
        Adding the z option to the tar command can create a compressed
        archive directly, without the need for the gzip command.
      </para>
    </sect2>
    <sect2>
      <title>Rebuilding the RPM database</title>
      <para>
        If the RPM database has been corrupted in some way, you can use
        the --rebuilddb option to tell the rpm command to rebuild your
        database.
      </para>
      <para>
        For example:
      </para>
      <para>
        rpm --rebuilddb
      </para>
      <para>
        This command rebuilds the RPM database from the installed
        packages, the file named Packages in the /var/lib/rpm directory.
        Only the Packages file is required. All the other files can be
        recreated from the Packages file. If your database is OK, this
        command won't do much, other than shrink the size of your RPM
        database by removing unused entries. This command will take some
        time to execute, though.
      </para>
      <para>
        Warning
      </para>
      <para>
        Before running this command, back up your RPM database.
      </para>
      <para>
        To check that the rpm --rebuilddb command has not damaged the
        RPM database, you can check with a file listing, query all
        packages, and then check the results of the rpm –rebuilddb
        command with another file listing when done.
      </para>
      <para>
        Another useful technique that can help with a corrupted RPM
        database is to use the db_dump and db_load utilities that come
        with RPM (from the SleepyCat DB database library). Use db_dump
        to dump the Packages file. Then, use db_load to reload the
        Packages file. The act of dumping and restoring may fix a
        corrupted file. As always, back up your RPM database prior to
        performing these commands.
      </para>
    </sect2>
    <sect2>
      <title>Creating a new RPM database</title>
      <para>
        If all else fails, use the --initdb option to tell the rpm
        command to create a new empty RPM database. In almost all cases,
        you do not want to create a new RPM database, since this
        database will be empty. It will not have any knowledge about the
        packages you have already installed on your system. That could
        lead to a lot of problems, since you have the files installed,
        but the RPM system just doesn’t know about them.
      </para>
      <para>
        The basic syntax follows.
      </para>
      <para>
        rpm --initdb
      </para>
      <para>
        Note
      </para>
      <para>
        This command should not damage an existing database.
      </para>
      <para>
        If the RPM system cannot be rebuilt, you may have to reinstall
        the operating system to recreate a clean system. In general, if
        things are this far gone, reinstalling may be your best answer
        instead of wiping the RPM database and creating an empty
        database.
      </para>
      <para>
        You can also use the --dbpath option to tell the rpm command to
        create an RPM database in a different directory.
      </para>
      <para>
        For example:
      </para>
      <para>
        mkdir /tmp/rpm
      </para>
      <para>
        rpm --initdb --dbpath /tmp/rpm
      </para>
      <para>
        These commands create a temporary directory and an RPM database
        in the /tmp/rpm directory.
      </para>
      <para>
        After running this command, you can examine the files created.
      </para>
      <para>
        # ls -l /tmp/rpm
      </para>
      <para>
        total 288
      </para>
      <para>
        -rw-r--r-- 1 root root 8192 Oct 10 20:29 __db.001
      </para>
      <para>
        -rw-r--r-- 1 root root 1310720 Oct 10 20:29 __db.002
      </para>
      <para>
        -rw-r--r-- 1 root root 360448 Oct 10 20:29 __db.003
      </para>
      <para>
        -rw-r--r-- 1 root root 12288 Oct 10 20:29 Packages
      </para>
      <para>
        This shows an empty RPM database.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      This chapter covers the rpm command options to query the RPM
      database and RPM package files. You can determine the packages
      installed on your system, as well as which packages are
      responsible for the files on your system.
    </para>
    <para>
      The RPM database maintains a lot of information about the files
      and packages on your system. Thus, it is crucial for managing your
      Linux systems. You should back up the RPM database before and
      after any installation, upgrade, or removal of packages.
    </para>
    <para>
      You can also use the --rebuilddb option to the rpm command to
      rebuild a damaged RPM database.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide-using-rpm.xml ---
<!-- $Id: -->

<chapter id="ch-using-rpm">
  <title>Using RPM</title>
  <para>
    This chapter covers:
  </para>
  <itemizedlist>
    <listitem>
      <para>
        Installing and upgrading software
      </para>
    </listitem>
    <listitem>
      <para>
        Removing software
      </para>
    </listitem>
  </itemizedlist>
  <para>
    This chapter covers the most common uses for RPM: installing,
    removing, and upgrading software. These are the most frequently used
    RPM commands.
  </para>
  <para>
    The RPM system includes the options you might expect, such as
    installing a package, but there’s a lot more you can do. For
    example, you can install packages from remote sites using HTTP or
    FTP to download the package to install. There are quite a few other
    <command>rpm</command> options you can use to get information and
    feedback on installation, for example.
  </para>
  <sect1>
    <title>The <command>rpm</command> Command</title>
    <para>
      Just about everything you do with RPM requires the
      <command>rpm</command> command. As a nice added benefit, just
      about everything you do with RPM requires a single invocation of
      the <command>rpm</command> command. That means common tasks such
      as installing and removing software can be done quickly and
      efficiently. The basics of the <command>rpm</command> command are
      not very hard, and you can perform the basic tasks within a few
      minutes of reading this chapter.
    </para>
  </sect1>
  <sect1>
    <title>Upgrading and Installing Software</title>
    <para>
      To install software, you need something to install. Typically,
      this is a file packaged as RPM, using a file-name extension of
      <filename>rpm</filename>. Of course, this isn’t required, but
      just about every RPM package is stored in a file with a
      <filename>rpm</filename> extension. For example, the following
      file holds an RPM package, ready to be installed:
    </para>
    <para>
      <filename>jikes-1.16-1.i386.rpm</filename>
    </para>
    <para>
      This package holds an application named <command>jikes</command>
      (a Java language compiler application). From the discussion in the
      last two chapters, you should be able to determine the version of
      the program this RPM holds and which release of the RPM package
      this represents.
    </para>
    <para>
      Other RPMs hold sources, the program source codes used to create
      an application or programming library. For example, the following
      file holds a source RPM:
    </para>
    <para>
      <filename>jikes-1.16-1.src.rpm</filename>
    </para>
    <para>
      The <filename>src</filename> in the package name is short for
      source. This file-naming convention is not required, but is used
      by just about all source code packages. (Following conventions
      helps other administrators know what to expect.)
    </para>
    <note>
      <title>Building Packages from Source RPMs</title>

      <para>
        Refer to <xref linkend="ch-creating-rpms"/> and
        <xref linkend="ch-rpmbuild"/> for information on building RPMs
        from source RPMs.
      </para>
    </note>
    <para>
      The <command>rpm</command> command provides three main operations
      for upgrading and installing packages:
    </para>
    <variablelist>
      <varlistentry>
        <term>Upgrade</term>
        <listitem>
          <para>
            An upgrade operation means installing a new version of a
            package and removing all previous versions of the same
            package. If you have not installed a package previously, the
            upgrade operation will install the package.
          </para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term>Freshen</term>
        <listitem>
          <para>
            A freshen operation means to install a new version of a
            package only if you have already installed another version
            of the package.
          </para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term>Install</term>
        <listitem>
          <para>
            An install operation installs a package for the first time.
            It also, through special command-line parameters, allows you
            to install multiple versions of a package, usually not what
            you want. So, in the vast majority of cases, you want to run
            the upgrade operation for all package installations.
          </para>
        </listitem>
      </varlistentry>
    </variablelist>
    <para>
      The following sections cover the command-line options that apply
      to these operations.
    </para>
    <sect2>
      <title>Upgrading with the <command>rpm</command> command</title>
      <para/>
      <para>
        Almost all installation steps use the <command>rpm</command>
        command with the <option>–U</option> option, short for
        upgrade, as introduced in <xref linkend="ch-rpm-overview"/> .
        The basic syntax is:
      </para>
      <para>
        <command>rpm</command> <option>-U</option>
        <replaceable>package_name</replaceable>
      </para>
      <para>
        For example:
      </para>
      <para>
<screen>
<userinput>rpm –i jikes-1.16-1.i386.rpm</userinput>
</screen>
      </para>
      <para>
        You can also use the <option>--upgrade</option> long option in
        place of <option>-U</option>.
      </para>
      <para>
        Unless something goes wrong, you won’t see any response except
        for the shell prompt ready for your next command. Options for
        the <command>rpm</command> command, covered shortly, present
        positive feedback that the package has been installed.
      </para>
      <para>
        The <command>rpm</command> command may print out warnings, such
        as the one following:
      </para>
<screen>
<computeroutput>warning: pyxf86config-0.3.1-2.i386.rpm: Header V3 DSA
signature: NOKEY, key ID 897da07a</computeroutput>
</screen>
      <para>
        This warning comes from the fact that the package was signed,
        but the key was not found. <xref linkend="ch-rpmbuild"/> covers
        signing packages. In most cases, warnings such as this one are
        not that serious. Errors, though, should be treated seriously.
      </para>
      <note>
        <title><systemitem class="username">root</systemitem> Permissions</title>

        <para>
          Just about every package you want to upgrade or install
          requires <systemitem class="username">root</systemitem>, or
          super user, permissions. That’s because most Linux
          application RPMs hold files that must be installed in a
          protected directory such as <filename>/usr/bin/</filename>. In
          addition, RPM requires root access to modify the RPM database.
          Even if you could modify the system directories like
          <filename>/usr/bin/</filename>, you must also be able to
          modify the RPM database to successfully install or remove
          packages.
        </para>
      </note>
      <sect3>
        <title>Checking That the Package Is Installed</title>
        <para>
          Use the <command>rpm –q</command> command to quickly verify
          a package has been installed. To verify, you need to use the
[...1739 lines suppressed...]
    <para>
      The syntax for the <option>--rcfile</option> option is
    </para>
    <para>
      <option>--rcfile</option> <replaceable>filename</replaceable>
    </para>
    <para>
      You can also supply more than one file name. This syntax follows:
    </para>
    <para>
      <option>--rcfile</option>
      <replaceable>filename1:filename2:filename3</replaceable>
    </para>
    <para>
      Separate each file name with a colon.
    </para>
    <para>
      With &RHL;, the default set of initialization files are:
    </para>
<screen>
<computeroutput>/usr/lib/rpm/rpmrc:/usr/lib/rpm/redhat/rpmrc:/etc/rpmrc:~/.rpmrc</computeroutput>
</screen>
    <note>
      <title>Tilde (~) Denotes Home Directory</title>

      <para>
        The <filename>~/.rpmrc</filename> means to look in the user's
        home directory for a file named <filename>rpmrc</filename>.
      </para>

      <para>
        You can use the <option>--showrc</option> option to list all the
        <filename>rc</filename> settings.
      </para>
    </note>
    <note>
      <title>The <option>--showrc</option> Option</title>

      <para>
        See <xref linkend="ch-customizing-rpm"/> for more on the
        <option>--showrc</option> option.
      </para>
    </note>
    <para>
      The <option>--version</option> option tells the
      <command>rpm</command> command to print out the version number of
      the command and then exit. For example:
    </para>
<screen>
<userinput>rpm --version</userinput>
</screen>
    <para>
      This command prints out a version number, like the following:
    </para>
<screen>
<computeroutput>RPM version 4.1</computeroutput>
</screen>
    <para>
      The <option>--dbpath</option> option, mentioned previously, tells
      the <command>rpm</command> command to use a different RPM
      database. This is useful when testing a complete system install,
      where you want to change the RPM database but don't want that to
      affect your running Linux system. In this case, you can use a
      different RPM database and test out your changes. The basic syntax
      for this option is:
    </para>
    <para>
      <option>--dbpath</option>
      <replaceable>directory_name</replaceable>
    </para>
    <para>
      The <option>--pipe</option> option tells the
      <command>rpm</command> command to send, or pipe, its output to
      another program. The syntax for this option is:
    </para>
    <para>
      <option>--pipe</option>
      <replaceable>command_to_send_out_to</replaceable>
    </para>
  </sect1>
  <sect1>
    <title>Summary</title>
    <para>
      This chapter covered the easy part of managing packages, the
      common actions of installing, removing, and upgrading software.
    </para>
    <para>
      The <command>rpm</command> <option>–e</option> command removes
      packages. The <command>rpm</command> <option>–U</option> command
      upgrades packages by installing new packages and removing old
      versions of all the packages upgraded. RPM upgrades also work for
      installing new packages. The <command>rpm</command>
      <option>–F</option> command freshens packages. This command only
      upgrades a package if an older version of the package has already
      been installed. The <command>rpm</command> <option>–i</option>
      command installs packages.
    </para>
    <para>
      The table below summarizes the <command>rpm</command> command-line
      options for installing, removing, and upgrading packages.
    </para>
    <table id="tb-rpm-command-options">
      <title>Installing, Removing, and Upgrading with the <command>rpm</command>
        command</title>
      <colspec colnum="1" colname="Command"/>
      <colspec colnum="2" colname="Usage"/>
      <tgroup cols="2">
        <thead>
          <row>
            <entry>Command</entry>
            <entry>Usage</entry>
          </row>
        </thead>
        <tbody>
          <row>
            <entry>
              <para>
                <command>rpm –i <replaceable>install_options
                package_files</replaceable></command>
              </para>
            </entry>
            <entry>
              <para>
                Install packages.
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                <command>rpm –e <replaceable>remove_options
                packages</replaceable></command>
              </para>
            </entry>
            <entry>
              <para>
                Erase, remove, packages.
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                <command>rpm –U <replaceable>install_options
                package_files</replaceable></command>
              </para>
            </entry>
            <entry>
              <para>
                Upgrade or install packages. Use this option for
                installations.
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                <command>rpm –Uvh <replaceable>install_options
                package_files</replaceable></command>
              </para>
            </entry>
            <entry>
              <para>
                Upgrade or install packages with extra output. This is
                the recommended command to install packages.
              </para>
            </entry>
          </row>
          <row>
            <entry>
              <para>
                <command>rpm –F <replaceable>install_options
                package_files</replaceable></command>
              </para>
            </entry>
            <entry>
              <para>
                Freshen packages.
              </para>
            </entry>
          </row>
        </tbody>
      </tgroup>
    </table>
    <para>
      Unfortunately, modern system management gets more complex than
      that. The next chapter delves into package dependencies and the
      nightmare you can get into when one package depends on another
      that then depends on another, ad infinitum.
    </para>
  </sect1>
</chapter>

<!--
Local variables:
mode: xml
sgml-parent-document:("rpm-guide.xml" "book" "chapter")
fill-column: 72
End:
-->


--- NEW FILE rpm-guide.xml ---
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
 "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [

<!ENTITY % FEDORA-ENTITIES-EN SYSTEM "../docs-common/common/fedora-entities-en.ent">
%FEDORA-ENTITIES-EN;

<!ENTITY VERSION "1.0"> <!-- version for this document -->

<!ENTITY BOOKID "rpm-guide-en-&VERSION; (2005-10-03-T23:30+01:00)"> <!-- change date here and VERSION entity everytime a change is made-->

<!-- Bugzilla bug number for the draft notice -->
<!ENTITY BUG-NUM "1000000">
<!ENTITY DOCLOCALVER "0.1">

<!ENTITY PACKAGINGINTRO SYSTEM "rpm-guide-intro-packaging.xml">
<!ENTITY RPMINTRO SYSTEM "rpm-guide-intro-rpm.xml">
<!ENTITY RPMOVERVIEW SYSTEM "rpm-guide-rpm-overview.xml">
<!ENTITY USINGRPM SYSTEM "rpm-guide-using-rpm.xml">
<!ENTITY USINGRPMDB SYSTEM "rpm-guide-using-rpm-db.xml">
<!ENTITY DEPENDENCIES SYSTEM "rpm-guide-dependencies.xml">
<!ENTITY TRANSACTIONS SYSTEM "rpm-guide-transactions.xml">
<!ENTITY MANAGEMENT SYSTEM "rpm-guide-management-software.xml">
<!ENTITY CREATING SYSTEM "rpm-guide-creating-rpms.xml">
<!ENTITY SPECFILES SYSTEM "rpm-guide-specfiles.xml">
<!ENTITY ADVPACKAGING SYSTEM "rpm-guide-advanced-packaging.xml">
<!ENTITY RPMBUILD SYSTEM "rpm-guide-rpmbuild.xml">
<!ENTITY PACKAGINGTOOLS SYSTEM "rpm-guide-extra-packaging-tools.xml">
<!ENTITY GUIDELINES SYSTEM "rpm-guide-packaging-guidelines.xml">
<!ENTITY SCRIPTING SYSTEM "rpm-guide-scripting.xml">
<!ENTITY PROGRAMMINGC SYSTEM "rpm-guide-programming-c.xml">
<!ENTITY PROGRAMMINGPY SYSTEM "rpm-guide-programming-python.xml">
<!ENTITY PROGRAMMINGPL SYSTEM "rpm-guide-programming-perl.xml">
<!ENTITY OTHERLINUXES SYSTEM "rpm-guide-other-linuxes.xml">
<!ENTITY OTHEROS SYSTEM "rpm-guide-other-os.xml">
<!ENTITY CUSTOMIZINGRPM SYSTEM "rpm-guide-customizing-rpm.xml">
<!ENTITY COMMANDREF SYSTEM "rpm-guide-command-reference.xml">
<!ENTITY SPECFILESYN SYSTEM "rpm-guide-specfile-syntax.xml">
<!ENTITY RPMEVOLUTION SYSTEM "rpm-guide-rpm-evolution.xml">
<!ENTITY RPMSTRUCTURE SYSTEM "rpm-guide-package-structure.xml">
<!ENTITY RESOURCES SYSTEM "rpm-guide-online-resources.xml">
<!ENTITY DEVTOOLS SYSTEM "rpm-guide-development-tools.xml">
<!ENTITY LICENSING SYSTEM "rpm-guide-licensing.xml">

]>

<book id="book" lang="en">
  <bookinfo>
    <title>RPM Guide</title>
    <!-- Remove DOCLOCALVER for release -->
    <copyright>
      <year>2005</year>
      <holder>Eric Foster-Johnson</holder>
    </copyright>
    <authorgroup>
      <author>
	<surname>Foster-Johnson</surname>
	<firstname>Eric</firstname>
      </author>
    </authorgroup>
    &LEGALNOTICE-OPL-CONTENT;
    <revhistory>
      <revision>
	<revnumber>0.1</revnumber>
	<date>2005-10-03</date>
	<authorinitials>StuartEllis</authorinitials>
	<revdescription>
	  <para>
	    First commission to CVS
	  </para>
	</revdescription>
      </revision>

    </revhistory>
  </bookinfo>

 &PACKAGINGINTRO;

 &RPMINTRO;

 &RPMOVERVIEW;

 &USINGRPM;

 &USINGRPMDB;

 &DEPENDENCIES;

 &TRANSACTIONS;

 &MANAGEMENT;

 &CREATING;

 &SPECFILES;

 &ADVPACKAGING;

 &RPMBUILD;

 &PACKAGINGTOOLS;

 &GUIDELINES;

 &SCRIPTING;

 &PROGRAMMINGC;

 &PROGRAMMINGPY;

 &PROGRAMMINGPL;

 &OTHERLINUXES;

 &OTHEROS;

 &CUSTOMIZINGRPM;

 &COMMANDREF;

 &SPECFILESYN;

 &RPMEVOLUTION;

 &RPMSTRUCTURE;

 &RESOURCES;

 &DEVTOOLS;

 &LICENSING;


  <index id="generated-index">
  </index>

</book>

<!--
Local variables:
mode: xml
fill-column: 72
End:
-->




More information about the Fedora-docs-commits mailing list