File 0001-Add-extension-with-dracut-modules.patch of Package uki-tool

From a55cba3d8027d86cea9809ab4ac1870bcb008b93 Mon Sep 17 00:00:00 2001
From: vlefebvre <valentin.lefebvre@suse.com>
Date: Wed, 11 Jun 2025 17:24:34 +0000
Subject: [PATCH] Add extension with dracut modules

Signed-off-by: vlefebvre <valentin.lefebvre@suse.com>
---
 CHANGELOG.md              |   2 +
 README.md                 |   2 +
 docs/man/uki-tool.1       |   3 +
 docs/man/uki-tool.1.md    |   1 +
 src/commands/extension.sh | 211 +++++++++++++++++++++++++++++---------
 5 files changed, 171 insertions(+), 48 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index a7c2fa5..ce1e4eb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,8 @@ All notable changes to this project will be documented in this file.
 
 ## Added
 
+- extension: dracut modules as single extension.
+
 ## Changed
 
 ## Fixed
diff --git a/README.md b/README.md
index 52b6721..5bccfa8 100644
--- a/README.md
+++ b/README.md
@@ -111,6 +111,7 @@ USAGE: uki-tool extension [OPTIONS]
 OPTIONS:
   -n|--name:        Extension's name
   -p|--packages:    List of packages to install into the extension
+  -m|--modules:     List of dracut modules to install into the extension
   -f|--format:      Extension format (squashfs by default)
   -t|--type:        Type of the extension (dir, raw)
   -u|--uki:         Path to the referenced UKI (dedicated exetnsion)
@@ -131,6 +132,7 @@ INFO:
  
 EXAMPLE:
     uki-tool extension -n "debug" -p "strace,gdb" -t "raw"
+    uki-tool extension -n "rescue" -m "rescue"
 ```
 
 * dedicated extensions: Extensions that  extend a particular UKI. The parameter
diff --git a/docs/man/uki-tool.1 b/docs/man/uki-tool.1
index 5a543d8..c4e95e4 100644
--- a/docs/man/uki-tool.1
+++ b/docs/man/uki-tool.1
@@ -49,6 +49,9 @@ It will need to be installed into
 \f[B]\-p\f[R]|\f[B]\-\-packages\f[R]: List of packages to install into
 the extension
 .IP \[bu] 2
+\f[B]\-m\f[R]|\f[B]\-\-modules\f[R]: List of dracut modules to install
+into the extension
+.IP \[bu] 2
 \f[B]\-f\f[R]|\f[B]\-\-format\f[R]: Extension format (squashfs by
 default)
 .IP \[bu] 2
diff --git a/docs/man/uki-tool.1.md b/docs/man/uki-tool.1.md
index 113e5cf..8898261 100644
--- a/docs/man/uki-tool.1.md
+++ b/docs/man/uki-tool.1.md
@@ -49,6 +49,7 @@ UKI. It will need to be installed into '/usr/lib/modules/uki.extra.d/'.
 
 * **-n**|**--name**: Extension's name
 * **-p**|**--packages**: List of packages to install into the extension
+* **-m**|**--modules**: List of dracut modules to install into the extension
 * **-f**|**--format**: Extension format (squashfs by default)
 * **-t**|**--type**: Type of the extension (dir, raw)
 * **-u**|**--uki**: Path to the referenced UKI (installed one by default)
diff --git a/src/commands/extension.sh b/src/commands/extension.sh
index e60ccbd..cd5aa53 100644
--- a/src/commands/extension.sh
+++ b/src/commands/extension.sh
@@ -105,6 +105,7 @@ _extension_usage() {
 OPTIONS:
   -n|--name:        Extension's name
   -p|--packages:    List of packages to install into the extension
+  -m|--modules:     List of dracut modules to install into the extension
   -f|--format:      Extension format (squashfs by default)
   -t|--type:        Type of the extension (dir, raw)
   -u|--uki:         Path to the referenced UKI (dedicated exetnsion)
@@ -125,7 +126,8 @@ INFO:
     '${COMMON_KERNEL_MODULESDIR}/uki.extra.d/'.
  
 EXAMPLE:
-    $BIN extension -n \"debug\" -p \"strace,gdb\" -t \"raw\""
+    $BIN extension -n \"debug\" -p \"strace,gdb\" -t \"raw\"
+    $BIN extension -n \"rescue\" -m \"rescue\""
     printf "%s\n" "$usage_str"
 }
 
@@ -150,7 +152,63 @@ _extension_size_partition() {
 }
 
 ###
-# Create an initrd extension image
+# Create extension from plain directory
+# ARGUMENTS:
+#   1 - Extension's name
+#   2 - Extension's image name
+#   3 - Extension's format
+#   4 - Sources dir path
+# OUTPUTS:
+#   debug status
+# RETURN:
+#   0 in success, 1 otherwise
+###
+_extension_create() {
+    name="$1"
+    img_name="$2"
+    format="$3"
+    src_dir="$4"
+    ext_name="${img_name%.*}"
+    ext_dir=$src_dir/usr/lib/extension-release.d
+    ext_file=$ext_dir/extension-release.$ext_name
+    mkdir -p "$ext_dir"
+    touch "$ext_file"
+    id_arg=$(echo "$EXTENSION_INITRD_RELEASE" | grep "^ID=\"*\"")
+    ver_id_arg=$(echo "$EXTENSION_INITRD_RELEASE" | grep "^VERSION_ID=\"*\"")
+    {
+        echo "SYSEXT_LEVEL=2"
+        echo "$id_arg"
+        echo "$ver_id_arg"
+        echo "SYSEXT_ID=$name"
+        # scope=[initrd,system,portable]
+        echo "SYSEXT_SCOPE=initrd"
+        echo "ARCHITECTURE=$arch"
+    } > "$ext_file"
+
+    # Create an empty disk raw image extensions
+    sized=$(du -s --block-size=1M "$src_dir" | awk '{print $1}')
+    sized=$((sized+1)) # Add at minimum 1M
+    part_sized=$(_extension_size_partition ${sized})
+    echo_info "Create an image of sized ${part_sized}M..."
+    if [ "$format" = "$EXTENSION_FORMAT_DEFAULT" ]; then
+        mksquashfs \
+            "$src_dir" \
+            "./$img_name" \
+            -quiet
+    else
+        dd if=/dev/zero of="./$img_name" bs=1M count="$part_sized" \
+            > /dev/null 2>&1
+        mkfs."$format" \
+            -U "$EXTENSION_PART_UUID" \
+            -L "$EXTENSION_PART_LABEL" \
+            -d "$src_dir" \
+            -q \
+            "./$img_name"
+    fi
+}
+
+###
+# Create an initrd extension image using packages
 # ARGUMENTS:
 #   1 - Extension's name
 #   2 - Extension's packages list
@@ -163,7 +221,7 @@ _extension_size_partition() {
 # RETURN:
 #   0 in success, 1 otherwise
 ###
-_extension_create() {
+_package_extension_create() {
     if [ $# -lt 6 ]; then
         echo_debug "Missing arguments"
         return 1
@@ -175,8 +233,8 @@ _extension_create() {
     type="$4"
     uki="$5"
     arch="$6"
-    echo_info "Create the extension '$img_name' with '$pkgs' in format $format\
- at type $type"
+    echo_info "Create the extension '$img_name' with packages '$pkgs' in \
+format $format at type $type"
     for pkg in $(printf "%s" "$pkgs" | sed 's/,/ /g'); do
         if [ "$pkg_list" = "" ]; then
             pkg_list="$pkg";
@@ -207,7 +265,8 @@ _extension_create() {
     fi
     
     # Get list of files to install
-    tmp_dir=$(mktemp -d)
+    tmp_dir="${name}-ext-build"
+    mkdir "${tmp_dir}"
     for pkg in $EXTENSION_LIST_DEPS; do
         for file in $(rpm -ql "$pkg" | sed 's/\n/ /g'); do
             if [ -f "$file" ]; then
@@ -216,49 +275,93 @@ _extension_create() {
             fi
         done
     done
-    ext_name="${img_name%.*}"
-    ext_dir=$tmp_dir/usr/lib/extension-release.d
-    ext_file=$ext_dir/extension-release.$ext_name
-    mkdir -p "$ext_dir"
-    touch "$ext_file"
-    id_arg=$(echo "$EXTENSION_INITRD_RELEASE" | grep "^ID=\"*\"")
-    ver_id_arg=$(echo "$EXTENSION_INITRD_RELEASE" | grep "^VERSION_ID=\"*\"")
-    {
-        echo "SYSEXT_LEVEL=2"
-        echo "$id_arg"
-        echo "$ver_id_arg"
-        echo "SYSEXT_ID=$name"
-        # scope=[initrd,system,portable]
-        echo "SYSEXT_SCOPE=initrd"
-        echo "ARCHITECTURE=$arch"
-    } > "$ext_file"
 
-    # Create an empty disk raw image extensions
-    sized=$(du -s --block-size=1M "$tmp_dir" | awk '{print $1}')
-    sized=$((sized+1)) # Add at minimum 1M
-    part_sized=$(_extension_size_partition ${sized})
-    echo_info "Create an image of sized ${part_sized}M..."
-    if [ "$format" = "$EXTENSION_FORMAT_DEFAULT" ]; then
-        mksquashfs \
-            "$tmp_dir" \
-            "./$img_name" \
-            -quiet
-    else
-        dd if=/dev/zero of="./$img_name" bs=1M count="$part_sized" \
-            > /dev/null 2>&1
-        mkfs."$format" \
-            -U "$EXTENSION_PART_UUID" \
-            -L "$EXTENSION_PART_LABEL" \
-            -d "$tmp_dir" \
-            -q \
-            "./$img_name"
+    _extension_create "${name}" "${img_name}" "${format}" "${tmp_dir}"
+    if [ ! -f "./$img_name" ]; then
+        echo_error "Failed to create ./$img_name"
+        return 1
     fi
+
     # Clean
-    [ "$tmp_dir" ] && rm -r "$tmp_dir"
+    [ -d "$tmp_dir" ] && rm -r "$tmp_dir"
     echo_info "extension image created at ./$img_name"
     return 0
 }
 
+###
+# Create an initrd extension image using modules (for dracut)
+# ARGUMENTS:
+#   1 - Extension's name
+#   2 - Extension's modules list
+#   3 - Extension's format
+#   4 - Extension's type
+#   5 - Extension's UKI
+#   6 - Extension's arch
+# OUTPUTS:
+#   debug status
+# RETURN:
+#   0 in success, 1 otherwise
+###
+_dracut_extension_create() {
+    if [ $# -lt 6 ]; then
+        echo_debug "Missing arguments"
+        return 1
+    fi
+    name="${1}"
+    img_name="${name}-ext.raw"
+    modules="$2"
+    format="$3"
+    type="$4"
+    uki="$5"
+    arch="$6"
+    rc=0
+    echo_info "Create the extension '$img_name' with modules '$modules' in \
+format $format at type $type"
+
+    tmp_dir="${name}-ext-tmp"
+    mkdir "./${tmp_dir}"
+    cd "./$tmp_dir" || return 1
+    for mod in $modules; do
+        if printf "%s" "$mod" | grep -Eq "^[0-9][0-9]"; then
+            mod="${mod#??}"
+        fi
+        if ! dracut --list-modules --quiet | grep -Eq "${mod}"; then
+            echo_error "${mod} doesn't exist in dracut modules dir"
+            rc=1
+            break
+        fi
+        dracut --no-compress --no-hostonly --modules "$mod"\
+            --quiet "./initrd-$mod.img"
+        if [ ! -f "./initrd-$mod.img" ]; then
+            echo_error "Dracut called failed to create ./initrd-$mod.img"
+            rc=1
+            break
+        fi
+        lsinitrd --unpack "./initrd-$mod.img"
+    done
+    cd .. || return 1
+    if [ $rc -eq 0 ]; then
+        src_dir="${name}-ext-src"
+        mkdir "${src_dir}"
+        if [ -d "./${tmp_dir}/usr" ]; then
+            cp -r "./${tmp_dir}/usr" "./${src_dir}/usr" || return 1
+        fi
+        if [ -d "./${tmp_dir}/opt" ]; then
+            cp -r "./${tmp_dir}/opt" "./${src_dir}/opt" || return 1
+        fi
+        _extension_create "${name}" "${img_name}" "${format}" "${src_dir}"
+        if [ ! -f "./$img_name" ]; then
+            echo_error "Failed to create ./$img_name"
+            rc=1
+        else
+            echo_info "extension image created at ./$img_name"
+        fi
+        [ -d "$src_dir" ] && rm -r "$src_dir"
+    fi
+    [ -d "$tmp_dir" ] && rm -r "${tmp_dir}"
+    return $rc
+}
+
 #######################################################################
 #                           ENTRY POINT                               #
 #######################################################################
@@ -282,7 +385,7 @@ extension_helper() {
 #   lsit of needed tools
 ###
 extension_tools_needed() {
-    printf "objcopy lsinitrd mksquashfs mktemp"
+    printf "objcopy lsinitrd mksquashfs mktemp dracut"
 }
 
 ###
@@ -296,14 +399,16 @@ extension_exec() {
     [ $# -lt 2 ] \
         && echo_error "Missing arguments"\
         && _extension_usage && exit 2
-    args=$(getopt -a -n extension -o n:p:f:t:u:a:\
-        --long name:,packages:,format:,type:,uki:,arch:,no-deps -- "$@")
+    args=$(getopt -a -n extension -o n:p:m:f:t:u:a:\
+        --long name:,packages:,modules:,format:,type:,uki:,arch:,no-deps\
+        -- "$@")
     eval set --"$args"
     while :
     do
         case "$1" in
             -n | --name)        name="$2"           ; shift 2 ;;
             -p | --packages)    packages="$2"       ; shift 2 ;;
+            -m | --modules)     modules="$2"       ; shift 2 ;;
             -t | --type)        type="$2"           ; shift 2 ;;
             -f | --format)      format="$2"         ; shift 2 ;;
             -u | --uki)         uki="$2"            ; shift 2 ;;
@@ -313,8 +418,12 @@ extension_exec() {
             *) echo_warning "Unexpected option: $1"; _extension_usage   ;;
         esac
     done
-    if [ ! ${packages+x} ]; then
-        echo_error "Missing packages to install in the extension"
+    if [ ! ${packages+x} ] && [ ! ${modules+x} ]; then
+        echo_error "Missing packages/modules to install in the extension"
+        _extension_usage
+        exit 2
+    elif [ ${packages+x} ] && [ ${modules+x} ]; then
+        echo_error "Choose between packages or modules to create the extension"
         _extension_usage
         exit 2
     fi
@@ -339,6 +448,12 @@ extension_exec() {
         echo_error "No mkfs.$format found, use another format"
         exit 1
     fi
-    _extension_create "$name" "$packages" "$format" "$type" "$uki" "$arch"
+    if [ ${package+x} ]; then
+        _package_extension_create "$name" "$packages" "$format" "$type" "$uki"\
+            "$arch"
+    elif [ ${modules+x} ]; then
+        _dracut_extension_create "$name" "$modules" "$format" "$type" "$uki"\
+            "$arch"
+    fi
     exit $?
 }
-- 
2.49.0

openSUSE Build Service is sponsored by