Bug 924660 - RPM cannot handle update if directory change to file
Summary: RPM cannot handle update if directory change to file
Keywords:
Status: CLOSED NEXTRELEASE
Alias: None
Product: Fedora
Classification: Fedora
Component: rpm
Version: 18
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
Assignee: Packaging Maintenance Team
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2013-03-22 10:04 UTC by Jaroslav Škarvada
Modified: 2013-03-27 07:39 UTC (History)
10 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2013-03-27 07:39:12 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)

Description Jaroslav Škarvada 2013-03-22 10:04:06 UTC
Description of problem:
RPM cannot handle update if directory (in old package) change to file (in new package), e.g. upgrade from espeak-1.46.02-8.fc18 to espeak-1.47.01-1.fc18:

Running Transaction
  Updating   : espeak-1.47.01-1.fc18.x86_64                                                                                                                       1/2 
Error unpacking rpm package espeak-1.47.01-1.fc18.x86_64
error: unpacking of archive failed on file /usr/share/espeak-data/voices/en: cpio: rename

The problem is that /usr/share/espeak-data/voices/en directory changes to /usr/share/espeak-data/voices/en file. I workarounded it by the following hack in the spec:

%pre
if [ -d %{_datadir}/%{name}-data/voices/en ]
then
  rm -f %{_datadir}/%{name}-data/voices/en/*
  rmdir %{_datadir}/%{name}-data/voices/en
fi
exit 0

But it is a valid update and it should be handled transparently by RPM without need of such dirty hacks.

Version-Release number of selected component (if applicable):
rpm-4.10.3.1-1.fc18.x86_64

How reproducible:
Always

Steps to Reproduce:
1. Try to update package where directory (in old package) change to file (in new package)
  
Actual results:
Update fail.

Expected results:
Update correctly finish.

Comment 1 Panu Matilainen 2013-03-22 11:03:10 UTC
Rpm cannot change a directory to anything else and is not likely to learn to do so any time soon. The workaround is to use %pretrans -p <lua> script (%pre is far too late) to do the dirty deeds manually.

Rpm >= 4.11 (so Fedora >= 19) detects an attempt to replace a directory with something else as a conflict, but that's the only "fix" this issue is going to receive in the foreseeable future.

Comment 2 Jaroslav Škarvada 2013-03-22 13:59:56 UTC
(In reply to comment #1)
> Rpm cannot change a directory to anything else and is not likely to learn to
> do so any time soon.

It is sad. RPM should transparently deliver the content and not redirect its work to developers to introduce such dirty hacks into their packages.

Comment 3 Adam Williamson 2013-03-23 07:24:05 UTC
Whatever was done in espeak 1.47.03-1 to 'work around' this is breaking live compose somehow. When I try and build a live image with the 1.47.03-1 package included, I get "Error creating Live CD : Dependency check failed!"

That's all the official python-imgcreate gives me, but I can see from yuminst.py that it raises that error when the yum 'ts.check' test fails. Going off of http://lists.baseurl.org/pipermail/yum-devel/2011-February/007861.html I hacked some horrible hack into yuminst.py to print out the actual output of the ts.check test, and I get:

(('espeak', '1.47.03', '1.fc19'), ('/bin/sh', ''), 0, 0, None)

Make of that what ye will, but it's something to do with espeak.

Comment 4 Adam Williamson 2013-03-23 07:27:55 UTC
Yup - if I take espeak 1.47.03 out of my side repo, the compose succeeds.

Comment 5 Adam Williamson 2013-03-23 07:31:17 UTC
N: Comparing espeak-1.47.01-1.fc20 and espeak-1.47.03-1.fc20 (archs: x86_64, i686) ...
W: requirement-added /bin/sh  

that's from autoqa's rpmguard test, and ties in with the second bit of the error output from ts.check. Something to do with the /bin/sh requirement? But all sorts of packages require /bin/sh. Bit odd.

Comment 6 Adam Williamson 2013-03-23 08:08:25 UTC
Filed https://bugzilla.redhat.com/show_bug.cgi?id=926004 for the live compose issue.

Comment 7 Jaroslav Škarvada 2013-03-24 19:30:59 UTC
(In reply to comment #3)
> Whatever was done in espeak 1.47.03-1 to 'work around' this is breaking live
> compose somehow. When I try and build a live image with the 1.47.03-1
> package included, I get "Error creating Live CD : Dependency check failed!"

That's exactly what I wrote before, delivering the content is task of RPM and any similar packaging hacks would lead to nothing more then problems.

I tried to be in sync with the comment 1 which stated that using %pre is too late, because Rpm >= 4.11 will detect this as a conflict so I moved the script from %pre to %pretrans. This adds implicit dep on /bin/sh which is not satisfied when building livecd, because "pre transaction" is too early and there is no shell installed in this phase. So I would have to use %pretrans -p, but I have no idea how to code the script there, becase the 'rm' hack takes at least two arguments (-rf and directory). Also I have no idea how to install some (binary ?) helper in this "early phase" and such "stripped down" hack would be much more ugly. So I am moving the workaround script back to the %pre and reopening this bug, because the current behaviour of RPM is unacceptable.

Comment 8 Panu Matilainen 2013-03-25 06:50:09 UTC
(In reply to comment #7)
> (In reply to comment #3)
> > Whatever was done in espeak 1.47.03-1 to 'work around' this is breaking live
> > compose somehow. When I try and build a live image with the 1.47.03-1
> > package included, I get "Error creating Live CD : Dependency check failed!"
> 
> That's exactly what I wrote before, delivering the content is task of RPM
> and any similar packaging hacks would lead to nothing more then problems.

You're not going to find anybody disagreeing that optimally rpm would be able to deal with such a situation, I love ponies as much as the next guy. Just do realize this limitation is as old as rpm, and there's a reason for its existence: this is anything but an easy thing to do because of how rpm does (and has to do) upgrades. Rpm might some day be able to handle a special case like this where package private directory changes to something else, but that is just not going to happen in F18.

> I tried to be in sync with the comment 1 which stated that using %pre is too
> late, because Rpm >= 4.11 will detect this as a conflict so I moved the
> script from %pre to %pretrans. This adds implicit dep on /bin/sh which is
> not satisfied when building livecd, because "pre transaction" is too early
> and there is no shell installed in this phase. So I would have to use
> %pretrans -p, but I have no idea how to code the script there, becase the
> 'rm' hack takes at least two arguments (-rf and directory). Also I have no
> idea how to install some (binary ?) helper in this "early phase" and such
> "stripped down" hack would be much more ugly. So I am moving the workaround
> script back to the %pre and reopening this bug, because the current
> behaviour of RPM is unacceptable.

If you look at comment 1 carefully, I wrote "%pretrans -p <lua>" script, not just any %pretrans. Using the built-in lua interpreter avoids the problematic dependency to /bin/sh which does not exist the point %pretrans executes on initial installation.

Comment 9 Jaroslav Škarvada 2013-03-25 11:09:28 UTC
(In reply to comment #8)
> If you look at comment 1 carefully, I wrote "%pretrans -p <lua>" script, not
> just any %pretrans. Using the built-in lua interpreter avoids the
> problematic dependency to /bin/sh which does not exist the point %pretrans
> executes on initial installation.

Heh, that's even more ugly than I previously thought :)

I workarounded it by the following snippet:

%pretrans -p <lua>
--# Migrate from espeak-1.46.
--# Remove /usr/share/espeak-data/voices/en directory (if found).
function migrate_espeak()
    t = posix.stat("%{_datadir}/%{name}-data/voices/en", "type")
    if t ~= "directory" then return end

    os.execute("rm -f %{_datadir}/%{name}-data/voices/en/*")
    os.execute("rmdir %{_datadir}/%{name}-data/voices/en")
end

migrate_espeak()
return 0

Comment 10 Jaroslav Škarvada 2013-03-25 12:23:45 UTC
(In reply to comment #9)
This is very ugly, in case the transaction fails / is aborted, it leaves the espeak package in the broken state (i.e. without en voices).

I could rename the directory in the %pretrans, and later delete it (if the transaction pass) in the %posttrans or rename it back if the transaction fails (not sure if the %posttrans is called for failed transaction). This is also very ugly.

Or please rollback the check mentioned in comment 1:
> Rpm >= 4.11 (so Fedora >= 19) detects an attempt to replace a directory with something else as a conflict
and IMHO it could be then workarounded safely in the %pre.

Comment 11 Panu Matilainen 2013-03-25 12:44:41 UTC
(In reply to comment #10)
> (In reply to comment #9)
> This is very ugly, in case the transaction fails / is aborted, it leaves the
> espeak package in the broken state (i.e. without en voices).
> 
> I could rename the directory in the %pretrans, and later delete it (if the
> transaction pass) in the %posttrans or rename it back if the transaction
> fails (not sure if the %posttrans is called for failed transaction). This is
> also very ugly.

Sure its ugly and unsafe no matter what kind of script-hackery is used. A better option would be switching to a different directory altogether, eg move the toplevel espeak-data to some other name. Or just the voices directory.

> Or please rollback the check mentioned in comment 1:
> > Rpm >= 4.11 (so Fedora >= 19) detects an attempt to replace a directory with something else as a conflict
> and IMHO it could be then workarounded safely in the %pre.

No, %pre is too late because fingerprinting is done with the wrong data on filesystem and it can have other "interesting" side-effects then. The sanity check is going to stay, its better for rpm to abort early for the case it can't handle than barf up somewhere in middle of a large transaction.

Comment 12 Jaroslav Škarvada 2013-03-25 14:56:44 UTC
(In reply to comment #11)
OK, I will try to temporary rename the parent dir to something else and rename it back when some other update occurs later. It seems as the least ugly workaround for me.

Comment 13 Panu Matilainen 2013-03-27 07:39:12 UTC
Yup. Closing NEXTRELEASE again as per comment #1: newer rpm versions will at least detect the problem early on, actually making directories replaceable with something else is beyond what can be done in the foreseeable future, let alone already released rpm versions.


Note You need to log in before you can comment on or make changes to this bug.