#!/bin/ash
# Split Fatdog "humoungous initrd" into small initrd and base sfs
# Copyright James Budiono 2012, 2013, 2016-2019
# License: GNU GPL Version 3 or later
#
# $1-initrd, $2-outputdir, $3-tmpdir, $4-basesfs-default-path, $5-base-sfs
#
# Jan 2018 - step: support early microcode update; gettexting

### configuration
TEXTDOMAIN=fatdog OUTPUT_CHARSET=UTF-8
export TEXTDOMAIN OUTPUT_CHARSET
. gettext.sh
# modules required for initrd (apart from MIN_MODULES)
BASE_MODULES="cryptoloop nbd cifs aufs usb-storage ohci uhci ehci xts hid-generic \
dm-crypt dm-snapshot sg crypto_simd cryptd glue_helper algif_skcipher af_alg" 
MODULE_SFS=kernel-modules.sfs
BASE_SFS=fd64.sfs
KERNEL_MODULE_COMPRESSION=${KERNEL_MODULE_COMPRESSION:-'-comp xz'}
BASESFS_COMPRESSION=${BASESFS_COMPRESSION:-'-comp gzip -Xcompression-level 4'}
[ "$BOOTSTATE_PATH" ] && . $BOOTSTATE_PATH   			# BASE_SFS_PATH
[ "$BASE_SFS_PATH" ] && BASE_SFS=${BASE_SFS_PATH##*/}	# updated by $5

### runtime variables
INITRD=$1
OUTPUTDIR=$2
TMPDIR=/tmp # updated by $3
BASE_SFS_DEFAULT_PATH=$4
[ "$5" ] && BASE_SFS="${5##*/}"

#INITRD=iso-root/initrd
#OUTPUTDIR=x

### update BASE_MODULES with list of required modules and their dependencies
# input: $1-BASE_MODULES, $2-MODULES_DEP returns: updated BASE_MODULES
get_modules_dep() {
	local OLD_MODULES GREP_PARAM MODULES_DEP
	BASE_MODULES=$1 MODULES_DEP=$2
	while [ ! "$OLD_MODULES" = "$BASE_MODULES" ]; do
		OLD_MODULES=$BASE_MODULES
		get_grep_param $BASE_MODULES
		set -- $(grep -E "$GREP_PARAM" $MODULES_DEP)
		while [ $1 ]; do
			case $1 in
				*:) ;;
				*)	new=${1##*/}; new=${new%.ko}; 
					case $BASE_MODULES in 
						*$new*) ;;
						*) BASE_MODULES="$BASE_MODULES $new"
					esac ;;
			esac
			shift
		done
	done
}
# $*-modules, returns GREP_PARAM
get_grep_param() {
	GREP_PARAM=
	while [ $1 ]; do
		GREP_PARAM="$GREP_PARAM|/$1.ko:"
		shift
	done
	GREP_PARAM=${GREP_PARAM#|}
}

abort_abort_abort() {
	echo "$1"
	cd "$CWD"
	rm -rf $INITRD_EXTRACT
	exit 1
}

############ main ############
# 1. initialise working variables
[ $(id -u) -ne 0 ] && echo "$(gettext "You must be root to use this.")" && exit
! [ "$INITRD" -a "$OUTPUTDIR" ] && echo "$(gettext "Usage"): $0 source-initrd output-dir [tmpdir] [basesfs-default-path] [base-sfs]" && exit
[ "$3" ] && TMPDIR=$(readlink -f "$3")
INITRD=$(readlink -f "$INITRD")
OUTPUTDIR=$(readlink -f "$OUTPUTDIR")
[ ! -e "$INITRD" ] && echo "$(gettext "initrd does not exist")" && exit
[ ! -e "$OUTPUTDIR" ] && mkdir -p "$OUTPUTDIR"
CWD=$(pwd)

# 2. unpack initrd
INITRD_EXTRACT=$(mktemp -dp $TMPDIR initrd-XXXXXXXX)
cd $INITRD_EXTRACT

case $(file -b --mime-type "$INITRD") in
	*gzip) TYPE="gzip" && zcat "$INITRD" | cpio -i ;;
	*xz) TYPE="xz" && xzcat "$INITRD" | cpio -i ;;
	*bzip2) TYPE="bzip2" && bzcat "$INITRD" | cpio -i ;;
	*) TYPE="none" && cat "$INITRD" | cpio -i ;;
esac || exit

# 3. extract kernel modules
[ -e $INITRD_EXTRACT/$MODULE_SFS ] || abort_abort_abort "$(eval_gettext "Cannot find \$MODULE_SFS in initrd, exiting.")"
MODULE_EXTRACT=$(mktemp -dp $TMPDIR module-XXXXXXXX); rmdir $MODULE_EXTRACT
unsquashfs -d $MODULE_EXTRACT $INITRD_EXTRACT/$MODULE_SFS
rm $INITRD_EXTRACT/$MODULE_SFS

# 4. extract base sfs (can't append directly - too bad :( - means we need more space)
[ -e $INITRD_EXTRACT/$BASE_SFS ] || abort_abort_abort "$(eval_gettext "Cannot find \$BASE_SFS in initrd, exiting.")"
BASE_EXTRACT=$(mktemp -dp $TMPDIR base-XXXXXXXX); rmdir $BASE_EXTRACT
unsquashfs -d $BASE_EXTRACT $INITRD_EXTRACT/$BASE_SFS
rm $INITRD_EXTRACT/$BASE_SFS

# 5. merge them
cp -af $MODULE_EXTRACT/* $BASE_EXTRACT

# 6. depmod the new base sfs
KERNEL_VERSION=$(ls $MODULE_EXTRACT/lib/modules)
depmod -a -b $BASE_EXTRACT $KERNEL_VERSION

# 7. repack base sfs - straight to target
rm -f "$OUTPUTDIR/$BASE_SFS"
mksquashfs $BASE_EXTRACT "$OUTPUTDIR/$BASE_SFS" $BASESFS_COMPRESSION
rm -rf $BASE_EXTRACT

# 7. delete all modules except what we need
# 7.1 get all modules and their dependencies
get_modules_dep "$BASE_MODULES" $(echo $MODULE_EXTRACT/lib/modules/*/modules.dep)
#echo $BASE_MODULES

# 7.2 convert this to find params
FIND_PARAM=""
for p in $BASE_MODULES; do
	FIND_PARAM="$FIND_PARAM -a ! -name $p.ko"
done
FIND_PARAM=${FIND_PARAM#*-a}

# 7.3 clean it - except the files we need
find $MODULE_EXTRACT/* \( -type f $FIND_PARAM -o -type l \) -delete
find $MODULE_EXTRACT/* -type d -empty -delete

# 8. depmod then repack module sfs
depmod -a -b $MODULE_EXTRACT $KERNEL_VERSION
mksquashfs $MODULE_EXTRACT $INITRD_EXTRACT/$MODULE_SFS $KERNEL_MODULE_COMPRESSION
rm -rf $MODULE_EXTRACT

# 9. change default base_sfs from "initrd" to "local" so that it will search basesfs on local drives
#    while we're at it, increase the default delay to 5 seconds too
sed -i -e '
s/BASE_SFS_DEFAULT=initrd/BASE_SFS_DEFAULT=local/
s/DEFAULT_DEVICE_DELAY=0/DEFAULT_DEVICE_DELAY=5/
' $INITRD_EXTRACT/sbin/system-init 
[ $BASE_SFS_DEFAULT_PATH ] &&
sed -i -e "
s|BASE_SFS_DEFAULT_PATH=.*|BASE_SFS_DEFAULT_PATH=$BASE_SFS_DEFAULT_PATH|
" $INITRD_EXTRACT/sbin/system-init 

# 10. repack initrd - don't compress it due to early microcode update and fatdog*-installer.sh
cd $INITRD_EXTRACT
find . | cpio -o -H newc > "$OUTPUTDIR/initrd"

# 11. final cleanup
cd "$CWD"
rm -rf $INITRD_EXTRACT  
#rox -d "$OUTPUTDIR"

