DDISKIT(1)
π ddiskit β Red Hat tool for Driver Update Disk creation π
okay bestie, welcome to ddiskit(1) π this is a General Commands Manual page and honestly? it's giving "power tool that runs the whole DUD pipeline." let's get into it.
πΈ NAME πΈ
ddiskit β the Red Hat tool for making Driver Update Disks π
β¨ SYNOPSIS β¨
ddiskit [-h] [-vvv] [-qQ] [-p PROFILE] [-R RES_DIR] [-T TEMPLATE_DIR]
[-P PROFILE_DIR] [-d] [-o DUMP_CONFIG_NAME] [-C KEY=VALUE]...
ACTION [ACTION_OPTIONS]...
π DESCRIPTION π
so ddiskit β pronounced dee-dis-kit, yes really, that's the vibe β helps you and simplifies the creation of (back-ported) out-of-tree kernel module RPMs and the Driver Update Disks that contain them. slay. π«
these RPMs and DUDs are considered suitable for using with distributions based on Red Hat Enterprise Linux. this version of ddiskit supports RHEL 7 and is backward-compatible with RHEL 6. no cap.
ddiskit assumes a certain workflow, and that whole thing is described in the USAGE EXAMPLE section. it's tailored to the process used for developing and releasing Driver Update Disks, and β while it totally can be used for creating driver packages for RHEL-based distributions in general β it's also worth considering other tools for a similar purpose, like dkms(8) or akmods(1). just saying. π
π₯ OPTIONS π₯
please refer to the Configuration generation section for the description of the "configuration option name" and "default value" fields, and to the ACTIONS section for the description of the actions mentioned here. iykyk π«Ά
π General options π
-h,--helpβ print a list of options.ddiskitwill exit after this action and just straight-up ignore the rest of the command line. bye π-v,--verbosityβ bump output verbosity by 1.- a value of
1means verbose output (it toggles printing of most of executed commands and all warnings), and a value of2is the debugging era (it enables printing of all the executed commands output, actions, and messages). a value of3further increases output verbosity of issuedrpm(1)commands. π’ - Configuration option name:
defaults.verbosity - Default value:
0
- a value of
-pPROFILE,--profilePROFILE β the configuration profile to use. please refer to the Configuration generation section for the extra info about profiles. π- Configuration option name:
defaults.profile - Default value: none;
"default"is provided in package configuration
- Configuration option name:
-RRES_DIR,--res-dirRES_DIR β resources directory. used as a base of evaluation for template and profile directory paths.- Configuration option name:
defaults.res_dir - Default value: none;
"/usr/share/ddiskit/"is a hard-coded default
- Configuration option name:
-TTEMPLATE_DIR,--template-dirTEMPLATE_DIR β templates directory, used as a base for searching for spec or module configuration templates. please refer to the File path evaluation section for the info regarding template file path resolution. ποΈ- Configuration option name:
defaults.template_dir - Default value: none;
"{res_dir}/templates"is a hard-coded default
- Configuration option name:
-PPROFILE_DIR,--profile-dirPROFILE_DIR β profiles directory, used as a base for searching for profiles. please refer to the File path evaluation section for the info regarding profile file path resolution.- Configuration option name:
defaults.profile_dir - Default value: none;
"{res_dir}/profiles"is a hard-coded default
- Configuration option name:
-d,--dump-configβ dump the derived configuration after performing the action. π€- Configuration option name:
defaults.dump_config - Default value:
False
- Configuration option name:
-oDUMP_CONFIG_NAME,--dump-config-nameDUMP_CONFIG_NAME β path to the file targeted for the configuration dump.- Configuration option name:
defaults.dump_config_name - Default value: none;
"{config}.generated"is a hard-coded default
- Configuration option name:
-q,--quilt-enableβ enable quilt support. please refer to the QUILT INTEGRATION section for the info regarding quilt integration. this option sets thedefaults.quilt_supportconfiguration option toTrue. π§΅-Q,--quilt-disableβ disable quilt support. this option sets thedefaults.quilt_supportconfiguration option toFalse.-CKEY=VALUE,--config-optionKEY=VALUE β override an arbitrary configuration option that has the name KEY with VALUE. the KEY should follow the{[section_name.]key_name}syntax, and thedefaultssection is assumed in case thesection_namepart is omitted. this argument can be used multiple times in order to override multiple options. π- Configuration option name: (n/a)
- Default value: (n/a)
π§ Options for prepare_sources action π§
-cCONFIG,--configCONFIG β path to the module configuration file.- Configuration option name:
defaults.config - Default value:
"module.config"
- Configuration option name:
-tCONFIG_TEMPLATE,--config-templateCONFIG_TEMPLATE β configuration file template. please refer to the File path evaluation section for the info regarding configuration template file path resolution.- Configuration option name:
defaults.config_template - Default value: none;
"config"is a hard-coded default
- Configuration option name:
-gGIT_DIRECTORY,--git-dirGIT_DIRECTORY β path to the.gitdirectory containing the repository from where source files should be checked out. πΏ- Configuration option name:
defaults.git_dir - Default value: none
- Configuration option name:
-rREVISION,--git-revisionREVISION β revision specification at which source files should be checked out from the repository.- Configuration option name:
defaults.git_revision - Default value:
"HEAD"
- Configuration option name:
-dDIRECTORIES,--git-src-directoryDIRECTORIES β whitespace-separated list of paths which should be checked out from the repository.- Configuration option name:
defaults.git_src_directory - Default value: none
- Configuration option name:
-MMAJOR,--majorMAJOR β major version number of the distribution the package is built for (for example,"7"for RHEL 7.3).- Configuration option name:
defaults.major - Default value:
7
- Configuration option name:
-mMINOR,--minorMINOR β minor version number of the distribution the package is built for (for example,"3"for RHEL 7.3).- Configuration option name:
defaults.minor - Default value:
0
- Configuration option name:
π Options for generate_spec action π
-cCONFIG,--configCONFIG β path to the module configuration file.- Configuration option name:
defaults.config - Default value:
"module.config"
- Configuration option name:
-tSPEC_TEMPLATE,--spec-templateSPEC_TEMPLATE β RPM spec file template. please refer to the File path evaluation section for the info regarding RPM spec template file path resolution. π- Configuration option name:
defaults.spec_template - Default value: none;
"spec"is a hard-coded default
- Configuration option name:
π¦ Options for build_rpm action π¦
-cCONFIG,--configCONFIG β path to the module configuration file.- Configuration option name:
defaults.config - Default value:
"module.config"
- Configuration option name:
-a,--tar-allβ tar all files, including hidden ones (files with names starting with a dot). otherwise, only files with names starting with a non-dot character will be added to the source tarball. this option sets the value of the relevant configuration parameter toTrue.- > heads up bestie: this check is independent from the check controlled by the
defaults.tar_strictconfiguration parameter. - Configuration option name:
defaults.tar_all - Default value:
False
- > heads up bestie: this check is independent from the check controlled by the
-e,--tar-strictβ tar only expected files. only the files with names matching the regular expression pattern provided in thedefaults.src_patternsconfiguration option will be added to the source tarball. this option sets the value of the relevant configuration parameter toTrue.- > and again: this check is independent from the check controlled by the
defaults.tar_allconfiguration parameter. - Configuration option name:
defaults.tar_strict - Default value:
False
- > and again: this check is independent from the check controlled by the
-s,--srpmβ force building of a source RPM instead of a binary one.ddiskithas several heuristics (whether the host architecture is among the architectures targeted by the module, whether the RPM build check passes) that detect the possibility of a binary RPM build, and it falls back to building a source RPM only in case they indicated that a binary RPM build is impossible; however, you can force building of a source RPM instead of a binary one with this switch. this option sets the value of the relevant configuration parameter toTrue. ποΈ- Configuration option name:
defaults.srpm - Default value:
False
- Configuration option name:
-m,--mockβ enablemock(1)usage for building the RPM. see the MOCK SUPPORT section for additional information.- Configuration option name:
defaults.mock - Default value:
False
- Configuration option name:
-rMOCK_CONFIG,--mock-configMOCK_CONFIG β which mock configuration should be used for building the RPM.- Configuration option name:
defaults.mock_config - Default value:
"default"
- Configuration option name:
-l,--mock-offlineβ whether to pass--offlineoption tomock.- Configuration option name:
defaults.mock_offline - Default value:
False
- Configuration option name:
-OMOCK_OPTIONS,--mock-optsMOCK_OPTIONS β additional options that have to be passed to mock invocations. shell quoting is supported. overwrites options set by previous-Oand/or-Aoptions. β οΈ- Configuration option name:
defaults.mock_opts - Default value: none
- Configuration option name:
-AMOCK_OPTIONS,--mock-opts-appendMOCK_OPTIONS β additional options that have to be passed to mock invocations. shell quoting is supported. appends options to the options set by previous-Oand/or-Aoptions. π§·- Configuration option name:
defaults.mock_opts - Default value: none
- Configuration option name:
-gLEVEL,--check-git-srcLEVEL β set the level of source code repository authenticity check. see the SOURCE CODE VERIFICATION section for the details. π- Configuration option name:
defaults.check_get_src - Default value:
0
- Configuration option name:
-G,--generate-spec-on-buildβ call thegenerate_specaction at the beginning of thebuild_rpmaction execution. this saves you from calling thegenerate_specaction separately every single time the module configuration or patch list are changed (assuming the spec file doesn't need manual changes after generation). time-saver era β¨- Configuration option name:
defaults.generate_spec_on_build - Default value:
0
- Configuration option name:
πΈ Options for build_iso action πΈ
-cCONFIG,--configCONFIG β path to the module configuration file.- Configuration option name:
defaults.config - Default value:
"module.config"
- Configuration option name:
-iISOFILE,--isofileISOFILE β file name for the output ISO. πΏ- Configuration option name:
defaults.isofile- Default value: none β and bestie, go peek at the
build_isoaction description section for the whole story π
- Default value: none β and bestie, go peek at the
Options for dump_config action ποΈ
-c CONFIG,--config CONFIGβ where your module configuration file lives, path-style.- Configuration option name:
defaults.config - Default value:
"module.config"
- Configuration option name:
-o DUMP_CONFIG_NAME,--dump-config-name DUMP_CONFIG_NAMEβ the name of the file where the configuration dump gets stored. Heads up: this is literally the same option as the-oin the General options section, it's just hanging out here too for convenience π- Configuration option name:
defaults.dump_config_name - Default value: none β but
"{config}.generated"is a hard-coded default, so that's what you get if you say nothing.
- Configuration option name:
Options for update_kabi action π§¬
-c CONFIG,--config CONFIGβ path to the module configuration file.- Configuration option name:
defaults.config - Default value:
"module.config"
- Configuration option name:
-g GIT_DIRECTORY,--git-dir GIT_DIRECTORYβ path to the.gitdirectory holding the repository that source files get checked out from.- Configuration option name:
defaults.git_dir - Default value: none
- Configuration option name:
-d KABI_DIRECTORY,--kabi-dest-dir KABI_DIRECTORYβ path to the kABI symbol information files directory inside the kernel source tree that's supposed to get updated.- Configuration option name:
defaults.kabi_dest_dir - Default value: none
- Configuration option name:
-e,--extract-kmodβ pull the kmods out of RPMs and use their modversion data instead of the RPM"Requires"tags. This one flipsdefaults.kabi_use_rpm_kotoTrue.-E,--no-extract-kmodβ do NOT extract kmods from RPM, just use whatever the"Requires"tags give you. This flipsdefaults.kabi_use_rpm_kotoFalse.-o,--overwriteβ overwrite the kABI symbol information files that already exist. This setsdefaults.kabi_files_overwriteto2.-O,--no-overwriteβ leave the existing kABI symbol information files alone. This setsdefaults.kabi_files_overwriteto0.-i,--overwrite-interactiveβ whenever there's a possibility of overwriting an existing kABI symbol information file, it asks you first. This setsdefaults.kabi_files_overwriteto1.-t,--commitβ on success, actually create a git commit with the affected kABI symbol files. This setsdefaults.kabi_committoTrue.-n,--no-commitβ on success, do NOT create a git commit with the affected kABI symbol files. This setsdefaults.kabi_committoFalse.-m MESSAGE,--kabi-commit-message MESSAGEβ the commit message that gets supplied for that git commit with the affected kABI symbol files.- Configuration option name:
defaults.kabi_commit - Default value: none
- Configuration option name:
-M SYMVERS_PATH,--symvers-path SYMVERS_PATHβ path to the relevant kernel'sModule.symversfile (for example,"/usr/src/kernels/KERNEL_VERSION.{arch}/Module.symvers", which ships inside the kernel-devel RPM).- Configuration option name:
defaults.symvers_path - Default value: none
- Configuration option name:
-w WHITELIST_PATH,--kabi-whitelist WHITELIST_PATHβ path to a file holding a list of symbols that are already white listed, inModule.symversformat.- Configuration option name:
defaults.kabi_whitelist - Default value: none
- Configuration option name:
-b,--break-on-errorsβ the second a symbol version conflict shows up, abort. This setsdefaults.kabi_check_symvers_conflictsto2.-B,--no-break-on-version-conflictsβ keep processing even if a symbol version conflict shows up. This setsdefaults.kabi_check_symvers_conflictsto0.-a,--ask-on-version-conflictsβ when a symbol version conflict shows up, ask the user what to do. This setsdefaults.kabi_check_symvers_conflictsto1.
β¨ CONFIGURATION β¨
Okay so configuration here is a sectioned key-value store, bestie. The values are strings, and they get interpreted based on context (the CONFIGURATION VALUES REFERENCE section is your reference, go read it π«Ά) as strings, integers, booleans (the Boolean values section breaks down exactly how boolean values get derived), or arrays.
Configuration generation π§
To build up its configuration, ddiskit collects configuration options from a bunch of different sources, and then does some fixed processing on top. The sources of configuration options are these:
- Hard-coded defaults, sitting right there in the ddiskit source code. These are mostly for the default configuration search paths and for other values that are expected to be defined one way or another. Right now it contains these configuration options:
defaultssectionres_dir = "/usr/share/ddiskit"template_dir = "{res_dir}/templates"profile_dir = "{res_dir}/profiles"config_template = "config"quilt_support = Truespec_template = "spec"src_patterns = "^Kbuild$|^Kconfig$|^Makefile$|^.*.[ch]$"
globalsectionmodule_vendor = "ENTER_MODULE_VENDOR"module_author = "ENTER_MODULE_AUTHOR"module_author_email = "ENTER_MODULE_AUTHOR_EMAIL"
- The "package" configuration. This one holds the rest of the configuration option defaults that need to be defined for proper operation (think spec file generation and such). Package configuration gets read from the fixed path
"/usr/share/ddiskit/ddiskit.config", and nobody β neither user nor system administrator β is expected to modify it (it's usually just overwritten when the package updates). - The "site" configuration. Living at
"/etc/ddiskit.config", this file is treated as a configuration file and it is subject to possible changes by the system administrator. - The "user" configuration. If a user wants some user-specific changes (like their own default values for the
global.module_authororglobal.module_author_emailconfiguration options, or a default profile), they should drop it into a.ddiskitrcfile in their home directory. - Profile. The profile in use gets derived from the
defaults.profileanddefault.profile_dirconfiguration variables (the File path evaluation section explains how the path to the profile gets evaluated). It contains overrides suited to a particular use case β for example, therh-testingprofile contains a spec file description suffix with a notice that the package provided is a testing package. Note that the values for those configuration variables can be overridden by the-pand-Pcommand line arguments. - Module configuration. This file is usually called
"module.config"(but the-ccommand line argument can override that) and it holds module-specific configuration. It's usually generated from a template by theprepare_sourcesaction, and it's self-documented about which values the user is expected to provide in there. - Command-line arguments. These update the
defaultssection of the configuration dictionary, and their key name is usually equal to the long option name with the dashes swapped out for underscores. The configuration option name for each specific command line option is given in the OPTIONS section. Unless it's explicitly specified (with the default value being"none"), a command line option always updates the configuration option value.
These files get applied one after another in that exact order, so the "last wins" rule is in charge here. The exception to that rule is command line options, which take precedence at every point of configuration generation (during the profile path evaluation, for example).
The configuration files themselves are sectioned key-value files, and their syntax is described in the related Python module documentation β except for the interpolation part, which is home-grown and described over in the Configuration value evaluation section.
Kernel package versioning scheme π§
Red Hat Enterprise Linux follows a specific kernel package versioning scheme, and ddiskit employs it so it can generate proper dependencies on the kernel package. So basically, anywhere a kernel version shows up, it expects that version to follow the specific scheme. More specifically, two version schemes are supported:
- Y-stream kernel version. This kernel package version ships as a part of a General Availability release, and it has this format:
kernel_version.kernel_patchlevel.kernel_sublevel-rhel_release.rpm_dist
For example, the RHEL 7.3 GA kernel has kernel version 3.10.0-514.el7. So consequently, it expects kernel_version, kernel_patchlevel, kernel_sublevel, rhel_release to be decimal numbers (with no more than 1, 2, 2, and 4 digits, respectively), and the rpm_dist part to be given in the form of "el<number>", where <number> is a 1-digit or 2-digit number that isn't less than 6.
- Z-stream kernel version. These kernel packages are provided as a part of updates for the existing release (the so-called Z-stream). The versions of these packages have this format:
kernel_version.kernel_patchlevel.kernel_sublevel-rhel_release[.update_release]+.rpm_dist
The restrictions on the parts that are also used for the Y-stream kernel package version description stay the same, and update_release is a number that can have up to 3 digits. Example of a Z-stream kernel package version (the RHEL 7.3 update from 2017-05-25): 3.10.0-514.21.1.el7.
Generally speaking, kernel module RPMs and Driver Update Disks are expected to be built for use alongside the Y-stream GA kernel (and all the following Z-stream kernels, thanks to kABI compatibility π), so when a Z-stream kernel package version gets detected, the user is warned about it. The differences between kernel package dependency generation in these cases are described in the Spec file generation section.
To enforce all these checks, ddiskit goes with a regular expression-based approach: it checks the version given in the defaults.kernel_version configuration variable against regular expressions set via the defaults.kernel_flex_version_re and defaults.kernel_fixed_version_re configuration options, which contain Python regular expressions (peep the Python re module documentation for the details about regular expression syntax) for matching the Y-stream and Z-stream kernel versioning scheme, respectively. And to extract the parts of the kernel version described above, these regular expression groups are used:
versionβ the kernel's major version (that'skernel_versionup in the description, bestie π )patchlevelβ the kernel's patch level (kernel_patchlevel)sublevelβ the kernel's sub-patch level (kernel_sublevel)rpm_releaseβ the major part of the RPM release (rhel_release)rpm_release_addβ the leftover part of the RPM release (update_release)rpm_distβ the RPM release dist part (rpm_dist)
And the default values of the defaults.kernel_flex_version_re and defaults.kernel_fixed_version_re config options are themselves built from other config options, like this:
kernel_flex_verson_re = {kernel_nvr_re}{kernel_dist_re}
kernel_fixed_version_re = {kernel_nvr_re}{kernel_fixed_re}{kernel_dist_re}
kernel_nvr_re = (?P<version>[0-9]).(?P<patchlevel>[0-9]{1,2}).(?P<sublevel>[0-9]{1,2})-(?P<rpm_release>[0-9]{1,4})
kernel_fixed_re = (?P<rpm_release_add>(.[0-9]{1,3})+)
kernel_dist_re = (?P<rpm_dist>.el([6-9]|[1-9][0-9]))
So yeah, there's some wiggle room in case you need to tune these checks. Very much iykyk energy π
Configuration check
Once the configuration has been constructed (and assuming module configuration is actually there), it goes through a whole lil vibe check π¦:
- Is the
globalconfiguration section there? Is thespec_fileone there? Gotta have both. - Do all the configuration options in the
globalandspec_filesections have non-default values? Here's the tea: a default value is whatever you get by gluing"ENTER_"onto the upper-cased configuration key name (so"ENTER_MODULE_NAME"for thespec_file.module_nameconfiguration option, for example). β¨ The one exception? Thespec_file.firmware_versionoption, but only when thespec_file.firmware_includeconfiguration option is set toFalse. - Does
spec_file.kernel_versionhave the proper format? Only Y-stream and Z-stream kernel versions get through, periodt. (Scoot over to the Kernel package versioning scheme section for the acceptable version string format details.) - Do
spec_file.module_name,spec_flie.module_version, andspec_file.module_rpm_releasecontain only characters RPM accepts? Here's the breakdown: alphanumeric plus'.','-','_','+','%','{','}'forspec_file.module_name; alphanumeric plus'.','_','+','%','{','}','~'forspec_flie.module_versionandspec_file.module_rpm_release. π
File path evaluation
Paths to all the external resource files (templates, profiles, the whole squad) get evaluated from the resource directory + name you gave, using this algorithm:
- If the resource name has no slashes in it, then it's treated as referring to a file inside the directory you provided.
- Otherwise? It's interpreted as a path relative to the current working directory (which is the directory where the module configuration lives).
So for example, the profile "my-profile" gets searched relative to the profile directory (that's the one stored in the defaults.profile_dir configuration option, which is "/usr/share/ddiskit/profiles" by default), but the profile "./my-profile" gets searched relative to the module's configuration directory. Same name, different vibe, different place. π
Configuration value evaluation
Configuration option values can reference other configuration options using the {[section_name.]key_name} syntax. If the section isn't there, it just assumes the referenced key lives in the same section as the value referencing it. And if the referenced key can't be found? No substitution happens, bestie, nothing. π€·
Let's look at an example, assume this configuration file:
[foo]
foo = aaa {bar} {bar.baz}
bar = bbb {baz} {bar.foo}
[bar]
foo = ccc {baz}
bar = ddd {foo.foo}
baz = eee
After evaluation: the foo.foo key would hold the value "aaa bbb {baz} ddd ccc eee eee", foo.bar would equal "bbb {baz} ccc eee", bar.foo would be "ccc eee", and bar.bar is "ddd ccc eee". Look at all those values popping off β¨
Circular dependencies are not explicitly resolved β there's only a substitution depth limit (currently set to 8). So don't go making loops, it's giving chaos π
Boolean values
Values that get treated as boolean can be any of the following (case-insensitive) strings to say "yeah, this is True": 1, t, y, true, or yes. To say False, you can use one of: 0, f, n, false, or no. And if a configuration value doesn't evaluate to True or False? It evaluates as None. π«Ά
None gets treated as False in most places, but sometimes it genuinely matters that you make a specific choice β and in those cases, an error would occur if the boolean value evaluated to None. No neutral answers allowed, you have to pick a side. πΈ
Spec file generation
Before spec file generation even happens, there's extra configuration processing going down:
spec_file.source_patchesandspec_file.source_patches_doget generated in accordance with a lexicographically sorted list of patch files found in the patch directory:src/patchrelative to the current working directory (except whenquilt(1)integration is enabled β see the QUILT INTEGRATION section for the details).spec_file.source_patchescontains lines in the"PatchN: patch-file-name"format, andspec_file.source_patches_docontains lines in the"%patchN -p1"format. So the first configuration variable is the one you want for describing your patch file list, and the second one is the useful one in the%prepsection for applying patches. π§ And if thedefault.quilt_supportconfiguration option is enabled, a file namedseriesgets ignored in the patch directory.spec_file.firmware_filesconfiguration variable holds the list of files found in thesrc/firmwaredirectory with the/lib/firmware/directory prepended β perfect for the%filessection of the firmware sub-package.spec_file.firmware_files_installconfiguration variable holds the list of firmware file installation commands in the format"install -m 644 -D source/firmware/firmware-file-path $RPM_BUILD_ROOT/lib/firmware/firmware-file-path"β which is exactly what you want for the%installsection of the firmware sub-package.spec_file.firmware_beginconfiguration option gets set to"%if 1"or"%if 0"depending on whether thespec_file.firmware_includeconfiguration variable is true or not, respectively.spec_file.firmware_endconfiguration variable gets set to"%endif".spec_file.dategets set to the current date and time in"%a %b %d %Y"strftime(3)format β but only if this variable hasn't already been set.spec_file.kernel_requiresgets formatted like this (again, only if the variable hasn't been set already):- if the
spec_file.kernel_version_minconfiguration option holds a non-empty value, it's set to
- if the
Requires: kernel >= spec_file.kernel_version_min
- otherwise, if the
spec_file.kernel_version_depconfiguration option holds a non-empty value, it's set to
Requires: kernel = spec_file.kernel_version_dep
- otherwise, it's set to
Requires: kernel >= kernel_version-kernel_release.kernel_dist
Requires: kernel < kernel_version-(kernel_release + 1).kernel_dist
when the spec_file.kernel_version configuration option holds a Y-stream kernel version, or
Requires: kernel = kernel_version-kernel_release.kernel_dist
when the spec_file.kernel_version configuration option holds a Z-stream kernel version (please head over to the Kernel package versioning scheme section for extra details about Y-stream and Z-stream versions).
If the spec_file.kernel_version configuration option isn't set and mock support is enabled, its value defaults to the latest version of the kernel-devel package available in the mock environment. Convenient π
spec_file.module_requiresgets set to thespec_file.dependenciesvalue with the"Requires: "string prepended β if the variable hasn't been set already. Heads up though: this special configuration variable is deprecated, it's only still around for backward compatibility, and this special value generation may be removed in the future. π
After all this configuration processing, parts of the spec template in the "%{[section_name.]key_name}" format (yes, notice the percent sign β that's different from the syntax used for configuration option substitution) get replaced with evaluated configuration values. If no appropriate configuration is found, no replacement happens. And if a configuration option evaluates to an empty string, %{nil} gets inserted into the resulting spec file instead. π
π₯ ACTIONS π₯
prepare_sources
Prepare the initial file and directory structure. This action creates the directories where all the various files are expected to land, and it creates module configuration (into the file set in the --config option) from the template file β that template's path is determined by the defaults.template_dir and defaults.config_template configuration variables (peep the File path evaluation section for how the module configuration template path gets derived). πΈ
The action creates this directory hierarchy:
rpmβ the directory for storingrpmbuild(1)artifacts.BUILDβ the build directory, used byrpmbuild(1).BUILDROOTβ the RPM build root.RPMSβ the directory where resulting binary RPMs are stored.SOURCESβ the directory where the source tarball and patches are stored.SPECSβ the directory where the generated spec file is placed.SRPMSβ the directory where the resulting source RPM is stored.
srcβ the directory where module sources are expected to be placed. There are no explicit constraints on the kernel module source file layout, but the expectation is that the main make file lives in a directory provided in thespec_file.module_build_dirconfiguration variable.patchesβ the directory with patches that should be applied to the source.firmwareβ firmware files.
On top of all that: if the defaults.git_src_directory configuration option is set (which itself defaults to the value of the spec_file.module_build_dir configuration option, as long as the latter is non-empty), then source files placed inside the directories listed in this whitespace-separated list get checked out (inside the src directory) from the repository pointed to by the defaults.git_dir configuration option, at the revision whose specification is set in the defaults.git_revision configuration option. And the actual revision that gets checked out is the output of the git rev-parse(1) command invocation with that aforementioned specification handed to it. π¦
Before the configuration template gets processed, these configuration options are also set:
spec_file.module_build_dirβ set to the value of the first element of the whitespace-separated list stored in thedefaults.git_src_directoryconfiguration option, or to"ENTER_MODULE_BUILD_DIR"if it's empty.spec_file.git_hashβ gets set to whatever theget rev-parse(1)call hands back, using the revision spec you gave indefaults.git_revision. β¨
generate_spec
Okay bestie, this one builds your spec file from the spec template β and which template that is gets decided by the defaults.template_dir and defaults.spec_template config variables (go peek at the File path evaluation section if you wanna know exactly how that path gets derived π§). The whole process is the one described in the Spec file generation section.
When it's done, you've got yourself a shiny "rpm/SPECS/{spec_file.module_name}.spec" file. π
While it's generating, it also peeks at whether kernel headers exist for the target kernel version and architectures, and if some are missing it prints a warning message. That check is purely decorative though β it does not affect the spec file generation process. Iconic behaviour, honestly.
build_rpm
The RPM build action is a whole multi-step journey, so buckle up:
- First it checks whether the module configuration file is even there (that's the one from the
defaults.configconfiguration variable, handed over via the--configcommand line option). Some config values get pulled straight out of it, so if it's missing the entire operation is pointless β early bailout, no cap. π - Then it either generates the spec file (if
defaults.generate_spec_on_buildis set toTrue) or checks it (ifdefaults.check_spec_on_buildis set to a positive value). That check does different things depending on the level you gave indefaults.check_spec_on_build, ranging from a lil warning all the way to straight-up killing the action:- Don't do the spec file check at all.
- Compare the spec files and throw a warning if the generated one and the existing one differ.
- Compare the spec files and throw a warning if they differ, then ask the user whether they wanna keep going.
- Compare the spec files and abort the action if there are any errors (during spec file generation or comparison).
Oh and btw, no spec file comparison happens at all β regardless of what defaults.check_spec_on_build says β if spec file generation is enabled. Obviously. π
- Next: is there a Makefile? If a file named
Makefileis chilling somewhere in the source tree, you pass this check. No Makefile? Early termination with a relevant exit code (the EXIT STATUS section has the deets). - If quilt integration is on (that's the
default.quilt_supportconfiguration option), quilt patches get de-applied. - Then we make the source tarball. A tar file named
"rpm/SOURCES/{spec_file.module_name}-{global.module_vendor}-{spec_file.module_version}.tar.bz2"
gets created, and the files in the src directory get added to it β with these exceptions:
- The
patchessubdirectory is skipped. - All RPM files sitting in the top level of the
srcdirectory are skipped. - Files in the firmware source subdirectory are skipped if the boolean config option
spec_file.firmware_includeisFalse. And if there are files in that directory, you get a warning message about it. - Hidden files (the ones starting with a dot) are skipped, unless
defaults.tar_all(controlled by the--tar-allaction-specific command line option) isTrue. - Only files matching the pattern in
defaults.src_patternsget added, ifdefaults.tar_strict(controlled by the--tar-strictaction-specific command line option) isTrue. The default pattern only covers*.c,*.h,Makefile,Kbuild, andKconfigfiles, which should work for most cases. πΈ
- All the files from
src/patchesget copied over torpm/SOURCES. - Now, if the current host architecture is among the architectures listed in
spec_file.kernel_arch, and therpmbuildcheck (rpmbuild -bc --nobuild) succeeded, anddefaults.srpm(controlled via the--srpmaction-specific command line option) isn't enabled β then it tries to build a binary RPM. Otherwise? Source RPM. That's the vibe check. π - Finally, if quilt integration (
default.quilt_support) is on, the quilt patches get applied back.
build_iso
This action takes a list of files and directories that should go onto the Driver Update Disk as non-option arguments. Then it does this:
- Iterates over the files you gave it (recursing down into directories) and adds to the candidate list any file that satisfies all of these:
- the file name ends with
".rpm", rpmquery(1)successfully pulls architecture info out of the package,- the RPM is a binary package, or it's a source package and
global.include_srpmis enabled, - the RPM is not a debug information package (its group isn't
"Development/Debug"), - the RPM has a valid GPG signature (in case GPG signature checking is enabled β the RPM SIGNATURE VERIFICATION section has extra info on that).
- the file name ends with
- All the qualifying candidates get copied into a temporary directory. Source RPMs land in the
srcsubdirectory of the disk hierarchy, and binary RPMs land inrpms/archβ where arch is the architecture of the binary RPM, with all thei386, ...,i686RPM architecture variants going into thei386subdirectory. π - RPM repository metadata gets generated (with the
createrepo(1)command) in each of those binary RPM directories. - An
rhdd3file containing the Driver Update Disk signature gets created in the temporary directory. - The ISO image gets created with the
mkisofs(1)command. Its name comes from thedefaults.isofileoption (settable via the--isofileaction-specific command line option). If you don't give an explicit ISO file name, it gets generated as
"dd-{spec_file.module_name}-{spec_file.module_version}-{spec_file.module_rpm_release}.{spec_file.rpm_dist}.iso"
or, if one of those configuration option values isn't a string, just plain old "dd.iso".
dump_config
Dumps the configuration dictionary exactly as it got evaluated by the process described in the Configuration generation section. The output file for the dump is set in the defaults.dump_config_name option. π
update_kabi
Generates files with kABI symbol information in the Red Hat Enterprise Linux kernel git repository, and optionally commits the changes. The action works through the kmods and RPMs you pass in the positional arguments, collecting versions (checksums) of symbols found in module information sections and/or "Requires" RPM tags, then adds files to the git repo for the symbols that aren't in there yet. β¨
The whole thing is controlled by these configuration options:
defaults.kabi_use_rpm_koβ whether to process the kmod files inside the provided RPMs instead of the RPM files themselves.defaults.symvers_symbol_re(string) β the regular expression used for parsing lines in symvers files. It's expected to containver,symbol,file, andexportgroups.defaults.kabi_files_overwrite(int) β whether to overwrite kABI files when files with the same name already exist. Can take these values:- Don't overwrite existing kABI files.
- Ask the user on each possible overwrite.
- Overwrite existing kABI files.
defaults.kabi_check_symvers_conflicts(int) β whether to abort the action when a symbol version conflict is detected (between a newly added symbol andModule.symversor the kABI white list). Can take these values:- Continue processing.
- Ask the user on each occesion.
- Abort the action.
defaults.kabi_commit(bool) β whether to commit the changes at the end of a successful kABI files update.defaults.symvers_path(string) [1] β path to the kernel'sModule.symversfile.defaults.kabi_whitelist(string) [1] β path to the kABI white list (inModule.symversformat).defaults.git_dir(string) β path to the kernel's git repository.defaults.kabi_dest_dir(string) [2] β path inside the kernel's repository to the directory with the kABI symbol files.defaults.kabi_file_name_pattern(string) [2] β the name of a kABI symbol file.defaults.kabi_file_template(string) [2] β the contents template of a kABI symbol file.defaults.kabi_commit_log_template(string) [2] β template of a line in the commit log regarding a specific kABI symbol file.defaults.kabi_commit_message(string) [2] β the commit message used for the git commit, ifdefaults.kabi_commitis enabled.
Notes, bestie, don't skip these:
[1] The arch variable gets overridden with the architecture of the kmod currently being processed ("x86_64" or "ppc64le", for example).
[2] Multiple overrides happen while those values are being evaluated:
- sym β symbol being processed.
- arch β architecture of the kmod being processed.
- ver β version (checksum) of the symbol being processed.
- kmod_file β file name of the kmod being processed.
- kernel_file β path to the file inside the kernel tree that holds the definition of the symbol being processed.
- kernel_export β type of the export (
"EXPORT_SYMBOL", for example).
As of now, the rh-release profile comes with some genuinely useful default values for all those config options. π«Ά
π§΅ QUILT INTEGRATION π§΅
ddiskit supports the quilt(1) patch workflow. Specifically:
- It de-applies quilt patches before building the source tarball, and applies them back after the build.
- It uses the contents of the
seriesfile in thepatchesdirectory as the source of the patch list during thegenerate_specaction, and also during tarball creation in thebuild_rpmaction. Theseriesfile itself is excluded from the list of files considered as patches. - It ignores hidden files during tarball creation in the
build_rpmaction, which conveniently avoids pulling in the.pcdirectory. π
All of this behaviour β except that last part, which is controlled by defaults.tar_all β is controlled by the defaults.quilt_support configuration option, reachable through the --quilt-enable and --quilt-disable command line options. π
π MOCK INTEGRATION π
okay so bestie, plot twist: ddiskit can hand off the whole RPM-building thing to mock(1) instead of doing it itself. this β¨magicβ¨ is turned on with the defaults.mock config option, which you flip via the --mock action-specific command line option (iykyk). once mock support is on, here's what changes, no cap:
mock(1)gets called instead ofrpmbuildfor both source and binary RPM creation. specifically:mock --buildsrpmdoes the source RPM, and then a little duo ofmock --buildsrpm+mock --rebuildbuilds the binary RPM out of the source RPM that got created inside the mock environment π«Ά- no build check (
rpmbuild -bc --nobuild) happens at all β that whole "can we even build a binary RPM tho" step is skipped, because it's just assumed mock can handle it π
π SOURCE CODE VERIFICATION π
so as part of the RPM build process (that's the build_rpm action, bestie), your source code can get vibe-checked against the git repository it supposedly came from π
here's the setup: the sources are assumed to live in the subdirectory given by the spec_file.module_build_dir config option, at the commit whose ID is in the spec_file.git_hash config option. the actual checking is done with the git-diff(1) command. and the path to the .git directory β the one holding the git repo your module's source should be checked against β goes in the defaults.git_repo config option.
whether the check even happens, and how serious it is, is decided by the default.check_git_src config option. its values mean:
0β the check is skipped, we're not doing this today π€1β the check runs, and a warning gets issued if the sources differ from the ones in the repository2β the check runs, and the build process gets aborted if the sources don't match or something else goes sideways during the check π
oh and one lil detail: the source code verification happens when quilt patches are already de-applied. important.
π RPM GPG SIGNATURE VERIFICATION π
during the ISO build process (the build_iso action, iconic), the RPMs you're including can get checked for whether their GPG signature is present and correct. whether we check is controlled by the rpm_gpg_check.check_level config option, which takes one of these values:
0β check skipped, moving on π1β check happens, and a warning is issued for every RPM that fails it2β check happens, and RPMs that didn't pass get skipped3β check happens, and ISO creation is aborted if even one RPM fails π
the boolean config option rpm_gpg_check.use_keyring controls whether a specific keyring directory with a specific set of keys gets used, or whether we just roll with the GPG keys present in the host's RPM DB. if using a keyring directory is enabled, then the rpm_gpg_check.keyring_dir config option points to the directory holding the public GPG keys. and ngl, for those files to be usable, their names have to end with ".key" β which is, in fact, RPM's implicit assumption, not ours, we just live here π
this check is enabled by default in the rh-release profile, and it's what lets you verify that the RPMs added to the release ISO carry Red Hat's GPG signature. iconic behavior, fr fr.
π οΈ USAGE EXAMPLE π οΈ
here's the whole glow-up journey, step by step:
- create the initial directory structure and the module configuration.
$ ddiskit prepare_sources
Writing new config file (module.config)... OK
Creating directory structure for RPM build ... OK
Creating directory structure for source code ... OK
Put your module source code in src directory.
- copy your code into the
srcdirectory:
$ tree src
src
βββ drivers
β βββ net
β βββ ethernet
β βββ broadcom
β βββ Makefile
β βββ tg3.c
β βββ tg3.h
βββ patches
βββ 0001-test.patch
βββ 0002-test.patch
- pls respect the directory hierarchy for drivers that are originally part of the kernel tree π
- any additional patches for the code can go in the
src/patchesdirectory
- fill out the
module.configand generate the spec file:
$ ddiskit generate_spec
Checking config ...
Config check ... OK
RPM spec file "rpm/SPECS/tg3.spec" exists!
Patches found, adding to the spec file:
Patch0: 0001-test.patch
Patch1: 0002-test.patch
Firmware directory is empty or nonexistent, skipping
Writing spec into rpm/SPECS/tg3.spec ... OK
- the resulting spec file lands in the
rpm/SPEC/directory, and you can totally peek at it before moving on if you want π
- build the binary RPM:
$ ddiskit build_rpm
- build the Driver Update Disk ISO:
$ ddiskit build_iso
π FILES π
/usr/share/ddiskit.configβ the package default configuration./etc/ddiskit.configβ the system-wide ("site") configuration.~/.ddiskitrcβ the user configuration.module.configβ the default configuration name./usr/share/ddiskit/templates/specβ template for RPM spec file generation. the path to it can be overridden by changing thedefaults.spec_templateconfig option, ordefaults.template_dirβ pls refer to the File path evaluation section for the extra deets./usr/share/ddiskit/templates/configβ template for module configuration. path can be overridden via thedefaults.config_templateconfig option, ordefaults.template_dirβ again, File path evaluation section, go look bestie./usr/share/ddiskit/profiles/defaultβ the default profile. contains config options that are useful in non-specific cases (none, currently β yes, literally none, it's giving minimalist π ). the profile in use gets selected through thedefaults.profileconfig option, and the path to the profile is configured bydefaults.profile_dir, another config option β File path evaluation section, you know the drill./usr/share/ddiskit/profiles/rh-testingβ profile holding config options used for testing DUP RPMs by Red Hat. this includes the disclaimer that the package is provided for testing purposes./usr/share/ddiskit/profiles/rh-releaseβ profile holding config options used for the release DUP RPMs by Red Hat. this includes enablement of various strict checks (like Git commit ID and RPM GPG signature verification). very demure, very strict π
π¦ EXIT STATUS π¦
so when ddiskit bounces, here's what the number actually means:
0β successful execution π1β generic error (no additional information available, she's mysterious like that)2β problems during command line argument parsing3β problems during the configuration check phase (see the Configuration check section for more)4β problem when trying to de-apply quilt patches (patches don't de-apply cleanly, for example)5β problem when trying to apply quilt patches6β problem during the sources verification7β problem during RPM GPG signature verification8β problem during git checkout of source files9β problem during spec file comparison10β symbol version (checksum) conflict occurred (update_kabiaction)11β problem during git add invocation (update_kabiaction)12β problem during git commit invocation (update_kabiaction)32β generic input/output error34β error while reading configuration file35β error while writing module configuration file (prepare_sourcesaction)36β spec template file read error (generate_specaction)38β spec read error (unused currently)39β spec write error (generate_specaction)41β source archive write error (build_rpmaction)42β Makefile not found (build_rpmaction)45β Driver Update Disk signature write error47β configuration dump file write error49β directory structure creation error
π REPORTING BUGS π
if something's giving broken, problems with ddiskit should be reported to the ddiskit project bug tracker π«Ά
π HISTORY π
story time, bestie π the initial version of ddiskit was created by John W. Linville in the year 2005, for 2.6-based Red Hat Enterprise Linux and Fedora Core distributions (like 2.6.9-based RHEL 4). it filled "the same need which Doug Ledford's Device Driver Update Disk Devel Kit filled for prior generations of Red Hat distributions", which was used for the Linux 2.4-series based Red Hat distributions around the year 2003.
in 2007, the responsibility for maintaining and enhancing ddiskit was passed to Jon Masters, who then developed ddiskit during the RHEL 5 and RHEL 6 era. and the third incarnation of ddiskit was conceived in 2016 by Petr OroΕ‘, in an attempt to bring more automation to the process of Driver Update Disk creation, along with RHEL 7 support. three eras, one tool, main character energy fr fr π
π SEE ALSO π
rpmbuild(1),dkms(8),akmods(1),mock(1),quilt(1)- Jon Masters. Red Hat Driver Update Packages. Official Reference Guide
- ddiskit project repository
and that's the whole page, bestie β every last drop π the little footer at the bottom is just the ddiskit manual page signature (that DDISKIT(1) source/version line plus its date), so nothing more to read down there. go build something iconic, and remember: check your exit codes, respect your directory hierarchy, and never skip the vibe check β¨π¦π
π¦ where this page comes from
- centos-stream 10: ddiskit 3.6-29.20260805git82d44fc.el10 Β· GPL-3.0-only
- centos-stream 9: ddiskit 3.6-18.git82d44fc.el9 Β· GPLv3
- fedora 43: ddiskit 3.6-31.20250206gitd857c77.fc43 Β· GPL-3.0-only
- fedora 44: ddiskit 3.6-33.20250206gitd857c77.fc44 Β· GPL-3.0-only
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms