#!/bin/sh
#
# Start all arrays specified in the configuration file.
#
# Copyright © 2001-2005 Mario Jou/3en <joussen@debian.org>
# Copyright © 2005-2008 Martin F. Krafft <madduck@debian.org>
# Distributable under the terms of the GNU GPL version 2.
#
### BEGIN INIT INFO
# Provides:          mdadm-raid
# Required-Start:    mountkernfs hostname
# Should-Start:      udev multipath-tools-boot
# X-Start-Before:    checkfs mountall
# Required-Stop:     mountkernfs
# Should-Stop:       udev
# X-Stop-After:      umountfs
# Default-Start:     S
# Default-Stop:      0 6
# Short-Description: MD array assembly
# Description:       This script assembles a system's MD arrays, according to
#                    the settings in /etc/mdadm/mdadm.conf and the preferences
#                    in /etc/default/mdadm.
### END INIT INFO
#
set -eu

MDADM=/sbin/mdadm
CONFIG=/etc/mdadm/mdadm.conf
ALTCONFIG=/etc/mdadm.conf
DEBIANCONFIG=/etc/default/mdadm

test -x "$MDADM" || exit 0

STATEDIR=/run/mdadm
test -f $DEBIANCONFIG && . $DEBIANCONFIG

. /lib/lsb/init-functions

short_dev()
{
  local dev; dev=${1##*/}
  case "$dev" in
    md*|md_*|mdp*|mdp_*) echo "$dev";;
    d*) echo "md_${dev}";;
    *) echo "md${dev}";;
  esac
}

log()
{
  case "$1" in
    [[:digit:]]*) success=$1; shift;;
    *) :;;
  esac
  log_action_begin_msg "$1"; shift
  log_action_end_msg ${success:-0} "$*"
}

log_dev()
{
  success=${1:-}; shift
  dev=${1:-}; shift
  log $success "${PREFIX:-} $(short_dev ${dev:-})" "$*"
}

log_notice()
{
  log 0 "${PREFIX:-}s" "$*"
}

log_problem()
{
  log 1 "${PREFIX:-}s" "$*"
}

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

case "${1:-}" in

  start)
    PREFIX="Assembling MD array"

    if [ ! -f /proc/mdstat ] && [ -x "$(command -v modprobe)" ] ; then
      modprobe -q md 2>/dev/null || :
    fi
    if [ ! -f /proc/mdstat ]; then
      log_problem "failed to load MD subsystem"
      exit 0
    fi

    if [ ! -f $CONFIG -a ! -f $ALTCONFIG ]; then
      log_problem "no $CONFIG file"
      exit 0
    fi

    # handle devfs-style names and version-1 devices
    # fail gracefully in case we're on a read-only filesystem, in which
    # case it's safe to assume that the admin knows what s/he's doing.
    # See (#382876).
    mkdir --parent /dev/md || :

    # ugly hack because shell sucks
    IFSOLD=${IFS:-}
    IFS='
'
    for line in $($MDADM --assemble --scan --auto=yes --symlink=no 2>&1); do
      IFS=$IFSOLD
      set -- $line
      shift

      case "$@" in

        'No arrays found in config file'*)
          # no point in carrying on.
          shift
          log_notice "no $*"
          exit 0
          ;;

        'Unknown keyword'*)
          # warn only
          if [ -x $(command -v logger >/dev/null) ]; then
            logger -t mdadm -p syslog.warning -- "$*"
          elif [ -w /dev/console ]; then
            echo "mdadm: $*" > /dev/console
          else
            echo "mdadm: $*" >&2
          fi
          ;;

        *' is already active.')
          log_dev 0 $1 "already running"
          ;;

        *'has been started with '[[:digit:]]*' drive'*' (out of '[[:digit:]]*') and '[[:digit:]]*' spare'*'.')
          log_dev 0 $1 "initialising [$6/${10%).}]"
          ;;

        *'has been started with '[[:digit:]]*' drive'*' (out of '[[:digit:]]*').')
          log_dev 0 $1 "degraded [$6/${10%).}]"
          ;;

        *'has been started with '[[:digit:]]*' drive'*'.')
          log_dev 0 $1 "started [$6/$6]"
          ;;

        *'assembled from '[[:digit:]]*' drive'*' - not enough to start the array.')
          log_dev 1 $1 "not enough devices"
          ;;

        'no devices found for '*)
          log_dev 1 $5 "no devices found"
          ;;

        'failed to RUN_ARRAY '*': Input/output error')
          log_dev 1 ${4%:} "RUN_ARRAY input/output error"
          ;;

        *) :;;
      esac
    done
    ret=$?

    log_action_begin_msg "Generating udev events for MD arrays"
    [ -d $STATEDIR ] || mkdir -p $STATEDIR
    for uevent in /sys/block/md*/uevent; do
      test -e $uevent || break
      sentinel=${uevent#/sys/block/}; sentinel=${sentinel%/uevent}-uevent
      test -e $STATEDIR/$sentinel && continue
      test -w $uevent || continue
      echo add > $uevent
      test -d $STATEDIR && : > $STATEDIR/$sentinel
    done
    log_action_end_msg 0

    exit $ret
    ;;

  stop)
    PREFIX="Stopping MD array"

    if [ ! -f /proc/mdstat ]; then
      log_problem "no MD subsystem loaded"
      exit 0
    fi

    # ugly hack because shell sucks
    IFSOLD=${IFS:-}
    IFS='
'
    set +e
    for line in $($MDADM --stop --scan 2>&1); do
      set -e
      IFS=$IFSOLD
      set -- $line
      shift
      case "$@" in

        'Unknown keyword'*)
          # warn only
          if [ -x $(command -v logger >/dev/null) ]; then
            logger -t mdadm -p syslog.warning -- "$*"
          elif [ -w /dev/console ]; then
            echo "mdadm: $*" > /dev/console
          else
            echo "mdadm: $*" >&2
          fi
          ;;

        'stopped '*)
          log_dev 0 $2 stopped
          ;;

        'fail to stop array '*': Device or resource busy')
          log_dev 1 ${5%:} busy
          ;;

        *) :;;
      esac
    done || exit $?

    rm -f $STATEDIR/md*-uevent
    ;;

  restart|force-reload)
    ${0:-} stop
    ${0:-} start
    ;;

  reload)
    PREFIX="Reloading MD array"
    log_notice "never anything to do"
    ;;

  status)
    if [ ! -f /proc/mdstat ]; then
      log_problem "no MD subsystem loaded"
      exit 1
    else
      cat /proc/mdstat
    fi
    ;;

  *)
    echo "Usage: ${0:-} {start|stop|restart}" >&2
    exit 1;;

esac

exit 0
