#!/bin/sh

# Copyright C 2002-2011 by Isilon Systems LLC. All rights not expressly
# granted herein are reserved.
# Created in the United States of America.
# 
# This digital media is protected by U.S. and international copyright and
# intellectual property laws. Unless otherwise specified, all information
# and screens appearing as part of this digital medium, including
# software, services, documents, text, images, icons, and logos design;
# the selection, assembly, arrangement, and design thereof; and the code
# that enables its presentation, are the sole property of Isilon Systems,
# Inc.
# 
# Except as otherwise required by applicable law, no part of any
# copyrighted material may be reproduced, modified, translated,
# distributed, published, or transmitted by any means, electronic or
# mechanical, for any purpose, without the prior written consent of Isilon
# Systems. 
#  
# Isilon and Isilon Systems are registered trademarks of Isilon Systems,
# Inc.  Legion is a trademark of Isilon Systems, Inc.  All other
# trademarks and registered trademarks are the property of their
# respective holders.

. /etc/rc.subr

TIMEOUT=30

preserve_diagnostics=0

usage()
{
    cat <<EOF
   usage: isi_reformat_node [-fhprP] [--nolkg] [--factory]

                    -f|yes: Force, do not prompt
                 -h|--halt: Halt when finished
             -p|--poweroff: Poweroff when finished (default for --factory)
               -r|--reboot: Reboot when finished (default unless --factory)
                   --nolkg: Skip copy to LKG
                 --factory: Factory reset (removes hardware specific files as well)
 -P|--preserve-diagnostics: Don't clean /var/log, /var/crash, etc.
EOF
    exit $1
}

while [ -n "$1" ]; do
    case $1 in
	yes|-f)
	    prompt=false ;;
	-P|--preserve-diagnostics)
	    preserve_diagnostics=1;;
	-h|--halt)
	    shutdown_opt="-h" ;;
	-p|--poweroff)
	    shutdown_opt="-p" ;;
	-r|--reboot)
	    shutdown_opt="-r" ;;
	-nolkg|--nolkg)
	    nolkg=true ;;
	--factory)
	    factory=true ;
	    shutdown_opt=${shutdown_opt:--p} ;;
	--help)
	    usage 0 ;;
	*)
	    usage 1 ;;
    esac
    shift
done

# Exit if running from within /ifs; Bug 79790
echo $PWD | grep -qe '^/ifs'
if [ $? -eq 0 ]; then
    echo "Unable to run if current working directory is in /ifs."
    echo "Change directory to / and try again."
    exit
fi

if ${prompt:-true}; then

    if ${factory:-false}; then
	echo "Reformatting node, restoring factory settings, and destroying"
        echo "filesystem."
	echo ""
	echo "*****"
	echo "The node will be prepared for shipping and will turn itself off."
	echo "Do not power the node back on until it has reached its destination,"
	echo "or you'll need to run 'isi_reformat_node --factory' again."
	echo "*****"
    else
	echo "Reformatting node and destroying filesystem"
    fi
    echo -n "Are you sure (yes/no) [no]? "
    read -t ${TIMEOUT} ANSWER
    if [ "${ANSWER:=no}" != "yes" ]; then
	echo "Quit without reformat"
	exit;
    fi

    ANSWER=no
    echo ""
    echo "This could destroy data"
    echo -n "Are you really sure (yes/no) [no]? "
    read -t ${TIMEOUT} ANSWER
    if [ "${ANSWER:=no}" != "yes" ]; then
	echo "Quit without reformat"
	exit;
    fi
fi

if ! ${nolkg:-false}; then
    isi_lkg_create
    if [ $? != 0 ]; then
	/usr/bin/isi_hwtools/isi_hal_predicate isVirtualSeries > /dev/null 2>&1
	is_virtual_series=$?
	if [ ${is_virtual_series} -eq 1 ]; then
	    echo "Your virtual machine has too few drives to create an lkg."
	else
	    echo "Failed to create lkg. Quit without reformat"
	    exit
	fi
    fi
fi

if ${factory:-false}; then
    # Check any SSD drives for wear
    /usr/sbin/isi_check_ssd_wear
    if [ $? != 0 ]; then
    	echo "*****"
	echo "Factory reset aborted."
	echo "Node contains one or more SSD drives that are too far worn,"
	echo "or are reporting wear monitoring related errors."
	echo "Once situation is remedied, you will need to "
	echo "run 'isi_reformat_node --factory' again."
    	echo "*****"
	exit;
    fi
fi

# Point of no return.  Mark that we are actually reseting
touch /etc/isi_resetting
touch /var/run/isi_resetting

# Turn off the alert led
/usr/bin/isi_hw_status ledalertoff

if [ -e /var/run/isi_mcp.pid ]; then
    /bin/kill -QUIT `cat /var/run/isi_mcp.pid`;
fi
if [ -e /var/run/isi_boot_d.pid ]; then
    /bin/kill -QUIT `cat /var/run/isi_boot_d.pid`;
fi

# Remove any override files
/bin/rm -f /etc/mcp/override/*
/bin/rm -f /etc/local/*

# Recreate /etc/sysctl.conf (in the same way the build made it)
install -c -o root -g 10 -m 660 /etc/mcp/templates/sysctl.conf /etc

#reset ldap
/etc/mcp/scripts/ldap.py /etc/mcp/sys/ldap.xml /etc/mcp/override/ldap.xml

#
# XXXNED: For bug 19696, we must kill any advisory lock waiters before
# unmount, or we'll deadlock.
#
/usr/sbin/isi_kill_busy

/sbin/umount -f -a -t efs 2> /dev/null
if [ -e /var/run/mountd.pid ]; then
    /bin/kill `cat /var/run/mountd.pid`
fi

# Reset the DON, if present. Ignored otherwise.
/usr/bin/isi_don_tool --reset

# On nodes that do not support Self Encrypting Drives (SEDs), fully format
# all of the OneFS partitions and initialize drives.xml. Note that this 
# needs to happen before we erase all the /etc/ifs/*.xml* files.
#
# On nodes that do support SEDs, release ownership of the SEDs and wipe 
# the drives, but DO NOT format for OneFS. We'll delay taking ownership
# of the drives until the next boot. 
JOURNALBACKUP=$(/usr/sbin/isi_bootdisk_provider_dev PROVIDER_ID_JOURNAL_BACKUP)
if [ "$?" -eq "0" ]; then
    newfs $JOURNALBACKUP
fi
/bin/rm -f /etc/ifs/drives.xml /etc/ifs/journal.xml /etc/ifs/node_status.gc
/usr/bin/isi_hwtools/isi_hal_predicate supportsSelfEncryptingDrives > /dev/null 2>&1
supports_self_encrypting_drives=$?
if [ ${supports_self_encrypting_drives} -eq 1 ]; then
    wipe_failed=0
    echo "Releasing all SEDs and wiping all user drives"
    /usr/sbin/isi_wipe_disk `isi_drivenum -D | awk '!/N\/A/ {printf("%s ", $0)}'`
    if [ "$?" -ne "0" ]; then
	# Report failure but ensure we destroy the old keystore
	echo "isi_wipe_disk has failed in isi_reformat_node"
	wipe_failed=1
	# FALLTHROUGH
    fi

    # Notify isi_post_shutdown so it doesn't attempt to lock the drives
    touch /etc/isi_keystore_unavailable

    # Shutdown the key manager
    retries=3
    echo "Stopping key manager before keystore reinit"
    stop_error=1
    while [ "$stop_error" -ne "0" ] && [ "$retries" -ne "0" ]
    do
        /usr/bin/isi_km_d stop
        stop_error=$?
        retries=$retries-1
    done

    if [ "$stop_error" -ne "0" ]; then
        echo "Failed to stop isi_km_d in isi_reformat_node"
    fi

    reinit_failed=0
    echo "Removing old and re-initializing new keystore"
    /usr/sbin/isi_keystore_reinit
    if [ "$?" -ne "0" ]; then
	# Report failure but check for exit conditions below
	echo "isi_keystore_reinit has failed in isi_reformat_node"
	reinit_failed=1
	# FALLTHROUGH
    fi

    # If either operation failed, we're done.
    if [ ${wipe_failed} -eq 1 ] || [  ${reinit_failed} -eq 1 ]; then
	exit 1
    fi
else
    /sbin/newfs_efs -f
    if [ "$?" -ne "0" ]; then
	echo "newfs_efs has failed in isi_reformat_node"
	exit 1
    fi
fi

# clean out /etc/ifs ...
# On nodes that do not support SEDs, save and restore drives.xml 
# and don't remove node_status.gc since they were both just created
# and brand new from the newfs_efs we just performed.
#
# On nodes that do support SEDs, just clean out /etc/ifs and don't 
# worry about saving anything.
if [ ${supports_self_encrypting_drives} -eq 0 ]; then
    /bin/mv /etc/ifs/drives.xml /etc/ifs/drives.save
    /bin/rm -f /etc/ifs/*.xml*
    /bin/mv /etc/ifs/drives.save /etc/ifs/drives.xml
else
    /bin/rm -f /etc/ifs/*.xml*
fi
/bin/rm -f /etc/ifs/journal_*
/bin/rm -f /etc/ifs/patchmgr/*.xml*
/bin/rm -f /etc/ifs/isi_*_already_ran
/bin/rm -f /etc/ifs/flexnetconfig.xml

# clean out any isi_join auto-join related files
/bin/rm -f /etc/ifs/isi_join_auto_*

# clean out roots zsh compiled files
/bin/rm -f /root/.zcompdump

# Use mcp to regenerate installed config files from just the base
/usr/sbin/isi_mcp -r > /dev/null 2> /dev/null

# Remove authentication files.
/bin/rm -f /usr/local/private/ifs_domain_acct
/bin/rm -f /usr/local/private/*secrets.tdb
/bin/rm -f /usr/local/private/smbpasswd

# Copy back the saved off defaults
/bin/rm -f /etc/*~
/bin/cp -p /etc/mcp/defaults/master.passwd /etc/master.passwd
/bin/cp -p /etc/mcp/defaults/group /etc/group
/bin/cp -p /etc/mcp/defaults/hosts /etc/hosts
/bin/cp -p /etc/mcp/defaults/fstab /etc/fstab
/bin/cp -p /etc/mcp/defaults/syslog.conf /etc/syslog.conf

# Regenerate the password file
/usr/sbin/pwd_mkdb -p -d /etc /etc/master.passwd

# Remove the exports file
echo "/ifs -alldirs -maproot=nobody:nobody:nogroup" > /etc/exports

# Regenerate the net-snmp configuration
/usr/sbin/snmpdctl stop > /dev/null
/usr/sbin/snmpdctl stopwait > /dev/null
/usr/sbin/snmpdctl isiconfigure > /dev/null

# Remove system files that ibootd creates to make a base state
/bin/rm -f /etc/resolv.conf
/bin/rm -f /etc/localtime

# wipe /var state files: history, logs, cron tabs, ...
for i in account at/jobs at/spool backups cron/tabs db/celog db/celog_master \
    db/entropy db/ipf empty heimdal ifs/alerts ifs/history mail msgs preserve \
    rwho ; do
    find /var/$i/ -type f -exec rm {} \;
done
# wipe gconfig's main cached config
/bin/rm -f /var/ifs/main_config.gc
/bin/rm -f /var/ifs/job_status.gc
/bin/rm -f /var/ifs/job_config.gc
/bin/rm -f /var/ifs/pstore.gc

# Preserve logs and cores for post-smart-fail analysis
if [ ${preserve_diagnostics} -eq 0 ] ; then
    for i in log ; do
    	find /var/$i/ -type f -exec rm {} \;
    done
    /bin/rm -rf /var/crash/*
else
    echo "Preserving /var/log/* and /var/crash/*."
fi
rm -f /var/db/locate.database

/usr/bin/touch /var/db/locate.database


# these files will be auto-generated on first boot
rm -f /etc/mcp/mlist.xml
rm -f /etc/mcp/sys/lni.xml

if ${factory:-false}; then
    # Remove node-specific files.  When the drives are installed into the node
    # they will be in, the files will be restored from that node's hardware.
    rm -f /etc/isilon_serial_number 
    rm -f /etc/isilon_system_config 
    rm -f /etc/isilon_hwversions 
    rm -f /etc/isilon_disks

    # Tag these drives as "factory fresh" so that SKU transformation
    # can take place during initial installation.
    /usr/bin/touch /etc/ifs/isi_factory_fresh_drives

    # Rebalance imdd partitions for shipping
    if [ "`/usr/sbin/isi_bootdisk_type --future`" = imdd ]; then
	/usr/bin/isi_imdd_rebalance -x -v
    fi
    
    # Turn off NVRAM battery
    /usr/bin/isi_hw_status nvrbatteryoff
    echo "*****"
    echo "The node is ready for shipping and will turn itself off."
    echo "Do not power the node back on until it has reached its destination,"
    echo "or you'll need to run 'isi_reformat_node --factory' again."
    echo "*****"
fi

# Reset complete
rm -f /etc/isi_resetting

/sbin/shutdown ${shutdown_opt:--r} now
