# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Distributed under the terms of the GNU General Public License v2

EAPI=4
CROS_WORKON_PROJECT="chromiumos/platform/initramfs"
CROS_WORKON_LOCALNAME="../platform/initramfs"
CROS_WORKON_OUTOFTREE_BUILD="1"

inherit cros-workon cros-board

DESCRIPTION="Create Chrome OS initramfs"
HOMEPAGE="http://www.chromium.org/"

LICENSE="GPL-2"
SLOT="0"
KEYWORDS="~amd64 ~arm ~x86"
IUSE="netboot_ramfs"

DEPEND="chromeos-base/chromeos-assets
	chromeos-base/chromeos-assets-split
	chromeos-base/vboot_reference
	chromeos-base/vpd
	media-gfx/ply-image
	sys-apps/busybox[-make-symlinks]
	sys-apps/flashrom
	sys-apps/pv
	sys-fs/lvm2
	netboot_ramfs? ( chromeos-base/chromeos-installshim )"
RDEPEND=""

src_prepare() {
	local srcroot='/mnt/host/source'
	BUILD_LIBRARY_DIR="${srcroot}/src/scripts/build_library"

	# Need the lddtree from the chromite dir.
	local chromite_bin="${srcroot}/chromite/bin"
	export PATH="${chromite_bin}:${PATH}"
}

# doexe for initramfs
idoexe() {
	einfo "Copied: $*"
	lddtree \
		--verbose \
		--copy-non-elfs \
		--root="${SYSROOT}" \
		--copy-to-tree="${INITRAMFS_TMP_S}" \
		--libdir='/lib' \
		"$@" || die "failed to copy $*"
}

# dobin for initramfs
idobin() {
	idoexe --bindir='/bin' "$@"
}

# Special handling for futility wrapper. This will go away once futility is
# converted to a single binary.
idofutility() {
	local src base
	idobin "$@"
	for src in "$@"; do
		base=$(basename "${src}")
		mv -f "${INITRAMFS_TMP_S}/bin/${base}" \
			"${INITRAMFS_TMP_S}/bin/old_bins/${base}" ||
			die "Cannot mv: ${src}"
		ln -sf futility "${INITRAMFS_TMP_S}/bin/${base}" ||
			die "Cannot symlink: ${src}"
		einfo "Symlinked: /bin/${base} -> futility"
	done
}

# install a list of images (presumably .png files) in /etc/screens
insimage() {
	cp "$@" "${INITRAMFS_TMP_S}"/etc/screens || die
}

pull_initramfs_binary() {
	# For busybox and sh
	idobin /bin/busybox
	ln -s busybox "${INITRAMFS_TMP_S}/bin/sh"

	# For verified rootfs
	idobin /sbin/dmsetup

	# For message screen display and progress bars
	idobin /usr/bin/ply-image
	idobin /usr/bin/pv
	idobin /usr/sbin/vpd

	# /usr/sbin/vpd invokes 'flashrom' via system()
	idobin /usr/sbin/flashrom

	# For recovery behavior
	idobin /usr/bin/futility
	idofutility /usr/bin/old_bins/cgpt
	idofutility /usr/bin/old_bins/crossystem
	idofutility /usr/bin/old_bins/dump_kernel_config
	idofutility /usr/bin/old_bins/tpmc
	idofutility /usr/bin/old_bins/vbutil_kernel

	# PNG image assets
	local shared_assets="${SYSROOT}"/usr/share/chromeos-assets
	insimage "${shared_assets}"/images/boot_message.png
	insimage "${S}"/assets/spinner_*.png
	insimage "${S}"/assets/icon_check.png
	insimage "${S}"/assets/icon_warning.png
	${S}/make_images "${S}/localized_text" \
					 "${INITRAMFS_TMP_S}/etc/screens" || die
}

pull_netboot_ramfs_binary() {
	# We want to keep GNU sh at /bin/sh, so let's change shebang for init
	# to busybox explicitly.
	sed -i '1s|.*|#!/bin/busybox sh\nset -x|' "${INITRAMFS_TMP_S}/init" || die

	# Busybox and utilities
	idobin /bin/busybox
	local bin_name
	local busybox_bins=(
		awk
		basename
		cat
		chmod
		chroot
		cp
		cut
		date
		dirname
		expr
		find
		grep
		gzip
		head
		id
		ifconfig
		mkdir
		mkfs.vfat
		mktemp
		modprobe
		mount
		rm
		rmdir
		route
		sed
		sleep
		stty
		sync
		tee
		tr
		true
		udhcpc
		umount
		uname
		uniq
	)
	for bin_name in ${busybox_bins[@]}; do
		ln -s busybox "${INITRAMFS_TMP_S}/bin/${bin_name}" || die
	done

	# Factory installer
	idobin /usr/sbin/factory_install.sh
	idobin /usr/sbin/chromeos-common.sh
	idobin /usr/sbin/netboot_postinst.sh
	idobin /usr/sbin/chromeos-install
	idobin /usr/sbin/ping_shopfloor.sh
	cp "${SYSROOT}"/usr/share/misc/shflags "${INITRAMFS_TMP_S}"/usr/share/misc

	# Binaries used by factory installer
	idobin /bin/bash
	idobin /bin/dd
	idobin /bin/sh
	idobin /bin/xxd
	idobin /sbin/blockdev
	idobin /sbin/fsck.vfat
	idobin /sbin/sfdisk
	idofutility /usr/bin/old_bins/cgpt
	idofutility /usr/bin/old_bins/crossystem
	idobin /usr/bin/futility
	idobin /usr/bin/getopt
	idobin /usr/bin/openssl
	idobin /usr/bin/uudecode
	idobin /usr/bin/wget
	idobin /usr/sbin/flashrom
	idobin /usr/sbin/htpdate
	idobin /usr/sbin/lightup_screen
	idobin /usr/sbin/partprobe
	ln -s "/bin/cgpt" "${INITRAMFS_TMP_S}/usr/bin/cgpt" || die

	# We don't need to display image. Create empty constants.sh so that
	# messages.sh doesn't freak out.
	touch "${INITRAMFS_TMP_S}/etc/screens/constants.sh"

	# Network support
	cp "${FILESDIR}"/udhcpc.script "${INITRAMFS_TMP_S}/etc" || die
	chmod +x "${INITRAMFS_TMP_S}/etc/udhcpc.script"

	# USB Ethernet kernel module
	USBNET_MOD_PATH=$(find "${SYSROOT}"/lib/modules/ -name usbnet.ko)
	[ -n "$USBNET_MOD_PATH" ] || die
	USBNET_DIR_PATH=$(dirname "${USBNET_MOD_PATH}")
	USBNET_INSTALL_PATH="${USBNET_DIR_PATH#${SYSROOT}}"
	mkdir -p "${INITRAMFS_TMP_S}/${USBNET_INSTALL_PATH}"
	while read module ; do
		cp -p "${module}" "${INITRAMFS_TMP_S}/${USBNET_INSTALL_PATH}/"
		einfo "Copied: ${module#${SYSROOT}}"
	done < <(find "${USBNET_DIR_PATH}" -name '*.ko')

	# Generates lsb-factory
	LSBDIR="mnt/stateful_partition/dev_image/etc"
	GENERATED_LSB_FACTORY="${INITRAMFS_TMP_S}/${LSBDIR}/lsb-factory"
	SERVER_ADDR="${SERVER_ADDR-10.0.0.1}"
	BOARD="$(get_current_board_with_variant)"
	mkdir -p "${INITRAMFS_TMP_S}/${LSBDIR}"
	cat "${FILESDIR}"/lsb-factory.template | \
		sed "s/%BOARD%/${BOARD}/g" |
		sed "s/%SERVER_ADDR%/${SERVER_ADDR}/g" \
		>"${GENERATED_LSB_FACTORY}"
	ln -s "/$LSBDIR/lsb-factory" "${INITRAMFS_TMP_S}/etc/lsb-release"

	# Partition table
	cp "${SYSROOT}"/root/.gpt_layout "${INITRAMFS_TMP_S}"/root/
	cp "${SYSROOT}"/root/.pmbr_code "${INITRAMFS_TMP_S}"/root/

	# Generates write_gpt.sh
	INSTALLED_SCRIPT="${INITRAMFS_TMP_S}"/usr/sbin/write_gpt.sh
	BOARD=$(get_current_board_with_variant)
	. "${BUILD_LIBRARY_DIR}"/disk_layout_util.sh || die
	write_partition_script usb "${INSTALLED_SCRIPT}" || die

	# Install Memento updater
	idoexe '/opt/google/memento_updater/*'
}

build_initramfs_file() {
	local dir

	local subdirs=(
		bin
		bin/old_bins
		dev
		etc
		etc/screens
		lib
		log
		newroot
		proc
		root
		stateful
		sys
		tmp
		usb
		usr/bin
		usr/sbin
		usr/share/misc
	)
	for dir in ${subdirs[@]}; do
		mkdir -p "${INITRAMFS_TMP_S}/$dir" || die
	done

	# On amd64, shared libraries must live in /lib64.  More generally,
	# $(get_libdir) tells us the directory name we need for the target
	# platform's libraries.  The 'copy_elf' script installs in /lib; to
	# keep that script simple we just create a symlink to /lib, if
	# necessary.
	local libdir=$(get_libdir)
	if [ "${libdir}" != "lib" ]; then
		ln -s lib "${INITRAMFS_TMP_S}/${libdir}"
	fi

	# Copy source files not merged from our dependencies.
	cp "${S}"/init "${INITRAMFS_TMP_S}/init" || die
	chmod +x "${INITRAMFS_TMP_S}/init"
	cp "${S}"/*.sh "${INITRAMFS_TMP_S}/lib" || die

	if use netboot_ramfs; then
		pull_netboot_ramfs_binary
	else
		pull_initramfs_binary
	fi

	# The kernel emake expects the file in cpio format.
	( cd "${INITRAMFS_TMP_S}"
	  find . | cpio -o -H newc |
		xz -9 --check=crc32 > \
		"${WORKDIR}/${INITRAMFS_FILE}" ) ||
		die "cannot package initramfs"
}

src_compile() {
	INITRAMFS_TMP_S=${WORKDIR}/initramfs_tmp
	if use netboot_ramfs; then
		INITRAMFS_FILE="netboot_ramfs.cpio.xz"
	else
		INITRAMFS_FILE="initramfs.cpio.xz"
	fi

	einfo "Creating ${INITRAMFS_FILE}"
	build_initramfs_file
	INITRAMFS_FILE_SIZE=$(stat --printf="%s" "${WORKDIR}/${INITRAMFS_FILE}")
	einfo "${INITRAMFS_FILE}: ${INITRAMFS_FILE_SIZE} bytes"
}

src_install() {
	insinto /var/lib/misc
	doins "${WORKDIR}/${INITRAMFS_FILE}"
}