72805ad038
Kernel modules may be needed to access rootfs. Such modules must be present in the initramfs. The mkmodpack script finds modules by given patterns. If the pattern is specified incorrectly, the module will not be found and booting will become impossible. Need to warn about module patterns that do not match with anything. The pattern can match the name of a module built into the kernel as given by modprobe. However, modprobe can fix some incorrect patterns. These patterns should also be reported.
248 lines
5.3 KiB
Bash
248 lines
5.3 KiB
Bash
#!/bin/sh
|
|
|
|
PROG=mkmodpack
|
|
VERSION=0.1
|
|
CATCHED=
|
|
|
|
Exit()
|
|
{
|
|
local rc=$?
|
|
[ -z "$1" ] || rc="$1"
|
|
CATCHED=1
|
|
exit $rc
|
|
}
|
|
|
|
Warning()
|
|
{
|
|
echo "$PROG: warning: $*" >&2
|
|
}
|
|
|
|
Fatal()
|
|
{
|
|
echo "$PROG: $*" >&2
|
|
Exit 1
|
|
}
|
|
|
|
KERNEL=
|
|
OUTPUT=
|
|
WORKDIR=
|
|
TEMPLATE=
|
|
pattern=
|
|
uname_r="$(uname -r)"
|
|
|
|
exit_handler()
|
|
{
|
|
local rc=$?
|
|
trap - EXIT
|
|
[ -n "$CATCHED" -o $rc -eq 0 ] ||
|
|
echo "$PROG: unhandled error, exiting..."
|
|
[ -z "$WORKDIR" ] || rm -rf "$WORKDIR"
|
|
[ -z "$TEMPLATE" ] || rm -f "$TEMPLATE"
|
|
exit $rc
|
|
}
|
|
|
|
signal_handler()
|
|
{
|
|
echo 'Interrupted!' >&2
|
|
Exit 1
|
|
}
|
|
|
|
trap exit_handler EXIT
|
|
trap signal_handler SIGHUP SIGPIPE SIGINT SIGTERM SIGQUIT
|
|
|
|
FIRMWARE_DIRS="/lib/firmware /usr/lib/hotplug/firmware"
|
|
|
|
Usage()
|
|
{
|
|
cat >&2 <<EOF
|
|
mkmodpack - creates an cpio archive, containing subset of kernel modules.
|
|
|
|
mkmodpack is free software, covered by the GNU General Public License.
|
|
mkmodpack comes with ABSOLUTELY NO WARRANTY, see license for details.
|
|
|
|
Usage: $PROG [options]
|
|
|
|
Valid options are:
|
|
--version print version number and exit.
|
|
-k, --kernel assume given kernel version, instead of uname -r.
|
|
-o, --output output filename, stdout if omitted.
|
|
-p, --pattern place into archive only modules which match one of pattern from given file.
|
|
-h, --help show this text.
|
|
|
|
Example: $PROG -o modpack -k $uname_r
|
|
|
|
EOF
|
|
[ -n "$1" ] && Exit "$1" || Exit
|
|
}
|
|
|
|
#---------------------------------------------------------------
|
|
ListModules()
|
|
{
|
|
if [ -s "$pattern" ]; then
|
|
find /lib/modules/$KERNEL -type f 2>/dev/null |grep -wf "$pattern"
|
|
else
|
|
find /lib/modules/$KERNEL -type f 2>/dev/null
|
|
fi
|
|
}
|
|
|
|
ListModuleFiles()
|
|
{
|
|
modprobe --set-version="$KERNEL" --show-depends "$@" 2>/dev/null
|
|
}
|
|
|
|
AddUniqueModule()
|
|
{
|
|
local path="$1" modules=
|
|
modules="$MODULES
|
|
$path"
|
|
modules="$(echo "$modules" |sort)"
|
|
if [ -z "$(echo "$modules" |uniq -d)" ]; then
|
|
echo "$modules"
|
|
fi
|
|
}
|
|
|
|
AddModuleFile()
|
|
{
|
|
local path="$1" name="$1" modules=
|
|
name="${name##*/}"
|
|
name="${name%.gz}"
|
|
name="${name%.xz}"
|
|
name="${name%.ko}"
|
|
|
|
modules=$(AddUniqueModule "$path")
|
|
if [ -n "$modules" ]; then
|
|
MODULES="$modules"
|
|
AddModuleFirmware "$name" "$path"
|
|
fi
|
|
}
|
|
|
|
AddModuleFirmware()
|
|
{
|
|
local mod_name="$1" && shift
|
|
local mod_path="$1" && shift
|
|
local fw_list fw_name fw_dir fw_file fw_privdir
|
|
|
|
fw_list="$(modinfo -F firmware "$mod_path")" || return
|
|
[ -n "$fw_list" ] || return
|
|
for fw_name in $fw_list; do
|
|
fw_file=
|
|
for fw_dir in $FIRMWARE_DIRS; do
|
|
if [ -r "$fw_dir/$fw_name" ]; then
|
|
fw_file="$fw_dir/$fw_name"
|
|
break
|
|
fi
|
|
done
|
|
[ -n "$fw_file" ] || {
|
|
Warning "Firmware file \"$fw_name\" for module \"$mod_name\" not found"
|
|
continue
|
|
}
|
|
[ "$fw_name" = "${fw_name##*/}" ] || {
|
|
[ -n "$fw_privdir" ] || {
|
|
fw_privdir="${fw_name%/*}"
|
|
FILES="$FILES
|
|
dir /lib/firmware/$fw_privdir 0755 0 0"
|
|
}
|
|
}
|
|
FILES="$FILES
|
|
file /lib/firmware/$fw_name $fw_file 0644 0 0"
|
|
done
|
|
}
|
|
|
|
AddModule()
|
|
{
|
|
local path="$1" name="$1" m list
|
|
name="${name##*/}"
|
|
name="${name%.gz}"
|
|
name="${name%.xz}"
|
|
name="${name%.ko}"
|
|
|
|
list=`ListModuleFiles "$name"`
|
|
for m in $list; do
|
|
[ -z "${m##/lib/modules/*}" ] || continue
|
|
AddModuleFile "$m"
|
|
done
|
|
}
|
|
|
|
TEMP=`getopt -n "$0" -o k:,o:,p:,h -l kernel:,output:,pattern:,help,version -- "$@"` || exit 1
|
|
eval set -- "$TEMP"
|
|
|
|
while :; do
|
|
case "$1" in
|
|
-k|--kernel)
|
|
shift
|
|
KERNEL="$1"
|
|
;;
|
|
-o|--output)
|
|
shift
|
|
OUTPUT="$1"
|
|
;;
|
|
-p|--pattern*)
|
|
shift
|
|
pattern="$1"
|
|
;;
|
|
-h|--help)
|
|
Usage 0
|
|
;;
|
|
--version)
|
|
echo "$PROG: version $VERSION"
|
|
exit 0
|
|
;;
|
|
--) shift; break
|
|
;;
|
|
*) Fatal "Unrecognized option: $1"
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
[ -n "$KERNEL" ] || KERNEL="$uname_r"
|
|
[ -d "/lib/modules/$KERNEL" ] || Fatal "Directory /lib/modules/$KERNEL does not exists."
|
|
|
|
# modprobe from kmod-9+ *requires* modules.dep.bin (ALT #27640)
|
|
if [ ! -f /lib/modules/$KERNEL/modules.dep.bin ]; then
|
|
depmod -a -F "/boot/System.map-$KERNEL" "$KERNEL" ||
|
|
Fatal "Failed to create modules dependencies (full)."
|
|
fi
|
|
|
|
#---------------------------------------------------------------
|
|
FIRMWARE_DIRS="$FIRMWARE_DIRS /lib/firmware/$KERNEL"
|
|
MODULES=
|
|
FILES=
|
|
|
|
for m in $(ListModules); do
|
|
AddModule "$m"
|
|
done
|
|
|
|
WORKDIR=`mktemp -td mkmodpack.XXXXXXXXXX` || Fatal "Failed to create working directory."
|
|
TEMPLATE=`mktemp -t mkmodpack.XXXXXXXXXX` || Fatal "Failed to create temporary file."
|
|
|
|
echo "$MODULES" |cpio -pmd "$WORKDIR" 2>/dev/null || Fatal "Failed to copy modules to working directory."
|
|
depmod -a -F "/boot/System.map-$KERNEL" -b "$WORKDIR" "$KERNEL" || Fatal "Failed to create modules dependencies."
|
|
|
|
(
|
|
cd "$WORKDIR"
|
|
find "lib/modules/$KERNEL" -type d |sed -e 's,^.\+$,dir\t/&\t0755\t0 0,g'
|
|
find "lib/modules/$KERNEL" -type f |sed -e "s,^.\+$,file\t/&\t$WORKDIR/&\t0644\t0 0,g"
|
|
echo "$FILES"
|
|
) > "$TEMPLATE"
|
|
|
|
if [ -n "$OUTPUT" ]; then
|
|
gencpio "$TEMPLATE" |gzip -c > "$OUTPUT"
|
|
else
|
|
gencpio "$TEMPLATE" |gzip -c
|
|
fi
|
|
|
|
if [ -s "$pattern" ]; then
|
|
for m in `grep -v '#' "$pattern" | sort -u`; do
|
|
name="${m##*/}"
|
|
name="${name%.gz}"
|
|
name="${name%.xz}"
|
|
name="${name%.ko}"
|
|
# Omit built-in modules whose names match in modprobe output and in "pattern"
|
|
ListModuleFiles "$name" | grep "builtin" | grep -q "$name" 2>/dev/null && continue
|
|
echo "$MODULES" | grep -qw "$m" 2>/dev/null || Warning "Module pattern \"$m\" doesn't match anything."
|
|
done
|
|
fi
|
|
|
|
Exit 0
|