In the discussion about a non-rpm controlled /etc I missed the migration path for files changed by the admin. Is there a proposal about how a disappeared '%config /path' or '%config(noreplace) /path' is supposed to be handled? If not, here is my idea how it could be done. There are plenty of "empty" files which are marked as "%config". In case of local modifications to such files, they will be kept as '/path.rpmsave' when '/path' is not packaged anymore. It will be cumbersome for the admin to move all of '/path.rpmsave' back to '/path' once '/path' is not under rpm control. Two rpm macros are needed to automate the restore of '/path' from '/path.rpmsave'. In the %pre section '/path' and '/path.rpmsave' will be tracked, in the %posttrans section '/path.rpmsave' will be moved back to '/path' under the following condtions: 1: '/path' exists and was unmodified: rpm will silently remove '/path'. Action: No action required. 2: '/path' exists and was modified: rpm will preserve a copy of '/path' as '/path.rpmsave'. Action: %posttrans will rename '/path.rpmsave' to '/path' 3: '/path' exists and was unmodified, '/path.rpmsave' exist, both are identical : rpm will silently remove '/path'. Action: remove stale '/path.rpmsave' 4: '/path' exists and was unmodified, '/path.rpmsave' exist, both differ : rpm will silently remove '/path'. Action: remove stale '/path.rpmsave' 5: '/path' exists and was modified, '/path.rpmsave' exist, both are identical : rpm will preserve a copy of '/path' as '/path.rpmsave'. Action: %posttrans will rename '/path.rpmsave' to '/path' 6: '/path' exists and was modified, '/path.rpmsave' exist, both differ : rpm will preserve a copy of '/path' as '/path.rpmsave'. Action: %posttrans will rename '/path.rpmsave' to '/path' 7: '/path.rpmsave' exists: rpm does nothing with '/path.rpmsave'. Action: remove stale '/path.rpmsave' I think with this logic most of the tedious work of renaming will be avoided, with no obvious risk. In my testing '%config /path' and '%config(noreplace) /path' behave identical once '/path' changes from rpm controlled to non-rpm controlled, there will be always a '/path.rpmsave' for local modifications. The logic below is supposed to address all 7 cases above, it just a proof-of-concept at this point. The usage of basename is wrong, it is not ready for build-compare. Here is a short excerpt from the long list of "empty" config files which will benefit from such helper macros: /etc/default/grub /etc/exports /etc/grub.d/* /etc/libguestfs-tools.conf /etc/systemd/*.conf /etc/xen/*.conf Olaf Name: config_noreplace Version: %(date -u +%%Y%%m%%d%%H%%M) Release: %(date -u +%%S) Summary: %{name} License: GPL Group: Example BuildRoot: %{_tmppath}/%{name}-%{version}-build # 0 or 1 %define carry_config_paths 0 %define path1 %{_datadir}/%{name}/conf.txt %define path2 %{_datadir}/%{name}/keep.txt %description %prep %setup -q -c -T %build %install pushd %{buildroot} mkdir -p %{buildroot}%{_datadir}/%{name} %if %{carry_config_paths} cat > .%{path1} <<_EOT_ # Example: preserve a copy of local changes _EOT_ cat > .%{path2} <<_EOT_ # Example: always keep the local changes _EOT_ %endif %pre echo "pre %{name} %{version}-%{release} $# $0 $*" trackdir=%{_tmppath}/%{name}-%{version}-%{release} pre_preserve_config() { local _path="$1" local pre_config=$trackdir/$(basename ${_path}).pre.md5 local pre_rpmsave=$trackdir/$(basename ${_path}).rpmsave.pre.md5 if test -f "${_path}" then md5sum < "${_path}" > $pre_config fi if test -f "${_path}.rpmsave" then md5sum < "${_path}.rpmsave" > $pre_rpmsave fi } if mkdir "$trackdir" then pre_preserve_config %{path1} pre_preserve_config %{path2} fi %post echo "post %{name} %{version}-%{release} $# $0 $*" %preun echo "preun %{name} %{version}-%{release} $# $0 $*" %postun echo "postun %{name} %{version}-%{release} $# $0 $*" %posttrans echo "posttrans %{name} %{version}-%{release} $# $0 $*" trackdir=%{_tmppath}/%{name}-%{version}-%{release} posttrans_perserve_config() { local _path="$1" local pre_config=$trackdir/$(basename ${_path}).pre.md5 local pre_rpmsave=$trackdir/$(basename ${_path}).rpmsave.pre.md5 local post_rpmsave=$trackdir/$(basename ${_path}).rpmsave.post.md5 if test -f "${_path}.rpmsave" then md5sum < "${_path}.rpmsave" > $post_rpmsave fi # config was present, now no config.rpmsave # -> no admin changes, nothing to do # config was present, now config.rpmsave # -> admin changes, move config.rpmsave to config # config and config.rpmsave was present, now config.rpmsave # pre: # -> if config == config.rpmsave then remove config.rpmsave # -> if config != config.rpmsave then preserve both # post: # -> if config == config.rpmsave, move config.rpmsave to config # -> if config != config.rpmsave if test -f "$pre_config" && test -f "$pre_rpmsave" then # pre: config and config.rpmsave was present if cmp -s "$pre_config" "$pre_rpmsave" then : pre: config and config.rpmsave identical, modification status unclear if test -f "$post_rpmsave" then : post: admin changes, restore config mv -v "${_path}.rpmsave" "${_path}" else : post: no admin changes, remove stale config.rpmsave, rpm removed config rm -v "${_path}.rpmsave" fi else : pre: config and config.rpmsave differ, modification status unclear if test -f "$post_rpmsave" then if cmp -s "$pre_config" "$post_rpmsave" then : post: admin changes, restore config mv -v "${_path}.rpmsave" "${_path}" else : post: no admin changes, remove stale config.rpmsave rm -v "${_path}.rpmsave" fi fi fi elif test -f "$pre_config" && test ! -f "$pre_rpmsave" then : pre: config present + config.rpmsave absent, modification status unclear if test -f "$post_rpmsave" then : post: admin changes, restore config mv -v "${_path}.rpmsave" "${_path}" fi fi : cleanup rm -f $pre_config rm -f $pre_rpmsave rm -f $post_rpmsave } posttrans_perserve_config %{path1} posttrans_perserve_config %{path2} rmdir $trackdir %files %defattr(-,root,root,-) %dir %{_datadir}/%{name} %if %{carry_config_paths} %config %{path1} %config(noreplace) %{path2} %endif