Why does a yum package update replaces my yum-cron config files?
Written by: J Dawg
Usually, when applying package updates via yum update
, rpm is ‘intelligent’ enough to respect my changes to configuration files under /etc
.
(It basically looks at the mtime, compares it and depending on the outcome replaces the file with the new version, or just puts the new version beside it.)
But with one of the last yum/yum-cron updates on Centos 7, my custom yum-cron config files were replaced:
/etc/yum/yum-cron.conf
/etc/yum/yum-cron-hourly.conf
Now I am wondering why this happened exactly?
I mean, the answer must be in the source package – but I can’t find it there:
$ rpm -qi yum-cron | grep src Source RPM : yum-3.4.3-132.el7.centos.0.1.src.rpm $ yumdownloader --source yum-3.4.3-132.el7.centos.0.1 $ grep '%.*yum-cron.*.conf' yum.spec %config(noreplace) %{_sysconfdir}/yum/yum-cron.conf %config(noreplace) %{_sysconfdir}/yum/yum-cron-hourly.conf
Looking at the spec file, in the yum-cron section, the config directive even has noreplace
specified.
On the other hand, the ownership of the config files seems to be shared among the yum
and the yum-cron
binary packages:
$ rpm -ql yum-cron | grep 'yum-cron.*.conf' /etc/yum/yum-cron-hourly.conf /etc/yum/yum-cron.conf $ rpm -ql yum | grep 'yum-cron.*.conf' /etc/yum/yum-cron-hourly.conf /etc/yum/yum-cron.conf
How come?
I mean, I only see the yum-cron config files mentioned in the cron specific files section of the spec file …
See also the CentOS issue and the RHEL issue on this.
This is a problem in the way Red Hat created the package – the yum-cron.conf
file should be marked as a config file (contrary to what your output indicates should be the case), but it is not (querying the installed package for config files does not list the yum-cron.conf
file). The actual answer is to get it fixed by RH, the likely more useful answer is chattr +i
. See also: http://serverfault.com/questions/744531/secure-yum-cron-conf-configuration-and-prevent-them-from-getting-auto-updated/744535#744535
This is due to the following line in the main %files
section of the yum.spec
file:
%(dirname %{compdir})
Meaning that rpm first substitutes %{compdir}
and then executes dirname
with the result as argument in a shell. The output is then added to the file list.
The compdir variable is defined like this:
%define compdir %(pkg-config --variable=completionsdir bash-completion)
%if "%{compdir}" == ""
%define compdir "/etc/bash_completion.d"
%endif
Assuming that bash-completion
is installed at build time (on the build system), pkg-config
thus returns perhaps:
/usr/share/bash-completion/completions
And thus adding
dirname /usr/share/bash-completion/completions
-> /usr/share/bash-completion
to the file list is ok (and makes sense if the yum package also installs helpers, i.e. under /usr/share/bash-completion/helpers
).
The problematic case is when the bash-completion
package is not installed at build time because then pkg-config
returns the empty string, i.e.:
compdir := /etc/bash_completion.d
=> dirname /etc/bash_completion.d
-> /etc
Thus, the complete /etc
directory from the package’s buildroot is recursively added to the file list.
Apparently, the box where the CentOS yum binary package was built didn’t have the bash-completion
package installed. In fact, RHEL (and thus CentOS) does not even provide a bash-completion
package.
This explains why the files
/etc/yum/yum-cron.conf
/etc/yum/yum-cron-hourly.conf
are owned by both the yum
and the yum-cron
package.
(And are only correctly marked by the yum-cron
package.)
Addendum
The motivation for the conditionals is probably the idea to have one yum spec file for multiple rpm based distributions (e.g. different versions of Fedora, RHEL, …). Consequent, the spec file also conditionally build-depends and bash-completions
only on non-RHEL systems:
%if ! 0%{?rhel}
# we don't have this in rhel yet...
BuildRequires: bash-completion
%endif
The change that introduced dirname was discussed on the yum mailinglist:
package also $(compdir)’s parent (not sure why, just in case)
The introduction of the conditional logic was also discussed:
Oh, and instead of hardcoding the completions dir, it’d be better to
get it from “pkg-config –variable=completionsdir bash-completion”.
Spec Fix
One fix is to move the dirname
call into the right conditional branch, e.g.:
--- a/SPECS/yum.spec +++ b/SPECS/yum.spec @@ -28,7 +28,7 @@ BuildRequires: bash-completion # disable broken /usr/lib/rpm/brp-python-bytecompile %define __os_install_post %{nil} -%define compdir %(pkg-config --variable=completionsdir bash-completion) +%define compdir %(pkg-config --variable=completionsdir bash-completion | xargs -r dirname) %if "%{compdir}" == "" %define compdir "/etc/bash_completion.d" %endif @@ -451,7 +451,7 @@ exit 0 %dir %{_sysconfdir}/yum/fssnap.d %dir %{_sysconfdir}/yum/vars %config(noreplace) %{_sysconfdir}/logrotate.d/%{name} -%(dirname %{compdir}) +%{compdir} %dir %{_datadir}/yum-cli %{_datadir}/yum-cli/* %exclude %{_datadir}/yum-cli/completion-helper.py?
Thanks for the detailed explanation maxschlepzig, but your proposed fix isn’t correct. It would result in comdir being set to /usr/share/bash-completion
when bash-completion is installed. Files from there aren’t loaded, they have to be in /usr/share/bash-completion/completions
. That would break being able to consistently use %{compdir}
as an install path for completion files, which is the whole point of the macro.
The safest way to fix this is be explicit:
%if 0%{?fedora} >= 19 || 0%{?rhel} >= 7 %global compdir %{_datadir}/bash-completion/completions %else %global compdir %{_sysconfdir}/bash_completion.d %endif
Then later in the %files section:
%if 0%{?fedora} >= 19 || 0%{?rhel} >= 7
%(dirname %{compdir})
%else
%{compdir}
%endif
Leave a Reply
You must be logged in to post a comment.