Wine added symlinks to cover its cross-arch DLL support. $ ls -l /usr/lib64/wine/ total 68 lrwxrwxrwx. 1 root root 23 Sep 16 19:00 i386-unix -> /usr/lib/wine/i386-unix lrwxrwxrwx. 1 root root 26 Sep 16 19:00 i386-windows -> /usr/lib/wine/i386-windows drwxr-xr-x. 2 root root 4096 Oct 16 16:36 x86_64-unix drwxr-xr-x. 2 root root 61440 Oct 16 16:36 x86_64-windows $ ls -l /usr/lib/wine/ total 72 drwxr-xr-x. 2 root root 4096 Oct 16 16:36 i386-unix drwxr-xr-x. 2 root root 65536 Oct 16 16:36 i386-windows lrwxrwxrwx. 1 root root 27 Sep 16 19:00 x86_64-unix -> /usr/lib64/wine/x86_64-unix lrwxrwxrwx. 1 root root 30 Sep 16 19:00 x86_64-windows -> /usr/lib64/wine/x86_64-windows As of Wine 10.12 in Fedora 43 this directory structure with symlinks is no longer needed. Unfortunately trying to add a %pretrans scriptlet to remove the symlinks does not help upgrades from Fedora 42 to 43. Running the "rpm" tool manually on the wine packages successfully runs the %pretrans scriptlets and the "rpm" tool upgrades packages without complaint. Reproducible: Always Steps to Reproduce: 1. Install Fedora 42 2. Install wine 3. Upgrade to Fedora 43 4. Build wine from the rawhide branch and use dnf upgrade ./*.rpm Actual Results: Running transaction Transaction failed: Rpm transaction failed. Warning: skipped OpenPGP checks for 34 packages from repository: @commandline - file /usr/lib/wine/i386-windows/ddraw.dll conflicts between attempted installs of wine-core-10.16-1.fc42.i686 and wine-core-10.16-1.fc42.x86_64 - file /usr/lib/wine/i386-windows/kernelbase.dll conflicts between attempted installs of wine-core-10.16-1.fc42.i686 and wine-core-10.16-1.fc42.x86_64 - file /usr/lib/wine/i386-windows/shell32.dll conflicts between attempted installs of wine-core-10.16-1.fc42.i686 and wine-core-10.16-1.fc42.x86_64 - file /usr/lib/wine/i386-windows/urlmon.dll conflicts between attempted installs of wine-core-10.16-1.fc42.i686 and wine-core-10.16-1.fc42.x86_64 - file /usr/lib/wine/i386-windows/windows.devices.bluetooth.dll conflicts between attempted installs of wine-core-10.16-1.fc42.i686 and wine-core-10.16-1.fc42.x86_64 - file /usr/lib/wine/i386-windows/wined3d.dll conflicts between attempted installs of wine-core-10.16-1.fc42.i686 and wine-core-10.16-1.fc42.x86_64 - file /usr/lib/wine/i386-windows/winexinput.sys conflicts between attempted installs of wine-core-10.16-1.fc42.i686 and wine-core-10.16-1.fc42.x86_64 - file /usr/lib/wine/i386-windows/wininet.dll conflicts between attempted installs of wine-core-10.16-1.fc42.i686 and wine-core-10.16-1.fc42.x86_64 - file /usr/lib/wine/i386-windows/winmm.dll conflicts between attempted installs of wine-core-10.16-1.fc42.i686 and wine-core-10.16-1.fc42.x86_64 - file /usr/lib/wine/i386-windows/wintrust.dll conflicts between attempted installs of wine-core-10.16-1.fc42.i686 and wine-core-10.16-1.fc42.x86_64 Expected Results: pretrans scriptlets run, symlinks deleted. Additional Information: The pretrans scriptlets are not built yet and live in the rawhide branch. https://src.fedoraproject.org/rpms/wine/c/39b67234f34e01832dc332196c7836fcfc1a31db?branch=rawhide
> Running the "rpm" tool manually on the wine packages successfully runs the %pretrans scriptlets and the "rpm" tool upgrades packages without complaint That's hard to believe because DNF5 calls RPM to install the packages, including performing RPM scritplets. I worry your testing did not have completely identical environment. > 1. Install Fedora 42 > 2. Install wine > 3. Upgrade to Fedora 43 Is that really necessary? Could a direct upgrade from Fedora 42 to your not-yet-existing F44 build be enough? > 4. Build wine from the rawhide branch and use dnf upgrade ./*.rpm > The pretrans scriptlets are not built yet and live in the rawhide branch. Please provide the built wine packages which can reproduce the bug. E.g. a link to scratch build in Koji.
I tested your pretrans script let in a separate package and "dnf reinstall" successfully removes the symlink: root@fedora-44:~ # stat /usr/lib/wine/x86_64-unix File: /usr/lib/wine/x86_64-unix -> foo Size: 3 Blocks: 0 IO Block: 4096 symbolic link Device: 252,0 Inode: 260076 Links: 1 Access: (0777/lrwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root) Context: unconfined_u:object_r:lib_t:s0 Access: 2025-10-24 12:01:18.212000000 +0200 Modify: 2025-10-24 12:01:18.212000000 +0200 Change: 2025-10-24 12:01:18.212000000 +0200 Birth: 2025-10-24 12:01:18.212000000 +0200 root@fedora-44:~ # rpm -q -p --scripts ~test/rpmbuild/RPMS/noarch/test-0-0.fc44.noarch.rpm pretrans scriptlet (using <lua>): pathA = "/usr/lib/wine/x86_64-unix" pathB = "/usr/lib/wine/x86_64-windows" stA = posix.stat(pathA) stB = posix.stat(pathB) if stA and stA.type == "link" then os.remove(pathA) end if stB and stB.type == "link" then os.remove(pathB) end root@fedora-44:~ # dnf -q -y reinstall ~test/rpmbuild/RPMS/noarch/test-0-0.fc44.noarch.rpm Package Arch Version Repository Size Reinstalling: test noarch 0-0.fc44 @commandline 0.0 B replacing test noarch 0-0.fc44 @commandline 0.0 B Transaction Summary: Reinstalling: 1 package Replacing: 1 package [1/4] Verify package files 100% | 90.0 B/s | 1.0 B | 00m00s [2/4] Prepare transaction 100% | 21.0 B/s | 2.0 B | 00m00s [3/4] Reinstalling test-0:0-0.fc44.noarch 100% | 10.1 KiB/s | 124.0 B | 00m00s [4/4] Removing test-0:0-0.fc44.noarch 100% | 467.0 B/s | 100.0 B | 00m00s Warning: skipped OpenPGP checks for 1 package from repository: @commandline root@fedora-44:~ # stat /usr/lib/wine/x86_64-unix stat: cannot statx '/usr/lib/wine/x86_64-unix': No such file or directory I recommend you checking /var/log/dnf5.log. If the pretrans script finishes, you should see an entry like this: 2025-10-24T10:01:51+0000 [2345] INFO RPM callback open file "/home/test/rpmbuild/RPMS/noarch/test-0-0.fc44.noarch.rpm" 2025-10-24T10:01:51+0000 [2345] INFO RPM callback start %pretrans scriptlet "test-0:0-0.fc44.noarch" 2025-10-24T10:01:51+0000 [2345] INFO RPM callback stop %pretrans scriptlet "test-0:0-0.fc44.noarch" return code 0 2025-10-24T10:01:51+0000 [2345] INFO RPM callback close file By the way the two %ifarch branches in the scriptlet in your wine.spec are identical, you might want to write a single "%ifarch %{ix86} x86_64" condition. I also recommends to place the %pretrans directive into the conditional block, so that you don't produce empty %pretrans scripts for other architectures.
> That's hard to believe because DNF5 calls RPM to install the packages, including performing RPM scritplets. I worry your testing did not have completely identical environment. I could take a video? I've been scratching my head for weeks. (In reply to Petr Pisar from comment #2) > I tested your pretrans script let in a separate package and "dnf reinstall" > successfully removes the symlink: Sure, but that isn't the same. Did your separate package contain files living in /usr/lib/wine/x86_64-unix ? > I recommend you checking /var/log/dnf5.log. If the pretrans script finishes, you should see an entry like this: No '%pretrans' line appears in my dnf5.log. That seems like a problem. > By the way the two %ifarch branches in the scriptlet in your wine.spec are > identical, you might want to write a single "%ifarch %{ix86} x86_64" > condition. I also recommends to place the %pretrans directive into the > conditional block, so that you don't produce empty %pretrans scripts for > other architectures. The committed version was wrong and I've since corrected it and tried even different ways to move files out of the way. Here's a scratch build: https://koji.fedoraproject.org/koji/taskinfo?taskID=138507391 You will need to start with a version of wine that has symlinks and then dnf upgrade to the scratch build. 10.4-6 was the first version with symlinks, or I can scratch build 10.15 with the "old" wow64 support. 10.4-6.fc43: https://koji.fedoraproject.org/koji/buildinfo?buildID=2744162 I promise you I'm not making this up. I know you and I have worked with RPM files for a very long time. Thanks for your time.
I enhanced my mock pakage to package the symlink in the old version and it still works for me. I installed wine-10.4-6.fc43.x86_64 from <https://koji.fedoraproject.org/koji/buildinfo?buildID=2744162> on F44. I checked that the /usr/lib64/wine/i386-unix symlink exists and is owned by wine-core.x86_64. Then I upgraded to your scratchbuild with developmental DNF5 version. RPM library correctly warned that /usr/lib64/wine/i386-unix could not been removed because it does not exist. dnf5.log correctly reported that the %pretrans scriptlet of wine-core-0:10.16-1.fc44.x86_64 was successfully executed (the %postrans too). And at the end, the symlink has gone from the file system. I will retry it with stable DNF5, and also on F43, but I worry I'll get the same success.
I tried you original procedure: I took an up-to-date Fedora 42 system. I installed wine-10.15-1.fc42.x86_64. It created the symlinks: root@fedora-42:~ # ls -l /usr/lib64/wine total 40 lrwxrwxrwx. 1 root root 23 Sep 17 02:00 i386-unix -> /usr/lib/wine/i386-unix lrwxrwxrwx. 1 root root 26 Sep 17 02:00 i386-windows -> /usr/lib/wine/i386-windows drwxr-xr-x. 2 root root 4096 Oct 29 12:44 x86_64-unix drwxr-xr-x. 2 root root 36864 Oct 29 12:44 x86_64-windows root@fedora-42:~ # ls -l /usr/lib/wine total 40 drwxr-xr-x. 2 root root 4096 Oct 29 12:44 i386-unix drwxr-xr-x. 2 root root 36864 Oct 29 12:45 i386-windows lrwxrwxrwx. 1 root root 27 Sep 17 02:00 x86_64-unix -> /usr/lib64/wine/x86_64-unix lrwxrwxrwx. 1 root root 30 Sep 17 02:00 x86_64-windows -> /usr/lib64/wine/x86_64-windows but no package owns the directories, the targets of the symlinks: # rpm -qf /usr/lib64/wine/* wine-core-10.15-1.fc42.x86_64 wine-core-10.15-1.fc42.x86_64 file /usr/lib64/wine/x86_64-unix is not owned by any package file /usr/lib64/wine/x86_64-windows is not owned by any package root@fedora-42:~ # rpm -qf /usr/lib/wine/* file /usr/lib/wine/i386-unix is not owned by any package file /usr/lib/wine/i386-windows is not owned by any package wine-core-10.15-1.fc42.i686 wine-core-10.15-1.fc42.i686 Then I commenced "dnf --releasever 43 upgrade". It failed: Transaction failed: Rpm transaction failed. - file /usr/lib64/wine/i386-windows from install of wine-core-10.15-1.fc43.x86_64 conflicts with file from package wine-core-10.15-1.fc42.x86_64 - file /usr/lib/wine/i386-windows/ddraw.dll conflicts between attempted installs of wine-core-10.15-1.fc43.i686 and wine-core-10.15-1.fc43.x86_64 - file /usr/lib/wine/i386-windows/urlmon.dll conflicts between attempted installs of wine-core-10.15-1.fc43.i686 and wine-core-10.15-1.fc43.x86_64 - file /usr/lib/wine/i386-windows/windows.devices.bluetooth.dll conflicts between attempted installs of wine-core-10.15-1.fc43.i686 and wine-core-10.15-1.fc43.x86_64 - file /usr/lib/wine/i386-windows/wined3d.dll conflicts between attempted installs of wine-core-10.15-1.fc43.i686 and wine-core-10.15-1.fc43.x86_64 - file /usr/lib/wine/i386-windows/winmm.dll conflicts between attempted installs of wine-core-10.15-1.fc43.i686 and wine-core-10.15-1.fc43.x86_64 So the problem has already existed with stable wine-core-10.15-1.fc43.x86_64. Then I tried upgrading in that F42 system to your new wine-0:10.16-1.fc44 scratch build and it failed similarly: Warning: skipped OpenPGP checks for 35 packages from repository: wine - file /usr/lib/wine/i386-windows/ddraw.dll conflicts between attempted installs of wine-core-10.16-1.fc44.i686 and wine-core-10.16-1.fc44.x86_64 - file /usr/lib/wine/i386-windows/urlmon.dll conflicts between attempted installs of wine-core-10.16-1.fc44.i686 and wine-core-10.16-1.fc44.x86_64 - file /usr/lib/wine/i386-windows/windows.devices.bluetooth.dll conflicts between attempted installs of wine-core-10.16-1.fc44.i686 and wine-core-10.16-1.fc44.x86_64 - file /usr/lib/wine/i386-windows/wined3d.dll conflicts between attempted installs of wine-core-10.16-1.fc44.i686 and wine-core-10.16-1.fc44.x86_64 - file /usr/lib/wine/i386-windows/winmm.dll conflicts between attempted installs of wine-core-10.16-1.fc44.i686 and wine-core-10.16-1.fc44.x86_64 Reading the dnf5.log indeed does not show any %pretrans script. The reason is that what fails is not the transaction, but a dry-run transaction verification which is performed before the transaction by DNF5. It exists to catch incompatibilities between DNF5 and RPM dependency solver and to catch file conflicts which DNF5 has no access to. The drawback is that %pretrans scripts are not executed in dry-run transaction because they could have side effects on the file system. But here in your case the script is abused to actually have a side effect. The reason why this happens with wine and not with my mocked packages is that in your case you at the same time swap files between x86_64 and i686 packages and their path prefix conflicts with the symlinks (before being removed by the scriptlet). If I rename the symlinks, then DNF5 can upgrade. So the question is whether DNF5 can and should perform the potentially destructive %pretrans scripts on the dry-run transaction verification. I'm for doing it. But I need to involve more experienced DNF5 developers as I worry that not performing the script is a property of librpm and not DNF5. Affected packages: dnf5-5.2.16.0-1.fc42.x86_64 rpm-libs-4.20.1-1.fc42.x86_64
(In reply to Petr Pisar from comment #5) > The reason why this happens with wine and not with my mocked packages is > that in your case you at the same time swap files between x86_64 and i686 > packages and their path prefix conflicts with the symlinks (before being > removed by the scriptlet). If I rename the symlinks, then DNF5 can upgrade. I suspected a dry-run check. Thank you for your time in confirming. > So the question is whether DNF5 can and should perform the potentially > destructive %pretrans scripts on the dry-run transaction verification. I'm > for doing it. But I need to involve more experienced DNF5 developers as I > worry that not performing the script is a property of librpm and not DNF5. My feelings won't be hurt if this is too invasive. The symlinks were a one-off solution for wine and should (tm) never be used again.
As a workaround, could wine get rid of the symlinks within a new F42 update? Then the symlink removal and the file swap between the packages would be split into multiple transactions and this deficiency of DNF5 would not manifest.
(In reply to Petr Pisar from comment #7) > As a workaround, could wine get rid of the symlinks within a new F42 update? > Then the symlink removal and the file swap between the packages would be > split into multiple transactions and this deficiency of DNF5 would not > manifest. I was seeing this problem on my F42 system. It has since upgraded to F43, but I was building wine without the symlinks to test upgrading on F42 (F42 Wine 10.15 w/links to F42 Wine 10.16 w/o links). For context: The symlinks were created for the "1.0" version of WoW64 in wine. A few versions back Wine supported a "2.0" WoW64 feature by no longer needing 32-bit binaries to run 32-bit executables. One of the wine co-maintainers blocked this 2.0 feature off for F43 and higher only.
Panu, DNF5 does in Transaction::Impl::_run() in libdnf5/base/transaction.cpp effectively this: rpmtsSetFlags(ts, RPMTRANS_FLAG_TEST); rpmtsRun(ts, nullptr, ...) for testing a transaction. Is that a reason why RPM does not execute the wine pretrans script for the test transaction? I found in RPM's handleInstInstalledFile() this: /* * There are some removal conflicts we can't handle. However * if the package has a %pretrans scriptlet, it might be able to * fix the conflict. Let it through on test-transaction to allow * eg yum to get past it, if the conflict is present on the actual * transaction we'll abort. Behaving differently on test is nasty, * but its still better than barfing in middle of large transaction. */ if (beingRemoved) { rConflicts = handleRemovalConflict(fi, fx, otherFi, ofx); if (rConflicts && rpmteHaveTransScript(p, RPMTAG_PRETRANS)) { if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST) rConflicts = 0; } } In this bug report the pretrans script is defined in the same package, wine-core, which triggers the file conflict. Is there anything DNF5 could do differently to let RPM to perform the pretrans script during the test transaction? Otherwise, DNF5 could provide an option to skip testing the transaction. That of course would decrease resilience of the upgrade process and should not be default.
Well, it's not a test-transaction anymore if scripts are executed. The whole test-transaction as inherited from yum is a bit of an anti-pattern. It basically tests for things that would prevent the transaction from taking place anyhow. The only thing it's good for is avoiding changes to the file system from %pretrans if there are dir<->symlink file conflicts. But doing that test-transaction prevents those %pretrans hacks from resolving them conflicts. And here we are. The quoted hack in rpm is an attempt to let it work but there are cases where it doesn't, and it's not really fixable.
When does RPM check for file conflicts in case of non-test transaction? Is it before installing all packages for all of them, or is it per-package activity just before installing that particular package? DNF5 uses the test transaction to discover file conflicts soon. In the past people complained that RPM installed many packages and then a file conflict was reported, leaving the transaction unfinished (with installed both old and new packages), or spending long time rolling back the installed packages to undo the transaction. I ponder whether it still makes sense to do the test transaction to prevent that, or whether its safe now not to do it and remove that code from DNF5.
Rpm checks for file-conflicts before the transaction, of course. That's one of the main things that happen during the "Preparing..." stage, regardless of whether it's a test-transaction or not. Old rpm versions (rpm < 4.11) did not detect those dir<->symlink (and some similar) issues at that stage though, and those are what could cause a mid-transaction failure. The gotcha is that %pretrans runs before those file conflicts checks. It has to, in order to be able to fix those dir<->symlink issues. And if you run a test-transaction that by definition does not execute anything, those scripts can't do what they intend to do, and thus the conflicts remain, and prevent the transaction. It's an oxymoron that only exists in the yum family line of depsolvers. Rpm itself does not do a separate test-transaction, and neither do any of the other depsolvers. Of course the real flaw is rpm having such a horribly broken mechanism in the first place. AIUI nothing like that exists in dpkg although it shares the same issue of symlink<->directory replacement, and they're better for it.
(In reply to Panu Matilainen from comment #12) > Rpm checks for file-conflicts before the transaction, of course. That's one > of the main things that happen during the "Preparing..." stage, regardless > of whether it's a test-transaction or not. Old rpm versions (rpm < 4.11) did > not detect those dir<->symlink (and some similar) issues at that stage > though, and those are what could cause a mid-transaction failure. > That's what I needed to know. Thanks. For interactive invocations it is clear that DNF should not test the transaction. Question is what to do with systemd off-line updates: When a user schedules an off-line update, he believes that everything is ready for the update and nothing can fail. The user commence a reboot, the update quickly fails on a file conflict, systemd reboots the machine again, and then the user needs to check whether the update passed or failed and why. It is more or less a problem of a good user interface to dig the error from journald. But still then the user can ask: Can DNF do more to catch the file conflict before rebooting the machine? And we have again the problem of testing the transaction on the stage. One could say that a transaction can fail for whatever reason, not only because a file conflict. That's true. But in distributions with multilib packages, IMHO, the most common cause is file conflicts. One resolution could be keep testing the transaction and allow the user to override the detected file conflicts. Like this one: Transaction test failed: Rpm transaction failed. - file /usr/lib64/wine/i386-windows from install of wine-core-10.15-1.fc43.x86_64 conflicts with file from package wine-core-10.15-1.fc42.x86_64 The requested transaction is expected to fail. Proceed anyway [N/y]?
No, don't offer the option to continue, that's nothing but a footgun that will come back to haunt us. The proper resolution is to uninstall the package. It's typically reinstallable afterwards.