Arch Linux pacman hooks: automate initramfs rebuilds without cron
Pacman hooks run maintenance exactly when package files change. Here is a local initramfs hook example, the checks that matter, and the failure modes to avoid.
07 Sept 2026, 14:58 UTC

If you maintain a custom kernel, an out-of-tree driver, or a firmware bundle that must be inside the initramfs, the usual automation instinct is a cron job or a filesystem watcher. Both react to the wrong event: a file changed on disk. Arch Linux pacman already knows when package-owned files enter, leave, or change during a transaction. A libalpm hook lets you run one small action at that exact point.
Thesis: keep transaction-aware maintenance in /etc/pacman.d/hooks/, make the action idempotent, and use absolute paths. Hooks are not a scheduler; they are a package-aware post-step.
Assume a current Arch Linux install with pacman/libalpm hook support. Verify quickly with pacman -V and by confirming /usr/share/libalpm/hooks/ exists. No version number is assumed here.
What a hook matches, and what it can run
A hook is an INI-style file. The [Trigger] section decides when it fires. The [Action] section decides what runs.
| Field | Meaning | Practical note |
|---|---|---|
Type | File or Path | File triggers match package-owned file paths; Path triggers are path-oriented. Confirm exact semantics in man alpm-hooks before using a new type. |
Operation | Install, Upgrade, Remove | List every operation that should cause the action. A kernel upgrade usually needs Install and Upgrade. |
Target | Path or package identity | For file triggers, use the root-relative path as it appears in package metadata, with globs if needed. |
When | Transaction timing | PostTransaction is the safe default for rebuilds because the new files are already in place. |
Exec | Command to run | Absolute path only. The environment is sanitized, so $PATH, aliases, shell functions, and interactive prompts are not available. |
Because hooks run inside the pacman process, they can modify system state after a specific package change without a separate systemd unit or cron entry. They also avoid the race in a filesystem watcher: the trigger is the package database transaction, not an arbitrary write.
Worked example: rebuild an initramfs after a kernel image change
First check whether a package already does this. Run in a normal shell:
grep -R "mkinitcpio" /usr/share/libalpm/hooks/ /etc/pacman.d/hooks/ 2>/dev/null
If an existing hook already rebuilds your preset, do not add a duplicate. If you maintain a custom kernel package or a preset that is not covered, continue.
Confirm the exact package-owned path you will trigger on. Run without root:
pacman -Ql linux | grep -E "vmlinuz|modules/"
Use the real path from that output in the hook. The example below assumes the kernel image is a package-owned file under usr/lib/modules/*/vmlinuz; adjust the glob if your package differs.
Create the local hook as root. This changes system state:
sudo tee /etc/pacman.d/hooks/99-local-kernel-initramfs.hook >/dev/null <<'EOF'
[Trigger]
Type = File
Operation = Install
Operation = Upgrade
Target = usr/lib/modules/*/vmlinuz
[Action]
Description = Rebuild local initramfs after kernel image change
When = PostTransaction
Exec = /usr/bin/mkinitcpio -p linux
EOF
sudo chmod 0644 /etc/pacman.d/hooks/99-local-kernel-initramfs.hook
Replace linux with your mkinitcpio preset name if it is not linux. If you need every preset rebuilt, /usr/bin/mkinitcpio -P is broader and slower; prefer the specific preset when you can.
To exercise it, run a normal upgrade as root:
sudo pacman -Syu linux
For a no-version-change test, an explicit reinstall such as sudo pacman -S linux is the usual path, but confirm pacman actually starts a transaction before treating a no-op as a hook failure.
Check the result by looking at the generated image for your preset, not by trusting the hook file:
stat -c '%y %n' /boot/initramfs-linux.img
The timestamp should be newer than the start of the pacman transaction, and mkinitcpio progress should appear in the transaction output. If it does not, compare the hook Target with pacman -Ql output: file triggers only match package-owned files, so a trigger on a generated path such as /boot/initramfs-linux.img may never fire.
Trade-offs and failure modes
- A failing hook can abort the transaction. Treat non-zero exits as fatal unless you have confirmed otherwise for your pacman version. Keep
Execcommands idempotent and make expected error paths return 0 only when success is real. - The environment is minimal. Use absolute paths for the binary and every file it touches. Do not depend on the calling shell,
$HOME, locale, or an interactive prompt. - Location matters. Hooks under
/usr/share/libalpm/hooks/are package-owned and may be replaced on upgrade. Local customizations belong in/etc/pacman.d/hooks/. - Broad triggers cost time. Matching large globs such as everything under
usr/bincan fire often and slow transactions. Target the package-owned file that actually implies the rebuild. - Hooks are synchronous. A long mkinitcpio run blocks the rest of the transaction. If the rebuild is expensive, that is a real cost during upgrades.
If you add multiple hooks, use the hook dependency fields documented in man alpm-hooks rather than assuming filename order. Do not infer behavior from systemd unit syntax.
Rollback and integrity check
Removing the hook stops future triggers but does not undo an initramfs already generated:
sudo rm /etc/pacman.d/hooks/99-local-kernel-initramfs.hook
Do not delete generated boot images as a rollback. If a boot entry is broken, regenerate with mkinitcpio or boot a known-good entry.
As a package-integrity check, run as root:
sudo pacman -Qkk
If this flags files after your hook runs, the hook is probably writing into package-owned paths. Fix the target or output location instead of ignoring the warning.
Actionable close
- Check for an existing mkinitcpio hook before adding one.
- Trigger on a package-owned path verified with
pacman -Ql. - Use
PostTransaction, absolute paths, and the narrowest preset rebuild that solves the problem. - Verify by timestamp and transaction output, then remove the hook if it is redundant.
That keeps automation tied to the package database, where Arch already has the exact information you need.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.