Skip to content

Commit

Permalink
Add 'broken' status
Browse files Browse the repository at this point in the history
If either a dkms module source, or the symbolic link pointing to
it is missing, the output of `dkms status` will be messed up.
Add a new status called 'broken', which will inform the user
about it in a nicely formatted way.
is_module_added() was modified to not report a module as added,
if not both the source directory and the 'source' symlink exist.
do_autoinstall() and run_match() were modified to handle a broken
status. They skip that particular module/version combo and continue
iterating.
The new function module_is_broken_and_die() was introduced to die
early on a broken module.
Because if in a broken state everything has to be considered volatile,
we always die. User intvervention is required to restore a healthy
environment.
The only exeption is, if only the symbolic link 'source' is missing,
the action 'add' can be used to re-add the module.
The man page was updated with the new 'broken' status.
Tests were added to the test suite.

Signed-off-by: Mart Frauenlob <[email protected]>
  • Loading branch information
AllKind committed Dec 14, 2023
1 parent dfbbef6 commit 9d6c9ab
Show file tree
Hide file tree
Showing 3 changed files with 241 additions and 1 deletion.
8 changes: 8 additions & 0 deletions dkms.8.in
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,14 @@ Returns the current status of modules, versions and kernels within
the tree as well as whether they have been added, built or installed.
Status can be shown for just a certain module, a certain kernel,
a module/version combination or a module/version/kernel combination.

If the source directory, or the symbolic link 'source' pointing to it is missing,
the status of the module/version combination will be displayed as 'broken'.
In that case dkms will not perform any other action on that particular module/version combination.
Manual intervention is required.
If only the symbolic link 'source' is missing, the
.B add
action may be used to re-add the module/version combination to dkms.
.SY autoinstall
.YS
.IP "" 4
Expand Down
44 changes: 43 additions & 1 deletion dkms.in
Original file line number Diff line number Diff line change
Expand Up @@ -1404,10 +1404,24 @@ list_each_installed_module()
done
}

# Check if either the module source, or the symlink pointing to it is missing
# A module can only be in this broken state, if the user or a faulty program
# messed up. The module then is considered volatile, because there is no reliable
# way to tell if files in the source tree are still in a valid state.
# Therefor any action (except 'add', if only the symlink is missing)
# to operate on the module has to be refused.
# Manual intervention by the user is required to return to a sane state.
is_module_broken() {
[[ $1 && $2 ]] || return 1
[[ -d $dkms_tree/$1/$2 ]] || return 2
[[ -L $dkms_tree/$1/$2/source && ! -d $dkms_tree/$1/$2/source ]] && return
[[ ! -L $dkms_tree/$1/$2/source && -d $source_tree/$1-$2/ ]] && return
}

is_module_added() {
[[ $1 && $2 ]] || return 1
[[ -d $dkms_tree/$1/$2 ]] || return 2
[[ -L $dkms_tree/$1/$2/source || -d $dkms_tree/$1/$2/source ]];
[[ -L $dkms_tree/$1/$2/source && -d $dkms_tree/$1/$2/source ]] || return 2
}

is_module_built() {
Expand Down Expand Up @@ -1607,6 +1621,12 @@ do_uninstall()
[[ $(find $dkms_tree/$module/original_module/* -maxdepth 0 -type d 2>/dev/null) ]] || rm -rf "$dkms_tree/$module/original_module"
}

module_is_broken_and_die() {
is_module_broken "$module" "$module_version" && die 4 $"$module/$module_version is broken!"\
$"Missing the source directory or the symbolic link pointing to it."\
$"Manual intervention is required!"
}

module_is_added_or_die()
{
is_module_added "$module" "$module_version" || die 3 \
Expand Down Expand Up @@ -1808,6 +1828,7 @@ module_status() {
mv="${directory#$dkms_tree/}"
m="${mv%/*}"
v="${mv#*/}"
is_module_broken "$m" "$v" && { echo "broken $m/$v"; continue; }
is_module_added "$m" "$v" || continue
ret=0
module_status_built "$m" "$v" "$3" "$4" || echo "added $m/$v"
Expand All @@ -1828,6 +1849,11 @@ do_status() {
while read status mvka; do
IFS=/ read m v k a <<< "$mvka"
case $status in
broken)
echo "$m/$v: $status"
error $"$m/$v: Missing the module source directory or the symbolic link pointing to it."\
$"Manual intervention is required!"
;;
added)
echo "$m/$v: $status"
;;
Expand Down Expand Up @@ -2104,6 +2130,13 @@ run_match()
echo $"Module: $template_module"
echo $"Version: $template_version"

# Continue if the status is broken, as there is nothing we can do
if is_module_broken "$template_module" "$template_version"; then
error $"$template_module/$template_version is broken!"\
$"Missing the source directory or the symbolic link pointing to it."\
$"Manual intervention is required!"
continue
fi
maybe_build_module "$template_module" "$template_version" "$kernelver" "$arch"
maybe_install_module "$template_module" "$template_version" "$kernelver" "$arch"
done < <(echo "$template_kernel_status")
Expand Down Expand Up @@ -2232,6 +2265,12 @@ autoinstall() {
# a list of modules and their latest version.
while read status mvka; do
IFS='/' read m v k a <<< "$mvka"
# If the module status is broken there is nothing that can be done
if [[ $status = broken ]]; then
error $"$m/$v is broken! Missing the source directory or the symbolic link pointing to it."\
$"Manual intervention is required!"
continue
fi
if [[ -z "${latest["$m"]}" ]]; then
known_modules[${#known_modules[@]}]="$m"
latest["$m"]="$v"
Expand Down Expand Up @@ -2586,12 +2625,14 @@ setup_kernels_arches "$action"
case "$action" in
remove | unbuild | uninstall)
check_module_args $action
module_is_broken_and_die
module_is_added_or_die
[[ $action = uninstall ]] && check_root || check_rw_dkms_tree
${action}_module
;;
add | build | install)
check_all_is_banned $action # TODO: fix/enable --all
[[ $action != add ]] && module_is_broken_and_die
[[ $action = install ]] && check_root || check_rw_dkms_tree
${action}_module
;;
Expand All @@ -2603,6 +2644,7 @@ match)
;;
mktarball)
check_module_args mktarball
module_is_broken_and_die
module_is_added_or_die
make_tarball
;;
Expand Down
190 changes: 190 additions & 0 deletions run_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1747,4 +1747,194 @@ trap - EXIT
echo 'Checking that the environment is clean again'
check_no_dkms_test

############################################################################
### Testing 'broken' status ###
############################################################################

echo
echo 'Running BROKEN tests'
echo

echo 'Adding the test module by directory'
run_with_expected_output dkms add test/dkms_test-1.0 << EOF
Creating symlink /var/lib/dkms/dkms_test/1.0/source -> /usr/src/dkms_test-1.0
EOF

echo ' Removing symlink /var/lib/dkms/dkms_test/1.0/source'
rm /var/lib/dkms/dkms_test/1.0/source

echo 'Checking broken status'
run_with_expected_output dkms status dkms_test/1.0 << EOF
dkms_test/1.0: broken
Error! dkms_test/1.0: Missing the module source directory or the symbolic link pointing to it.
Manual intervention is required!
EOF

echo 'Re-adding the test module'
run_with_expected_output dkms add dkms_test/1.0 << EOF
Creating symlink /var/lib/dkms/dkms_test/1.0/source -> /usr/src/dkms_test-1.0
EOF

echo ' Removing symlink /var/lib/dkms/dkms_test/1.0/source'
rm /var/lib/dkms/dkms_test/1.0/source

echo 'Building broken test module (expected erorr)'
run_with_expected_error 4 dkms build dkms_test/1.0 << EOF
Error! dkms_test/1.0 is broken!
Missing the source directory or the symbolic link pointing to it.
Manual intervention is required!
EOF

echo 'Installing broken test module (expected erorr)'
run_with_expected_error 4 dkms install dkms_test/1.0 << EOF
Error! dkms_test/1.0 is broken!
Missing the source directory or the symbolic link pointing to it.
Manual intervention is required!
EOF

echo 'Unbuild broken test module (expected erorr)'
run_with_expected_error 4 dkms unbuild dkms_test/1.0 << EOF
Error! dkms_test/1.0 is broken!
Missing the source directory or the symbolic link pointing to it.
Manual intervention is required!
EOF

echo 'Uninstall broken test module (expected erorr)'
run_with_expected_error 4 dkms uninstall dkms_test/1.0 << EOF
Error! dkms_test/1.0 is broken!
Missing the source directory or the symbolic link pointing to it.
Manual intervention is required!
EOF

echo 'Adding the multiver test module 1.0 by directory'
run_with_expected_output dkms add test/dkms_multiver_test/1.0 << EOF
Creating symlink /var/lib/dkms/dkms_multiver_test/1.0/source -> /usr/src/dkms_multiver_test-1.0
EOF

echo 'Checking broken status'
run_with_expected_output dkms status << EOF
dkms_multiver_test/1.0: added
dkms_test/1.0: broken
Error! dkms_test/1.0: Missing the module source directory or the symbolic link pointing to it.
Manual intervention is required!
EOF

echo 'Remove broken test module (expected erorr)'
run_with_expected_error 4 dkms remove dkms_test/1.0 << EOF
Error! dkms_test/1.0 is broken!
Missing the source directory or the symbolic link pointing to it.
Manual intervention is required!
EOF

echo 'Re-adding the test module'
run_with_expected_output dkms add dkms_test/1.0 << EOF
Creating symlink /var/lib/dkms/dkms_test/1.0/source -> /usr/src/dkms_test-1.0
EOF

echo ' Removing source tree /usr/src/dkms_test-1.0/'
rm -rf /usr/src/dkms_test-1.0/

echo 'Checking broken status'
run_with_expected_output dkms status << EOF
dkms_multiver_test/1.0: added
dkms_test/1.0: broken
Error! dkms_test/1.0: Missing the module source directory or the symbolic link pointing to it.
Manual intervention is required!
EOF

echo 'Removing dkms_multiver_test'
dkms remove dkms_multiver_test/1.0 -k "${KERNEL_VER}" > /dev/null

echo 'Removing dkms_test'
rm -rf /var/lib/dkms/dkms_test/

echo 'Adding and building the test module by directory'
set_signing_message "dkms_test" "1.0"
run_with_expected_output dkms build test/dkms_test-1.0 -k "${KERNEL_VER}" << EOF
Creating symlink /var/lib/dkms/dkms_test/1.0/source -> /usr/src/dkms_test-1.0
Building module:
Cleaning build area...
Building module(s)...
${SIGNING_MESSAGE}Cleaning build area...
EOF

echo 'Adding and building the multiver test module 1.0 by directory'
set_signing_message "dkms_multiver_test" "1.0"
run_with_expected_output dkms build test/dkms_multiver_test/1.0 -k "${KERNEL_VER}" << EOF
Creating symlink /var/lib/dkms/dkms_multiver_test/1.0/source -> /usr/src/dkms_multiver_test-1.0
Building module:
Cleaning build area...
Building module(s)...
${SIGNING_MESSAGE}Cleaning build area...
EOF

echo ' Removing symlink /var/lib/dkms/dkms_multiver_test/1.0/source'
rm /var/lib/dkms/dkms_multiver_test/1.0/source

echo 'Adding and building the multiver test module 2.0 by directory'
set_signing_message "dkms_multiver_test" "2.0"
run_with_expected_output dkms build test/dkms_multiver_test/2.0 -k "${KERNEL_VER}" << EOF
Creating symlink /var/lib/dkms/dkms_multiver_test/2.0/source -> /usr/src/dkms_multiver_test-2.0
Building module:
Cleaning build area...
Building module(s)...
${SIGNING_MESSAGE}Cleaning build area...
EOF

echo 'Running dkms autoinstall'
run_with_expected_output dkms autoinstall -k "${KERNEL_VER}" << EOF
Error! dkms_multiver_test/1.0 is broken! Missing the source directory or the symbolic link pointing to it.
Manual intervention is required!
dkms_test.ko${mod_compression_ext}:
Running module version sanity check.
- Original module
- No original module exists within this kernel
- Installation
- Installing to /lib/modules/${KERNEL_VER}/${expected_dest_loc}/
depmod...
dkms autoinstall on ${KERNEL_VER}/${KERNEL_ARCH} succeeded for dkms_test
EOF
run_with_expected_output dkms status << EOF
dkms_multiver_test/1.0: broken
Error! dkms_multiver_test/1.0: Missing the module source directory or the symbolic link pointing to it.
Manual intervention is required!
dkms_multiver_test/2.0, ${KERNEL_VER}, ${KERNEL_ARCH}: built
dkms_test/1.0, ${KERNEL_VER}, ${KERNEL_ARCH}: installed
EOF

echo 'Removing all modules'
echo ' Removing the test module'
run_with_expected_output dkms remove dkms_test/1.0 -k "${KERNEL_VER}" << EOF
Module dkms_test-1.0 for kernel ${KERNEL_VER} (${KERNEL_ARCH}).
Before uninstall, this module version was ACTIVE on this kernel.
dkms_test.ko${mod_compression_ext}:
- Uninstallation
- Deleting from: /lib/modules/${KERNEL_VER}/${expected_dest_loc}/
- Original module
- No original module was found for this module on this kernel.
- Use the dkms install command to reinstall any previous module version.
Deleting module dkms_test-1.0 completely from the DKMS tree.
EOF

echo ' Removing the multi_ver_test 2.0 module'
run_with_expected_output dkms remove -m dkms_multiver_test -v 2.0 -k "${KERNEL_VER}" << EOF
Module dkms_multiver_test 2.0 is not installed for kernel ${KERNEL_VER} (${KERNEL_ARCH}). Skipping...
Deleting module dkms_multiver_test-2.0 completely from the DKMS tree.
EOF

echo ' Removing directories: /var/lib/dkms/dkms_test/ /var/lib/dkms/dkms_multiver_test /usr/src/dkms_test-1.0 /usr/src/dkms_multiver_test-?.0'
rm -rf /var/lib/dkms/dkms_test/ /var/lib/dkms/dkms_multiver_test /usr/src/dkms_test-1.0 /usr/src/dkms_multiver_test-?.0

echo 'Checking that the environment is clean again'
check_no_dkms_test

echo
echo 'End of BROKEN tests'
echo

echo 'All tests successful :)'

0 comments on commit 9d6c9ab

Please sign in to comment.