#!/bin/sh
set -f

CR="
"

error() { echo "$@" 1>&2; }
fail() { [ $# -eq 0 ] || error "$@"; exit 1; }

bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; return 1; }
read_uptime() {
	local idle
	{ read _RET idle </proc/uptime; } >/dev/null 2>&1 || _RET=""
}

debug() {
	local level=${1}; shift;
	[ "${level}" -gt "${VERBOSITY}" ] && return
	error "${@}"
}

net_get_gateway() {
	_RET=$(route -n | awk '$1 == "0.0.0.0" && $2 != "0.0.0.0" { print $2 }')
}
net_get_nameservers() {
	local gw nslist
	local t1 t2 t3 nslist="" ns=""
	while read t1 t2 t3; do
		case "$t1" in
			nameserver) nslist="${nslist} ${t2}";;
		esac
	done < /etc/resolv.conf
	_RET="$nslist"
}

debug_connection() {
	local gw=""

	echo "############ debug start ##############"
	echo "### /etc/init.d/sshd start"
	/etc/init.d/sshd start
	net_get_gateway && gw=$_RET
	gw=$(route -n | awk '$1 == "0.0.0.0" && $2 != "0.0.0.0" { print $2 }')
	echo "### ifconfig -a"
	ifconfig -a
	echo "### route -n"
	route -n
	echo "### cat /etc/resolv.conf"
	cat /etc/resolv.conf
	if [ -n "${gw}" ]; then
		echo "### ping -c 5 ${gw}"
		ping -c 5 ${gw}
	else
		echo "### gateway not found"
	fi
	local t1 t2 t3 nslist="" ns=""
	while read t1 t2 t3; do
		case "$t1" in
			nameserver) nslist="${nslist} ${t2}";;
		esac
	done < /etc/resolv.conf
	echo "### pinging nameservers"
	for ns in ${nslist}; do
		echo "#### ping -c 5 ${ns}"
		ping -c 5 ${ns}
	done
	echo "### uname -a"
	uname -a
	lxc-is-container || { echo "### lsmod"; lsmod; }
	echo "### dmesg | tail"
	dmesg | tail
	echo "### tail -n 25 /var/log/messages"
	tail -n 25 /var/log/messages
	echo "############ debug end   ##############"
}

mount_callback_umount() {
	# dev, opts, callback, args
	local dev="$1" opts="$2" callback="$3" ret=""
	local tmpd=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.mp.XXXXXX")
	mount "$dev" $opts "$tmpd" || {
		ret=$?;
		debug 2 "failed mount $dev";
		rmdir "$tmpd"
		return $ret;
	}
	shift 3;
	"$callback" "$tmpd" "$@"
	ret=$?
	umount "$tmpd" || {
		ret=$?;
		debug 1 "failed umount $dev";
		return $ret;
	}
	rmdir "$tmpd"
	return 0
}

find_devs_with() {
	# return a list of devices that match filter
	# where filter is like:
    #  TYPE=<filesystem>
    #  LABEL=<label>
    #  UUID=<uuid>
	local filter="$1"
	local out rc ret=""
	out=$(blkid "-t$filter" "-odevice" 2>/dev/null)
	rc=$?
	if [ $rc -eq 0 ]; then
		local item=""
		for item in ${out}; do
			ret="${ret} ${item}"
		done
		_RET=${ret# }
		return 0
	elif [ $rc -eq 2 ]; then
		# 2 is "no matching devices"
		_RET=""
		return 0
	fi
	return $rc
}

ipinfo() {
	# return a list of ip info
	# each line contain: ifname,up/down,ipv4,ipv4mask
	local cur_if="" cur_up=0 cur_inargs=0 cur_good=0 cur_ipv4="" cur_ipv6="" cur_nm
	local data="" dline=""
	while read line; do
		case "$line" in
			[0-9]:*|[0-9][0-9]:*|[0-9][0-9][0-9]:*)
				if [ -n "$cur_if" ]; then
					dline="${cur_if},${cur_up},${cur_ipv4},${cur_nm},${cur_ipv6}"
					data="${data}|${dline}"
				fi
				set -- ${line}
				cur_if=${2%:}
				cur_up=down
				cur_ipv4=""
				cur_ipv6=""
				case "$3" in
					*,UP,*|*,UP\>|\<UP,*) cur_up=up;;
				esac
		esac
		case "$line" in
			*inet\ *)
				set -- $line
				[ "${2#*/}" != "$2" ] && {
					cur_ipv4="${2%/*}";
					cur_nm="${2#*/}";
				}
				;;
			*inet6\ *) :
				# don't know how to do this
				set -- $line
				[ "${2#*/}" != "$2" ] && cur_ipv6="${2%/*}";;
		esac
	done
	if [ -n "$cur_if" ]; then
		data="${data}|${cur_if},${cur_up},${cur_ipv4},${cur_nm},${cur_ipv6}"
	fi
	_RET="${data#|}"
	return 0
}

# upon return, the following globals are set (KC=Kernel Commandline)
# KC_CONSOLES : full path (including /dev) to all console= entries that exist
# KC_CONSOLE : the last entry on the kernel command line
# KC_PREF_CONSOLE : the last existing entry on kernel command line
# KC_ROOT : root= variable
# KC_DEBUG_INITRAMFS : set to '1' if debug-initramfs is on commandline
# KC_VERBOSE: set to '1' if 'verbose' on commandline
# KC_RAMDISK_ROOT: set to 1 if cmdline said not to mount a root (0 otherwise)
parse_cmdline() {
	# expects that /dev is mounted/populated
	KC_VERBOSE=0
	KC_RAMDISK_ROOT=0
	local cmdline="$1" tok="" val="" key="" consoles=""
	local last_con="" pref_con=""
	is_lxc && return 0
	KC_CONSOLE=/dev/tty0
	set -f
	[ $# -eq 0 ] && read cmdline < /proc/cmdline
	for tok in $cmdline; do
		val=${tok#*=}
		key=${tok%%=*}
		case $key in
			console)
				val="/dev/${val#/dev}"
				last_con="$val"
				[ -e "$val" ] && { echo "" > "$val"; } 2>/dev/null || continue
				consoles="$consoles $val"
				pref_con="$val"
				KC_CONSOLE="$val"
				;;
			rdroot) KC_RAMDISK_ROOT=1;;
			root) KC_ROOT="$val";;
			debug-initramfs) KC_DEBUG_INITRAMFS=1;;
			verbose) KC_VERBOSE=1;;
		esac
	done

	case "$KC_ROOT" in
		[Nn][Oo][Nn][Ee]|ramdisk) KC_RAMDISK_ROOT=1;;
	esac

	# set KC_PREF_CONSOLE to the last writable console
	# if that is the same as the last
	[ "$pref_con" = "$last_con" ] && pref_con=""
	KC_PREF_CONSOLE="$pref_con"
	KC_CONSOLES="${consoles# }"

	set +f
	return
}

idebug() {
	[ "$KC_VERBOSE" = "0" ] && return
	echo "debug:" "$@"
}
iinfo() {
	[ "$KC_QUIET" = "1" ] && return
	echo "info:" "$@"
}
failure() {
	echo "FATAL: ====" "$@" "===="
	echo "Executing /bin/sh. maybe you can help"
	exec /bin/sh
}

is_mounted() {
	awk '($3 == fs || fs == "") && ( $2 == mp || mp == "") && \
		( $1 == dev || dev == "" ) { e=0; };  END { exit(e); }' \
		e=1 "fs=$1" "dev=$2" "mp=$3" /proc/self/mounts
}

mount_once() {
	local fs="$1" dev="$2" mp="$3"
	is_mounted "$fs" "$dev" "$mp" && return
	shift 3
	mount -t "$fs" "$dev" "$mp" "$@"
}

is_lxc() {
	local container=""
	[ "$0" = "/init" ] && return 1 # lxc wont use /init (not a ramdisk)

	# logic copied from ubuntu's /etc/init/container-detect.conf (upstart)
	if [ -z "$container" ]; then
		[ -n "$LIBVIRT_LXC_UUID" ] && container=lxc-libvirt
	fi

	# Detect OpenVZ containers
	if [ -z "$container" ]; then
		[ -d /proc/vz ] && [ ! -d /proc/bc ] && container=openvz
	fi

	# Detect Vserver containers
	if [ -z "$container" -a -f /proc/self/status ]; then
		while read k v; do
			[ "$k" = "VxID:" ] && [ ${v:-0} -gt 1 ] &&
				container=vserver && break;
		done < /proc/self/status >/dev/null 2>&1
	fi

	[ -n "$container" ]
}
is_not_lxc() { ! is_lxc; }

# vi: ts=4 noexpandtab syntax=sh
