#!/bin/sh
#
# $Id$
#
# Copyright (c) 2013, 2016, Juniper Networks, Inc.
# All rights reserved.
#

OAM_COMPAT=27

pkgtools=${PKGTOOLS:-/usr/libexec}
pkgtmp=${TMPDIR:-/tmp}

gblopts=
command=
cmdopts=
cmdargs=
force=
oam_version=
oam_compat=
oamctl_from_pkg=
xml_vars=

oamctl_usage() {
	echo "usage:" ${0##*/} -v
	echo "      " ${0##*/} '<command>' '[<args>]'
	echo ""
	echo "commands supported:"
	echo "  set-boot-phase <number>"
	echo "  get-boot-phase"
	echo "  set-boot-function <number>"
	echo "  get-boot-function"
	echo "  set-boot-device <name>"
	echo "  get-boot-device"
	echo "  get-boot-cause"
	echo "  get-last-boot-device"
	echo "  set-boot-volume <volume-name>"
	echo "  get-oam-logs"
	echo "  clear-oam-logs"
	echo "  upload-firmware  <filename>"
	echo "  list-snapshots"
	echo "  delete-snapshot <name>"
	echo "  add-snapshot <filename>"
	echo "  add-file-to-oam <source_file> <target_file>"
	echo "    source_file - Path to source file on the Junos volume"
	echo "    target_file - Path to target file on the OAM volume"
	echo "                  Empty target_file copies to root on OAM volume"
	echo "  list-packages"
	echo "  delete-package <name>"
	echo "  add-package <filename>"
	echo "  update-oam <path>"
	echo ""
	echo "flags supported:"
	echo "  [-d, -dd, -ddd ...] display debug information"
	exit 1
}

oamctl_label_source() {
	local s

	for s in mirror gpt ufs; do
		if test -c /dev/$s/oam; then
			echo $s
			return 0
		fi
	done
	echo ""
	return 0
}

oamctl_remount_oam() {
	local access=$1
	local source

	source=`oamctl_label_source`
	mount -u -o $access /dev/$source/oam /oam || return $?
	if test $access = rw; then
		trap "oamctl_remount_oam ro" EXIT
	fi
}

oamctl_mount_oam() {
	local source

	source=`oamctl_label_source`
	mount -o ro /dev/$source/oam /oam || return $?
	trap "umount /oam" EXIT
}

oamctl_on_oam() {
	case `realpath $0` in
	/oam/*) return 0;;
	*) return 1;;
	esac
}

oamctl_load_version() {
	if test -s /oam/boot/OAM-VERSION; then
		while read line
		do
			case "$line" in
			"Version: "*[0-9]*)
				oam_version=${line#Version: }
				;;
			"Compatible: "*[0-9]*)
				oam_compat=${line#Compatible: }
				;;
			esac
		done < /oam/boot/OAM-VERSION
	fi

	oam_version=${oam_version:-0}
	oam_compat=${oam_compat:-$oam_version}
}

oamctl_version_ok() {
	local pkg_version=$1
	local pkg_compat=$2

	if test -z $oam_version; then
		oamctl_load_version
	fi

	# If the OAM volume version is at least the package version,
	# then everything is okay
	test $oam_version -ge $pkg_version
}

oamctl_compat_ok() {
	if test -z $oam_version; then
		oamctl_load_version
	fi

	test $oam_version -ge $OAM_COMPAT
}

oamctl_compat_check() {
	oamctl_compat_ok && return
	$oamctl_from_pkg echo "ERROR: 'oam' package needs to be updated in order to use OAM functionality"
	return 1
}

oamctl_set() {
	local name=$1
	local value="$2"

	echo "${name}=$value" > /dev/oamctl
}

oamctl_get() {
	local name=$1

	awk -F= "/${name}=/ { print \$2 }" /dev/oamctl
}

oamctl_get_boot_phase() {
	oamctl_get "phase"
}

oamctl_set_boot_phase() {
	oamctl_set "phase" $@
}

oamctl_get_boot_function() {
	oamctl_get "function"
}

oamctl_set_boot_function() {
	oamctl_set "function" $@
}

oamctl_get_boot_device() {
	oamctl_get "device"
}

oamctl_set_boot_device() {
	oamctl_set "device" $@
}

oamctl_get_boot_cause() {
	oamctl_get "bootcause"
}

oamctl_get_last_boot_device() {
	oamctl_get "bootdevice"
}

oamctl_set_boot_volume() {
	echo ERROR: unknown boot volume "'$1'"
	return 1
}
:
#
# $Id$
#
# Copyright (c) 2016, Juniper Networks, Inc.
# All rights reserved.
#

oamctl_set_boot_volume() {
	case "$1" in
	oam|junos) oamctl_set_boot_device nand;;
	usb) oamctl_set_boot_device usb;;
	*)
		echo ERROR: unknown boot volume "'$1'"
		return 1
		;;
	esac
}
:
# $Id$
#
# Copyright (c) 2013, 2016, Juniper Networks, Inc.
# All rights reserved.
#

set -e

update_oam() {
	local pkgdir=$1

	if test ! -d $pkgdir/contents; then
		return 1
	fi

	if test -z "$xml_package_1_volume_1_version" -o \
	    -z "$xml_package_1_volume_1_compat"; then
		echo "${0##*/}: update-oam should only be run by pkg"
		oamctl_usage
		return 1
	fi

	local pkg_version=${xml_package_1_volume_1_version:-0}
	local pkg_compat=${xml_package_1_volume_1_compat:-0}

	$force oamctl_version_ok $pkg_version $pkg_compat && return 0

	oamctl_remount_oam rw

	echo "Installing OAM volume contents ..."
	if test -s $pkgdir/oam-boot.tar; then
		skip_boot=
		if test -s $pkgdir/oam-boot.hash -a -s /oam/boot/manifest.esig; then
			want=`cat $pkgdir/oam-boot.hash`
			have=`sha1 < /oam/boot/manifest.esig`
			test x$have = x$want && skip_boot=:
		fi
		$skip_boot tar -C /oam -xpf $pkgdir/oam-boot.tar
	fi
	tar -C $pkgdir/contents --one-file-system -cf - . | \
	    tar -C /oam/boot -xpf -
	cat > /oam/boot/OAM-VERSION << _EOR_
Version: $pkg_version
Compatible: $pkg_compat
_EOR_
	# Should clean up any old files here
	echo "The OAM volume is now installed"
}

add_snapshot() {
	local snapshot=$1
	local bootbits=$2

	oamctl_remount_oam rw

	rm -rf /oam/boot/junos /oam/snapshot

	mkdir /oam/snapshot
	cp $snapshot /oam/snapshot

	if test ! -z $bootbits; then
		mkdir /oam/boot/junos
		tar -C /oam/boot/junos -xf $bootbits
	fi
}

add_file_to_oam() {
	local srcfile=$1
	local target=$2
	local destdir="/oam/${target#/}"

	oamctl_remount_oam rw

	if ! test -f "$srcfile"; then
		echo "Error: Not a valid source_file"
		return 1
	fi

	if test -d "$destdir"; then
		destfile=${srcfile##*/}
	else
		destfile=${destdir##*/}
		destdir=${destdir%/*}
	fi

	case $(realpath -q "$destdir") in
	/oam|/oam/*) ;;
	*)
		echo "Error: '$target' is not a valid destination"
		return 1
		;;
	esac
    
	cp -f $srcfile $destdir/$destfile
}

delete_snapshot() {
	local snapshot=$1
	local nsnaps=0

	local snap
	for snap in /oam/snapshot/${1}.*
	do
		test -s "$snap" || continue

		local name=$(basename $snap)
		test "$snapshot" = "${name%.*}" || continue
		oamctl_remount_oam rw
		rm -f "$snap"
		nsnaps=$((nsnaps + 1))
	done
	if test $nsnaps -gt 0; then
		echo $snapshot snapshot deleted.
	else
		echo No snapshots named $snapshot were found
	fi
}

list_snapshots() {
	local nsnaps=0

	local snap
	for snap in /oam/snapshot/recovery*
	do
		local name=$(basename $snap)
		test -s "$snap" || continue
		test $nsnaps -eq 0 && \
			echo Snapshots available on the OAM volume:
		echo ${name%.*}
		echo "Date created: `date -r $snap`"
		echo "Junos version: `cat /oam/snapshot/VERSION`"
		nsnaps=$((nsnaps + 1))
	done

	if test $nsnaps -gt 0; then
		echo
		echo Total recovery snapshots: $nsnaps
	else
		echo No recovery snapshots available on the OAM volume
	fi
}

get_oam_logs() {
	if test ! -s /oam/var/log/oam; then
		echo No OAM logs available
	else
		cat /oam/var/log/oam
	fi
}

clear_oam_logs() {

	if test -s /oam/var/log/oam; then
		oamctl_remount_oam rw
		rm -f /oam/var/log/oam
	fi
	echo OAM logs cleared
}

upload_firmware() {
	echo The upload-firmware command is not supported in this release
}

list_packages() {
	echo The list-packages command is not supported in this release
}

add_package() {
	echo The add-package command is not supported in this release
}

delete_package() {
	echo The delete-package command is not supported in this release
}

while test $# -ne 0; do
	if test -z $command; then
		case $1 in
		-v|--version)      echo 0.1.0; exit 0 ;;
		-d*)    debuglength=${1#-}
			debuglevel=${#debuglength} ;;
		-f)	force=: ;;
		-x)     set -x; gblopts="$gblopts${gblopts:+ }$1" ;;
		-*)     gblopts="$gblopts${gblopts:+ }$1" ;;
		*=*)    eval "$1";;
		*)      command=$1 ;;
		esac
	else
		case $1 in
		-*)     cmdopts="$cmdopts${cmdopts:+ }$1" ;;
		*)      cmdargs="$cmdargs${cmdargs:+ }$1" ;;
		esac
	fi
	shift
done

if test -z $command; then
	oamctl_usage
fi

case $command in
set-boot-phase)		# set-boot-phase <number>
	oamctl_set_boot_phase "$cmdargs"
	;;
get-boot-phase) 	# get-boot-phase
	oamctl_get_boot_phase
	;;
set-boot-function)	# set-boot-function <number>
	oamctl_set_boot_function "$cmdargs"
	;;
get-boot-function)	# get-boot-function
	oamctl_get_boot_function
	;;
set-boot-device)	# set-boot-device <name>
	oamctl_set_boot_device "$cmdargs"
	;;
get-boot-device)	# get-boot-device
	oamctl_get_boot_device
	;;
get-boot-cause)		# get-boot-cause
	oamctl_get_boot_cause
	;;
get-last-boot-device)	# get-last-boot-device
	oamctl_get_last_boot_device
	;;
set-boot-volume)	# set-boot-volume <volume-name>
	set_boot_volume "$cmdargs"
	;;
get-oam-logs)		# get-oam-logs
	get_oam_logs
	;;
clear-oam-logs)		# clear-oam-logs
	clear_oam_logs
	;;
upload-firmware)	# upload-firmware  <filename>
	upload_firmware $cmdargs
	;;
list-snapshots)		# list-snapshots
	list_snapshots
	;;
delete-snapshot)	# delete-snapshot <name>
	delete_snapshot $cmdargs
	;;
add-snapshot)		# add-snapshot <filename>
	add_snapshot $cmdargs
	;;
add-file-to-oam)	# add-file-to-oam <file> <destdir>
	add_file_to_oam $cmdargs
	;;
list-packages)		# list-packages
	list_packages
	;;
delete-package)		# delete-package <name>
	delete_package $cmdargs
	;;
add-package)		# add-package <filename>
	add_package $cmdargs
	;;
update-oam)		# update-oam <path>
	set -- $cmdargs
	pkgdir=$1

	if oamctl_on_oam; then
		# If running from oam volume, exec the oamctl in the package
		# dir instead
		if test -x $pkgdir/contents/oamctl; then
			exec $pkgdir/contents/oamctl $gblopts $command $cmdopts $cmdargs
		fi
	else
		update_oam $pkgdir
	fi
	;;
*)
	oamctl_usage
	;;
esac

