229 lines
4.6 KiB
Bash
229 lines
4.6 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
|
|
modprobe --set-version="$KERNEL" --list "$@" 2>/dev/null |grep -wf "$pattern"
|
|
else
|
|
modprobe --set-version="$KERNEL" --list "$@" 2>/dev/null
|
|
fi
|
|
}
|
|
|
|
ListModuleFiles()
|
|
{
|
|
modprobe --set-version="$KERNEL" --show-depends \
|
|
--ignore-all-commands "$@" 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%.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%.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."
|
|
|
|
#---------------------------------------------------------------
|
|
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
|
|
|
|
Exit 0
|