#!/bin/sh
# vi: ts=4 noexpandtab
# load modules
. ${CIRROS_LIB:=/lib/cirros/shlib_cirros} ||
	{ echo "failed to read ${CIRROS_LIB}" 1>&2; exit 1; }

get_fslist() {
	# set _RET to a list of currently supported filesystems
	# stdin should be /proc/filesystems (proc(5))
	local line="" fs="" tab='	'
	_RET=""
	while read line; do
		line=${line#nodev}
		line=${line#$tab}
		_RET="${_RET} $line"
	done
}

loadmods() {
	local mod="" mod_ubar="" fslist="" kver="" fails="" skip=""
	get_fslist </proc/filesystems || error "Failed to read filesystems."
	fslist=" $_RET "
	kver=$(uname -r)
	local builtins="" mbuiltin="/lib/modules/${kver}/modules.builtin"
	if [ -f "$mbuiltin" ]; then
		builtins=$(sed -e 's,.*/,,' -e 's/[.]ko$//' -e 's/-/_/g' "$mbuiltin")
		builtins=" $(echo $builtins) "
	fi
	while read mod; do
		[ -n "$mod" ] || continue
		skip=""
		replace "$mod" "-" "_"
		mod_ubar="$_RET"
		[ -d "/sys/module/${mod_ubar}" ] && skip="already loaded."
		if [ -z "$skip" ]; then
			case "${builtins}" in
				*\ ${mod_ubar}\ *) skip="builtin."
			esac
		fi
		if [ -z "$skip" ]; then
			case "$mod_ubar" in
				isofs)
					case "$fslist" in
						*\ iso9660\ *) skip="iso9660 fs already supported.";;
					esac
					;;
				# in Ubuntu vfat uses cp437 and iso8859-1
				vfat)
					case "$fslist" in
						*\ vfat\ *) skip="vfat fs already supported.";;
					esac
					;;
				# present in Linux 4.6+
				qemu_fw_cfg)
					kver_cmp "$kver" -lt 4.6 && skip="kernel $kver older than 4.6"
					;;
			esac
		fi
		if [ -n "$skip" ]; then
			debug 2 "not loading '$mod': $skip"
			continue
		fi
		modprobe $mod || fails="$fails $mod"
	done

	if [ -n "$fails" ]; then
		error "failed loading these modules: $fails"
		return 1
	fi
	local loaded=""
	loaded=$(awk '{print $1}' /proc/modules | sort | tr '\n' ' ')
	debug 0 "currently loaded modules: $loaded"
	return 0
}

parse_modules() {
	local f="$1" arch="$2" march="" comment="" modinfo="" oifs="$IFS"
	local x="" found=false
	[ -f "$f" ] || return 1
	case "$arch" in
		i?86) march=",i386,x86,";;
		amd64|x86_64) march=",x86_64,x86,";;
		ppc64|powerpc) march=",powerpc,ppc64,";;
		arm*) march=",arm,$arch,";;
		*) march=",$arch,";;
	esac
	while read line; do
		[ -n "$line" ] || continue
		modinfo=${line%%#*}
		[ -n "$modinfo" ] || continue
		[ "$modinfo" = "$line" ] && comment="" ||
			comment="${line#${modinfo}#}"
		[ "${comment#*arch=}" = "$comment" ] &&
			{ echo "$modinfo"; continue; }
		found=false
		for tok in $comment; do
			[ "${tok#arch=}" != "$tok" ] || continue
			IFS=","; set -- ${tok#arch=}; IFS="$oifs";
			[ $# -eq 0 ] && continue
			for x in "$@"; do
				[ "${march#*,$x,}" != "$march" ] &&
					{ echo "$modinfo"; found=true; break; }
				shift;
			done
			$found && break
		done
	done < "$f"
}

MODULES_FILE="/etc/modules"

case "$1" in
	start)
		lxc-is-container && exit 0
		if [ -f "$MODULES_FILE" ]; then
			[ -d "/lib/modules/$(uname -r)" ] || exit 0
			march=$(uname -m)
			parse_out=$(parse_modules "$MODULES_FILE" "$march") ||
				fail "Failed to parse modules"
			echo "${parse_out}" | loadmods ||
				fail "failed to load modules."
			if [ "$march" = "ppc64" ]; then
				sleep 1
			fi
		fi
		;;
	stop|restart|reload) : ;;
	parse_modules)
		parse_modules "$2" "$3";;
	*)
		echo $"Usage: $0 {start}"
		exit 1
esac

exit $?
