#!/bin/sh
#
# NAME
#   resize-parts.sh - Script to automate resizing of FreeBSD partitions
#                     within a slice
#
# SYNOPSIS
#   sh resize-parts.sh [-b] [-l] [-r] [-m mnt] [-d dir] [-f label] target
#
#   Switches:
#      -b        backup partition data
#      -l        write new slice label for partitions (via bsdlabel)
#      -r        restore partition data (presumably from a previous invocation 
#                of resize-part.sh -b -l)
#      -d  dir   set location for backup tar files
#      -m  mnt   set mount point for slices during backup and restore.
#                Default is /mnt
#      -f  label use pre-defined bsdlabel input file.  If -f is not specified,
#                bsdlabel will be invoked in edit mode (-e) to allow the
#                interactive editing of the partition table.
#
#   target is one of chrome, crimson or topaz.  The script defines
#   the root slice and the expected mapping between partition and 
#   mount point.
#
#   If no switch is specified, -b, -l and -r are assumed.
#
# DESCRIPTION 
#   Automates backup, re-labelling, with different sizes, and
#   restoring of FreeBSD partitions.  Assumes knowledge of bsdlabel
#   syntax, and that a suitably sized directory is available for
#   backup on /tank.
#
#   If a pre-defined bsdlabel file is provided via the -f switch, the
#   script assumes that interactive control is not required.  No
#   prompts are issued before critical actions (i.e. writing new label
#   and formatting partitions/restoring data).
#
#   Backup directory is assumed to be /tank/${target}, unless changed
#   with the -d switch.
#
#
# MPW 20100130

SCRIPT=${0##*/}
backup=0;label=0;restore=0
chkmount=1
BACKUPROOT=/tank
TEMPMNT="/mnt"
LABELFILE=""

# function to prompt user to continue
continuewith() {
    echo -n "$SCRIPT: $1  OK to continue? (y/n): "
    read cont
    if [ $cont != "y" ]; then
        echo "${SCRIPT}: Terminated."
        exit 1
    fi
}

# exit script with message
die() {
    echo "${SCRIPT}: $1  Terminating..."
    exit 1
}

while [ $# -gt 1 ]; do
   case $1 in
       -b)
           backup=1
           ;;
       -l)
           label=1
           ;;
       -r)
           restore=1
           ;;
       -d)
           BACKUPROOT=$2
           shift
           ;;
       -f)
           LABELFILE=$2
           shift
           ;;
       -m)
           TEMPMNT=$2
           shift
           ;;
       *)
           die "${SCRIPT}: unrecognised switch: $1. Usage: sh resize-parts.sh [-b] [-l] [-r] [-m mnt] [-d dir] [-f label] target"
           ;;
   esac;
   shift
done

if [ ${backup} -eq 0 -a ${label} -eq 0 -a ${restore} -eq 0 ]; then
    backup=1
    label=1
    restore=1
fi

TARGET=$1

case ${TARGET} in
    chrome) 
        SLICE="ad3s1"
        PARTS="a=root d=var e=tmp f=usr g=home"
        ;;
    crimson) 
        SLICE="ad0s1"
        PARTS="a=root d=tmp e=var f=usr g=home h=rep" 
        ;;
    topaz) 
        SLICE="ad0s1"
        PARTS="a=root d=usr e=tmp f=var g=home h=rep" 
        ;;
    *) 
        die "illegal (or no) target specified."
        ;;
esac

BACKUPDIR="${BACKUPROOT}/${TARGET}"

if [ ! -d ${BACKUPDIR} ]; then
    mkdir -p ${BACKUPDIR}
    if [ $? -ne 0 ]; then
        die "unable to create backup directory ${BACKUPDIR}."
    fi
fi

# if label file provided, check it is readable
if [ "$LABELFILE" != "" -a ! -r ${LABELFILE} ]; then
    die "unable to read label file."
fi

# check no part of slice is mounted
# use expr as it is available in /rescue (grep is not)
mnts=$(expr "/`mount`" : ".*${SLICE}")
if [ ${mnts} -ne 0 ]; then
    die "one or more partitions of ${SLICE} are mounted."
fi

# backup partition data
if [ ${backup} -eq 1 ]; then
    for part in $PARTS
    do
        partid=${part%=*}
        mntpt=${part#*=}
        mount -t ufs /dev/${SLICE}${partid} ${TEMPMNT}
        if [ $? -ne 0 ]; then
            die " unable to mount ${SLICE}${partid} on ${mntpt}."
        fi
        echo "${SCRIPT}: backing up ${SLICE}${partid} to ${BACKUPDIR}/${mntpt}.tar.gz..."
        tar czf ${BACKUPDIR}/${mntpt}.tar.gz -C ${TEMPMNT} .
        if [ $? -ne 0 ]; then
            die "error backing up data."
        fi
        umount ${TEMPMNT}
    done
fi

echo "${SCRIPT}: backup directory:"
ls -l ${BACKUPDIR}/*.tar.gz

if [ ${label} -eq 1 ]; then
    if [ "${LABELFILE}" = "" ]; then
        # interactive; check ok to continue?
        continuewith "invoking bsdlabel (better know vi!)."
        # modify partition sizes as required (interactive)
        bsdlabel -e ${SLICE}
    else
        echo "${SCRIPT}: partitioning ${SLICE} with contents of ${LABELFILE}"
        bsdlabel -R ${SLICE} ${LABELFILE}
    fi
    if [ $? -ne 0 ]; then
        die "bsdlabel failed."
    fi
fi

if [ ${restore} -eq 1 ]; then
    if [ "${LABELFILE}" = "" -a ${label} -eq 1 ]; then
        # ok to continue? only asked if bsdlabel step has been run interactively
        continuewith "formatting partitions and restoring."
    fi
    # format new partitions and restore data
    for part in ${PARTS}
    do
        partid=${part%=*}
        mntpt=${part#*=}
        echo "${SCRIPT}: formatting ${SLICE}${partid}..."
        newfs -L ${TARGET}${mntpt} /dev/${SLICE}${partid}
        if [ $? -ne 0 ]; then
            die "unable to format the filesystem: ${SLICE}${partid}."
        fi
        mount -t ufs  /dev/${SLICE}${partid} ${TEMPMNT}
        if [ $? -ne 0 ]; then
            die "unable to mount new formatted filesystem: ${SLICE}${partid}."
        fi
        echo "${SCRIPT}: restoring ${BACKUPDIR}/${mntpt} to ${SLICE}${partid}..."
        tar xzpf ${BACKUPDIR}/${mntpt}.tar.gz -C ${TEMPMNT}
        if [ $? -ne 0 ]; then
            umount ${TEMPMNT}
            die "unable to restore ${mntpt} files to ${SLICE}${partid}."
        fi
        umount ${TEMPMNT}
    done
fi

