github.com/canonical/ubuntu-image@v0.0.0-20240430122802-2202fe98b290/tests/lib/external/snapd-testing-tools/tools/repack-kernel (about) 1 #!/bin/bash 2 set -e 3 4 if [ -n "$D" ]; then 5 set -x 6 fi 7 8 show_help() { 9 echo "usage: repack-kernel <command> <opts>" 10 echo "" 11 echo "handle extraction of the kernel snap to a workspace directory, and later" 12 echo "repacking it back to a snap." 13 echo "" 14 echo " repack-kernel setup - setup system dependencies" 15 echo " repack-kernel extract <snap-file> <target> - extract under <target> workspace tree" 16 echo " repack-kernel prepare <target> - prepare initramfs & kernel for repacking" 17 echo " repack-kernel pack <target> - pack the kernel" 18 echo " repack-kernel cull-firmware <target> - remove unnecessary firmware" 19 echo " repack-kernel cull-modules <target> - remove unnecessary modules" 20 echo "" 21 } 22 23 setup() { 24 if [ "$UID" != "0" ]; then 25 echo "run as root (only this command)" 26 exit 1 27 fi 28 29 # carries ubuntu-core-initframfs 30 add-apt-repository ppa:snappy-dev/image -y 31 apt update 32 33 if ! dpkg -s ubuntu-core-initramfs >/dev/null 2>&1; then 34 if ! apt install -y ubuntu-core-initramfs; then 35 echo "ubuntu-core-initramfs was not available in deb repository!" 36 exit 1 37 fi 38 fi 39 } 40 41 get_kver() { 42 local kerneldir="$1" 43 find "$kerneldir" -maxdepth 1 -name "config-*" | grep -Po 'config-\K.*' 44 } 45 46 extract() { 47 local snap_file="$1" 48 local target="$2" 49 50 if [ -z "$target" ] || [ -z "$snap_file" ]; then 51 echo "repack-kernel: invalid arguments for extract" 52 exit 1 53 fi 54 55 target=$(realpath "$target") 56 57 mkdir -p "$target" "$target/work" "$target/backup" 58 59 # kernel snap is huge, unpacking to current dir 60 unsquashfs -d "$target/kernel" "$snap_file" 61 62 kver="$(get_kver "$target/kernel")" 63 64 # repack initrd magic, beware 65 # assumptions: initrd is compressed with LZ4, cpio block size 512, microcode 66 # at the beginning of initrd image 67 68 # XXX: ideally we should unpack the initrd, replace snap-boostrap and 69 # repack it using ubuntu-core-initramfs --skeleton=<unpacked> this does not 70 # work and the rebuilt kernel.efi panics unable to start init, but we 71 # still need the unpacked initrd to get the right kernel modules 72 objcopy -j .initrd -O binary "$target"/kernel/kernel.efi "$target/work/initrd" 73 74 # copy out the kernel image for create-efi command 75 objcopy -j .linux -O binary "$target"/kernel/kernel.efi "$target/work/vmlinuz-$kver" 76 77 cp -a "$target"/kernel/kernel.efi "$target/backup/" 78 79 # this works on 20.04 but not on 18.04 80 unmkinitramfs "$target"/work/initrd "$target"/work/unpacked-initrd 81 82 # copy the unpacked initrd to use as the target skeleton 83 cp -ar "$target/work/unpacked-initrd" "$target/skeleton" 84 85 echo "prepared workspace at $target" 86 echo " kernel: $target/kernel ($kver)" 87 echo " kernel.efi backup: $target/backup/kernel.efi" 88 echo " temporary artifacts: $target/work" 89 echo " initramfs skeleton: $target/skeleton" 90 91 } 92 93 prepare() { 94 local target="$1" 95 96 if [ -z "$target" ]; then 97 echo "repack-kernel: missing target for prepare" 98 exit 1 99 fi 100 101 target=$(realpath "$target") 102 103 local kver 104 kver="$(get_kver "$target/kernel")" 105 106 ( 107 # all the skeleton edits go to a local copy of distro directory 108 local skeletondir="$target/skeleton" 109 110 cd "$target/work" 111 # XXX: need to be careful to build an initrd using the right kernel 112 # modules from the unpacked initrd, rather than the host which may be 113 # running a different kernel 114 ( 115 # accommodate assumptions about tree layout, use the unpacked initrd 116 # to pick up the right modules 117 cd unpacked-initrd/main 118 ubuntu-core-initramfs create-initrd \ 119 --kernelver "$kver" \ 120 --skeleton "$skeletondir" \ 121 --feature main \ 122 --kerneldir "lib/modules/$kver" \ 123 --output "$target/work/repacked-initrd" 124 ) 125 126 # assumes all files are named <name>-$kver 127 ubuntu-core-initramfs create-efi \ 128 --kernelver "$kver" \ 129 --initrd repacked-initrd \ 130 --kernel vmlinuz \ 131 --output repacked-kernel.efi 132 133 cp "repacked-kernel.efi-$kver" "$target/kernel/kernel.efi" 134 135 # XXX: needed? 136 chmod +x "$target/kernel/kernel.efi" 137 ) 138 } 139 140 cull_firmware() { 141 local target="$1" 142 143 if [ -z "$target" ]; then 144 echo "repack-kernel: missing target for cull-firmware" 145 exit 1 146 fi 147 148 # XXX: drop ~450MB+ of firmware which should not be needed in under qemu 149 # or the cloud system 150 rm -rf "$target"/kernel/firmware/* 151 } 152 153 cull_modules() { 154 local target="$1" 155 156 if [ -z "$target" ]; then 157 echo "repack-kernel: missing target for cull-modules" 158 exit 1 159 fi 160 161 target=$(realpath "$target") 162 163 local kver 164 kver="$(get_kver "$target/kernel")" 165 166 ( 167 cd "$target/kernel" 168 # drop unnecessary modules 169 awk '{print $1}' < /proc/modules | sort > "$target/work/current-modules" 170 #shellcheck disable=SC2044 171 for m in $(find modules/ -name '*.ko'); do 172 noko=$(basename "$m"); noko="${noko%.ko}" 173 if echo "$noko" | grep -f "$target/work/current-modules" -q ; then 174 echo "keeping $m - $noko" 175 else 176 rm -f "$m" 177 fi 178 done 179 180 # depmod assumes that /lib/modules/$kver is under basepath 181 mkdir -p fake/lib 182 ln -s "$PWD/modules" fake/lib/modules 183 depmod -b "$PWD/fake" -A -v "$kver" 184 rm -rf fake 185 ) 186 } 187 188 pack() { 189 local target="$1" 190 191 if [ -z "$target" ]; then 192 echo "repack-kernel: missing target for pack" 193 exit 1 194 fi 195 snap pack "${@:2}" "$target/kernel" 196 } 197 198 main() { 199 if [ $# -eq 0 ]; then 200 show_help 201 exit 0 202 fi 203 204 local subcommand="$1" 205 local action= 206 while [ $# -gt 0 ]; do 207 case "$1" in 208 -h|--help) 209 show_help 210 exit 0 211 ;; 212 *) 213 action=$(echo "$subcommand" | tr '-' '_') 214 shift 215 break 216 ;; 217 esac 218 done 219 220 if [ -z "$(declare -f "$action")" ]; then 221 echo "repack-kernel: no such command: $subcommand" >&2 222 show_help 223 exit 1 224 fi 225 226 "$action" "$@" 227 } 228 229 main "$@" 230