Skip to Content

Automatically archive the modules of the currently running kernel on upgrade on Arch Linux

I don’t reboot my laptop very often. My current uptime is 11 days; that’s quite low, I’m pretty sure the previous one was at least a month. Yet I often upgrade my system with pacman -Syu (or more precisely yay -Syu). As a consequence, I’m often running a kernel that is older that the one that is currently installed:

~ % uname -sr
Linux 4.20.13-arch1-1-ARCH
~ % pacman -Qi linux | grep Version
Version                  : 5.0.1.arch1-1

This is usually fine, except when I plug a new device (for example a USB stick or a memory card) that is handled by a kernel module that hasn’t been loaded yet. Since the current kernel and its modules are not available anymore, the device doesn’t work… And I don’t want to reboot just for that.

I found a simple solution using Pacman hooks. The idea is to create a new hook that runs when the linux package (or any linux-* package) is upgraded or removed, and that will archive the corresponding modules as a tarball. This way I can easily extract the tarball and replug my device to have the running kernel autoload the needed module if needed.

This hook needs 2 files:

  • the hook file used by pacman to decide if and when the hook command must be run;
  • the actual hook command: a shell script that handles archiving the modules directory.

The hook file installed as /etc/pacman.d/hooks/keep_kernel_modules.hook:

[Trigger]
Operation = Upgrade
Operation = Remove
Type = Package
Target = linux
Target = linux-*

[Action]
Description = Archive the modules of the currently running kernel
When = PreTransaction
Exec = /usr/local/bin/keep_kernel_modules.sh

And the shell script is installed as /usr/local/bin/keep_kernel_modules.sh:

#!/usr/bin/env bash

. /usr/share/makepkg/util/message.sh

VERSION=$(uname -r)

if [[ -z "${VERSION}" ]]; then
    error "Could not get the running kernel version number"
    exit 1
elif [[ -s "/usr/lib/modules/backup_${VERSION}.tar.gz" ]]; then
    warning "/usr/lib/modules/backup_${VERSION}.tar.gz already exists: skipping"
elif [[ -d "/usr/lib/modules/${VERSION}" ]]; then
    msg "Creating /usr/lib/modules/backup_${VERSION}.tar.gz"
    cd /usr/lib/modules
    tar czf "backup_${VERSION}.tar.gz" "${VERSION}"
    msg "Removing other backups"
    find . -\( -type f -and -name 'backup_*.tar.gz' \
         -and -not -name "backup_${VERSION}.tar.gz" -\) \
         -delete
else
    warning "/usr/lib/modules/${VERSION} doesn't exist: skipping"
fi

I’ve been running this for 3 years now without any issue.