= Dracut Modules

== Writing modules

Some general rules for writing modules:

* Use one of the inst family of functions to actually install files
on to the initramfs.  They handle mangling the pathnames and (for binaries,
scripts, and kernel modules) installing dependencies as appropriate so
you do not have to.
* Scripts that end up on the initramfs should be POSIX compliant. dracut
will try to use /bin/dash as /bin/sh for the initramfs if it is available,
so you should install it on your system -- dash aims for strict POSIX
compliance to the extent possible.
* Hooks MUST be POSIX compliant -- they are sourced by the init script,
and having a bashism break your user's ability to boot really sucks.
* Generator modules should have a two digit numeric prefix in the range
of 50-59 -- they run in ascending sort order.
Anything in the 80-89 range is stuff that dracut
relies on, so try not to break those hooks.
* Hooks must have a .sh extension.
* Generator modules are described in more detail later on.
* We have some breakpoints for debugging your hooks.  If you pass `rdbreak`
as a kernel parameter, the initramfs will drop to a shell just before
switching to a new root. You can pass `rdbreak=hookpoint`, and the initramfs
will break just before hooks in that hookpoint run.

Also, there is an attempt to keep things as distribution-agnostic as
possible.  Every distribution has their own tool here and it's not
something which is really interesting to have separate across them.
So contributions to help decrease the distro-dependencies are welcome.

=== Module format

Most of the functionality that dracut implements are actually implemented by
dracut modules.  dracut modules live in `modules.d`, and have the following
structure:

----
dracut_install_dir/modules.d/
	00modname/
		module-setup.sh
		<other files as needed by the hook>
----

`00modname`::
The name of the module prefixed by a two-digit numeric sort code.
+
The numeric code must be present and in the range of 00 - 99.
+
NOTE: Range 00-09, 50-59 and 90-99 are reserved for out of tree
(3rd party) dracut modules.

It is strongly recommended to use the 50-59 range for out of tree
dracut modules. Range 90-99 are reserved for unusual
dracut customizations for completeness, but using range 90-99
is not recommended for out of tree dracut modules.

Not using the 50-59 range for out of tree dracut modules
will likely lead to unintended errors in the initramfs
generation process as your dracut module will either run too
early or too late in the generaiton process. You have been warned.
+
Modules with lower numbers are installed first.  This is important
because the dracut install functions (which install files onto
the initrd) refuse to overwrite already installed files. This makes
it easy for an earlier module to override the functionality of a
later module, so that you can have a distro or system specific
module override or modify the functionality of a generic module
without having to patch the more generic module.

`module-setup.sh`::
dracut sources this script to install the functionality that a
module implements onto the initrd.  For the most part, this amounts
to copying files from the host system onto the initrd in a controlled
manner.

==== `module-setup.sh` function API

`install()`::
This function of `module-setup.sh` is called to install all
non-kernel files.
+
dracut supplies several install functions that are specialized for different
file types.  Browse through `dracut-functions` for more details.
+
dracut also provides a `$moddir` variable if you
need to install a file from the module directory, such as an initrd
hook, a udev rule, or a specialized executable.

`installkernel()`::
This function of `module-setup.sh` is called to install all
kernel related files.

`check()`::
dracut calls this function to check and see if a module can be installed
on the initrd.
+
When called without options, check should check to make sure that
any files it needs to install into the initrd from the host system
are present.  It should exit with a `0` if they are, and a `1` if they are
not.
+
When called with `$hostonly` set, it should perform the same check
that it would without it set, and it should also check to see if the
functionality the module implements is being used on the host system.
+
For example, if this module handles installing support for LUKS
encrypted volumes, it should return `0` if all the tools to handle
encrypted volumes are available and the host system has the root
partition on an encrypted volume, `1` otherwise.

`depends()`::
This function should output a list of dracut modules
that it relies upon.
+
An example would be the nfs and iscsi modules, which rely on the network module
to detect and configure network interfaces.

Any other files in the module will not be touched by dracut directly.

You are encouraged to provide a `README` that describes what the module is for.

== Hooks

Dracut init looks for custom hook scripts in the following locations
(`HOOKDIR` below): `/var/lib/dracut/hooks`, `/etc/dracut/hooks`, and
`/usr/lib/dracut/hooks`. The intended use of these locations is: standard,
distribution shipped scripts are put to `/usr/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

`HOOKDIR/pre-udev/*.sh`::
scripts to run before udev is started

`HOOKDIR/pre-trigger/*.sh`::
scripts to run before the main udev trigger is pulled

`HOOKDIR/initqueue/*.sh`::
runs in parallel to the udev trigger
+
Udev events can add scripts here with `/sbin/initqueue`.
+
If `/sbin/initqueue` is called with the `--onetime` option, the script
will be removed after it was run.
+
If `/var/lib/dracut/hooks/initqueue/work` is created then
this loop can process the jobs in parallel to the udevtrigger.
+
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.
+
Scripts can remove themselves from the initqueue by `rm $job`.

`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.

`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.

`HOOKDIR/pre-pivot/*.sh`::
scripts to run before latter initramfs cleanups

`HOOKDIR/cleanup/*.sh`::
scripts to run before the real init is executed and the initramfs
disappears
+
All processes started before should be killed here.

