#!/bin/sh
# geninitrd mod: mdadm
USE_MD=${USE_MD:-yes}

# if we should init md (softraid) at boot
have_md=no

# setup geninitrd module
# @access	public
setup_mod_md() {
	mdadm=$(find_tool /sbin/mdadm $initrd_dir/mdadm /sbin/initrd-mdadm)
	if [ ! -x "$mdadm" ]; then
		USE_MD=no
	fi
}

# return true if mdadm is set on $devpath
# @param	string $devpath device node to be examined
# @access	public
is_md() {
	local devpath="$1"

	# mdadm disabled
	if ! is_yes "$USE_MD"; then
		return 1
	fi

	if [[ "$devpath" == /dev/md* ]]; then
		return 0
	fi

	return 1
}

# find md modules for $devpath
# @param	$devpath	device to be examined
# @return	false if $devpath is not on md
# @access	public
find_modules_md() {
	local found raidlevel

	if [ -f /etc/mdadm.conf ]; then
		verbose "Finding RAID details using mdadm for rootdev=$1"
		eval `($mdadm -v --examine --scan --config=/etc/mdadm.conf 2> /dev/null;$mdadm -v --detail --scan --config=/etc/mdadm.conf 2> /dev/null) | awk -v rootdev="$1" '
		BEGIN {
			found = "no";
			dev_list = "";
			raidlevel = ""
			rootdev_new = rootdev
			rootdev_alias = rootdev;
			# alternative name: normalize from /dev/md/X to /dev/mdX
			if (rootdev_alias ~ /\/dev\/md\/[0-9]+/) {
				gsub(/\/dev\/md\//,"/dev/md",rootdev_alias);
			}
			# alternative name: normalize from /dev/mdXpY to /dev/mdX
			if (rootdev_alias ~/\/dev\/md[0-9]+p[0-9]+/) {
				gsub(/p[0-9]+/,"",rootdev_alias);
			}
		}

		/^ARRAY/ {
			arr_device = $2
			# normalize to /dev/mdX form
			if (arr_device ~ /\/dev\/md\/[0-9]+/) {
				gsub(/\/dev\/md\//,"/dev/md",arr_device);
			}
			if ((arr_device == rootdev) || (arr_device == rootdev_alias)) {
				raidlevel=$3;
				rootdev_new=arr_device
				gsub(/level=/,NUL,raidlevel);
				if (raidlevel ~ /^raid([0-6]|10)/) {
					gsub(/raid/,NUL,raidlevel);
				};
				found="yes";
				getline x;
				if (x ~ /devices=/) {
					dev_list = x;
					gsub(".*devices=", NUL, dev_list);
					gsub(",", " ", dev_list);
				}
			}
		}

		END {
			print "rootdev_new=" rootdev_new;
			print "have_md=" found;
			print "raidlevel=" raidlevel;
			print "dev_list=\"" dev_list "\"";
		}'`
	fi

	if [ "$have_md" != "yes" -a -f /etc/raidtab ]; then
		die "raidtools are not longer supported. Please migrate to mdadm setup!"
	fi

	if is_yes "$have_md"; then
		case "$raidlevel" in
		[01]|10)
			find_module "raid$raidlevel"
			;;
		[456])
			find_module "-raid$raidlevel"
			find_module "-raid456"
			;;
		linear)
			find_module "linear"
			;;
		*)
			warn "raid level $number (in mdadm config) not recognized"
			;;
		esac
	else
		die "RAID devices not found for \"$1\", check your configuration!"
	fi

	verbose "md: found rootdev=$1 on device $rootdev_new with devices list ${dev_list}"

	rootdev_nr=$(( $rootdev_nr + 1 ))
	eval "rootdev${rootdev_nr}=\"$rootdev_new\""
	eval "dev_list${rootdev_nr}=\"${dev_list}\""

	for device in $dev_list; do
		find_modules_for_devpath $device
	done
}


# generate initrd fragment for md
# @access	public
initrd_gen_md() {
	if ! is_yes "$have_md"; then
		return
	fi
	verbose "Setting up mdadm..."

	inst_exec $mdadm /sbin/mdadm

	echo "DEVICE partitions containers" >> "$DESTDIR/etc/mdadm.conf"

	# LVM on RAID case
	local dev_list_extra ex_dev
	dev_list_extra=$(awk '/^DEVICE / { for (i=2; i<=NF; i++) { printf "%s ", $i; }; } ' /etc/mdadm.conf | xargs)
	new_dev_list_extra=""
	for ex_dev in $dev_list_extra; do
		if [ "$ex_dev" = "partitions" -o "$ex_dev" = "containers" ]; then
			echo "DEVICE $ex_dev" >> "$DESTDIR/etc/mdadm.conf"
			# FIXME: find and copy partition devices from /proc/partitions
			#        - best if done at runtime, now initrd gen time
			continue
		fi
		echo "DEVICE $ex_dev" >> "$DESTDIR/etc/mdadm.conf"
		new_dev_list_extra="$new_dev_list_extra $ex_dev"
	done
	dev_list_extra=$new_dev_list_extra

	local cr_rootdev cr_dev_list do_md0=1 nr cr_dev_list_md f cr_md_conf
	for nr in `seq 1 $rootdev_nr`; do
		eval cr_rootdev="\$rootdev${nr}"
		eval cr_dev_list="\$dev_list${nr}"
		verbose "Setting up array ($cr_rootdev = $cr_dev_list)"

		[ "$cr_rootdev" = "/dev/md0" ] && do_md0=0

		echo "DEVICE $cr_dev_list" >> "$DESTDIR/etc/mdadm.conf"
		cr_dev_list_md="$(echo "$cr_dev_list" | xargs | awk ' { gsub(/ +/,",",$0); print $0; }')"
		cr_md_conf=$($mdadm --detail --brief --config=/etc/mdadm.conf $cr_rootdev | awk ' { gsub(/spares=[0-9]+/, "", $0); print $0; }')
		if [ -n "$cr_md_conf" ]; then
			echo "$cr_md_conf" >> "$DESTDIR/etc/mdadm.conf"
		else
			echo "ARRAY $cr_rootdev devices=$cr_dev_list_md" >> "$DESTDIR/etc/mdadm.conf"
		fi

		for f in $cr_dev_list $cr_rootdev $dev_list_extra; do
			# mkdir in case of devfs name
			inst_d $(dirname $f)
			[ -e "$DESTDIR/$f" ] && continue
			# this works fine with and without devfs
			inst $f $f
		done
	done

	echo "wait_for_files $cr_dev_list" | add_linuxrc
	add_linuxrc <<-'EOF'
	/sbin/mdadm --assemble --scan

	if [ "$DEBUGINITRD" ]; then
		[ -e /proc/mdstat ] && echo "/proc/mdstat contents:" && cat /proc/mdstat
	fi
	EOF

	# needed to determine md-version
	if [ "$do_md0" -eq 1 ]; then
		mknod -m 660 $DESTDIR/dev/md0 b 9 0
	fi
}
