I am writing a package for a binary kernel that should not allow uninstall of the current running kernel. The package accurately calls `die` when it detects that attempt, but the removal of the package proceeds as if nothing happened Reproducible: Always Actual Results: >>> Unmerging (1 of 1) sys-kernel/bubba-b3-kernel-5.4.28... * Checking current running kernel version ... [ !! ] * ERROR: sys-kernel/bubba-b3-kernel-5.4.28::x-tmp failed (prerm phase): * Cowardly refusing to uninstall the current running kernel * * Call stack: * ebuild.sh, line 125: Called pkg_prerm * environment, line 505: Called die * The specific snippet of code: * die "Cowardly refusing to uninstall the current running kernel"; * * If you need support, post the output of `emerge --info '=sys-kernel/bubba-b3-kernel-5.4.28::x-tmp'`, * the complete build log and the output of `emerge -pqv '=sys-kernel/bubba-b3-kernel-5.4.28::x-tmp'`. * The complete build log is located at '/var/tmp/portage/._unmerge_/sys-kernel/bubba-b3-kernel-5.4.28/temp/build.log'. * The ebuild environment file is located at '/var/tmp/portage/._unmerge_/sys-kernel/bubba-b3-kernel-5.4.28/temp/environment'. * Working directory: '/var/tmp/portage/._unmerge_/sys-kernel/bubba-b3-kernel-5.4.28/homedir' * S: '/var/tmp/portage/._unmerge_/sys-kernel/bubba-b3-kernel-5.4.28/work/bubba-b3-kernel-5.4.28' !!! FAILED prerm: 1 No package files given... Grabbing a set. <<< obj /usr/src/linux-5.4.28-gentoo/System.map <<< obj /usr/src/linux-5.4.28-gentoo/Module.symvers <<< obj /usr/src/linux-5.4.28-gentoo/.config --- cfgpro sym /lib/modules/5.4.28-gentoo-b3/source --- cfgpro obj /lib/modules/5.4.28-gentoo-b3/modules.symbols.bin --- cfgpro obj /lib/modules/5.4.28-gentoo-b3/modules.symbols --- cfgpro obj /lib/modules/5.4.28-gentoo-b3/modules.softdep --- cfgpro obj /lib/modules/5.4.28-gentoo-b3/modules.order --- cfgpro obj /lib/modules/5.4.28-gentoo-b3/modules.devname --- cfgpro obj /lib/modules/5.4.28-gentoo-b3/modules.dep.bin --- cfgpro obj /lib/modules/5.4.28-gentoo-b3/modules.dep --- cfgpro obj /lib/modules/5.4.28-gentoo-b3/modules.builtin.modinfo ... ... --- cfgpro sym /lib/modules/5.4.28-gentoo-b3/build --- cfgpro dir /lib/modules/5.4.28-gentoo-b3 <<< obj /boot/vmlinuz-5.4.28-gentoo-b3 <<< obj /boot/config-5.4.28-gentoo-b3 <<< obj /boot/System.map-5.4.28-gentoo-b3 <<< obj /boot/Module.symvers-5.4.28-gentoo-b3 <<< dir /usr/src/linux-5.4.28-gentoo --- !empty dir /usr/src --- !empty dir /usr --- !empty dir /lib/modules --- !empty dir /lib --- !empty dir /boot Packages installed: 617 Packages in world: 63 Packages in system: 43 Required packages: 617 Number removed: 1 Expected Results: Execution stop rather than simply print that the programmed preconditions were not met.
Updated to version 2.3.99-r2 today. No change, die() called in the prerm() phase still does not prevent portage to proceed with package removal. Note that this may be verified with any binary kernel installation by having /boot unmounted during removal, in which case it will proceed to remove the associated modules and the /var/db/pkg entry.
I think we could probably change the portage behavior but then we'd probably have to add an option to allow people to forcefully remove the package if necessary.
How would that work with weak blockers though?
Right. Should have probably mentioned that the function I was referring to in my previous comment is part of the `mount-boot` eclass, which unlike what its name appears to indicate does not mount boot if it was not already mounted, but returns an error if it is not. When you install a binary kernel package (or a boot manager I presume) and /boot is not mounted, the `mount-boot` eclass will call die() in the pretend phase and that actually stops portage from proceeding. When you uninstall a package though, it never calls pretend() but goes straight to prerm() where die() causes a lot of error information to be printed (as expected) but portage carries on as if the error didn't occur. A bit reading between the lines of your comment, could this be because the *rm() functions have a double function, also called to clean up a previous installed version of a package after install?
(In reply to Gordon Bos from comment #4) > A bit reading between the lines of your comment, could this be because the > *rm() functions have a double function, also called to clean up a previous > installed version of a package after install? Yes, exactly, and I even didn't think of that simpler case. The general problem is that removing some old package may be necessary for other installed package to function correctly. Leaving it installed might leave the system in a weird state. At the very least, Portage should abort further operations if that occurs.
Reflecting on above comments. I had actually missed the remark about weak blockers and I do follow the reasoning that bad things may happen if conflicting packages are allowed to co-exist, but the same applies to a kernel where all the modules have been wiped. What I am wondering is if there is any actual use case of an unexpected die during a prerm phase? If there is, surely that must have some OS return code associated with it that allows distinguishing it from a deliberate call to die().
(In reply to Gordon Bos from comment #6) > What I am wondering is if there is any actual use case of an unexpected die > during a prerm phase? I suppose the die from comment #0 would be unexpected in a chroot, since there's no danger in unmerging the running kernel when it happens to be in a chroot. > If there is, surely that must have some OS return code associated with it that > allows distinguishing it from a deliberate call to die(). Portage is able to distinguish deliberate die calls via ipc (or if ipc is disabled then it uses a temporary file referenced by a variable named PORTAGE_EBUILD_EXIT_FILE to indicate deliberate exit).
(In reply to Zac Medico from comment #7) > (In reply to Gordon Bos from comment #6) > > What I am wondering is if there is any actual use case of an unexpected die > > during a prerm phase? > > I suppose the die from comment #0 would be unexpected in a chroot, since > there's no danger in unmerging the running kernel when it happens to be in a > chroot. Have to disagree, because this may still lead to a broken kernel without modules if /boot is not mounted within the chroot environment. > > If there is, surely that must have some OS return code associated with it that > > allows distinguishing it from a deliberate call to die(). > > Portage is able to distinguish deliberate die calls via ipc (or if ipc is > disabled then it uses a temporary file referenced by a variable named > PORTAGE_EBUILD_EXIT_FILE to indicate deliberate exit). Okay, but that would mean that a call to die() which must be considered a deliberate action by the ebuild file can be identified and thus should be obeyed. But it isn't.
(In reply to Gordon Bos from comment #8) > (In reply to Zac Medico from comment #7) > > (In reply to Gordon Bos from comment #6) > > > What I am wondering is if there is any actual use case of an unexpected die > > > during a prerm phase? > > > > I suppose the die from comment #0 would be unexpected in a chroot, since > > there's no danger in unmerging the running kernel when it happens to be in a > > chroot. > > > Have to disagree, because this may still lead to a broken kernel without > modules if /boot is not mounted within the chroot environment. You may want to support some notion of a non-live system. My regular update process involves creating a btrfs snapshot of my root filesystem, updating that snapshot in a chroot, and then rebooting into the updated snapshot. My /boot happens to be on a separate partition, but that need not always be the case.
(In reply to Zac Medico from comment #9) > You may want to support some notion of a non-live system. My regular update > process involves creating a btrfs snapshot of my root filesystem, updating > that snapshot in a chroot, and then rebooting into the updated snapshot. My > /boot happens to be on a separate partition, but that need not always be the > case. Uhmmm.... That is actually the precise point that I was making. That if /boot is on a separate partition and thus proceeding to attempt removal will remove the kernel modules but will be unable to remove the kernel itself or make any required changes to the bootloader. The only difference between live and non-live for this use case is that in the non-live system you can clear the complete /lib/modules/[kernel] folder whereas in a live environment you cannot.