#!/bin/bash
# License: GPL 
# Author: Steven Shiau <steven _at_ clonezilla org>
# Description: Program to feed multicast 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.

#
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"

# Functions
USAGE() {
    echo "$ocs - To start feeding image for multicast mode in Clonezilla"
    echo "Usage:"
    echo "To run $ocs:"
    echo "$ocs [OPTION] MODE [IMAGE_NAME] [DEVICE]"
    echo "This program is specially used in Clonezilla live to start feeding multicast packets for clients."
    echo "Options:"
    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  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 " -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
    echo "MODE is \"start\" or \"stop\""
    echo "IMAGE_NAME is the image dir name, not absolute path"
    echo "DEVICE is the device name, e.g. sda, sda1, sda2..."
    echo "If \"ask_user\" is used as IMAGE_NAME or DEVICE, a dialog menu will be shown to allow selection."
    echo "If no IMAGE_NAME is specified, a dialog menu will be shown."
    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
#
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));;
      -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 M$ 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 M$ 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)
  	    shift; n_shift=$((n_shift+1))
              if [ -z "$(echo $1 |grep ^-.)" ]; then
                # skip the -xx option, in case 
  	      eth_for_multicast="$1"
  	      shift; n_shift=$((n_shift+1))
              fi
              [ -z "$eth_for_multicast" ] && 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
  	    OCS_OPT="$OCS_OPT -um"
  	    ;;
      -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));;
      -*)   echo "${0}: ${1}: invalid option" >&2
            USAGE >& 2
            exit 2 ;;
       *)   break ;;
   esac
  done
} # end of parse_ocs_live_feed_img_cmd_options_with_dash
#
task_start_feed_img_for_mcast() {
  local MCAST_TMP ans_ mcast_dev_action
  local start_cmd
  local OCS_OPT_PRE
  local interactive_mode="no"
  local rc_chkimg

  [ -z "$ocs_restore_img_name" ] && ocs_restore_img_name="ask_user"
  [ -z "$ocs_restore_dev" ] && ocs_restore_dev="ask_user"

  # Even if it's local repository, we still have to configure network
  # otherwise the udp-sender won't start.
  network_config_if_necessary

  if [ "$ocs_restore_img_name" = "ask_user" -a \
       "$ocs_restore_dev" = "ask_user" ]; then
     interactive_mode="yes"
  fi

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

  if [ -n "$(pidof udp-sender)" ]; then
    task_stop_feed_img_for_mcast
  fi

  # When $ocsroot is not a mount point, and nothing lists under it, run prep-ocsroot
  if [ "$interactive_mode" = "yes" ]; then
    if ! mountpoint $ocsroot &>/dev/null; then
      if [ -z "$(ls -d $ocsroot/*/ 2>/dev/null)" ]; then
        prep-ocsroot
      fi
    fi
  fi

  # eth_for_multicast will be passed to function start_ocs_service
  # When Clonezilla live runs as multicast feeding server, the uplink port is where the packets sending.
  eth_for_multicast="$(LC_ALL=C get-all-nic-ip -u)" 

  if [ "$interactive_mode" = "yes" ]; then
    [ -z "$ocs_user_mode" ] && ask_if_beginner_or_expert_mode
  fi

  # Ask image name first (disk or parts image)
  # 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
    mcast_dev_action=$(cat $TMP)
    [ -f "$TMP" ] && rm -f $TMP
    case "$mcast_dev_action" in
    "restoredisk")
      get_target_dir_name_when_restoring_disk # get $target_dir
      dev_type="disk"
      ;;
    "restoreparts")
      get_target_dir_name_when_restoring_parts # get $target_dir
      dev_type="parts"
      ;;
    esac
    ocs_restore_img_name="$target_dir"  # Keep it for later use in run_again prompt
  else
    target_dir="$ocs_restore_img_name"
  fi
  check_input_target_image "$ocsroot/$target_dir"

  # Get target device
  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
        ;;
    esac
  else
    if [ -n "$dev_type" ]; then
      # In interactive mode, we know $dev_type is.
      case "$dev_type" in
        "disk") target_hd="$ocs_restore_dev";;
        "parts") target_parts="$ocs_restore_dev";;
      esac
    else
      # 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
      # mcast_dev_action is required for function start_ocs_service
      # while target_hd or target_parts is required for function 
      # multicast_restoredisk and multicast_restoreparts (hence for start_ocs_service)
      first_ele="$(echo $ocs_restore_dev | awk -F" " '{print $1}')"
      if is_whole_disk $first_ele; then
        mcast_dev_action="restoredisk"
        target_hd="$ocs_restore_dev"
      else
        mcast_dev_action="restoreparts"
        target_parts="$ocs_restore_dev"
      fi
    fi
  fi

  if [ "$interactive_mode" = "yes" ]; 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 $OCS_PARAM_TMP $dev_type
    # OCS_OPT_PRE is for ocs-live-feed-img, we have to convert to that for ocs-sr
    OCS_OPT_PRE="$(cat $OCS_PARAM_TMP)"
    OCS_OPT_PRE="$(echo $OCS_OPT_PRE)"  # Make it in one line
    parse_ocs_live_feed_img_cmd_options_with_dash $OCS_OPT_PRE  # Obtain $OCS_OPT for ocs-sr
    [ -f "$OCS_PARAM_TMP" ] && rm -f $OCS_PARAM_TMP
  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

  # Force to make client won't check the image integrity since this is for multicast restoring.
  OCS_OPT="$OCS_OPT -scr"
  task="multicast_restore"
  OCS_OPT="$OCS_OPT --mcast-port $MULTICAST_PORT"
  if [ "$interactive_mode" = "yes" ]; then
    if [ -z "$n_clients" ]; 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
    mcast_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

  # 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

  # For multicast_restoredisk, the input device variable is $target_hd
  # For multicast_restoreparts, the input device variable is $target_parts
  start_cmd="start_ocs_service $mcast_client_no_opt -f -t \"multicast_$mcast_dev_action\" -o \"$target_dir $ocs_restore_dev\""
  echo "Running: $start_cmd"
  eval $start_cmd
  while [ -z "$(LC_ALL=C ps -www --no-headers -C "udp-sender" -o pid,cmd)" ]; do
    sleep 0.2
  done
  echo "Feeding status:"
  echo $msg_delimiter_star_line
  ps -www -C "cat" -C "udp-sender" -o pid,cmd
  echo $msg_delimiter_star_line
  echo "More udp-sender and cat comamnds (if available) will be spawned when the 1st one is done."
  # Prepare the commands for clients
  if ! systemctl status lighttpd >/dev/null 2>&1; then
    systemctl start lighttpd
  fi

  echo $msg_delimiter_star_line
  # Two parts: img-wo-fs.tar.xz and ocs-client-run.sh
  # Part 1: img-wo-fs.tar.xz
  rm -f /var/www/html/ocs-client-run.sh /var/www/html/img-wo-fs.tar.xz
  echo "Preparing files for clients to download in /var/www/html/: ocs-client-run.sh, img-wo-fs.tar.xz"
  echo "Packing the tarball containing no file system images: img-wo-fs.tar.xz..."
  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
  # 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
    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"
  fi
  # Part 2: ocs-client-run.sh
  mcast_srv_ip="$(LC_ALL=C drbl-get-ipadd $eth_for_multicast)"
  cat <<-CLIENT_END > /var/www/html/ocs-client-run.sh
#!/bin/bash
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
[ -e "/etc/ocs/ocs-live.conf" ] && . /etc/ocs/ocs-live.conf

ask_and_load_lang_set
echo "Preparing the image info..."
rm -f /tmp/img-wo-fs.tar.xz
wget -P /tmp/ http://$mcast_srv_ip/img-wo-fs.tar.xz
if [ ! -e /tmp/img-wo-fs.tar.xz ]; then
  [ "\$BOOTUP" = "color" ] && \$SETCOLOR_FAILURE
  echo "Failed to retreive img-wo-fs.tar.xz from http://$mcast_srv_ip/."
  [ "\$BOOTUP" = "color" ] && \$SETCOLOR_NORMAL
  echo "Program terminated!"
  exit 1
fi
image="\$(mktemp -d /tmp/ocs-img.XXXXXX)"
tar -xJf /tmp/img-wo-fs.tar.xz -C \$image
if [ -n "\$(ls -A \$image 2>/dev/null)" ]; then
  echo "Starting restoring..."
  ocs-sr --ocsroot /tmp/ -l en_US.UTF-8 $OCS_OPT --max-time-to-wait $mcast_max_wait_time multicast_$mcast_dev_action "\$(basename \$image)" $ocs_restore_dev
else
  [ "\$BOOTUP" = "color" ] && \$SETCOLOR_FAILURE
  echo "Failed to find the correct pseudo image dir \$image"
  [ "\$BOOTUP" = "color" ] && \$SETCOLOR_NORMAL
  echo "Program terminated!"
  exit 1
fi
CLIENT_END
  if [ -e "/var/www/html/img-wo-fs.tar.xz" -a -e "/var/www/html/ocs-client-run.sh" ]; then
    echo "Files /var/www/html/img-wo-fs.tar.xz and /var/www/html/ocs-client-run.sh created successfully:"
    ls -lv /var/www/html/img-wo-fs.tar.xz /var/www/html/ocs-client-run.sh
  else
    [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
    echo "Failed to create /var/www/html/img-wo-fs.tar.xz and /var/www/html/ocs-client-run.sh."
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    echo "$msg_program_stop!" | tee --append ${OCS_LOGFILE}
    exit 1
  fi
  echo $msg_delimiter_star_line

  # 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 [ "$interactive_mode" = "yes" ]; 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 --append ${OCS_LOGFILE}
    echo $ocs $OCS_OPT_PRE $mode $ocs_restore_img_name $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
  echo "$msg_boot_client_with_same_version_clonezilla_live: $mcast_srv_ip"
  echo "$msg_append_parameter_for_unattended_mode: locales=en_US.UTF-8 keyboard-layouts=us ocs_live_run=\"ocs-live-get-img $mcast_srv_ip\""
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL

} # end of task_start_feed_img_for_mcast

task_stop_feed_img_for_mcast() {
  # 1. Kill process
  kill_ps_by_killall_9 udp-sender
  # 2. Remove the file for clients.
} # task_stop_feed_img_for_mcast


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

ocs_file="$0"
ocs=`basename $ocs_file`

parse_ocs_live_feed_img_cmd_options_with_dash $*
shift ${n_shift}
mode="$1"
shift
ocs_restore_img_name="$1"
shift
ocs_restore_dev="$*"

# 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"

#
check_if_root
ask_and_load_lang_set

# check DIA
check_DIA_set_ESC $DIA

# 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."
   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

case "$mode" in 
  start) task_start_feed_img_for_mcast;;
   stop) task_stop_feed_img_for_mcast;;
      *) USAGE;;
esac
