#!/bin/sh
#  Copyright (c) 2013-2017, Parallels International GmbH
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#  Our contact details: Parallels International GmbH, Vordergasse 59, 8200
#  Schaffhausen, Switzerland.
#
# This script is called by CRIU (http://criu.org) after creating namespaces.
#
# Parameters are passed in environment variables.
# Required parameters:
#   STATUSFD	  - file descriptor for sending signal to vzctl
#   WAITFD	  - file descriptor for receiving signal from vzctl
#   CRTOOLS_SCRIPT_ACTION - current action (set by criu)

exec 1>&2

restore_devices()
{
	local s d t major minor old dir device
	local pid=$CRTOOLS_INIT_PID

	root=/proc/$pid/root

	# VE_PLOOP_DEVS=UUID@ploopN:major:minor:[root]
	for s in $VE_PLOOP_DEVS; do
		uuid=${s%%@*}
		t=${s#*@}
		device=${t%%:*}
		t=${t#*:}
		major=${t%%:*}
		t=${t#*:}
		minor=${t%%:*}

		[ ! -L "$root/dev/$uuid" ] && continue

		old=$(readlink $root/dev/$uuid)
		[ -z "$old" ] && continue

		for d in "${old}" "${device}"; do
			dir=$root/$d
			dir=${dir%/*}
			if [ -e "$dir" ]; then
				rm -f $root/$d
			else
				mkdir -p $dir
			fi
			mknod -m 600 $root/$d b $major $minor
		done

		rm -f $root/dev/$uuid
	done
}

if [ -z "$CRTOOLS_SCRIPT_ACTION" ]; then
	echo "Missing parameter CRTOOLS_SCRIPT_ACTION"
	exit 1
fi

set -e
case "$CRTOOLS_SCRIPT_ACTION" in
"setup-namespaces")
	pid=$CRTOOLS_INIT_PID
	ln -s /proc/$pid/ns/net $VE_NETNS_FILE

	if [ -n "$VEID" ]; then
		[ -n "$VE_CLOCK_BOOTBASED" ] && cgset -r ve.clock_bootbased="$VE_CLOCK_BOOTBASED" $VEID
		[ -n "$VE_CLOCK_MONOTONIC" ] && cgset -r ve.clock_monotonic="$VE_CLOCK_MONOTONIC" $VEID
		[ -n "$VE_IPTABLES_MASK" ] && cgset -r ve.iptables_mask="$VE_IPTABLES_MASK" $VEID
		[ -n "$VE_FEATURES" ] && cgset -r ve.features="$VE_FEATURES" $VEID
		[ -n "$VE_AIO_MAX_NR" ] && cgset -r ve.aio_max_nr="$VE_AIO_MAX_NR" $VEID
		cgset -r ve.state="START $pid" $VEID || { echo "Failed to start $VEID"; exit 1; }
	fi
	;;
"post-setup-namespaces")
	restore_devices
	if [ -n "$VEID" ]; then
		[ -n "$VE_OS_RELEASE" ] && cgset -r ve.os_release="$VE_OS_RELEASE" $VEID
		[ -n "$VE_PID_MAX" ] && cgset -r ve.pid_max="$VE_PID_MAX" $VEID
	fi
	;;
"network-unlock")
	ret=0
	[ -n "$STATUSFD" ] && printf '\0\0\0\0' >&${STATUSFD}
	[ -n "$WAITFD" ] && ret=$(head -c 4 <&$WAITFD | hexdump -e '"%d"' -n 4)

	[ "$ret" = "0" ] || { echo "Failed on network unlocking for $VEID"; exit 1; }
	;;
"post-restore")
	if [ -z "$CRTOOLS_IMAGE_DIR" ]; then
		echo "Missing parameter CRTOOLS_IMAGE_DIR"
		exit 1
	fi
	if [ -n "$VEID" ]; then
		[ -f "$CRTOOLS_IMAGE_DIR/vz_core_pattern.img" ] && \
			{ cgexec -g ve:$VEID echo `cat $CRTOOLS_IMAGE_DIR/vz_core_pattern.img` \
			 > /proc/sys/kernel/core_pattern || { echo "Failed to restore core_pattern"; exit 1; } }
		[ -f "$CRTOOLS_IMAGE_DIR/vz_fsync-enable.img" ] && \
			{ cgexec -g ve:$VEID echo `cat $CRTOOLS_IMAGE_DIR/vz_fsync-enable.img` \
			 > /proc/sys/fs/fsync-enable || { echo "Failed to restore fsync-enable"; exit 1; } }
		[ -f "$CRTOOLS_IMAGE_DIR/vz_odirect_enable.img" ] && \
			{ cgexec -g ve:$VEID echo `cat $CRTOOLS_IMAGE_DIR/vz_odirect_enable.img` \
			 > /proc/sys/fs/odirect_enable || { echo "Failed to restore odirect_enable"; exit 1; } }
		[ -f "$CRTOOLS_IMAGE_DIR/vz_randomize_va_space.img" ] && \
			{ cgexec -g ve:$VEID echo `cat $CRTOOLS_IMAGE_DIR/vz_randomize_va_space.img` \
			 > /proc/sys/kernel/randomize_va_space || { echo "Failed to restore randomize_va_space"; exit 1; } }
	fi
	[ -n "$VEID" ] && { cgset -r ve.pseudosuper="0" $VEID || { echo "Failed to drop pseudosuper on $VEID"; exit 1; } }
	ret=0
	[ -n "$STATUSFD" ] && printf '\0\0\0\0' >&${STATUSFD}
	[ -n "$WAITFD" ] && ret=$(head -c 4 <&$WAITFD | hexdump -e '"%d"' -n 4)

	[ "$ret" = "0" ] || { echo "Failed on post-restore for $VEID"; exit 1; }
	;;
esac

#
# Exit with success by default, any error must cause
# messaging with explicit "exit 1"
exit 0
