有时,我的系统会进入某些内核缺少一个或两个模块的状态,因为 DKMS 不知何故忘记为该内核编译这些模块。与其花时间诊断问题,不如运行一个命令来重建每一个dkms 控制模块每一个安装了内核。有这样的命令吗?
答案1
我想出了一条 shell 单行命令来做到这一点:
ls /var/lib/initramfs-tools | \
sudo xargs -n1 /usr/lib/dkms/dkms_autoinstaller start
这是因为目录名称/var/lib/initramfs-tools
正是您需要传递给它的内核版本名称,dkms_autoinstaller
以告诉它为这些内核版本重建所有模块。请注意,如果您卸载了一些旧内核,它们的目录可能仍然存在并导致报告一些错误,但这不是问题,因为dkms_autoinstaller
不会对未安装的内核版本执行任何操作。
答案2
该命令似乎dkms
不允许您这样做。我创建了一个小型 Python 脚本,可以执行您想要的操作。您可以在您的~/.bashrc
类似
alias dkms-buildall='sudo ./wherever/your/script/is'
当然,你需要先让它可执行。代码如下:
#!/bin/env python
#
# NOTE: This assumes that all modules and versions are built for at
# least one kernel. If that's not the case, adapt parsing as needed.
import os
import subprocess
# Permission check.
if os.geteuid() != 0:
print "You need to be root to run this script."
exit(1)
# Get DKMS status output.
cmd = ['dkms', 'status']
process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
dkms_status = process.communicate()[0].strip('\n').split('\n')
dkms_status = [x.split(', ') for x in dkms_status]
# Get kernel versions (probably crap).
cmd = ['ls', '/var/lib/initramfs-tools/']
# Alternative (for use with Arch Linux for example)
# cmd = ['ls', '/usr/lib/modules/']
process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
kernels = process.communicate()[0].strip('\n').split('\n')
# Parse output, 'modules' will contain all modules pointing to a set
# of versions.
modules = {}
for entry in dkms_status:
module = entry[0]
version = entry[1].split(': ')[0]
try:
modules[module].add(version)
except KeyError:
# We don't have that module, add it.
modules[module] = set([version])
# For each module, build all versions for all kernels.
for module in modules:
for version in modules[module]:
for kernel in kernels:
cmd = ['dkms', 'build', '-m', module, '-v', version, '-k', kernel]
ret = subprocess.call(cmd)
在这里测试了一下,似乎运行良好:
$ dkms status
nvidia-current, 275.09.07, 3.0.0-5-generic, x86_64: installed
virtualbox, 4.0.10, 3.0.0-5-generic, x86_64: installed
$ sudo python dkms.py
...
$ dkms status
nvidia-current, 275.09.07, 3.0.0-5-generic, x86_64: installed
nvidia-current, 275.09.07, 3.0-2-generic, x86_64: built
nvidia-current, 275.09.07, 3.0-3-generic, x86_64: built
virtualbox, 4.0.10, 3.0.0-5-generic, x86_64: installed
virtualbox, 4.0.10, 3.0-2-generic, x86_64: built
virtualbox, 4.0.10, 3.0-3-generic, x86_64: built
如果您还想安装模块,请替换建造和安装在倒数第二行。
答案3
结合@htorque 和@Ryan Thompson 的答案,这是我的(作为 root)一句话:
dkms status | sed s/,//g | awk '{print "-m",$1,"-v",$2}' | while read line; do ls /var/lib/initramfs-tools | xargs -n 1 dkms install $line -k; done
答案4
@htorque 对脚本进行了编辑。如果您需要力量重建(并安装)已构建的模块。切换到 python3,subprocess.run()
需要 Python 3.5+。
#!/usr/bin/env python3
#
# NOTE: This assumes that all modules and versions are built for at
# least one kernel. If that's not the case, adapt parsing as needed.
import os
import subprocess
import re
# Permission check.
if os.geteuid() != 0:
print("You need to be root to run this script.")
exit(1)
# Get DKMS status output.
cmd = ['dkms', 'status']
dkms_status = subprocess.run(cmd, stdout=subprocess.PIPE).stdout.decode("utf-8").strip('\n').split('\n')
dkms_status = [re.split(', |/', x) for x in dkms_status]
##
# Get kernel versions (probably crap).
#cmd = ['ls', '/var/lib/initramfs-tools/'] # Does not work on Ubuntu 22.04
# Alternative (for use with Arch Linux for example)
# cmd = ['ls', '/usr/lib/modules/']
#kernels = subprocess.run(cmd, stdout=subprocess.PIPE).stdout.decode("utf-8").strip('\n').split('\n')
##
## Works on 22.04
prefix = 'initrd.img-'
kernels = [k[len(prefix):] for k in os.listdir('/boot')
if k.startswith(prefix)]
##
# Parse output, 'modules' will contain all modules pointing to a set
# of versions.
modules = {}
for entry in dkms_status:
module = entry[0]
version = entry[1].split(': ')[0]
try:
modules[module].add(version)
except KeyError:
# We don't have that module, add it.
modules[module] = set([version])
# For each module, build all versions for all kernels.
for module in modules:
for version in modules[module]:
for kernel in kernels:
for action in ['remove', 'install']:
cmd = ['dkms', action, '-m', module, '-v', version, '-k', kernel]
subprocess.run(cmd)