阻拦者

阻拦者

我想通过命令行安装正在运行的内核。

举个例子,我已经安装了一个自定义内核,linux-image-4.0-1-xyz并且我已经用这个内核启动了(当我这样做时uname -r,我得到了上述内核版本。

现在,我想删除这个内核而不切换到通用内核。

我试过了apt purge -y linux-image-4.0-1-xyz,并且运行了,但我收到了一个Package Configuration对话框,询问

Do you want to abort removal now?

有 2 个选项

<Yes> <No>

我如何<No>通过命令行选择?

答案1

这个问题的实际答案比我预期的要烦人一些。是的,是的,这很危险,维护人员正是出于这个原因才让这样做变得异常困难。但是,如果您试图自动化您的基础设施来做这样的事情,我相信您真的知道自己在做什么。就我而言,这是因为我试图在另一个脚本中清除(当前正在运行的)内核,该脚本验证确实有较新的内核可用。

通过检查的输出debconf-get-selections,确实有一个选项可以为您预先选择该值:

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

但是,如果使用 将其设置为“false” debconf-set-selections,则不会发生任何变化。系统仍会提示您。

这让我们深入研究究竟是什么调用了它。事实证明,至少在相对较新的 Debian (Buster) 版本和可能的 Ubuntu 上,有一个单独的 Perl 脚本,其linux-check-removal目的似乎是忽略、重置,然后提示此警告。

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

prerm dpkg该脚本从给定内核的脚本调用,例如

$ 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

并验证其运行情况:

$ 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

因此,实际的解决方案是使用仅返回 0 的命令来覆盖该命令。

然而,尽管该命令使用了相对调用,但$PATH这个脚本内部当被调用时dpkg不包括/usr/local目录。因此,您可能希望能够简单地覆盖 中的脚本/usr/local/bin,但这样做不起作用。为了演示,我修改了 以prerm打印$PATHwhich值,然后调用apt remove命令:

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

因此,我们被迫暂时将 real 移开/usr/bin/linux-check-removal,并安装一个只返回 0 的虚拟占位符脚本。我能想到的最简单的方法是:

$ 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

如果愿意,您可以删除该echo行,但我将其包含在内是为了演示。

现在您可以以非交互方式成功清除正在运行的内核版本:

$ 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) ...

然后恢复原来linux-check-removal

$ sudo mv /usr/bin/linux-check-removal.orig /usr/bin/linux-check-removal

答案2

访客需注意:虽然可以,但是强烈建议不要删除正在运行的内核。如果该内核是唯一安装的内核,并且在卸载或删除它后重新启动或断电,则系统将无法启动,您可能必须重新安装。恢复模式将不起作用。如果发生这种情况,您可以从实时系统启动以挽救数据,并可能将内核文件复制到正确的位置。通常没有理由卸载正在运行的内核。所以你可能不应该遵循这个答案 :)


您在评论中表示,您希望避免使用包管理工具删除正在运行的内核时出现的对话框。我能想到的唯一实现此目的的方法是删除属于正在运行的内核的所有文件。

我们将使用它locate来查找内核的文件。首先更新其数据库。

sudo updatedb

如果由于某种原因您不想删除dpkg内核的数据库记录,请运行此命令而不是上述命令:

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

查找正在运行的内核及其模块等:

locate -be $(uname -r)

检查列表。要删除所有属于内核的文件,甚至包括 中的许多小文件/usr/src,请-b从 中省略标志locate。获得所需列表后,将结果传输到 以xargs删除文件:

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

为了实现xargs交互,您可以添加标志-p,它会提示您确认是否确实要rm对列表中的每个文件运行。如果您省略-bfromlocate并添加-pto xargs,您将需要很长时间确认。

无需使用-0标志来获取空分隔输出,因为所有这些文件都将具有合理的名称,除非您或其他人对它们进行了修改。但使用空分隔是一种很好的做法xargs,因为如果任何文件名中有空格,它就会出错。

为了防止 GRUB 尝试启动或为您提供启动不存在的内核的选项,请更新配置:

sudo update-grub

我刚刚测试了这一点,现在,我正在从我已以这种方式删除正在运行的内核的系统上输入此内容(我从较旧的 Ubuntu 内核启动来执行此操作,因为我通常使用dpkg不知道的修补内核,并且我不想删除它并再次编译它)。

内核位于 RAM 中。它在启动时加载到 RAM 中,因此现在不需要其文件。但是,我现在要使用以下命令重新安装内核:

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

由于您似乎对非交互式过程感兴趣,所以我要提一下,如果您希望将任何输出捕获到文件中以供以后使用,则可以apt-get优先使用。apt

答案3

使用TAB键移动选择器。使用ENTER选择。

答案4

阻拦者

正是/usr/bin/linux-check-removal在促使。

$ /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.

解决方案

这并不复杂。只需阅读以下内容:

如果禁用 debconf 提示,它将始终成功而无需提示。

附加DEBIAN_FRONTEND=noninteractive禁用 Debian 提示

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

无需提示即可工作。

相关内容