]> git.ipfire.org Git - thirdparty/dracut-ng.git/commitdiff
feat(dracut): introduce additional hooks locations
authorVitaly Kuznetsov <vkuznets@redhat.com>
Mon, 6 Oct 2025 14:54:46 +0000 (16:54 +0200)
committerNeal Gompa (ニール・ゴンパ) <ngompa13@gmail.com>
Wed, 4 Feb 2026 16:55:21 +0000 (11:55 -0500)
Dracut init supports running custom hooks which are placed to
/var/lib/dracut/hooks/. The location was previously changed to /var
as the place needs to be writeable as some hooks are created and removed
in runtime. The current location, however, may come inconvenient in some
scenarios when the user wants to extend initramfs with custom scripts. In
particular, systemd allows extending initrd with 'sysext' and 'confext'
mechanism. This comes handy for extending e.g. UKI's initramfs without
the need to rebuild (and re-sign) the UKI. The problem is that 'sysext' can
only be used to extend /usr and /opt and 'confext/ can only extend /etc.
Both services make the location read-only and thus can't be used for the
main dracut hooks location even if we move it somewhere.

Add additional locations where users can put dracut hooks:
- /lib/dracut/hooks -- this location is supposed to be used for
  distro-specific static hooks.
- /etc/dracut/hooks -- this location can be used by users for locally
  created hooks.
- /var/lib/dracut/hooks -- the default location which is supposed to be
  used by dracut modules. This location is always writeable so modules
  can place and remove hooks from there in runtime. The existing '$hookdir'
  variable keeps pointing at this place.

Dracut also has support for /var/lib/dracut/hooks/initqueue/work flag and
in theory, it does not have to be in the hooks directory as it is not a
hook. The location, however, is documented and it is not entirely clear
if it would make sense to add support for /lib/dracut/hooks/initqueue/work
and /etc/dracut/hooks/initqueue/work as well: these locations can (and
probably should) be read-only so creating/removing flag there is hard. Keep
the status quo and only support '$hookdir/initqueue/work' for now.

Closes: https://github.com/dracut-ng/dracut-ng/issues/1618
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
12 files changed:
doc_site/modules/ROOT/pages/developer/modules.adoc
dracut.sh
man/dracut.modules.7.adoc
modules.d/77dracut-systemd/dracut-cmdline.service
modules.d/77dracut-systemd/dracut-mount.service
modules.d/77dracut-systemd/dracut-pre-mount.service
modules.d/77dracut-systemd/dracut-pre-pivot.service
modules.d/77dracut-systemd/dracut-pre-trigger.service
modules.d/77dracut-systemd/dracut-pre-udev.service
modules.d/80base/dracut-lib.sh
modules.d/80base/module-setup.sh
modules.d/86shutdown/module-setup.sh

index 54e21967a552fa6b1b144b17a04b440ddacde40e..f5637c3361a6f705790505746a4a619506ea5688 100644 (file)
@@ -123,18 +123,25 @@ You are encouraged to provide a `README` that describes what the module is for.
 
 == Hooks
 
-init has the following hook points to inject scripts:
-
-`/var/lib/dracut/hooks/cmdline/*.sh`::
+Dracut init looks for custom hook scripts in the following locations
+(`HOOKDIR` below): `/var/lib/dracut/hooks`, `/etc/dracut/hooks`, and
+`/lib/dracut/hooks`. The intended use of these locations is: standard,
+distribution shipped scripts are put to `/lib/dracut/hooks`;
+`/etc/dracut/hooks` is used as a local override; dracut modules create
+(and remove) scripts in runtime in `/var/lib/dracut/hooks` (and `$hookdir`
+variable is provided). The following hook points to inject scripts are
+currently supported:
+
+`HOOKDIR/cmdline/*.sh`::
 scripts for command line parsing
 
-`/var/lib/dracut/hooks/pre-udev/*.sh`::
+`HOOKDIR/pre-udev/*.sh`::
 scripts to run before udev is started
 
-`/var/lib/dracut/hooks/pre-trigger/*.sh`::
+`HOOKDIR/pre-trigger/*.sh`::
 scripts to run before the main udev trigger is pulled
 
-`/var/lib/dracut/hooks/initqueue/*.sh`::
+`HOOKDIR/initqueue/*.sh`::
 runs in parallel to the udev trigger
 +
 Udev events can add scripts here with `/sbin/initqueue`.
@@ -151,23 +158,23 @@ a timeout.
 +
 Scripts can remove themselves from the initqueue by `rm $job`.
 
-`/var/lib/dracut/hooks/pre-mount/*.sh`::
+`HOOKDIR/pre-mount/*.sh`::
 scripts to run before the root filesystem is mounted
 +
 Network filesystems like NFS that do not use device files are an
 exception. Root can be mounted already at this point.
 
-`/var/lib/dracut/hooks/mount/*.sh`::
+`HOOKDIR/mount/*.sh`::
 scripts to mount the root filesystem
 +
 If the udev queue is empty and no root device is found or no root
 filesystem was mounted, the user will be dropped to a shell after
 a timeout.
 
-`/var/lib/dracut/hooks/pre-pivot/*.sh`::
+`HOOKDIR/pre-pivot/*.sh`::
 scripts to run before latter initramfs cleanups
 
-`/var/lib/dracut/hooks/cleanup/*.sh`::
+`HOOKDIR/cleanup/*.sh`::
 scripts to run before the real init is executed and the initramfs
 disappears
 +
index 6a1963b9d2e057db4e6aa79883a26ee38823b5ef..e1aafac7b10848d819d3106a807da4909ef920d2 100755 (executable)
--- a/dracut.sh
+++ b/dracut.sh
@@ -1994,11 +1994,13 @@ dracut_kernel_post() {
 }
 
 if [[ "$(ln --help)" == *--relative* ]]; then
+    # shellcheck disable=SC2329
     ln_r() {
         local dstdir="${dstdir:-"$initdir"}"
         ln -sfnr "${dstdir}/$1" "${dstdir}/$2"
     }
 else
+    # shellcheck disable=SC2329
     ln_r() {
         local dstdir="${dstdir:-"$initdir"}"
         local _source=$1
@@ -2701,9 +2703,6 @@ if [[ $kernel_only != yes ]]; then
     # shellcheck disable=SC2068
     ((${#install_optional_items[@]} > 0)) && inst_multiple -o ${install_optional_items[@]}
 
-    # symlink to old hooks location for compatibility
-    ln_r /var/lib/dracut/hooks /lib/dracut/hooks
-
     for _d in $hookdirs; do
         # shellcheck disable=SC2174
         mkdir -m 0755 -p "${initdir}/var/lib/dracut/hooks/$_d"
index 62aaca5c6d22e87406357087ab1972528fb8c550..af5fc03934191d4c74f70234b3ae8b4ae838fae2 100644 (file)
@@ -47,6 +47,17 @@ These hooks are plain directories containing shell scripts ending with ".sh",
 which are sourced by init.
 Common used functions are in _dracut-lib.sh_, which can be sourced by any script.
 
+dracut looks for custom hook scripts in subdirectories (cmdline, pre-udev,
+pre-trigger, initqueue, pre-mount, mount, pre-pivot, cleanup) of the following
+locations:  _/var/lib/dracut/hooks_, _/etc/dracut/hooks_, and
+_/lib/dracut/hooks_. The intended use of these locations is: standard,
+distribution shipped scripts are put to _/lib/dracut/hooks_; _/etc/dracut/hooks_
+is used as a local override; dracut modules create (and remove) scripts in
+runtime in _/var/lib/dracut/hooks_. If a hook with the same name exists in
+multiple locations simultaneously, the most privileged location
+(_/var/lib/dracut/hooks_, then _/etc/dracut/hooks_, and then
+_/lib/dracut/hooks_) wins and only one instance of the hook is executed.
+
 === Hook: cmdline
 
 The _cmdline_ hook is a place to insert scripts to parse the kernel command line
index d4fbc695a519c688dae5c18d291d7494690115dd..d991619e8f55f8019d90dda7678f7dddd572aa34 100644 (file)
@@ -10,6 +10,8 @@ Wants=systemd-journald.socket
 ConditionPathExists=/usr/lib/initrd-release
 ConditionPathExistsGlob=|/etc/cmdline.d/*.conf
 ConditionDirectoryNotEmpty=|/var/lib/dracut/hooks/cmdline
+ConditionDirectoryNotEmpty=|/etc/dracut/hooks/cmdline
+ConditionDirectoryNotEmpty=|/lib/dracut/hooks/cmdline
 ConditionKernelCommandLine=|rd.break=cmdline
 Conflicts=shutdown.target emergency.target
 
index 884c699bf630730af56e266b4f7fa5a1815c902c..dd5e2cb212814f3512309ed7ac59b41e973c46b7 100644 (file)
@@ -7,6 +7,8 @@ After=initrd-root-fs.target initrd-parse-etc.service
 After=dracut-initqueue.service dracut-pre-mount.service
 ConditionPathExists=/usr/lib/initrd-release
 ConditionDirectoryNotEmpty=|/var/lib/dracut/hooks/mount
+ConditionDirectoryNotEmpty=|/etc/dracut/hooks/mount
+ConditionDirectoryNotEmpty=|/lib/dracut/hooks/mount
 ConditionKernelCommandLine=|rd.break=mount
 DefaultDependencies=no
 Conflicts=shutdown.target emergency.target
index 0e19cac0372cfc3be15e00150b082f13686494e2..3c76ff5e68f9728708f450c53fe8efbbacb4def4 100644 (file)
@@ -8,6 +8,8 @@ Before=initrd-root-fs.target sysroot.mount systemd-fsck-root.service
 After=dracut-initqueue.service cryptsetup.target
 ConditionPathExists=/usr/lib/initrd-release
 ConditionDirectoryNotEmpty=|/var/lib/dracut/hooks/pre-mount
+ConditionDirectoryNotEmpty=|/etc/dracut/hooks/pre-mount
+ConditionDirectoryNotEmpty=|/lib/dracut/hooks/pre-mount
 ConditionKernelCommandLine=|rd.break=pre-mount
 Conflicts=shutdown.target emergency.target
 
index 6c786341e9dc958cf508ebf9bd318d453f6d54d7..8194ee254e140da4095b1623359ca851786d5261 100644 (file)
@@ -11,7 +11,11 @@ Wants=remote-fs.target
 After=remote-fs.target
 ConditionPathExists=/usr/lib/initrd-release
 ConditionDirectoryNotEmpty=|/var/lib/dracut/hooks/pre-pivot
+ConditionDirectoryNotEmpty=|/etc/dracut/hooks/pre-pivot
+ConditionDirectoryNotEmpty=|/lib/dracut/hooks/pre-pivot
 ConditionDirectoryNotEmpty=|/var/lib/dracut/hooks/cleanup
+ConditionDirectoryNotEmpty=|/etc/dracut/hooks/cleanup
+ConditionDirectoryNotEmpty=|/lib/dracut/hooks/cleanup
 ConditionKernelCommandLine=|rd.break=pre-pivot
 ConditionKernelCommandLine=|rd.break=cleanup
 ConditionKernelCommandLine=|rd.break
index 555fcefb33d34ff9f0565e46a7bd4f2e710b40c3..b99837b31f838029f5f84a5cf199ee28d4bd5210 100644 (file)
@@ -9,6 +9,8 @@ After=dracut-pre-udev.service systemd-udevd.service systemd-tmpfiles-setup-dev.s
 Wants=dracut-pre-udev.service systemd-udevd.service
 ConditionPathExists=/usr/lib/initrd-release
 ConditionDirectoryNotEmpty=|/var/lib/dracut/hooks/pre-trigger
+ConditionDirectoryNotEmpty=|/etc/dracut/hooks/pre-trigger
+ConditionDirectoryNotEmpty=|/lib/dracut/hooks/pre-trigger
 ConditionKernelCommandLine=|rd.break=pre-trigger
 Conflicts=shutdown.target emergency.target
 
index f3c10214a97e226ce0a0c2d81af1bcdc9401b8d5..8a803697ca3738a299fd7205fb8931e2b07b7b3a 100644 (file)
@@ -9,6 +9,8 @@ After=dracut-cmdline.service
 Wants=dracut-cmdline.service
 ConditionPathExists=/usr/lib/initrd-release
 ConditionDirectoryNotEmpty=|/var/lib/dracut/hooks/pre-udev
+ConditionDirectoryNotEmpty=|/etc/dracut/hooks/pre-udev
+ConditionDirectoryNotEmpty=|/lib/dracut/hooks/pre-udev
 ConditionKernelCommandLine=|rd.break=pre-udev
 ConditionKernelCommandLine=|rd.driver.blacklist
 ConditionKernelCommandLine=|rd.driver.pre
index 851090a48313d4332caed8501f65acc9bd1029d4..2710347bf82f184163f57918a002ed10d2e74926 100755 (executable)
@@ -373,8 +373,19 @@ list_hooks() {
     [ -z "$pattern" ] && pattern="*.sh"
     local hook
 
-    for hook in "$hookdir/$dir/"$pattern; do
-           [ -f "$hook" ] && echo "$hook"
+    # It is allowed to override hooks by creating a file with the same name
+    # in a directory which has higher priority. '/var/lib/dracut/hooks' gets top
+    # priority, '/etc/dracut/hooks' comes after and '/lib/dracut/hooks' is the
+    # least priviliged location.
+    for hook in "/var/lib/dracut/hooks/$dir/"$pattern; do
+        [ -f "$hook" ] && echo "$hook"
+    done
+    for hook in "/etc/dracut/hooks/$dir/"$pattern; do
+        [ -f "$hook" ] && [ ! -f "/var/lib/dracut/hooks/$dir/${hook##*/}" ] && echo "$hook"
+    done
+    for hook in "/lib/dracut/hooks/$dir/"$pattern; do
+        [ -f "$hook" ] && [ ! -f "/var/lib/dracut/hooks/$dir/${hook##*/}" ] \
+            && [ ! -f "/etc/dracut/hooks/$dir/${hook##*/}" ] && echo "$hook"
     done
 }
 
index 91797d858972eed20b8eb61c1012f2fcfaac0e22..dfe81ec3a32fd197611ffd4ceca368b2b80f8288 100755 (executable)
@@ -88,9 +88,6 @@ install() {
     mkdir -m 0755 -p "${initdir}"/lib/dracut
     mkdir -m 0755 -p "${initdir}"/var/lib/dracut/hooks
 
-    # symlink to old hooks location for compatibility
-    ln_r /var/lib/dracut/hooks /lib/dracut/hooks
-
     mkdir -p "${initdir}"/tmp
 
     inst_simple "$moddir/dracut-lib.sh" "/lib/dracut-lib.sh"
index d9ce47328b804f0fc65c57377f755283e1640b4d..846cf7e7cace8b16c0cee1f7a10459763b4f6419 100755 (executable)
@@ -14,9 +14,6 @@ install() {
     inst "$moddir/shutdown.sh" "$prefix/shutdown"
     mkdir -m 0755 -p "${initdir}"/var/lib/dracut/hooks
 
-    # symlink to old hooks location for compatibility
-    ln_r /var/lib/dracut/hooks /lib/dracut/hooks
-
     for _d in $hookdirs shutdown shutdown-emergency; do
         mkdir -m 0755 -p "${initdir}"/var/lib/dracut/hooks/"$_d"
     done