#!/bin/bash
# Author: Steven Shiau <steven _at_ nchc org tw>
# License: GPL 
# Description: This program is used to convert the clonezilla image from hdx to sdx or vice versa.

# Load DRBL setting and functions
DRBL_SCRIPT_PATH="${DRBL_SCRIPT_PATH:-/usr/share/drbl}"

. $DRBL_SCRIPT_PATH/sbin/drbl-conf-functions
. /etc/drbl/drbl-ocs.conf
. $DRBL_SCRIPT_PATH/sbin/ocs-functions

# Fedora Core 1 seems to use dumb for rc1, we have to force it use linux.
# otherwise setterm will complain.
[ -z "$TERM" -o "$TERM" = "dumb" ] && TERM="linux"
echo "Setting the TERM as $TERM"
export TERM="$TERM"

# 
ocs=`basename $0`
# Initial setting
batch_mode="no"
force_mode="no"

#
check_if_root

#
USAGE() {
    echo "$ocs: To change the device name in saved clonezilla image"
    echo "Usage:"
    echo "$ocs [OPTION] IMAGE_NAME SOURCE_DEV_NAME TARGET_DEVICE_NAME"
    echo "NOTE! (1) The cloned OS should support the device driver, such as SCSI or SATA if you convert it to SCSI/SATA. (2) If it's GNU/Linux, maybe you have to modify the /etc/fstab in the cloned OS"
    echo 
    echo "OPTION:"
    language_help_prompt_by_idx_no
    echo "-b, --batch        Run in batch mode, i.e. without any prompt or wait to press enter"
    echo "-d, --ocsroot DIR  Specify clonezilla image dir as DIR"
    echo
    echo "Example:"
    echo "To convert the image located in /home/images/, which was originally saved from hda, to sda, use: "
    echo "$ocs" '-d /home/images NOMOREXP hda sda'
    echo "To convert the image located in /home/images/, which was originally saved from sda, to mmcblk0, use: "
    echo "$ocs" '-d /home/images NOMOREWIN sda mmcblk0'
}
#
wait_for_confirm() {
  local rename_confirm_ans=""
  echo -n "Are you sure you want to continue ? (y/N) "
  read rename_confirm_ans
  case "$rename_confirm_ans" in
        y|Y|[yY][eE][sS])
           echo "Let's do it!"
           ;;
        *)
           echo "Program terminated!"
           exit 1
  esac
}
#
# Parse command-line options
while [ $# -gt 0 ]; do
  case "$1" in
    -b|--batch)
            batch_mode="yes"
	    shift;;
    -f|--force)
            force_mode="yes"
	    shift;;
    -l|--language)
            shift
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
	      specified_lang="$1"
              shift
            fi
            [ -z "$specified_lang" ] && USAGE && exit 1
	    ;;
    -d|--ocsroot)
            # overwrite the ocsroot in drbl.conf
            shift; 
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
              ocsroot="$1"
	      shift
            fi
            [ -z "$ocsroot" ] && USAGE && exit 1
	    ;;
    -*)     echo "${0}: ${1}: invalid option" >&2
            USAGE >& 2
            exit 2 ;;
    *)      break ;;
  esac
done

image_name="$1"
src_dev="$2"
tgt_dev="$3"

#
ask_and_load_lang_set $specified_lang

# 
for i in image_name src_dev tgt_dev; do
  eval iv=\$$i
  [ -z "$iv" ] && USAGE && exit 1
done

# ocs root
echo "clonezilla image dir: $ocsroot"

##############
#### main ####
##############

# check image
if [ ! -d "$ocsroot/$image_name" ]; then
  [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
  echo "$ocsroot/$image_name NOT found!"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  echo "Program terminated!"
  exit 1
fi

# Check if src and target is same. If it's in force mode, we create it anyway.
if [ "$force_mode" = "no" ]; then
  if [ "$src_dev" = "$tgt_dev" ]; then
    [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
    echo "Source device ($src_dev) and target device ($tgt_dev) are same one!"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    echo "Skip converting!"
    exit 1
  fi
else
  # force_mode is yes
  if [ "$src_dev" = "$tgt_dev" ]; then
    echo "Although source device ($src_dev) and target device ($tgt_dev) are the same, but it's forced to continue. This program is exited with return code 0."
    exit 0
  fi
fi

# check src_dev
check_input_hd $src_dev
if [ -z "$(unalias ls 2>/dev/null; ls $ocsroot/$image_name/$(to_filename ${src_dev})* 2>/dev/null)" ]; then
  [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
  echo "$ocsroot/$image_name/$(to_filename ${src_dev})* NOT found!"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  echo "Program terminated!"
  exit 1
fi

# check tgt_dev
check_input_hd $tgt_dev

#
if [ "$batch_mode" = "no" ]; then
  [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
  echo "$msg_uppercase_Warning!!! $msg_uppercase_Warning!!! $msg_uppercase_Warning!!!"
  echo "$msg_uppercase_Warning! THIS ACTION IS RISKY! THE CONVERTION MAYBE WILL LET CLIENT FAIL TO BOOT!"
  echo "NOTE!"
  echo "(1) The OS itself from image \"$image_name\" should support the device driver, such as SCSI or SATA if you convert it to SCSI/SATA."
  echo "(2) If the OS itself from image \"$image_name\" is GNU/Linux, maybe you have to modify the /etc/fstab inside it. You can do that after cloing it to harddisk, then boot it into single user mode, or use Live CD/DRBL client mode to make it."
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  wait_for_confirm
fi

# The files in an image are, for example: 
# Clonezilla 1.x
# chs.sf  disk  hda1.ntfs-img  mbr  parts  pt.sf
# Clonezilla 2.x
# Ex 1:
# hda-chs.sf  disk  hda1.ntfs-img  hda-mbr  parts  hda-pt.sf
# Ex 2:
# disk hda1.aa hda3.aa hda-chs.sf hda-mbr hda-pt.sf parts swappt-hda2.info hda-pt.parted
# chs.sf is not necessary to be modified.
# In this example, just modify: disk parts pt.sf hda-pt.sf, actually pt.sf only exists in clonezilla 1.x, and hda-pt.sf only exists in clonezilla 2.x. Anyway, if it is found, just modify that.
# files_2_be_mod_about_disk means the content of file contains disk name, e.g. sda, cciss/c0d0
# files_2_be_mod_about_parts means the content of file contains partition name, e.g. sda1, cciss/c0d0p1
files_2_be_mod_about_disk="disk $(to_filename ${src_dev})-pt.parted $(to_filename ${src_dev})-pt.parted.compact"
files_2_be_mod_about_parts="parts pt.sf $(to_filename ${src_dev})-pt.sf"

if [ "$force_mode" = "no" ]; then
  if [ -n "$(unalias ls 2>/dev/null; ls $ocsroot/$image_name/$(to_filename ${tgt_dev})* 2>/dev/null)" ]; then
    [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
    echo "Target device files ($ocsroot/$image_name/$(to_filename ${tgt_dev})*) already exist!"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    wait_for_confirm
  fi
fi
for ifile in $files_2_be_mod_about_disk; do
  [ ! -e "$ocsroot/$image_name/$ifile" ] && continue
  echo -n "Change $src_dev to $tgt_dev in $ocsroot/$image_name/$ifile... "
  LC_ALL=C perl -pi -e "s|$src_dev|$tgt_dev|g" $ocsroot/$image_name/$ifile
  echo "done!"
done
for ifile in $files_2_be_mod_about_parts; do
  [ ! -e "$ocsroot/$image_name/$ifile" ] && continue
  echo -n "Change $src_dev to $tgt_dev in $ocsroot/$image_name/$ifile... "
  case $tgt_dev in
  cciss*|mmcblk*|md*|rd*|ida*|nvme*|nbd*)
    # sda1 -> cciss/c0d0p1 or sda1 -> mmcblk0p1
    # How about cciss/c0d0p1 -> cciss/c0d1p1?
    # How about mmcblk0p1 -> sda1? OK!
    # nvme0n1p1 -> sda1
    LC_ALL=C perl -pi -e "s|$src_dev[p]?|${tgt_dev}p|g" $ocsroot/$image_name/$ifile
    ;;
  *)
    # [p]? is for cciss device partitions, e.g. when convering cciss/c0d0 to sda, i.e. cciss/c0d0p1 -> sda1
    LC_ALL=C perl -pi -e "s|$src_dev[p]?|$tgt_dev|g" $ocsroot/$image_name/$ifile
    ;;
  esac
  echo "done!"
done
# There are 3 files (lvm_etch.conf  lvm_logv.list  lvm_vg_dev.list) about LVM devices in Clonezilla image, and only lvm_vg_dev.list is necessary to be modified. We separate this from the above is because it's format is like "/dev/hda" instead of "hda".
if [ -f "$ocsroot/$image_name/lvm_vg_dev.list" ]; then
  echo -n "Change /dev/$src_dev to /dev/$tgt_dev in $ocsroot/$image_name/lvm_vg_dev.list... "
  case $tgt_dev in
  cciss*|mmcblk*|md*|rd*|ida*|nvme*|nbd*)
    LC_ALL=C perl -pi -e "s|/dev/$src_dev[p]?|/dev/${tgt_dev}p|g" $ocsroot/$image_name/lvm_vg_dev.list
    ;;
  *)
    # [p]? is for cciss device partitions, e.g. when convering cciss/c0d0 to sda
    # cciss/c0d0p1 -> sda1
    LC_ALL=C perl -pi -e "s|/dev/$src_dev[p]?|/dev/$tgt_dev|g" $ocsroot/$image_name/lvm_vg_dev.list
    ;;
  esac
  echo "done!"
fi

# Change the file names
# hda, hda1.ntfs-img...
# hda1.ntfs-img -> sda1.ntfs-img
# For clonezilla 2.x format, hda-mbr, hda-pt.sf, hda-pt.parted, hda-chs.sf also will be processed here: hda-mbr -> sda-mbr...
# filenames_2_be_mod_about_disk="$(to_filename ${src_dev})-pt.sf $(to_filename ${src_dev})-chs.sf $(to_filename ${src_dev})-hidden-data-after-mbr $(to_filename ${src_dev})-mbr $(to_filename ${src_dev})-pt.parted $(to_filename ${src_dev})-pt.parted.compact $(to_filename ${src_dev})-gpt-1st $(to_filename ${src_dev})-gpt-2nd $(to_filename ${src_dev})-gpt.gdisk $(to_filename ${src_dev})-gpt.sgdisk"
# Better way to list all of them:
filenames_2_be_mod_about_disk="$(LC_ALL=C find $ocsroot/$image_name/ -name \
"$(to_filename ${src_dev})-*" -print | sort)"
filenames_2_be_mod_about_parts="$(LC_ALL=C find $ocsroot/$image_name/ \( -name \
"$(to_filename ${src_dev})*.*-img*" -o -name "$(to_filename ${src_dev})*.files-*sum.info.gz" \) \
-print | sort)"
filenames_2_be_mod_about_swap="$(LC_ALL=C find $ocsroot/$image_name/ -name \
"swappt-$(to_filename ${src_dev})*.info" -print | sort)"

# Process the disk-related file names
for im in $filenames_2_be_mod_about_disk; do
  [ ! -e "$im" ] && continue
  imname="$(LC_ALL=C basename $im)"
  newname="$(LC_ALL=C echo $imname| sed -r -e "s/$(to_filename ${src_dev})/$(to_filename ${tgt_dev})/g")"
  if [ -z "$newname" ]; then
    [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
    echo "Name converted failed!"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    echo "Program terminated!"
    exit 1
  fi
  mv -vf $ocsroot/$image_name/$imname $ocsroot/$image_name/$newname
done
# Process the partition-related file names
for im in $filenames_2_be_mod_about_parts; do
  [ ! -e "$im" ] && continue
  imname="$(LC_ALL=C basename $im)"
  # [p]? is for cciss device partitions, e.g. when convering cciss/c0d0 to sda
  # cciss/c0d0p1 -> sda1
  case $tgt_dev in
  cciss*|mmcblk*|md*|rd*|ida*|nvme*|nbd*)
    newname="$(LC_ALL=C echo $imname | sed -r -e "s/$(to_filename ${src_dev})[p]?/$(to_filename ${tgt_dev})p/g")"
    ;;
  *)
    newname="$(LC_ALL=C echo $imname | sed -r -e "s/$(to_filename ${src_dev})[p]?/$(to_filename ${tgt_dev})/g")"
    ;;
  esac
  if [ -z "$newname" ]; then
    [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
    echo "Name converted failed!"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    echo "Program terminated!"
    exit 1
  fi
  mv -vf $ocsroot/$image_name/$imname $ocsroot/$image_name/$newname
done
# For swappt-*.info
for im in $filenames_2_be_mod_about_swap; do
  [ ! -e "$im" ] && continue
  imname="$(LC_ALL=C basename $im)"
  case $tgt_dev in
  cciss*|mmcblk*|md*|rd*|ida*|nvme*|nbd*)
   newname="$(LC_ALL=C echo $imname| sed -r -e "s/$(to_filename ${src_dev})[p]?/$(to_filename ${tgt_dev})p/g")"
   ;;
  *)
   # [p]? is for cciss device partitions, e.g. when convering cciss/c0d0 to sda
   # cciss/c0d0p1 -> sda1
   newname="$(LC_ALL=C echo $imname| sed -r -e "s/$(to_filename ${src_dev})[p]?/$(to_filename ${tgt_dev})/g")"
   ;;
  esac
  if [ -z "$newname" ]; then
    [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
    echo "Name converted failed!"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    echo "Program terminated!"
    exit 1
  fi
  mv -vf $ocsroot/$image_name/$imname $ocsroot/$image_name/$newname
done

exit 0
