RPM 4.20 Is Coming
RPM 4.20 is coming [LWN.net]


The RPM Package Manager (RPM) project is
nearing the release of RPM 4.20, the last major planned update for the RPM 4.x
series. It has few user-facing changes, but
several additions and enhancements for developers—as well as
some small incompatibilities that will likely require RPM packagers to
revise their spec
files. 4.20 will be rolling out to many users soon, in
Fedora 41, which is scheduled for October. RPM 6.0 is
already in the works, with a new package format and opening the door
to enabling C++ use in the RPM codebase.

An RPM release consists of the command-line
suite of tools for installing, managing, removing, and creating
RPM packages. It also includes RPM plugins and librpm, which
provides the RPM API to user-facing tools like DNF, Zypper, and
others. In addition, the project maintains the RPM package
format and spec
file format documentation, which is updated with each RPM
release. RPM spec files are text files, with the .spec
extension, that describe how to build an RPM. They are included with a package's source RPM
(.src.rpm), along with the original source code and patches
to be applied to the software.


$ sudo subscribe today

Subscribe today and elevate your LWN privileges. You’ll have
access to all of LWN’s high-quality articles as soon as they’re
published, and help support LWN in the process.  Act now and you can start with a free trial subscription.

Many Linux users interact directly with RPM rarely, if at
all. Desktop users can do all their software management on RPM-based systems,
like Fedora and openSUSE, with tools that use RPM behind the scenes,
such as DNF, Zypper, or GNOME Software.
Packagers, on the other hand, spend quite a bit of time with RPM, and the
bulk of the features in 4.20 are designed to make it easier to build and
maintain RPMs.

Append and prepend

RPM spec files define package-build steps in scriplet
sections such as %prep (get sources ready),
%setup (create build directories), %patch (apply
patches), and so forth. With 4.20, RPM has added the ability to append
(-a) and prepend (-p) the sections with additional
commands. This will allow packagers to insert instructions before or
after each build step. For example, one might add an %install
-a section to remove a file after the package is installed. The
append and prepend directives are useful to RPM in any case, but are
particularly useful in conjunction with the addition of one of
RPM 4.20's more interesting new features:
declarative builds.

Declarative builds

This feature is meant to allow upstream projects and distributions to
provide build-system macros for common build processes, such as
creating Python packages, Ruby gems, or Rust crates. Packagers can use
this feature to declare a desired build system for a package with a
single stanza, rather than each packager having to describe the build
process on their own. The example given in the request for enhancement (RFE)
is building projects that use GNU Autotools. When compiling from source, that would usually involve
the familiar steps:

    $ ./configure
    $ make
    # make install



In an RPM spec file, that would usually look something like
this:

    %prep
    %autosetup
    
    %build
    %configure
    %make_build
    
    %install
    %make_install



With this release, that can be condensed to a single line:

    BuildSystem: autotools



Declarative builds should reduce the amount of redundant boilerplate that
developers have to add to package spec files—but it does not
preclude tweaking things if necessary. Declarative builds can be
modified using the BuildOption tag or by prepending and
appending %install -a, %build -p, etc., sections. See the documentation
and example
macros for more on declarative builds.

Public plugin API

RPM plugins
provide support for features that are not suitable for all
platforms. For example, Fedora users may want the SELinux
plugin, but it is not suitable for systems with AppArmor, such as
openSUSE. RPM has also been ported to non-Linux systems, and many of
RPM's plugins are Linux-specific.

Work began
on RPM's plugin system in 2012. RPM shipped a plugin system in the 4.12 release in 2014, but the
API has been considered subject to change and kept internal-only ever since. Not that
it has changed: the RPM
plugin interface is basically unmodified since the 4.12.0
release. In 2023, RPM developer Panu Matilainen said 
that the API should have been public to begin with and committed the change
to make it so. "We've
procrastinated on making this API public for about ten years now, and
in the meanwhile there has been exactly one disruptive change to the API."

Making the API public will make it possible for others to develop
RPM plugins with confidence that subsequent RPM releases won't break
the plugins. There is still work to be done for RPM to verify
that plugins are compatible with the version of RPM being used, but
that does not look likely to ship in 4.20.

Isolation

When RPMs are installed or removed, they can run scriptlets
that make updates to the system. For example, a package may need to
restart a service or make updates to the system's GNOME
settings. Running these scriptlets is necessary, but Johannes Segitz
noted that they can pose a security challenge since packagers may "naively"
place code in /tmp that could be exploited for privilege
escalation and submitted pull
request with a proof-of-concept to provide a private /tmp
directory for scriptlets.

Matilainen broke
that out as a plugin and added
Linux-specific functionality to implement optional
filesystem and network isolation using namespaces. Specifically, the unshare
plugin shipped with RPM 4.20 can mount paths privately during scriptlet execution, such as /tmp
and /home, so that scriptlets do not have access to the system
/tmp or user home directories. The directories to be isolated
are specified in
/usr/lib/rpm/macros.d/macros.transaction_unshare as a
colon-separated list of directories.

The plugin also allows disabling
network access, so that the scriptlet cannot upload or download
anything during execution.

Goodbye %patchN

Packagers often add patches to the original upstream source code of
a project. RPM has a macro for this, %patch, which
has accepted several variations for some time: "%patch N",
"%patch -P N", or "%patchN" allow packagers to specify
one or more patches to be applied at build time. However, in RPM 4.19,
the %patchN syntax, was deprecated in favor of %patch N
or %patch -p N. Matilainen said
on the fedora-devel list that the reason for its deprecation was
"it's a mind-bogglingly bad syntax for what it does, and prevents
making %prep like any other section in the spec". He did not
elaborate on how it prevented this, except to say "don't ask, you
don't want to know".

The RPM developers may be happy to shed the %patchN
syntax, but it is widely used. Dominique Leuenberger posted
a message to the opensuse-factory mailing list in February about work
needed to enable 4.20, saying that more than 2,066 packages used that
syntax. According to the Fedora 41 change
proposal for RPM 4.20, more than 1,000 spec files in Fedora's
repository were using that syntax as of April. No doubt, many
packagers still have work to do to update their package specs.

Miscellaneous

There are, of course, plenty of smaller changes that users and
developers may (or may not) notice. For instance, the rpmkeys command,
which is used to manage and provide information about RPM signing
keys, now has options to list installed keys (--list) and to
delete keys (--delete). Previously rpmkeys could
only import keys and verify package signatures.

RPM has also added JSON as a query format. It joins the XML
query format, which Matilainen noted
is "an eyesore". For example, developers who want to access all
of the information about an RPM for a program can use the following to get full output in
JSON format:

    $ rpm -q --json <packagename>



Packagers who would like to enable reproducible builds will
be interested in the %build_mtime_policy. This allows the
packager to set a timestamp policy for the package to help ensure that
the timestamps remain the same for all builds. See the documentation
for more information.

Beyond 4.20

The RPM project is now in its 29th year, with the first
commit (to a CVS repository) made on November 27, 1995, by either Marc
Ewing or Erik Troan. The RPM timeline notes that the first commit
was added as root, thus the identity of the original author is lost to history. So it
goes. The project has pushed out substantial feature releases to the 4.x
series about once a year since the project rebooted
in 2006. According to the RPM roadmap, RPM 6.0 will be
released sometime in the third quarter of 2025, which will coincide
with the 30th anniversary of RPM. Those wondering about
the jump from RPM 4.20 to 6.0 may not have lived through (or have
forgotten) the fork
that prompted the RPM.org reboot, relaunch of
the fork, the fork's RPM 5.0.0
release, and subsequent drama in 2011.

The fork is showing few signs of life at present. The project site is
still up but its news page has
no updates after the 2009 release of 5.2, though there appears to have
been a 5.4.17 release
in 2016. The distributions that had switched to the fork, such as
OpenMandriva Lx and OpenEmbedded,
have switched back to the RPM.org version.

At any rate, it seems
likely the RPM maintainers thought the best course was to avoid any confusion with
the fork's 5.x releases and will skip straight to 6.0. The version jump will introduce the RPM
v6 package format, which is described as a face-lift for the
format rather than a full redesign. The goals are to shed some
compatibility baggage, drop obsolete crypto algorithms (MD5, SHA1, and
DSA1), and use 64-bit sizes in all headers.

RPM v6 will stop using cpio as the archive
format for its file archive (payload) and start using the new
format, which supports files larger than 4GB. If 4GB sounds excessive
for an RPM, it's worth noting that the Chromium source RPM for
Fedora 40 weighs in at a hefty 3.8GB. The Firefox source RPM is a
comparatively svelte 826MB. If there are no packages that exceed the
4GB limit today, it seems likely that there will be before long.

To prepare for the new format, RPM 4.20 ships with a new
utility, rpm2archive,
which replaces the now-outdated rpm2cpio
utility. Historically, rpm2cpio has been used to convert RPMs
to cpio files, which can be unpacked with cpio. The rpm2archive utility
converts RPMs to a gzipped-compressed tar archive that can be manipulated with
tar instead.

The move to the v6 format should not be disruptive to distributions
still on RPM 4.20 when 6.0 is released. In the first
draft Matilainen sent to the rpm-maint mailing list, he said that
the last RPM 4.x version would be able to read and install v6
packages and that RPM v6 would be able to read and install v4
packages. This should mean that RPM 4.20 will be able to work
with v6 packages, since no further major 4.x releases are on the RPM roadmap.

6.0 and C++

In March, Matilainen started a discussion
on GitHub about RPM in C++. He said that the project had been
"dreaming about richer data structures than C has to offer"
since the RPM reboot, but his early experiments in 2010 with C++ left him with
a "resounding 'ugh no' conclusion". Recently, he took another
look at C++ and "woke up to a language that seems almost like a
distant cousin to the C++ I cursed at in 2010 (and before)".

With RPM 6.0 on the horizon, it was a good opportunity
to enable the use of C++ in the RPM codebase. This is not a rewrite,
he said, just an implementation detail. After 4.20 branched,
Matilainen merged
a commit that made it possible to build RPM with a C++ compiler and
start switching to C++. Currently RPM's Python bindings,
its plugins, and the low-level engine for RPM's ndb database are
not planned for conversion.

In the initial discussion, Neal H. Walfield wondered
whether it would make sense to wait a few more years to port RPM to
Rust instead of C++. Matilainen said
that Rust is not an option, but if someone wants to rewrite RPM in
Rust from
scratch "in another 15 years when I'm retired", they are
welcome to do so.

The final RPM 4.20 release is expected before the end of September.
The most recent release as of this writing is 4.19.94 (aka 4.20 RC2),
released on September 10. That release is already available in
Fedora 41 Beta, which was released on September 17. It
will also likely turn up in the openSUSE Tumbleweed
rolling-release distribution early in 2025 (RPM 4.19 entered
Tumbleweed in February of this year), though it's unclear whether it
will make it into openSUSE Leap 16.

There are quite a few other changes arriving in RPM 4.20, see
the draft release notes for
a comprehensive list of changes and bug fixes.
            