#!/bin/bash
# 
# Copyright (C) 2007 Oracle.  All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public
# License, version 2,  as published by the Free Software Foundation.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
# 
# You should have received a copy of the GNU General Public
# License along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
# Boston, MA  02110-1301 USA.
#
# Author: Sunil Mushran 03/01/2007
#
################################################################
#
# verify_backup_super
#
# This script lists all the objects using the clusters that are
# reserved for OCFS2's backup superblocks. This script is
# useful for users unable to retroactively enable backup super
# block using tunefs.ocfs2 --backup-super.
#
################################################################

usage() {
    echo "usage ${APP} /dev/sdX"
    exit 1
}

get_sizes() {
    bsbits=`${DEBUGFS} -R "stats" ${device} 2>/dev/null | ${AWK} '/Block Size Bits/ {print $4;}'`
    csbits=`${DEBUGFS} -R "stats" ${device} 2>/dev/null | ${AWK} '/Cluster Size Bits/ {print $8;}'`
    numcls=`${DEBUGFS} -R "stats" ${device} 2>/dev/null | ${AWK} '/Clusters:/ {print $4;}'`

    if [ -z "$bsbits" ] || [ -a "$csbits" ] || [ -a "$numcls" ]; then
        echo "error: not an OCFS2 device"
        exit 1
    fi

    #in bytes
    blocksize=$[$[2 ** $[$bsbits - 9]] * 512]
    clustsize=$[$[2 ** $[$csbits - 9]] * 512]

    #in blocks
    numblocks=$[$numcls * $clustsize / $blocksize]
}

# Ensure version is >= 1.2.3
verify_version() {
    ret=`${DEBUGFS} --version 2>&1 |
         ${AWK} '/debugfs.ocfs2/ {
              flds=split($2, ver, ".");
              if (flds >= 3) { if (ver[1] > 1) {print 1;}
                               else if (ver[2] < 2) {print 0;}
                               else if (ver[2] > 2) {print 1;}
                               else if (ver[3] > 2) {print 1;}
                               else {print 0}; }
              else {print 0;} }'`
    if [ "${ret}" = "0" ]; then
        echo "Upgrade to ocfs2-tools 1.2.3 or later"
        exit 1
    fi
}

# Feature Compat: 1 BackupSuper
has_backup_super() {
    feat=`${DEBUGFS} -R "stats" ${device} 2>/dev/null |
            ${AWK} 'BEGIN {fnd=0;} /Feature Compat/ {if (match($0, "BackupSuper")) fnd=1;} END {print fnd;}'`
    if [ "${feat}" = "1" ]; then
        echo "Backup super block already enabled on device ${device}"
        exit 0
    fi
}

get_icheck_args() {
    if [ $numblocks -le ${backup[0]} ]; then
        echo "Device $device too small to hold backup superblocks"
        exit 0
    fi

    for i in `${SEQ} 0 5`
    do
       block=$[${backup[$i]} / $[2 ** $[$bsbits - 9]]]
       if [ $block -lt $numblocks ]; then
           icheckargs="$icheckargs $block"
       else
           break
       fi
    done
}

DEBUGFS=`which debugfs.ocfs2`
AWK=`which awk`
SEQ=`which seq`
TEE=`which tee`
DATE=`which date`
APP=`basename $0`

if [ -z "${DEBUGFS}" ]; then echo "error: \"debugfs.ocfs2\" not found in path"; exit 1; fi
if [ -z "${AWK}" ]; then echo "error: \"awk\" not found in path"; exit 1; fi
if [ -z "${SEQ}" ]; then echo "error: \"seq\" not found in path"; exit 1; fi
if [ -z "${TEE}" ]; then echo "error: \"tee\" not found in path"; exit 1; fi
if [ -z "${DATE}" ]; then echo "error: \"date\" not found in path"; exit 1; fi

blocksize=0
bsbits=0
csbits=0
clustersize=0
numblocks=0
icheckargs=""

YMD=`${DATE} +%Y%m%d_%H%M%S`
TEMPFILE=/tmp/__${YMD}__

# Backup super offsets in 512 byte blocks
backup[0]=2097152
backup[1]=8388608
backup[2]=33554432
backup[3]=134217728
backup[4]=536870912
backup[5]=2147483648

device=$1

if [ -z "${device}" ]; then
    usage ;
fi

get_sizes

verify_version

has_backup_super

get_icheck_args

echo "Locating inodes using blocks${icheckargs} on device ${device}"
#echo "${DEBUGFS} -R \"icheck${icheckargs}\" ${device}"
${DEBUGFS} -R "icheck${icheckargs}" ${device} | ${TEE} ${TEMPFILE}

inodes=`${AWK} 'BEGIN {out = "";} // {if (strtonum($2) != 0) out = out " " "<"$2">";} END {print out};'  ${TEMPFILE}`

#echo $inodes

if [ -z "${inodes}" ]; then
    echo "All Backup superblock clusters are unused"
    exit 0
fi

echo "Matching inodes to object names"
#echo "${DEBUGFS} -R \"findpath ${inodes}\" ${device}"
${DEBUGFS} -R "findpath ${inodes}" ${device}
