#!/bin/sh
#  Copyright (c) 2013-2017, Parallels International GmbH
# Copyright (c) 2017-2019 Virtuozzo International GmbH. All rights reserved.
#
#  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: Virtuozzo 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

action_script=/usr/libexec/libvzctl/scripts/vz-rst-action

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

	if [ -z "$VZ_RST_USE_NSENTER" ]; then
		export VZ_RST_USE_NSENTER="y"
		nsenter -m -t $pid bash $action_script
		exit 0
	fi

	for root in $CRIU_MNT_NS_ROOTS; do
		# 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
	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")
	if [ -n "$VEID" ]; then
		restore_devices
		[ -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
	;;
"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 "$CRIU_ACTION_POST_RESUME_READ_FD" ] && printf '\0\0\0\0' >&${CRIU_ACTION_POST_RESUME_READ_FD}
	[ -n "$CRIU_ACTION_POST_RESUME_WRITE_FD" ] && ret=$(head -c 4 <&${CRIU_ACTION_POST_RESUME_WRITE_FD} | hexdump -e '"%d"' -n 4)
	[ "$ret" = "0" ] || { echo "Failed on action script in post-restore for $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
