#!/usr/bin/bash
# Copyright (c) 2001-2017, Parallels International GmbH
# Copyright (c) 2017-2019 Virtuozzo International GmbH. All rights reserved.
#
# This file is part of OpenVZ libraries. OpenVZ is free software; you can
# redistribute it and/or modify it under the terms of the GNU Lesser 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
# Our contact details: Virtuozzo International GmbH, Vordergasse 59, 8200
# Schaffhausen, Switzerland.

# Set the sane umask
umask 022

ROUTED_UUID=4896d4dc-7035-45f9-ac14-2bd1d1809c26

NWSYSTEMDIR=/etc/NetworkManager
NWCONFDIR="$NWSYSTEMDIR/system-connections"
NWSYMLINK=/etc/systemd/system/multi-user.target.wants/NetworkManager.service
SYSTEMCTL=/bin/systemctl
IP4_ROUTED_GW=169.254.0.1
IP4=
IP6=

# Error codes
VZ_SYSTEM_ERROR=3
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
VZ_SET_RATE=80
VZ_SET_ACCOUNT=81
CP='/bin/cp -fp'
WICKED=/etc/systemd/system/network.service
[ -f /etc/fedora-release ] && CP='/bin/cp -f --preserve=mode,ownership'

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

# Puts line
# NAME="value"
# to config file. If NAME is found, line gets replaced,
# otherwise it is added to the end of file.
# Parameters:
# $1 - config file
# $2 - NAME
# $3 - value
function put_param()
{
	local file="$1"
	local name="$2"
	local value="$3"
	local path

	path=${file%/*}
	if [ ! -d "${path}" ]; then
		 mkdir -p ${path} || error "Unable to create dir ${path}" $VZ_FS_NO_DISK_SPACE
	fi

	if [ ! -e "${file}" ]; then
		touch "${file}" || error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
	fi

	${CP} ${file} ${file}.$$ || error "Can't copy file $file" $VZ_FS_NO_DISK_SPACE
	if grep -E "^$name=.*" $file.$$ >/dev/null 2>&1; then
		/bin/sed -e "s|^$name=.*|$name=\"$value\"|" < ${file} > ${file}.$$
		if [ $? -ne 0 ]; then
			rm -f ${file}.$$ 2>/dev/null
			error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
		fi
	else
		echo "$name=\"$value\"" >> $file.$$ || error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
	fi

	mv -f ${file}.$$ ${file} || rm -f ${file}.$$
}

# Adds value to variable NAME
# in config file. If NAME is found, value gets added,
# otherwise it is added to the end of file.
# Parameters:
# $1 - config file
# $2 - NAME
# $3 - value
function add_param()
{
	local file=$1
	local name=$2
	local value=$3
	local path

	path=${file%/*}
	if [ ! -d "${path}" ]; then
		 mkdir -p ${path} || error "Unable to create dir ${path}" $VZ_FS_NO_DISK_SPACE
	fi

	if [ ! -e "${file}" ]; then
		touch "${file}" || error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
	fi

	${CP} ${file} ${file}.$$ || error "Can't copy file $file" $VZ_FS_NO_DISK_SPACE
	if grep -qe "^$name=" $file.$$ >/dev/null 2>&1; then
		/bin/sed -e "s|^$name=\"\(.*\)\"|$name=\"\1 $value \"|" < ${file} > ${file}.$$
		if [ $? -ne 0 ]; then
			rm -f ${file}.$$ 2>/dev/null
			error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
		fi
	else
		echo "$name=\"$value\"" >> $file.$$ || error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
	fi

	mv -f ${file}.$$ ${file} || rm -f ${file}.$$
}

function del_param()
{
	local file=$1
	local name=$2
	local value="$3"
	local path

	path=${file%/*}
	if [ ! -d "${path}" ]; then
		 mkdir -p ${path} || error "Unable to create dir ${path}" $VZ_FS_NO_DISK_SPACE
	fi
	if grep -qe "^$name=" $file >/dev/null 2>&1; then
		${CP} ${file} ${file}.$$ || \
			error "Can't copy file $file" $VZ_FS_NO_DISK_SPACE
		if [ -z "${value}" ]; then
			/bin/sed -e "/^${name}=.*/d" < ${file} > ${file}.$$
		else
			sed -e "s|^${name}=\(.*\)${value}\(.*\)|${name}=\1\2|" <${file} > ${file}.$$
		fi
		if [ $? -ne 0 ]; then
			rm -f ${file}.$$ 2>/dev/null
			error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
		fi
		mv -f ${file}.$$ ${file} || rm -f ${file}.$$
	fi
}

function del_param2()
{
	local file=$1
	local name=$2
	local path

	path=${file%/*}
	if [ ! -d "${path}" ]; then
		 mkdir -p ${path} || error "Unable to create dir ${path}" $VZ_FS_NO_DISK_SPACE
	fi
	if grep -qe "^$name " $file >/dev/null 2>&1; then
		${CP} ${file} ${file}.$$ || \
			error "Can't copy file $file" $VZ_FS_NO_DISK_SPACE
		/bin/sed -e "/^${name} .*/d" < ${file} > ${file}.$$
		if [ $? -ne 0 ]; then
			rm -f ${file}.$$ 2>/dev/null
			error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
		fi
		mv -f ${file}.$$ ${file} || rm -f ${file}.$$
	fi
}

# Puts line
# NAME value
# to config file. If NAME is found, line gets replaced,
# otherwise it is added to the end of file.
# Parameters:
# $1 - config file
# $2 - NAME
# $3 - value
function put_param2()
{
	local file="$1"
	local name="$2"
	local value="$3"
	local path;

	path=${file%/*}
	if [ ! -d "${path}" ]; then
		 mkdir -p ${path} || error "Unable to create dir ${path}" $VZ_FS_NO_DISK_SPACE
	fi

	if [ ! -e "${file}" ]; then
		touch "${file}" || error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
	fi

	${CP} ${file} ${file}.$$ || error "Can't copy file $file" $VZ_FS_NO_DISK_SPACE
	if grep -E "^\<$name\>" $file.$$ >/dev/null 2>&1; then
		/bin/sed -e "s|^\<$name\>.*|$name $value|" < ${file} > ${file}.$$
		if [ $? -ne 0 ]; then
			rm -f ${file}.$$ 2>/dev/null
			error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
		fi
	else
		echo "$name $value" >> $file.$$ || error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
	fi

	mv -f ${file}.$$ ${file} || rm -f ${file}.$$
}

# Puts line
# NAME=( value )
# to config file. If NAME is found, line gets replaced,
# otherwise it is added to the end of file.
# Parameters:
# $1 - config file
# $2 - NAME
# $3 - value
function put_param3() {
	local file=$1
	local name=$2
	local value=$3
	local path

	path=${file%/*}
	if [ ! -d "${path}" ]; then
		 mkdir -p ${path} || error "Unable to create dir ${path}" $VZ_FS_NO_DISK_SPACE
	fi

	if [ ! -e "${file}" ]; then
		touch "${file}" || error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
	fi

	${CP} ${file} ${file}.$$ || error "Can't copy file $file" $VZ_FS_NO_DISK_SPACE
	if grep -E "^$name=\(.*\)" $file.$$ >/dev/null 2>&1; then
		if [ -z "${value}" ]; then
			/bin/sed -e "s|^$name=\(.*\)|$name=\( \)|" < ${file} > ${file}.$$
		else
			/bin/sed -e "s|^$name=\(.*\)|$name=\( \"$value\" \)|" < ${file} > ${file}.$$
		fi
		if [ $? -ne 0 ]; then
			rm -f ${file}.$$ 2>/dev/null
			error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
		fi
	else
		if [ -z "${value}" ]; then
			echo "$name=( )" >> $file.$$ || error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
		else
			echo "$name=( \"$value\" )" >> $file.$$ || error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
		fi
	fi

	mv -f ${file}.$$ ${file} || rm -f ${file}.$$

}

# Puts line
# NAME=value
# to config file. If NAME is found, line gets replaced,
# otherwise it is added to the end of file.
# Parameters:
# $1 - config file
# $2 - NAME
# $3 - value
function put_param4()
{
	local file="$1"
	local name="$2"
	local value="$3"
	local path

	path=${file%/*}
	if [ ! -d "${path}" ]; then
		 mkdir -p ${path} || error "Unable to create dir ${path}" $VZ_FS_NO_DISK_SPACE
	fi

	if [ ! -e "${file}" ]; then
		touch "${file}" || error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
	fi

	${CP} ${file} ${file}.$$ || error "Can't copy file $file" $VZ_FS_NO_DISK_SPACE
	if grep -E "^$name=.*" $file.$$ >/dev/null 2>&1; then
		/bin/sed -e "s|^$name=.*|$name=$value|" < ${file} > ${file}.$$
		if [ $? -ne 0 ]; then
			rm -f ${file}.$$ 2>/dev/null
			error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
		fi
	else
		echo "$name=$value" >> $file.$$ || error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
	fi

	mv -f ${file}.$$ ${file} || rm -f ${file}.$$
}


# Adds value to array NAME
# in config file. If NAME is found, value gets added,
# otherwise it is added to the end of file.
# Parameters:
# $1 - config file
# $2 - NAME
# $3 - value
function add_param3() {
	local file=$1
	local name=$2
	local value=$3
	local path

	path=${file%/*}
	if [ ! -d "${path}" ]; then
		 mkdir -p ${path} || error "Unable to create dir ${path}" $VZ_FS_NO_DISK_SPACE
	fi

	if [ ! -e "${file}" ]; then
		touch "${file}" || error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
	fi

	${CP} ${file} ${file}.$$ || error "Can't copy file $file" $VZ_FS_NO_DISK_SPACE
	if grep -E "^$name=\(.*\)" $file.$$ >/dev/null 2>&1; then
		/bin/sed -r "s|^$name=\((.*)\)|$name=\( \1 \"$value\" \)|" < ${file} > ${file}.$$
		if [ $? -ne 0 ]; then
			rm -f ${file}.$$ 2>/dev/null
			error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
		fi
	else
		echo "$name=( \"$value\" )" >> $file.$$ || error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
	fi

	mv -f ${file}.$$ ${file} || rm -f ${file}.$$
}

# Removes value from array NAME
# in config file. If NAME is found, value gets removed,
# otherwise this is a noop function.
# Parameters:
# $1 - config file
# $2 - NAME
# $3 - value
function del_param3() {
	local file=$1
	local name=$2
	local value=$3

	[ ! -f $file ] && return

	if grep -E "^$name=\(.*\)" $file>/dev/null 2>&1; then
		${CP} ${file} ${file}.$$ || error "Can't copy file $file" $VZ_FS_NO_DISK_SPACE
		/bin/sed -r "s|^($name=\( .*)\"$value\"(.* \))|\1\2|" < ${file} > ${file}.$$
		if [ $? -ne 0 ]; then
			rm -f ${file}.$$ 2>/dev/null
			error "Can't change file $file" $VZ_FS_NO_DISK_SPACE
		fi
		mv -f ${file}.$$ ${file}
	else
		return
	fi
}

function remove_debian_interface_by_proto()
{
	local dev="$1"
	local proto=$2
	local cfg="$3"

	${CP} ${cfg} ${cfg}.$$ || \
		error "Can't copy file ${cfg}" $VZ_FS_NO_DISK_SPACE

	awk '
		NF == 0 {next}
		line=""
		$1 == "auto" && $2 ~/'${dev}'$/ {line=$0; getline;}
		$1 == "iface" && $3 ~/'$proto'$/ && $2 ~/'${dev}'$/ {skip = 1; next}
		line != "" && !skip {print line}
		line=""
		$1 == "auto" && $2 ~/'${dev}':[0-9]+$/ {line=$0; getline;}
		$1 == "iface" && $3 ~/'$proto'$/ && $2 ~/'${dev}':[0-9]+$/ {skip = 1; next}
		line != "" && !skip {print line}
		/^\t/ && skip {next}
		{skip = 0; print}
	' < ${cfg} > ${cfg}.$$ && mv -f ${cfg}.$$ ${cfg}

	rm -f ${cfg}.$$ 2>/dev/null
}

function remove_debian_interface()
{
	local dev="$1"
	local cfg="$2"

	[ ! -e "$cfg" ] && return

	${CP} ${cfg} ${cfg}.$$ || \
		error "Can't copy file ${cfg}" $VZ_FS_NO_DISK_SPACE

	awk '
		NF == 0 {next}
		$1 == "auto" && $2 ~/'${dev}$'/ {next}
		$1 == "iface" && $2 ~/'${dev}$'/ {skip = 1; next}
		/^\t/ && skip {next}
		{skip = 0; print}
	' < ${cfg} > ${cfg}.$$ && mv -f ${cfg}.$$ ${cfg}

	rm -f ${cfg}.$$ 2>/dev/null
}

get_routed_default_dev()
{
	if [ -z "$1" ]; then
		dev=`grep -l $ROUTED_UUID ${IFCFG_DIR}/ifcfg-* | head -n1`
		[ -n "$dev" ] && echo "${dev##*-}"
	else
		awk '/'$ROUTED_UUID'/{print $2; exit}' $1
	fi
}

restore_debian_default_route()
{
	local proto=$1
	local cmd iproto
	local cfg=/etc/network/interfaces
	local dev=`get_routed_default_dev $cfg`

	[ -z "$dev" ] && return
	if [ "$proto" = "-6" ]; then
		iproto=inet6
		cmd="up ip -6 route add default dev $dev"
	else
		iproto=inet
		cmd="up ip route add default dev $dev"
	fi

	if grep -qe "$cmd" ${cfg}; then
		return 0
	fi

	${CP} ${cfg} ${cfg}.$$ || \
		error "Can't copy file ${cfg}" $VZ_FS_NO_DISK_SPACE

	awk '
		BEGIN {addgw = 0}
		NF == 0 {next}
		/^\t/ { print; next ;}
		addgw { print "\t'"$cmd"'"; addgw=0; print; next }
		$1 == "iface" && $2 == "'$dev'" && $3 == "'"$iproto"'" { addgw=1 }
		{print}
		END {
			if (addgw) {print "\t'"$cmd"'"}
		}
	' < ${cfg} > ${cfg}.$$ && mv -f ${cfg}.$$ ${cfg}

	ip $proto r r default dev venet0 2>/dev/null
	rm -f ${cfg}.$$
}

function add_debian_ip6()
{
	local ips=$1
	local cfg=/etc/network/interfaces
	local i c ip

	[ "${IPV6}" != "yes" ] && return
	[ -z "$ips" ] && return

	${CP} ${cfg} ${cfg}.$$ || \
		error "Can't copy file ${cfg}" $VZ_FS_NO_DISK_SPACE

	for ip in $ips; do
		if [ -z "$i" ]; then
			i="address $ip"
		else
			i="$i
	up ip addr add $ip dev venet0"
		fi
	done

	if ! grep -qe "auto ${VENET_DEV}" ${CFGFILE} 2>/dev/null; then
		c="auto ${VENET_DEV}"
	fi

	echo "$c
iface ${VENET_DEV} inet6 static
	${i}
	up ip -6 r a default dev ${VENET_DEV}" >> ${cfg}.$$ && mv -f ${cfg}.$$ ${cfg}
	rm -f ${cfg}.$$
}

function change_hostname()
{
	local cfg="$1"
	local host="$2"
	local ip="$3"
	local comm='# Auto-generated hostname. Please do not remove this comment.'

	[ -f "${cfg}" ] || touch ${cfg}
	if [ "${host}" = "localhost" -o "${host}" = "localhost.localdomain" ];
	then
		put_param2 ${cfg} "127.0.0.1" "localhost.localdomain localhost"
		return
	fi
	${CP} ${cfg} ${cfg}.$$ || \
		error "Can't copy file ${cfg}" $VZ_FS_NO_DISK_SPACE
	awk -v ip="${ip}" -v host="${host}" -v comm="${comm}" '
	BEGIN {found = 0; skip = 0}
	$0 == comm {found = 1; next}
	found {
		if (ip == "") {ip = $1}
		found = 0;
		next;
	}
	$0 ~ "\\<" host "\\>" {
		if (!skip) {
			skip = 1;
		} else {
			next;
		}
	}
	{print}
	END {
		if (skip) exit 0;
		if (ip == "") { ip ="127.0.0.1" }
		print comm;
		alias=""
		if ((i=index(host, ".")) > 1) {
			alias=substr(host, 1, i - 1);
		}
		print ip " " host " " alias;
	}
	' < ${cfg} > ${cfg}.$$
	if [ $? -ne 0 ]; then
		rm -f ${cfg}.$$ 2>/dev/null
		error "Can't change file ${cfg}" $VZ_FS_NO_DISK_SPACE
	fi
	mv -f ${cfg}.$$ ${cfg} || rm -f ${cfg}.$$
}

function is_ipv6()
{
	if [ "${1#*:}" != "${1}" ]; then
		return 0
	else
		return 1
	fi
}

function get_netmask()
{
	local dev=$1
	local ip=$2

	ip a l dev $dev 2>/dev/null | grep -e "inet[6]* ${ip}/" | sed -e 's/[^\/]*\/\([0-9]*\).*/\1/'
}

check_dhcp()
{
	for pkg in dhcpcd dhclient; do
		for p in /sbin /usr/sbin; do
			if [ -x $p/$pkg ]; then
				return
			fi
		done
	done
	echo "Warning: DHCP client daemon not found"
}

check_dhcp_ipv6()
{
	for p in /sbin /usr/sbin; do
		if [ -x $p/dhcp6c ]; then
			return
		fi
	done
	dhclient --help 2>&1 | grep -q -w -- -6 2>/dev/null
	if [ $? -eq 0 ]; then
		return
	fi
	echo "Warning: DHCP IPv6 client daemon not found"
}

is_default_route_configured()
{
	local dev=
	local proto=$2

	[ -n "$1" ] && dev="dev $1"
 
	if ip $proto l r $dev 2>/dev/null | grep -qe "^default"; then
		echo yes
		return 0
	else
		echo no
		return 1
	fi
}

cleanup_vzquota()
{
	rm -f ${SCRIPTNAME}
	rm -f /etc/mtab
	ln -sf /proc/mounts /etc/mtab
}

is_quota_support_ext4()
{
	grep -q usrquota /proc/mounts && return 0

	quotacheck -V | awk '/ version /{
	i=split($4, a, ".");
	if (i < 2) {
		print("Unable to detect quota version: "$0);
		exit 1;
	}
	if (a[1] >= 4) {
		exit 0;
	}
	if (a[1] < 3 || (a[1] == 3 && a[2] < 17)) {
		print "Old quota version detected " $0 " Quota should be > 3.16";
		exit 1;
	}
}'
}

setup_quota()
{
	[ -f "$SCRIPTNAME" ] && cleanup_vzquota

	if [ -z "$UGIDLIMIT" ]; then
		quotaoff -a
		rm -f /aquota.user /aquota.group 2>/dev/null
	elif [ ! -f "/aquota.user" -o ! -f "/aquota.group" ]; then
		is_quota_support_ext4 || exit 1
	fi
}

is_wicked()
{
	readlink ${WICKED} 2>/dev/null | grep wicked > /dev/null
	return $?
}

# Randomize systemd timers
randtimer()
{
	for t in man-db logrotate exim4-base; do
		f=/etc/systemd/system/$t.timer.d
		[ -e "$f/override.conf" ] && continue
		mkdir -p $f
		echo '[Timer]
RandomizedDelaySec=12h' > $f/override.conf
	done
}

# Functions for network managment by NetworkManager
mask2cidr()
{
	c=0 x=0$( printf '%o' ${1//./ } )
	while [ $x -gt 0 ]; do
		let c+=$((x%2)) 'x>>=1'
	done
	echo $c
}

is_nm_enabled()
{
	local status

	[ ! -e "$NWCONFDIR" ] || [ ! -f "$NWSYMLINK" ] && return 1

	status=$($SYSTEMCTL is-enabled NetworkManager 2>&1)
	[ "$status" != "enabled" ] && return 1

	return 0
}

nm_clean_ip_and_gw()
{
	local name=$1
	local proto=$2
	local uuid

	uuid=$(nmcli -g connection.uuid c s $name)

	nmcli c modify $name ipv${proto}.gateway ''
	nmcli c modify $name ipv${proto}.address '' ipv4.method link-local
	nmcli c modify $uuid ipv${proto}.gateway ''
	nmcli c up $uuid
}

get_ips()
{
	IP6=
	IP4=
	for ipm in $1; do
		ip=${ipm%%/*}
		mask=${ipm##*/}

		[ "$mask" = "$ipm" ] && mask=
		if is_ipv6 "$ip"; then
			[ -z "$mask" ] && mask=64
			IP6="$IP6 $ip/$mask"
		else
			if [ -z "$mask" ]; then
				mask=24
			else
				mask=`mask2cidr $mask`
			fi

			IP4="$IP4 $ip/$mask"
		fi
	done
}

nm_create_config()
{
	local dev=$1
	local id=$2
	local conf="$NWCONFDIR/$id"
	local ip4 ip6 gw i uuid

	[ "$NETWORK_TYPE" = "routed" ] && uuid=$ROUTED_UUID
	[ -z "$uuid" ] && uuid=$(cat /proc/sys/kernel/random/uuid)

	echo "[main]
no-auto-default+=$dev
plugins-=ifcfg-rh" > $NWSYSTEMDIR/conf.d/$id.conf
	chmod 600 $NWSYSTEMDIR/conf.d/$id.conf

	echo "[connection]
id=$id
uuid=$uuid
type=ethernet
interface-name=$dev" > $conf
	chmod 600 $conf

	get_ips "$IPADD"
	if [ -n "$IP4" ]; then
		echo '[ipv4]
method=manual' >> $conf
		i=1
		[ -n "$GW" ] && gw=",$GW"
		[ -z "$gw" ] && [ "$NETWORK_TYPE" = "routed" ] && gw=",$IP4_ROUTED_GW"
		for ip in $IP4; do
			echo "address$i=$ip$gw" >> $conf
			let i=i+1
			gw=
		done
	elif [ "$DHCP4" = "yes" ]; then
		echo '[ipv4]
method=auto' >> $conf
	else

		echo '[ipv4]
method=link-local' >> $conf
	fi

	if [ -n "$IP6" ]; then
		echo '[ipv6]
method=manual' >> $conf
		i=1
		for ip in $IP6; do
			echo "address$i=$ip" >> $conf
			let i=i+1
		done
	elif [ "$DHCP6" = "yes" ]; then
		echo '[ipv6]
method=auto' >> $conf
	else
		echo '[ipv6]
method=ignore' >> $conf
	fi
}


nm_set_ip()
{
	local name=$1
	local ip4 gw4 ip6 gw6

	gw4=$(nmcli -g ipv4.gateway c s $name | sed 's/[,\\]//g')
	gw6=$(nmcli -g ipv6.gateway c s $name | sed 's/[,\\]//g')

	if [ -n "$IPDEL" ]; then
		ips=$(nmcli -g ipv4.addresses c s $name | sed 's/[,\\]//g')
		for ipm in $ips; do
			for ipd in $IPDEL; do
				[ "$ipd" = "all" ] && break
				ip=${ipd%%/*}
				if ! echo $ipm | grep -qw $ip; then
					ip4="$ip4 $ipm"
				fi
			done
		done

		ips=$(nmcli -g ipv6.addresses c s $name | sed 's/[,\\]//g')
		for ipm in $ips; do
			for ipd in $IPDEL; do
				[ "$ipd" = "all" ] && break
				ip=${ipd%%/*}
				if ! echo $ipm | grep -qw $ip; then
					ip6="$ip6 $ipm"
				fi
			done
		done
		nmcli c modify $name ipv4.gateway ''
		nmcli c modify $name ipv4.address '' ipv4.method link-local
		nmcli c modify $name ipv6.gateway ''
		nmcli c modify $name ipv6.address '' ipv6.method link-local
	fi

	#add ips
	get_ips "$IPADD"
	ip4="$ip4 $IP4"
	for ipm in $ip4; do
		nmcli c modify $name +ipv4.address $ipm ipv4.method manual || exit
	done

	if [ "$NETWORK_TYPE" = "routed" ]; then
		if [ -z "$gw4" ]; then
			gw4=$IP4_ROUTED_GW
		fi
	fi

	[ -n "$gw4" ] && nmcli c modify $name ipv4.gateway $gw4

	ip6="$ip6 $IP6"
	for ipm in $ip6; do
		nmcli c modify $name +ipv6.address $ipm ipv6.method manual || exit $?
	done
	[ -n "$gw6" ] && nmcli c modify $name ipv6.gateway $gw6
}

nm_set_dhcp()
{
	local name=$1
	local method

	for p in 4 6; do
		dhcp=DHCP$p
		[ "${!dhcp}" != "yes" ] && continue

		nm_clean_ip_and_gw $name $p
		nmcli c modify $name ipv${p}.method auto
		if [ $? -ne 0 ]; then
			nmcli c modify $name ipv${p}.method link-local || exit $?
		fi
	done
}

nm_set_gw()
{
	local name=$1
	local uuid

	uuid=$(nmcli -g connection.uuid c s $name)

	if [ -n "$GWDEL" ]; then
		nmcli c modify $name ipv4.gateway ''
		nmcli c modify $uuid ipv4.gateway $IP4_ROUTED_GW
		nmcli c up $uuid
	fi

	if [ -n "$GW" ]; then
		nmcli c modify $name ipv4.gateway ''
		nmcli c modify $uuid ipv4.gateway $GW
		nmcli c up $uuid
	fi

	[ -n "$GW6DEL" ] && nmcli c modify $name ipv6.gateway ''
	[ -n "$GW6" ] && nmcli c modify $name ipv6.gateway $GW6
}

nm_cfg_fixup()
{
	local status
	local retry
	local cfg_name="NetworkManager/conf.d/10-globally-managed-devices.conf"

	[ ! -f /usr/lib/$cfg_name ] && return
	[ -f /etc/$cfg_name ] && return

	# We must shadow the NM config file from path /usr/lib/...
	echo "[keyfile]" > /etc/$cfg_name

	status=$($SYSTEMCTL is-active NetworkManager 2>&1)
	[ "$status" != "active" ] && return

	$SYSTEMCTL restart NetworkManager 2>&1

	retry=0
	while ! $SYSTEMCTL is-active -q NetworkManager 2>&1 && [[ $retry < 3 ]]; do
		sleep 1
		((retry=$retry+1))
	done
}

nm_setup()
{
	local dev=$1
	local id=vz-$dev

	nm_cfg_fixup

	if [ "$VE_STATE" = "starting" ]; then
		nm_create_config $dev $id
	else
		nmcli -g connection.uuid c s $id >/dev/null 2>&1
		if [ $? -ne 0 ]; then
			nmcli con add con-name $id ifname $dev type ethernet || exit $?
		fi
		nm_set_ip $id
		nm_set_dhcp $id
		nm_set_gw $id

		nmcli c up $id
	fi
}

nm_delete()
{
	local dev=$1
	local id=vz-$dev

	if [ "$VE_STATE" != "starting" ]; then
		nm_cfg_fixup
		nmcli connection delete $id >/dev/null 2>&1
	fi

	rm -f $NWCONFDIR/$id*
	rm -f $NWSYSTEMDIR/conf.d/$id*
}

nm_set_hostname()
{
	local hname=$1

	if [ "$VE_STATE" != "starting" ]; then
		nm_cfg_fixup
		nmcli general hostname $hname >/dev/null 2>&1
	fi
}
