#!/bin/sh
#
# Start all arrays specified in the configuration file.
#
# Copyright © 2001-2005 Mario Jou/3en <joussen@debian.org>
# Copyright © 2005-2006 Martin F. Krafft <madduck@debian.org>
# Distributable under the terms of the GNU GPL version 2.
#
# $Id: mdadm-raid 290 2006-12-19 08:18:50Z madduck $
#
### BEGIN INIT INFO
# Provides:          mdadm-raid
# Required-Start:    mountkernfs
# Should-Start:      udev devfsd
# Required-Stop:     mountkernfs
# Should-Stop:       udev devfsd
# 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

AUTOSTART=true
test -f $DEBIANCONFIG && . $DEBIANCONFIG

. /lib/lsb/init-functions

short_dev()
{
  local 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
}

for dir in /lib/init/rw /dev/shm /dev; do
  statedir=$dir/.mdadm
  test -d $statedir && STATEDIR=$statedir && break
  test -w $dir || continue
  mkdir $statedir || continue
  STATEDIR=$statedir
  break
done

case "${1:-}" in
  start)
    PREFIX="Assembling MD array"

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

      if [ -f $CONFIG ] || [ -f $ALTCONFIG ]; then
        # 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_problem "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:]]*' drives.')
              log_dev 0 $1 "started [$6/$6]"
              ;;

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

            *'assembled from '[[:digit:]]*' drive's#' - 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"
        for uevent in /sys/block/md*/uevent; do
          sentinel=${uevent#/sys/block/}; sentinel=${sentinel%/uevent}-uevent
          test -e ${STATEDIR:-/doesnotexist}/$sentinel && continue
          test -w $uevent || continue
          echo add > $uevent
          test -d "${STATEDIR:-}" && : > $STATEDIR/$sentinel
        done
        log_action_end_msg 0

        [ $ret -ne 0 ] && exit $ret

      else
        log_problem "no $CONFIG file"
      fi
    else
      log_notice "disabled in $DEBIANCONFIG"
    fi
    ;;

  stop)
    PREFIX="Stopping MD array"

    if is_true $AUTOSTART; then
      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 -rf ${STATEDIR:-}

    else
      log_notice "disabled in $DEBIANCONFIG"
    fi
    ;;

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

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

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

esac

exit 0
