8

I want to install the running kernel by command line.

Say for example, I have installed a custom kernel, linux-image-4.0-1-xyz and I have booted with this kernel (when I do uname -r, I get above kernel version.

Now, I want to remove this kernel without switching to the generic kernel.

I tried apt purge -y linux-image-4.0-1-xyz and this runs, but I am getting a Package Configuration dialog which asks

Do you want to abort removal now?

There are 2 options

<Yes> <No>

How can I select <No> through command line?

Zanna
  • 70,465
  • You can't install the kernel version which is running. –  Nov 02 '18 at 11:05
  • 1
    @GabrielaGarcia Yes, you can. – fkraiem Nov 02 '18 at 11:26
  • @fkraiem Waiting for your answer then. :) –  Nov 02 '18 at 11:29
  • 1
    This seems a question about how to select options using the keyboard, so I do not quite understand the long, distracting paragraph about unwise package management. – user535733 Nov 02 '18 at 11:52
  • @Zanna Can you share the exact command that you used. Also, did you uninstall from same kernel or from different kernel? I am trying to do from same kernel. – Pulkit Lall Nov 05 '18 at 04:44
  • The running kernel as I said, but I think I actually just deleted it and then reinstalled it rather than uninstalling with APT. I just tried it now (sudo apt remove linux-image-$(uname -r)) and I did get the dialog you mentioned. I moved to NO with the arrow key and pressed enter and the kernel packages were uninstalled. To install it again, I had to run sudo apt install linux-image-$(uname -r) linux-modules-extra-$(uname -r) because the modules package got removed but didn't automatically get pulled in. I wonder why you want to uninstall the running kernel though. – Zanna Nov 05 '18 at 09:15
  • @Zanna I am trying to do using commandline. Though command line, how to select NO. – Pulkit Lall Nov 06 '18 at 10:03
  • do you mean you want to avoid the dialog? – Zanna Nov 06 '18 at 10:22
  • @Zanna yes please – Pulkit Lall Nov 08 '18 at 05:17

4 Answers4

5

The actual answer to this question is a little more annoying than I anticipated. Yes, yes, this is dangerous, and the maintainers make it exceptionally hard to do this for precisely this reason. But if you're trying to automate your infrastructure to do something like this, I trust you actually know what you're doing. In my case, it's because I'm trying to purge the (currently running) kernel inside another script which verifies that there is indeed a newer kernel available.

By checking through the output of debconf-get-selections, there is indeed an option to preselect this value for you:

$ sudo debconf-get-selections | grep -B1 linux-base
# Abort kernel removal?
linux-base      linux-base/removing-running-kernel      boolean true

If you set this to "false" using debconf-set-selections, however, nothing changes. You are still prompted.

This let to some digging into exactly what is calling this. It turns out, at least on relatively current (Buster) versions of Debian and likely Ubuntu, there is a separate Perl script called linux-check-removal whos purpose seems to be to ignore, reset, and then prompt for this warning.

http://manpages.ubuntu.com/manpages/cosmic/man1/linux-check-removal.1.html

This script is called from the prerm dpkg script for the given kernel, e.g.

$ cat /var/lib/dpkg/info/linux-image-4.19.0-13-amd64.prerm
#!/bin/sh -e

version=4.19.0-13-amd64 image_path=/boot/vmlinuz-$version

if [ "$1" != remove ]; then exit 0 fi

linux-check-removal $version

if [ -d /etc/kernel/prerm.d ]; then DEB_MAINT_PARAMS="$*" run-parts --report --exit-on-error --arg=$version
--arg=$image_path /etc/kernel/prerm.d fi

exit 0

And verifying its operation:

$ sudo linux-check-removal $(uname -r)
# "Yes" selected
E: Aborting removal of the running kernel
$ echo $?
1
$ sudo linux-check-removal $(uname -r)
# "No" selected
W: Removing the running kernel
$ echo $?
0

So, the actual solution is to override this command with something that just returns 0 instead.

However, despite the command using a relative call, the $PATH inside this script when called from dpkg does not include /usr/local directories. So a simple override of the script in /usr/local/bin, as you might expect to be able to do, does not work. To demonstrate, I modified the prerm to print the $PATH and which values and then called the apt remove command:

Removing linux-image-4.19.0-13-amd64 (4.19.160-2) ...
PATH: /usr/sbin:/usr/bin:/sbin:/bin
WHICH: /usr/bin/linux-check-removal
W: Removing the running kernel

Thus, we are forced to temporarily move the real /usr/bin/linux-check-removal out of the way and install a dummy placeholder script that just returns 0 instead. The simplest way I can think to do this would be:

$ sudo mv /usr/bin/linux-check-removal /usr/bin/linux-check-removal.orig
$ echo -e '#!/bin/sh\necho "Overriding default linux-check-removal script!"\nexit 0' | sudo tee /usr/bin/linux-check-removal
$ sudo chmod +x /usr/bin/linux-check-removal

You can probably remove the echo line if you wish, but I include it for the demonstration.

Now you can successfully purge the running kernel version non-interactively:

$ sudo apt purge -y linux-image-4.19.0-13-amd64
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following packages were automatically installed and are no longer required:
  linux-headers-4.19.0-12-amd64 linux-headers-4.19.0-12-common linux-image-4.19.0-12-amd64
Use 'sudo apt autoremove' to remove them.
The following packages will be REMOVED:
  linux-image-4.19.0-13-amd64*
0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded.
After this operation, 270 MB disk space will be freed.
(Reading database ... 104395 files and directories currently installed.)
Removing linux-image-4.19.0-13-amd64 (4.19.160-2) ...
Overriding default linux-check-removal script!
I: /vmlinuz.old is now a symlink to boot/vmlinuz-4.19.0-12-amd64
I: /initrd.img.old is now a symlink to boot/initrd.img-4.19.0-12-amd64
/etc/kernel/postrm.d/initramfs-tools:
update-initramfs: Deleting /boot/initrd.img-4.19.0-13-amd64
/etc/kernel/postrm.d/zz-update-grub:
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-4.19.0-14-amd64
Found initrd image: /boot/initrd.img-4.19.0-14-amd64
Found linux image: /boot/vmlinuz-4.19.0-12-amd64
Found initrd image: /boot/initrd.img-4.19.0-12-amd64
done
(Reading database ... 99993 files and directories currently installed.)
Purging configuration files for linux-image-4.19.0-13-amd64 (4.19.160-2) ...

And then restore the original linux-check-removal:

$ sudo mv /usr/bin/linux-check-removal.orig /usr/bin/linux-check-removal
Joshua Boniface
  • 171
  • 1
  • 5
3

Note to vistors: while it is possible, it is highly inadvisable to remove the running kernel. If that kernel is the only one installed, and you reboot or lose power after uninstalling or deleting it, your system will be unbootable and you will probably have to reinstall. Recovery mode will not work. If this happens, you can boot from a live system to rescue your data and possibly copy kernel files to the right locations. There is normally no reason to uninstall the running kernel. So you probably should not follow this answer :)


You stated in comments that you want to avoid the dialog that appears when you use package management tools to remove the running kernel. The only way I can think of to achieve this is to delete all the files belonging to the running kernel.

We are going to use locate to find the kernel's files. First update its database.

sudo updatedb

If for some reason you don't want to delete the dpkg database records for the kernel, run this command instead of the above:

sudo updatedb --prunepaths=/var/lib/dpkg

Find the running kernel and its modules, etc:

locate -be $(uname -r)

Check the list. To remove ALL the files that belong to the kernel, even the many small files in /usr/src, omit the -b flag from locate. When you have the list you want, pipe the results to xargs to delete the files:

locate -be $(uname -r) -0 | xargs -0 sudo rm -r

To make xargs interactive, you can add the -p flag and it will prompt you to confirm that you really do want to run rm on each file in the list. If you omit -b from locate and add -p to xargs, you will be confirming for a long time.

It is not really necessary to use -0 flags to get null-delimited output because all these files will have sane names unless you or someone else has tinkered with them. But it is good practice to use null-delimiting with xargs, because it makes mistakes if any filename has a space.

To prevent GRUB attempting to boot or giving you the option of booting a non-existent kernel, update the configuration:

sudo update-grub

I just tested this, and right now, I am typing this from the system on which I've deleted the running kernel in this way (I booted from an older Ubuntu kernel to do this, because I normally use a patched kernel that dpkg doesn't know about, and I don't want to delete it and compile it again).

The kernel is in RAM. It is loaded into RAM at boot time, so it doesn't need its files right now. However, I'm now going to reinstall the kernel using these commands:

sudo apt update
sudo apt install --reinstall linux-image-$(uname -r) \
                             linux-modules-extra-$(uname -r) \
                             linux-headers-$(uname -r) \
                             linux-modules-$(uname -r)

Since you seem to be interested in a non-interactive process, I'll mention that you can use apt-get in preference to apt if you wish to capture any output into a file for later use.

Zanna
  • 70,465
  • 1
    Works like a charm, thanks! Regarding highly inadvisable - this depends on circumstances. If you're doing this on a fresh cloud VM as part of an automated build (e.g. creating AWS AMI with a custom kernel), there is absolutely nothing wrong with this approach. – nirvana-msu Jan 14 '23 at 13:23
1

Use the TAB key to move the selector. Use ENTER to select.

user535733
  • 62,253
0

The blocker

It is /usr/bin/linux-check-removal that is prompting.

$ /usr/bin/linux-check-removal

Usage: /usr/bin/linux-check-removal VERSION

This command is intended to be called from the prerm maintainer scripts of Linux kernel packages.

The VERSION argument must be the kernel version string as shown by 'uname -r' and used in filenames.

If the currently running kernel matches VERSION, linux-check-removal will normally prompt the user to confirm this potentially dangerous action and will fail if the user chooses to abort. However, if the current environment is in a chroot or container, or if debconf prompts are disabled, it will always succeed without prompting.


The solution

It doesn't have to be complicated. Just read what it says:

if debconf prompts are disabled, it will always succeed without prompting.

Prepend DEBIAN_FRONTEND=noninteractive to disable Debian prompts.

DEBIAN_FRONTEND=noninteractive apt purge --autoremove --assume-yes linux-image-$(uname --kernel-release)

works without prompting you.