#!/bin/sh
#
# Copyright (c) 2022-2023, Jesús Daniel Colmenares Oviedo <DtxdF@disroot.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
#   list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
#   this list of conditions and the following disclaimer in the documentation
#   and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
#   contributors may be used to endorse or promote products derived from
#   this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

lib_load "${LIBDIR}/check_func"
lib_load "${LIBDIR}/copy"
lib_load "${LIBDIR}/kern_modules"
lib_load "${LIBDIR}/keys"
lib_load "${LIBDIR}/jail"
lib_load "${LIBDIR}/random"
lib_load "${LIBDIR}/replace"
lib_load "${LIBDIR}/tempfile"

# Allows to use the default values in the *_run functions.
QUICK_DEFAULT_SUBGROUP="<default>"

# Types & Default interface types used by the `bridge` option.
QUICK_IFACE_TYPE_EPAIR="epair"
QUICK_IFACE_TYPE_IFACE="iface"
QUICK_DEFAULT_IFACE_TYPE="${QUICK_IFACE_TYPE_EPAIR}"

# See `quick_set_jng`
QUICK_REGEX_JNG="^[a-zA-Z_]+[a-zA-Z0-9_]*$"
QUICK_REGEX_JNG_NAME="^[0-9a-zA-Z_]+$"

# Temp dir
QUICK_TEMPDIR=

# Misc
QUICK_ESCAPE_TEMPLATE=3
QUICK_IFNAMSIZ=15
QUICK_USE_AJNET=0

# Directories
QUICK_KEY_BRIDGE="bridge"
QUICK_KEY_DEVICE="device"
QUICK_KEY_DHCP="dhcp"
QUICK_KEY_ETHER="ether"
QUICK_KEY_EXPOSE="expose"
QUICK_KEY_FSTAB="fstab"
QUICK_KEY_HEALTH="healthcheck"
QUICK_KEY_IP4="ip4"
QUICK_KEY_IP6="ip6"
QUICK_KEY_JNG="jng"
QUICK_KEY_LABELS="labels"
QUICK_KEY_LIMITS="limits"
QUICK_KEY_NAT="nat"
QUICK_KEY_NETWORK="network"
QUICK_KEY_NONAT="nonat"
QUICK_KEY_SLAAC="slaac"
QUICK_KEY_VIRTUALNET="virtualnet"
QUICK_KEY_VOLUME="volume"

# Fstab constants
QUICK_FSTAB_OPTION_DEVICE=1
QUICK_FSTAB_OPTION_MOUNTPOINT=2
QUICK_FSTAB_OPTION_TYPE=3
QUICK_FSTAB_OPTION_OPTIONS=4
QUICK_FSTAB_OPTION_DUMP=5
QUICK_FSTAB_OPTION_PASS=6

# Jail name
QUICK_JAILNAME=
# Temp template
QUICK_TEMP_TEMPLATE=
# Jail path
QUICK_JAILPATH=
# Options
QUICK_OPTION_ALIAS=0
QUICK_OPTION_ALIAS_IFACE=
QUICK_OPTION_BOOT="${DEFAULT_BOOT}"
QUICK_OPTION_BRIDGE=0
QUICK_OPTION_CLONE_JAIL=0
QUICK_OPTION_CLONE_RELEASE=0
QUICK_OPTION_COPY=0
QUICK_OPTION_COPYDIR="${DEFAULT_COPYDIR}"
QUICK_OPTION_CPUSET=
QUICK_OPTION_CREATE_ARGS=
QUICK_OPTION_DEFNET=
QUICK_OPTION_DEVFS_RULESET=
QUICK_OPTION_DEVICE=0
QUICK_OPTION_DHCP=0
QUICK_OPTION_EMPTY=0
QUICK_OPTION_EXPOSE=0
QUICK_OPTION_FILE=
QUICK_OPTION_FILES=
QUICK_OPTION_FSTAB=0
QUICK_OPTION_HEALTH=0
QUICK_OPTION_IMPORT_JAIL=0
QUICK_OPTION_IMPORT_ROOT=0
QUICK_OPTION_INITSCRIPT=
QUICK_OPTION_INSTALL_METHOD="${DEFAULT_INSTALL_METHOD}"
QUICK_OPTION_IP4=0
QUICK_OPTION_IP4_DISABLE=0
QUICK_OPTION_IP4_INHERIT=0
QUICK_OPTION_IP6=0
QUICK_OPTION_IP6_DISABLE=0
QUICK_OPTION_IP6_INHERIT=0
QUICK_OPTION_JAILTYPE="${JAIL_TYPE_THIN}"
QUICK_OPTION_JNG=0
QUICK_OPTION_LABEL=0
QUICK_OPTION_LINUXFS=0
QUICK_OPTION_LOGIN="${DEFAULT_LOGIN}"
QUICK_OPTION_LOGIN_USER="${DEFAULT_LOGIN_USER}"
QUICK_OPTION_MACADDR=0
QUICK_OPTION_MOUNT_DEVFS="${DEFAULT_MOUNT_DEVFS}"
QUICK_OPTION_NAT=0
QUICK_OPTION_NETWORK=0
QUICK_OPTION_NONAT=0
QUICK_OPTION_OSARCH="${FREEBSD_ARCH}"
QUICK_OPTION_OSVERSION="${FREEBSD_VERSION}"
QUICK_OPTION_OVERWRITE="${DEFAULT_OVERWRITE}"
QUICK_OPTION_PKG="${DEFAULT_PACKAGES}"
QUICK_OPTION_PRIORITY="${DEFAULT_PRIORITY}"
QUICK_OPTION_RELEASE="${DEFAULT_RELEASE}"
QUICK_OPTION_RESTART="${DEFAULT_RESTART}"
QUICK_OPTION_RUN="${DEFAULT_RUN}"
QUICK_OPTION_RUN_ARGS=
QUICK_OPTION_RUN_ENV=
QUICK_OPTION_SLAAC=0
QUICK_OPTION_START="${DEFAULT_START}"
QUICK_OPTION_START_ARGS=
QUICK_OPTION_START_ENV=
QUICK_OPTION_STOP_ARGS=
QUICK_OPTION_STOP_ENV=
QUICK_OPTION_TEMPLATE="${DEFAULT_TEMPLATE}"
QUICK_OPTION_TINY_IMPORT=0
QUICK_OPTION_TMPDIR=0
QUICK_OPTION_USE_LIMITS=0
QUICK_OPTION_USE_RESOLV_CONF="${USE_RESOLV_CONF}"; QUICK_OPTION_RESOLV_CONF="${DEFAULT_RESOLV_CONF}"
QUICK_OPTION_USE_TZDATA="${USE_TIMEZONE}"; QUICK_OPTION_TZDATA="${DEFAULT_TIMEZONE}"
QUICK_OPTION_VIRTUALNET=0
QUICK_OPTION_VNET=0
QUICK_OPTION_VNET_INTERFACES=
QUICK_OPTION_VOLUME=0
QUICK_OPTION_X11=0
QUICK_OPTION_ZFS_IMPORT_JAIL=0
QUICK_OPTION_ZFS_IMPORT_ROOT=0

quick_desc="Create a pre-configured jail."

quick_main()
{
	if ! which -s "appjail"; then
		lib_err ${EX_UNAVAILABLE} "appjail is not installed. Cannot continue ..."
	fi

	QUICK_JAILNAME="$1"; shift
	if lib_check_empty "${QUICK_JAILNAME}"; then
		quick_usage
		exit ${EX_USAGE}
	fi

	# Jail path
	QUICK_JAILPATH="${JAILDIR}/${QUICK_JAILNAME}"

	# Random color name
	lib_set_logprefix " [`random_color`${QUICK_JAILNAME}${COLOR_DEFAULT}]"

	# Useful for debugging
	lib_debug "quick parameters: $@"

	# Tempdir
	QUICK_TEMPDIR=`lib_generate_tempdir` || exit $?

	local escape_tempdir
	escape_tempdir=`lib_escape_string "${QUICK_TEMPDIR}"`

	lib_atexit_add "rm -rf \"${escape_tempdir}\" > /dev/null 2>&1"
	
	local option value
	for option in "$@"; do
		value=`lib_jailparam_value "${option}" =`
		option=`lib_jailparam_name "${option}" =`

		case "${option}" in
			alias|boot|bridge|clone+jail|clone+release|copy|copydir|cpuset|create_args|devfs_ruleset|device|dhcp|empty|expose|file|files|fstab|healthcheck|import+jail|import+root|initscript|ip4|ip4_disable|ip4_inherit|ip6|ip6_disable|ip6_inherit|jng|label|limits|linuxfs|login|login_user|macaddr|mount_devfs|nat|network|noboot|nomount_devfs|nonat|nologin|nooverwrite|noresolv_conf|norestart|norun|nostart|notzdata|osarch|osversion|overwrite|pkg|priority|release|resolv_conf|restart|run|run_args|run_env|slaac|start|start_args|start_env|stop_args|stop_env|template|tiny+import|tmpdir|type|tzdata|virtualnet|vnet|volume|x11|zfs+import+jail|zfs+import+root) quick_set_${option} "${value}" ;;
			*) lib_err ${EX_NOINPUT} -- "${option}: option not found." ;;
		esac
	done

	# temp. template
	quick_temp_template

	# create jail
	quick_create_jail

	local label_options
	label_options="label"

	local file_options
	file_options="copy tzdata resolv_conf"

	local vnet_options
	vnet_options="vnet"

	local bridge_options
	bridge_options="bridge"

	local alias_options
	alias_options="alias"
	
	local jng_options
	jng_options="jng"

	local network_options
	network_options="network"

	local virtualnet_options
	virtualnet_options="virtualnet"

	local interface_options
	interface_options="macaddr"

	local autoconf_options
	autoconf_options="dhcp slaac"

	local nat_options
	nat_options="nat nonat expose"

	local network_options
	network_options="${vnet_options} ${bridge_options} ${alias_options} ${network_options} ${virtualnet_options} ${interface_options} ${jng_options} ${autoconf_options} ${nat_options}"

	local limits_options
	limits_options="cpuset limits"

	local device_options
	device_options="devfs device volume fstab tmpdir linuxfs x11"

	local startup_options
	startup_options="boot priority"

	local health_options
	health_options="healthcheck"

	local args_options
	args_options="start_env run_env stop_env create_args start_args run_args stop_args"

	local all_options
	all_options="${label_options} ${file_options} ${network_options} ${limits_options} ${device_options} ${startup_options} ${health_options} ${args_options}"

	for option in ${all_options}; do
		quick_run_${option}
	done

	# write template
	quick_write_template

	# start must be executed after the template is written
	quick_run_start

	# Options that are executed after starting the jail.

	local other_options
	other_options="pkg"

	for option in ${other_options}; do
		quick_run_${option}
	done
	
	# end
	quick_end_jail
}

quick_temp_template()
{
	if [ ! -f "${QUICK_OPTION_TEMPLATE}" ]; then
		lib_err ${EX_NOINPUT} "Cannot find the template \`${QUICK_OPTION_TEMPLATE}\`."
	fi

	QUICK_TEMP_TEMPLATE="`lib_generate_tempfile`" || exit $?

	local escape_temp_template
	escape_temp_template=`lib_escape_string "${QUICK_TEMP_TEMPLATE}"`

	lib_atexit_add "rm -f \"${escape_temp_template}\""

	if ! cat -- "${QUICK_OPTION_TEMPLATE}" > "${QUICK_TEMP_TEMPLATE}"; then
		lib_err ${EX_IOERR} "Error writing ${QUICK_OPTION_TEMPLATE} to ${QUICK_TEMP_TEMPLATE}"
	fi

	local errlevel

	local ajconf_out
	ajconf_out=`lib_ajconf check -t "${QUICK_TEMP_TEMPLATE}" 2>&1`

	errlevel=$?

	if [ ${errlevel} -ne 0 ]; then
		lib_err ${errlevel} "appjail-config: ${ajconf_out}"
	fi
}

quick_create_jail()
{
	if [ -d "${JAILDIR}/${QUICK_JAILNAME}" ]; then
		if [ "${QUICK_OPTION_OVERWRITE}" != 0 ]; then
			lib_warn "Trying to remove ${QUICK_JAILNAME} ..."

			appjail stop -- "${QUICK_JAILNAME}" || exit $?

			local destroy_flags=
			case "${QUICK_OPTION_OVERWRITE}" in
				force) destroy_flags="-f" ;;
				recursive) destroy_flags="-R" ;;
				force+recursive) destroy_flags="-fR" ;;
				*) QUICK_OPTION_OVERWRITE=; destroy_flags= ;;
			esac

			lib_debug "Destroy flags: <${QUICK_OPTION_OVERWRITE}>"

			appjail jail destroy ${destroy_flags} -- "${QUICK_JAILNAME}" || exit $?
		else
			lib_err ${EX_CANTCREAT} -- "Jail already created."
		fi
	fi

	local escape_osarch=`lib_escape_string "${QUICK_OPTION_OSARCH}"`
	local escape_install_method=`lib_escape_string "${QUICK_OPTION_INSTALL_METHOD}"`
	local escape_release=`lib_escape_string "${QUICK_OPTION_RELEASE}"`
	local escape_jail_type=`lib_escape_string "${QUICK_OPTION_JAILTYPE}"`
	local escape_osversion=`lib_escape_string "${QUICK_OPTION_OSVERSION}"`
	# This is not necessary after running `appjail jail create` because
	# the jail name is already checked.
	local escape_jail_name=`lib_escape_string "${QUICK_JAILNAME}"`

	local appjail_cmd="appjail jail create"
	appjail_cmd="${appjail_cmd} -a \"${escape_osarch}\" -I \"${escape_install_method}\" -r \"${escape_release}\" -T \"${escape_jail_type}\" -v \"${escape_osversion}\""

	if [ -n "${QUICK_OPTION_INITSCRIPT}" ]; then
		local escape_initscript=`lib_escape_string "${QUICK_OPTION_INITSCRIPT}"`

		appjail_cmd="${appjail_cmd} -i \"${escape_initscript}\""
	fi

	appjail_cmd="${appjail_cmd} -- \"${escape_jail_name}\""

	if ! sh -c "${appjail_cmd}"; then
		appjail jail mark dirty "${QUICK_JAILNAME}" > /dev/null 2>&1

		lib_err ${EX_CANTCREAT} "Error creating ${QUICK_JAILNAME} jail."
	fi

	lib_atexit_add "appjail jail mark dirty \"${QUICK_JAILNAME}\" > /dev/null 2>&1"
}

quick_write_template()
{
	local jail_template
	jail_template="${QUICK_JAILPATH}/conf/template.conf"
	if ! cat -- "${QUICK_TEMP_TEMPLATE}" > "${jail_template}"; then
		lib_err ${EX_IOERR} "Error writing ${QUICK_TEMP_TEMPLATE} to ${jail_template}"
	fi

	lib_debug "Template generated:"
	lib_debug_read "${jail_template}"
}

quick_end_jail()
{
	# Clean up
	lib_atexit_add "appjail jail mark clean \"${QUICK_JAILNAME}\" > /dev/null 2>&1"
	appjail jail mark clean "${QUICK_JAILNAME}" > /dev/null 2>&1

	lib_debug "Done."
}

quick_run_label()
{
	if [ ${QUICK_OPTION_LABEL} -eq 0 ]; then
		return 0
	fi

	lib_keys_list "${QUICK_KEY_LABELS}" | while IFS= read -r label; do
		value=`lib_keys_get "${QUICK_KEY_LABELS}" "${label}" "value"`

		lib_debug "Adding label ${label}=${value} ..."

		appjail label add "${QUICK_JAILNAME}" "${label}" "${value}" || exit $?
	done || exit $?
}

quick_set_label()
{
	local label

	label="$1"

	quick_reqoption "label" "${label}"

	local key value

	key=`lib_jailparam_name "${label}" :`

	if ! lib_check_labelname "${key}"; then
		lib_err ${EX_DATAERR} "Invalid label name '${key}'"
	fi

	value=`lib_jailparam_value "${label}" :`

	if lib_check_empty "${value}"; then
		lib_err ${EX_DATAERR} "label syntax: key:value"
	fi

	lib_keys_set "${QUICK_KEY_LABELS}" "${key}" "value" "${value}"

	QUICK_OPTION_LABEL=1
}

quick_run_vnet()
{
	if [ ${QUICK_OPTION_VNET} -eq 0 ]; then
		return 0
	fi

	lib_ajconf set -t "${QUICK_TEMP_TEMPLATE}" vnet

	local interface
	for interface in ${QUICK_OPTION_VNET_INTERFACES}; do
		lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" vnet.interface="\"${interface}\""
	done
}

quick_set_vnet()
{
	if [ ${QUICK_OPTION_ALIAS} -eq 1 ]; then
		quick_exclusive "vnet" "alias"
	fi

	quick_vimage

	local interface
	interface="$1"; quick_reqoption "vnet" "${interface}"

	quick_iface "${interface}"

	QUICK_OPTION_VNET_INTERFACES="${QUICK_OPTION_VNET_INTERFACES} ${interface}"

	QUICK_OPTION_VNET=1
}

quick_run_nat()
{
	local errlevel

	if [ ${QUICK_OPTION_NAT} -eq 0 ]; then
		return 0
	fi

	if [ ${QUICK_OPTION_VIRTUALNET} -eq 0 ]; then
		quick_reqoptions "nat" "virtualnet"
	fi

	lib_debug "Creating NAT rules ..."

	lib_keys_list "${QUICK_KEY_NAT}" | while IFS= read -r network
	do
		if [ "${network}" = "${QUICK_DEFAULT_SUBGROUP}" ]; then
			real_network="${QUICK_OPTION_DEFNET}"

			if lib_check_empty "${real_network}"; then
				lib_err ${EX_CONFIG} "This NAT rule cannot be configured because the default network is not defined."
			fi
		else
			real_network="${network}"

			if ! lib_keys_check "${QUICK_KEY_VIRTUALNET}" "${real_network}"; then
				lib_err ${EX_NOINPUT} -- "${real_network}: unknown virtual network."
			fi
		fi

		# head
		nat_add_cmd="appjail nat add jail -n \"${real_network}\""

		# ext_if
		ext_if=`lib_keys_get "${QUICK_KEY_NAT}" "${network}" "ext_if"`
		nat_add_cmd="${nat_add_cmd} -e \"${ext_if}\""

		# logopts
		use_logopts=`lib_keys_get "${QUICK_KEY_NAT}" "${network}" "use_logopts"`
		if [ ${use_logopts} -eq 1 ]; then
			logopts=`lib_keys_get "${QUICK_KEY_NAT}" "${network}" "logopts"`

			if [ -z "${logopts}" ]; then
				logopts="-"
			fi

			escape_logopts=`lib_escape_string "${logopts}"`

			nat_add_cmd="${nat_add_cmd} -l \"${escape_logopts}\""
		fi

		# on_if
		on_if=`lib_keys_get "${QUICK_KEY_NAT}" "${network}" "on_if"`
		nat_add_cmd="${nat_add_cmd} -o \"${on_if}\""

		# tail
		nat_add_cmd="${nat_add_cmd} -- \"${QUICK_JAILNAME}\""

		# debugging
		lib_debug "Setting NAT rule: network:${real_network} ext_if:${ext_if} logopts:${use_logopts} (${logopts}) on_if:${on_if}"

		# profit!
		sh -c "${nat_add_cmd}" || exit $?
	done

	errlevel=$?
	if [ ${errlevel} -ne 0 ]; then
		exit ${errlevel}
	fi

	lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" exec.prestart='"appjail nat on jail \"${name}\""'
	lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" exec.poststop='"appjail nat off jail \"${name}\""'
}

quick_set_nat()
{
	local params
	local total_items=0 current_index=0

	params="$1"
	if ! lib_check_empty "${params}"; then
		params=`lib_split_jailparams "${params}"` || exit $?
		total_items=`printf "%s\n" "${params}" | wc -l`
	fi

	local network_name=
	local ext_if=
	local use_logopts=0 logopts=
	local on_if=

	local arg parameter value
	while [ ${current_index} -lt ${total_items} ]; do 
		current_index=$((current_index+1))

		arg=`printf "%s\n" "${params}" | head -${current_index} | tail -n 1`
		if lib_check_empty "${arg}"; then
			continue
		fi

		parameter=`lib_jailparam_name "${arg}" :`
		value=`lib_jailparam_value "${arg}" :`

		case "${parameter}" in
			ext_if)
				ext_if="${value}"
				;;
			logopts)
				use_logopts=1
				logopts="${value}"
				;;
			network)
				network_name="${value}"
				;;
			on_if)
				on_if="${value}"
				;;
			*)
				lib_err ${EX_DATAERR} -- "${parameter} (nat): parameter not found."
				;;
		esac
	done

	if lib_check_empty "${network_name}"; then
		network_name="${QUICK_DEFAULT_SUBGROUP}"
	else
		if lib_check_ifacelen "${network_name}"; then
			lib_err ${EX_DATAERR} -- "${network_name}: network name too long."
		fi

		if ! lib_check_networkname "${network_name}"; then
			lib_err ${EX_DATAERR} -- "${network_name}: invalid network name."
		fi
	fi

	if lib_check_empty "${ext_if}"; then
		ext_if="${EXT_IF}"
	else
		quick_iface "${ext_if}"
	fi

	if lib_check_empty "${on_if}"; then
		on_if="${ON_IF}"
	else
		quick_iface "${on_if}"
	fi

	lib_keys_set "${QUICK_KEY_NAT}" "${network_name}" "ext_if" "${ext_if}"
	lib_keys_set "${QUICK_KEY_NAT}" "${network_name}" "use_logopts" "${use_logopts}"
	lib_keys_set "${QUICK_KEY_NAT}" "${network_name}" "logopts" "${logopts}"
	lib_keys_set "${QUICK_KEY_NAT}" "${network_name}" "on_if" "${on_if}"

	QUICK_OPTION_NAT=1
}

quick_run_network()
{
	local errlevel

	if [ ${QUICK_OPTION_NETWORK} -eq 0 ]; then
		return 0
	fi

	lib_keys_list "${QUICK_KEY_NETWORK}" | while IFS= read -r network
	do
		network_add_cmd="appjail network add"

		name=`lib_keys_get "${QUICK_KEY_NETWORK}" "${network}" "name"`
		escape_name=`lib_escape_string "${name}"`

		address=`lib_keys_get "${QUICK_KEY_NETWORK}" "${network}" "address"`
		escape_address=`lib_escape_string "${address}"`

		descr=`lib_keys_get "${QUICK_KEY_NETWORK}" "${network}" "descr"`
		if ! lib_check_empty "${descr}"; then
			escape_descr=`lib_escape_string "${descr}"`
			network_add_cmd="${network_add_cmd} -d \"${descr}\""
		fi

		lib_debug "Creating network name:${name} address:${address} descr:${descr} ..."

		sh -c "${network_add_cmd} -- \"${escape_name}\" \"${escape_address}\"" || exit $?
	done

	errlevel=$?
	if [ ${errlevel} -ne 0 ]; then
		exit ${errlevel}
	fi
}

quick_set_network()
{
	local params

	params="$1"
	if lib_check_empty "${params}"; then
		lib_err ${EX_DATAERR} "network syntax: name address [description]"
	fi

	params=`lib_split_jailparams "${params}"` || exit $?
	local total_items=`printf "%s\n" "${params}" | wc -l`

	local name=`printf "%s\n" "${params}" | head -1 | tail -n 1`
	local address=`printf "%s\n\n" "${params}" | head -2 | tail -n 1`
	local description=`printf "%s\n\n\n" "${params}" | head -3 | tail -n 1`

	if lib_check_empty "${name}" || lib_check_empty "${address}"; then
		quick_set_network # usage
	fi

	if [ -d "${NETWORKDIR}/${name}" ]; then
		lib_debug "Virtual network \`${name}\` is already created. Ignoring ..."
		return 0
	fi

	local nro

	lib_keys_mk "${QUICK_KEY_NETWORK}"
	nro=`lib_keys_append "${QUICK_KEY_NETWORK}" "name" "${name}"`
	lib_keys_set "${QUICK_KEY_NETWORK}" "${nro}" "address" "${address}"
	lib_keys_set "${QUICK_KEY_NETWORK}" "${nro}" "descr" "${description}"

	QUICK_OPTION_NETWORK=1
}

quick_run_nonat()
{
	local errlevel

	if [ ${QUICK_OPTION_NONAT} -eq 0 ]; then
		return 0
	fi

	if [ ${QUICK_OPTION_VIRTUALNET} -eq 0 ]; then
		quick_reqoptions "nonat" "virtualnet"
	fi

	lib_debug "Creating NONAT rules ..."

	lib_keys_list "${QUICK_KEY_NONAT}" | while IFS= read -r network
	do
		if [ "${network}" = "${QUICK_DEFAULT_SUBGROUP}" ]; then
			real_network="${QUICK_OPTION_DEFNET}"

			if lib_check_empty "${real_network}"; then
				lib_err ${EX_CONFIG} "This NONAT rule cannot be configured because the default network is not defined."
			fi
		else
			real_network="${network}"

			if ! lib_keys_check "${QUICK_KEY_VIRTUALNET}" "${real_network}"; then
				lib_err ${EX_NOINPUT} -- "${real_network}: unknown virtual network."
			fi
		fi

		# head
		nonat_add_cmd="appjail nat add jail -N -n \"${real_network}\""

		# ext_if
		ext_if=`lib_keys_get "${QUICK_KEY_NONAT}" "${network}" "ext_if"`
		nonat_add_cmd="${nonat_add_cmd} -e \"${ext_if}\""

		# on_if
		on_if=`lib_keys_get "${QUICK_KEY_NONAT}" "${network}" "on_if"`
		nonat_add_cmd="${nonat_add_cmd} -o \"${on_if}\""

		# tail
		nonat_add_cmd="${nonat_add_cmd} -- \"${QUICK_JAILNAME}\""

		# debugging
		lib_debug "Setting NONAT rule: network:${real_network} ext_if:${ext_if} on_if:${on_if}"

		# profit!
		sh -c "${nonat_add_cmd}" || exit $?
	done

	errlevel=$?
	if [ ${errlevel} -ne 0 ]; then
		exit ${errlevel}
	fi

	lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" exec.prestart='"appjail nat on jail \"${name}\""'
	lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" exec.poststop='"appjail nat off jail \"${name}\""'
}

quick_set_nonat()
{
	local params
	local total_items=0 current_index=0

	params="$1"
	if ! lib_check_empty "${params}"; then
		params=`lib_split_jailparams "${params}"` || exit $?
		total_items=`printf "%s\n" "${params}" | wc -l`
	fi

	local network_name=
	local ext_if=
	local on_if=

	local arg parameter value
	while [ ${current_index} -lt ${total_items} ]; do 
		current_index=$((current_index+1))

		arg=`printf "%s\n" "${params}" | head -${current_index} | tail -n 1`
		if lib_check_empty "${arg}"; then
			continue
		fi

		parameter=`lib_jailparam_name "${arg}" :`
		value=`lib_jailparam_value "${arg}" :`

		case "${parameter}" in
			ext_if)
				ext_if="${value}"
				;;
			network)
				network_name="${value}"
				;;
			on_if)
				on_if="${value}"
				;;
			*)
				lib_err ${EX_DATAERR} -- "${parameter} (nonat): parameter not found."
				;;
		esac
	done

	if lib_check_empty "${network_name}"; then
		network_name="${QUICK_DEFAULT_SUBGROUP}"
	else
		if lib_check_ifacelen "${network_name}"; then
			lib_err ${EX_DATAERR} -- "${network_name}: network name too long."
		fi

		if ! lib_check_networkname "${network_name}"; then
			lib_err ${EX_DATAERR} -- "${network_name}: invalid network name."
		fi
	fi

	if lib_check_empty "${ext_if}"; then
		ext_if="${EXT_IF}"
	else
		quick_iface "${ext_if}"
	fi

	if lib_check_empty "${on_if}"; then
		on_if="${ON_IF}"
	else
		quick_iface "${on_if}"
	fi

	lib_keys_set "${QUICK_KEY_NONAT}" "${network_name}" "ext_if" "${ext_if}"
	lib_keys_set "${QUICK_KEY_NONAT}" "${network_name}" "on_if" "${on_if}"

	QUICK_OPTION_NONAT=1
}

quick_run_expose()
{
	local errlevel

	if [ ${QUICK_OPTION_EXPOSE} -eq 0 ]; then
		return 0
	fi

	if [ ${QUICK_OPTION_VIRTUALNET} -eq 0 ]; then
		quick_reqoptions "expose" "virtualnet"
	fi

	lib_keys_list "${QUICK_KEY_EXPOSE}" | while IFS= read -r nro
	do
		network=`lib_keys_get "${QUICK_KEY_EXPOSE}" "${nro}" "network"`

		if [ "${network}" = "${QUICK_DEFAULT_SUBGROUP}" ]; then
			network="${QUICK_OPTION_DEFNET}"

			if lib_check_empty "${network}"; then
				lib_err ${EX_CONFIG} "This expose rule cannot be configured because the default network is not defined."
			fi
		else
			if ! lib_keys_check "${QUICK_KEY_VIRTUALNET}" "${network}"; then
				lib_err ${EX_NOINPUT} -- "${network}: unknown virtual network."
			fi
		fi

		expose_set_cmd="appjail expose set -k \"${network}\""

		# ext_if
		ext_if=`lib_keys_get "${QUICK_KEY_EXPOSE}" "${nro}" "ext_if"`
		expose_set_cmd="${expose_set_cmd} -i \"${ext_if}\""

		# logopts
		use_logopts=`lib_keys_get "${QUICK_KEY_EXPOSE}" "${nro}" "use_logopts"`
		if [ ${use_logopts} -eq 1 ]; then
			logopts=`lib_keys_get "${QUICK_KEY_EXPOSE}" "${nro}" "logopts"`

			if [ -z "${logopts}" ]; then
				logopts="-"
			fi

			escape_logopts=`lib_escape_string "${logopts}"`
			expose_set_cmd="${expose_set_cmd} -l \"${escape_logopts}\""
		fi

		# proto
		proto=`lib_keys_get "${QUICK_KEY_EXPOSE}" "${nro}" "proto"`
		if [ "${proto}" = "tcp" ]; then
			expose_set_cmd="${expose_set_cmd} -t"
		else
			expose_set_cmd="${expose_set_cmd} -u"
		fi
	
		# port
		port=`lib_keys_get "${QUICK_KEY_EXPOSE}" "${nro}" "port"`
		escape_port=`lib_escape_string "${port}"`
		expose_set_cmd="${expose_set_cmd} -p \"${escape_port}\""

		# on_if
		on_if=`lib_keys_get "${QUICK_KEY_EXPOSE}" "${nro}" "on_if"`
		expose_set_cmd="${expose_set_cmd} -o \"${on_if}\""

		# description
		description=`lib_keys_get "${QUICK_KEY_EXPOSE}" "${nro}" "description"`
		if ! lib_check_empty "${description}"; then
			escape_description=`lib_escape_string "${description}"`

			expose_set_cmd="${expose_set_cmd} -N \"${escape_description}\""
		fi

		# debugging
		lib_debug "Setting expose rule#${nro}: network:${network} port:${port}/${proto} ext_if:${ext_if} logopts:${use_logopts} (${logopts}) on_if:${on_if} descr:${description}"

		# tail
		expose_set_cmd="${expose_set_cmd} -- \"${QUICK_JAILNAME}\""

		# profit!
		sh -c "${expose_set_cmd}" || exit $?
	done

	errlevel=$?
	if [ ${errlevel} -ne 0 ]; then
		exit ${errlevel}
	fi

	lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" exec.prestart='"appjail expose on \"${name}\""'
	lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" exec.poststop='"appjail expose off \"${name}\""'
}

quick_set_expose()
{
	local params

	params="$1"
	if lib_check_empty "${params}"; then
		lib_err ${EX_DATAERR} "expose syntax: hport[:jport] [descr:description] [ext_if:external_interface] [logopts:firewall_logopts] [network:network_name] [on_if:interface] [proto:protocol]"
	fi

	local params
	local total_items
	local current_index=0

	params=`lib_split_jailparams "${params}"` || exit $?
	total_items=`printf "%s\n" "${params}" | wc -l`

	local port=
	local description=
	local ext_if=
	local use_logopts=0 logopts=
	local proto=
	local network_name=
	local on_if=

	local arg parameter value
	while [ ${current_index} -lt ${total_items} ]; do 
		current_index=$((current_index+1))

		arg=`printf "%s\n" "${params}" | head -${current_index} | tail -n 1`
		if lib_check_empty "${arg}"; then
			continue
		fi

		if [ -z "${port}" ]; then
			port="${arg}"
			continue
		fi

		parameter=`lib_jailparam_name "${arg}" :`
		value=`lib_jailparam_value "${arg}" :`

		case "${parameter}" in
			descr)
				description="${value}"
				;;
			ext_if)
				ext_if="${value}"
				;;
			logopts)
				use_logopts=1
				logopts="${value}"
				;;
			proto)
				proto="${value}"
				;;
			network)
				network_name="${value}"
				;;
			on_if)
				on_if="${value}"
				;;
			*)
				lib_err ${EX_DATAERR} -- "${parameter} (expose): parameter not found."
				;;
		esac
	done

	if lib_check_empty "${port}"; then
		quick_set_expose # usage
	fi

	if ! printf "%s" "${port}" | grep -Eq '^[^:]+(:[^:]+)?$'; then
		lib_err ${EX_DATAERR} "Invalid port: ${port}"
	fi

	if lib_check_empty "${proto}"; then
		proto="tcp"
	fi

	case "${proto}" in
		tcp|udp) ;;
		*) lib_err ${EX_DATAERR} -- "${proto}: invalid protocol." ;;
	esac

	if lib_check_empty "${network_name}"; then
		network_name="${QUICK_DEFAULT_SUBGROUP}"
	else
		if lib_check_ifacelen "${network_name}"; then
			lib_err ${EX_DATAERR} -- "${network_name}: network name too long."
		fi

		if ! lib_check_networkname "${network_name}"; then
			lib_err ${EX_DATAERR} -- "${network_name}: invalid network name."
		fi
	fi

	if lib_check_empty "${ext_if}"; then
		ext_if="${EXT_IF}"
	else
		quick_iface "${ext_if}"
	fi

	if lib_check_empty "${on_if}"; then
		on_if="${ON_IF}"
	else
		quick_iface "${on_if}"
	fi

	local nro

	lib_keys_mk "${QUICK_KEY_EXPOSE}"
	nro=`lib_keys_append "${QUICK_KEY_EXPOSE}" "description" "${description}"`
	lib_keys_set "${QUICK_KEY_EXPOSE}" "${nro}" "ext_if" "${ext_if}"
	lib_keys_set "${QUICK_KEY_EXPOSE}" "${nro}" "use_logopts" "${use_logopts}"
	lib_keys_set "${QUICK_KEY_EXPOSE}" "${nro}" "logopts" "${logopts}"
	lib_keys_set "${QUICK_KEY_EXPOSE}" "${nro}" "proto" "${proto}"
	lib_keys_set "${QUICK_KEY_EXPOSE}" "${nro}" "port" "${port}"
	lib_keys_set "${QUICK_KEY_EXPOSE}" "${nro}" "on_if" "${on_if}"
	lib_keys_set "${QUICK_KEY_EXPOSE}" "${nro}" "network" "${network_name}"

	QUICK_OPTION_EXPOSE=1
}

quick_run_jng()
{
	if [ ${QUICK_OPTION_JNG} -eq 0 ]; then
		return 0
	fi

	if ! which -s "jng"; then
		lib_err ${EX_UNAVAILABLE} "jng is not installed or does not have the execute bit. Use \`install -m 555 /usr/share/examples/jails/jng /usr/local/bin/jng\` to install it."
	fi

	# required by jng
	lib_modules_load "ng_ether"
	
	# vnet
	lib_ajconf set -t "${QUICK_TEMP_TEMPLATE}" vnet

	lib_keys_list "${QUICK_KEY_JNG}" | while IFS= read -r jng_name
	do
		ng_interfaces=`lib_keys_get "${QUICK_KEY_JNG}" "${jng_name}" "ng_interfaces"`
		interfaces=`lib_keys_get "${QUICK_KEY_JNG}" "${jng_name}" "interfaces"`
		bridge=`lib_keys_get "${QUICK_KEY_JNG}" "${jng_name}" "bridge"`

		lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" vnet.interface="${ng_interfaces}"
		lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" exec.prestart="\"jng bridge -b ${bridge} ${jng_name} ${interfaces}\""
		lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" exec.poststop="\"jng shutdown ${jng_name}\""
	done
}

quick_set_jng()
{
	if [ ${QUICK_OPTION_ALIAS} -eq 1 ]; then
		quick_exclusive "jng" "alias"
	fi

	quick_vimage

	local params="$1"
	if lib_check_empty "${params}"; then
		lib_err ${EX_DATAERR} "jng syntax: name [iface:]interface ... [bridge:bridge_name]"
	fi

	params=`lib_split_jailparams "${params}"` || exit $?
	local total_items=`printf "%s\n" "${params}" | wc -l`
	local current_index=0

	local jng_name=
	local jng_bridge=
	local interfaces=
	local ng_interfaces= niface=0

	local arg parameter value
	while [ ${current_index} -lt ${total_items} ]; do 
		current_index=$((current_index+1))

		arg=`printf "%s\n" "${params}" | head -${current_index} | tail -n 1`
		if lib_check_empty "${arg}"; then
			continue
		fi

		if [ -z "${jng_name}" ]; then
			jng_name="${arg}"
			continue
		fi

		parameter=`lib_jailparam_name "${arg}" :`
		value=`lib_jailparam_value "${arg}" :`

		if lib_check_empty "${value}"; then
			value="${parameter}"
			parameter="iface"
		fi

		case "${parameter}" in
			bridge)
				jng_bridge="${value}"
				;;
			iface)
				local interface="${value}"

				if ! printf "%s" "${interface}" | grep -qEe "${QUICK_REGEX_JNG}"; then
					lib_err ${EX_DATAERR} -- "${interface}: invalid interface name."
				fi

				if ! lib_check_iface "${interface}"; then
					lib_err ${EX_NOINPUT} -- "${interface}: interface does not exist."
				fi

				if [ -z "${interfaces}" ]; then
					interfaces="${interface}"
				else
					interfaces="${interfaces} ${interface}"
				fi

				if [ -z "${ng_interfaces}" ]; then
					ng_interfaces="ng${niface}_"
				else
					ng_interfaces="${ng_interfaces} ng${niface}_"
				fi

				niface=$((niface+1))
				;;
			*)
				lib_err ${EX_DATAERR} -- "${parameter} (jng): parameter not found."
				;;
		esac
	done

	if lib_check_empty "${interfaces}" || lib_check_empty "${jng_name}"; then
		quick_set_jng # usage
	fi

	if lib_check_empty "${jng_bridge}"; then
		jng_bridge="bridge"
	fi

	if ! printf "%s" "${jng_bridge}" | grep -qEe "${QUICK_REGEX_JNG}"; then
		lib_err ${EX_DATAERR} -- "${jng_bridge}: invalid bridge name."
	fi

	if ! printf "%s" "${jng_name}" | grep -qEe "${QUICK_REGEX_JNG_NAME}"; then
		lib_err ${EX_DATAERR} -- "${jng_name}: invalid name."
	fi

	# ng<niface>_ -> ng<niface>_<jng_name>
	local ng_interface _ng_interfaces
	for ng_interface in ${ng_interfaces}; do
		ng_interface="${ng_interface}${jng_name}"

		if [ `echo -n "${ng_interface}" | wc -c` -gt ${QUICK_IFNAMSIZ} ]; then
			lib_err ${EX_DATAERR} -- "${ng_interface}: interface name too long."
		fi

		if [ -z "${_ng_interfaces}" ]; then
			_ng_interfaces="${ng_interface}"
		else
			_ng_interfaces="${_ng_interfaces} ${ng_interface}"
		fi
	done
	ng_interfaces="${_ng_interfaces}"

	lib_keys_set "${QUICK_KEY_JNG}" "${jng_name}" "bridge" "${jng_bridge}"
	lib_keys_set "${QUICK_KEY_JNG}" "${jng_name}" "interfaces" "${interfaces}"
	lib_keys_set "${QUICK_KEY_JNG}" "${jng_name}" "ng_interfaces" "${ng_interfaces}"

	QUICK_OPTION_JNG=1
}

quick_run_virtualnet()
{
	local errlevel

	if [ ${QUICK_OPTION_VIRTUALNET} -eq 0 ]; then
		return 0
	fi

	# see `quick_run_alias`
	if [ ${QUICK_OPTION_ALIAS} -eq 1 ]; then
		return 0
	fi

	# vnet
	lib_ajconf set -t "${QUICK_TEMP_TEMPLATE}" vnet

	lib_keys_list "${QUICK_KEY_VIRTUALNET}" | while IFS= read -r virtualnet
	do
		# interface
		interface=`lib_keys_get "${QUICK_KEY_VIRTUALNET}" "${virtualnet}" "interface"`
		if lib_check_empty "${interface}"; then
			lib_err ${EX_CONFIG} -- "${virtualnet}: an interface is required."
		fi

		if lib_check_etherlen "${interface}"; then
			lib_err ${EX_DATAERR} -- "${interface}: interface name too long."
		fi

		if ! lib_check_interfacename "${interface}"; then
			lib_err ${EX_DATAERR} -- "${interface}: invalid interface name."
		fi

		ip4=`lib_keys_get "${QUICK_KEY_VIRTUALNET}" "${virtualnet}" "ip4"`
		if lib_check_empty "${ip4}"; then
			ip4="forceauto"
		fi

		lib_debug "Reserving an IPv4 address for ${QUICK_JAILNAME} in ${virtualnet} ..."

		# current IPv4
		ip4=`appjail network reserve -j "${QUICK_JAILNAME}" -n "${virtualnet}" -a "${ip4}"` || exit $?

		# interface description
		interface_desc=`lib_keys_get "${QUICK_KEY_VIRTUALNET}" "${virtualnet}" "interface_desc"`
		
		# vnet interfaces
		lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" vnet.interface="\"eb_${interface}\""

		lib_debug "VNET Interface:e[ab]_${interface} Description:${interface_desc}"

		# plug
		if ! lib_check_empty "${interface_desc}"; then
			local escape_interface_desc
			escape_interface_desc=`lib_escape_string "${interface_desc}" "${QUICK_ESCAPE_TEMPLATE}"`

			lib_ajconf set \
				-It "${QUICK_TEMP_TEMPLATE}" \
				exec.prestart="\"appjail network plug -e \\\"${interface}\\\" -n \\\"${virtualnet}\\\" -d \\\"${escape_interface_desc}\\\"\""
		else
			lib_ajconf set \
				-It "${QUICK_TEMP_TEMPLATE}" \
				exec.prestart="\"appjail network plug -e \\\"${interface}\\\" -n \\\"${virtualnet}\\\"\""
		fi

		# assign
		if [ -n "${QUICK_OPTION_DEFNET}" ] && [ "${QUICK_OPTION_DEFNET}" = "${virtualnet}" ]; then
			lib_debug "${virtualnet} is the default router."

			lib_ajconf set \
				-It "${QUICK_TEMP_TEMPLATE}" \
				exec.poststart="\"appjail network assign -d -e \\\"${interface}\\\" -j \\\"\${name}\\\" -n \\\"${virtualnet}\\\"\""
		else
			lib_ajconf set \
				-It "${QUICK_TEMP_TEMPLATE}" \
				exec.poststart="\"appjail network assign -e \\\"${interface}\\\" -j \\\"\${name}\\\" -n \\\"${virtualnet}\\\"\""
		fi

		# unplug
		lib_ajconf set \
			-It "${QUICK_TEMP_TEMPLATE}" \
			exec.poststop="\"appjail network unplug \\\"${virtualnet}\\\" \\\"${interface}\\\"\""
	done

	errlevel=$?
	if [ ${errlevel} -ne 0 ]; then
		exit ${errlevel}
	fi
}

quick_set_virtualnet()
{
	if [ ${QUICK_OPTION_IP4_INHERIT} -eq 1 ]; then
		quick_exclusive "ip4" "ip4_inherit"
	elif [ ${QUICK_OPTION_IP4_DISABLE} -eq 1 ]; then
		quick_exclusive "ip4" "ip4_disable"
	fi

	quick_vimage

	local params="$1"
	if lib_check_empty "${params}"; then
		lib_err ${EX_DATAERR} "virtualnet syntax: virtualnet:interface [default] [address:ipv4_address] [interface_desc:interface_description]"
	fi

	params=`lib_split_jailparams "${params}"` || exit $?
	local total_items=`printf "%s\n" "${params}" | wc -l`
	local current_index=0

	local interface= virtualnet=
	local default=0
	local address=
	local interface_desc=

	local arg parameter value
	while [ ${current_index} -lt ${total_items} ]; do 
		current_index=$((current_index+1))

		arg=`printf "%s\n" "${params}" | head -${current_index} | tail -n 1`
		if lib_check_empty "${arg}"; then
			continue
		fi

		if [ -z "${virtualnet}" ]; then
			virtualnet="${arg}"
			continue
		fi

		parameter=`lib_jailparam_name "${arg}" :`
		value=`lib_jailparam_value "${arg}" :`

		case "${parameter}" in
			default)
				default=1
				;;
			address)
				address="${value}"
				;;
			interface_desc)
				interface_desc="${value}"
				;;
			*)
				lib_err ${EX_DATAERR} -- "${parameter} (virtualnet): parameter not found."
				;;
		esac
	done

	if lib_check_empty "${virtualnet}"; then
		quick_set_virtualnet # usage
	fi

	if ! lib_check_empty "${address}"; then
		if ! lib_check_ipv4addr "${address}"; then
			lib_err ${EX_DATAERR} -- "${address}: invalid IPv4 address."
		fi
	fi

	interface=`lib_jailparam_value "${virtualnet}" :`
	virtualnet=`lib_jailparam_name "${virtualnet}" :`

	if printf "%s" "${virtualnet}" | grep -qEe '^:'; then
		interface=`printf "%s" "${virtualnet}" | sed -Ee 's/^:(.+)$/\1/'`
		virtualnet="${AUTO_NETWORK_NAME}"

		if [ ${QUICK_USE_AJNET} -eq 1 ]; then
			lib_err - "Virtual network \`${virtualnet}\` cannot be used again."
			lib_err - "It is necessary to provide a virtual network explicitly."
			exit ${EX_CONFIG}
		fi

		lib_info "Virtual network was not specified, using \`${virtualnet}\` as the virtual network ..."

		if [ ! -d "${NETWORKDIR}/${virtualnet}" ]; then
			lib_debug -- "Virtual network \`${virtualnet}\` does not exist, creating ..."

			appjail network auto-create || exit $?
		fi

		QUICK_USE_AJNET=1
	fi

	if lib_check_ifacelen "${virtualnet}"; then
		lib_err ${EX_DATAERR} -- "${virtualnet}: network name too long."
	fi

	if ! lib_check_networkname "${virtualnet}"; then
		lib_err ${EX_DATAERR} -- "${virtualnet}: invalid network name."
	fi

	if [ ${default} -eq 1 ]; then
		if [ -n "${QUICK_OPTION_DEFNET}" ]; then
			lib_warn "Overwriting default network: ${QUICK_OPTION_DEFNET} -> ${virtualnet}"
		fi

		QUICK_OPTION_DEFNET="${virtualnet}"
	fi

	if [ "${interface}" = "<name>" ]; then
		interface="${QUICK_JAILNAME}"
	elif [ "${interface}" = "<random>" ]; then
		interface=`random_hexstring 11 0 15 | tr -d '\n'`
	fi

	lib_keys_set "${QUICK_KEY_VIRTUALNET}" "${virtualnet}" "ip4" "${address}"
	lib_keys_set "${QUICK_KEY_VIRTUALNET}" "${virtualnet}" "interface" "${interface}"
	lib_keys_set "${QUICK_KEY_VIRTUALNET}" "${virtualnet}" "interface_desc" "${interface_desc}"

	QUICK_OPTION_VIRTUALNET=1
}

quick_set_ip4()
{
	if [ ${QUICK_OPTION_IP4_INHERIT} -eq 1 ]; then
		quick_exclusive "ip4" "ip4_inherit"
	elif [ ${QUICK_OPTION_IP4_DISABLE} -eq 1 ]; then
		quick_exclusive "ip4" "ip4_disable"
	fi

	local interface ip4 netmask

	ip4="$1"; quick_reqoption "ip4" "${ip4}"

	interface=`lib_jailparam_name "${ip4}" '|'`
	ip4=`lib_jailparam_value "${ip4}" '|'`

	# The user should use `interface`.
	if lib_check_empty "${ip4}"; then
		ip4="${interface}"
		interface=
	else
		quick_iface "${interface}"
	fi

	if lib_check_empty "${ip4}"; then
		lib_err - "ip4 syntax: ip4_address"
		lib_err - "            interface|ip4_address"
		exit ${EX_DATAERR}
	fi

	netmask=`lib_jailparam_value "${ip4}" '/'`
	ip4=`lib_jailparam_name "${ip4}" '/'`

	if ! lib_check_ipv4addr "${ip4}"; then
		lib_err ${EX_DATAERR} -- "${ip4}: invalid IPv4 address."
	fi

	if ! lib_check_empty "${netmask}"; then
		if lib_check_number "${netmask}"; then
			if [ ${netmask} -lt 0 -o ${netmask} -gt 32 ]; then
				lib_err ${EX_DATAERR} -- "${netmask}: invalid netmask."
			fi
		else
			if ! lib_check_ipv4addr "${netmask}"; then
				lib_err ${EX_DATAERR} -- "${netmask}: invalid netmask."
			fi
		fi
	fi

	local nro

	lib_keys_mk "${QUICK_KEY_IP4}"
	nro=`lib_keys_append "${QUICK_KEY_IP4}" "addr" "${ip4}"`
	lib_keys_set "${QUICK_KEY_IP4}" "${nro}" "netmask" "${netmask}"
	lib_keys_set "${QUICK_KEY_IP4}" "${nro}" "interface" "${interface}"

	QUICK_OPTION_IP4=1
}

quick_set_ip4_inherit()
{
	if [ ${QUICK_OPTION_IP4} -eq 1 ]; then
		quick_exclusive "ip4_inherit" "ip4"
	elif [ ${QUICK_OPTION_IP4_DISABLE} -eq 1 ]; then
		quick_exclusive "ip4_inherit" "ip4_disable"
	elif [ ${QUICK_OPTION_VIRTUALNET} -eq 1 ]; then
		quick_exclusive "ip4_inherit" "virtualnet"
	fi

	QUICK_OPTION_IP4_INHERIT=1
}

quick_set_ip4_disable()
{
	if [ ${QUICK_OPTION_IP4} -eq 1 ]; then
		quick_exclusive "ip4_disable" "ip4"
	elif [ ${QUICK_OPTION_IP4_INHERIT} -eq 1 ]; then
		quick_exclusive "ip4_disable" "ip4_inherit"
	elif [ ${QUICK_OPTION_VIRTUALNET} -eq 1 ]; then
		quick_exclusive "ip4_disable" "virtualnet"
	fi

	QUICK_OPTION_IP4_DISABLE=1
}

quick_set_ip6()
{
	if [ ${QUICK_OPTION_IP6_INHERIT} -eq 1 ]; then
		quick_exclusive "ip6" "ip6_inherit"
	elif [ ${QUICK_OPTION_IP6_DISABLE} -eq 1 ]; then
		quick_exclusive "ip6" "ip6_disable"
	fi

	local interface ip6 netmask

	ip6="$1"; quick_reqoption "ip6" "${ip6}"

	interface=`lib_jailparam_name "${ip6}" '|'`
	ip6=`lib_jailparam_value "${ip6}" '|'`

	# The user should use `interface`.
	if lib_check_empty "${ip6}"; then
		ip6="${interface}"
		interface=
	else
		quick_iface "${interface}"
	fi

	if lib_check_empty "${ip6}"; then
		lib_err - "ip6 syntax: ip6_address"
		lib_err - "            interface|ip6_address"
		exit ${EX_DATAERR}
	fi

	netmask=`lib_jailparam_value "${ip6}" '/'`
	ip6=`lib_jailparam_name "${ip6}" '/'`

	if ! lib_check_ipv6addr "${ip6}"; then
		lib_err ${EX_DATAERR} -- "${ip6}: invalid IPv6 address."
	fi

	if ! lib_check_empty "${netmask}"; then
		if lib_check_number "${netmask}"; then
			if [ ${netmask} -lt 0 -o ${netmask} -gt 128 ]; then
				lib_err ${EX_DATAERR} -- "${netmask}: invalid netmask."
			fi
		else
			if ! lib_check_ipv6addr "${netmask}"; then
				lib_err ${EX_DATAERR} -- "${netmask}: invalid netmask."
			fi
		fi
	fi

	local nro

	lib_keys_mk "${QUICK_KEY_IP6}"
	nro=`lib_keys_append "${QUICK_KEY_IP6}" "addr" "${ip6}"`
	lib_keys_set "${QUICK_KEY_IP6}" "${nro}" "netmask" "${netmask}"
	lib_keys_set "${QUICK_KEY_IP6}" "${nro}" "interface" "${interface}"

	QUICK_OPTION_IP6=1
}

quick_set_ip6_inherit()
{
	if [ ${QUICK_OPTION_IP6} -eq 1 ]; then
		quick_exclusive "ip6_inherit" "ip6"
	elif [ ${QUICK_OPTION_IP6_DISABLE} -eq 1 ]; then
		quick_exclusive "ip6_inherit" "ip6_disable"
	fi

	QUICK_OPTION_IP6_INHERIT=1
}

quick_set_ip6_disable()
{
	if [ ${QUICK_OPTION_IP6} -eq 1 ]; then
		quick_exclusive "ip6_disable" "ip6"
	elif [ ${QUICK_OPTION_IP6_INHERIT} -eq 1 ]; then
		quick_exclusive "ip6_disable" "ip6_inherit"
	fi

	QUICK_OPTION_IP6_DISABLE=1
}

quick_run_alias()
{
	local errlevel
	local has_option=0

	if [ ${QUICK_OPTION_ALIAS} -eq 0 ]; then
		return 0
	fi

	lib_debug "Using alias option ..."

	if [ -n "${QUICK_OPTION_ALIAS_IFACE}" ]; then
		lib_debug "Default interface: ${QUICK_OPTION_ALIAS_IFACE}"

		lib_ajconf set -t "${QUICK_TEMP_TEMPLATE}" interface="\"${QUICK_OPTION_ALIAS_IFACE}\""
	fi

	if [ ${QUICK_OPTION_VIRTUALNET} -eq 1 ]; then
		lib_keys_list "${QUICK_KEY_VIRTUALNET}" | while IFS= read -r virtualnet
		do
			cidr=`appjail network get -I -- "${virtualnet}" cidr` || exit $?

			lib_debug "Reserving an IPv4 address for ${QUICK_JAILNAME} in ${virtualnet} ..."

			ip4=`lib_keys_get "${QUICK_KEY_VIRTUALNET}" "${virtualnet}" "ip4"`

			if lib_check_empty "${ip4}"; then
				ip4="forceauto"
			fi
			
			ip4=`appjail network reserve -j "${QUICK_JAILNAME}" -n "${virtualnet}" -a "${ip4}"` || exit $?
			ip4="${ip4}/${cidr}"

			interface=`lib_keys_get "${QUICK_KEY_VIRTUALNET}" "${virtualnet}" "interface"`
			if ! lib_check_empty "${interface}"; then
				ip4="${interface}|${ip4}"
			fi

			lib_debug "Adding IPv4 address to ${QUICK_JAILNAME} template: ${ip4}"

			lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" ip4.addr="${ip4}"
		done

		errlevel=$?
		if [ ${errlevel} -ne 0 ]; then
			exit ${errlevel}
		fi

		has_option=1
	fi

	if [ ${QUICK_OPTION_IP4} -eq 1 ]; then
		lib_keys_list "${QUICK_KEY_IP4}" | while IFS= read -r nro
		do
			addr=`lib_keys_get "${QUICK_KEY_IP4}" "${nro}" "addr"`

			interface=`lib_keys_get "${QUICK_KEY_IP4}" "${nro}" "interface"`
			if [ -n "${interface}" ]; then
				addr="${interface}|${addr}"
			fi

			netmask=`lib_keys_get "${QUICK_KEY_IP4}" "${nro}" "netmask"`
			if [ -n "${netmask}" ]; then
				addr="${addr}/${netmask}"
			fi

			lib_debug "Adding IPv4 address to ${QUICK_JAILNAME} template: ${addr}"

			lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" ip4.addr="${addr}"
		done

		has_option=1
	elif [ ${QUICK_OPTION_IP4_INHERIT} -eq 1 ]; then
		lib_debug -- "${QUICK_JAILNAME} will inherit the IPv4 stack ..."

		lib_ajconf set -t "${QUICK_TEMP_TEMPLATE}" ip4="inherit"

		has_option=1
	elif [ ${QUICK_OPTION_IP4_DISABLE} -eq 1 ]; then
		lib_debug -- "${QUICK_JAILNAME} will not be able to use the IPv4 stack ..."

		lib_ajconf set -t "${QUICK_TEMP_TEMPLATE}" ip4="disable"

		has_option=1
	fi

	if [ ${QUICK_OPTION_IP6} -eq 1 ]; then
		lib_keys_list "${QUICK_KEY_IP6}" | while IFS= read -r nro
		do
			addr=`lib_keys_get "${QUICK_KEY_IP6}" "${nro}" "addr"`

			interface=`lib_keys_get "${QUICK_KEY_IP6}" "${nro}" "interface"`
			if [ -n "${interface}" ]; then
				addr="${interface}|${addr}"
			fi

			netmask=`lib_keys_get "${QUICK_KEY_IP6}" "${nro}" "netmask"`
			if [ -n "${netmask}" ]; then
				addr="${addr}/${netmask}"
			fi

			lib_debug "Adding IPv6 address to ${QUICK_JAILNAME} template: ${addr}"

			lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" ip6.addr="${addr}"
		done

		has_option=1
	elif [ ${QUICK_OPTION_IP6_INHERIT} -eq 1 ]; then
		lib_debug -- "${QUICK_JAILNAME} will inherit the IPv6 stack ..."

		lib_ajconf set -t "${QUICK_TEMP_TEMPLATE}" ip6="inherit"

		has_option=1
	elif [ ${QUICK_OPTION_IP6_DISABLE} -eq 1 ]; then
		lib_debug -- "${QUICK_JAILNAME} will not be able to use the IPv6 stack ..."

		lib_ajconf set -t "${QUICK_TEMP_TEMPLATE}" ip6="disable"

		has_option=1
	fi

	if [ ${has_option} -eq 0 ]; then
		quick_reqoptions "alias" "virtualnet, ip4, ip4_disable, ip4_inherit, ip6, ip6_disable or ip6_inherit"
	fi

	lib_debug -- "${QUICK_JAILNAME} has been configured to use \`alias\`."
}

quick_set_alias()
{
	if [ ${QUICK_OPTION_BRIDGE} -eq 1 ]; then
		quick_exclusive "alias" "bridge"
	elif [ ${QUICK_OPTION_JNG} -eq 1 ]; then
		quick_exclusive "alias" "jng"
	elif [ ${QUICK_OPTION_VNET} -eq 1 ]; then
		quick_exclusive "alias" "vnet"
	fi

	local interface="$1"
	if ! lib_check_empty "${interface}"; then
		quick_iface "${interface}"

		QUICK_OPTION_ALIAS_IFACE="${interface}"
	fi

	QUICK_OPTION_ALIAS=1
}

quick_run_dhcp()
{
	local errlevel

	if [ ${QUICK_OPTION_DHCP} -eq 0 ]; then
		return 0
	fi

	if [ ${QUICK_OPTION_BRIDGE} -eq 0 -a ${QUICK_OPTION_JNG} -eq 0 -a ${QUICK_OPTION_VNET} -eq 0 ]; then
		quick_reqoptions "dhcp" "bridge, jng or vnet"
	fi

	case "${QUICK_OPTION_JAILTYPE}" in
		${JAIL_TYPE_THIN}|${JAIL_TYPE_THICK}) ;;
		*) lib_err ${EX_CONFIG} -- "${QUICK_OPTION_JAILTYPE}: dhcp can only be used when the jail type is a ${JAIL_TYPE_THICK} or a ${JAIL_TYPE_THIN} jail."
	esac

	lib_keys_list "${QUICK_KEY_DHCP}" | while IFS= read -r nro
	do
		interface=`lib_keys_get "${QUICK_KEY_DHCP}" "${nro}" "interface"`

		# Check if {interface} is in {vnet.interface}.
		match=`quick_vnetiface "${interface}"`
		if lib_check_empty "${match}"; then
			interfaces=`quick_list_vifaces`
			lib_err ${EX_CONFIG} -- "${interface}: the interface is not in vnet.interface. Current interfaces: ${interfaces}"
		fi

		lib_debug "Configuring ${interface} to use DHCP ..."

		mkdir -p "${QUICK_JAILPATH}/jail/etc" || exit $?
		sysrc -f "${QUICK_JAILPATH}/jail/etc/rc.conf" ifconfig_${interface}+="SYNCDHCP" >&2 || exit $?
	done

	errlevel=$?
	if [ ${errlevel} -ne 0 ]; then
		exit ${errlevel}
	fi
}

quick_set_dhcp()
{
	local interface

	interface="$1"; quick_reqoption "dhcp" "${interface}"

	lib_keys_append "${QUICK_KEY_DHCP}" "interface" "${interface}" > /dev/null

	QUICK_OPTION_DHCP=1
}

quick_run_slaac()
{
	if [ ${QUICK_OPTION_SLAAC} -eq 0 ]; then
		return 0
	fi

	if [ ${QUICK_OPTION_BRIDGE} -eq 0 -a ${QUICK_OPTION_JNG} -eq 0 -a ${QUICK_OPTION_VNET} -eq 0 ]; then
		quick_reqoptions "slaac" "bridge, jng or vnet"
	fi

	case "${QUICK_OPTION_JAILTYPE}" in
		${JAIL_TYPE_THIN}|${JAIL_TYPE_THICK}) ;;
		*) lib_err ${EX_CONFIG} -- "${QUICK_OPTION_JAILTYPE}: slaac can only be used when the jail type is a ${JAIL_TYPE_THICK} or a ${JAIL_TYPE_THIN} jail."
	esac

	lib_debug "Enabling rtsold ..."

	mkdir -p "${QUICK_JAILPATH}/jail/etc" || exit $?
	sysrc -f "${QUICK_JAILPATH}/jail/etc/rc.conf" rtsold_enable="YES" >&2 || exit $?
	sysrc -f "${QUICK_JAILPATH}/jail/etc/rc.conf" rtsold_flags="--" >&2 || exit $?

	lib_keys_list "${QUICK_KEY_SLAAC}" | while IFS= read -r nro
	do
		interface=`lib_keys_get "${QUICK_KEY_SLAAC}" "${nro}" "interface"`

		# Check if {interface} is in {vnet.interface}.
		match=`quick_vnetiface "${interface}"`
		if lib_check_empty "${match}"; then
			interfaces=`quick_list_vifaces`
			lib_err ${EX_CONFIG} -- "${interface}: the interface is not in vnet.interface. Current interfaces: ${interfaces}"
		fi

		lib_debug "Configuring ${interface} to use SLAAC ..."

		# Actives the interface if the `dhcp` option did not.
		if [ ${QUICK_OPTION_DHCP} -eq 0 ]; then
			sysrc -f "${QUICK_JAILPATH}/jail/etc/rc.conf" ifconfig_${interface}+="up" >&2 || exit $?
		fi

		sysrc -f "${QUICK_JAILPATH}/jail/etc/rc.conf" ifconfig_${interface}_ipv6="inet6 auto_linklocal accept_rtadv" >&2 || exit $?
		sysrc -f "${QUICK_JAILPATH}/jail/etc/rc.conf" rtsold_flags+="${interface}" >&2 || exit $?
	done

	errlevel=$?
	if [ ${errlevel} -ne 0 ]; then
		exit ${errlevel}
	fi
}

quick_set_slaac()
{
	local interface

	interface="$1"; quick_reqoption "slaac" "${interface}"

	lib_keys_append "${QUICK_KEY_SLAAC}" "interface" "${interface}" > /dev/null

	QUICK_OPTION_SLAAC=1
}

quick_run_bridge()
{
	if [ ${QUICK_OPTION_BRIDGE} -eq 0 ]; then
		return 0
	fi
	
	# vnet
	lib_ajconf set -t "${QUICK_TEMP_TEMPLATE}" vnet

	lib_keys_list "${QUICK_KEY_BRIDGE}" | while IFS= read -r bridge
	do
		lib_debug "Configuring ${QUICK_JAILNAME} to use ${bridge} bridge ..."

		epairs=`lib_keys_get "${QUICK_KEY_BRIDGE}" "${bridge}" "epairs"`
		for epair in ${epairs}; do
			lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" vnet.interface="\"sb_${epair}\""
			lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" exec.prestart="\"appjail network attach -b \\\"${bridge}\\\" \\\"epair:${epair}\\\"\""
			lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" exec.poststop="\"appjail network detach -b \\\"${bridge}\\\" -id \\\"epair:${epair}\\\"\""
		done

		interfaces=`lib_keys_get "${QUICK_KEY_BRIDGE}" "${bridge}" "interfaces"`
		for interface in ${interfaces}; do
			lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" exec.prestart="\"appjail network attach -b \\\"${bridge}\\\" \\\"iface:${interface}\\\"\""
		done
	done
}

quick_set_bridge()
{
	if [ ${QUICK_OPTION_ALIAS} -eq 1 ]; then
		quick_exclusive "bridge" "alias"
	fi

	quick_vimage

	local params="$1"
	if lib_check_empty "${params}"; then
		lib_err ${EX_DATAERR} "bridge syntax: [[epair|iface]:]interface ... [bridge:bridge_name]"
	fi

	params=`lib_split_jailparams "${params}"` || exit $?
	local total_items=`printf "%s\n" "${params}" | wc -l`
	local current_index=0

	local bridge_name=
	local epairs=
	local interfaces=

	local arg parameter value
	while [ ${current_index} -lt ${total_items} ]; do 
		current_index=$((current_index+1))

		arg=`printf "%s\n" "${params}" | head -${current_index} | tail -n 1`
		if lib_check_empty "${arg}"; then
			continue
		fi

		parameter=`lib_jailparam_name "${arg}" :`
		value=`lib_jailparam_value "${arg}" :`

		if lib_check_empty "${value}"; then
			value="${parameter}"
			parameter="${QUICK_DEFAULT_IFACE_TYPE}"
		fi

		case "${parameter}" in
			bridge)
				bridge_name="${value}"
				;;
			epair)
				local interface="${value}"

				if lib_check_etherlen "${interface}"; then
					lib_err ${EX_DATAERR} -- "${interface}: interface name too long."
				fi

				if ! lib_check_interfacename "${interface}"; then
					lib_err ${EX_DATAERR} -- "${interface}: invalid interface name."
				fi

				if [ -z "${epairs}" ]; then
					epairs="${interface}"
				else
					epairs="${epairs} ${interface}"
				fi
				;;
			iface)
				local interface="${value}"

				quick_iface "${interface}"

				if [ -z "${interfaces}" ]; then
					interfaces="${interface}"
				else
					interfaces="${interfaces} ${interface}"
				fi
				;;
			*)
				lib_err ${EX_DATAERR} -- "${parameter} (bridge): parameter not found."
				;;
		esac
	done

	if lib_check_empty "${epairs}" && lib_check_empty "${interfaces}"; then
		quick_set_bridge # usage
	fi

	if lib_check_empty "${bridge_name}"; then
		bridge_name="${SHARED_BRIDGE}"
	fi

	if lib_check_ifacelen "${bridge_name}"; then
		lib_err ${EX_DATAERR} -- "${bridge_name}: network name too long."
	fi

	if ! lib_check_networkname "${bridge_name}"; then
		lib_err ${EX_DATAERR} -- "${bridge_name}: invalid bridge name."
	fi

	lib_keys_set "${QUICK_KEY_BRIDGE}" "${bridge_name}" "epairs" "${epairs}"
	lib_keys_set "${QUICK_KEY_BRIDGE}" "${bridge_name}" "interfaces" "${interfaces}"

	QUICK_OPTION_BRIDGE=1
}

quick_run_volume()
{
	local errlevel

	if [ ${QUICK_OPTION_VOLUME} -eq 0 ]; then
		return 0
	fi

	lib_debug "Configuring volumes ..."

	lib_keys_list "${QUICK_KEY_VOLUME}" | while IFS= read -r volume_name
	do
		volume_add_cmd="appjail volume add"

		group=`lib_keys_get "${QUICK_KEY_VOLUME}" "${volume_name}" "group"`
		if ! lib_check_empty "${group}"; then
			escape_group=`lib_escape_string "${group}"`

			volume_add_cmd="${volume_add_cmd} -g \"${escape_group}\""
		fi

		mountpoint=`lib_keys_get "${QUICK_KEY_VOLUME}" "${volume_name}" "mountpoint"`
		if ! lib_check_empty "${mountpoint}"; then
			escape_mountpoint=`lib_escape_string "${mountpoint}"`

			volume_add_cmd="${volume_add_cmd} -m \"${escape_mountpoint}\""
		fi

		owner=`lib_keys_get "${QUICK_KEY_VOLUME}" "${volume_name}" "owner"`
		if ! lib_check_empty "${owner}"; then
			escape_owner=`lib_escape_string "${owner}"`

			volume_add_cmd="${volume_add_cmd} -o \"${escape_owner}\""
		fi

		perm=`lib_keys_get "${QUICK_KEY_VOLUME}" "${volume_name}" "perm"`
		if ! lib_check_empty "${perm}"; then
			escape_perm=`lib_escape_string "${perm}"`

			volume_add_cmd="${volume_add_cmd} -p \"${escape_perm}\""
		fi

		type=`lib_keys_get "${QUICK_KEY_VOLUME}" "${volume_name}" "type"`
		if ! lib_check_empty "${type}"; then
			escape_type=`lib_escape_string "${type}"`

			volume_add_cmd="${volume_add_cmd} -t \"${escape_type}\""
		fi

		escape_volume_name=`lib_escape_string "${volume_name}"`

		# tail
		volume_add_cmd="${volume_add_cmd} -- \"${QUICK_JAILNAME}\" \"${escape_volume_name}\""

		lib_debug "volume (${volume_name}): \"group:${group}\" \"mountpoint:${mountpoint}\" \"owner:${owner}\" \"perm:${mode}\" \"type:${type}\""

		# profit!
		sh -c "${volume_add_cmd}" || exit $?
	done

	errlevel=$?
	if [ ${errlevel} -ne 0 ]; then
		exit ${errlevel}
	fi
}

quick_set_volume()
{
	local params="$1"
	if lib_check_empty "${params}"; then
		lib_err ${EX_DATAERR} "volume syntax: volume [group:gid] [mountpoint:/path/to/some/directory] [owner:uid] [perm:mode] [type:fs_type]"
	fi

	params=`lib_split_jailparams "${params}"` || exit $?
	local total_items=`printf "%s\n" "${params}" | wc -l`
	local current_index=0

	local volume_name=
	local uid=
	local mountpoint=
	local gid=
	local mode=
	local type=

	local arg parameter value
	while [ ${current_index} -lt ${total_items} ]; do
		current_index=$((current_index+1))

		arg=`printf "%s\n" "${params}" | head -${current_index} | tail -n 1`
		if lib_check_empty "${arg}"; then
			continue
		fi

		if [ -z "${volume_name}" ]; then
			volume_name="${arg}"
			continue
		fi

		parameter=`lib_jailparam_name "${arg}" :`
		value=`lib_jailparam_value "${arg}" :`

		case "${parameter}" in
			group)
				gid="${value}"
				;;
			mountpoint)
				mountpoint="${value}"
				;;
			owner)
				uid="${value}"
				;;
			perm)
				mode="${value}"
				;;
			type)
				type="${value}"
				;;
			*)
				lib_err ${EX_DATAERR} -- "${parameter} (volume): parameter not found."
				;;
		esac
	done

	if lib_check_empty "${volume_name}"; then
		quick_set_volume # usage
	fi

	lib_keys_set "${QUICK_KEY_VOLUME}" "${volume_name}" "group" "${gid}"
	lib_keys_set "${QUICK_KEY_VOLUME}" "${volume_name}" "mountpoint" "${mountpoint}"
	lib_keys_set "${QUICK_KEY_VOLUME}" "${volume_name}" "owner" "${uid}"
	lib_keys_set "${QUICK_KEY_VOLUME}" "${volume_name}" "perm" "${mode}"
	lib_keys_set "${QUICK_KEY_VOLUME}" "${volume_name}" "type" "${type}"

	QUICK_OPTION_VOLUME=1
}

quick_run_fstab()
{
	if [ ${QUICK_OPTION_FSTAB} -eq 0 ]; then
		return 0
	fi

	lib_debug "Configuring fstab ..."

	lib_keys_list "${QUICK_KEY_FSTAB}" | sort -n | while IFS= read -r nro
	do
		device=`lib_keys_get "${QUICK_KEY_FSTAB}" "${nro}" "device"`
		mountpoint=`lib_keys_get "${QUICK_KEY_FSTAB}" "${nro}" "mountpoint"`
		type=`lib_keys_get "${QUICK_KEY_FSTAB}" "${nro}" "type"`
		options=`lib_keys_get "${QUICK_KEY_FSTAB}" "${nro}" "options"`
		dump=`lib_keys_get "${QUICK_KEY_FSTAB}" "${nro}" "dump"`
		pass=`lib_keys_get "${QUICK_KEY_FSTAB}" "${nro}" "pass"`

		lib_debug "fstab#${nro}: \"${device}\" \"${mountpoint}\" \"${type}\" \"${options}\" \"${dump}\" \"${pass}\""

		appjail fstab jail "${QUICK_JAILNAME}" set -d "${device}" -m "${mountpoint}" -t "${type}" -o "${options}" -D "${dump}" -P "${pass}"
	done
}

quick_set_fstab()
{
	local params

	params="$1"; quick_reqoption "fstab" "${params}"

	params=`lib_split_jailparams "${params}"` || exit $?
	local total_items=`printf "%s\n" "${params}" | wc -l`
	local current_index=0

	# options
	local device=
	local mountpoint=
	local type="nullfs"
	local options="rw"
	local dump=0
	local pass=0
	
	while [ ${current_index} -lt ${total_items} ]; do 
		current_index=$((current_index+1))

		local arg=`printf "%s\n" "${params}" | head -${current_index} | tail -n 1`

		if lib_check_empty "${arg}"; then
			lib_err ${EX_DATAERR} "An empty field cannot be used in fstab."
		fi

		if [ ${current_index} -eq ${QUICK_FSTAB_OPTION_DEVICE} ]; then
			device="${arg}"
		elif [ ${current_index} -eq ${QUICK_FSTAB_OPTION_MOUNTPOINT} ]; then
			mountpoint="${arg}"
		elif [ ${current_index} -eq ${QUICK_FSTAB_OPTION_TYPE} ]; then
			type="${arg}"
		elif [ ${current_index} -eq ${QUICK_FSTAB_OPTION_OPTIONS} ]; then
			options="${arg}"
		elif [ ${current_index} -eq ${QUICK_FSTAB_OPTION_DUMP} ]; then
			dump="${arg}"
		elif [ ${current_index} -eq ${QUICK_FSTAB_OPTION_PASS} ]; then
			pass="${arg}"
		else
			break
		fi
	done

	if [ -z "${device}" -o -z "${mountpoint}" ]; then
		lib_err ${EX_DATAERR} "fstab syntax: device mountpoint [type] [options] [dump] [pass]"
	fi

	if ! lib_check_number "${dump}"; then
		lib_err ${EX_DATAERR} "DUMP must be a number!"
	fi

	if ! lib_check_number "${pass}"; then
		lib_err ${EX_DATAERR} "PASS must be a number!"
	fi

	local nro

	lib_keys_mk "${QUICK_KEY_FSTAB}"
	nro=`lib_keys_append "${QUICK_KEY_FSTAB}" "device" "${device}"`
	lib_keys_set "${QUICK_KEY_FSTAB}" "${nro}" "mountpoint" "${mountpoint}"
	lib_keys_set "${QUICK_KEY_FSTAB}" "${nro}" "type" "${type}"
	lib_keys_set "${QUICK_KEY_FSTAB}" "${nro}" "options" "${options}"
	lib_keys_set "${QUICK_KEY_FSTAB}" "${nro}" "dump" "${dump}"
	lib_keys_set "${QUICK_KEY_FSTAB}" "${nro}" "pass" "${pass}"

	QUICK_OPTION_FSTAB=1
}

quick_run_cpuset()
{
	if [ -z "${QUICK_OPTION_CPUSET}" ]; then
		return 0
	fi

	lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" \
		exec.created="\"appjail cpuset \\\"\${name}\\\" \\\"${QUICK_OPTION_CPUSET}\\\"\""
}

quick_set_cpuset()
{
	local cpuset
	cpuset="$1"; quick_reqoption "cpuset" "${cpuset}"

	cpu_list=`lib_check_cpulist "${cpuset}"` || exit $?

	QUICK_OPTION_CPUSET="${cpu_list}"
}

quick_run_limits()
{
	local errlevel

	if [ ${QUICK_OPTION_USE_LIMITS} -eq 0 ]; then
		return 0
	fi

	lib_debug "Configuring limits rules ..."

	lib_keys_list "${QUICK_KEY_LIMITS}" | sort -n | while IFS= read -r nro
	do
		limits_set_cmd="appjail limits set"

		limits_descr=`lib_keys_get "${QUICK_KEY_LIMITS}" "${nro}" "descr"`
		if ! lib_check_empty "${limits_descr}"; then
			escape_limits_descr=`lib_escape_string "${limits_descr}"`
			limits_set_cmd="${limits_set_cmd} -N \"${escape_limits_descr}\""
		fi

		limits_rule=`lib_keys_get "${QUICK_KEY_LIMITS}" "${nro}" "rule"`
		escape_limits_rule=`lib_escape_string "${limits_rule}"`

		lib_debug "limits#${nro}: \"rule:${limits_rule}\" \"descr:${limits_descr}\""

		limits_set_cmd="${limits_set_cmd} -- \"${QUICK_JAILNAME}\" \"${escape_limits_rule}\""

		sh -c "${limits_set_cmd}"

		errlevel=$?
		if [ ${errlevel} -ne 0 ]; then
			lib_err ${errlevel} "An error occurred while adding the limits rule (${limits_rule}) to ${QUICK_JAILNAME} jail."
		fi
	done

	errlevel=$?
	if [ ${errlevel} -ne 0 ]; then
		exit ${errlevel}
	fi

	lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" exec.created='"appjail limits on \"${name}\""'
	lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" exec.poststop='"appjail limits off \"${name}\""'
}

quick_set_limits()
{
	if ! lib_check_racct; then
		lib_err ${EX_UNAVAILABLE} "racct is disable.  Run \`echo kern.racct.enable=1 >> /boot/loader.conf && reboot\` to enable it."
	fi

	local params="$1"
	if lib_check_empty "${params}"; then
		lib_err ${EX_DATAERR} "limits syntax: rule [descr:description]"
	fi

	params=`lib_split_jailparams "${params}"` || exit $?
	local total_items=`printf "%s\n" "${params}" | wc -l`
	local current_index=0

	local description=
	local rule=

	local arg parameter value
	while [ ${current_index} -lt ${total_items} ]; do 
		current_index=$((current_index+1))

		arg=`printf "%s\n" "${params}" | head -${current_index} | tail -n 1`
		if lib_check_empty "${arg}"; then
			continue
		fi

		if [ -z "${rule}" ]; then
			rule="${arg}"
			continue
		fi

		parameter=`lib_jailparam_name "${arg}" :`
		value=`lib_jailparam_value "${arg}" :`

		case "${parameter}" in
			descr)
				description="${value}"
				;;
			*)
				lib_err ${EX_DATAERR} -- "${parameter} (limits): parameter not found."
				;;
		esac
	done

	if lib_check_empty "${rule}"; then
		quick_set_limits # usage
	fi

	lib_debug "Using limits option: rule:${rule} descr:${description}"

	local nro

	lib_keys_mk "${QUICK_KEY_LIMITS}"
	nro=`lib_keys_append "${QUICK_KEY_LIMITS}" "rule" "${rule}"`
	lib_keys_set "${QUICK_KEY_LIMITS}" "${nro}" "descr" "${description}"

	QUICK_OPTION_USE_LIMITS=1
}

quick_run_x11()
{
	if [ ${QUICK_OPTION_X11} -eq 0 ]; then
		return 0
	fi

	lib_debug "Using x11 option ..."

	if [ ! -d "/tmp/.X11-unix" ]; then
		lib_warn "/tmp/.X11-unix: directory does not seem to exist or is not a directory."
	fi
	
	mkdir -pm 1777 "${JAILDIR}/${QUICK_JAILNAME}/jail/tmp/.X11-unix" || exit $?
	appjail fstab jail "${QUICK_JAILNAME}" set -d /tmp/.X11-unix -m /tmp/.X11-unix || exit $?
}

quick_set_x11()
{
	if [ ${QUICK_OPTION_TMPDIR} -eq 1 ]; then
		quick_exclusive "x11" "tmpdir"
	fi

	QUICK_OPTION_X11=1
}

quick_run_tmpdir()
{
	if [ ${QUICK_OPTION_TMPDIR} -eq 0 ]; then
		return 0
	fi

	lib_debug "Using tmpdir option ..."

	if [ ! -d "/tmp" ]; then
		lib_warn "/tmp: directory does not seem to exist or is not a directory."
	fi
	
	mkdir -pm 1777 "${JAILDIR}/${QUICK_JAILNAME}/jail/tmp" || exit $?
	appjail fstab jail "${QUICK_JAILNAME}" set -d /tmp -m /tmp || exit $?
}

quick_set_tmpdir()
{
	if [ ${QUICK_OPTION_X11} -eq 1 ]; then
		quick_exclusive "tmpdir" "x11"
	fi

	QUICK_OPTION_TMPDIR=1
}

quick_run_linuxfs()
{
	if [ ${QUICK_OPTION_LINUXFS} -eq 0 ]; then
		return 0
	fi
	
	lib_debug "Using linuxfs option ..."

	quick_assign_devfs_ruleset

	quick_chknumber "devfs_ruleset" "${QUICK_OPTION_DEVFS_RULESET}"

	appjail fstab jail "${QUICK_JAILNAME}" set -d devfs -m /dev -t devfs -o rw,ruleset="${QUICK_OPTION_DEVFS_RULESET}" || exit $?
	appjail fstab jail "${QUICK_JAILNAME}" set -d tmpfs -m /dev/shm -t tmpfs -o rw,size=1g,mode=1777 || exit $?
	appjail fstab jail "${QUICK_JAILNAME}" set -d fdescfs -m /dev/fd -t fdescfs -o rw,linrdlnk || exit $?
	appjail fstab jail "${QUICK_JAILNAME}" set -d linprocfs -m /proc -t linprocfs || exit $?
	appjail fstab jail "${QUICK_JAILNAME}" set -d linsysfs -m /sys -t linsysfs || exit $?
}

quick_set_linuxfs()
{
	if [ "${QUICK_OPTION_MOUNT_DEVFS}" != 0 ]; then
		quick_exclusive "linuxfs" "mount_devfs"
	fi

	QUICK_OPTION_LINUXFS=1
}

quick_run_run_env()
{
	if [ -z "${QUICK_OPTION_RUN_ENV}" ]; then
		return 0
	fi

	quick_args "run" "-V" "${QUICK_OPTION_RUN_ENV}"
}

quick_set_run_env()
{
	local run_env

	run_env="$1"; quick_reqoption "run_env" "${run_env}"
	run_env=`lib_escape_string "${run_env}" "" '\"' "-"`

	if [ -z "${QUICK_OPTION_RUN_ENV}" ]; then
		QUICK_OPTION_RUN_ENV="\"${run_env}\""
	else
		QUICK_OPTION_RUN_ENV="${QUICK_OPTION_RUN_ENV} \"${run_env}\""
	fi
}

quick_run_start_env()
{
	if [ -z "${QUICK_OPTION_START_ENV}" ]; then
		return 0
	fi

	quick_args "start" "-V" "${QUICK_OPTION_START_ENV}"
}

quick_set_start_env()
{
	local start_env

	start_env="$1"; quick_reqoption "start_env" "${start_env}"
	start_env=`lib_escape_string "${start_env}" "" '\"' "-"`

	if [ -z "${QUICK_OPTION_START_ENV}" ]; then
		QUICK_OPTION_START_ENV="\"${start_env}\""
	else
		QUICK_OPTION_START_ENV="${QUICK_OPTION_START_ENV} \"${start_env}\""
	fi
}

quick_run_start_args()
{
	if [ -z "${QUICK_OPTION_START_ARGS}" ]; then
		return 0
	fi

	quick_args "start" "-s" "${QUICK_OPTION_START_ARGS}"
}

quick_set_start_args()
{
	local start_args

	start_args="$1"; quick_reqoption "start_args" "${start_args}"
	start_args=`lib_escape_string "${start_args}" "" '\"' "-"`

	if [ -z "${QUICK_OPTION_START_ARGS}" ]; then
		QUICK_OPTION_START_ARGS="\"${start_args}\""
	else
		QUICK_OPTION_START_ARGS="${QUICK_OPTION_START_ARGS} \"${start_args}\""
	fi
}

quick_run_create_args()
{
	if [ -z "${QUICK_OPTION_CREATE_ARGS}" ]; then
		return 0
	fi

	quick_args "start" "-c" "${QUICK_OPTION_CREATE_ARGS}"
}

quick_set_create_args()
{
	local create_args

	create_args="$1"; quick_reqoption "create_args" "${create_args}"
	create_args=`lib_escape_string "${create_args}" "" '\"' "-"`

	if [ -z "${QUICK_OPTION_CREATE_ARGS}" ]; then
		QUICK_OPTION_CREATE_ARGS="\"${create_args}\""
	else
		QUICK_OPTION_CREATE_ARGS="${QUICK_OPTION_CREATE_ARGS} \"${create_args}\""
	fi
}

quick_run_run_args()
{
	if [ -z "${QUICK_OPTION_RUN_ARGS}" ]; then
		return 0
	fi

	quick_args "run" "-p" "${QUICK_OPTION_RUN_ARGS}"
}

quick_set_run_args()
{
	local run_args

	run_args="$1"; quick_reqoption "run_args" "${run_args}"
	run_args=`lib_escape_string "${run_args}" "" '\"' "-"`

	if [ -z "${QUICK_OPTION_RUN_ARGS}" ]; then
		QUICK_OPTION_RUN_ARGS="\"${run_args}\""
	else
		QUICK_OPTION_RUN_ARGS="${QUICK_OPTION_RUN_ARGS} \"${run_args}\""
	fi
}

quick_run_stop_env()
{
	if [ -z "${QUICK_OPTION_STOP_ENV}" ]; then
		return 0
	fi

	quick_args "stop" "-V" "${QUICK_OPTION_STOP_ENV}"
}

quick_set_stop_env()
{
	local stop_env

	stop_env="$1"; quick_reqoption "stop_env" "${stop_env}"
	stop_env=`lib_escape_string "${stop_env}" "" '\"' "-"`

	if [ -z "${QUICK_OPTION_STOP_ENV}" ]; then
		QUICK_OPTION_STOP_ENV="\"${stop_env}\""
	else
		QUICK_OPTION_STOP_ENV="${QUICK_OPTION_STOP_ENV} \"${stop_env}\""
	fi
}

quick_run_stop_args()
{
	if [ -z "${QUICK_OPTION_STOP_ARGS}" ]; then
		return 0
	fi

	quick_args "stop" "-p" "${QUICK_OPTION_STOP_ARGS}"
}

quick_set_stop_args()
{
	local stop_args

	stop_args="$1"; quick_reqoption "stop_args" "${stop_args}"
	stop_args=`lib_escape_string "${stop_args}" "" '\"' "-"`

	if [ -z "${QUICK_OPTION_STOP_ARGS}" ]; then
		QUICK_OPTION_STOP_ARGS="\"${stop_args}\""
	else
		QUICK_OPTION_STOP_ARGS="${QUICK_OPTION_STOP_ARGS} \"${stop_args}\""
	fi
}

quick_args()
{
	local enable_cmd="$1" enable_param="$2" args="$3"
	if [ -z "${enable_cmd}" -o -z "${enable_param}" -o -z "${args}" ]; then
		lib_err ${EX_USAGE} "usage: quick_args enable_cmd enable_param args"
	fi

	lib_debug "Setting ${enable_cmd} args: ${args}"

	enable_cmd="appjail enable \"${QUICK_JAILNAME}\" ${enable_cmd}"

	local args_list
	local total_items
	local current_index=0

	args_list=`lib_split_jailparams "${args}"` || exit $?
	total_items=`printf "%s\n" "${args_list}" | wc -l`

	local args enable_cmd_args=
	while [ ${current_index} -lt ${total_items} ]; do 
		current_index=$((current_index+1))
		arg=`printf "%s\n" "${args_list}" | head -${current_index} | tail -n 1`
		if lib_check_empty "${arg}"; then
			continue
		fi

		arg=`lib_escape_string "${arg}"`

		if [ -z "${enable_cmd_args}" ]; then
			enable_cmd_args="${enable_param} \"${arg}\""
		else
			enable_cmd_args="${enable_cmd_args} ${enable_param} \"${arg}\""
		fi
	done

	enable_cmd="${enable_cmd} ${enable_cmd_args}"

	lib_debug "Running: ${enable_cmd}"

	sh -c "${enable_cmd}"
}

quick_run_start()
{
	if [ "${QUICK_OPTION_START}" = 0 ]; then
		return 0
	fi
		
	appjail start -- "${QUICK_JAILNAME}" || exit $?

	if [ "${QUICK_OPTION_RESTART}" != 0 ]; then
		appjail restart "${QUICK_JAILNAME}" || exit $?
	fi

	if [ "${QUICK_OPTION_RUN}" != 0 ]; then
		appjail run -- "${QUICK_JAILNAME}" || exit $?
	fi

	if [ "${QUICK_OPTION_LOGIN}" != 0 ]; then
		lib_debug "Trying to log in to ${QUICK_JAILNAME} ..."

		appjail login -u "${QUICK_OPTION_LOGIN_USER}" -- "${QUICK_JAILNAME}"
	fi
}

quick_set_start()
{
	QUICK_OPTION_START=1
}

quick_set_nostart()
{
	QUICK_OPTION_START=0
}

quick_set_restart()
{
	QUICK_OPTION_RESTART=1
}

quick_set_norestart()
{
	QUICK_OPTION_RESTART=0
}

quick_set_run()
{
	QUICK_OPTION_RUN=1
}

quick_set_norun()
{
	QUICK_OPTION_RUN=0
}

quick_set_login()
{
	QUICK_OPTION_LOGIN=1
}

quick_set_nologin()
{
	QUICK_OPTION_LOGIN=0
}

quick_set_login_user()
{
	local login_user

	login_user="$1"; quick_reqoption "login_user" "${login_user}"

	QUICK_OPTION_LOGIN_USER="${login_user}"
}

quick_run_devfs()
{
	if [ ${QUICK_OPTION_MOUNT_DEVFS} -eq 0 ]; then
		return 0
	fi

	lib_debug "Using devfs option ..."

	quick_assign_devfs_ruleset

	quick_chknumber "devfs_ruleset" "${QUICK_OPTION_DEVFS_RULESET}"

	lib_ajconf set -t "${QUICK_TEMP_TEMPLATE}" mount.devfs
	lib_ajconf set -t "${QUICK_TEMP_TEMPLATE}" devfs_ruleset="${QUICK_OPTION_DEVFS_RULESET}"
}

quick_set_devfs_ruleset()
{
	local devfs_ruleset

	devfs_ruleset="$1"

	quick_reqoption "devfs_ruleset" "${devfs_ruleset}"
	quick_chknumber "devfs_ruleset" "${devfs_ruleset}"

	if ! lib_check_devfs_ruleset "${devfs_ruleset}"; then
		lib_warn "${devfs_ruleset}: ruleset number does not seem to exist ..."
	fi

	QUICK_OPTION_DEVFS_RULESET="${devfs_ruleset}"
}

quick_run_device()
{
	if [ ${QUICK_OPTION_DEVICE} -eq 0 ]; then
		return 0
	fi

	lib_debug "Configuring DEVFS ..."

	lib_keys_list "${QUICK_KEY_DEVICE}" | sort -n | while IFS= read -r nro
	do
		rulespec=`lib_keys_get "${QUICK_KEY_DEVICE}" "${nro}" "rulespec"`

		lib_debug "devfs#${nro}: ${rulespec}"

		appjail devfs set -- "${QUICK_JAILNAME}" "${rulespec}"
	done

	if [ ${QUICK_OPTION_DEVICE} -eq 1 ]; then
		lib_ajconf set -It "${QUICK_TEMP_TEMPLATE}" exec.poststop='"appjail devfs delset -q -- \"${name}\""'
	fi
}

quick_set_device()
{
	local rulespec

	rulespec="$1"; quick_reqoption "device" "${rulespec}"

	local nro

	lib_keys_mk "${QUICK_KEY_DEVICE}"
	lib_keys_append "${QUICK_KEY_DEVICE}" "rulespec" "${rulespec}" > /dev/null

	QUICK_OPTION_DEVICE=1
}

quick_run_macaddr()
{
	local errlevel

	if [ ${QUICK_OPTION_MACADDR} -eq 0 ]; then
		return 0
	fi

	if [ ${QUICK_OPTION_BRIDGE} -eq 0 -a ${QUICK_OPTION_JNG} -eq 0 -a ${QUICK_OPTION_VNET} -eq 0 ]; then
		quick_reqoptions "macaddr" "bridge, jng or vnet"
	fi

	case "${QUICK_OPTION_JAILTYPE}" in
		${JAIL_TYPE_THIN}|${JAIL_TYPE_THICK}) ;;
		*) lib_err ${EX_CONFIG} -- "${QUICK_OPTION_JAILTYPE}: macaddr can only be used when the jail type is a ${JAIL_TYPE_THICK} or a ${JAIL_TYPE_THIN} jail."
	esac

	lib_keys_list "${QUICK_KEY_ETHER}" | while IFS= read -r nro
	do
		interface=`lib_keys_get "${QUICK_KEY_ETHER}" "${nro}" "interface"`
		addr=`lib_keys_get "${QUICK_KEY_ETHER}" "${nro}" "addr"`

		# Check if {interface} is in {vnet.interface}.
		match=`quick_vnetiface "${interface}"`
		if lib_check_empty "${match}"; then
			interfaces=`quick_list_vifaces`
			lib_err ${EX_CONFIG} -- "${interface}: the interface is not in vnet.interface. Current interfaces: ${interfaces}"
		fi

		lib_debug "Configuring ${interface} to use the MAC address \`${addr}\`"

		mkdir -p "${QUICK_JAILPATH}/jail/etc" || exit $?
		sysrc -f "${QUICK_JAILPATH}/jail/etc/rc.conf" ifconfig_${interface}+="ether ${addr}" >&2 || exit $?
	done

	errlevel=$?
	if [ ${errlevel} -ne 0 ]; then
		exit ${errlevel}
	fi
}

quick_set_macaddr()
{
	local parameters

	parameters="$1"; quick_reqoption "macaddr" "${parameters}"

	local interface addr

	interface=`lib_jailparam_name "${parameters}" :`
	addr=`lib_jailparam_value "${parameters}" :`

	if lib_check_empty "${interface}" || lib_check_empty "${addr}"; then
		lib_err ${EX_DATAERR} "macddr syntax: interface:addr"
	fi

	if [ "${addr}" != "random" ] && ! lib_check_macaddr "${addr}"; then
		lib_err ${EX_DATAERR} "Invalid MAC address: ${addr}"
	fi

	local nro

	lib_keys_mk "${QUICK_KEY_ETHER}"
	nro=`lib_keys_append "${QUICK_KEY_ETHER}" "interface" "${interface}"`
	lib_keys_set "${QUICK_KEY_ETHER}" "${nro}" "addr" "${addr}"

	QUICK_OPTION_MACADDR=1
}

quick_set_mount_devfs()
{
	if [ ${QUICK_OPTION_LINUXFS} -eq 1 ]; then
		quick_exclusive "mount_devfs" "linuxfs"
	fi

	QUICK_OPTION_MOUNT_DEVFS=1
}

quick_set_nomount_devfs()
{
	QUICK_OPTION_MOUNT_DEVFS=0
}

quick_run_boot()
{
	if [ "${QUICK_OPTION_BOOT}" = 0 ]; then
		return 0
	fi

	lib_debug "Setting the boot flag to the ${QUICK_JAILNAME} jail ..."

	appjail jail boot on "${QUICK_JAILNAME}" || exit $?
}

quick_set_boot()
{
	QUICK_OPTION_BOOT=1
}

quick_set_noboot()
{
	QUICK_OPTION_BOOT=0
}

quick_run_priority()
{
	if [ "${QUICK_OPTION_PRIORITY}" = 0 ]; then
		return 0
	fi

	quick_chknumber "priority" "${QUICK_OPTION_PRIORITY}"

	lib_debug "Setting priority ${QUICK_OPTION_PRIORITY} to the ${QUICK_JAILNAME} jail ..."

	appjail jail priority -p "${QUICK_OPTION_PRIORITY}" -- "${QUICK_JAILNAME}" || exit $?
}

quick_set_priority()
{
	local priority

	priority="$1"

	quick_reqoption "priority" "${priority}"
	quick_chknumber "priority" "${priority}"

	QUICK_OPTION_PRIORITY="${priority}"
}

quick_run_healthcheck()
{
	local errlevel

	if [ ${QUICK_OPTION_HEALTH} -eq 0 ]; then
		return 0
	fi

	lib_debug "Configuring healthcheckers ..."

	lib_keys_list "${QUICK_KEY_HEALTH}" | sort -n | while IFS= read -r nro
	do
		hchk_set_cmd="appjail healthcheck set"

		health_cmd=`lib_keys_get "${QUICK_KEY_HEALTH}" "${nro}" "health_cmd"`
		if ! lib_check_empty "${health_cmd}"; then
			escape_health_cmd=`lib_escape_string "${health_cmd}"`
			hchk_set_cmd="${hchk_set_cmd} -h \"${escape_health_cmd}\""
		fi

		interval=`lib_keys_get "${QUICK_KEY_HEALTH}" "${nro}" "interval"`
		if ! lib_check_empty "${interval}"; then
			escape_interval=`lib_escape_string "${interval}"`
			hchk_set_cmd="${hchk_set_cmd} -i \"${escape_interval}\""
		fi

		kill_after=`lib_keys_get "${QUICK_KEY_HEALTH}" "${nro}" "kill_after"`
		if ! lib_check_empty "${kill_after}"; then
			escape_kill_after=`lib_escape_string "${kill_after}"`
			hchk_set_cmd="${hchk_set_cmd} -k \"${escape_kill_after}\""
		fi

		name=`lib_keys_get "${QUICK_KEY_HEALTH}" "${nro}" "name"`
		if ! lib_check_empty "${name}"; then
			escape_name=`lib_escape_string "${name}"`
			hchk_set_cmd="${hchk_set_cmd} -N \"${escape_name}\""
		fi

		recover_cmd=`lib_keys_get "${QUICK_KEY_HEALTH}" "${nro}" "recover_cmd"`
		if ! lib_check_empty "${recover_cmd}"; then
			escape_recover_cmd=`lib_escape_string "${recover_cmd}"`
			hchk_set_cmd="${hchk_set_cmd} -r \"${escape_recover_cmd}\""
		fi

		recover_kill_after=`lib_keys_get "${QUICK_KEY_HEALTH}" "${nro}" "recover_kill_after"`
		if ! lib_check_empty "${recover_kill_after}"; then
			escape_recover_kill_after=`lib_escape_string "${recover_kill_after}"`
			hchk_set_cmd="${hchk_set_cmd} -K \"${escape_recover_kill_after}\""
		fi

		recover_timeout=`lib_keys_get "${QUICK_KEY_HEALTH}" "${nro}" "recover_timeout"`
		if ! lib_check_empty "${recover_timeout}"; then
			escape_recover_timeout=`lib_escape_string "${recover_timeout}"`
			hchk_set_cmd="${hchk_set_cmd} -u \"${escape_recover_timeout}\""
		fi

		recover_timeout_signal=`lib_keys_get "${QUICK_KEY_HEALTH}" "${nro}" "recover_timeout_signal"`
		if ! lib_check_empty "${recover_timeout_signal}"; then
			escape_recover_timeout_signal=`lib_escape_string "${recover_timeout_signal}"`
			hchk_set_cmd="${hchk_set_cmd} -l \"${escape_recover_timeout_signal}\""
		fi

		recover_total=`lib_keys_get "${QUICK_KEY_HEALTH}" "${nro}" "recover_total"`
		if ! lib_check_empty "${recover_total}"; then
			escape_recover_total=`lib_escape_string "${recover_total}"`
			hchk_set_cmd="${hchk_set_cmd} -T \"${escape_recover_total}\""
		fi

		retries=`lib_keys_get "${QUICK_KEY_HEALTH}" "${nro}" "retries"`
		if ! lib_check_empty "${retries}"; then
			escape_retries=`lib_escape_string "${retries}"`
			hchk_set_cmd="${hchk_set_cmd} -R \"${escape_retries}\""
		fi

		start_period=`lib_keys_get "${QUICK_KEY_HEALTH}" "${nro}" "start_period"`
		if ! lib_check_empty "${start_period}"; then
			escape_start_period=`lib_escape_string "${start_period}"`
			hchk_set_cmd="${hchk_set_cmd} -s \"${escape_start_period}\""
		fi

		timeout=`lib_keys_get "${QUICK_KEY_HEALTH}" "${nro}" "timeout"`
		if ! lib_check_empty "${timeout}"; then
			escape_timeout=`lib_escape_string "${timeout}"`
			hchk_set_cmd="${hchk_set_cmd} -t \"${escape_timeout}\""
		fi

		timeout_signal=`lib_keys_get "${QUICK_KEY_HEALTH}" "${nro}" "timeout_signal"`
		if ! lib_check_empty "${timeout_signal}"; then
			escape_timeout_signal=`lib_escape_string "${timeout_signal}"`
			hchk_set_cmd="${hchk_set_cmd} -S \"${escape_timeout_signal}\""
		fi

		lib_debug "healthcheck#${nro}: health_cmd:${health_cmd} interval:${interval} kill_after:${kill_after} name:${name} recover_cmd:${recover_cmd} recover_kill_after:${recover_kill_after} recover_timeout:${recover_timeout} recover_timeout_signal:${recover_timeout_signal} recover_total:${recover_total} retries:${retries} start_period:${start_period} timeout:${timeout} timeout_signal:${timeout_signal}"

		hchk_set_cmd="${hchk_set_cmd} -- \"${QUICK_JAILNAME}\""

		sh -c "${hchk_set_cmd}"

		errlevel=$?
		if [ ${errlevel} -ne 0 ]; then
			lib_err ${errlevel} "An error occurred while adding the healthchecker (${nro}) to ${QUICK_JAILNAME} jail."
		fi
	done

	errlevel=$?
	if [ ${errlevel} -ne 0 ]; then
		exit ${errlevel}
	fi
}

quick_set_healthcheck()
{
	local params="$1"

	local health_cmd=
	local interval=
	local kill_after=
	local name=
	local recover_cmd=
	local recover_kill_after=
	local recover_timeout=
	local recover_timeout_signal=
	local recover_total=
	local retries=
	local start_period=
	local timeout=
	local timeout_signal=

	if ! lib_check_empty "${params}"; then
		params=`lib_split_jailparams "${params}"` || exit $?
		local total_items=`printf "%s\n" "${params}" | wc -l`
		local current_index=0

		local arg parameter value
		while [ ${current_index} -lt ${total_items} ]; do 
			current_index=$((current_index+1))

			arg=`printf "%s\n" "${params}" | head -${current_index} | tail -n 1`
			if lib_check_empty "${arg}"; then
				continue
			fi

			parameter=`lib_jailparam_name "${arg}" :`
			value=`lib_jailparam_value "${arg}" :`

			case "${parameter}" in
				health_cmd)
					health_cmd="${value}"
					;;
				interval)
					interval="${value}"
					;;
				kill_after)
					kill_after="${value}"
					;;
				name)
					name="${value}"
					;;
				recover_cmd)
					recover_cmd="${value}"
					;;
				recover_kill_after)
					recover_kill_after="${value}"
					;;
				recover_timeout)
					recover_timeout="${value}"
					;;
				recover_timeout_signal)
					recover_timeout_signal="${value}"
					;;
				recover_total)
					recover_total="${value}"
					;;
				retries)
					retries="${value}"
					;;
				start_period)
					start_period="${value}"
					;;
				timeout)
					timeout="${value}"
					;;
				timeout_signal)
					timeout_signal="${value}"
					;;
				*)
					lib_err ${EX_DATAERR} -- "${parameter} (healthcheck): parameter not found."
					;;
			esac
		done

		if [ -n "${interval}" ] && ! lib_check_number "${interval}"; then
			lib_err ${EX_DATAERR} -- "${interval}: Invalid interval."
		fi

		if [ -n "${kill_after}" ] && ! lib_check_number "${kill_after}"; then
			lib_err ${EX_DATAERR} -- "${kill_after}: Invalid kill_after."
		fi

		if [ -n "${recover_kill_after}" ] && ! lib_check_number "${recover_kill_after}"; then
			lib_err ${EX_DATAERR} -- "${recover_kill_after}: Invalid recover_kill_after."
		fi

		if [ -n "${recover_timeout}" ] && ! lib_check_number "${recover_timeout}"; then
			lib_err ${EX_DATAERR} -- "${recover_timeout}: Invalid recover_timeout."
		fi

		if [ -n "${recover_total}" ] && ! lib_check_number "${recover_total}"; then
			lib_err ${EX_DATAERR} -- "${recover_total}: Invalid recover_total."
		fi

		if [ -n "${retries}" ] && ! lib_check_number "${retries}"; then
			lib_err ${EX_DATAERR} -- "${retries}: Invalid retries."
		fi

		if [ -n "${start_period}" ] && ! lib_check_number "${start_period}"; then
			lib_err ${EX_DATAERR} -- "${start_period}: Invalid start_period."
		fi

		if [ -n "${timeout}" ] && ! lib_check_number "${timeout}"; then
			lib_err ${EX_DATAERR} -- "${timeout}: Invalid timeout."
		fi
	fi

	local nro

	lib_keys_mk "${QUICK_KEY_HEALTH}"
	nro=`lib_keys_append "${QUICK_KEY_HEALTH}" "health_cmd" "${health_cmd}"`
	lib_keys_set "${QUICK_KEY_HEALTH}" "${nro}" "interval" "${interval}"
	lib_keys_set "${QUICK_KEY_HEALTH}" "${nro}" "kill_after" "${kill_after}"
	lib_keys_set "${QUICK_KEY_HEALTH}" "${nro}" "name" "${name}"
	lib_keys_set "${QUICK_KEY_HEALTH}" "${nro}" "recover_cmd" "${recover_cmd}"
	lib_keys_set "${QUICK_KEY_HEALTH}" "${nro}" "recover_kill_after" "${recover_kill_after}"
	lib_keys_set "${QUICK_KEY_HEALTH}" "${nro}" "recover_timeout" "${recover_timeout}"
	lib_keys_set "${QUICK_KEY_HEALTH}" "${nro}" "recover_timeout_signal" "${recover_timeout_signal}"
	lib_keys_set "${QUICK_KEY_HEALTH}" "${nro}" "recover_total" "${recover_total}"
	lib_keys_set "${QUICK_KEY_HEALTH}" "${nro}" "retries" "${retries}"
	lib_keys_set "${QUICK_KEY_HEALTH}" "${nro}" "start_period" "${start_period}"
	lib_keys_set "${QUICK_KEY_HEALTH}" "${nro}" "timeout" "${timeout}"
	lib_keys_set "${QUICK_KEY_HEALTH}" "${nro}" "timeout_signal" "${timeout_signal}"

	QUICK_OPTION_HEALTH=1
}

quick_run_tzdata()
{
	local errlevel

	if [ "${QUICK_OPTION_USE_TZDATA}" = 0 ]; then
		return 0
	fi

	mkdir -p "${QUICK_JAILPATH}/jail/etc" || exit $?

	local tzdata="${QUICK_OPTION_TZDATA}"
	local jail_tzdata="${QUICK_JAILPATH}/jail/etc/localtime"

	if lib_check_empty "${tzdata}"; then
		if [ -f "/etc/localtime" ]; then
			lib_debug "Copying /etc/localtime as ${jail_tzdata}"

			cp -a "/etc/localtime" "${jail_tzdata}"
		else
			lib_err ${EX_NOINPUT} "/etc/localtime: file does not exist."
		fi
	else
		lib_debug "Linking /usr/share/zoneinfo/${tzdata} -> ${jail_tzdata}"

		ln -s "/usr/share/zoneinfo/${tzdata}" "${jail_tzdata}"
	fi

	errlevel=$?
	if [ ${errlevel} -ne 0 ]; then
		lib_err ${errlevel} "Error creating ${jail_tzdata}"
	fi
}

quick_set_tzdata()
{
	QUICK_OPTION_USE_TZDATA=1
	QUICK_OPTION_TZDATA="$1"
}

quick_set_notzdata()
{
	QUICK_OPTION_USE_TZDATA=0
}

quick_set_release()
{
	local release

	release="$1"; quick_reqoption "release" "${release}"

	QUICK_OPTION_RELEASE="${release}"
}

quick_run_resolv_conf()
{
	local errlevel
	
	if [ ${QUICK_OPTION_USE_RESOLV_CONF} -eq 0 ]; then
		return 0
	fi

	local resolv_conf jail_resolv_conf

	resolv_conf="${QUICK_OPTION_RESOLV_CONF}"
	jail_resolv_conf="${QUICK_JAILPATH}/jail/etc/resolv.conf"

	lib_debug "Copying ${resolv_conf} as ${jail_resolv_conf}"

	cp -a -- "${resolv_conf}" "${jail_resolv_conf}"

	errlevel=$?
	if [ ${errlevel} -ne 0 ]; then
		lib_err ${errlevel} "Error copying ${resolv_conf} as ${jail_resolv_conf}"
	fi
}

quick_set_resolv_conf()
{
	local resolv_conf="$1"

	if lib_check_empty "${resolv_conf}"; then
		# Use default value
		resolv_conf="${QUICK_OPTION_RESOLV_CONF}"
	fi

	if [ ! -f "${resolv_conf}" ]; then
		lib_err ${EX_NOINPUT} -- "${resolv_conf}: file does not exist."
	fi

	QUICK_OPTION_USE_RESOLV_CONF=1
	QUICK_OPTION_RESOLV_CONF="${resolv_conf}"
}

quick_set_noresolv_conf()
{
	QUICK_OPTION_USE_RESOLV_CONF=0
}

quick_run_copy()
{
	local errlevel

	if [ -z "${QUICK_OPTION_FILE}" -a -z "${QUICK_OPTION_FILES}" ]; then
		return 0
	fi

	local files
	files="`lib_generate_tempfile`" || exit $?

	local escape_temp_files
	escape_temp_files=`lib_escape_string "${files}"`

	lib_atexit_add "rm -f \"${escape_temp_files}\""

	if [ -n "${QUICK_OPTION_FILE}" ]; then
		lib_debug "Adding files (${QUICK_OPTION_FILE}) to the list of files to copy ..."

		lib_split_jailparams "${QUICK_OPTION_FILE}" >> "${files}"
	fi

	if [ -n "${QUICK_OPTION_FILES}" ]; then
		lib_debug "Adding files in (${QUICK_OPTION_FILES}) to the list of files to copy ..."

		local files2copy
		files2copy=`lib_split_jailparams "${QUICK_OPTION_FILES}"` || exit $?

		printf "%s\n" "${files2copy}" | while IFS= read -r file
		do
			lib_debug "Reading ${file} ..."

			# Can be removed at this point.
			if [ ! -f "${file}" ]; then
				lib_err ${EX_NOINPUT} -- "${file}: file does not exist."
			fi

			cat -- "${file}"
		done >> "${files}"

		errlevel=$?
		if [ ${errlevel} -ne 0 ]; then
			exit ${errlevel}
		fi
	fi

	lib_safe_copy_lst -l "${files}" -s "${QUICK_OPTION_COPYDIR}" -d "${QUICK_JAILPATH}/jail"
}

quick_set_copydir()
{
	local copydir

	copydir="$1"; quick_reqoption "copydir" "${copydir}"

	if [ ! -d "${copydir}" ]; then
		lib_err ${EX_NOINPUT} -- "${copydir}: does not exist or is not a directory."
	fi

	QUICK_OPTION_COPYDIR="${copydir}"
}

quick_set_file()
{
	local file

	file="$1"; quick_reqoption "file" "${file}"
	file=`lib_escape_string "${file}" "" '\"' "-"`

	if [ -z "${QUICK_OPTION_FILE}" ]; then
		QUICK_OPTION_FILE="\"${file}\""
	else
		QUICK_OPTION_FILE="${QUICK_OPTION_FILE} \"${file}\""
	fi
}

quick_set_files()
{
	local files

	files="$1"; quick_reqoption "files" "${files}"
	if [ ! -f "${files}" ]; then
		lib_err ${EX_NOINPUT} -- "${files}: file does not exist."
	fi

	files=`lib_escape_string "${files}" "" '\"' "-"`
	if [ -z "${QUICK_OPTION_FILES}" ]; then
		QUICK_OPTION_FILES="\"${files}\""
	else
		QUICK_OPTION_FILES="${QUICK_OPTION_FILES} \"${files}\""
	fi
}

quick_set_template()
{
	local template

	template="$1"; quick_reqoption "template" "${template}"

	QUICK_OPTION_TEMPLATE="${template}"
}

quick_set_initscript()
{
	local initscript

	initscript="$1"; quick_reqoption "initscript" "${initscript}"

	QUICK_OPTION_INITSCRIPT="${initscript}"
}

quick_set_osversion()
{
	local osversion

	osversion="$1"; quick_reqoption "osversion" "${osversion}"

	QUICK_OPTION_OSVERSION="${osversion}"
}

quick_set_type()
{
	local jail_type

	jail_type="$1"; quick_reqoption "type" "${jail_type}"

	QUICK_OPTION_JAILTYPE="${jail_type}"
}

quick_set_clone+jail()
{
	if [ ${QUICK_OPTION_CLONE_RELEASE} -eq 1 ]; then
		quick_exclusive "clone+jail" "clone+release"
	elif [ ${QUICK_OPTION_COPY} -eq 1 ]; then
		quick_exclusive "clone+jail" "copy"
	elif [ ${QUICK_OPTION_EMPTY} -eq 1 ]; then
		quick_exclusive "clone+jail" "empty"
	elif [ ${QUICK_OPTION_IMPORT_JAIL} -eq 1 ]; then
		quick_exclusive "clone+jail" "import+jail"
	elif [ ${QUICK_OPTION_IMPORT_ROOT} -eq 1 ]; then
		quick_exclusive "clone+jail" "import+root"
	elif [ ${QUICK_OPTION_TINY_IMPORT} -eq 1 ]; then
		quick_exclusive "clone+jail" "tiny+import"
	elif [ ${QUICK_OPTION_ZFS_IMPORT_JAIL} -eq 1 ]; then
		quick_exclusive "clone+jail" "zfs+import+jail"
	elif [ ${QUICK_OPTION_ZFS_IMPORT_ROOT} -eq 1 ]; then
		quick_exclusive "clone+jail" "zfs+import+root"
	fi

	local jail2clone
	jail2clone="$1"; quick_reqoption "clone+jail" "${jail2clone}"

	QUICK_OPTION_INSTALL_METHOD="clone+jail=${jail2clone}"
	QUICK_OPTION_CLONE_JAIL=1
}

quick_set_clone+release()
{
	if [ ${QUICK_OPTION_CLONE_JAIL} -eq 1 ]; then
		quick_exclusive "clone+release" "clone+jail"
	elif [ ${QUICK_OPTION_COPY} -eq 1 ]; then
		quick_exclusive "clone+release" "copy"
	elif [ ${QUICK_OPTION_EMPTY} -eq 1 ]; then
		quick_exclusive "clone+release" "empty"
	elif [ ${QUICK_OPTION_IMPORT_JAIL} -eq 1 ]; then
		quick_exclusive "clone+release" "import+jail"
	elif [ ${QUICK_OPTION_IMPORT_ROOT} -eq 1 ]; then
		quick_exclusive "clone+release" "import+root"
	elif [ ${QUICK_OPTION_TINY_IMPORT} -eq 1 ]; then
		quick_exclusive "clone+release" "tiny+import"
	elif [ ${QUICK_OPTION_ZFS_IMPORT_JAIL} -eq 1 ]; then
		quick_exclusive "clone+release" "zfs+import+jail"
	elif [ ${QUICK_OPTION_ZFS_IMPORT_ROOT} -eq 1 ]; then
		quick_exclusive "clone+release" "zfs+import+root"
	fi

	local snapshot_name
	snapshot_name="$1"; quick_reqoption "clone+release" "${snapshot_name}"

	QUICK_OPTION_INSTALL_METHOD="clone+release=${snapshot_name}"
	QUICK_OPTION_CLONE_RELEASE=1
}

quick_set_copy()
{
	if [ ${QUICK_OPTION_CLONE_JAIL} -eq 1 ]; then
		quick_exclusive "copy" "clone+jail"
	elif [ ${QUICK_OPTION_CLONE_RELEASE} -eq 1 ]; then
		quick_exclusive "copy" "clone+release"
	elif [ ${QUICK_OPTION_EMPTY} -eq 1 ]; then
		quick_exclusive "copy" "empty"
	elif [ ${QUICK_OPTION_IMPORT_JAIL} -eq 1 ]; then
		quick_exclusive "copy" "import+jail"
	elif [ ${QUICK_OPTION_IMPORT_ROOT} -eq 1 ]; then
		quick_exclusive "copy" "import+root"
	elif [ ${QUICK_OPTION_TINY_IMPORT} -eq 1 ]; then
		quick_exclusive "copy" "tiny+import"
	elif [ ${QUICK_OPTION_ZFS_IMPORT_JAIL} -eq 1 ]; then
		quick_exclusive "copy" "zfs+import+jail"
	elif [ ${QUICK_OPTION_ZFS_IMPORT_ROOT} -eq 1 ]; then
		quick_exclusive "copy" "zfs+import+root"
	fi

	local jail2copy
	jail2copy="$1"; quick_reqoption "copy" "${jail2copy}"

	QUICK_OPTION_INSTALL_METHOD="copy=${jail2copy}"
	QUICK_OPTION_COPY=1
}

quick_set_empty()
{
	if [ ${QUICK_OPTION_CLONE_JAIL} -eq 1 ]; then
		quick_exclusive "empty" "clone+jail"
	elif [ ${QUICK_OPTION_CLONE_RELEASE} -eq 1 ]; then
		quick_exclusive "empty" "clone+release"
	elif [ ${QUICK_OPTION_COPY} -eq 1 ]; then
		quick_exclusive "empty" "copy"
	elif [ ${QUICK_OPTION_IMPORT_JAIL} -eq 1 ]; then
		quick_exclusive "empty" "import+jail"
	elif [ ${QUICK_OPTION_IMPORT_ROOT} -eq 1 ]; then
		quick_exclusive "empty" "import+root"
	elif [ ${QUICK_OPTION_TINY_IMPORT} -eq 1 ]; then
		quick_exclusive "empty" "tiny+import"
	elif [ ${QUICK_OPTION_ZFS_IMPORT_JAIL} -eq 1 ]; then
		quick_exclusive "empty" "zfs+import+jail"
	elif [ ${QUICK_OPTION_ZFS_IMPORT_ROOT} -eq 1 ]; then
		quick_exclusive "empty" "zfs+import+root"
	fi

	QUICK_OPTION_INSTALL_METHOD="empty"
	QUICK_OPTION_EMPTY=1
}

quick_set_import+jail()
{
	if [ ${QUICK_OPTION_CLONE_JAIL} -eq 1 ]; then
		quick_exclusive "import+jail" "clone+jail"
	elif [ ${QUICK_OPTION_CLONE_RELEASE} -eq 1 ]; then
		quick_exclusive "import+jail" "clone+release"
	elif [ ${QUICK_OPTION_COPY} -eq 1 ]; then
		quick_exclusive "import+jail" "copy"
	elif [ ${QUICK_OPTION_EMPTY} -eq 1 ]; then
		quick_exclusive "import+jail" "empty"
	elif [ ${QUICK_OPTION_IMPORT_ROOT} -eq 1 ]; then
		quick_exclusive "import+jail" "import+root"
	elif [ ${QUICK_OPTION_TINY_IMPORT} -eq 1 ]; then
		quick_exclusive "import+jail" "tiny+import"
	elif [ ${QUICK_OPTION_ZFS_IMPORT_JAIL} -eq 1 ]; then
		quick_exclusive "import+jail" "zfs+import+jail"
	elif [ ${QUICK_OPTION_ZFS_IMPORT_ROOT} -eq 1 ]; then
		quick_exclusive "import+jail" "zfs+import+root"
	fi

	local image
	image="$1"; quick_reqoption "import+jail" "${image}"

	QUICK_OPTION_INSTALL_METHOD="import+jail=${image}"
	QUICK_OPTION_IMPORT_JAIL=1
}

quick_set_import+root()
{
	if [ ${QUICK_OPTION_CLONE_JAIL} -eq 1 ]; then
		quick_exclusive "import+root" "clone+jail"
	elif [ ${QUICK_OPTION_CLONE_RELEASE} -eq 1 ]; then
		quick_exclusive "import+root" "clone+release"
	elif [ ${QUICK_OPTION_COPY} -eq 1 ]; then
		quick_exclusive "import+root" "copy"
	elif [ ${QUICK_OPTION_EMPTY} -eq 1 ]; then
		quick_exclusive "import+root" "empty"
	elif [ ${QUICK_OPTION_IMPORT_JAIL} -eq 1 ]; then
		quick_exclusive "import+root" "import+jail"
	elif [ ${QUICK_OPTION_TINY_IMPORT} -eq 1 ]; then
		quick_exclusive "import+root" "tiny+import"
	elif [ ${QUICK_OPTION_ZFS_IMPORT_JAIL} -eq 1 ]; then
		quick_exclusive "import+root" "zfs+import+jail"
	elif [ ${QUICK_OPTION_ZFS_IMPORT_ROOT} -eq 1 ]; then
		quick_exclusive "import+root" "zfs+import+root"
	fi

	local image
	image="$1"; quick_reqoption "import+root" "${image}"

	QUICK_OPTION_INSTALL_METHOD="import+root=${image}"
	QUICK_OPTION_IMPORT_ROOT=1
}

quick_set_tiny+import()
{
	if [ ${QUICK_OPTION_CLONE_JAIL} -eq 1 ]; then
		quick_exclusive "tiny+import" "clone+jail"
	elif [ ${QUICK_OPTION_CLONE_RELEASE} -eq 1 ]; then
		quick_exclusive "tiny+import" "clone+release"
	elif [ ${QUICK_OPTION_COPY} -eq 1 ]; then
		quick_exclusive "tiny+import" "copy"
	elif [ ${QUICK_OPTION_EMPTY} -eq 1 ]; then
		quick_exclusive "tiny+import" "empty"
	elif [ ${QUICK_OPTION_IMPORT_JAIL} -eq 1 ]; then
		quick_exclusive "tiny+import" "import+jail"
	elif [ ${QUICK_OPTION_IMPORT_ROOT} -eq 1 ]; then
		quick_exclusive "tiny+import" "import+root"
	elif [ ${QUICK_OPTION_ZFS_IMPORT_JAIL} -eq 1 ]; then
		quick_exclusive "tiny+import" "zfs+import+jail"
	elif [ ${QUICK_OPTION_ZFS_IMPORT_ROOT} -eq 1 ]; then
		quick_exclusive "tiny+import" "zfs+import+root"
	fi

	local image
	image="$1"; quick_reqoption "tiny+import" "${image}"

	QUICK_OPTION_INSTALL_METHOD="tiny+import=${image}"
	QUICK_OPTION_TINY_IMPORT=1
}

quick_set_zfs+import+jail()
{
	if [ ${QUICK_OPTION_CLONE_JAIL} -eq 1 ]; then
		quick_exclusive "zfs+import+jail" "clone+jail"
	elif [ ${QUICK_OPTION_CLONE_RELEASE} -eq 1 ]; then
		quick_exclusive "zfs+import+jail" "clone+release"
	elif [ ${QUICK_OPTION_COPY} -eq 1 ]; then
		quick_exclusive "zfs+import+jail" "copy"
	elif [ ${QUICK_OPTION_EMPTY} -eq 1 ]; then
		quick_exclusive "zfs+import+jail" "empty"
	elif [ ${QUICK_OPTION_IMPORT_JAIL} -eq 1 ]; then
		quick_exclusive "zfs+import+jail" "import+jail"
	elif [ ${QUICK_OPTION_IMPORT_ROOT} -eq 1 ]; then
		quick_exclusive "zfs+import+jail" "import+root"
	elif [ ${QUICK_OPTION_TINY_IMPORT} -eq 1 ]; then
		quick_exclusive "zfs+import+jail" "tiny+import"
	elif [ ${QUICK_OPTION_ZFS_IMPORT_ROOT} -eq 1 ]; then
		quick_exclusive "zfs+import+jail" "zfs+import+root"
	fi

	local image
	image="$1"; quick_reqoption "zfs+import+jail" "${image}"

	QUICK_OPTION_INSTALL_METHOD="zfs+import+jail=${image}"
	QUICK_OPTION_ZFS_IMPORT_JAIL=1
}

quick_set_zfs+import+root()
{
	if [ ${QUICK_OPTION_CLONE_JAIL} -eq 1 ]; then
		quick_exclusive "zfs+import+root" "clone+jail"
	elif [ ${QUICK_OPTION_CLONE_RELEASE} -eq 1 ]; then
		quick_exclusive "zfs+import+root" "clone+release"
	elif [ ${QUICK_OPTION_COPY} -eq 1 ]; then
		quick_exclusive "zfs+import+root" "copy"
	elif [ ${QUICK_OPTION_EMPTY} -eq 1 ]; then
		quick_exclusive "zfs+import+root" "empty"
	elif [ ${QUICK_OPTION_IMPORT_JAIL} -eq 1 ]; then
		quick_exclusive "zfs+import+root" "import+jail"
	elif [ ${QUICK_OPTION_IMPORT_ROOT} -eq 1 ]; then
		quick_exclusive "zfs+import+root" "import+root"
	elif [ ${QUICK_OPTION_TINY_IMPORT} -eq 1 ]; then
		quick_exclusive "zfs+import+root" "tiny+import"
	elif [ ${QUICK_OPTION_ZFS_IMPORT_JAIL} -eq 1 ]; then
		quick_exclusive "zfs+import+root" "zfs+import+jail"
	fi

	local image
	image="$1"; quick_reqoption "zfs+import+root" "${image}"

	QUICK_OPTION_INSTALL_METHOD="zfs+import+root=${image}"
	QUICK_OPTION_ZFS_IMPORT_ROOT=1
}

quick_set_osarch()
{
	local osarch

	osarch="$1"; quick_reqoption "osarch" "${osarch}"

	QUICK_OPTION_OSARCH="${osarch}"
}

quick_set_overwrite()
{
	local opts="$1"

	if lib_check_empty "${opts}"; then
		QUICK_OPTION_OVERWRITE=1
	else
		case "${opts}" in
			force|recursive|force+recursive) ;;
			*) lib_err ${EX_DATAERR} "overwrite syntax: [force|recursive|force+recursive]"
		esac

		QUICK_OPTION_OVERWRITE="${opts}"
	fi
}

quick_run_pkg()
{
	local errlevel

	if lib_check_empty "${QUICK_OPTION_PKG}"; then
		return 0
	fi

	if [ "${QUICK_OPTION_START}" = 0 ] || ! appjail status -q -- "${QUICK_JAILNAME}"; then
		lib_err ${EX_CONFIG} "Packages '${QUICK_OPTION_PKG}' cannot be installed because the jail is not started."
	fi

	lib_split_jailparams "${QUICK_OPTION_PKG}" | while IFS= read -r package; do
		lib_debug "Installing package '${package}' ..."

		appjail pkg jail "${QUICK_JAILNAME}" install -y -- "${package}"

		errlevel=$?

		if [ ${errlevel} -ne 0 ]; then
			lib_err ${errlevel} "Failed to install package '${package}'."
		fi
	done

	errlevel=$?

	if [ ${errlevel} -ne 0 ]; then
		exit ${errlevel}
	fi
}

quick_set_pkg()
{
	local package

	package="$1"; quick_reqoption "pkg" "${package}"
	package=`lib_escape_string "${package}" "" '\"' "-"`

	if [ -z "${QUICK_OPTION_PKG}" ]; then
		QUICK_OPTION_PKG="\"${package}\""
	else
		QUICK_OPTION_PKG="${QUICK_OPTION_PKG} \"${package}\""
	fi
}

quick_set_nooverwrite()
{
	QUICK_OPTION_OVERWRITE=0
}

quick_vimage()
{
	if ! lib_check_vimage; then
		lib_err ${EX_UNAVAILABLE} "This kernel doesn't support VIMAGE!"
	fi
}

quick_vnetiface()
{
	local interface="$1"
	if [ -z "${interface}" ]; then
		lib_err ${EX_USAGE} "usage: quick_vnetiface interface"
	fi

	quick_list_vifaces | while IFS= read -r vnet_interface
	do
		if [ "${interface}" = "${vnet_interface}" ]; then
			printf "%s\n" "${vnet_interface}"
		fi
	done
}

quick_list_vifaces()
{
	lib_ajconf getColumn -Ppt "${QUICK_TEMP_TEMPLATE}" vnet.interface
}

quick_iface()
{
	local interface="$1"
	if [ -z "${interface}" ]; then
		lib_err ${EX_USAGE} "usage: quick_iface interface"
	fi

	if lib_check_ifacelen "${interface}"; then
		lib_err ${EX_DATAERR} -- "${interface}: interface name too long."
	fi

	if ! lib_check_interfacename "${interface}"; then
		lib_err ${EX_DATAERR} -- "${interface}: invalid interface name."
	fi

	if ! lib_check_iface "${interface}"; then
		lib_err ${EX_NOINPUT} -- "${interface}: interface does not exist."
	fi
}

quick_exclusive()
{
	local option="$1" conflict="$2"
	if [ -z "${option}" -o -z "${conflict}" ]; then
		lib_err ${EX_USAGE} "usage: quick_exclusive option conflict"
	fi

	lib_err ${EX_DATAERR} -- "${option}, ${conflict}: options are mutually exclusive."
}

quick_chknumber()
{
	local option="$1" value="$2"
	if [ -z "${option}" ]; then
		lib_err ${EX_USAGE} "usage: quick_chknumber option value"
	fi

	if ! lib_check_number "${value}"; then
		lib_err ${EX_DATAERR} "${option}: A positive number is required!"
	fi
}

quick_reqoption()
{
	local option="$1" value="$2"
	if [ -z "${option}" ]; then
		lib_err ${EX_USAGE} "usage: quick_reqoption option value"
	fi

	if lib_check_empty "${value}"; then
		lib_err ${EX_DATAERR} -- "${option}: option requires an argument."
	fi
}

quick_reqoptions()
{
	local option="$1" options="$2"
	if [ -z "${option}" -o -z "${options}" ]; then
		lib_err ${EX_USAGE} "usage: quick_reqoptions option options"
	fi

	lib_err ${EX_CONFIG} "${option} requires the following options: ${options}."
}

quick_assign_devfs_ruleset()
{
	if [ ${QUICK_OPTION_DEVICE} -eq 1 ]; then
		if lib_check_empty "${QUICK_OPTION_DEVFS_RULESET}"; then
			QUICK_OPTION_DEVFS_RULESET="auto"
		fi

		lib_debug "Assigning a ruleset ..."

		QUICK_OPTION_DEVFS_RULESET=`appjail devfs ruleset assign -r "${QUICK_OPTION_DEVFS_RULESET}" -- "${QUICK_JAILNAME}"` || exit $?
	else
		if lib_check_empty "${QUICK_OPTION_DEVFS_RULESET}"; then
			QUICK_OPTION_DEVFS_RULESET="${DEFAULT_DEVFS_RULESET}"
		fi
	fi

	lib_debug "Current ruleset is ${QUICK_OPTION_DEVFS_RULESET}"
}

quick_help()
{
	man 1 appjail-quick
}

quick_usage()
{
	echo "usage: quick <name> [<options> ...]"
}
