2

Situation

I have an RPM that uses semanage (SELinux policy management tool) and restorecon (SELinux context configuration tool) in the post-installation and pre-uninstallation stages.

Unfortunately, between RHEL 6/7 and 8, the package containing these tools was renamed from policycoreutils-python to policycoreutils-python-utils.

A working spec file for the RHEL8 RPM contains:

Requires(post): policycoreutils-python-utils
Requires(preun): policycoreutils-python-utils

And a working spec file for the RHEL6/7 RPM contains:

Requires(post): policycoreutils-python
Requires(preun): policycoreutils-python

What I try to achieve

I could live with the two spec files/two RPMs, one for every OS type, but I'm lazy and I want one spec that serves all.

What I tried

I read about the OS conditional %{rhel}, containing the OS version. The following should work, according to the RPM manual:

%if %{rhel} < 8
Requires(post): policycoreutils-python
Requires(preun): policycoreutils-python
%endif 

%if %{rhel} == 8
Requires(post): policycoreutils-python-utils
Requires(preun): policycoreutils-python-utils
%endif

If I check the value of the %{rhel} variable on my target systems, I get what I expect:

centos7-system» rpm --eval '%{rhel}'
7

centos8-system» rpm --eval '%{rhel}'
8

Installation of this RPM on a CentOS 6/7 instance works fine. However, upon installation of the OS-independent RPM on an CentOS 8 instance, I get:

centos8-system» dnf install my-1.26-0.x86_64.rpm
<...>
Error:
 Problem: conflicting requests
  - nothing provides policycoreutils-python needed by my-1.26-0.x86_64

Debug output:

centos8-system» rpm -ivvvh my-1.26-0.x86_64.rpm 2>&1 | grep Requires
D:  Requires: /bin/bash                                     YES (db files)
D:  Requires: /bin/sh                                       YES (db files)
D:  Requires: /bin/sh                                       YES (cached)
D:  Requires: /bin/sh                                       YES (cached)
D:  Requires: /usr/bin/env                                  YES (db files)
D:  Requires: /usr/bin/perl                                 YES (db files)
D:  Requires: /usr/bin/php                                  YES (db files)
D:  Requires: nagios-plugins                                NO
D:  Requires: perl(Getopt::Long)                            YES (db provides)
D:  Requires: perl(strict)                                  YES (db provides)
D:  Requires: policycoreutils-python                        NO
D:  Requires: policycoreutils-python                        NO  (cached)
D:  Requires: policycoreutils-python                        NO
D:  Requires: rpmlib(CompressedFileNames) <= 3.0.4-1        YES (rpmlib provides)
D:  Requires: rpmlib(FileDigests) <= 4.6.0-1                YES (rpmlib provides)
D:  Requires: rpmlib(PayloadFilesHavePrefix) <= 4.0-1       YES (rpmlib provides)
D:  Requires: rpmlib(PayloadIsXz) <= 5.2-1                  YES (rpmlib provides)

It would seem that the Requires for the CentOS 6/7 scenario are used, and not those from the CentOS 8 scenario.

What am I not seeing here? Is there anything I can do to debug this?

Related and sources

2 Answers 2

1

You could omit the conditionals and depend on the semanage exectutable instead of the policycoreutils-python package:

Requires(post): %{_sbindir}/semanage
Requires(post): %{_sbindir}/restorecon

See Fedora's dokuwiki.spec for an example. An example that depends on the packages is bdii.spec.

1
  • Right. This way the OS determines which package to pull in dynamically from the binary name. Brilliant! Thanks very much. Accepted and +1.
    – Edward
    Jan 27, 2022 at 16:01
1

The conditional in SPEC file are evaluating during build time. So when you SPEC file contains:

%if %{rhel} < 8
Requires(post): policycoreutils-python
%endif 

%if %{rhel} == 8
Requires(post): policycoreutils-python-utils
%endif

and you build your package on RHEL 7 then it will have

Requires(post): policycoreutils-python

and this Requires will be used even if you install your package on RHEL 8. It will not be re-evaluated after the package was built.

If you want to have only one binary package then you need the file base requires as pointed out by Andreas. The enterprise solution is to use

Release: 1%{?dist}
...
%if %{rhel} < 8
Requires(post): policycoreutils-python
Requires(preun): policycoreutils-python
%endif 

%if %{rhel} == 8
Requires(post): policycoreutils-python-utils
Requires(preun): policycoreutils-python-utils
%endif

and build it for different platforms using:

mock -r epel-7-x86_64 my.src.rpm
mock -r epel-8-x86_64 my.src.rpm

the first command produces my-1.0-1.el7 and requires policycoreutils-python While the second one produces my-1.0-1.el8 and requires policycoreutils-python-utils.

As a side note the condition should be written as:

%if 0%{?rhel} < 8

to prevent syntax error when the macro is not defined.

1
  • Thank you very much for the detailed explanation!
    – Edward
    Feb 2, 2022 at 15:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.