#!/bin/sh
#
#(C) Sergey Sergeev aka adron, 2019
#

. ./globals.sh

_kernel_bin_binwalk=""
kernel_bin_binwalk(){
	[ -z "${_kernel_bin_binwalk}" ] && \
		_kernel_bin_binwalk=$(binwalk ./bins/kernel.bin)
	echo "${_kernel_bin_binwalk}"
}
kernel_bin_binwalk_rawelf() {
	binwalk ./bins/kernel.bin --raw "\177ELF"
}

get_xz_offsets(){
	kernel_bin_binwalk | grep "xz compressed data" | sed -n 's/^\([0-9]\+\).*/\1/p'
}

get_file_size(){
	[ -f ${1} ] || {
		echo 0
		return 0
	}
	du -b ${1} | sed -e 's/\([0-9]\+\).*/\1/'
}

unpack_kernel_bin(){
	local xz_offsets
	local p_count=0
	local pred_offset
	local size
	local offset
	xz_offsets=$(get_xz_offsets)
	for offset in ${xz_offsets} 0; do
		#echo $offset
		[ -n "${pred_offset}" ] && {
			p_count=$((${p_count}+1))
			size=$((${offset}-${pred_offset}))
			[ ${offset} -eq 0 ] && size=104857600
			echo "$p_count - ${pred_offset} - ${size}"
			dd if=./bins/kernel.bin of=./bins/kernel.p${p_count}.xz bs=1 skip=${pred_offset} count=${size}
		}
		pred_offset=${offset}
	done
}

extract_kernel_elf(){
	local offsets
	local offset
	local kernel_elf_size=0
	local garbage_size=70
	offsets=`kernel_bin_binwalk | sed -n 's/ELF,//p' | sed -n 's/^\([0-9]\+\).*/\1/p'`
	local elf_last_offset
	local first_xz_offset
	[ -z  "${offsets}" ] && {
		echo "Warning: trying Raw ELF signatures search !"
		offsets=`kernel_bin_binwalk_rawelf | sed -n 's/Raw signature//p' | sed -n 's/^\([0-9]\+\).*/\1/p'`
		[ -z "${offsets}" ] && {
			echo "NO ELF offsets found in kernel.bin !!!"
			exit 100
		}
	}
	for offset in ${offsets}; do
		elf_last_offset=${offset}
	done
	[ -z "${elf_last_offset}" ] && {
		[ -z "${elf_last_offset}" ] &&	exit 100
	}
	[ -n "${elf_last_offset}" ] && {
		offsets=$(get_xz_offsets)
		for offset in ${offsets}; do
			first_xz_offset=${offset}
			break
		done
		echo "${elf_last_offset} - ${first_xz_offset}"
		#elf size without xz
		kernel_elf_size=$((${first_xz_offset}-${elf_last_offset}))
		local p
		local size
		for p in $(seq 1 3); do
			size=$(get_file_size ./bins/kernel.p${p}.xz)
			kernel_elf_size=$((${kernel_elf_size}+${size}))
		done
		#dd if=./bins/kernel.bin bs=1 skip=${elf_last_offset} of=./bins/kernel-all.elf
		dd if=./bins/kernel.bin bs=1 skip=${elf_last_offset} count=${kernel_elf_size} of=./bins/kernel.elf
		[ -f ./bins/p3-garbage.bin ] && {
			size=$(get_file_size ./bins/p3-garbage.bin)
			#some of this data may be related to the elf (for 64-bit kernels - RB5009, ...\)
			[ $size -gt $garbage_size ] && {
				offset=$((size-garbage_size))
				dd if=./bins/p3-garbage.bin bs=${offset} count=1 >> ./bins/kernel.elf
			}
		}
	}
}

truncate_kernel_p3(){
	local garbage_size
	local p3_size
	garbage_size=$(get_file_size ./bins/p3-garbage.bin)
	p3_size=$(get_file_size ./bins/kernel.p3.xz)
	dd if=./bins/kernel.p3.xz of=./bins/kernel.p3-stripped.xz bs=$((${p3_size}-${garbage_size})) count=1
	cat ./bins/kernel.p3-stripped.xz > ./bins/kernel.p3.xz
	rm ./bins/kernel.p3-stripped.xz
}

extract_kernel_cpiofs(){
	local ROOT=$(pwd)
	rm -Rf ./cpio-fs-${TARGET_ARCH}
	mkdir ./cpio-fs-${TARGET_ARCH}
	cd ./cpio-fs-${TARGET_ARCH}
	xzcat ${ROOT}/bins/kernel.p3.xz | cpio -idv
	cp ./init ./oldinit
}

#extract_kernel_elf
#unpack_kernel_bin
#exit 0

unpack_kernel_bin

( xz -dc --single-stream > ./bins/initramfs.cpio && cat > ./bins/p3-garbage.bin ) < ./bins/kernel.p3.xz
#do kerne.p3.xz fix(cut garbage)
[ -f ./bins/p3-garbage.bin ] && {
	truncate_kernel_p3
}

extract_kernel_elf

#if cpio-fs dir is empty
ls -1qA ./cpio-fs-${TARGET_ARCH}/ | grep -q . || \
extract_kernel_cpiofs
