# This bash script is sourced by the various tools to set the
# adt_... variables and some other useful ones.

set -e${ADT_SHELLX}
set -o pipefail

#---------- useful general functions ----------

fail () {
	echo >&2 "xenlvm: ${0##*/}: error: $*"
	exit 16
}

x () { echo "x $*"; "$@"; }
xl () { echo "x $*"; 3>&- 4>&- "$@"; }

case "$BASH_VERSION" in
'')	fail 'scripts using adtxenlvm readconfig must be bash scripts' ;;
*)	;;
esac

#---------- default values for simple settings ----------

: ${adt_nominum:=adt}
: ${adt_testbed_ram:=256}
: ${adt_freeze_ram:=32}
: ${adt_fs_size:=6144M}
: ${adt_fs_snapsize:=5120M}
: ${adt_fs_cowchunk:=8}
: ${adt_swap_size:=5120M}
: ${adt_playbase:=/var/lib/autopkgtest/xenlvm}
: ${adt_fs_type:=ext3}
: ${adt_fs_mkfs_args:=}
: ${adt_vm_reduce_retries:=10}
: ${adt_ssh_keytype:=dsa}

: ${adt_debootstrap_opts:=}
: ${adt_debootstrap_components:='*'}
: ${adt_debootstrap_include:=openssh-server,ed}
: ${adt_debootstrap_includemore:=}
: ${adt_debootstrap_mirrors:=}
: ${adt_debootstrap_script:=}

: ${adt_fw_localmirrors:=}
: ${adt_fw_prohibnets:=192.168.0.0/24 172.16.0.0/12 10.0.0.0/8}
: ${adt_fw_allowglobalports:=80}

: ${adt_guest_macaddr:=00:16:3e:7c:aa:7f}
: ${adt_net_vifscript:=/etc/xen/scripts/vif-route-adt}
: ${adt_normaluser:=adtxenu}

#---------- arguments and config file ----------

cmdline_args () {
	while [ $# -gt 0 ]; do
		arg="$1"
		case "$arg" in
		--*=*)
			value="${arg#*=}"

			var=${arg%%=*}
			var=${var#--}
			case "$var" in
			*-*)	var="$(printf "%s" "$var" | tr -- - _)" ;;
			esac
			var=${var#adt_}

			case $var in
			guests_domain) ;; # @@varlist@@
			guest_hostname) ;; # @@varlist@@
			guest_ipaddr) ;; # @@varlist@@
			fw_localmirrors) ;; # @@varlist@@
			fw_testbedclients) ;; # @@varlist@@
			fw_prohibnets) ;; # @@varlist@@
			fw_allowglobalports) ;; # @@varlist@@
			fw_hook) ;; # @@varlist@@
			sshauthkeys_hook) ;; # @@varlist@@
			kernel) ;; # @@varlist@@
			ramdisk) ;; # @@varlist@@
			modules) ;; # @@varlist@@
			lvm_vg) ;; # @@varlist@@
			distro) ;; # @@varlist@@
			lvm_erasebase) ;; # @@varlist@@
			debootstrap_opts) ;; # @@varlist@@
			debootstrap_includemore) ;; # @@varlist@@
			debootstrap_include) ;; # @@varlist@@
			debootstrap_components) ;; # @@varlist@@
			debootstrap_mirrors) ;; # @@varlist@@
			debootstrap_script) ;; # @@varlist@@
			setup_hook) ;; # @@varlist@@
			fs_type) ;; # @@varlist@@
			fs_mkfs_args) ;; # @@varlist@@
			testbed_ram) ;; # @@varlist@@
			freeze_ram) ;; # @@varlist@@
			fs_size) ;; # @@varlist@@
			fs_snapsize) ;; # @@varlist@@
			fs_cowchunk) ;; # @@varlist@@
			swap_size) ;; # @@varlist@@
			swap_cowchunk) ;; # @@varlist@@
			vm_reduce_retries) ;; # @@varlist@@
			config) ;; # @@varlist@@
			ssh_keytype) ;; # @@varlist@@
			ssh_privkey) ;; # @@varlist@@
			ssh_pubkey) ;; # @@varlist@@
			ssh_keyident_args) ;; # @@varlist@@
			ssh_keygen_args) ;; # @@varlist@@
			nominum) ;; # @@varlist@@
			lvm_swapvg) ;; # @@varlist@@
			lvm_eraseswap) ;; # @@varlist@@
			lvm_pv_fsbase) ;; # @@varlist@@
			lvm_pv_fssnap) ;; # @@varlist@@
			lvm_pv_swapbase) ;; # @@varlist@@
			lvm_pv_swapsnap) ;; # @@varlist@@
			guest_macaddr) ;; # @@varlist@@
			net_vifscript) ;; # @@varlist@@
			normaluser) ;; # @@varlist@@
			host_hostname) ;; # @@varlist@@
			host_ipaddr) ;; # @@varlist@@
			playbase) ;; # @@varlist@@
			play) ;; # @@varlist@@
			lock) ;; # @@varlist@@
			xmconfig) ;; # @@varlist@@
			lvm_baselv) ;; # @@varlist@@
			lvm_cowdatalv) ;; # @@varlist@@
			lvm_snapbaselv) ;; # @@varlist@@
			lvm_snapcowdatalv) ;; # @@varlist@@
			devmapper_cowdev) ;; # @@varlist@@
			devmapper_swapcowdev) ;; # @@varlist@@
			fslink_dir) ;; # @@varlist@@
			swaplink_dir) ;; # @@varlist@@
			fslink_name) ;; # @@varlist@@
			swaplink_name) ;; # @@varlist@@
			xmname) ;; # @@varlist@@
			xmhook_disk) ;; # @@varlist@@
			xmhook_vif) ;; # @@varlist@@
			xmhook_extra) ;; # @@varlist@@
			xmhook_config) ;; # @@varlist@@
			*) fail "unknown configuration variable \`$var'" ;;
			esac

			eval "adt_$var=\"\$value\"; export adt_$var"
			shift ;;

		--)	shift; break ;;
		-*)	fail "unknown option \`$arg'" ;;
		*)	break ;;
		esac
	done
	nonoptargs=$#
}

cmdline_args "$@"
: "${adt_config:=/etc/autopkgtest/xenlvm_${adt_nominum}_config}"
test ! -e "${adt_config}" || . "${adt_config}"
cmdline_args "$@"

#---------- settings needed for locking ----------

if [ ! "${adt_readconfig_initscript}" ]; then
 case "$adt_distro" in
 '')
	printf "considering which distro to use ... "
	test -e /etc/lsb-release || \
		fail 'no /etc/lsb-version, config must specify adt_distro'
	. /etc/lsb-release
	adt_distro=$DISTRIB_CODENAME
	echo "using same distro as host: $adt_distro"
	;;
 esac
fi

# In-host-file-system playground
: ${adt_play:=${adt_playbase}/${adt_nominum}_${adt_distro}}
: ${adt_xmconfig:=${adt_play}/xmconfig}
: ${adt_lock:=${adt_play}.lock}

if [ "${adt_readconfig_needlock}" ] &&
   [ "x${adt_lock}" != xnone ] && \
   [ "x${ADT_LOCKED}" != "x$adt_lock" ]; then
 if [ "${adt_whenlock_replumb81}" ]; then
   exec >&8 8>&-
 fi
 ADT_LOCKED="$adt_lock" exec with-lock-ex -w "$adt_lock" "$0" "$@"
fi

#---------- calculated defaults for complex settings ----------

if [ ! "${adt_readconfig_initscript}" ]; then
 case "$adt_lvm_vg" in
 '')
	printf "searching for default volume group ... "
	vgdisplay_out=`vgdisplay -c 3>&- 8>&-`
	case "$vgdisplay_out" in
	"")	fail 'no volume groups found';;
	*"
 "*)		fail 'several volume groups, config must specify which';;
	esac
	adt_lvm_vg=${vgdisplay_out%%:*}
	case "$adt_lvm_vg" in
	*[^\ ]\ *) fail "volume group name \`$adt_lvm_vg' has spaces!";;
	esac
	adt_lvm_vg=${adt_lvm_vg##* }
	echo "using system's only volume group: $adt_lvm_vg"
	;;
 esac
fi

if [ "$adt_readconfig_needkernel" ]; then
 case "$adt_kernel" in
 '')
	printf "searching for kernel ... "
	for f in /boot/*"`uname -r`"*; do
		test -e "$f" || continue
		printf "(%s:" "$f"
		output="$(file -- "$f")"
		case "$output" in
		*"gzip compressed data"*) ;;
		*) printf "!gzip) "; continue ;;
		esac
		trap 'rm -f -- "$tf"; exit 127' 0
		tf=`mktemp -t`
		zcat -- "$f" >"$tf"
		output="$(file -- "$tf")"
		case "$output" in
		*"ELF "*" executable,"*) ;;
		*) printf "!ELF) "; continue;;
		esac
		output="$(objdump -j __xen_guest -s -- "$tf")"
		rm -f "$tf"; trap '' 0
		case "$output" in
		*" __xen_guest:"*) ;;
		*) printf "!Xen) "; continue
		esac
		printf "y) "
		test "x$adt_kernel" = x || \
			fail 'several kernels, config must specify which'
		adt_kernel="$f"
	done
	[ "x$adt_kernel" != x ] || \
		fail 'could not find currently booted Xen kernel'
	echo "using currently booted kernel: $adt_kernel"
	;;
 esac

 case "$adt_ramdisk" in
 none)	echo "ramdisk \`none' specified, using static kernel"
	adt_ramdisk='' ;;
 '')	adt_ramdisk="${adt_kernel/\/vmlinuz-//initrd.img-}"
	test -e "$adt_ramdisk" || \
 fail "calculated default ramdisk initrd.img \`$adt_ramdisk' does not exist"
	echo "using calculated default ramdisk initrd.img: $adt_ramdisk" ;;
 *)	;;
 esac
fi

case "$adt_modules" in
'')	adt_modules="/lib/modules/`uname -r`" ;;
*)	;;
esac

hostname_from_ipaddr () {
 eval '
  if [ x"$adt_'$1'_hostname" = x ] && \
     [ x"$adt_'$1'_ipaddr" != x ]; then
   printf "%s" "finding '$1' hostname from IP address $adt_'$1'_ipaddr: "
   adt_'$1'_hostname=`adnshost -t ptr +Do +Dt +Dc -i $adt_'$1'_ipaddr`
   printf "%s\n" "${adt_'$1'_hostname}"
  fi
 '
}

hostname_from_ipaddr host

if [ ! "${adt_readconfig_initscript}" ]; then
 hostname_from_ipaddr guest
fi

if [ x"$adt_host_hostname" = x ]; then
	printf "finding host hostname, supposely our own FQDN: "
	adt_host_hostname=`hostname -f`
	printf "%s\n" "$adt_host_hostname"
fi

if [ ! "${adt_readconfig_initscript}" ]; then
 if [ x"$adt_guest_hostname" = x ]; then
	case "$adt_guests_domain" in
	'')	printf "guessing guest hostname from host hostname: "
 adt_guest_hostname=$adt_distro.$adt_nominum.${adt_host_hostname#*.} ;;
	.*)	printf "setting guest hostname using distro and nominum: "
 adt_guest_hostname=$adt_distro.$adt_nominum$adt_guests_domain ;;
	*)	printf "setting guest hostname using distro and domain: "
 adt_guest_hostname=$adt_distro.$adt_guests_domain ;;
	esac
	printf "%s\n" "$adt_guest_hostname"
 fi
fi

ipaddr_from_hostname () {
 eval '
  if [ x"$adt_'$1'_ipaddr" = x ] && \
     [ x"$adt_'$1'_hostname" != x ]; then
   printf "%s" "finding '$1' IP address from hostname $adt_'$1'_hostname: "
   adt_'$1'_ipaddr=`adnshost -t a +Do +Dt +Dc - "$adt_'$1'_hostname"`
   echo "${adt_'$1'_ipaddr}"
  fi
 '
}

ipaddr_from_hostname host
if [ ! "${adt_readconfig_initscript}" ]; then
 ipaddr_from_hostname guest
fi

search_hook () {
 eval '
  printf "looking for '$2' hook ... "
  case "$adt_'$1'_hook" in
  "")
    case "$adt_config" in
    *_config)
      adt_'$1'_hook=${adt_config%_config}_'$3'
      if test -e "$adt_'$1'_hook"; then
	      echo "default exists: $adt_'$1'_hook"
      else
	      echo "default $adt_'$1'_hook is not a file, so: none"
	      adt_'$1'_hook=""
      fi
      ;;
    *)
      echo "not specified, not computable from config, so: none"
      adt_'$1'_hook=""
      ;;
    esac
    ;;
  *)
    if test -e "$adt_'$1'_hook"; then
      echo "exists: $adt_'$1'_hook"
    else
      echo "specified as $adt_'$1'_hook, but not a file, so: none"
      adt_'$1'_hook=""
    fi
    ;;
  esac
 '
}

search_hook fw firewall fwhook
search_hook setup setup setuphook
search_hook sshauthkeys "ssh auth keys" sshauthkeys

boolean_config () {
  eval '
    case "${adt_'$1'}" in
    y*|Y*|1*|t*)	adt_'$1'=true ;;
    n*|N*|0*|f*)	adt_'$1'=false ;;
    "")			adt_'$1'=$2 ;;
    *)			fail "unknown boolean value \`$1'\'' for adt_'$1'" ;;
    esac
  '
}

# SSH
: ${adt_ssh_privkey:=/root/.ssh/id_${adt_ssh_keytype}_${adt_nominum}}
: ${adt_ssh_pubkey:=${adt_ssh_privkey}.pub}
: ${adt_ssh_keyident_args:=-i ${adt_ssh_privkey}}
: ${adt_ssh_keygen_args:=-t ${adt_ssh_keytype}}

# Xen
: ${adt_xmname:=${adt_nominum}_${adt_distro}}

# LVM
boolean_config lvm_erasebase true

: ${adt_lvm_baselv:=${adt_nominum}_${adt_distro}_base}
: ${adt_lvm_cowdatalv:=${adt_nominum}_${adt_distro}_cowdata}
: ${adt_devmapper_cowdev:=${adt_nominum}_${adt_distro}_snap}

: ${adt_fslink_dir:=adt-xenlvm}
: ${adt_fslink_name:=${adt_nominum}_${adt_distro}_fs}

# LVM - swap
: ${adt_lvm_eraseswap:=$adt_lvm_erasebase}

: ${adt_lvm_swapbaselv:=${adt_nominum}_${adt_distro}_swapbase}
: ${adt_lvm_swapcowdatalv:=${adt_nominum}_${adt_distro}_swapcowdata}
: ${adt_devmapper_swapcowdev:=${adt_nominum}_${adt_distro}_swapsnap}

: ${adt_swaplink_dir:=adt-xenlvm}
: ${adt_swaplink_name:=${adt_nominum}_${adt_distro}_swap}

: ${adt_lvm_swapvg:=$adt_lvm_vg}

: ${adt_swap_snapsize:=$adt_swap_size}
: ${adt_swap_cowchunk:=$adt_fs_cowchunk}

case "$adt_swap_size" in
*[!0A-Za-z]*)	provide_swap=true	;;
*)		provide_swap=false	;;
esac

# Firewall
: ${adt_fw_testbedclients:=${adt_host_ipaddr}}

for fs in fs swap; do swap=${fs#fs}; eval "
  lvm_baselv_${swap}namerhs=\${adt_lvm_${swap}vg}/\${adt_lvm_${swap}baselv}
  lvm_baselv_${swap}namepath=/dev/\${lvm_baselv_${swap}namerhs}

  lvm_cowdata_${swap}namerhs=\${adt_lvm_${swap}vg}/\${adt_lvm_${swap}cowdatalv}
  lvm_cowdata_${swap}namepath=/dev/\${lvm_cowdata_${swap}namerhs}

  lvm_${swap}snapdev=/dev/mapper/\${adt_devmapper_${swap}cowdev}

  lvm_${fs}link_ptrrhs=\${adt_${fs}link_dir}/\${adt_${fs}link_name}
  lvm_${fs}link_dirpath=/dev/\${adt_${fs}link_dir}
  lvm_${fs}link_ptr=/dev/\${adt_${fs}link_dir}/\${adt_${fs}link_name}
  "
done

echo "adtxenlvm: configuration for read for nominum=${adt_nominum}"
