#!/bin/sh

__start_jail () {
    local _name _dataset _fulluuid _jail_type  _tag _jail_hostid _jail_path \
          _jail_release _istemplate _cpuset _procfs _state _vnet _nics \
          _jail_zfs_datasets _jail_zfs _clone_check _exec_fib _exec_start _bpf \
          _dhcp _devfs_string _linprocfs _zfs_dataset

    if [ "$1" = "ALL" ] ; then
        __start_jail_all
        exit $?
    fi

    _name=$1
    _dataset="$(__find_jail ${_name})" || exit $?
    _fulluuid="$(__check_name ${_name} ${_dataset})"

    # Prepare the mounts and export _fulluuid
    __hack88_mount ${_fulluuid} ${_dataset} _fulluuid
    _exec_start="$(__get_jail_prop exec_start ${_fulluuid} ${_dataset})"
    _jail_type="$(__get_jail_prop type ${_fulluuid} ${_dataset})"
    _bpf="$(__get_jail_prop bpf ${_fulluuid} ${_dataset})"
    _dhcp="$(__get_jail_prop dhcp ${_fulluuid} ${_dataset})"
    _tag="$(__get_jail_prop tag ${_fulluuid} ${_dataset})"
    _jail_hostid="$(__get_jail_prop hostid ${_fulluuid} ${_dataset})"
    _jail_path="$(__get_jail_prop mountpoint ${_fulluuid} ${_dataset})"
    _jail_release="$(__get_jail_prop release ${_fulluuid} ${_dataset})"
    _istemplate="$(__get_jail_prop istemplate ${_fulluuid} ${_dataset})"
    _cpuset="$(__get_jail_prop cpuset ${_fulluuid} ${_dataset})"
    _procfs="$(__get_jail_prop mount_procfs ${_fulluuid} ${_dataset})"
    _linprocfs="$(__get_jail_prop mount_linprocfs ${_fulluuid} ${_dataset})"
    _state=$(__is_running ${_fulluuid})
    _vnet="$(__get_jail_prop vnet ${_fulluuid} ${_dataset})"
    _exec_fib="$(__get_jail_prop exec_fib ${_fulluuid} ${_dataset})"
    _nics="$(__get_jail_prop interfaces ${_fulluuid} ${_dataset} \
           | awk 'BEGIN { FS = "," } ; { print $1,$2,$3,$4 }')"
    _clone_check="$(zfs get -H origin ${_dataset} | awk '{print $3}')"
    _devfs_string="$(fgrep -xq \
                  "## IOCAGE -- Add DHCP to ruleset 4" /etc/devfs.rules \
                  ; echo $?)"

    if [ "${_state}" ] ; then
        __info "${_fulluuid} (${_tag}) is already up" >&2
        return 1
    fi

    if [ ! -d ${iocroot}/log ] ; then
        mkdir ${iocroot}/log
    fi

    if [ "${_jail_type}" = "jail" ] ; then
        # Check for thick or clone jails and migrate their type
        if [ "${_clone_check}" = "-" ] ; then
            __set_jail_prop type=thickjail "${_fulluuid}" \
                "${pool}/iocell/jails/${_fulluuid}"
        else
            __set_jail_prop type=clonejail "${_fulluuid}" \
                "${pool}/iocell/jails/${_fulluuid}"
        fi
    fi

    for i in ${_nics} ; do
        _nic="$(echo ${i} | awk 'BEGIN { FS = ":" } ; { print $1 }')"
        _bridge="$(echo ${i} | awk 'BEGIN { FS = ":" } ; { print $2 }')"

        if [ -z "${_nic}" -o -z "${_bridge}" ] ; then
            echo "  ERROR  : incorrect interfaces property format" >&2
            echo "  HINT   : check with \"iocell get interfaces ${_fulluuid}\"" >&2
            echo "  Example: vnet0:bridge0" >&2
            exit 1
        fi
    done

    if [ "${_istemplate}" = "yes" ] ; then
        if [ "${_force}" != "1" ] ; then
            echo "  INFO: ${_tag} is a template jail, ignoring start request."
            echo "        (disable template flag with: iocell set template=no ${_tag})"
            return
        else
            __mount_istemplate "${_tag}" "${_jail_release}"
        fi
    fi

    if [ "${_jail_hostid}" != "${hostid}" ] ; then
        if [ -z "$(uname -v | grep -i "freenas")" ] ; then
            echo "ERROR: hostid mismatch, start failed!" >&2
            echo "    jail hostid: ${_jail_hostid}" >&2
            echo "  host's hostid: ${hostid}" >&2
            exit 1
        fi
    fi

    if [ "${_procfs}" = "1" ] ; then
        mount -t procfs proc ${_jail_path}/root/proc
    fi

    if [ "${_linprocfs}" = "1" ] ; then
        if [ ! -e "${_jail_path}/root/compat/linux/proc" ] ; then
            mkdir -p "${_jail_path}/root/compat/linux/proc"
        fi
    fi

    _jail_zfs="$(__get_jail_prop jail_zfs "${_fulluuid}" "${_dataset}")"
    _jail_zfs_datasets="$(__get_jail_prop jail_zfs_dataset "${_fulluuid}" \
        "${_dataset}")"

    if [ "${_jail_zfs}" = "on" ] ; then
        __set_jail_prop allow_mount=1 "${_fulluuid}" "${_dataset}"
        __set_jail_prop enforce_statfs=1 "${_fulluuid}" "${_dataset}"
        __set_jail_prop allow_mount_zfs=1 "${_fulluuid}" "${_dataset}"
        for _zfs_dataset in ${_jail_zfs_datasets} ; do

            _zfs_dataset=$(__zfs_dataset_add_poolname "${_zfs_dataset}")
            zfs set jailed=on "${_zfs_dataset}"

        done
    fi

    if [ "${_dhcp}" = "on" ] ; then
        if [ "${_vnet}" != "on" ] ; then
            __die "vnet is needed to use dhcp, please set vnet=on for ${_fulluuid}"
        elif [ "${_bpf}" = "off" ] ; then
            __die "bpf is needed to use dhcp, please set bpf=yes for ${_fulluuid}"
        fi
    fi

    # Make doubly sure that bpf entry exists since FreeNAS wipes /etc on boot.
    if [ "${_bpf}" = "on" ] ; then
        if [ "${_devfs_string}" != "0" ] ; then
            __bpf_devfs >> /etc/devfs.rules
            service devfs restart 1> /dev/null
        fi
    fi

    if [ "${_jail_type}" = "basejail" ] ; then
        # Check the required filesystems
        __check_basejail "${_fulluuid}" "${_dataset}"
    fi

    if [ "${_jail_type}" = "clonejail" ] ; then
        # Mount old filesystems
        __mount_basejail "${_fulluuid}" "${_jail_release}"
    fi

    if [ "${_linprocfs}" = "1" ] ; then
        # Needs to be down here so basejails can see the new directory
        mount -t linprocfs linproc ${_jail_path}/root/compat/linux/proc
    fi

    if [ "${_vnet}" = "on" -o "${_vnet}" = "-" ] ; then
        if [ ! -z $(sysctl -qn kern.features.vimage) ] ; then
            echo "* Starting ${_fulluuid} (${_tag})"
            __vnet_start "${_fulluuid}" "${_dataset}"

            if [ $? -eq 1 ] ; then
                echo "  ! Start                FAILED" >&2

                if [ "${_jail_type}" = "basejail" -o "${_jail_type}" = "clonejail" ] ; then
                    __umount_basejail "${_fulluuid}" "${_dataset}" >&2
                elif [ "${_jail_type}" = "template" ] ; then
                    __umount_istemplate "${_tag}" >&2
                fi
                exit 1
            else
                echo "  + Started                  OK"
            fi

            echo -n "  + Configuring VNET"
            __networking start "${_fulluuid}" "${_dataset}"

            if [ $? -eq 1 ] ; then
                echo "         FAILED" >&2

                if [ "${_jail_type}" = "basejail" -o "${_jail_type}" = "clonejail" ] ; then
                    __umount_basejail "${_fulluuid}" "${_dataset}" >&2
                elif [ "${_jail_type}" = "template" ] ; then
                    __umount_istemplate "${_tag}" >&2
                fi
                exit 1
            else
                echo "         OK"
            fi
        else
            echo "  ERROR: start failed for ${_fulluuid}" >&2
            echo "  vnet=on but kernel is not VNET capable!" >&2
            echo "  Turn vnet off for this jail or recompile kernel with VNET." >&2

            if [ "${_jail_type}" = "basejail" -o "${_jail_type}" = "clonejail" ] ; then
                __umount_basejail "${_fulluuid}" "${_dataset}" >&2
            elif [ "${_jail_type}" = "template" ] ; then
                __umount_istemplate "${_tag}" >&2
            fi
            exit 1
        fi
    else
        echo "* Starting ${_fulluuid} (${_tag})"
        __legacy_start "${_fulluuid}" "${_dataset}"
        if [ $? -eq 1 ] ; then
            echo "  ! Start                FAILED" >&2
            if [ "${_jail_type}" = "basejail" -o "${_jail_type}" = "clonejail" ] ; then
                __umount_basejail "${_fulluuid}" "${_dataset}" >&2
            elif [ "${_jail_type}" = "template" ] ; then
                __umount_istemplate "${_tag}" >&2
            fi
            exit 1
        else
            echo "  + Started (shared IP mode) OK"
        fi
    fi

    cd "${_jail_path}/root/dev" && ln -s ../var/run/log log &

    __rctl_limits "${_fulluuid}" "${_dataset}"

    if [ "${_cpuset}" != "off" ] ; then
        echo -n "  + Appliyng CPU affinity"
        local jid="$(jls -j ioc-${_fulluuid} jid)"
        cpuset -l "${_cpuset}" -j "${jid}"
        if [ $? -eq 1 ] ; then
            echo "    FAILED" >&2
            if [ "${_jail_type}" = "basejail" -o "${_jail_type}" = "clonejail" ] ; then
                __umount_basejail "${_fulluuid}" "${_dataset}" >&2
            elif [ "${_jail_type}" = "template" ] ; then
                __umount_istemplate "${_tag}" >&2
            fi
            exit 1
        else
            echo "    OK"
        fi
    fi

    if [ "${_jail_zfs}" = "on" ] ; then
        for _zfs_dataset in ${_jail_zfs_datasets} ; do

            _zfs_dataset=$(__zfs_dataset_add_poolname "${_zfs_dataset}")
            zfs jail "ioc-${_fulluuid}" "${_zfs_dataset}"

        done
        jexec "ioc-${_fulluuid}" zfs mount -a
    fi

    __resolv_conf ${_fulluuid} ${_dataset} > ${_jail_path}/root/etc/resolv.conf
    echo -n "  + Starting services"
    setfib ${_exec_fib} jexec ioc-${_fulluuid} ${_exec_start} \
     >> "${iocroot}/log/${_fulluuid}-console.log" 2>&1

    if [ $? -eq 1 ] ; then
        echo "        FAILED" >&2
        if [ "${_jail_type}" = "basejail" -o "${_jail_type}" = "clonejail" ] ; then
            __umount_basejail "${_fulluuid}" "${_dataset}" >&2
        elif [ "${_jail_type}" = "template" ] ; then
            __umount_istemplate "${_tag}" >&2
        fi
        exit 1
    else
        echo "        OK"
    fi

    __set_jail_prop last_started=$(date "+%F_%T") "${_fulluuid}" "${_dataset}" &
}

# Start a VNET jail
__vnet_start () {
    local _fulluuid _dataset _jail_path _fdescfs _tmpfs

    _fulluuid="$1"
    _dataset="$2"
    _jail_path="$(__get_jail_prop mountpoint ${_fulluuid} ${_dataset})"
    _fdescfs="mount.fdescfs=$(__get_jail_prop mount_fdescfs ${_fulluuid} \
        ${_dataset})"
    _tmpfs="allow.mount.tmpfs=$(__get_jail_prop allow_mount_tmpfs ${_fulluuid} \
        ${_dataset})"
    _sysvmsg="sysvmsg=$(__get_jail_prop sysvmsg ${_fulluuid} ${_dataset})"
    _sysvsem="sysvsem=$(__get_jail_prop sysvsem ${_fulluuid} ${_dataset})"
    _sysvshm="sysvshm=$(__get_jail_prop sysvshm ${_fulluuid} ${_dataset})"

    if [ "$(uname -U)" = "903000" ] ; then
      _fdescfs=""
      _tmpfs=""
    fi

    if [ "$(uname -U)" -lt "1004000" ]; then
      _sysvmsg=""
      _sysvsem=""
      _sysvshm=""
    fi

    jail -c vnet \
    name="ioc-${_fulluuid}" \
    host.domainname="$(__get_jail_prop host_domainname ${_fulluuid} \
        ${_dataset})" \
    host.hostname="$(__get_jail_prop host_hostname ${_fulluuid} ${_dataset})" \
    path="${_jail_path}/root" \
    securelevel="$(__get_jail_prop securelevel ${_fulluuid} ${_dataset})" \
    host.hostuuid="${_fulluuid}" \
    devfs_ruleset="$(__get_jail_prop devfs_ruleset ${_fulluuid} ${_dataset})" \
    enforce_statfs="$(__get_jail_prop enforce_statfs ${_fulluuid} \
        ${_dataset})" \
    children.max="$(__get_jail_prop children_max ${_fulluuid} ${_dataset})" \
    allow.set_hostname="$(__get_jail_prop allow_set_hostname ${_fulluuid} \
        ${_dataset})" \
    allow.sysvipc="$(__get_jail_prop allow_sysvipc ${_fulluuid} ${_dataset})" \
    ${_sysvmsg} \
    ${_sysvsem} \
    ${_sysvshm} \
    allow.raw_sockets="$(__get_jail_prop allow_raw_sockets ${_fulluuid} \
        ${_dataset})" \
    allow.chflags="$(__get_jail_prop allow_chflags ${_fulluuid} ${_dataset})" \
    allow.mount="$(__get_jail_prop allow_mount ${_fulluuid} ${_dataset})" \
    allow.mount.devfs="$(__get_jail_prop allow_mount_devfs ${_fulluuid} \
        ${_dataset})" \
    allow.mount.nullfs="$(__get_jail_prop allow_mount_nullfs ${_fulluuid} \
        ${_dataset})" \
    allow.mount.procfs="$(__get_jail_prop allow_mount_procfs ${_fulluuid} \
        ${_dataset})" \
    "${_tmpfs}" \
    allow.mount.zfs="$(__get_jail_prop allow_mount_zfs ${_fulluuid} \
        ${_dataset})" \
    allow.quotas="$(__get_jail_prop allow_quotas ${_fulluuid} ${_dataset})" \
    allow.socket_af="$(__get_jail_prop allow_socket_af ${_fulluuid} \
        ${_dataset})" \
    exec.prestart="$(__findscript ${_fulluuid} prestart ${_dataset})" \
    exec.poststart="$(__findscript ${_fulluuid} poststart ${_dataset})" \
    exec.prestop="$(__findscript ${_fulluuid} prestop ${_dataset})" \
    exec.stop="$(__get_jail_prop exec_stop ${_fulluuid} ${_dataset})" \
    exec.clean="$(__get_jail_prop exec_clean ${_fulluuid} ${_dataset})" \
    exec.timeout="$(__get_jail_prop exec_timeout ${_fulluuid} ${_dataset})" \
    stop.timeout="$(__get_jail_prop stop_timeout ${_fulluuid} ${_dataset})" \
    mount.fstab="${_jail_path}/fstab" \
    mount.devfs="$(__get_jail_prop mount_devfs ${_fulluuid} ${_dataset})" \
    "${_fdescfs}" \
    allow.dying \
    exec.consolelog="${iocroot}/log/${name}-console.log" \
    persist
}

# Start a shared IP jail
__legacy_start () {
    local _fulluuid _dataset _jail_path _ip4_addr _ip6_addr _ip4 _ip6 _exec_fib \
          _fdescfs _tmpfs _default_iface _cur_ip4_iface _cur_ip6_iface \
          _ip4_addr_propline _ip6_addr_propline _new_iface

    _fulluuid="$1"
    _dataset="$2"
    _jail_path="$(__get_jail_prop mountpoint "${_fulluuid}" ${_dataset})"
    _ip4_addr="$(__get_jail_prop ip4_addr "${_fulluuid}" ${_dataset})"
    _ip6_addr="$(__get_jail_prop ip6_addr "${_fulluuid}" ${_dataset})"
    _ip4="$(__get_jail_prop ip4 "${_fulluuid}" ${_dataset})"
    _ip6="$(__get_jail_prop ip6 "${_fulluuid}" ${_dataset})"
    _exec_fib="$(__get_jail_prop exec_fib "${_fulluuid}" ${_dataset})"
    _fdescfs="mount.fdescfs=$(__get_jail_prop mount_fdescfs "${_fulluuid}" \
        ${_dataset})"
    _tmpfs="allow.mount.tmpfs=$(__get_jail_prop allow_mount_tmpfs \
        "${_fulluuid}" ${_dataset})"
    _sysvmsg="sysvmsg=$(__get_jail_prop sysvmsg ${_fulluuid} ${_dataset})"
    _sysvsem="sysvsem=$(__get_jail_prop sysvsem ${_fulluuid} ${_dataset})"
    _sysvshm="sysvshm=$(__get_jail_prop sysvshm ${_fulluuid} ${_dataset})"
    # Get the default and current interfaces specified
    _default_iface="$(__get_default_iface)"
    _cur_ip4_iface=$(echo "${_ip4_addr}" | cut -d '|' -f 1)
    _cur_ip6_iface=$(echo "${_ip6_addr}" | cut -d '|' -f 1)

    if [ "$(uname -U)" = "903000" ];
    then
      _fdescfs=""
      _tmpfs=""
    fi

    if [ "$(uname -U)" -lt "1004000" ]; then
      _sysvmsg=""
      _sysvsem=""
      _sysvshm=""
    fi

    if [ "${_ip4_addr}" = "none" ] ; then
        _ip4_addr=""
    fi

    if [ "${_ip6_addr}" = "none" ] ; then
        _ip6_addr=""
    fi

    # Change the DEFAULT tag to correct iface
    _ip4_addr="$(echo ${_ip4_addr} | sed "s/DEFAULT|/${_default_iface}|/g")"
    _ip6_addr="$(echo ${_ip6_addr} | sed "s/DEFAULT|/${_default_iface}|/g")"

    # TODO: this is mostly a temporary workaround for
    # https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=196474
    if [ "${_ip4}" = 'inherit' ] ; then
        _ip4="inherit"
        _ip4_addr_propline=""
        _ip6="inherit"
        _ip6_addr_propline=""
    else
        _ip4_addr_propline="ip4.addr=${_ip4_addr}"
        _ip6_addr_propline="ip6.addr=${_ip6_addr}"
    fi

    # Check if the user specified they wanted to use an automatic IP4 address
    echo "${_ip4_addr}" | grep -q "AUTOIP4"
    if [ "$?" -eq 0 ] ; then
        __get_autoip4
        if [ -z "${_cur_ip4_iface}" -o "${_cur_ip4_iface}" = "DEFAULT" ] ; then
            _new_iface="DEFAULT"
            _ip4_addr_propline="ip4.addr=${_default_iface}|${auto_ip4}"
        else
            _new_iface="${_cur_ip4_iface}"
            _ip4_addr_propline="ip4.addr=${_cur_ip4_iface}|${auto_ip4}"
        fi
        __set_jail_prop "ip4_addr=${_new_iface}|${auto_ip4}" "${_fulluuid}" \
            "${_dataset}"
    fi

    if [ "${ipv6}" = "on" ] ; then
        jail -c \
        "${_ip4_addr_propline}" \
        ip4.saddrsel="$(__get_jail_prop ip4_saddrsel "${_fulluuid}" \
            ${_dataset})" \
        ip4="${_ip4}" \
        "${_ip6_addr_propline}" \
        ip6.saddrsel="$(__get_jail_prop ip6_saddrsel "${_fulluuid}" \
            ${_dataset})" \
        ip6="${_ip6}" \
        name="ioc-${_fulluuid}" \
        host.domainname="$(__get_jail_prop host_domainname "${_fulluuid}" \
            ${_dataset})" \
        host.hostname="$(__get_jail_prop host_hostname "${_fulluuid}" \
            ${_dataset})" \
        path="${_jail_path}/root" \
        securelevel="$(__get_jail_prop securelevel "${_fulluuid}" \
            ${_dataset})" \
        host.hostuuid="${_fulluuid}" \
        devfs_ruleset="$(__get_jail_prop devfs_ruleset "${_fulluuid}" \
            ${_dataset})" \
        enforce_statfs="$(__get_jail_prop enforce_statfs "${_fulluuid}" \
            ${_dataset})" \
        children.max="$(__get_jail_prop children_max "${_fulluuid}" \
            ${_dataset})" \
        allow.set_hostname="$(__get_jail_prop allow_set_hostname \
            "${_fulluuid}" ${_dataset})" \
        allow.sysvipc="$(__get_jail_prop allow_sysvipc "${_fulluuid}" \
            ${_dataset})" \
        ${_sysvmsg} \
        ${_sysvsem} \
        ${_sysvshm} \
        allow.raw_sockets="$(__get_jail_prop allow_raw_sockets "${_fulluuid}" \
            ${_dataset})" \
        allow.chflags="$(__get_jail_prop allow_chflags "${_fulluuid}" \
            ${_dataset})" \
        allow.mount="$(__get_jail_prop allow_mount "${_fulluuid}" \
            ${_dataset})" \
        allow.mount.devfs="$(__get_jail_prop allow_mount_devfs "${_fulluuid}" \
            ${_dataset})" \
        allow.mount.nullfs="$(__get_jail_prop allow_mount_nullfs \
            "${_fulluuid}" ${_dataset})" \
        allow.mount.procfs="$(__get_jail_prop allow_mount_procfs \
            "${_fulluuid}" ${_dataset})" \
        "${_tmpfs}" \
        allow.mount.zfs="$(__get_jail_prop allow_mount_zfs "${_fulluuid}" \
            ${_dataset})" \
        allow.quotas="$(__get_jail_prop allow_quotas "${_fulluuid}" \
            ${_dataset})" \
        allow.socket_af="$(__get_jail_prop allow_socket_af "${_fulluuid}" \
            ${_dataset})" \
        exec.prestart="$(__findscript "${_fulluuid}" prestart ${_dataset})" \
        exec.poststart="$(__findscript "${_fulluuid}" poststart ${_dataset})" \
        exec.prestop="$(__findscript "${_fulluuid}" prestop ${_dataset})" \
        exec.stop="$(__get_jail_prop exec_stop "${_fulluuid}" ${_dataset})" \
        exec.clean="$(__get_jail_prop exec_clean "${_fulluuid}" ${_dataset})" \
        exec.timeout="$(__get_jail_prop exec_timeout "${_fulluuid}" \
            ${_dataset})" \
        exec.fib="${_exec_fib}" \
        stop.timeout="$(__get_jail_prop stop_timeout "${_fulluuid}" \
            ${_dataset})" \
        mount.fstab="${_jail_path}/fstab" \
        mount.devfs="$(__get_jail_prop mount_devfs "${_fulluuid}" \
            ${_dataset})" \
        "${_fdescfs}" \
        allow.dying \
        exec.consolelog="${iocroot}/log/${name}-console.log" \
        persist
    else
        jail -c \
        "${_ip4_addr_propline}" \
        ip4.saddrsel="$(__get_jail_prop ip4_saddrsel "${_fulluuid}" \
            ${_dataset})" \
        ip4="${_ip4}" \
        name="ioc-${_fulluuid}" \
        host.domainname="$(__get_jail_prop host_domainname "${_fulluuid}" \
            ${_dataset})" \
        host.hostname="$(__get_jail_prop host_hostname "${_fulluuid}" \
            ${_dataset})" \
        path="${_jail_path}/root" \
        securelevel="$(__get_jail_prop securelevel "${_fulluuid}" \
            ${_dataset})" \
        host.hostuuid="${_fulluuid}" \
        devfs_ruleset="$(__get_jail_prop devfs_ruleset "${_fulluuid}" \
            ${_dataset})" \
        enforce_statfs="$(__get_jail_prop enforce_statfs "${_fulluuid}" \
            ${_dataset})" \
        children.max="$(__get_jail_prop children_max "${_fulluuid}" \
            ${_dataset})" \
        allow.set_hostname="$(__get_jail_prop allow_set_hostname \
            "${_fulluuid}" ${_dataset})" \
        allow.sysvipc="$(__get_jail_prop allow_sysvipc "${_fulluuid}" \
            ${_dataset})" \
        ${_sysvmsg} \
        ${_sysvsem} \
        ${_sysvshm} \
        allow.raw_sockets="$(__get_jail_prop allow_raw_sockets "${_fulluuid}" \
            ${_dataset})" \
        allow.chflags="$(__get_jail_prop allow_chflags "${_fulluuid}" \
            ${_dataset})" \
        allow.mount="$(__get_jail_prop allow_mount "${_fulluuid}" \
            ${_dataset})" \
        allow.mount.devfs="$(__get_jail_prop allow_mount_devfs "${_fulluuid}" \
            ${_dataset})" \
        allow.mount.nullfs="$(__get_jail_prop allow_mount_nullfs \
            "${_fulluuid}" ${_dataset})" \
        allow.mount.procfs="$(__get_jail_prop allow_mount_procfs \
            "${_fulluuid}" ${_dataset})" \
        "${_tmpfs}" \
        allow.mount.zfs="$(__get_jail_prop allow_mount_zfs "${_fulluuid}" \
            ${_dataset})" \
        allow.quotas="$(__get_jail_prop allow_quotas "${_fulluuid}" \
            ${_dataset})" \
        allow.socket_af="$(__get_jail_prop allow_socket_af "${_fulluuid}" \
            ${_dataset})" \
        exec.prestart="$(__findscript "${_fulluuid}" prestart ${_dataset})" \
        exec.poststart="$(__findscript "${_fulluuid}" poststart ${_dataset})" \
        exec.prestop="$(__findscript "${_fulluuid}" prestop ${_dataset})" \
        exec.stop="$(__get_jail_prop exec_stop "${_fulluuid}" ${_dataset})" \
        exec.clean="$(__get_jail_prop exec_clean "${_fulluuid}" ${_dataset})" \
        exec.timeout="$(__get_jail_prop exec_timeout "${_fulluuid}" \
            ${_dataset})" \
        exec.fib="${_exec_fib}" \
        stop.timeout="$(__get_jail_prop stop_timeout "${_fulluuid}" \
            ${_dataset})" \
        mount.fstab="${_jail_path}/fstab" \
        mount.devfs="$(__get_jail_prop mount_devfs "${_fulluuid}" \
            ${_dataset})" \
        "${_fdescfs}" \
        allow.dying \
        exec.consolelog="${iocroot}/log/${name}-console.log" \
        persist
    fi
}

# Stop completely and start the jail anew
__reboot_jail () {

    if [ "$1" = "ALL" ] ; then
        __reboot_jail_all
        exit $?
    fi

    __stop_jail "$1" && __start_jail "$1"
}

__stop_jail () {
    local _fulluuid _dataset _name _jail_path _tag _exec_prestop _exec_stop \
          _exec_poststop _vnet _state _ip4 _jail_type _jail_zfs \
          _jail_zfs_datasets _zfs_dataset _zfs_dataset_subsets \
          _zfs_dataset_subset _nfulluuid

    if [ "$1" = "ALL" ] ; then
        __stop_jail_all
        exit $?
    fi

    _name=$1
    _dataset="$(__find_jail ${_name})" || exit $?
    _fulluuid="$(__check_name ${_name} ${_dataset})"

    # Prepare the mounts and export _nfulluuid
    __hack88_mount ${_fulluuid} ${_dataset} _nfulluuid

    _jail_type="$(__get_jail_prop type ${_fulluuid} ${_dataset})"
    _jail_path="$(__get_jail_prop mountpoint ${_fulluuid} ${_dataset})"
    _jail_zfs="$(__get_jail_prop jail_zfs ${_fulluuid} ${_dataset})"
    _jail_zfs_datasets="$(__get_jail_prop jail_zfs_dataset "${_fulluuid}" \
        "${_dataset}")"
    _tag="$(__get_jail_prop tag ${_fulluuid} ${_dataset})"
    _exec_prestop="$(__findscript ${_fulluuid} prestop ${_dataset})"
    _exec_stop="$(__get_jail_prop exec_stop ${_fulluuid} ${_dataset})"
    _exec_poststop="$(__findscript ${_fulluuid} poststop ${_dataset})"
    _vnet="$(__get_jail_prop vnet ${_fulluuid} ${_dataset})"
    _state="$(__is_running ${_fulluuid})"
    _ip4="$(__get_jail_prop ip4 ${_fulluuid} ${_dataset})"

    if [ -z "${_state}" ] ; then
        __info "${_fulluuid} (${_tag}) is already down" >&2
        return 1
    fi

    echo "* Stopping ${_fulluuid} (${_tag})"

    echo -n "  + Running pre-stop"
    eval "${_exec_prestop}"

    if [ $? -ne 1 ] ; then
        echo "         OK"
    else
        echo "     FAILED"
    fi

    echo -n "  + Stopping services"

    jexec ioc-${_fulluuid} ${_exec_stop} >> \
        "${iocroot}/log/${_fulluuid}-console.log" 2>&1

    if [ $? -ne 1 ] ; then
        echo "        OK"
    else
        echo "    FAILED"
    fi

    if [ "${_vnet}" = "on" ] ; then
        echo -n "  + Tearing down VNET"
        __networking stop "${_fulluuid}" "${_dataset}"
        if [ $? -eq 1 ] ; then
            echo "        FAILED"
        else
            echo "        OK"
        fi
    else
        # don't try to tear down networking if we have "inherit" set
        if [ "${_ip4}" != 'inherit' ] ; then
            __stop_legacy_networking "${_fulluuid}" "${_dataset}"
        fi
    fi

    if [ "${_jail_zfs}" = "on" ] ; then
        for _zfs_dataset in ${_jail_zfs_datasets} ; do

            _zfs_dataset=$(__zfs_dataset_add_poolname "${_zfs_dataset}")
            _zfs_dataset_subsets="$(zfs list -Hr -o name -S name \
                "${_zfs_dataset}")"
            for _zfs_dataset_subset in ${_zfs_dataset_subsets} ; do
                jexec "ioc-${_fulluuid}" zfs umount "${_zfs_dataset_subset}"
            done

            zfs unjail "ioc-${_fulluuid}" "${_zfs_dataset}"

        done
    fi

    echo -n "  + Removing jail process"
    jail -r "ioc-${_fulluuid}" 1> /dev/null

    if [ $? -ne 1 ] ; then
        echo "    OK"
    else
        echo "FAILED"
    fi

    echo -n "  + Running post-stop"
    eval "${_exec_poststop}"
    if [ $? -ne 1 ] ; then
        echo "        OK"
    else
        echo "    FAILED"
    fi

    umount -afvF "${_jail_path}/fstab"              > /dev/null 2>&1
    umount "${_jail_path}/root/dev/fd"              > /dev/null 2>&1
    umount "${_jail_path}/root/dev"                 > /dev/null 2>&1
    umount "${_jail_path}/root/proc"                > /dev/null 2>&1
    umount "${_jail_path}/root/compat/linux/proc"   > /dev/null 2>&1

    if [ "${_jail_type}" = "basejail" -o "${_jail_type}" = "clonejail" ] ; then
        __umount_basejail "${_fulluuid}" "${_dataset}" >&2
    elif [ "${_jail_type}" = "template" ] ; then
        __umount_istemplate "${_tag}" >&2
    fi

    if [ -d "${iocroot}/jails/${_nfulluuid}/recorded" ] ; then
        umount -ft unionfs "${iocroot}/jails/${_nfulluuid}/root" > /dev/null 2>&1
    fi
    if [ ! -z $(sysctl -qn kern.features.rctl) ] ; then
        if [ "$(sysctl -qn kern.racct.enable)" = "1" ] ; then
            local rlimits="$(rctl | grep ${_fulluuid}| wc -l)"
            if [ "${rlimits}" -gt "0" ] ; then
                rctl -r "jail:ioc-${_fulluuid}"
            fi
        fi
    fi
}

__stop_jail_all () {
    local _jails _state
    _jails=$(__find_jail ALL | \
            awk 'BEGIN { FS = "/" } ; { if (length($NF)==36) { print }}')

    for _jail in ${_jails} ; do
        # _jail is actually a dataset, so fulluuid needs to be faked.
        _juuid="$(__check_name "name" ${_jail} 2> /dev/null)"
        _state="$(__is_running ${_juuid} ; echo $?)"
        if [ "${_state}" != "0" ] ; then
            __stop_jail ${_juuid}
        fi
    done
    return $?
}

__start_jail_all () {
    local _jails _juuid _jtag _state
    _jails=$(__find_jail ALL | \
            awk 'BEGIN { FS = "/" } ; { if (length($NF)==36) { print }}')

    for _jail in ${_jails} ; do
        # _jail is actually a dataset, so fulluuid needs to be faked.
        _juuid="$(__check_name "name" ${_jail} 2> /dev/null)"
        _state="$(__is_running ${_juuid} ; echo $?)"
        if [ "${_state}" != "1" ] ; then
            __start_jail ${_juuid}
        fi
    done
    return $?
}

__reboot_jail_all () {
    local _jails _juuid _jtag _state
    _jails=$(__find_jail ALL | \
            awk 'BEGIN { FS = "/" } ; { if (length($NF)==36) { print }}')

    for _jail in ${_jails} ; do
        # _jail is actually a dataset, so fulluuid needs to be faked.
        _juuid="$(__check_name "name" ${_jail} 2> /dev/null)"
        _jtag=$(__get_jail_prop tag ${_jail})
        _state="$(__is_running ${_juuid} ; echo $?)"
        if [ "${_state}" != "0" ] ; then
            __reboot_jail ${_juuid}
        else
            __info "${_jtag} is not running." >&2
        fi
    done
    return $?
}

__restart_jail_all () {
    local _jails _juuid _jtag _state
    _jails=$(__find_jail ALL | \
            awk 'BEGIN { FS = "/" } ; { if (length($NF)==36) { print }}')

    for _jail in ${_jails} ; do
        # _jail is actually a dataset, so fulluuid needs to be faked.
        _juuid="$(__check_name "name" ${_jail} 2> /dev/null)"
        _jtag=$(__get_jail_prop tag ${_jail})
        _state="$(__is_running ${_juuid} ; echo $?)"
        if [ "${_state}" != "0" ] ; then
                __restart_jail ${_juuid}
        else
            __info "${_jtag} is not running." >&2
        fi
    done
    return $?
}

# Soft restart
__restart_jail () {
    local _name _dataset _fulluuid _exec_stop _exec_start _jid _tag

    _name="$1"

    if [ -z "${_name}" ] ; then
        __die "missing UUID!"
    fi

    _dataset="$(__find_jail ${_name})" || exit $?

    if [ "$1" = "ALL" ] ; then
        __restart_jail_all
        exit $?
    fi

    if [ -z "${_dataset}" ] ; then
        __die "${_name} not found!"
    fi

    _fulluuid="$(__check_name ${_name} ${_dataset})"
    _exec_stop="$(__get_jail_prop exec_stop ${_fulluuid})"
    _exec_start="$(__get_jail_prop exec_start ${_fulluuid})"
    _jid="$(jls -j ioc-${_fulluuid} jid)"
    _tag="$(__get_jail_prop tag ${_fulluuid})"

    __info "soft restarting ${_fulluuid} (${_tag})"
    jexec ioc-${_fulluuid} ${_exec_stop} >> \
        "${iocroot}/log/${fulluuid}-console.log" 2>&1

    if [ $? -ne "1" ] ; then
        pkill -j "${_jid}"
        jexec ioc-${_fulluuid} ${_exec_start} >> \
            "${iocroot}/log/${fulluuid}-console.log" 2>&1
        __set_jail_prop last_started=$(date "+%F_%T") "${_fulluuid}" \
            "${_dataset}" &
    else
        echo "  soft restart failed!"
        return 1
    fi
}

__rc_jails () {
    local _action _jails _boot_list _name _boot _jail_hostid _priority \
          _boot_order _shutdown_order _jail _jail_path _state

    _action=$1
    _jails=$(__find_jail ALL | \
            awk 'BEGIN { FS = "/" } ; { if (length($NF)==36) { print }}')
    _boot_list="/tmp/iocell.$$"

    for _jail in ${_jails} ; do
        # _jail is actually a dataset, so fulluuid needs to be faked.
        _name="$(__check_name "name" ${_jail} 2> /dev/null)"
        _boot="$(__get_jail_prop boot ${_jail})"
        _jail_hostid="$(__get_jail_prop hostid \
                    ${_jail})"
        _priority="$(__get_jail_prop priority \
                    ${_jail})"

        if [ "${_boot}" = "on" -a "${_jail_hostid}" = "${hostid}" ] ; then
            echo "${_priority},${_name}" >> "${_boot_list}"
        fi
    done

    if [ -e "${_boot_list}" ] ; then
        _boot_order=$(sort -n ${_boot_list})
        _shutdown_order=$(sort -rn ${_boot_list})
    else
        __info "no jails found with property boot=on"
        echo "  or hostid: ${hostid}, exiting.."
        exit 0
    fi

    if [ "${_action}" = "boot" ] ; then
        echo "* [I|O|C] booting jails... "

        for _i in ${_boot_order} ; do
            _jail="$(echo ${_i} | cut -f2 -d,)"
            _priority="$(echo ${_i} | cut -f1 -d,)"
            _dataset="${pool}/iocell/jails/${_jail}"
            _jail_path="$(__get_jail_prop mountpoint ${_jail} ${_dataset})"
            _state="$(jls | grep ${_jail_path} | wc -l)"

            if [ "${_state}" -lt "1" -a "${_priority}" -eq 99 ] ; then
                __info "executing background start for ${_jail}"
                __start_jail "${_jail}" > "/var/tmp/${_jail}" 2>&1 \
                    && cat "/var/tmp/${_jail}" &
                sleep 1
            else
                __start_jail "${_jail}"
            fi

        done
    elif [ "${_action}" = "shutdown" ] ; then
        echo "* [I|O|C] shutting down jails... "

        for _i in ${_shutdown_order} ; do
            _jail="$(echo ${_i} | cut -f2 -d,)"
            _dataset="${pool}/iocell/jails/${_jail}"
            _jail_path="$(__get_jail_prop mountpoint ${_jail} ${_dataset})"
            _state="$(jls | grep ${_jail_path} | wc -l)"

            if [ "${_state}" -eq "1" ] ; then
                __stop_jail "${_jail}" "${_dataset}"
            fi
        done

    fi
    rm "${_boot_list}"
}
