#!/bin/sh
#  Copyright (C) 2000-2007 SWsoft. 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
#
#
# Common stuff for vzctl helper scripts
# get the name of the script
SELFNAME="${0##*/}"

# Set the sane umask
umask 022

# Error codes
VZ_INVALID_PARAMETER_SYNTAX=20
VZ_FS_NO_DISK_SPACE=46
VZ_FS_BAD_TMPL=47
VZ_FS_NEW_VE_PRVT=48
VZ_CHANGEPASS=74
VZ_CANT_ADDIP=34
VZ_IP_INUSE=78

# iptables parameters
VE_STATE_DIR="/var/lib/vz/veip/"
CONF_DIR="/etc/vz/conf/"

ARPSEND_CMD="arpsend -c 1 -w 1"
IP_CMD=/sbin/ip

# Prints error message and exits
# Parameters:
#   $1 - error message
#   $2 - exit code
# Example of usage:
#   vzerror "Fatal error" 1
vzerror()
{
	# print errors to stdout too
	ERR=$?
	echo "$SELFNAME ERROR: $1"
	exit ${2}
}

# Prints warning message
# Parameters:
#   $* - error message
# Example of usage:
#   vzwarning Invalid user
vzwarning()
{
	echo "$SELFNAME WARNING: $*"
}

# Prints debug message
# Parameters:
#   $* - debug message
# Example of usage:
#   vzdebug Trying to start ls
vzdebug()
{
	echo "$SELFNAME: $*"
}

# Checks if environment variable exists,
# and exits with exit code 1 if not
# Parameters:
#   $* - option names
# Example:
#   vzcheckvar VEID IP_ADDR
vzcheckvar()
{
	local VAR
	for VAR; do
		if eval test "\"x\$$VAR\"" = "x"; then
			vzerror "Missing parameter: $VAR" $VZ_INVALID_PARAMETER_SYNTAX
		fi
	done
}

# This function fills $NETDEVICES with all network interfaces
# You should always call it before calling vzarp
vzgetnetdev()
{
	# Get a list of interfaces, excluding ones with LOOPBACK,
	# NOARP, or SLAVE flags
	NETDEVICES="$(${IP_CMD} addr list | awk '
	/^[0-9]+/ {
		dev="";
	}
	/^[0-9]+/ && /UP/ && !/LOOPBACK/ && !/SLAVE/ && !/NOARP/ {
		dev=$2;
	}
	/^[\ \t]+inet / {
		if (dev != "") print (dev);
		dev="";
	}' | sed 's/:$//')"
}

vz_get_local_dev()
{
	local dev netdev

	[ -n "$1" -a -n "$NETDEVICES" ] || return 1

	dev="$(${IP_CMD} route get "$1" |sed -ne '/ via /! s/^.* dev \([^ ]\+\) \+src \+.*$/\1/p;Q')"
	[ -n "$dev" ] || return 1

	for netdev in ${NETDEVICES}; do
		if [ "$dev" = "$netdev" ]; then
			printf %s "$dev"
			return 0
		fi
	done
	return 1
}

# Adds/deletes public ARP records for given IP for all interfaces
# Parameters:
#   $1		- should be either "add" or "del"
#   $2		- IP address
#   $NETDEVICES - Network devices used to take MAC addresses from
vzarp()
{
	local dev

	dev="$(vz_get_local_dev "$2")" || return
	${IP_CMD} neigh "$1" proxy "$2" dev "$dev" >/dev/null 2>&1
}

# Send ARP request to detect that somebody already have this IP
vzarpipdetect()
{
	local dev ip

	[ -n "$1" ] || return
	[ "${SKIP_ARPDETECT}" = "yes" ] && return

	for ip in ${1}; do
		dev="$(vz_get_local_dev "$ip")" || continue
		${ARPSEND_CMD} -D -e "$ip" "$dev" ||
			vzwarning "$ARPSEND_CMD -D -e $ip $dev FAILED"
	done
}

# Send ARP request to update neighbour ARP caches
vzarpipset()
{
	local dev ip

	[ -n "$1" ] || return

	for ip in ${1}; do
		dev="$(vz_get_local_dev "$ip")" || continue
		${ARPSEND_CMD} -U -i "$ip" -e "$ip" "$dev" ||
			vzwarning "$ARPSEND_CMD -U -i $ip -e $ip $dev FAILED"
	done
}

vzaddrouting4()
{
	local src_addr=

	if [ -n "$VE_ROUTE_SRC_DEV" ]; then
		src_addr=`${IP_CMD} route list table local dev "$VE_ROUTE_SRC_DEV" |
			grep '^local'| cut -d' ' -f2 | grep -v '^127\.' | head -n 1`
		[ -n "${src_addr}" ] ||
			vzerror "Unable to get source ip [${VE_ROUTE_SRC_DEV}]" $VZ_CANT_ADDIP
		src_addr="src ${src_addr}"
	fi
	${IP_CMD} route add $1 dev venet0 ${src_addr} ||
		vzerror "Unable to add route ${IP_CMD} route add $1 dev venet0 ${src_addr}" $VZ_CANT_ADDIP
}

vzaddrouting6()
{
	${IP_CMD} route add ${1} dev venet0 ||
		vzerror "Unable to add route ${IP_CMD} route add $1 dev venet0" ${VZ_CANT_ADDIP}
}

# Sets VE0 source routing for given IP
# Parameters:
#   $1 - IP address
vzaddrouting()
{

	if ! ${IP_CMD} route list table all "$1" | grep -qs "$1 dev venet0"; then
		if [ "${1#*:}" = "$1" ]; then
			vzaddrouting4 "$1"
		else
			vzaddrouting6 "$1"
		fi
	fi
}

# Deletes VE0 source routing for given IP
# Parameters:
#   $1 - IP address
vzdelrouting()
{
	if ${IP_CMD} route list ${1} | grep -qs "$1 dev venet0"; then
		${IP_CMD} route del ${1} dev venet0 ||
			vzwarning "Unable to del route ${IP_CMD} route del $1 dev venet0"
	fi
}
