#!/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.
#
# 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

VZCTL="/usr/sbin/vzctl"
JOIN_CT="$VZCTL --skiplock --skipowner exec3 $VEID"
SYSTEMCTL="/bin/systemctl -q"
VE_FEATURE_NFSD=$(( 1 << 8 ))
TIMEOUT="/usr/bin/timeout"
NFSD_TIMEOUT="10s"

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

service_stop_and_save_state () {
	SERVICE=$1
	IMAGE=$2

	if $TIMEOUT $NFSD_TIMEOUT $JOIN_CT $SYSTEMCTL is-active $SERVICE; then
		echo "$SERVICE" >> $IMAGE || \
			{ echo "Failed to dump $SERVICE status"; exit 1; }
		$TIMEOUT $NFSD_TIMEOUT $JOIN_CT $SYSTEMCTL stop $SERVICE || \
			{ echo "Failed to stop $SERVICE"; exit 1; }
		echo "Stopped $SERVICE service"
	fi
}

stop_nfs_server_service_before_dump () {
	NFSD_IMAGE="$CRTOOLS_IMAGE_DIR/vz_nfsd_active.img"
	echo "" > $NFSD_IMAGE || \
		{ echo "Failed to dump nfs-server status"; exit 1; }
	if (( $(cgget -n -v -r ve.features $VEID) & $VE_FEATURE_NFSD )) && \
		[ $(cgget -n -v -r freezer.state machine.slice/$VEID) = "THAWED" ]; then
		service_stop_and_save_state "nfs-server" "$NFSD_IMAGE"
		service_stop_and_save_state "nfs-mountd" "$NFSD_IMAGE"
		service_stop_and_save_state "nfsdcld" "$NFSD_IMAGE"
		service_stop_and_save_state "nfs-blkmap" "$NFSD_IMAGE"
	fi
}

# For container with nfsd feature restart nfs-server and friends if they were stopped before dump
restart_nfs_server_service_alive() {
	NFSD_IMAGE="$CRTOOLS_IMAGE_DIR/vz_nfsd_active.img"
	if [ -n "$VEID" ] && (( $(cgget -n -v -r ve.features $VEID) & $VE_FEATURE_NFSD )) && \
		[ -f "$NFSD_IMAGE" ]; then
		VZ_NFSD_ACTIVE=`cat $NFSD_IMAGE`
		if [ -n "$VZ_NFSD_ACTIVE" ]; then
			for SERVICE in $VZ_NFSD_ACTIVE; do
				$TIMEOUT $NFSD_TIMEOUT $JOIN_CT $SYSTEMCTL start $SERVICE || \
					{ echo "Failed to start $SERVICE"; exit 1; }
				echo "Restarted $SERVICE service"
			done
			echo "Restarted nfs server related services"
		fi
	fi
}

set -e
case "$CRTOOLS_SCRIPT_ACTION" in
"pre-dump")
	if [ -z "$CRTOOLS_IMAGE_DIR" ]; then
		echo "Missing parameter CRTOOLS_IMAGE_DIR"
		exit 1
	fi
	if [ -n "$VEID" ]; then
		# Save monotonic offsets for next restore
		cat /sys/fs/cgroup/ve/$VEID/ve.clock_bootbased  > $CRTOOLS_IMAGE_DIR/vz_clock_bootbased.img || \
			{ echo "Failed to dump ve.clock_bootbased"; exit 1;  }
		cat /sys/fs/cgroup/ve/$VEID/ve.clock_monotonic  > $CRTOOLS_IMAGE_DIR/vz_clock_monotonic.img || \
			{ echo "Failed to dump ve.clock_monotonic"; exit 1; }
		cat /sys/fs/cgroup/memory/machine.slice/$VEID/memory.limit_in_bytes > \
			$CRTOOLS_IMAGE_DIR/vz_memory_limit_in_bytes.img || \
			{ echo "Failed to dump memory limit in bytes"; exit 1; }
		cat /sys/fs/cgroup/memory/machine.slice/$VEID/memory.memsw.limit_in_bytes > \
			$CRTOOLS_IMAGE_DIR/vz_memory_memsw_limit_in_bytes.img || \
			{ echo "Failed to dump memory swap limit in bytes"; exit 1; }

		# For container with nfsd feature stop nfs-server before dump
		stop_nfs_server_service_before_dump
	fi
	;;
"post-dump")
	if [ -z "$CRTOOLS_IMAGE_DIR" ]; then
		echo "Missing parameter CRTOOLS_IMAGE_DIR"
		exit 1
	fi
	if [ -n "$VEID" ]; then
		cgexec -g ve:$VEID cat /proc/sys/kernel/core_pattern > \
			$CRTOOLS_IMAGE_DIR/vz_core_pattern.img || { echo "Failed to dump core_pattern"; exit 1; }
		if [ -f "/proc/sys/fs/fsync-enable" ]; then
			cgexec -g ve:$VEID cat /proc/sys/fs/fsync-enable > \
				$CRTOOLS_IMAGE_DIR/vz_fsync-enable.img || { echo "Failed to dump fsync-enable"; exit 1; }
		fi
		cgexec -g ve:$VEID cat /proc/sys/fs/odirect_enable > \
			$CRTOOLS_IMAGE_DIR/vz_odirect_enable.img || { echo "Failed to dump odirect_enable"; exit 1; }
		cgexec -g ve:$VEID cat /proc/sys/kernel/randomize_va_space > \
			$CRTOOLS_IMAGE_DIR/vz_randomize_va_space.img || { echo "Failed to dump randomize_va_space"; exit 1; }
	fi
	ret=0
	[ -n "$STATUSFD" ] && printf '\0\0\0\0' >&${STATUSFD}
	[ -n "$WAITFD" ] && ret=$(head -c 4 <&$WAITFD | hexdump -e '"%d"' -n 4)

	[ "$ret" = "0" ]
	;;
"dump-alive")
	if [ -z "$CRTOOLS_IMAGE_DIR" ]; then
		echo "Missing parameter CRTOOLS_IMAGE_DIR"
		exit 1
	fi

	# For container with nfsd feature restart nfs-server and friends if they were stopped before dump
	restart_nfs_server_service_alive
	;;
esac
exit 0
