#!/bin/bash
# License: GPL 
# Author: Steven Shiau <steven _at_ clonezilla org>
# Description: Program to feed multicast/bt packets for clients to restore.
# What will be done in this program:
# 1. Image repository has to be mounted first.
# 2. Create a tarball about the image which contains all files in the image except file system image files.
# 3. Provide full command for client to run. 
# For 2 and 3, the files will be put in httpd server.
# //NOTE// Bittorrent is still under development. Not enabled yet.

#
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

# Load the config in ocs-live.conf. This is specially for Clonezilla live. It will overwrite some settings of /etc/drbl/drbl-ocs.conf, such as $DIA...
[ -e "/etc/ocs/ocs-live.conf" ] && . /etc/ocs/ocs-live.conf

# Settings
# OCS_OPT is for ocs-sr
OCS_OPT=
nfs_restart="no"
udpcast_stderr="/dev/null"
udp_sender_extra_opt="$udp_sender_extra_opt_default"
run_prerun_dir="no"
run_postrun_dir="no"
create_part="yes"
restore_mbr="yes"
restore_prebuild_mbr="no"
rm_win_swap_hib="no"
chk_img_restoreable_on_srv_def="yes"
# Timeout (secs) for wating udp-sender & BT program
timeout_max="60"
# Network settings for closed LAN
ipadd_closed_lan="192.168.169.250"
netmask_closed_lan="24"
gwadd_closed_lan="192.168.169.254"
ocs_sr_mode=""
bt_raw_dev_psuedo_img_prefix="btraw-psdo"
check_ocs_live="yes"

# Functions
USAGE() {
    echo "$ocs - To start feeding image for multicast/BT mode in Clonezilla"
    echo "Usage:"
    echo "To run $ocs:"
    echo "$ocs [OPTION] MODE [IMAGE] [DEVICE]"
    echo "This program is specially used in Clonezilla live to start feeding multicast/BT packets for clients."
    echo "MODE is \"start\" or \"stop\""
    echo "IMAGE is the image dir name, not absolute path"
    echo "DEVICE name can be with or without /dev/, e.g., /dev/sda or sda."
    echo "Two reserved parameters can be used for image (BT from device mode) or device name (only for whole disk):"
    echo "\"all\" is for all the available hard drives."
    echo "\"all-but-usb\" is for all the available hard drives excluding USB ones."
    echo "If \"ask_user\" is used as IMAGE or DEVICE, a dialog menu will be shown to allow selection."
    echo "If no IMAGE is specified, a dialog menu will be shown."
    echo 
    echo "OPTION:"
    USAGE_common_restore
    USAGE_common_restore_server
    USAGE_reserved_word_for_restore
    echo
    echo " General options:"
    USAGE_common_general
    dialog_like_prog_help_prompt
    echo " -s, --skip-hw-detect     Skip the hardware detection (kudzu, harddrake or discover)"
    echo " -n, --no-nfs-restart     Do not to restart nfs when start or stop $ocs (This is default)"
    echo " -f, --nfs-restart        Restart nfs when start or stop $ocs (Default is to restart nfs)"
    echo " -mcast-iface, --mcast-iface  PORT   Specify the multicast seed ethernet port PORT (eth0, eth1, eth2...). Suppose clonezilla will try to find that for you, but in some case, you might want to specify that."
    echo " -bt-iface, --bt-iface  PORT         Specify the BT seed ethernet port PORT (eth0, eth1, eth2...). Suppose clonezilla will try to find that for you, but in some case, you might want to specify that."
    echo " -x, --full-duplex        Use full-duplex network with udpcast in multicast mode (faster, but does not work with network hub, only works in switch.)."
    echo " -dm, --dhcpd-mode  MODE  Assign the dhcp service mode: use-existing-dhcpd, start-new-dhcpd, auto-detect, no-dhcpd"
    echo " -md, --massive-deploy-mode MODE   Assign the mass deployment mode: broadcast, multicast, or bittorrent"
    echo " -cbm, --client-boot-mode MODE     Assign the client boot mode: netboot, local-boot-media, or both"
    echo " -lscm, --lite-srv-client-mode MODE  Assign lite server client mode: massive-deployment or interactive-client"
    echo " -mdst, --massive-deploy-source-type MODE  Assign massive deployment source type: from-image or from-device"
    echo " -mdst-img, --massive-deploy-source-type-img IMAGE  Assign massive deployment source image name. You have to make sure the file system in the source device is not modified, and the image dir already exists."
    echo " -bdt, --bt-dev-type MODE Assign BT device type: disk-2-mdisks or part-2-mparts" 
    echo " -bsdf, --bt-src-dev-fsck  TYPE   Assign the type for fsck the source device: sfsck, fsck, fsck-y. Do not put \"-\" before the TYPE. It will confuse $ocs. Use it like: \"-bsdf fsck-y\""
    echo " -icol, --ignore-check-ocs-live   Skip checking if the working environment is Clonezilla live or not."
    echo
    echo "Ex:"
    echo "To start feeding the image \"my-image\" for restoring it in client's device sda, run"
    echo "   $ocs start my-image sda"
    echo
} # end of USAGE
#
prompt_for_lite_server() {
  if [ "$ocs_sr_mode" = "interactive" ]; then
    echo "$msg_delimiter_star_line"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
    echo "$msg_ocs_live_lite_server_des"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    confirm_continue_or_not_default_continue
  fi
} # end of prompt_for_lite_server
#
ask_start_or_stop_mode() {
  TMP="$(mktemp /tmp/ocsmode.XXXXXX)"
  trap "[ -f "$TMP" ] && rm -f $TMP" HUP INT QUIT TERM EXIT
  $DIA --backtitle "$msg_nchc_free_software_labs" --title  \
  "Clonezilla live Lite server" --menu "$msg_ocs_live_lite_server_des\n$msg_choose_mode:" \
  0 0 0 $DIA_ESC \
  "start"  "$msg_start_clonezilla_live_lite_server" \
  "stop"   "$msg_stop_clonezilla_live_lite_server" \
  "exit"   "$msg_exit. $msg_enter_cml" \
  2> $TMP
  mode="$(cat $TMP)"
  [ -f "$TMP" ] && rm -f $TMP
  if [ "$mode" = "exit" ]; then
    exit 3
  else
    echo "Action is $mode"
  fi
} # end of ask_start_or_stop_mode
#
parse_ocs_live_feed_img_cmd_options_with_dash() { 
  n_shift=0
  #
  while [ $# -gt 0 ]; do
   case "$1" in
      -p|--postaction)  
	    shift; n_shift=$((n_shift+1))
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
              postaction="$1"
	      shift; n_shift=$((n_shift+1))
            fi
            OCS_OPT="$OCS_OPT -p $postaction"
            ;;
      -g|--grub-install)  
            install_grub="on"
  	    shift; n_shift=$((n_shift+1))
            # skip the -xx option, in case 
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              grub_partition=$1
  	    shift; n_shift=$((n_shift+1))
            fi
            [ -z "$grub_partition" ] && USAGE && exit 1
  	    OCS_OPT="$OCS_OPT -g $grub_partition"
            ;;
      -a|--no-force-dma-on)  
  	    OCS_OPT="$OCS_OPT --no-force-dma-on"
  	    shift; n_shift=$((n_shift+1));;
      -k|--no-fdisk|--no-create-partition)  
  	    create_part="no"
  	    OCS_OPT="$OCS_OPT -k"
  	    shift; n_shift=$((n_shift+1));;
      -k0)  # Do nothing. Just an option to let us explain the action easier.
	    true
  	    OCS_OPT="$OCS_OPT -k0"
  	    shift; n_shift=$((n_shift+1));;
      -k1|--fdisk-proportion)  
  	    create_part="yes"
  	    create_part_type="proportion"
  	    OCS_OPT="$OCS_OPT -k1"
  	    shift; n_shift=$((n_shift+1));;
      -k2|--fdisk-manual)  
  	    create_part="yes"
  	    create_part_type="manual"
  	    OCS_OPT="$OCS_OPT -k2"
  	    shift; n_shift=$((n_shift+1));;
      -t|--no-restore-mbr)  
  	    restore_mbr="no"
  	    OCS_OPT="$OCS_OPT -t"
              shift; n_shift=$((n_shift+1));;
      -t1|--restore-raw-mbr)  
            # The flag to restore syslinux mbr.bin to MS windows system.
  	    restore_prebuild_mbr="yes"
  	    OCS_OPT="$OCS_OPT -t1"
              shift; n_shift=$((n_shift+1));;
      -t2|--no-restore-ebr)  
  	    restore_ebr="no"
  	    OCS_OPT="$OCS_OPT -t2"
              shift; n_shift=$((n_shift+1));;
      -e|--load-geometry)
  	    OCS_OPT="$OCS_OPT -e"
              shift; n_shift=$((n_shift+1));;
      -e1|--change-geometry)  
              change_ntfs_boot_chs="on"
              shift; n_shift=$((n_shift+1))
              # skip the -xx option, in case 
              if [ -z "$(echo $1 |grep ^-.)" ]; then
                ntfs_boot_partition=$1
                shift; n_shift=$((n_shift+1))
              fi
              [ -z "$ntfs_boot_partition" ] && USAGE && exit 1
  	    OCS_OPT="$OCS_OPT -e1 $ntfs_boot_partition"
              ;;
      -e2|--load-geometry-from-edd)
  	    OCS_OPT="$OCS_OPT -e2"
              shift; n_shift=$((n_shift+1));;
      -c|--confirm)
  	    OCS_OPT="$OCS_OPT -c"
  	    shift; n_shift=$((n_shift+1));;
      -w|--wait-time)
              shift; n_shift=$((n_shift+1))
              if [ -z "$(echo $1 |grep ^-.)" ]; then
                # skip the -xx option, in case 
  	      TIME_to_wait="$1"
  	      OCS_OPT="$OCS_OPT -w $TIME_to_wait"
                shift; n_shift=$((n_shift+1))
              fi
  	    ;;
      -s|--skip-hw-detect)
              hw_detect="off"
  	    shift; n_shift=$((n_shift+1));;
      --debug=?*)
            debug_level=${1#--debug=}
  	    OCS_OPT="$OCS_OPT --debug=$debug_level"
  	    shift; n_shift=$((n_shift+1));;
      -b|--batch)
            # Here we append --batch to OCS_OPT instead of -b, (it will confuse init, sinice -b for init is emergency mode)
            ocs_batch_mode="on"
  	    OCS_OPT="$OCS_OPT --batch"
  	    shift; n_shift=$((n_shift+1));;
      -d|--debug-mode)
            debug_mode="on"
  	    OCS_OPT="$OCS_OPT -d"
  	    shift; n_shift=$((n_shift+1));;
      -d0|--dialog)   DIA="dialog"; shift; n_shift=$((n_shift+1));;
      -d1|--Xdialog)  DIA="Xdialog"; shift; n_shift=$((n_shift+1));;
      -d2|--whiptail) DIA="whiptail"; shift; n_shift=$((n_shift+1));;
      -d3|--gdialog)  DIA="gdialog"; shift; n_shift=$((n_shift+1));;
      -d4|--kdialog)  DIA="kdialog"; shift; n_shift=$((n_shift+1));;
      -r|--resize-partition)
  	    OCS_OPT="$OCS_OPT -r"
  	    shift; n_shift=$((n_shift+1));;
      -v|--verbose)
  	    verbose="on"
  	    OCS_OPT="$OCS_OPT -v"
  	    shift; n_shift=$((n_shift+1));;
      -nogui|--nogui)
            # -nogui is for backward compatable, better to use --nogui
            OCS_OPT="$OCS_OPT --nogui"
  	    shift; n_shift=$((n_shift+1));;
      -rm-win-swap-hib|--rm-win-swap-hib)
            # Remove page and hibernation files in MS windows
            OCS_OPT="$OCS_OPT --rm-win-swap-hib"
  	    shift; n_shift=$((n_shift+1));;
      -rescue|--rescue)
            OCS_OPT="$OCS_OPT --rescue"
  	    shift; n_shift=$((n_shift+1));;
      -mp|--mount-point)
            shift; 
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
              mount_point=$1
  	    shift; n_shift=$((n_shift+1))
            fi
            [ -z "$mount_point" ] && USAGE && exit 1
  	    OCS_OPT="$OCS_OPT --mount-point $mount_point" ; 
  	    ;;
      --time-to-wait)
  	    shift; n_shift=$((n_shift+1))
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
  	    mcast_wait_time="$1"
  	    shift; n_shift=$((n_shift+1))
            fi
  	    ;;
      --clients-to-wait)
  	    shift; n_shift=$((n_shift+1))
              if [ -z "$(echo $1 |grep ^-.)" ]; then
                # skip the -xx option, in case 
  	      n_clients="$1"
  	      shift; n_shift=$((n_shift+1))
              fi
  	    ;;
      --max-time-to-wait)
  	    shift; n_shift=$((n_shift+1))
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
  	    mcast_max_wait_time="$1"
  	    shift; n_shift=$((n_shift+1))
            fi
            [ -z "$mcast_max_wait_time" ] && USAGE && exit 1
  	    # Client need to know the --max-time-to-wait so that when sleeping
  	    # between partitions restoring clone won't timeout.
            OCS_OPT="$OCS_OPT --max-time-to-wait $mcast_max_wait_time"
  	    ;;
      -x|--full-duplex)
            udp_sender_extra_opt="$udp_sender_extra_opt --full-duplex"
  	    shift; n_shift=$((n_shift+1));;
      -brdcst|--broadcast)
            udp_sender_extra_opt="$udp_sender_extra_opt --broadcast"
  	    shift; n_shift=$((n_shift+1));;
      -j|--create-part-by-sfdisk)
            # We leave this option for backward compatability.
  	    OCS_OPT="$OCS_OPT --create-part-by-sfdisk"
  	    shift; n_shift=$((n_shift+1));;
      -j0|--create-part-by-dd)
  	    OCS_OPT="$OCS_OPT --create-part-by-dd"
  	    shift; n_shift=$((n_shift+1));;
      -j1|--dump-mbr-in-the-end)
  	    OCS_OPT="$OCS_OPT --dump-mbr-in-the-end"
  	    shift; n_shift=$((n_shift+1));;
      -j2|--clone-hidden-data)
  	    OCS_OPT="$OCS_OPT --clone-hidden-data"
  	    shift; n_shift=$((n_shift+1));;
      -icrc|--icrc)
  	    OCS_OPT="$OCS_OPT --icrc"
  	    shift; n_shift=$((n_shift+1));;
      -irvd|--irvd)
  	    OCS_OPT="$OCS_OPT --irvd"
  	    shift; n_shift=$((n_shift+1));;
      -irhr|--irhr)
  	    OCS_OPT="$OCS_OPT --irhr"
  	    shift; n_shift=$((n_shift+1));;
      -ius|--ius)
  	    OCS_OPT="$OCS_OPT --ius"
  	    shift; n_shift=$((n_shift+1));;
      -icds|--ignore-chk-dsk-size-pt)
  	    OCS_OPT="$OCS_OPT --ignore-chk-dsk-size-pt"
  	    shift; n_shift=$((n_shift+1));;
      -iefi|--ignore-update-efi-nvram)
  	    OCS_OPT="$OCS_OPT --ignore-update-efi-nvram"
  	    shift; n_shift=$((n_shift+1));;
      -srel|--save-restore-error-log)
  	    OCS_OPT="$OCS_OPT --save-restore-error-log"
  	    shift; n_shift=$((n_shift+1));;
      -hn0)
  	    shift; n_shift=$((n_shift+1))
            change_win_hostname="By_IP"
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
  	    win_hostname_prefix="$1"
  	    shift; n_shift=$((n_shift+1))
            fi
            [ -z "$win_hostname_prefix" ] && USAGE && exit 1
            OCS_OPT="$OCS_OPT -hn0 $win_hostname_prefix"
  	    ;;
      -hn1)
  	    shift; n_shift=$((n_shift+1))
            change_win_hostname="By_MAC"
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
  	    win_hostname_prefix="$1"
  	    shift; n_shift=$((n_shift+1))
            fi
            [ -z "$win_hostname_prefix" ] && USAGE && exit 1
            OCS_OPT="$OCS_OPT -hn1 $win_hostname_prefix"
  	    ;;
      -o|-o1|--run-postrun-dir) 
              # -o is for backward compatability
  	    run_postrun_dir="yes"
  	    OCS_OPT="$OCS_OPT --run-postrun-dir"
  	    shift; n_shift=$((n_shift+1));;
      -o0|--run-prerun-dir) 
  	    run_prerun_dir="yes"
  	    OCS_OPT="$OCS_OPT --run-prerun-dir"
  	    shift; n_shift=$((n_shift+1));;
      -ns|--ntfs-progress-in-image-dir)
  	    OCS_OPT="$OCS_OPT --ntfs-progress-in-image-dir"
  	    shift; n_shift=$((n_shift+1));;
      -cm|--check-md5sum)
  	    check_md5sum="yes"
  	    OCS_OPT="$OCS_OPT -cm"
  	    shift; n_shift=$((n_shift+1));;
      -cs|--check-sha1sum)
  	    check_sha1sum="yes"
  	    OCS_OPT="$OCS_OPT -cs"
  	    shift; n_shift=$((n_shift+1));;
      -cmf|--chk-chksum-for-files-in-dev)
  	    chk_chksum_for_files_in_dev="yes"
  	    OCS_OPT="$OCS_OPT -cmf"
  	    shift; n_shift=$((n_shift+1));;
      -mcast-iface|--mcast-iface|-bt-iface|--bt-iface)
  	    shift; n_shift=$((n_shift+1))
              if [ -z "$(echo $1 |grep ^-.)" ]; then
                # skip the -xx option, in case 
  	      eth_for_cast="$1"
  	      shift; n_shift=$((n_shift+1))
              fi
              [ -z "$eth_for_cast" ] && USAGE && exit 1
  	    ;;
      -um|--user-mode)
            shift; n_shift=$((n_shift+1))
            # skip the -xx option, in case 
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              ocs_user_mode="$1"
              shift; n_shift=$((n_shift+1))
            fi
            [ -z "$ocs_user_mode" ] && USAGE && exit 1
	    # There is no need to pass user mode because it's already in batch mode.
  	    # XXXXXX OCS_OPT="$OCS_OPT -um $ocs_user_mode"
  	    ;;
      -bm|--beginner-mode) 
	    ocs_user_mode="beginner"
	    # There is no need to pass user mode because it's already in batch mode.
  	    # XXXXXX OCS_OPT="$OCS_OPT -um $ocs_user_mode"
            shift; n_shift=$((n_shift+1));;
      -em|--expert-mode) 
	    ocs_user_mode="expert"
	    # There is no need to pass user mode because it's already in batch mode.
  	    # XXXXXX OCS_OPT="$OCS_OPT -um $ocs_user_mode"
            shift; n_shift=$((n_shift+1));;
      -sc0|--skip-check-restorable-on-srv)
            # flag to check if the image is restorable on clonezilla server
  	    chk_img_restoreable_on_srv="no"
  	    shift; n_shift=$((n_shift+1));;
      -sc|-scs|--skip-check-restorable|--skip-check-restorable-s)
            # flag to check if the image is restorable
  	    chk_img_restoreable_mod_save="no"
  	    OCS_OPT="$OCS_OPT -scs"
  	    shift; n_shift=$((n_shift+1));;
      -scr|--skip-check-restorable-r)
            # Flag to check if the image is restorable
  	    chk_img_restoreable_mod_restore="no"
  	    OCS_OPT="$OCS_OPT -scr"
  	    shift; n_shift=$((n_shift+1));;
      -md|--massive-deploy-mode)
            shift; n_shift=$((n_shift+1))
            # skip the -xx option, in case 
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              massive_deploy_mode="$1"
              shift; n_shift=$((n_shift+1))
            fi
            [ -z "$massive_deploy_mode" ] && USAGE && exit 1
	    # //NOTE// Do not pass -md option to OCS_OPT here.
	    # OCS_OPT is for ocs-sr, not for ocs-live-feed-img
  	    # XXXXXX OCS_OPT="$OCS_OPT -md $massive_deploy_mode"
  	    ;;
      -dm|--dhcpd-mode)
            shift; n_shift=$((n_shift+1))
            # skip the -xx option, in case 
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              ocs_litesrv_netmode="$1"
              shift; n_shift=$((n_shift+1))
            fi
            [ -z "$ocs_litesrv_netmode" ] && USAGE && exit 1
	    # //NOTE// Do not pass -md option to OCS_OPT here.
	    # OCS_OPT is for ocs-sr, not for ocs-live-feed-img
  	    # XXXXXX OCS_OPT="$OCS_OPT -dm $ocs_litesrv_netmode"
  	    ;;
      -cbm|--client-boot-mode)
            shift; n_shift=$((n_shift+1))
            # skip the -xx option, in case 
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              client_boot_mode="$1"
              shift; n_shift=$((n_shift+1))
            fi
            [ -z "$client_boot_mode" ] && USAGE && exit 1
	    # //NOTE// Do not pass -cbm option to OCS_OPT here.
	    # OCS_OPT is for ocs-sr, not for ocs-live-feed-img
  	    # XXXXXX OCS_OPT="$OCS_OPT -cbm $client_boot_mode"
  	    ;;
      -lscm|--lite-srv-client-mode)
            shift; n_shift=$((n_shift+1))
            # skip the -xx option, in case 
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              ls_client_mode="$1"
              shift; n_shift=$((n_shift+1))
            fi
            [ -z "$ls_client_mode" ] && USAGE && exit 1
	    # //NOTE// Do not pass -lscm option to OCS_OPT here.
	    # OCS_OPT is for ocs-sr, not for ocs-live-feed-img
  	    # XXXXXX OCS_OPT="$OCS_OPT -lscm $client_boot_mode"
  	    ;;
      -mdst|--massive-deploy-source-type)
            shift; n_shift=$((n_shift+1))
            # skip the -xx option, in case 
            if [ -z "$(echo $1 |grep ^-.)" ]; then
	      md_source_type="$1"
              shift; n_shift=$((n_shift+1))
            fi
            [ -z "$md_source_type" ] && USAGE && exit 1
	    # //NOTE// Do not pass -mdst option to OCS_OPT here.
	    # OCS_OPT is for ocs-sr, not for ocs-live-feed-img
  	    # XXXXXX OCS_OPT="$OCS_OPT -mdst $client_boot_mode"
  	    ;;
      -mdst-img|--massive-deploy-source-type-img)
            shift; n_shift=$((n_shift+1))
            # skip the -xx option, in case 
            if [ -z "$(echo $1 |grep ^-.)" ]; then
	      mdst_img="$1"
              shift; n_shift=$((n_shift+1))
            fi
            [ -z "$mdst_img" ] && USAGE && exit 1
	    # //NOTE// Do not pass -mdst option to OCS_OPT here.
	    # OCS_OPT is for ocs-sr, not for ocs-live-feed-img
  	    # XXXXXX OCS_OPT="$OCS_OPT -mdst $client_boot_mode"
  	    ;;
      -bdt|--bt-dev-type)
            shift; n_shift=$((n_shift+1))
            # skip the -xx option, in case 
            if [ -z "$(echo $1 |grep ^-.)" ]; then
	      bt_dev_type="$1"
              shift; n_shift=$((n_shift+1))
            fi
            [ -z "$bt_dev_type" ] && USAGE && exit 1
	    # //NOTE// Do not pass -mdst option to OCS_OPT here.
	    # OCS_OPT is for ocs-sr, not for ocs-live-feed-img
  	    # XXXXXX OCS_OPT="$OCS_OPT -mdst $client_boot_mode"
  	    ;;
      -bsdf|--bt-src-dev-fsck)
            shift; n_shift=$((n_shift+1))
            # skip the -xx option, in case 
            if [ -z "$(echo $1 |grep ^-.)" ]; then
	      btsrc_dev_fsck="$1"
              shift; n_shift=$((n_shift+1))
            fi
            [ -z "$btsrc_dev_fsck" ] && USAGE && exit 1
	    # //NOTE// Do not pass -mdst option to OCS_OPT here.
	    # OCS_OPT is for ocs-sr, not for ocs-live-feed-img
  	    # XXXXXX OCS_OPT="$OCS_OPT -mdst $client_boot_mode"
  	    ;;
      -icol|--ignore-check-ocs-live)
  	    check_ocs_live="no"
  	    shift; n_shift=$((n_shift+1));;
      -*)   echo "${0}: ${1}: invalid option" >&2
            USAGE >& 2
            exit 2 ;;
       *)   break ;;
   esac
  done
} # end of parse_ocs_live_feed_img_cmd_options_with_dash
#
get_cast_srv_ip() {
  if [ -n "$eth_for_cast" ]; then
    eth_for_deploy_packet="$eth_for_cast"
  else
    eth_for_deploy_packet="$(LC_ALL=C get-all-nic-ip -u)"
  fi
  if [ -z "$eth_for_deploy_packet" ]; then
    [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE | tee -a ${OCS_LOGFILE}
    echo "No network card was assigned for sending packets." | tee -a ${OCS_LOGFILE}
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL | tee -a ${OCS_LOGFILE}
    echo "$msg_program_stop!"
    exit 1
  fi
  cast_srv_ip="$(LC_ALL=C drbl-get-ipadd $eth_for_deploy_packet)"
} # end of get_cast_srv_ip
#
config_netcard() {
  local status_done
  # nic_dev_only is global variable
  # Get the NIC device name for the only one device
  # TODO: find a better way to find when there are multiple NICs?
  nic_dev_only="$(get-nic-devs | head -n 1)"
  ip address add $ipadd_closed_lan/$netmask_closed_lan dev ${nic_dev_only}
  ip link set ${nic_dev_only} up
  # Set the routing
  ip route add default via $gwadd_closed_lan dev ${nic_dev_only}
  echo "$msg_delimiter_star_line"
  echo "Network settings for ${nic_dev_only}:"
  ip address show ${nic_dev_only}
} # end of config_netcard
#
gen_lite_dhcpd_conf() {
  local srv_cfg="$1"
  if [ -e "$dnsmasq_cfg" ]; then
    mv -f $dnsmasq_cfg ${dnsmasq_cfg}.orig
  fi
  gen_dnsmasq_cfg -r "${dhcp_rang_start_closed_lan},${dhcp_rang_end_closed_lan}" $dnsmasq_cfg
  echo "$msg_delimiter_star_line" >> ${OCS_LOGFILE}
  echo "DHCP service settings in $dnsmasq_cfg:" >> ${OCS_LOGFILE}
  cat $dnsmasq_cfg >> ${OCS_LOGFILE}
  echo "$msg_delimiter_star_line" >> ${OCS_LOGFILE}
} # end of gen_lite_dhcpd_conf
#
gen_ocs_live_netboot_conf() {
  local pxe_menu_to_hide pxe_menu_to_reveal
  local grub_menu_to_hide grub_menu_to_reveal
  # squashfs_fmode is global variable.
  PXE_CONF="$PXELINUX_DIR/default"
  GRUB_CONF="$GRUB_EFINB_DIR/grub.cfg"
  pxe_menu_to_hide="drbl clonezilla"
  pxe_menu_to_reveal="Clonezilla-live local"
  grub_menu_to_hide="drbl-client clonezilla-se-client"
  grub_menu_to_reveal="clonezilla-live-client local-disk"
  generate-pxe-menu

  # A workaround to fix the dnsmasq issue for uEFI network boot clients (actually grub should be patched)
  # i.e., we have to assign the tftp server IP address in grub network boot loader.
  # This is only necessary when dnsmasq is used to relay the DHCP request from clients to existing DHCP service
  # Now this only works for non-secure-boot clients.
  # Ref: http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2017q1/011124.html
  #      https://lists.gnu.org/archive/html/grub-devel/2016-04/msg00051.html
  if [ "$secure_boot_client" = "no" ]; then
    case "$ocs_litesrv_netmode" in
      "use-existing-dhcpd") drbl-gen-grub-efi-nb -t $cast_srv_ip ;;
    esac
  else
    # Secure boot for clients is enabled, so force to use the signed shim and grub.
    drbl-gen-grub-efi-nb -s
  fi

  # Add Clonezilla live in the boot menu and for netboot. Actually we will use http service instead of tftpd. However, just run drbl-sl to make things easier. Hence both files for netboot using tftpd and httpd will be ready.
  if [ "$squashfs_fmode" -ge 4 ]; then
    # Use link since it's readable for www-data account (default user for lighttpd)
    drbl-sl -e -b -n -o -p $LIVE_MEDIA
  else
    # Just copy the file to tftpboot root since it's not readable by www-data
    drbl-sl -b -n -o -p $LIVE_MEDIA
    chmod 644 $pxecfg_pd/Clonezilla-live-filesystem.squashfs
  fi
  # Reveal and hide boot menu
  for imenu in $pxe_menu_to_reveal; do
    hide_reveal_pxe_img $imenu reveal $PXE_CONF
  done
  for imenu in $pxe_menu_to_hide; do
    hide_reveal_pxe_img $imenu hide $PXE_CONF
  done
  for imenu in $grub_menu_to_reveal; do
    hide_reveal_grub_efi_ent $imenu reveal $GRUB_CONF
  done
  for imenu in $grub_menu_to_hide; do
    hide_reveal_grub_efi_ent $imenu hide $GRUB_CONF
  done
  if [ -n "$target_dir" ]; then
    # massive-deployment mode
    set-default-pxe-img -i "Clonezilla-live" -c $PXE_CONF -l "Clonezilla live lite client: restore $target_dir"
    set-default-grub-efi-img -i "clonezilla-live-client" -c $GRUB_CONF -l "Clonezilla live lite client: restore $target_dir"
  else
    # interactive-client mode
    set-default-pxe-img -i "Clonezilla-live" -c $PXE_CONF
    set-default-grub-efi-img -i "clonezilla-live-client" -c $GRUB_CONF
  fi

  # Add boot parameters: locales, kb, ocs-live-get-img $server
  echo "Modifying keyboard-layouts, locales, ocs_daemonon, and ocs_prerun in $PXE_CONF if necessary..."
  # Keymap should be the same with server. If not found use that assigned in drbl-ocs.conf.
  if [ -e /etc/default/keyboard ]; then
    # Debian based system. The content of vconsole.conf is like:
    # ================
    # XKBMODEL="pc105"
    # XKBLAYOUT="us"
    # XKBVARIANT=""
    # XKBOPTIONS=""
    # ================
    . /etc/default/keyboard
    client_kb_layout="$XKBLAYOUT"
    client_kb_model="$XKBMODEL"
    client_kb_variant="$XKBVARIANT"
    client_kb_options="$XKBOPTIONS"
  fi
  if [ -z "$client_kb_layout" ]; then
    # If no keybouard layout is found, set it as that
    # is assigned in drbl-ocs.conf, force to update it.
    client_kb_layout="$ocs_live_keymap_for_pxe_ocs_live"
    # For the rest (model, variant or options they might be nothing.
  fi
  if [ -n "$client_kb_layout" ]; then
    add_opt_in_pxelinux_cfg_block -n Clonezilla-live keyboard-layouts "$client_kb_layout"
    add_opt_in_grub_efi_cfg_block -n "clonezilla-live-client" keyboard-layouts "$client_kb_layout"
  fi
  if [ "$ls_client_mode"  = "massive-deployment" ]; then
    # While for massive-deployment mode, force to use $ocs_lang_for_pxe_ocs_live. 
    # Normally it should be "en_US.UTF-8". Check drbl-ocs.conf for more details.
    if [ -n "$ocs_lang_for_pxe_ocs_live" ]; then
      add_opt_in_pxelinux_cfg_block -n Clonezilla-live locales "$ocs_lang_for_pxe_ocs_live"
      add_opt_in_grub_efi_cfg_block -n "clonezilla-live-client" locales "$ocs_lang_for_pxe_ocs_live"
    fi
    add_opt_in_pxelinux_cfg_block Clonezilla-live ocs_live_run "ocs-live-get-img $cast_srv_ip"
    add_opt_in_grub_efi_cfg_block "clonezilla-live-client" ocs_live_run "ocs-live-get-img $cast_srv_ip"
  elif [ "$ls_client_mode"  = "interactive-client" ]; then
    # For interactive-client mode, we might enter CJK language which needs framebuffer mode to run jfbterm.
    # Hence we add vga=788 to enter framebuffer mode.
    add_opt_in_pxelinux_cfg_block -n Clonezilla-live vga 788
    add_opt_in_grub_efi_cfg_block -n "clonezilla-live-client" vga 788
    # We take ocs_lang from ocs-live.conf and set it for netboot client in interactive mode.
    add_opt_in_pxelinux_cfg_block -n Clonezilla-live locales "$ocs_lang"
    add_opt_in_grub_efi_cfg_block -n "clonezilla-live-client" locales "$ocs_lang"
  fi
  # Overwrite the default background photo
  cp -a $DRBL_SCRIPT_PATH/image/ocswp-grub2.png $pxecfg_pd/drblwp.png
  # Switch the menu title to Clonezilla
  perl -pi -e "s|^MENU TITLE.*|MENU TITLE Clonezilla \(https://clonezilla.org\)|g" $PXELINUX_DIR/default
} # end of gen_ocs_live_netboot_conf
#
start_nat_service() {
  local subnet
  NAT_RULES_FOR_DEBIAN=/etc/default/ocs-live-lite-nat.rules
  subnet="$(LC_ALL=C drbl-ipcalc $ipadd_closed_lan/$netmask_closed_lan | awk -F' ' '/Network:/ {print $2}')"
  # Flush all rules first
  iptables -F
  iptables -t nat -F
  iptables -t mangle -F
  # Configure it 
  iptables -t nat -A POSTROUTING -s ${subnet} -j MASQUERADE
  iptables-save > $NAT_RULES_FOR_DEBIAN
  # Enable IP forwarding
  echo 1 > /proc/sys/net/ipv4/ip_forward
} # end of start_nat_service
# 
stop_nat_service() {
  local ret
  # Borrow from Debian
  IPTABLES=iptables
  IPV=${IPTABLES%tables} # ip for ipv4 | ip6 for ipv6
  PROC_IPTABLES_NAMES=/proc/net/${IPV}_tables_names
  # Flush firewall rules and delete chains.
  [ -e "$PROC_IPTABLES_NAMES" ] || return 1

  # Check if firewall is configured (has tables)
  tables=`cat $PROC_IPTABLES_NAMES 2>/dev/null`
  echo -n $"Flushing firewall rules: "
  ret=0
  # For all tables
  for i in $tables; do
      # Flush firewall rules.
      $IPTABLES -t $i -F;
      let ret+=$?;

      # Delete firewall chains.
      $IPTABLES -t $i -X;
      let ret+=$?;

      # Set counter to zero.
      $IPTABLES -t $i -Z;
      let ret+=$?;
  done

  [ $ret -eq 0 ] && echo "success" || echo "failure"
  # Disable IP forwarding
  echo 0 > /proc/sys/net/ipv4/ip_forward
} # end of stop_nat_service
#
configure_net_and_dhcp_mode(){
  # If network setting is not configured. Ask
  # TODO: What if multiple IP addresses?
  configured_ip="$(get-all-nic-ip --all-ip-address)"
  if [ -z "$client_boot_mode" ]; then
    TMP="$(mktemp /tmp/ocslivemode.XXXXXX)"
    trap "[ -f "$TMP" ] && rm -f $TMP" HUP INT QUIT TERM EXIT
    $DIA --backtitle "$msg_nchc_free_software_labs" --title  \
    "Client boot mechanism" --menu "$msg_which_mode_for_client_boot\n$msg_choose_mode:" \
    0 0 0 $DIA_ESC \
    "netboot"          "$msg_boot_client_with_network" \
    "local-boot-media" "$msg_boot_with_local_media" \
    "both"             "$msg_boot_client_with_network_and_local_media" \
    2> $TMP
    client_boot_mode="$(cat $TMP)"
    echo "client_boot_mode is $client_boot_mode"
    [ -f "$TMP" ] && rm -f $TMP
  fi
  if [ -n "$client_boot_mode" ]; then
    OCS_OPT_PRE="$OCS_OPT_PRE -cbm $client_boot_mode"
  fi

  # If secure boot is enabled for clients, then set ocs_litesrv_netmode as start-new-dhcpd
  # This limit can be lifted in the future when shim and grub honor the proxy mode of dnsmasq.
  # Ref: https://lists.gnu.org/archive/html/grub-devel/2016-04/msg00051.html
  #      http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2017q1/011347.html
  if [ "$secure_boot_client" = "yes" ]; then
    [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING | tee --append ${OCS_LOGFILE}
    echo "$msg_secure_boot_for_clients_is_enabled" | tee --append ${OCS_LOGFILE}
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL | tee --append ${OCS_LOGFILE}
    ocs_litesrv_netmode="start-new-dhcpd"
    if [ "$ocs_batch_mode" != "on" ]; then
      echo -n "$msg_press_enter_to_continue..."
      read
    fi
  fi
  # 
  if [ -z "$ocs_litesrv_netmode" ]; then
    ask_dhcpd=""
    case "$client_boot_mode" in
      "netboot")          ask_dhcpd="yes";;
      "local-boot-media") ask_dhcpd="no";;
      "both")             ask_dhcpd="yes";;
    esac
    # Ask if starts own dhcpd or using existing dhcpd
    if [ "$ask_dhcpd" = "yes" ]; then
      TMP="$(mktemp /tmp/ocslivemode.XXXXXX)"
      trap "[ -f "$TMP" ] && rm -f $TMP" HUP INT QUIT TERM EXIT
      $DIA --backtitle "$msg_nchc_free_software_labs" --title  \
      "DHCP service" --menu "$msg_how_to_run_dhcpd\n$msg_choose_mode:" \
      0 0 0 $DIA_ESC \
      "auto-detect"         "$msg_auto_detect_dhcpd" \
      "use-existing-dhcpd"  "$msg_use_existing_dhcpd" \
      "start-new-dhcpd"     "$msg_start_new_dhcpd" \
      2> $TMP
      ocs_litesrv_netmode="$(cat $TMP)"
      echo "ocs_litesrv_netmode is $ocs_litesrv_netmode"
      [ -f "$TMP" ] && rm -f $TMP
    else
      # ask_dhcpd is "no"
      ocs_litesrv_netmode="no-dhcpd"
    fi
  fi
  # 4 modes for ocs_litesrv_netmode: use-existing-dhcpd, start-new-dhcpd, auto-detect, no-dhcpd" -> where auto-detect will be decided as "use-existing-dhcpd" or "start-new-dhcpd" in the end.
  if [ -n "$ocs_litesrv_netmode" ]; then
    OCS_OPT_PRE="$OCS_OPT_PRE -dm $ocs_litesrv_netmode"
  fi
  if [ "$ocs_litesrv_netmode" = "auto-detect" ]; then
    # Detect if there is an existing DHCP service in LAN
    detect_dhcp_srv_in_lan  # Get use_existing_dhcp_srv and DHCPOFFER_eth
    case "$use_existing_dhcp_srv" in
      "yes") dhclient -v $DHCPOFFER_eth
	     ocs_litesrv_netmode="use-existing-dhcpd"
	     ;;
      "no")  ocs_litesrv_netmode="start-new-dhcpd";;
    esac
  fi
  case "$ocs_litesrv_netmode" in
    "no-dhcpd")
       # Even if no dhcpd, like local repository,
       # we still have to configure network
       # otherwise the udp-sender won't start.
       network_config_if_necessary
       ;;
    "use-existing-dhcpd")
       # Even if it's local repository, we still have to configure network
       # otherwise the udp-sender won't start.
       network_config_if_necessary
       gen_dnsmasq_cfg -a $dnsmasq_cfg
       ;;
    "start-new-dhcpd") 
       if [ -z "$configured_ip" ]; then
         config_netcard
       fi
       uplink_port="$(LC_ALL=C get-all-nic-ip -u)"
       if [ -z "$uplink_port" ]; then
         [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE | tee -a ${OCS_LOGFILE}
         echo "No default gateway was configured." | tee -a ${OCS_LOGFILE}
         [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL | tee -a ${OCS_LOGFILE}
         echo "$msg_program_stop!"
         exit 1
       fi
       uplink_port_ip="$(LC_ALL=C drbl-get-ipadd $uplink_port)"
       uplink_port_nm="$(LC_ALL=C drbl-get-netmask $uplink_port)"
       if [ -z "$uplink_port_ip" -o -z "$uplink_port_nm" ]; then
         [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE | tee -a ${OCS_LOGFILE}
         echo "No configured IP address or netmask was found in NIC $uplink_port." | tee -a ${OCS_LOGFILE}
         [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL | tee -a ${OCS_LOGFILE}
         echo "$msg_program_stop!"
         exit 1
       fi
       dhcp_rang_start_closed_lan="$(LC_ALL=C drbl-ipcalc $uplink_port_ip $uplink_port_nm | awk -F' ' '/^HostMin:/ {print $2}')"
       dhcp_rang_end_closed_lan="$(LC_ALL=C drbl-ipcalc $uplink_port_ip $uplink_port_nm | awk -F' ' '/^HostMax:/ {print $2}')"
       echo "In isolation environment. Now start dhcp service..." 
       gen_lite_dhcpd_conf $dnsmasq_cfg
       ;;
    *) echo "Unknown mode for ocs_litesrv_netmode: $ocs_litesrv_netmode"
       echo "$msg_program_stop" | tee -a ${OCS_LOGFILE}
       exit 0
       ;;
  esac
} # end of configure_net_and_dhcp_mode
#
task_start_feed_img_for_cast() {
  local MCAST_TMP ans_ cast_dev_action 
  local start_cmd
  local OCS_OPT_PRE ocs_opt_dia
  local rc_chkimg rc_final bt_metainfo_cmd rc_feed
  local castmode choose_term input_key input_key2 raw_dev_opt
  local pid1_prog
  local pseudo_img_cmd

  #prompt_for_lite_server

  configure_net_and_dhcp_mode

  MCAST_TMP=`mktemp /tmp/ocs_recovery_tmp.XXXXXX`
  trap "[ -f "$MCAST_TMP" ] && rm -f $MCAST_TMP" HUP INT QUIT TERM EXIT

  if [ -e "$ocs_lock_dir/clonezilla.lock" ]; then 
    task_stop_feed_img_for_cast
  fi

  # Deal with ocs_repository since it's not processed in ocs-live-run-menu when ocs_repository is shown in kernel boot parameters.
  # ocs-live-repository directly parses /proc/cmdline, not reads variable from ocs-live.conf
  if [ -n "$(grep -Ewo ocs_repository /proc/cmdline)" ]; then
    ocs-live-repository
  fi
  # When $ocsroot is not a mount point, and nothing lists under it, run ocs-prep-repo
  if [ "$ocs_sr_mode" = "interactive" ]; then
    if ! mountpoint $ocsroot &>/dev/null; then
      if [ -z "$(ls -d $ocsroot/*/ 2>/dev/null)" ]; then
        ocs-prep-repo
      fi
    fi
  fi

  #
  if [ "$ocs_sr_mode" = "interactive" ]; then
    [ -z "$ocs_user_mode" ] && ask_if_beginner_or_expert_mode
  fi

  if [ -z "$ls_client_mode" ]; then
    # Ask if restoring or clonezilla live diskless service
    TMP=$(mktemp /tmp/menu.XXXXXX)
    trap "[ -f "$TMP" ] && rm -f $TMP" HUP INT QUIT TERM EXIT
    $DIA \
    --backtitle "$msg_nchc_title" \
    --title "$msg_start_clonezilla_mode" \
    --menu "$msg_clonezilla_is_free_and_no_warranty\n$msg_choose_mode:" 0 0 0 \
    "massive-deployment" "$msg_clonezilla_massive_deployment" \
    "interactive-client" "$msg_netboot_interactive_client" \
    2> $TMP
    ls_client_mode="$(cat $TMP)"
    [ -f "$TMP" ] && rm -f $TMP
  fi
  if [ -z "$ls_client_mode" ]; then
    echo "$msg_program_stop!"
    exit 1
  fi
  if [ -n "$ls_client_mode" ]; then
    OCS_OPT_PRE="$OCS_OPT_PRE -lscm $ls_client_mode"
  fi

  # Clean stale files to avoid accidentally using them.
  rm -f /var/www/html/ocs-client-run.conf /var/www/html/img-wo-fs.tar.xz | tee -a ${OCS_LOGFILE}
  if [ "$ls_client_mode"  = "massive-deployment" ]; then
    if type ocs-bttrack &>/dev/null; then
      # Enable from-device (BT) when ocs-bttrack exists, otherwise only from-image.
      # Ask image massive deployment or BT onthefly
      # from-image: ocs_restore_img_name=ocs_img_name_or_src_dev
      # from-device: ocs_source_dev=ocs_img_name_or_src_dev
      if [ -z "$md_source_type" ]; then
        TMP=$(mktemp /tmp/menu.XXXXXX)
        trap "[ -f "$TMP" ] && rm -f $TMP" HUP INT QUIT TERM EXIT
        $DIA \
        --backtitle "$msg_nchc_title" \
        --title "$msg_start_clonezilla_mode" \
        --menu "$msg_clonezilla_is_free_and_no_warranty\n$msg_choose_mode:" 0 0 0 \
        "from-image" "$msg_img_massive_deploy" \
        "from-device" "$msg_dev_massive_deploy" \
        2> $TMP
        md_source_type="$(cat $TMP)"
        [ -f "$TMP" ] && rm -f $TMP
      fi
    else
        [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
        echo "Program ocs-bttrack was not found. Only massive deploymnet from image is available."
        md_source_type="from-image"
        [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    fi
    case "$md_source_type" in
      from-image)  ocs_restore_img_name="$ocs_img_name_or_src_dev";;
      from-device) # No matter the input is like /dev/sda or sda, format it as sda
		   ocs_source_dev="$(strip_leading_dev $ocs_img_name_or_src_dev)"
		   ;; 
               *)  echo "Unknown type for md_source_type!"
                   echo "$msg_program_stop!"
                   exit 1
		   ;;
    esac
    if [ -n "$md_source_type" ]; then
      OCS_OPT_PRE="$OCS_OPT_PRE -mdst $md_source_type"
    fi

    case "$md_source_type" in
    from-image) 
      # Ask image name first (disk or parts image) for from-image mode
      # Image name
      if [ "$ocs_restore_img_name" = "ask_user" ]; then
        TMP=$(mktemp /tmp/menu.XXXXXX)
        trap "[ -f "$TMP" ] && rm -f $TMP" HUP INT QUIT TERM EXIT
        $DIA \
        --backtitle "$msg_nchc_title" \
        --title "$msg_start_clonezilla_mode" \
        --menu "$msg_clonezilla_is_free_and_no_warranty\n$msg_choose_mode:" 0 0 0 \
        "restoredisk" "$msg_clonezilla_restore_disk" \
        "restoreparts" "$msg_clonezilla_restore_parts" \
        2> $TMP
        cast_dev_action="$(cat $TMP)"
        [ -f "$TMP" ] && rm -f $TMP
        # ocs_mode_prompt will be passed to the dialog about asking dev_type, OCS parameters...
        ocs_mode_prompt="$cast_dev_action"
        case "$cast_dev_action" in
        "restoredisk")
          ANS_TMP=`mktemp /tmp/ocs_ans.XXXXXX`
          trap "[ -f "$ANS_TMP" ] && rm -f $ANS_TMP" HUP INT QUIT TERM EXIT
          get_existing_disk_image $ANS_TMP rest-unenc
          # the return name will be only one image name.
          target_dir="$(cat $ANS_TMP)"
          [ -e "$ANS_TMP" ] && rm -f $ANS_TMP
          dev_type="disk"
          ;;
        "restoreparts")
          ANS_TMP=`mktemp /tmp/ocs_ans.XXXXXX`
          trap "[ -f "$ANS_TMP" ] && rm -f $ANS_TMP" HUP INT QUIT TERM EXIT
          get_existing_parts_image $ANS_TMP rest-unenc
          # the return name will be only one image name.
          target_dir="$(cat $ANS_TMP)"
          [ -e "$ANS_TMP" ] && rm -f $ANS_TMP
          dev_type="parts"
          ;;
        *)
          echo "Unknown mode for cast_dev_action: $cast_dev_action"
          echo "$msg_program_stop!"
          exit 1
          ;;
        esac
        ocs_restore_img_name="$target_dir"  # Keep it for later use in run_again prompt
      else
        target_dir="$ocs_restore_img_name"
      fi
      ;;
    from-device) 
      # For from-device mode (BT onthefly) since ocs_source_dev is for from-device mode
      if [ "$ocs_source_dev" = "ask_user" ]; then
        if [ -z "$bt_dev_type" ]; then
          TMP=$(mktemp /tmp/menu.XXXXXX)
          trap "[ -f "$TMP" ] && rm -f $TMP" HUP INT QUIT TERM EXIT
          $DIA \
          --backtitle "$msg_nchc_title" \
          --title "$msg_start_clonezilla_mode" \
          --menu "$msg_clonezilla_is_free_and_no_warranty\n$msg_choose_mode:" 0 0 0 \
          "disk-2-mdisks" "$msg_disk_to_mdisk_by_BT" \
          "part-2-mparts" "$msg_part_to_mpart_by_BT" \
          2> $TMP
          bt_dev_type="$(cat $TMP)"
          [ -f "$TMP" ] && rm -f $TMP
        fi
      
        # ocs_mode_prompt will be passed to the dialog about asking dev_type, OCS parameters...
        ocs_mode_prompt="$bt_dev_type"
        case "$bt_dev_type" in
        "disk-2-mdisks")
          if [ "$ocs_source_dev" = "ask_user" ]; then
            # To get $target_hd
            get_target_hd_name_from_local_machine "$msg_local_source_disk \n$msg_linux_disk_naming $msg_press_space_to_mark_selection"
            ocs_source_dev="$target_hd"
          fi
          dev_type="disk"
          ;;
        "part-2-mparts")
          if [ "$ocs_source_dev" = "ask_user" ]; then
            # To get $target_parts
            get_target_parts_name_from_local_machine "$msg_local_source_part \n$msg_linux_parts_MS_mapping" $dia_sel_opt
            ocs_source_dev="$target_parts"
          fi
          dev_type="parts"
          ;;
        *)
          echo "Unknown mode for bt_dev_type: $bt_dev_type"
          echo "$msg_program_stop!"
          exit 1
          ;;
        esac
        if [ -n "$bt_dev_type" ]; then
          OCS_OPT_PRE="$OCS_OPT_PRE -bdt $bt_dev_type"
        fi
        # Since the mode is decided, we can assign some variables now.
        # Force set destination disk in the clients as the same one from this local machine, and the mode is BT
        ocs_restore_dev="$ocs_source_dev"
        massive_deploy_mode="bittorrent"
        # Prepare 3 variables: cast_dev_action, target_hd|target_parts for later use with start_ocs_service:
        # cast_dev_action is required for function start_ocs_service
        # while target_hd or target_parts is required for function 
        # multicast|bt_restoredisk and multicast|bt_restoreparts (hence for start_ocs_service)
        case "$bt_dev_type" in
          "disk-2-mdisks") cast_dev_action="restoredisk" ;;
          "part-2-mparts") cast_dev_action="restoreparts" ;;
        esac
      fi
      ;;
    esac

    if [ "$md_source_type" = "from-image" ]; then
      check_input_target_image "$ocsroot/$target_dir"
    fi
  
    # Get target device for both from-image and from-device modes
    if [ -z "$ocs_restore_dev" -o \
            "$ocs_restore_dev" = "ask_user" ]; then
      # choose the only dev we want
      case "$dev_type" in
       "disk")
          ANS_TMP=`mktemp /tmp/ocs_ans.XXXXXX`
          trap "[ -f "$ANS_TMP" ] && rm -f $ANS_TMP" HUP INT QUIT TERM EXIT
  	  get_existing_disks_from_img $ANS_TMP $imagedir/$target_dir
          # we have to remove " (comes with checklist in dialog) so that for loop
          # will work (Specially for FC3/4...)
          target_hd="$(cat $ANS_TMP | tr -d \")"
          ocs_restore_dev="$target_hd" # keep it for later use in run_again prompt
          [ -f "$ANS_TMP" ] && rm -f $ANS_TMP
          ;;
       "parts")
          ANS_TMP=`mktemp /tmp/ocs_ans.XXXXXX`
          trap "[ -f "$ANS_TMP" ] && rm -f $ANS_TMP" HUP INT QUIT TERM EXIT
  	  get_existing_partitions_from_img $ANS_TMP $imagedir/$target_dir no restore
          # we have to remove " (comes with checklist in dialog) so that for loop
          # will work (Specially for FC3/4...)
          target_parts="$(cat $ANS_TMP | tr -d \")"
          ocs_restore_dev="$target_parts" # keep it for later use in run_again prompt
          [ -f "$ANS_TMP" ] && rm -f $ANS_TMP
          ;;
       *)
         echo "Unknown dev_type in $0: $dev_type"
         echo "$msg_program_stop!"
         exit 1
         ;;
      esac
    elif [ "$ocs_restore_dev" = "all" -o "$ocs_restore_dev" = "all-but-usb" ]; then
      # If "all" is used, only whole disk(s), not partitions.
      # //NOTE// Need to exclude Clonezilla live USB flash drive
      # Prepare 3 variables: cast_dev_action, target_hd|target_parts for later use with start_ocs_service:
      # cast_dev_action is required for function start_ocs_service
      # while target_hd or target_parts is required for function 
      # multicast|bt_restoredisk and multicast|bt_restoreparts (hence for start_ocs_service)
      # For BT mode, bt_dev_type is assigned. For multicast/broadcst mode, not yet?
      cast_dev_action="restoredisk"
      get_not_busy_disks_or_parts harddisk "" ""  # we will get dev_list
      target_hd=""
      if [ "$ocs_restore_dev" = "all-but-usb" ]; then
        # Only non-USB device
        for id in $dev_list; do
          if ! is_usb_dev $id; then
	    target_hd="$target_hd $id"
	  fi
	done
      else
        # Include USB device, i.e., all available disks
        target_hd="$dev_list"
      fi
      ocs_restore_dev="$target_hd" # keep it for later use in run_again prompt
    else
      # "ocs_restore_dev" is already assigned
      if [ -n "$dev_type" ]; then
        # In interactive mode, we know what the $dev_type is.
        case "$dev_type" in
          "disk")  cast_dev_action="restoredisk"
		   target_hd="$ocs_restore_dev"
		   ;;
          "parts") cast_dev_action="restoreparts"
		   target_parts="$ocs_restore_dev"
		   ;;
        esac
      else
        # Prepare 3 variables: cast_dev_action, target_hd|target_parts for later use with start_ocs_service:
        # cast_dev_action is required for function start_ocs_service
        # while target_hd or target_parts is required for function 
        # multicast|bt_restoredisk and multicast|bt_restoreparts (hence for start_ocs_service)
	# For BT mode, bt_dev_type is assigned. For multicast/broadcst mode, not yet?
        case "$bt_dev_type" in
          "disk-2-mdisks") cast_dev_action="restoredisk"
                           target_hd="$ocs_restore_dev"
		           ;;
          "part-2-mparts") cast_dev_action="restoreparts"
                           target_parts="$ocs_restore_dev"
		           ;;
        esac
	# For cast_dev_action still can not be found at the moment.
        # When not in interactive mode, we have no idea what $dev_type is.
        # However, we can tell from $ocs_restore_dev, e.g. sda -> disk, sda1 -> parts
	if [ -z "$cast_dev_action" ]; then
          first_ele="$(echo $ocs_restore_dev | awk -F" " '{print $1}')"
          if is_whole_disk $first_ele; then
            cast_dev_action="restoredisk"
            target_hd="$ocs_restore_dev"
          else
            cast_dev_action="restoreparts"
            target_parts="$ocs_restore_dev"
          fi
        fi
      fi
    fi
  
    # When Clonezilla live runs as multicast feeding server, the uplink port is where the packets sending.
    # No matter it's multicast, broadcast or bt, we use that ethernet port
    get_cast_srv_ip
  
    case "$md_source_type" in
      from-image) 
        if [ "$ocs_sr_mode" = "interactive" ]; then
          # ask if want to set ocs extra param
          OCS_PARAM_TMP=`mktemp /tmp/ocs_param_tmp.XXXXXX`
          trap "[ -f "$OCS_PARAM_TMP" ] && rm -f $OCS_PARAM_TMP" HUP INT QUIT TERM EXIT
          set_drbl_ocs_extra_param -s -p reboot restore $dev_type
          # OCS_OPT_PRE is for ocs-live-feed-img, we have to convert to that for ocs-sr
          ocs_opt_dia="$(cat $OCS_PARAM_TMP)"
          ocs_opt_dia="$(echo $ocs_opt_dia)"  # Make it in one line
          parse_ocs_live_feed_img_cmd_options_with_dash $ocs_opt_dia # Obtain $OCS_OPT for ocs-sr
          [ -f "$OCS_PARAM_TMP" ] && rm -f $OCS_PARAM_TMP
          if [ -n "$ocs_opt_dia" ]; then
            OCS_OPT_PRE="$OCS_OPT_PRE $ocs_opt_dia"
          fi
        fi
        # Load default settings if not assigned
        if [ -z "$chk_img_restoreable_on_srv" ]; then
          chk_img_restoreable_on_srv="$chk_img_restoreable_on_srv_def"
        fi
        ;;
      from-device) 
	# Two parts: (1) fsck source dev. 
	#            (2) Parameters for restoring clients.
	# 1. Ask about fsck source dev
        OCS_PARAM_TMP=`mktemp /tmp/ocs_sr_param_tmp.XXXXXX`
        trap "[ -f "$OCS_PARAM_TMP" ] && rm -f $OCS_PARAM_TMP" HUP INT QUIT TERM EXIT
        # Question about fsck the source partition. By default, no matter it's beginner or advanced mode, we will ask.
        if [ -z "$btsrc_dev_fsck" ]; then
          $DIA --backtitle "$msg_nchc_free_software_labs" --title  \
          "$msg_clonezilla_advanced_extra_param | $msg_mode: $ocs_mode_prompt" --menu "$msg_save_temp_img_for_BT\n$msg_choose_if_fsck_the_source_part" \
          0 0 0 $DIA_ESC \
          "-sfsck "  "$msg_skip_check_source_fs" \
          "-fsck "   "$msg_ocs_param_fsck_src_part" \
          "-fsck-y " "$msg_ocs_param_fsck_src_part_yes" \
          2>> $OCS_PARAM_TMP
	  # Remove the first "-", make like: -sfsck -> sfsck
	  # This is to avoid it's used as an option for ocs-live-feed-img.
	  # Otherwise ocs-live-feed-img will parse wrongly.
	  perl -pi -e 's|^-(.*)$|$1|' $OCS_PARAM_TMP
        else
          echo "${btsrc_dev_fsck} " >> $OCS_PARAM_TMP
        fi
        btsrc_dev_fsck="$(cat $OCS_PARAM_TMP)"
        [ -f "$OCS_PARAM_TMP" ] && rm -f $OCS_PARAM_TMP
        if [ -n "$btsrc_dev_fsck" ]; then
          OCS_OPT_PRE="$OCS_OPT_PRE -bsdf ${btsrc_dev_fsck}"
	  # E.g., sfsck -> -sfsck
	  btsrc_dev_fsck_opt="-${btsrc_dev_fsck}"
        fi

	# 2. Ask parameters about restoring clients
        if [ "$ocs_sr_mode" = "interactive" ]; then
          # ask if want to set ocs extra param
          OCS_PARAM_TMP=`mktemp /tmp/ocs_param_tmp.XXXXXX`
          trap "[ -f "$OCS_PARAM_TMP" ] && rm -f $OCS_PARAM_TMP" HUP INT QUIT TERM EXIT
	  # The pseudo image is not restorable. Only some files about partition table and boot loader. Therefore skip check it.
	  chk_img_restoreable_on_srv="-sc0"
          set_drbl_ocs_extra_param -s -p reboot restore $dev_type
          # OCS_OPT_PRE is for ocs-live-feed-img, we have to convert to that for ocs-sr
          ocs_opt_dia="$(cat $OCS_PARAM_TMP)"
          ocs_opt_dia="$(echo $ocs_opt_dia)"  # Make it in one line
          parse_ocs_live_feed_img_cmd_options_with_dash $ocs_opt_dia # Obtain $OCS_OPT for ocs-sr
          [ -f "$OCS_PARAM_TMP" ] && rm -f $OCS_PARAM_TMP
          if [ -n "$ocs_opt_dia" ]; then
            OCS_OPT_PRE="$OCS_OPT_PRE $ocs_opt_dia"
          fi
        fi
        ;;
    esac
    # keep ocs_img_name_or_src_dev so it can be used for run again prompt
    case "$md_source_type" in
      from-image) ocs_img_name_or_src_dev="$ocs_restore_img_name";;
      from-device) ocs_img_name_or_src_dev="$ocs_source_dev";;
    esac
  
    # Enable bittorrent restoring when ocs-bttrack is available
    if type ocs-bttrack &>/dev/null; then
      bt_restore_msg_1="bittorrent"
      bt_restore_msg_2="$(rep_whspc_w_udrsc "$msg_bittorent_restore")"
    fi
    # get the mode of multicast, broadcast or bittorrent
    eval msg_choose_the_mode_to_restore_dev=\$msg_choose_the_mode_to_restore_${dev_type}
    if [ -z "$massive_deploy_mode" ]; then
      TMP=$(mktemp /tmp/menu.XXXXXX)
      trap "[ -f "$TMP" ] && rm -f $TMP" HUP INT QUIT TERM EXIT
      $DIA \
      --backtitle "$msg_nchc_title" \
      --title "$msg_nchc_clonezilla | $msg_mode: $ocs_mode_prompt" \
      --menu "$msg_choose_the_mode_to_restore_dev" 0 0 0 \
      "multicast"       "$msg_multicast_restore" \
      "broadcast"       "$msg_broadcast_restore" \
      $bt_restore_msg_1 $bt_restore_msg_2 \
      2> $TMP
      massive_deploy_mode=$(cat $TMP)
      [ -f "$TMP" ] && rm -f $TMP
    fi
    case "$massive_deploy_mode" in
      multicast|broadcast) castmode="multicast";;
               bittorrent) castmode="bt";;
  		        *) echo "$msg_program_stop!"
  			   exit 1;;
    esac
    [ "$massive_deploy_mode" = "broadcast" ] && udp_sender_extra_opt="$udp_sender_extra_opt --broadcast"
    if [ -n "$massive_deploy_mode" ]; then
      OCS_OPT_PRE="$OCS_OPT_PRE -md $massive_deploy_mode"
    fi
  
    # ocs_mode_prompt will be passed to the dialog about asking mcast_wait_time, n_clients, mcast_max_wait_time
    ocs_mode_prompt="$massive_deploy_mode"
    if [ "$castmode" = "multicast" ]; then
      # eth_for_multicast will be passed to function start_ocs_service
      eth_for_multicast="$eth_for_deploy_packet" # passed to function start_ocs_service
      # Force to make client won't check the image integrity since this is for multicast restoring.
      OCS_OPT="$OCS_OPT -scr"
      task="multicast_restore" # pass to function get_multicast_restore_mode_if_mcast
      OCS_OPT="$OCS_OPT --mcast-port $MULTICAST_PORT"
  
      if [ "$ocs_sr_mode" = "interactive" ]; then
        if [ -z "$n_clients" -o "$mcast_wait_time" ]; then
          get_multicast_restore_mode_if_mcast
          # Obtain mcast_wait_time, n_clients, mcast_max_wait_time (global variables) to pass to function start_ocs_service
        fi
      fi
      if [ -n "$n_clients" ]; then
        cast_client_no_opt="-n $n_clients"  # Used for start_ocs_service
        OCS_OPT_PRE="$OCS_OPT_PRE --clients-to-wait $n_clients"  # For re-run prompt
      fi
      if [ -n "$mcast_wait_time" ]; then
        OCS_OPT_PRE="$OCS_OPT_PRE --time-to-wait $mcast_wait_time"  # For re-run prompt
      fi
      if [ -n "$mcast_max_wait_time" ]; then
        OCS_OPT_PRE="$OCS_OPT_PRE --max-time-to-wait $mcast_max_wait_time"  # For re-run prompt
      fi
    elif [ "$castmode" = "bt" ]; then
      # Force to make client won't check the image integrity since this is for BT restoring.
      OCS_OPT="$OCS_OPT -scr"
      # 2020/11/26 No need to ask, since it's BT.
      #get_bt_restore_mode_if_bittorrent
      ## Obtain n_clients (global variables) to pass to function start_ocs_service
      [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
      echo "It's BT mode, so no need to assign the client number." | tee -a ${OCS_LOGFILE}
      [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    fi
  
    # Before really starting the feeding service, we can check if the image integrity is OK or not.
    # If the image is checked on the server, then we force to skip image checking on the clients when restoring.
    if [ -d "$imagedir/$target_dir" -a "$chk_img_restoreable_on_srv" = "yes" ]; then
      echo $msg_delimiter_star_line
      check_image_if_restorable -i "$target_dir" "$imagedir"
      rc_chkimg="$?"
      if [ "$rc_chkimg" -ne 0 ]; then
        echo "$msg_program_stop!"
        exit 1
      fi
    fi

    if [ "$md_source_type" = "from-device" ]; then
      # BT from raw device, we have to ignore the input image name, and create a pseudo image
      # The pseudo image is not restorable. Only some files about partition table and boot loader.
      # If an image name is assigned (for reuse purpose, and user has to make sure the source file system was not modified).
      if [ -n "$mdst_img" -a -d "$imagedir/$mdst_img" ]; then
        target_dir="$mdst_img"
      else
        target_dir="${bt_raw_dev_psuedo_img_prefix}-$(LC_ALL=C date +%Y%m%d-%H%M%S)"
        if [ -d "$ocsroot/${target_dir}" ]; then
          mv $imagedir/${target_dir} $imagedir/${target_dir}-saved
        fi
        case "$bt_dev_type" in
        "disk-2-mdisks")
           pseudo_img_cmd="ocs-sr $btsrc_dev_fsck_opt -sfs -nogui -q2 --batch -j2 -scs -senc -p true savedisk ${target_dir} $target_hd"
	   echo "Running: $pseudo_img_cmd"
	   eval $pseudo_img_cmd
           # Need to list all the partitions.
           part_rec_f="$(mktemp /tmp/part_rec_f_bt.XXXXXX)"
           target_parts=""
           for idisk in $target_hd; do
             echo "Searching for data/swap/extended partition(s)..." | tee --append $OCS_LOGFILE
             get_known_partition_proc_format $idisk all $part_rec_f
             target_parts="$target_parts $(awk -F":" '/^data_dev:/ {print $2}' $part_rec_f | sed -r -e "s|^[[:space:]]*||g")"
           done
           ;;
        "part-2-mparts")
           pseudo_img_cmd="ocs-sr $btsrc_dev_fsck_opt -sfs -nogui -q2 --batch -j2 -scs -senc -p true saveparts ${target_dir} $target_parts"
	   echo "Running: $pseudo_img_cmd"
	   eval $pseudo_img_cmd
           ;;
        esac
      fi
      one_time_image_for_bt="$target_dir"  # Keep the image name for later usage since target_dir is only temporary name.
      if [ -n "$mdst_img" -a -d "$imagedir/btzone/$mdst_img" ]; then
        [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
        echo "Assigned image $mdst_img was found. No need to re-generate torrent metainfo file."
        [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
      else
        mkdir -p $imagedir/btzone/${target_dir}
        bt_metainfo_cmd="ocs-gen-bt-metainfo -d $imagedir/btzone/${target_dir}/ -i $imagedir/${target_dir} $target_parts"
        echo "Running: $bt_metainfo_cmd"
        eval $bt_metainfo_cmd
        echo "Torrent info dir for \"BT from device\" mode use only. This dir can be safely removed if the corresponding pseudo image dir \"$imagedir/$one_time_image_for_bt\" is removed." > "$imagedir/btzone/$one_time_image_for_bt/00-pseudo-img-note.txt"
      fi
      # Assign option raw_dev_opt for start_ocs_service
      raw_dev_opt="-r"
    fi

    # For {multicast|bt}_restoredisk, the input device variable is $target_hd
    # For {multicast|bt}_restoreparts, the input device variable is $target_parts
    start_cmd="start_ocs_service $cast_client_no_opt $raw_dev_opt -f -t \"${castmode}_${cast_dev_action}\" -o \"$target_dir $ocs_restore_dev\""
    echo "Running: $start_cmd"
    eval $start_cmd  # Do not put "| tee -a ${OCS_LOGFILE}". It will loop.
    rc_feed="$?"
    # TODO: Check return status, if it fails, stop here. (not well written here)
    if [ "$rc_feed" -ne 0 ]; then
      [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
      echo "Failed to start service by running:"
      echo "$start_cmd"
      [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
      echo "$msg_program_stop!"
      exit 1
    fi
  
    if [ "$castmode" = "multicast" ]; then
      echo -n "Waiting for udp-sender service to be started... "
      time=$timeout_max
      while [ -z "$(LC_ALL=C ps -www --no-headers -C "udp-sender" -o pid,cmd)" ]; do
        sleep 1
        time="$((time - 1))"
        if [ "$time" -le "0" ]; then
          [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
          echo -n "Timeout for waiting for udp-sender process..." | tee -a ${OCS_LOGFILE}
          [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
          echo "$msg_program_stop!" | tee -a ${OCS_LOGFILE}
          exit 1
        else
          echo -n "$time "
        fi
      done
      echo -e -n "Done!\n"
      echo "Feeding status:" | tee -a ${OCS_LOGFILE}
      echo $msg_delimiter_star_line | tee -a ${OCS_LOGFILE}
      ps -www -C "cat" -C "udp-sender" -o pid,cmd | tee -a ${OCS_LOGFILE}
      echo $msg_delimiter_star_line | tee -a ${OCS_LOGFILE}
      echo "More udp-sender and cat comamnds (if available) will be spawned when the 1st one is done." | tee -a ${OCS_LOGFILE}
    fi
    #
    if [ "$castmode" = "bt" ]; then
      if [ "$md_source_type" = "from-device" ]; then
         # For BT from device, it must be ezio, we decide it's ezio or ezio-static
         get_ezio_prog  # get the variable ezio_prog
         bt_client="$ezio_prog"
      else
	 # For BT from image files, it can be ezio or others (ctorrent, aria2c..)
         # TODO: Make sure it is the same with ocs-btsrv if user assigns it by option -t|--bt-client in ocs-btsrv. Here we assume it's bt_client_def.
         bt_client="$bt_client_def"
	 if [ "$bt_client" = "ezio" ]; then
           # when bt_client is ezio, we have to decide it's ezio or ezio-static
           get_ezio_prog  # get the variable ezio_prog
           bt_client="$ezio_prog"
	 fi
      fi
      echo -n "Waiting for $bt_client service to be started... "
      time=$timeout_max
      while [ -z "$(LC_ALL=C ps -www --no-headers -C "$bt_client" -o pid,cmd)" ]; do
        sleep 1
        time="$((time - 1))"
        if [ "$time" -le "0" ]; then
          [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
          echo -n "Timeout for waiting for $bt_client process..." | tee -a ${OCS_LOGFILE}
          [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
          echo "$msg_program_stop!" | tee -a ${OCS_LOGFILE}
          exit 1
        else
          echo -n "$time "
        fi
      done
      echo -e -n "Done!\n"
      echo "Feeding status:" | tee -a ${OCS_LOGFILE}
      echo $msg_delimiter_star_line | tee -a ${OCS_LOGFILE}
      ps -www -C "cat" -C "$bt_client" -o pid,cmd | tee -a ${OCS_LOGFILE}
      echo $msg_delimiter_star_line | tee -a ${OCS_LOGFILE}
      # We use multi-torrent feature by ezio >= 1.1.6 so there is only one ezio process for all the partitions and LVs.
    fi
  
    # Prepare image for clients
    echo $msg_delimiter_star_line
    # Two parts: img-wo-fs.tar.xz and ocs-client-run.conf
    # Part 1: img-wo-fs.tar.xz
    echo "Preparing files for clients to download in /var/www/html/: ocs-client-run.conf, img-wo-fs.tar.xz" | tee -a ${OCS_LOGFILE}
    echo "Packing the tarball containing no file system images: img-wo-fs.tar.xz..." | tee -a ${OCS_LOGFILE}
    img_no_fs_tmp="$(mktemp -d /tmp/img_no_fs.XXXXXX)"
    rsync -a --exclude=*-ptcl-img.* --exclude=*.ntfs-img.* --exclude=*.dd-img.* $imagedir/$target_dir/* $img_no_fs_tmp | tee -a ${OCS_LOGFILE}
    if [ -d "$imagedir/btzone/$target_dir" ]; then
      mkdir -p $img_no_fs_tmp/btzone/$target_dir
      rsync -a $imagedir/btzone/$target_dir/*.torrent $img_no_fs_tmp/btzone/$target_dir | tee -a ${OCS_LOGFILE}
    fi
    # TODO: partimage file name, or drop it?
    for ifile in $imagedir/$target_dir/*-ptcl-img.* \
               $imagedir/$target_dir/*.ntfs-img.* \
               $imagedir/$target_dir/*.dd-img.*; do
      [ ! -e "$ifile" ] && continue  
      fn="$(basename $ifile)"
      touch $img_no_fs_tmp/$fn
    done
    ( cd $img_no_fs_tmp
      # The img_no_fs_tmp dir now contains a subdir btzone (if BT mode) and the clonezilla image files.
      # E.g.:
      #  -rw-r--r-- root/root       116 2019-09-11 13:13 00-pseudo-img-note.txt
      #  -rw-r--r-- root/root      1067 2019-09-11 13:13 blkdev.list
      #  -rw-r--r-- root/root       579 2019-09-11 13:13 blkid.list
      #  drwxr-xr-x root/root         0 2019-09-11 13:13 btzone/
      #  drwxr-xr-x root/root         0 2019-09-11 13:13 btzone/btraw-psdo-20190911-131338/
      #  -rw------- root/root    161711 2019-09-11 13:13 btzone/btraw-psdo-20190911-131338/sda1.torrent
      #  -rw-r--r-- root/root      2495 2019-09-11 13:13 clonezilla-img
      #  -rw-r--r-- root/root       144 2019-09-11 13:13 dev-fs.list
      #  -rw-r--r-- root/root         4 2019-09-11 13:13 disk
      #  -rw-r--r-- root/root     97840 2019-09-11 13:13 Info-dmi.txt
      #  -rw-r--r-- root/root       187 2019-09-11 13:13 Info-img-id.txt
      #  -rw-r--r-- root/root     53419 2019-09-11 13:13 Info-lshw.txt
      #  -rw-r--r-- root/root      4696 2019-09-11 13:13 Info-lspci.txt
      #  -rw-r--r-- root/root       212 2019-09-11 13:13 Info-packages.txt
      #  -rw-r--r-- root/root        65 2019-09-11 13:13 Info-saved-by-cmd.txt
      #  -rw-r--r-- root/root         5 2019-09-11 13:13 parts
      #  -rw-r--r-- root/root       512 2019-09-11 13:13 sda2-ebr
      #  -rw-r--r-- root/root        36 2019-09-11 13:13 sda-chs.sf
      #  -rw-r--r-- root/root   1048064 2019-09-11 13:13 sda-hidden-data-after-mbr
      #  -rw-r--r-- root/root       512 2019-09-11 13:13 sda-mbr
      #  -rw-r--r-- root/root       405 2019-09-11 13:13 sda-pt.parted
      #  -rw-r--r-- root/root       366 2019-09-11 13:13 sda-pt.parted.compact
      #  -rw-r--r-- root/root       250 2019-09-11 13:13 sda-pt.sf
      #  -rw-r--r-- root/root        53 2019-09-11 13:13 swappt-sda5.info
      tar -cJf /var/www/html/img-wo-fs.tar.xz *
    )
    if [ -d "$img_no_fs_tmp" -a \
         -n "$(echo $img_no_fs_tmp | grep -i "img_no_fs")" ]; then
      rm -rf "$img_no_fs_tmp" | tee -a ${OCS_LOGFILE}
    fi
    # Part 2: ocs-client-run.conf
    cat <<-CLIENT_END > /var/www/html/ocs-client-run.conf
pseudo_img="img-wo-fs.tar.xz"
img_prefix="$target_dir"
ocs_sr_opt="--ocsroot /tmp/ -l en_US.UTF-8 --batch $OCS_OPT ${castmode}_${cast_dev_action}"
ocs_restore_dev="$ocs_restore_dev"
CLIENT_END
    if [ -e "/var/www/html/img-wo-fs.tar.xz" -a -e "/var/www/html/ocs-client-run.conf" ]; then
      echo "Files /var/www/html/img-wo-fs.tar.xz and /var/www/html/ocs-client-run.conf created successfully:" | tee -a ${OCS_LOGFILE}
      ls -lv /var/www/html/img-wo-fs.tar.xz /var/www/html/ocs-client-run.conf | tee -a ${OCS_LOGFILE}
    else
      [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
      echo "Failed to create /var/www/html/img-wo-fs.tar.xz and /var/www/html/ocs-client-run.conf." | tee -a ${OCS_LOGFILE}
      [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
      echo "$msg_program_stop!" | tee -a ${OCS_LOGFILE}
      exit 1
    fi
    echo $msg_delimiter_star_line
  
    #
    case "$ocs_litesrv_netmode" in
      "use-existing-dhcpd"|"start-new-dhcpd") always_restore="no" ;;  # So that ocsmgrd will update PXE/Grub NB confi
      "no-dhcpd")                             always_restore="yes" ;; # So that ocsmgrd won't update PXE/Grub NB config
    esac
    start_ocsmgrd_daemon
    echo $msg_delimiter_star_line
  elif [ "$ls_client_mode"  = "interactive-client" ]; then
    # Interactive mode for clients.
    echo "Starting network booting mechanism for clients to enter Clonezilla live interactive mode..."
    # cast_srv_ip is required for generating uEFI netboot, a workaround for tftp to fix the dnsmasq issue for uEFI network boot clients. Check "drbl-gen-grub-efi-nb -t $cast_srv_ip" in function gen_ocs_live_netboot_conf
    get_cast_srv_ip
  else
    echo "Unknown mode for ls_client_mode: $ls_client_mode"
    echo "$msg_program_stop" | tee -a ${OCS_LOGFILE}
    exit 1
  fi
  
  # Prepare the config for clients
  if ! systemctl status lighttpd >/dev/null 2>&1; then
    pid1_prog="$(LC_ALL=C ps -p 1 -o comm=)"
    # In Singularity container, there is an issue to use systemctl
    # to start systemd service because its PID=1 is sinit, not systemd.
    case "$pid1_prog" in
      *systemd*) systemctl start lighttpd | tee -a ${OCS_LOGFILE};;
      *)         lighttpd -f /etc/lighttpd/lighttpd.conf | tee -a ${OCS_LOGFILE};;
    esac
  fi

  # Prepare netboot required files and services
  case "$ocs_litesrv_netmode" in
   "use-existing-dhcpd"|"start-new-dhcpd") 
    # Check the file permission mode of squashfs, we need that for later use
    squashfs_fmode="$(LC_ALL=C stat -c %a $LIVE_MEDIA/live/filesystem.squashfs | cut -c 3)"
    # Not matter if clients use netboot or not, we start the required services and prepare the PXE and uEFI network boot
    systemctl stop dnsmasq
    systemctl start dnsmasq
    start_nat_service
    gen_ocs_live_netboot_conf
    # Put filesystem.squashfs in http service root.
    if [ "$squashfs_fmode" -ge 4 ]; then
      ln -fsv $LIVE_MEDIA/live/filesystem.squashfs /var/www/html/Clonezilla-live-filesystem.squashfs
    else
      # To save space, since $pxecfg_pd/Clonezilla-live-filesystem.squashfs exists, we link from it instead of the source one.
      ln -fsv $pxecfg_pd/Clonezilla-live-filesystem.squashfs /var/www/html/Clonezilla-live-filesystem.squashfs
    fi
    # Change fetch protocol to http
    add_opt_in_pxelinux_cfg_block -n Clonezilla-live fetch "http://$cast_srv_ip/Clonezilla-live-filesystem.squashfs"
    add_opt_in_grub_efi_cfg_block -n "clonezilla-live-client" fetch "http://$cast_srv_ip/Clonezilla-live-filesystem.squashfs"
   ;;
  esac

  # Only in interactive mode we will show the command to run it again. For non-interactive mode, $OCS_OPT_PRE is not collected so the command is not complete.
  if [ "$ocs_sr_mode" = "interactive" ]; then
    run_again_fname="/tmp/ocs-live-feed-img-`date +%F-%H-%M`"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_SUCCESS
    echo PS. $msg_run_drbl_ocs_again_cmd | tee -a ${OCS_LOGFILE}
    echo $ocs $OCS_OPT_PRE $mode $ocs_img_name_or_src_dev $ocs_restore_dev | tee $run_again_fname
    [ -e "$run_again_fname" ] && chmod 755 $run_again_fname
    echo "$msg_ocs_sr_again_command_saved_filename: $run_again_fname"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  fi
  echo $msg_delimiter_star_line
  [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING

  case "$ocs_litesrv_netmode" in
   "use-existing-dhcpd"|"start-new-dhcpd") 
    echo "$msg_turn_on_client_to_clone" 
    echo "$msg_if_boot_from_locaL_media:"
    ;;
  esac
  echo "$msg_boot_client_with_same_version_clonezilla_live: $cast_srv_ip" | tee -a ${OCS_LOGFILE}
  echo "$msg_append_parameter_for_unattended_mode: locales=en_US.UTF-8 keyboard-layouts=us ocs_live_run=\"ocs-live-get-img $cast_srv_ip\"" | tee -a ${OCS_LOGFILE}
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL

  # We have to wait for udp-sender/ezio to finish so that when CJK locales uses jfbterm, udp-sender/ezio won't be terminated due to jfbterm is finished.
  echo $msg_delimiter_star_line
  choose_term="no"
  while [ "$choose_term" = "no" ]; do
    echo "$msg_now_wait_for_client_to_connect"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
    echo "$msg_do_all_clients_finish_jobs" "$msg_it_might_stop_required_restoring_service"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    echo -n "[y/N] "
    read input_key
    case "$input_key" in
     y|Y) 
          [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
	  echo "$msg_let_me_ask_you_again."
          echo "$msg_do_all_clients_finish_jobs" "$msg_it_might_stop_required_restoring_service"
          [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
          echo -n "[y/N] "
          read input_key2
          case "$input_key2" in
           y|Y) rc_final="0"
                choose_term="yes"
	  esac
          ;;
    esac
  done
  # The ocsmgrd outputs will be put in /var/log/clonezilla/ocsmgrd*.log. Therefore no need to force postaction=true. Here make it nothing so that user can choose the postaction later.
  postaction=""
  save_ocs_related_vars
  return $rc_final
} # end of task_start_feed_img_for_cast
#
task_stop_feed_img_for_cast() {
  # Assign the required variables so that stop_ocs_service can be correctly run.
  diskless_client_os="clonezilla-live"
  PXE_CONF="$PXELINUX_DIR/default"
  GRUB_CONF="$GRUB_EFINB_DIR/grub.cfg"
  if [ "$ocs_litesrv_netmode" != "no-dhcpd" ]; then
    # This stop is before staring the ocs-live-feed-img, hence we have ocs_litesrv_netmode.
    # When $ocs_litesrv_netmode is auto-detect, use-existing-dhcpd, or start-new-dhcpd,
    # it means the netboot service exists, we have to clean it.
    echo -n "Clean all the previous saved config file if they exist..."
    clean_stale_node_pxe_cfg
    clean_stale_node_grub_efi_cfg
  fi
  systemctl stop dnsmasq
  systemctl stop lighttpd stop
  stop_nat_service
  stop_ocs_service -m $ocs no
  return 0
} # task_stop_feed_img_for_cast

####################
### Main program ###
####################

ocs_file="$0"
ocs=`basename $ocs_file`
# ocs_myself_id PID is important variable so that it won't be killed by kill_ps_by_kill_9 in stop_ocs_service
ocs_myself_id="$$"
OCS_LOGFILE="/var/log/${ocs}.log"

parse_ocs_live_feed_img_cmd_options_with_dash $*
shift ${n_shift}
mode="$1"
shift
ocs_img_name_or_src_dev="$1"  # Later we will decide it's used as image name or source device (BT onthefly).
shift
ocs_restore_dev="$(strip_leading_dev $*)" # No matter the input is like /dev/sda or sda, format it as sda

#
[ -z "$mode" ] && mode="ask_user"
[ -z "$ocs_img_name_or_src_dev" ] && ocs_img_name_or_src_dev="ask_user"
[ -z "$ocs_restore_dev" ] && ocs_restore_dev="ask_user"

if [ "$ocs_img_name_or_src_dev" = "ask_user" -a \
     "$ocs_restore_dev" = "ask_user" ]; then
   ocs_sr_mode="interactive"
fi

force_TERM_as_linux_if_necessary

#
check_if_root
if [ "$check_ocs_live" = "yes" ]; then
  check_if_in_clonezilla_live  # get $LIVE_MEDIA
  # Check if we can find LIVE_MEDIA
  if [ -z "$LIVE_MEDIA" -o ! -d "$LIVE_MEDIA" ]; then
   [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
   echo "Failed to find root file system in $LIVE_MEDIA!"
   [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
   echo "Unable to let PXE client boot Clonezilla live."
   echo "$msg_program_stop!"
   exit 1
  fi
fi

ask_and_load_lang_set

# check DIA
check_DIA_set_ESC $DIA

#
if [ "$mode" = "ask_user" ]; then
  ask_start_or_stop_mode
fi

# Change to other mount point for extra harddisk
# Note: functions get_existing_disk_image, get_existing_parts_image and get_existing_partitions_from_img will use $imagedir 
if [ -n "$mount_point" ]; then
   echo "Using the image root directory $mount_point instead of $ocsroot." | tee -a ${OCS_LOGFILE}
   imagedir="$mount_point" 
else
   imagedir="$ocsroot"
fi

echo $msg_delimiter_star_line
if [ "$verbose" = "on" ]; then
  # The default output for udpcast stderr is surpressed, now turn it on
  udpcast_stderr="/dev/stderr"
fi

mkdir -p $ocs_log_dir
ocs_log_rotate $OCS_LOGFILE

rc=""
case "$mode" in 
  start) task_start_feed_img_for_cast
	 rc=$?
         if [ "$rc" -eq 0 ]; then
           # It's one-time service, if all finishes correctly, 
	   # the BT related services should be stopped
	   # so that poweroff/reboot can be executed smoothly.
           ocs-btsrv stop
         fi
	 ;;
   stop) task_stop_feed_img_for_cast
	 rc=$? ;;
      *) USAGE
	 rc=1 ;;
esac

echo "done!"
exit $rc
