#!/bin/sh
#
# Copyright © 2006-2008 Martin F. Krafft <madduck@debian.org>,
#             2012 Michael Tokarev <mjt@tls.msk.ru>
# based on the scripts in the initramfs-tools package.
# released under the terms of the Artistic Licence.
#
set -eu

PREREQ=
prereqs()
{
  echo "$PREREQ"
}

case "${1:-}" in
  prereqs)
    prereqs
    exit 0
    ;;
esac

is_true()
{
  case "${1:-}" in
    [Yy]es|[Yy]|1|[Tt]rue|[Tt]) return 0;;
    *) return 1;;
  esac
}

write()
{
  local PREFIX; PREFIX=$1; shift
  echo "${PREFIX}: mdadm: $@" >&2
}

info()
{
  is_true ${VERBOSE:-false} && write I "$@" || :
}

warn()
{
  write W "$@"
}

err()
{
  write E "$@"
}

MDADM=/sbin/mdadm
MDMON=/sbin/mdmon
[ -x "$MDADM" ] || exit 0

[ -r /usr/share/initramfs-tools/hook-functions ] || exit 0
. /usr/share/initramfs-tools/hook-functions

# copy the binary as early as possible
copy_exec $MDADM /sbin
copy_exec $MDMON /sbin

# copy all modules into the initramfs, just for safety.
# we copy raid456 / raid5+raid6 because the hook script just won't do
# anything when the module cannot be found.
modules="linear multipath raid0 raid1 raid456 raid5 raid6 raid10"
for mod in $modules; do manual_add_modules $mod; done

# read in the configuration
CONFIG=/etc/mdadm/mdadm.conf
ALTCONFIG=/etc/mdadm.conf
[ ! -f $CONFIG ] && [ -f $ALTCONFIG ] && CONFIG=$ALTCONFIG || :

DEBIANCONFIG=/etc/default/mdadm
INITRDSTART=all
[ -s $DEBIANCONFIG ] && . $DEBIANCONFIG
[ -z "$INITRDSTART" ] && INITRDSTART=none

DESTMDADMCONF=$DESTDIR/etc/mdadm/mdadm.conf
DESTCONFIG=$DESTDIR/conf/mdadm

if [ -f $CONFIG ]; then
  homehost="$(sed -ne 's,^[[:space:]]*HOMEHOST[[:space:]]*,,p' $CONFIG)"
fi
if [ -z "${homehost:-}" ] || [ "${homehost:-}" = '<system>' ]; then
  echo "MD_HOMEHOST='$(hostname)'" > $DESTCONFIG
fi

install_config()
{
  # install the configuration file
  mkdir -p ${2%/*}
  # only copy ARRAY/DEVICE/HOMEHOST lines, and merge continuation lines into one
  if [ -f "$1" ] ; then
    sed -e :a -re '$!N;s/\n[[:space:]]+/ /;ta' -ne '/^(ARRAY|DEVICE|HOMEHOST)/P;D' $1 > $2
  fi
}

if [ ! -f $CONFIG ]; then
  # there is no configuration file, so let's create one

  if /usr/share/mdadm/mkconf generate $CONFIG; then
    # all is well
    install_config $CONFIG $DESTMDADMCONF
    info "auto-generated the mdadm.conf configuration file."
  else
    # we failed to auto-generate, so let the emergency procedure take over
    warn "failed to auto-generate the mdadm.conf file."
  fi

else

  if grep -q '^ARRAY' $CONFIG; then

    # this is the ideal case
    install_config $CONFIG $DESTMDADMCONF
    info "using configuration file: $CONFIG"

  else

    # the file defines no ARRAYs. We better create a temporary file to be sure.

    warn "$CONFIG defines no arrays."

    mkdir --parents ${DESTMDADMCONF%/*}
    tmpfile="${DESTMDADMCONF}.tmp"
    if /usr/share/mdadm/mkconf > $tmpfile; then
      # all is well, we now have a temporary configuration file
      info "auto-generated temporary mdadm.conf configuration file."
      install_config $tmpfile $DESTMDADMCONF
    else
      # stuff's really broke, as we failed to generate a temporary file.
      # let's hope the unchecked file works, provided it contains at least one
      # ARRAY statement...
      warn "failed to auto-generate temporary mdadm.conf file."
      if grep -q '^ARRAY' $CONFIG; then
        warn "using the unchecked file and hoping for the best..."
        install_config $CONFIG $DESTMDADMCONF
      fi
    fi
    rm -f $tmpfile

  fi

fi

# if at this point, $DESTMDADMCONF does not exist or it does not contain any
# ARRAY statements, we must let the initramfs handle stuff.
if [ ! -f $DESTMDADMCONF ]; then
  warn "no configuration file available."
  info "letting initramfs assemble auto-detected arrays."
  exit 0
elif ! grep -q '^ARRAY' $DESTMDADMCONF; then
  warn "no arrays defined in configuration file."
  info "letting initramfs assemble auto-detected arrays."
  exit 0
else
  # obtain devices list from config file, honouring multiline entries
  devices="$(
    dev=
    while read line; do
      case "$line" in
        (ARRAY*) :;;
        (*) continue;;
      esac
      for atom in $line; do
        case "$atom" in
          (/dev*) dev=$atom;;
        esac
      done

      # /dev/mdX and /dev/md/X are the same, really
      case "$dev" in
        "") continue ;;
        (/dev/md/*) alt=/dev/md${dev##*/};;
        (/dev/md*) alt=/dev/md/${dev#/dev/md};;
        (*)
          err "unknown device encountered: $dev"
          warn_emergency
          exit 0
          ;;
      esac
      if [ ! -b "$dev" ] && [ -b "$alt" ]; then
        dev="$alt"
      fi

      echo "$dev"
    done < $DESTMDADMCONF)" || exit $?
fi

if [ "$INITRDSTART" != none ] && [ -n "$devices" ]; then

  devs=
  for dev in $devices; do
    case "$INITRDSTART " in
      all|*${dev}[[:space:]]*)
        case "$devs " in	# uniquiness
          (*${dev}\ *) :;;
          (*) devs="${devs:+$devs }$dev" ;;
        esac
        ;;
      *) :;;
    esac
  done

  # make sure the configuration file knows about all running devices
  $MDADM --detail --scan | while read array device params; do
    uuid=${params#*UUID=}; uuid=${uuid%% *}
    if ! grep -qi "uuid=$uuid" $DESTMDADMCONF; then
      warn "the array $device with UUID $uuid"
      warn "is currently active, but it is not listed in mdadm.conf. if"
      warn "it is needed for boot, then YOUR SYSTEM IS NOW UNBOOTABLE!"
      warn "please inspect the output of /usr/share/mdadm/mkconf, compare"
      warn "it to $CONFIG, and make the necessary changes."
    fi
  done

  for i in $INITRDSTART; do
    case "$INITRDSTART" in all) break;; *) :;; esac
    case "$devs" in
      *${i}*) continue;;
      *) :;;
    esac

    warn "I am supposed to start $i from the initial ramdisk,"
    warn "yet I cannot find the array in the configuration file."
    warn "I am thus reverting to starting all arrays."
    INITRDSTART=all
    break
  done

  if [ "$INITRDSTART" = all ]; then
    echo "MD_DEVS=all" >> $DESTCONFIG
  else
    echo "MD_DEVS='$devs'" >> $DESTCONFIG
  fi

  if [ "$INITRDSTART" = all ]; then
    info "will start all available MD arrays from the initial ramdisk."
  else
    for i in $devs; do
      info "will start MD array $i from the initial ramdisk."
    done
  fi

  # Copy udev rules, which udev no longer does
  for rules_file in 63-md-raid-arrays.rules 64-md-raid-assembly.rules
  do
    for rules_folder in /lib/udev/rules.d /etc/udev/rules.d; do
      if [ -f $rules_folder/$rules_file ]; then
	  mkdir -p $DESTDIR$rules_folder
	  cp $rules_folder/$rules_file $DESTDIR$rules_folder/$rules_file
      fi
    done
  done

else
  echo "MD_DEVS=none" >> $DESTCONFIG
  info "no MD arrays will be started from the initial ramdisk."
fi

# only output this on Debian systems
[ -s /etc/default/mdadm ] && \
  info 'use `dpkg-reconfigure --priority=low mdadm` to change this.'

exit 0
