#!/bin/bash
# Author: Steven Shiau <steven _at_ nchc org tw>
# License: GPL
# Description: This script will create a Debian live CD iso which is used as a template for clonezilla image with restoration function.

#
set -e

#
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

# debian_mirror_url_def, debian_mirror_security_url_def, DRBL_REPOSITORY_URL_def and DRBL_GPG_KEY_URL are loaded from drbl-ocs.conf

# debian_type can be minimal (about 67 MB for Etch)/minimal-net (about 85 MB for Etch).
# Since from live-build 3.0~a55 "minimal" for debootstrap was removed. We use the option --variant of "debootstrap", i.e. "minbase" for minimal.
debian_type="minbase"
#debian_type="standard"
DEBIAN_DIST_DEF="wheezy"
pkgs="$PKG_FROM_DBN_WHICH_OCS_LIVE_NEED drbl $PKG_FROM_DRBL_FOR_CLONEZILLA_LIVE"
categories_default="main"
cpu_flavor_default="586"
bootstrap_default="debootstrap"

# The files in dir $ocs_live_script_dir/ will be copied to the dir /live-hook-dir in dir chroot. The file "ocs-live-hook" is in $ocs_live_script_dir
# We put some files in dir ocs_minimal_hook/ to do some jobs, like clean unnecessary files, set locales...
ocs_live_script_dir="$DRBL_SCRIPT_PATH/setup/files/ocs/live-hook"
# The script inside $ocs_live_script_dir/ will be run when chroot. There are many files in $ocs_live_script_dir/, we will just run one here.
run_hook_script="ocs-live-hook"
# This hook is for binary_local-hooks, not for chroot hook
run_binary_hook_script="efi-binary-hook"
# The option to create a corresponding source image.
gen_source_tarball="no"

#
check_if_root
#
prog="$(basename $0)"

# functions
USAGE() {
    echo "Usage:"
    echo "To create a Debian live CD which is used a template for Clonezilla live:"
    echo "$prog [OPTION]"
    echo "OPTION:"
    echo "-a, --packages PKG     Specify to add PKG, e.g. firmware-bnx2"
    echo "-b, --branch [s|stable|t|testing|u|unstable|e|experimental]  Specify the DRBL branch to be used in Live CD. Default is stable."
    echo "-bt, --bootstrap BOOTSTRAP  Specify the bootsrap type as BOOTSTRAP (cdebootstrap or debootstrap). If not specified, $bootstrap_default will be used."
    echo "-c, --categories CAT   Sepcify the category, e.g. 'main', 'main non-free', default is \'$categories_default\' if not specified."
    echo "-d, --debian-dist [stable|testing|unstable|lenny|squeeze|wheezy|sid...]  Assign Debian dist, the default is $DEBIAN_DIST_DEF if not assigned."
    echo "-f, --arch-flavor ARCH  Assign the CPU architecture flavor as ARCH, e.g. 586, 686 or amd64. If it's not assigned, $cpu_flavor_default will be used."
    echo "-g, --drbl-repo-url URL  Assign the DRBL repository URL instead of default one $DRBL_REPOSITORY_URL_def."
    echo "-i, --assign-version-no NO  Assign the version no as NO instead of date."
    echo "-k, --live-kernel-pkg KERNEL_VER Assign kernel version as KERNEL_VER (KERNEL VER package must exist in repository. Ex. if KERNEL_VER is 2.6.20-1-486, then linux-image-2.6.20-1-486, squashfs-modules-2.6.20-1-486, and unionfs-modules-2.6.20-1-486 will be used."
    echo "-l, --drbl-live-branch [s|stable|t|testing|u|unstable|e|experimental]  specifies the DRBL live branch to be used in Live CD. Default is stable."
    echo "-p, --use-backports Include backports in the repository."
    echo "-m, --mirror-url URL  Assign the Debian repository URL instead of default one $debian_mirror_url_def. "
    echo "-s, --mirror-security-url URL  Assign the Debian security repository URL instead of default one $debian_mirror_security_url_def."
    echo "-o, --create-source-tarball  Create a corresponding source image to the binary image.  By default such an source image will not be created since this would require to download quite a few source packages."
    echo "-v, --verbose   Run live build in verbose mode"
    echo "Ex: $0 -l experimental -b unstable -k 2.6.24-etchnhalf.1"
}
#
build_it() {
  mkdir debian-live
  cd debian-live
  
  $pref lb config --archive-areas "$categories"
  # It's important to make the url for --parent-mirror-binary is different from that of --parent-mirror-chroot so that in /usr/lib/live/build/chroot_archives the "lb config --cache-packages false" and "lb config --apt-indices false" can work and those /var/cache/apt/{pkgcache.bin,srcpkgcache.bin} and those /var/lib/apt/lists/{*_Packages,*Release*,*_Sources} won't be cached.
  $pref lb config --parent-mirror-bootstrap $mirror_url --parent-mirror-binary $debian_mirror_url_def --parent-mirror-chroot $mirror_url --parent-mirror-chroot-security $mirror_security_url --parent-mirror-binary-security $debian_mirror_security_url_def --parent-mirror-debian-installer $debian_mirror_url_def
  # Since we use Debian Sid normally, disable updates.
  $pref lb config --updates false
  $pref lb config --mirror-debian-installer $mirror_url
  $pref lb config --mirror-binary $mirror_url --mirror-binary-security $mirror_security_url 
  $pref lb config --mirror-bootstrap $mirror_url
  $pref lb config --mirror-chroot $mirror_url --mirror-chroot-security $mirror_security_url
  if [ "$use_backports" = "yes" ]; then
    $pref lb config --backports true
  else
    $pref lb config --backports false
  fi
  
  # From live-build 3.0~a58-1, no --bootstrap-flavour option.
  #$pref lb config --bootstrap-flavour $debian_type 

  #export DEBOOTSTRAP_OPTIONS="$DEBOOTSTRAP_OPTIONS --variant=$debian_type"
  # Due to this issue: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=830696
  # We have to add gnupg in the base environment
  export DEBOOTSTRAP_OPTIONS="$DEBOOTSTRAP_OPTIONS --include=gnupg"
  $pref lb config --debootstrap-options="${DEBOOTSTRAP_OPTIONS} --variant=$debian_type"
  # Since we might assign the package version, e.g. live-boot=3.0.1-1.drbl4.
  # If we do not adding "--no-upgrade", then 
  # in /usr/lib/live/build/chroot_live-packages it will run
  # "apt-get install live-boot" then it will be upgraded.
  $pref lb config --apt apt --apt-options "--yes --no-upgrade --allow-downgrades" --apt-recommends false --bootstrap $bootstrap
  # From live-build 3.0~a59-1, no --volatile option.
  #$pref lb config --volatile false
  # Disable the firmware packages automatically inclusion
  $pref lb config --firmware-binary false --firmware-chroot false
  $pref lb config --security false
  $pref lb config --initramfs live-boot
  # Refer to /usr/share/live/build/functions/defaults.sh for the original boot append parameters.
  # Don't be confused. It won't be appended. Therefore we have to put all required ones.
  $pref lb config --bootappend-live "boot=live union=overlay config username=user"
  # Enable cache-indices, by doing this, "apt-get upgrade" won't be run in lb chroot_sources after hook since we might assign older package version when building.
  # This is important especially when there is newer live-boot in Sid. E.g. on 2014/Apr/1 live-boot 4.0 alpha is aviailable, but we still want to keep using 3.0.1-1.drbl4. If --cache-indices is set true, live-boot is upgraded, and 4.0 is installed on the system after filesystem.squashfs is created. Then the initrd.img is re-created again, with live-boot 4.x in initrd.img. It will be inconsistent with what we want.
  $pref lb config --cache-indices true
  $pref lb config --cache-packages false
  $pref lb config --apt-indices false
  $pref lb config --apt-source-archives true
  #$pref lb config --tasksel none
  
  if [ "$debian_dist" = "lenny" ]; then
    # Force to use iso instead of iso-hybrid. Since the syslinux in lenny comes without isohybrid program.
    $pref lb config --binary-images iso
  else
    # Enable iso-hybrid for version >= squeeze
    # //NOTE// This is for template iso only, not for Clonezilla live iso.
    $pref lb config --binary-images iso-hybrid
  fi
  
  # This decide_live_kernel_related_pkgs_from_debian function will output "kernel_related_pkgs" and "export MKSQUASHFS_OPTIONS"
  decide_live_kernel_related_pkgs_from_debian
  $pref lb config --distribution $debian_dist --parent-distribution $debian_dist
  $pref lb config --linux-packages "$kernel_related_pkgs"
  
  # We force to use the specific CPU kernel.
  $pref lb config --linux-flavours $cpu_flavor
  
  # For OS arch, we can build amd64 Debian on i386 Debian or vice versus.
  case "$cpu_flavor" in
    686*|586*|486*) os_arch="i386";;
    amd64) os_arch="amd64";;
  esac
  $pref lb config --architectures $os_arch
  $pref lb config --initsystem systemd
  
  # No memtest from debian, we will use the one from drbl since it's newer.
  $pref lb config --memtest none
  
  $pref lb config --debian-installer false
  $pref lb config --win32-loader false
  
  # Disable zsync, it might fail due to download files after /etc/resolv.conf is deconfigured.
  $pref lb config --zsync false
  
  # Create a source tarball or not.
  if [ "$gen_source_tarball" = "yes" ]; then
    $pref lb config --source true
    $pref lb config --source-images tar
    # Since most of the debian packages are compressed (xz or gzip), we just use none, not the default one gzip.
    $pref lb config --compression none
  else
    $pref lb config --source false
  fi
  
  # Put files to be included in the chroot hook
  mkdir -p config/includes.chroot/live-hook-dir
  for i in $ocs_live_script_dir; do
    cp -pr $i/* config/includes.chroot/live-hook-dir/
  done
  cp -a /etc/drbl/{drbl.conf,drbl-ocs.conf} config/includes.chroot/live-hook-dir
  
  # Put the mirror url and settings, which we might need.
  cat <<-HOOK_APPEND_END >> config/includes.chroot/live-hook-dir/ocs-live-hook.conf
# The following settings were added before running hook" >> config/includes.chroot/live-hook-dir/ocs-live-hook.conf
debian_dist="$debian_dist"
mirror_url="$mirror_url"
HOOK_APPEND_END
  
  # Put packages list in config/package-lists/. //NOTE// Do not use file name like clonezilla-packages.list. Make it like clonezilla-packages.list.binary (for lb_binary) or clonezilla-packages.list.chroot (for lb_chroot). Otherwise lb_binary_package-lists will generate deb repository (/pool). 
  # Ref: http://lists.debian.org/debian-live/2012/07/msg00119.html
  echo "$pkgs" > config/package-lists/clonezilla-packages.list.chroot
  
  # Put hook file to be run in chroot
  cp $ocs_live_script_dir/${run_hook_script} config/hooks/${run_hook_script}.chroot
  
  # Put hook file to be run in the binary local hook
  cp $ocs_live_script_dir/$run_binary_hook_script config/hooks/${run_binary_hook_script}.binary
  
  # prepare drbl source list
  # //NOTE// Use drbl-repository.list instead of drbl-repository.list.chroot because 
  # with ".chroot" it means only for chroot and it will be removed from the squashfs.
  cat << AddDRBLRepository > config/archives/drbl-repository.list
deb $DRBL_REPOSITORY_URL drbl $LIVE_REPOSITORY_SECTIONS_drbl
deb-src $DRBL_REPOSITORY_URL drbl $LIVE_REPOSITORY_SECTIONS_drbl
AddDRBLRepository
  
  # prepare drbl key
  LC_ALL=C wget -O config/archives/drbl-gpg.key $DRBL_GPG_KEY_URL
  
  # Disable apt languages and translations when creating DRBL live. This could reduce apt repository issue.
  disable_apt_lang_translation chroot/etc/apt/apt.conf.d/99lang
  
  # Build it.
  $pref lb build
} # End of build_it

# Parse command-line options
while [ $# -gt 0 ]; do
  case "$1" in
    -a|--packages)
            shift
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
              extra_pkgs="$1"
              shift
            fi
	    [ -z "$extra_pkgs" ] && USAGE && exit 1
            ;;
    -b|--branch)
            shift
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
              drbl_branch="$1"
              shift
            fi
	    [ -z "$drbl_branch" ] && USAGE && exit 1
            ;;
    -bt|--bootstrap)
            shift
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
              bootstrap="$1"
              shift
            fi
	    [ -z "$bootstrap" ] && USAGE && exit 1
            ;;
    -c|--categories)
            shift
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
              categories="$1"
              shift
            fi
	    [ -z "$categories" ] && USAGE && exit 1
            ;;
    -d|--debian-dist)
            shift
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
              debian_dist="$1"
              shift
            fi
	    [ -z "$debian_dist" ] && USAGE && exit 1
            ;;
    -i|--assign-version-no)
            shift
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
              version_no="$1"
              shift
            fi
	    [ -z "$version_no" ] && USAGE && exit 1
            ;;
    -k|--live-kernel)
            shift
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
              live_kernel_ver="$1"
              shift
            fi
	    [ -z "$live_kernel_ver" ] && USAGE && exit 1
            ;;
    -l|--drbl-live-branch)
            shift
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
              drbl_live_branch="$1"
              shift
            fi
	    [ -z "$drbl_live_branch" ] && USAGE && exit 1
            ;;
    -p|--use-backports)
	    use_backports="yes"
            shift ;;
    -f|--arch-flavor)
            shift
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
              cpu_flavor="$1"
              shift
            fi
	    [ -z "$cpu_flavor" ] && USAGE && exit 1
            ;;
    -g|--drbl-repo-url)
            shift
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
              DRBL_REPOSITORY_URL="$1"
              shift
            fi
	    [ -z "$DRBL_REPOSITORY_URL" ] && USAGE && exit 1
            ;;
    -m|--mirror-url)
            shift
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
              mirror_url="$1"
              shift
            fi
	    [ -z "$mirror_url" ] && USAGE && exit 1
            ;;
    -o|--create-source-tarball)
	    gen_source_tarball="yes"
            shift ;;
    -s|--mirror-security-url)
            shift
            if [ -z "$(echo $1 |grep ^-.)" ]; then
              # skip the -xx option, in case 
              mirror_security_url="$1"
              shift
            fi
	    [ -z "$mirror_security_url" ] && USAGE && exit 1
            ;;
    -v|--verbose)
	    verbose="on"
            shift ;;
    -*)     echo "${0}: ${1}: invalid option" >&2
            USAGE >& 2
            exit 2 ;;
    *)      break ;;
  esac
done

if ! type lb &>/dev/null; then
  [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
  echo "This script only works in Debian Etch or later!"
  echo "If you are running Debian Etch or later, use 'apt-get install live-build' to install the live-build (version $lh_ver_required or later), then run $0 again."
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  exit 1
fi

create_live_required_debian_based_prompt

rm -rf debian-live/.stage/

# Apply default settings if not assigned
[ -z "$debian_dist" ] && debian_dist="$DEBIAN_DIST_DEF"
[ -z "$categories" ] && categories="$categories_default"
[ -z "$DRBL_REPOSITORY_URL" ] && DRBL_REPOSITORY_URL="$DRBL_REPOSITORY_URL_def"
[ -z "$mirror_url" ] && mirror_url="$debian_mirror_url_def"
[ -z "$mirror_security_url" ] && mirror_security_url="$debian_mirror_security_url_def"
[ -z "$cpu_flavor" ] && cpu_flavor="$cpu_flavor_default"
[ -z "$bootstrap" ] && bootstrap=$bootstrap_default

# Append the extra packages
[ -n "$extra_pkgs" ] && pkgs="$pkgs $extra_pkgs"

# If version_no is not assigned, use date (Ex. 20070409)
[ -z "$version_no" ] && version_no="$(date +%Y%m%d)"
target_iso="debian-live-for-ocs-${version_no}.iso"
target_src_tarball="clonezilla-live-src-${version_no}.debian.tar"
target_src_tarball_list="clonezilla-live-src-${version_no}.debian.contents"
target_src_debian_live_tarball="clonezilla-live-src-${version_no}.debian-live.tar"
target_src_debian_live_tarball_list="clonezilla-live-src-${version_no}.debian-live.contents"

[ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
echo "Creating a Debian live cd iso which is used for clonezilla image with restoration function. The created iso will be in $target_iso" 
[ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
#
echo "Using Debian repository from: $mirror_url"
echo "Using Debian security repository from: $mirror_security_url"
echo "Using DRBL repository from: $DRBL_REPOSITORY_URL"

#
case "$drbl_branch" in
  t|testing)
     echo "Using DRBL testing branch..."
     LIVE_REPOSITORY_SECTIONS_drbl="testing"
     ;;
  u|unstable)
     echo "Using DRBL unstable branch..."
     LIVE_REPOSITORY_SECTIONS_drbl="unstable"
     ;;
  e|experimental)
     echo "Using DRBL experimental branch..."
     LIVE_REPOSITORY_SECTIONS_drbl="experimental"
     ;;
  *)
     echo "Using DRBL stable branch..."
     LIVE_REPOSITORY_SECTIONS_drbl="stable"
     ;;
esac
case "$drbl_live_branch" in
  t|testing)
     echo "Using DRBL Live testing branch..."
     LIVE_REPOSITORY_SECTIONS_drbl="$LIVE_REPOSITORY_SECTIONS_drbl live-testing"
     ;;
  u|unstable)
     echo "Using DRBL Live unstable branch..."
     LIVE_REPOSITORY_SECTIONS_drbl="$LIVE_REPOSITORY_SECTIONS_drbl live-unstable"
     ;;
  e|experimental)
     echo "Using DRBL Live experimental branch..."
     LIVE_REPOSITORY_SECTIONS_drbl="$LIVE_REPOSITORY_SECTIONS_drbl live-experimental"
     ;;
  *)
     echo "Using DRBL live stable branch..."
     LIVE_REPOSITORY_SECTIONS_drbl="$LIVE_REPOSITORY_SECTIONS_drbl live-stable"
     ;;
esac

#
if [ "$debian_dist" = "squeeze" -o \
     "$debian_dist" = "wheezy" -o \
     "$debian_dist" = "sid" ]; then
  # From around Oct/2009, the dummy package name "grub" is actually grub-pc, therefore we force to use grub-legacy and assume that if grub2 boot loader is used in the restored GNU/Linux, grub2 is available in the restored GNU/Linux so therefore we can use chroot to run it.
  # 2011/Dec/03 Since most of GNU/Linux distributions now use grub2, no more force to use grub-legacy, and we have backup plan by putting grub1 deb package in the live system. 
  # pkgs="$(LC_ALL=C echo $pkgs | sed -r -e "s/grub[[:space:]]+/grub-legacy /")"
  # Since with squeeze or sid, we can use uvesafb to replace vesafb, we need v86d. Check https://bugs.launchpad.net/ubuntu/+source/v86d/+bug/189621 for more details.
  pkgs="$pkgs v86d"
fi
# Adding libc6-i386 for AMD64 arch. This will allow 32-bit program to run on AMD64 arch.
if [ "$cpu_flavor" = "amd64" ]; then
  pkgs="$pkgs libc6-i386"
fi

if [ "$verbose" = "on" ]; then
  pref="bash -x"
  export CDEBOOTSTRAP_OPTIONS="$CDEBOOTSTRAP_OPTIONS -v --debug"
fi

if [ -d "debian-live" ]; then
  echo "Found dir debian-live, clean stale debian-live files..."
  chroot debian-live/chroot umount /dev/pts &>/dev/null || true
  chroot debian-live/chroot umount /proc &>/dev/null || true
  chroot debian-live/chroot umount /sys &>/dev/null || true
  (
    cd debian-live/
    lb clean
  )
  rm -rf debian-live
fi

# Use sub shell to keep the working dir
(build_it)

lb_ver="$(LC_ALL=C lb --version)"  # e.g. 3.0.5-1
if [ "$lb_ver" \> 3 ] && [ "$lb_ver" \< 4 ]; then
  # Live build version 3 
  mv -f debian-live/binary*.iso $target_iso
  if [ "$gen_source_tarball" = "yes" ]; then
    mv -f debian-live/source.debian.tar $target_src_tarball
    mv -f debian-live/source.debian.contents $target_src_tarball_list
    mv -f debian-live/source.debian-live.tar $target_src_debian_live_tarball
    mv -f debian-live/source.debian-live.contents $target_src_debian_live_tarball_list
  fi
else
  # Live build version 4
  mv -f debian-live/live-image*.iso $target_iso
  if [ "$gen_source_tarball" = "yes" ]; then
    mv -f debian-live/live-image-source.debian.contents $target_src_tarball_list
    mv -f debian-live/live-image-source.debian.tar $target_src_tarball
    mv -f debian-live/live-image-source.live.contents $target_src_debian_live_tarball_list
    mv -f debian-live/live-image-source.live.tar $target_src_debian_live_tarball
  fi
fi
