From a190099450a8e403adc29dad642ad2db2ccde3f9 Mon Sep 17 00:00:00 2001 From: tschettervictor Date: Sun, 3 Aug 2025 13:32:59 -0600 Subject: [PATCH] deprecate parallel mode --- docs/chapters/targeting.rst | 13 - docs/chapters/usage.rst | 3 +- usr/local/bin/bastille | 45 +- usr/local/share/bastille/cmd.sh | 19 +- usr/local/share/bastille/common.sh | 48 -- usr/local/share/bastille/common.sh.save | 621 ++++++++++++++++++++++++ usr/local/share/bastille/config.sh | 14 +- usr/local/share/bastille/console.sh | 2 +- usr/local/share/bastille/cp.sh | 13 +- usr/local/share/bastille/jcp.sh | 13 +- usr/local/share/bastille/limits.sh | 9 +- usr/local/share/bastille/mount.sh | 9 +- usr/local/share/bastille/pkg.sh | 22 +- usr/local/share/bastille/restart.sh | 9 +- usr/local/share/bastille/service.sh | 19 +- usr/local/share/bastille/start.sh | 9 +- usr/local/share/bastille/stop.sh | 7 - usr/local/share/bastille/sysrc.sh | 22 +- usr/local/share/bastille/tags.sh | 7 - usr/local/share/bastille/template.sh | 7 - usr/local/share/bastille/umount.sh | 9 +- 21 files changed, 699 insertions(+), 221 deletions(-) create mode 100644 usr/local/share/bastille/common.sh.save diff --git a/docs/chapters/targeting.rst b/docs/chapters/targeting.rst index cab9c518..2d5bfe1b 100644 --- a/docs/chapters/targeting.rst +++ b/docs/chapters/targeting.rst @@ -43,19 +43,6 @@ This value can be changed using ``bastille config TARGET set priority VALUE``. This value will be shown using ``bastille list all``. -Parallel Mode -------------- - -Any command that supports multiple targets, also supports parallel mode. This -means that Bastille will run the command on multiple jails at a single time, -depending on the value given. - -To use parallel mode, run ``bastille -p 4 pkg ALL update``, for example, to start -updating packages in all jails, 4 processes at a time. - -Note that the ``-p`` option should follow the main ``bastille`` command, and not -the sub-command. - Examples: Containers -------------------- diff --git a/docs/chapters/usage.rst b/docs/chapters/usage.rst index b6623a8f..efa46b54 100644 --- a/docs/chapters/usage.rst +++ b/docs/chapters/usage.rst @@ -52,5 +52,4 @@ Usage Use "bastille -v|--version" for version information. Use "bastille command -h|--help" for more information about a command. - Use "bastille -c|--config config.conf command" to specify a non-default config file. - Use "bastille -p|--parallel VALUE command" to run bastille in parallel mode. \ No newline at end of file + Use "bastille -c|--config config.conf command" to specify a non-default config file. \ No newline at end of file diff --git a/usr/local/bin/bastille b/usr/local/bin/bastille index e127226a..20012645 100755 --- a/usr/local/bin/bastille +++ b/usr/local/bin/bastille @@ -119,7 +119,6 @@ Available Commands: Use "bastille -v|--version" for version information. Use "bastille command -h|--help" for more information about a command. Use "bastille -c|--config FILE command" to specify a non-default config file. -Use "bastille -p|--parallel VALUE command" to run bastille in parallel mode. EOF exit 1 @@ -146,8 +145,6 @@ bastille_perms_check . /usr/local/share/bastille/common.sh # Handle options -bastille_parallel_mode=0 -bastille_process_limit="${bastille_process_limit:-1}" while [ "$#" -gt 0 ]; do case "${1}" in -h|--help|help) @@ -170,15 +167,6 @@ while [ "$#" -gt 0 ]; do . /usr/local/share/bastille/common.sh shift 2 ;; - -p|--parallel) - bastille_parallel_mode=1 - bastille_process_limit="${2}" - if ! echo "${bastille_process_limit}" | grep -Eq "^[0-9]+$"; then - error_exit "Not a valid process limit: ${bastille_process_limit}" - else - shift 2 - fi - ;; -*) error_exit "Unknown Option: \"${1}\"" ;; @@ -188,9 +176,6 @@ while [ "$#" -gt 0 ]; do esac done -# Export parallel and limit -export bastille_process_limit - if [ "$#" -lt 1 ]; then usage else @@ -200,12 +185,14 @@ fi # Handle sub-commands. case "${CMD}" in - # Commands that don't allow parallel mode + # 38 total commands bootstrap| \ clone| \ cmd| \ + config| \ console| \ convert| \ + cp| \ create| \ destroy| \ edit| \ @@ -213,38 +200,30 @@ case "${CMD}" in export| \ htop| \ import| \ + jcp| \ limits| \ list| \ migrate| \ + mount| \ network| \ pkg| \ rcp| \ rdr| \ rename| \ + restart| \ service| \ setup| \ - top| \ - update| \ - upgrade| \ - verify| \ - zfs) - if [ "${bastille_parallel_mode}" -eq 1 ]; then - error_exit "Command does not support parallel mode: ${CMD}" - fi - ;; - # Commands that allow parallel mode - config| \ - cp| \ - jcp| \ - limits| \ - mount| \ - restart| \ start| \ stop| \ sysrc| \ tags| \ template| \ - umount) + top| \ + umount| \ + update| \ + upgrade| \ + verify| \ + zfs) ;; *) usage diff --git a/usr/local/share/bastille/cmd.sh b/usr/local/share/bastille/cmd.sh index 10f15fb7..313db834 100644 --- a/usr/local/share/bastille/cmd.sh +++ b/usr/local/share/bastille/cmd.sh @@ -84,10 +84,7 @@ bastille_root_check TARGET="${1}" shift 1 - -# Use mktemp to store exit codes -export TMP_BASTILLE_EXIT_CODE="$(mktemp)" -echo 0 > "${TMP_BASTILLE_EXIT_CODE}" +ERRORS=0 set_target "${TARGET}" @@ -110,9 +107,15 @@ for _jail in ${JAILS}; do else jexec -l -U root "${_jail}" "$@" fi - - bastille_check_exit_code "${_jail}" "$?" - + + if [ "$?" -ne 0 ]; then + ERRORS=$((ERRORS + 1)) + fi + done -bastille_return_exit_code +if [ "${ERRORS}" -ne 0 ]; then + error_exit "[ERROR]: Command failed on ${ERRORS} jails." +fi + +echo \ No newline at end of file diff --git a/usr/local/share/bastille/common.sh b/usr/local/share/bastille/common.sh index bf7692c2..38be75d1 100644 --- a/usr/local/share/bastille/common.sh +++ b/usr/local/share/bastille/common.sh @@ -93,54 +93,6 @@ warn() { echo -e "${COLOR_YELLOW}$*${COLOR_RESET}" } -# This function checks and adds any error code -# that is not "0" to the tmp file -bastille_check_exit_code() { - - local jail="${1}" - local exit_code="${2}" - - # Set exit code variable - if [ -z "${TMP_BASTILLE_EXIT_CODE}" ]; then - error_exit "[ERROR]: Exit code status not set." - else - local old_exit_code="$(cat ${TMP_BASTILLE_EXIT_CODE})" - fi - - if [ "${exit_code}" -ne 0 ]; then - local new_exit_code="$(( ${old_exit_code} + ${exit_code} ))" - echo "${new_exit_code}" > "${TMP_BASTILLE_EXIT_CODE}" - error_notify "[ERROR CODE]: ${exit_code}" - fi -} - -# This needs to be the last function called -# if used on any command -bastille_return_exit_code() { - - local exit_code="$(cat ${TMP_BASTILLE_EXIT_CODE})" - - rm -f ${TMP_BASTILLE_EXIT_CODE} - return "${exit_code}" -} - -# Parallel mode, don't exceed process limit -bastille_running_jobs() { - - _process_limit="${1}" - _running_jobs=$((_running_jobs + 1)) - - if [ "${_running_jobs}" -ge "${_process_limit}" ]; then - - # Wait for at least one process to finish - wait 2>/dev/null || wait - - _running_jobs=$((_running_jobs - 1)) - - fi - -} - check_target_exists() { local _TARGET="${1}" local _jaillist="$(bastille list jails)" diff --git a/usr/local/share/bastille/common.sh.save b/usr/local/share/bastille/common.sh.save new file mode 100644 index 00000000..d9f4350a --- /dev/null +++ b/usr/local/share/bastille/common.sh.save @@ -0,0 +1,621 @@ +#!/bin/sh +# +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright (c) 2018-2025, Christer Edwards +# 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. + +# Load config. This only has to be done here +# because all commands load this file +# shellcheck disable=SC1090 +. ${BASTILLE_CONFIG} + +COLOR_RED= +COLOR_GREEN= +COLOR_YELLOW= +COLOR_RESET= + +bastille_root_check() { + if [ "$(id -u)" -ne 0 ]; then + ## permission denied + error_notify "Bastille: Permission Denied" + error_exit "root / sudo / doas required" + fi +} + +enable_color() { + . /usr/local/share/bastille/colors.pre.sh +} + +enable_debug() { + # Enable debug mode. + warn "***DEBUG MODE***" + set -x +} + +# If "NO_COLOR" environment variable is present, or we aren't speaking to a +# tty, disable output colors. +if [ -z "${NO_COLOR}" ] && [ -t 1 ]; then + enable_color +fi + +# Notify message on error +# Do not echo blank line +error_continue() { + error_notify "$@" + # shellcheck disable=SC2104 + continue +} + +# Notify message on error, but do not exit +error_notify() { + echo -e "${COLOR_RED}$*${COLOR_RESET}" 1>&2 +} + +# Notify message on error and exit +# Echo blank line when exiting +error_exit() { + error_notify "$@" + echo + exit 1 +} + +info() { + # Print content in green + echo -e "${COLOR_GREEN}$*${COLOR_RESET}" +} + +warn() { + # Print content in yellow + echo -e "${COLOR_YELLOW}$*${COLOR_RESET}" +} + +# This function checks and adds any error code +# that is not "0" to the tmp file +bastille_check_exit_code() { + + local jail="${1}" + local exit_code="${2}" + + # Set exit code variable + if [ -z "${TMP_BASTILLE_EXIT_CODE}" ]; then + error_exit "[ERROR]: Exit code status not set." + else + local old_exit_code="$(cat ${TMP_BASTILLE_EXIT_CODE})" + fi + + if [ "${exit_code}" -ne 0 ]; then + local new_exit_code="$(( ${old_exit_code} + ${exit_code} ))" + echo "${new_exit_code}" > "${TMP_BASTILLE_EXIT_CODE}" + error_notify "[ERROR CODE]: ${exit_code}" + fi +} + +# This needs to be the last function called +# if used on any command +bastille_return_exit_code() { + + local exit_code="$(cat ${TMP_BASTILLE_EXIT_CODE})" + + rm -f ${TMP_BASTILLE_EXIT_CODE} + return "${exit_code}" +} + +# Parallel mode, don't exceed process limit +bastille_running_jobs() { + + _process_limit="${1}" + _running_jobs=$((_running_jobs + 1)) + + if [ "${_running_jobs}" -ge "${_process_limit}" ]; then + + # Wait for at least one process to finish + wait 2>/dev/null || wait + + _running_jobs=$((_running_jobs - 1)) + + fi + +} + +check_target_exists() { + local _TARGET="${1}" + local _jaillist="$(bastille list jails)" + if ! echo "${_jaillist}" | grep -Eq "^${_TARGET}$"; then + return 1 + else + return 0 + fi +} + +check_target_is_running() { + _TARGET="${1}" + if ! jls name | grep -Eq "^${_TARGET}$"; then + return 1 + else + return 0 + fi +} + +check_target_is_stopped() { + _TARGET="${1}" + if jls name | grep -Eq "^${_TARGET}$"; then + return 1 + else + return 0 + fi +} + +get_jail_name() { + local _JID="${1}" + local _jailname="$(jls -j ${_JID} name 2>/dev/null)" + if [ -z "${_jailname}" ]; then + return 1 + else + echo "${_jailname}" + fi +} + +jail_autocomplete() { + local _TARGET="${1}" + local _jaillist="$(bastille list jails)" + local _AUTOTARGET="$(echo "${_jaillist}" | grep -E "^${_TARGET}")" + if [ -n "${_AUTOTARGET}" ]; then + if [ "$(echo "${_AUTOTARGET}" | wc -l)" -eq 1 ]; then + echo "${_AUTOTARGET}" + else + error_continue "Multiple jails found for ${_TARGET}:\n${_AUTOTARGET}" + return 1 + fi + else + return 2 + fi +} + +list_jail_priority() { + local _jail_list="${1}" + if [ -d "${bastille_jailsdir}" ]; then + for _jail in ${_jail_list}; do + # Remove boot.conf in favor of settings.conf + if [ -f ${bastille_jailsdir}/${_jail}/boot.conf ]; then + rm -f ${bastille_jailsdir}/${_jail}/boot.conf >/dev/null 2>&1 + fi + local _settings_file=${bastille_jailsdir}/${_jail}/settings.conf + # Set defaults if settings file does not exist + if [ ! -f ${_settings_file} ]; then + sysrc -f ${_settings_file} boot=on >/dev/null 2>&1 + sysrc -f ${_settings_file} depend="" >/dev/null 2>&1 + sysrc -f ${_settings_file} priority=99 >/dev/null 2>&1 + fi + # Add defaults if they dont exist + if ! grep -oq "boot=" ${_settings_file}; then + sysrc -f ${_settings_file} boot=on >/dev/null 2>&1 + fi + if ! grep -oq "depend=" ${_settings_file}; then + sysrc -f ${_settings_file} depend="" >/dev/null 2>&1 + fi + if ! grep -oq "priority=" ${_settings_file}; then + sysrc -f ${_settings_file} priority=99 >/dev/null 2>&1 + fi + _priority="$(sysrc -f ${_settings_file} -n priority)" + echo "${_jail} ${_priority}" + done + fi +} + +set_target() { + local _TARGET=${1} + if [ "${2}" = "reverse" ]; then + local _order="${2}" + else + local _order="forward" + fi + JAILS="" + TARGET="" + if [ "${_TARGET}" = ALL ] || [ "${_TARGET}" = all ]; then + target_all_jails + else + for _jail in ${_TARGET}; do + if [ ! -d "${bastille_jailsdir}/${_TARGET}" ] && echo "${_jail}" | grep -Eq '^[0-9]+$'; then + if get_jail_name "${_jail}" > /dev/null; then + _jail="$(get_jail_name ${_jail})" + else + error_continue "Error: JID \"${_jail}\" not found. Is jail running?" + fi + elif ! check_target_exists "${_jail}"; then + if jail_autocomplete "${_jail}" > /dev/null; then + _jail="$(jail_autocomplete ${_jail})" + elif [ $? -eq 2 ]; then + if grep -Ehoqw ${_jail} ${bastille_jailsdir}/*/tags; then + _jail="$(grep -Eow ${_jail} ${bastille_jailsdir}/*/tags | awk -F"/tags" '{print $1}' | sed "s#${bastille_jailsdir}/##g" | tr '\n' ' ')" + else + error_continue "Jail not found \"${_jail}\"" + fi + else + echo + exit 1 + fi + fi + TARGET="${TARGET} ${_jail}" + JAILS="${JAILS} ${_jail}" + done + # Exit if no jails + if [ -z "${TARGET}" ] && [ -z "${JAILS}" ]; then + exit 1 + fi + if [ "${_order}" = "forward" ]; then + TARGET="$(list_jail_priority "${TARGET}" | sort -k2 -n | awk '{print $1}')" + JAILS="$(list_jail_priority "${TARGET}" | sort -k2 -n | awk '{print $1}')" + elif [ "${_order}" = "reverse" ]; then + TARGET="$(list_jail_priority "${TARGET}" | sort -k2 -nr | awk '{print $1}')" + JAILS="$(list_jail_priority "${TARGET}" | sort -k2 -nr | awk '{print $1}')" + fi + export TARGET + export JAILS + fi +} + +set_target_single() { + local _TARGET="${1}" + if [ "${_TARGET}" = ALL ] || [ "${_TARGET}" = all ]; then + error_exit "[all|ALL] not supported with this command." + elif [ "$(echo ${_TARGET} | wc -w)" -gt 1 ]; then + error_exit "Error: Command only supports a single TARGET." + elif [ ! -d "${bastille_jailsdir}/${_TARGET}" ] && echo "${_TARGET}" | grep -Eq '^[0-9]+$'; then + if get_jail_name "${_TARGET}" > /dev/null; then + _TARGET="$(get_jail_name ${_TARGET})" + else + error_exit "Error: JID \"${_TARGET}\" not found. Is jail running?" + fi + elif ! check_target_exists "${_TARGET}"; then + if jail_autocomplete "${_TARGET}" > /dev/null; then + _TARGET="$(jail_autocomplete ${_TARGET})" + elif [ $? -eq 2 ]; then + error_exit "Jail not found \"${_TARGET}\"" + else + echo + exit 1 + fi + fi + # Exit if no jails + if [ -z "${_TARGET}" ] && [ -z "${_JAILS}" ]; then + exit 1 + fi + TARGET="${_TARGET}" + JAILS="${_TARGET}" + export TARGET + export JAILS +} + +# This function is run immediately +set_bastille_mountpoints() { + + if checkyesno bastille_zfs_enable; then + + # We have to do this if ALTROOT is enabled/present + local _altroot="$(zpool get -Ho value altroot ${bastille_zfs_zpool})" + + # Set mountpoints to *bastille*dir* + # shellcheck disable=SC2034 + bastille_prefix_mountpoint="${bastille_prefix}" + # shellcheck disable=SC2034 + bastille_backupsdir_mountpoint="${bastille_backupsdir}" + # shellcheck disable=SC2034 + bastille_cachedir_mountpoint="${bastille_cachedir}" + # shellcheck disable=SC2034 + bastille_jailsdir_mountpoint="${bastille_jailsdir}" + # shellcheck disable=SC2034 + bastille_releasesdir_mountpoint="${bastille_releasesdir}" + # shellcheck disable=SC2034 + bastille_templatesdir_mountpoint="${bastille_templatesdir}" + # shellcheck disable=SC2034 + bastille_logsdir_mountpoint="${bastille_logsdir}" + + # Add _altroot to *dir* if set + if [ "${_altroot}" != "-" ]; then + # Set *dir* to include ALTROOT + bastille_prefix="${_altroot}${bastille_prefix}" + bastille_backupsdir="${_altroot}${bastille_backupsdir}" + bastille_cachedir="${_altroot}${bastille_cachedir}" + bastille_jailsdir="${_altroot}${bastille_jailsdir}" + bastille_releasesdir="${_altroot}${bastille_releasesdir}" + bastille_templatesdir="${_altroot}${bastille_templatesdir}" + bastille_logsdir="${_altroot}${bastille_logsdir}" + fi + fi +} + +target_all_jails() { + local _JAILS="$(bastille list jails)" + JAILS="" + for _jail in ${_JAILS}; do + if [ -d "${bastille_jailsdir}/${_jail}" ]; then + JAILS="${JAILS} ${_jail}" + fi + done + # Exit if no jails + if [ -z "${JAILS}" ]; then + exit 1 + fi + if [ "${_order}" = "forward" ]; then + JAILS="$(list_jail_priority "${JAILS}" | sort -k2 -n | awk '{print $1}')" + elif [ "${_order}" = "reverse" ]; then + JAILS="$(list_jail_priority "${JAILS}" | sort -k2 -nr | awk '{print $1}')" + fi + export JAILS +} + +update_fstab() { + local _oldname="${1}" + local _newname="${2}" + local _fstab="${bastille_jailsdir}/${_newname}/fstab" + if [ -f "${_fstab}" ]; then + sed -i '' "s|${bastille_jailsdir}/${_oldname}/root/|${bastille_jailsdir}/${_newname}/root/|" "${_fstab}" + else + error_notify "Error: Failed to update fstab: ${_newmane}" + fi +} + +generate_static_mac() { + local jail_name="${1}" + local external_interface="${2}" + local external_interface_mac="$(ifconfig ${external_interface} | grep ether | awk '{print $2}')" + # Use FreeBSD vendor MAC prefix (58:9c:fc) for jail MAC prefix + local macaddr_prefix="58:9c:fc" + # Use hash of interface+jailname for jail MAC suffix + local macaddr_suffix="$(echo -n "${external_interface_mac}${jail_name}" | sed 's#:##g' | sha256 | cut -b -5 | sed 's/\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F]\)/\1:\2:\3/')" + if [ -z "${macaddr_prefix}" ] || [ -z "${macaddr_suffix}" ]; then + error_notify "Failed to generate MAC address." + fi + macaddr="${macaddr_prefix}:${macaddr_suffix}" + export macaddr +} + +generate_vnet_jail_netblock() { + + local jail_name="${1}" + local use_unique_bridge="${2}" + local external_interface="${3}" + local static_mac="${4}" + + if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then + if [ -n "${use_unique_bridge}" ]; then + if [ "$(echo -n "e0a_${jail_name}" | awk '{print length}')" -lt 16 ]; then + local host_epair=e0a_${jail_name} + local jail_epair=e0b_${jail_name} + else + name_prefix="$(echo ${jail_name} | cut -c1-7)" + name_suffix="$(echo ${jail_name} | rev | cut -c1-2 | rev)" + local host_epair="e0a_${name_prefix}xx${name_suffix}" + local jail_epair="e0b_${name_prefix}xx${name_suffix}" + fi + else + if [ "$(echo -n "e0a_${jail_name}" | awk '{print length}')" -lt 16 ]; then + local host_epair=e0a_${jail_name} + local jail_epair=e0b_${jail_name} + local jib_epair=${jail_name} + else + name_prefix="$(echo ${jail_name} | cut -c1-7)" + name_suffix="$(echo ${jail_name} | rev | cut -c1-2 | rev)" + local host_epair="e0a_${name_prefix}xx${name_suffix}" + local jail_epair="e0b_${name_prefix}xx${name_suffix}" + local jib_epair="${name_prefix}xx${name_suffix}" + fi + fi + elif [ "${bastille_network_vnet_type}" = "netgraph" ]; then + if [ "$(echo -n "ng0_${jail_name}" | awk '{print length}')" -lt 16 ]; then + local ng_if=ng0_${jail_name} + local jng_if=${jail_name} + else + name_prefix="$(echo ${jail_name} | cut -c1-7)" + name_suffix="$(echo ${jail_name} | rev | cut -c1-2 | rev)" + local ng_if="ng0_${name_prefix}xx${name_suffix}" + local jng_if="${name_prefix}xx${name_suffix}" + fi + fi + + ## If BRIDGE is enabled, generate bridge config, else generate VNET config + if [ -n "${use_unique_bridge}" ]; then + if [ -n "${static_mac}" ]; then + ## Generate bridged VNET config with static MAC address + generate_static_mac "${jail_name}" "${external_interface}" + cat <<-EOF + vnet; + vnet.interface = ${jail_epair}; + exec.prestart += "epair0=\\\$(ifconfig epair create) && ifconfig \\\${epair0} up name ${host_epair} && ifconfig \\\${epair0%a}b up name ${jail_epair}"; + exec.prestart += "ifconfig ${external_interface} addm ${host_epair}"; + exec.prestart += "ifconfig ${host_epair} ether ${macaddr}a"; + exec.prestart += "ifconfig ${jail_epair} ether ${macaddr}b"; + exec.prestart += "ifconfig ${host_epair} description \"vnet0 host interface for Bastille jail ${jail_name}\""; + exec.poststop += "ifconfig ${host_epair} destroy"; +EOF + else + ## Generate bridged VNET config without static MAC address + cat <<-EOF + vnet; + vnet.interface = ${jail_epair}; + exec.prestart += "epair0=\\\$(ifconfig epair create) && ifconfig \\\${epair0} up name ${host_epair} && ifconfig \\\${epair0%a}b up name ${jail_epair}"; + exec.prestart += "ifconfig ${external_interface} addm ${host_epair}"; + exec.prestart += "ifconfig ${host_epair} description \"vnet0 host interface for Bastille jail ${jail_name}\""; + exec.poststop += "ifconfig ${host_epair} destroy"; +EOF + fi + else + if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then + if [ -n "${static_mac}" ]; then + ## Generate VNET config with static MAC address + generate_static_mac "${jail_name}" "${external_interface}" + cat <<-EOF + vnet; + vnet.interface = ${jail_epair}; + exec.prestart += "jib addm ${jib_epair} ${external_interface}"; + exec.prestart += "ifconfig ${host_epair} ether ${macaddr}a"; + exec.prestart += "ifconfig ${jail_epair} ether ${macaddr}b"; + exec.prestart += "ifconfig ${host_epair} description \"vnet0 host interface for Bastille jail ${jail_name}\""; + exec.poststop += "ifconfig ${host_epair} destroy"; +EOF + else + ## Generate VNET config without static MAC address + cat <<-EOF + vnet; + vnet.interface = ${jail_epair}; + exec.prestart += "jib addm ${jib_epair} ${external_interface}"; + exec.prestart += "ifconfig ${host_epair} description \"vnet0 host interface for Bastille jail ${jail_name}\""; + exec.poststop += "ifconfig ${host_epair} destroy"; +EOF + fi + elif [ "${bastille_network_vnet_type}" = "netgraph" ]; then + if [ -n "${static_mac}" ]; then + ## Generate VNET config with static MAC address + generate_static_mac "${jail_name}" "${external_interface}" + cat <<-EOF + vnet; + vnet.interface = ${ng_if}; + exec.prestart += "jng bridge ${jng_if} ${external_interface}"; + exec.prestart += "ifconfig ${ng_if} ether ${macaddr}b"; + exec.poststop += "jng shutdown ${jng_if}"; +EOF + else + ## Generate VNET config without static MAC address + cat <<-EOF + vnet; + vnet.interface = ${ng_if}; + exec.prestart += "jng bridge ${jng_if} ${external_interface}"; + exec.poststop += "jng shutdown ${jng_if}"; +EOF + fi + fi + fi +} + +validate_netconf() { + + # Add default 'bastille_network_vnet_type' on old config file + # This is so we don't have to indtroduce a 'breaking change' statement + if ! grep -oq "bastille_network_vnet_type=" "${BASTILLE_CONFIG}"; then + sed -i '' "s|## Networking|&\nbastille_network_vnet_type=\"if_bridge\" ## default: \"if_bridge\"|" ${BASTILLE_CONFIG} + # shellcheck disable=SC1090 + . ${BASTILLE_CONFIG} + fi + + # Validate that 'bastille_network_vnet_type' has been set + if [ -n "${bastille_network_loopback}" ] && [ -n "${bastille_network_shared}" ]; then + error_exit "[ERROR]: 'bastille_network_loopback' and 'bastille_network_shared' cannot both be set." + fi + if [ "${bastille_network_vnet_type}" != "if_bridge" ] && [ "${bastille_network_vnet_type}" != "netgraph" ]; then + error_exit "[ERROR]: 'bastille_network_vnet_type' not set properly: ${bastille_network_vnet_type}" + fi +} + +checkyesno() { + ## copied from /etc/rc.subr -- cedwards (20231125) + ## issue #368 (lowercase values should be parsed) + ## now used for all bastille_zfs_enable=YES|NO tests + ## example: if checkyesno bastille_zfs_enable; then ... + ## returns 0 for enabled; returns 1 for disabled + eval _value=\$${1} + case $_value in + [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) + return 0 + ;; + [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) + return 1 + ;; + *) + warn "\$${1} is not set properly - see rc.conf(5)." + return 1 + ;; + esac +} + +update_jail_syntax_v1() { + + local jail="${1}" + local jail_config="${bastille_jailsdir}/${jail}/jail.conf" + local jail_rc_config="${bastille_jailsdir}/${jail}/root/etc/rc.conf" + + # Only apply if old syntax is found + if grep -Eoq "exec.prestart.*ifconfig epair[0-9]+ create.*" "${jail_config}"; then + + if [ "$(echo -n "e0a_${jail}" | awk '{print length}')" -lt 16 ]; then + local new_host_epair=e0a_${jail} + local new_jail_epair=e0b_${jail} + else + name_prefix="$(echo ${jail} | cut -c1-7)" + name_suffix="$(echo ${jail} | rev | cut -c1-2 | rev)" + local new_host_epair="e0a_${name_prefix}xx${name_suffix}" + local new_jail_epair="e0b_${name_prefix}xx${name_suffix}" + fi + + # Delete unneeded lines + sed -i '' "/.*exec.prestart.*ifconfig.*up name.*;/d" "${jail_config}" + sed -i '' "/.*exec.poststop.*ifconfig.*deletem.*;/d" "${jail_config}" + + # Change jail.conf + sed -i '' "s|.*vnet.interface =.*| vnet.interface = ${new_jail_epair};|g" "${jail_config}" + sed -i '' "s|.*ifconfig epair.*create.*| exec.prestart += \"epair0=\\\\\$(ifconfig epair create) \&\& ifconfig \\\\\${epair0} up name ${new_host_epair} \&\& ifconfig \\\\\${epair0%a}b up name ${new_jail_epair}\";|g" "${jail_config}" + sed -i '' "s|addm.*|addm ${new_host_epair}\";|g" "${jail_config}" + sed -i '' "/ether.*:.*:.*:.*:.*:.*a/ s|ifconfig.*ether|ifconfig ${new_host_epair} ether|g" "${jail_config}" + sed -i '' "/ether.*:.*:.*:.*:.*:.*b/ s|ifconfig.*ether|ifconfig ${new_jail_epair} ether|g" "${jail_config}" + sed -i '' "s|ifconfig.*description|ifconfig ${new_host_epair} description|g" "${jail_config}" + sed -i '' "s|ifconfig.*destroy|ifconfig ${new_host_epair} destroy|g" "${jail_config}" + + # Change rc.conf + sed -i '' "/ifconfig_.*_name.*vnet.*/ s|ifconfig_.*_name|ifconfig_${new_jail_epair}_name|g" "${jail_rc_config}" + + elif grep -Eoq "exec.poststop.*jib destroy.*" "${jail_config}"; then + + local external_interface="$(grep -Eo "jib addm.*" "${jail_config}" | awk '{print $4}')" + + if [ "$(echo -n "e0a_${jail}" | awk '{print length}')" -lt 16 ]; then + local new_host_epair=e0a_${jail} + local new_jail_epair=e0b_${jail} + local jib_epair="${jail}" + else + name_prefix="$(echo ${jail} | cut -c1-7)" + name_suffix="$(echo ${jail} | rev | cut -c1-2 | rev)" + local new_host_epair="e0a_${name_prefix}xx${name_suffix}" + local new_jail_epair="e0b_${name_prefix}xx${name_suffix}" + local jib_epair="${name_prefix}xx${name_suffix}" + fi + + # Change jail.conf + sed -i '' "s|.*vnet.interface =.*| vnet.interface = ${new_jail_epair};|g" "${jail_config}" + sed -i '' "s|jib addm.*|jib addm ${jib_epair} ${external_interface}|g" "${jail_config}" + sed -i '' "/ether.*:.*:.*:.*:.*:.*a/ s|ifconfig.*ether|ifconfig ${new_host_epair} ether|g" "${jail_config}" + sed -i '' "/ether.*:.*:.*:.*:.*:.*b/ s|ifconfig.*ether|ifconfig ${new_jail_epair} ether|g" "${jail_config}" + sed -i '' "s|ifconfig.*description|ifconfig ${new_host_epair} description|g" "${jail_config}" + sed -i '' "s|jib destroy.*|ifconfig ${new_host_epair} destroy\";|g" "${jail_config}" + + # Change rc.conf + sed -i '' "/ifconfig_.*_name.*vnet.*/ s|ifconfig_.*_name|ifconfig_${new_jail_epair}_name|g" "${jail_rc_config}" + + fi +} + +set_bastille_mountpoints diff --git a/usr/local/share/bastille/config.sh b/usr/local/share/bastille/config.sh index ccffb3c5..e64bc603 100644 --- a/usr/local/share/bastille/config.sh +++ b/usr/local/share/bastille/config.sh @@ -88,13 +88,12 @@ shift 2 set_target "${TARGET}" case "${ACTION}" in - get) + get|remove) if [ "$#" -ne 1 ]; then - error_notify 'Too many parameters for [get|remove] operation.' - usage + error_exit "[ERROR]: Too many parameters for [get|remove] operation." fi ;; - add|set|remove) + add|set) ;; *) error_exit "[ERROR]: Only (add|set), get and remove are supported." @@ -125,8 +124,6 @@ print_jail_conf() { } for _jail in ${JAILS}; do - - ( # Backwards compatibility for specifying only an IP with ip[4|6].addr if [ "${ACTION}" = "set" ] && [ "${PROPERTY}" = "ip4.addr" ]; then @@ -310,13 +307,8 @@ for _jail in ${JAILS}; do rm "${_tmpfile}" fi fi - - ) & - - bastille_running_jobs "${bastille_process_limit}" done -wait # Only display this message once at the end (not for every jail). -- cwells if { [ "${ACTION}" = "set" ] || [ "${ACTION}" = "remove" ]; } && [ "${BASTILLE_PROPERTY}" -eq 0 ]; then diff --git a/usr/local/share/bastille/console.sh b/usr/local/share/bastille/console.sh index 7d4111d3..a553fa63 100644 --- a/usr/local/share/bastille/console.sh +++ b/usr/local/share/bastille/console.sh @@ -140,7 +140,7 @@ for _jail in ${JAILS}; do else check_fib "${_jail}" LOGIN="$(jexec -l "${_jail}" which login)" - ${_setfib} jexec -l "${_jail}" $LOGIN -f root + ${_setfib} jexec -l "${_jail}" ${LOGIN} -f root fi done diff --git a/usr/local/share/bastille/cp.sh b/usr/local/share/bastille/cp.sh index 10d4760e..26d27956 100644 --- a/usr/local/share/bastille/cp.sh +++ b/usr/local/share/bastille/cp.sh @@ -83,26 +83,25 @@ fi TARGET="${1}" HOST_PATH="${2}" JAIL_PATH="${3}" +ERRORS=0 bastille_root_check set_target "${TARGET}" for _jail in ${JAILS}; do - ( - info "\n[${_jail}]:" host_path="${HOST_PATH}" jail_path="$(echo ${bastille_jailsdir}/${_jail}/root/${JAIL_PATH} | sed 's#//#/#g')" if ! cp "${OPTION}" "${host_path}" "${jail_path}"; then + ERRORS=$((ERRORS + 1)) error_continue "[ERROR]: CP failed: ${host_path} -> ${jail_path}" fi - - ) & - - bastille_running_jobs "${bastille_process_limit}" done -wait + +if [ "${ERRORS}" -ne 0 ]; then + error_exit "[ERROR]: Command failed on ${ERRORS} jails." +fi diff --git a/usr/local/share/bastille/jcp.sh b/usr/local/share/bastille/jcp.sh index 0e2c736a..ec522679 100644 --- a/usr/local/share/bastille/jcp.sh +++ b/usr/local/share/bastille/jcp.sh @@ -84,6 +84,7 @@ SOURCE_TARGET="${1}" SOURCE_PATH="${2}" DEST_TARGET="${3}" DEST_PATH="${4}" +ERRORS=0 bastille_root_check set_target_single "${SOURCE_TARGET}" && SOURCE_TARGET="${TARGET}" @@ -91,8 +92,6 @@ set_target "${DEST_TARGET}" && DEST_TARGET="${JAILS}" for _jail in ${DEST_TARGET}; do - ( - if [ "${_jail}" = "${SOURCE_TARGET}" ]; then continue else @@ -103,14 +102,14 @@ for _jail in ${DEST_TARGET}; do dest_path="$(echo ${bastille_jailsdir}/${_jail}/root/${DEST_PATH} | sed 's#//#/#g')" if ! cp "${OPTION}" "${source_path}" "${dest_path}"; then + ERRORS=$((ERRORS + 1)) error_continue "[ERROR]: JCP failed: ${source_path} -> ${dest_path}" fi fi - - ) & - - bastille_running_jobs "${bastille_process_limit}" done -wait \ No newline at end of file + +if [ "${ERRORS}" -ne 0 ]; then + error_exit "[ERROR]: Command failed on ${ERRORS} jails." +fi \ No newline at end of file diff --git a/usr/local/share/bastille/limits.sh b/usr/local/share/bastille/limits.sh index 472f3ef6..64058311 100644 --- a/usr/local/share/bastille/limits.sh +++ b/usr/local/share/bastille/limits.sh @@ -139,8 +139,6 @@ add_cpuset() { for _jail in ${JAILS}; do - ( - check_target_is_running "${_jail}" || if [ "${AUTO}" -eq 1 ]; then bastille start "${_jail}" else @@ -301,10 +299,5 @@ for _jail in ${JAILS}; do ;; esac - - ) & - bastille_running_jobs "${bastille_process_limit}" - -done -wait +done \ No newline at end of file diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index 6b0d6d40..386859f5 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -144,8 +144,6 @@ fi for _jail in ${JAILS}; do - ( - check_target_is_running "${_jail}" || if [ "${AUTO}" -eq 1 ]; then bastille start "${_jail}" else @@ -202,10 +200,5 @@ for _jail in ${JAILS}; do echo "${_fstab_entry}" >> "${bastille_jailsdir}/${_jail}/fstab" || error_continue "Failed to create fstab entry: ${_fstab_entry}" mount -F "${bastille_jailsdir}/${_jail}/fstab" -a || error_continue "Failed to mount volume: ${_fullpath}" echo "Added: ${_fstab_entry}" - - ) & - - bastille_running_jobs "${bastille_process_limit}" - + done -wait diff --git a/usr/local/share/bastille/pkg.sh b/usr/local/share/bastille/pkg.sh index 677b4f4a..c0a03b09 100644 --- a/usr/local/share/bastille/pkg.sh +++ b/usr/local/share/bastille/pkg.sh @@ -96,14 +96,12 @@ fi TARGET="${1}" shift -# Use mktemp to store exit codes -export TMP_BASTILLE_EXIT_CODE="$(mktemp)" -echo 0 > "${TMP_BASTILLE_EXIT_CODE}" +ERRORS=0 bastille_root_check set_target "${TARGET}" -pkg_run_command() { +for _jail in ${JAILS}; do # Validate jail state check_target_is_running "${_jail}" || if [ "${AUTO}" -eq 1 ]; then @@ -136,12 +134,14 @@ pkg_run_command() { fi fi - bastille_check_exit_code "${_jail}" "$?" -} - -for _jail in ${JAILS}; do - pkg_run_command "$@" + if [ "$?" -ne 0 ]; then + ERRORS=$((ERRORS + 1)) + fi + done -echo -bastille_return_exit_code +if [ "${ERRORS}" -ne 0 ]; then + error_exit "[ERROR]: Command failed on ${ERRORS} jails." +fi + +echo \ No newline at end of file diff --git a/usr/local/share/bastille/restart.sh b/usr/local/share/bastille/restart.sh index dc1aed1b..4703531f 100644 --- a/usr/local/share/bastille/restart.sh +++ b/usr/local/share/bastille/restart.sh @@ -112,17 +112,12 @@ set_target "${TARGET}" for _jail in ${JAILS}; do - ( - # Only restart running jails if check_target_is_running "${_jail}"; then bastille stop ${_stop_options} ${_jail} bastille start ${_start_options} ${_jail} fi - ) & - - bastille_running_jobs "${bastille_process_limit}" - done -wait \ No newline at end of file + +echo \ No newline at end of file diff --git a/usr/local/share/bastille/service.sh b/usr/local/share/bastille/service.sh index b2988066..b909ee33 100644 --- a/usr/local/share/bastille/service.sh +++ b/usr/local/share/bastille/service.sh @@ -82,9 +82,7 @@ fi TARGET="${1}" shift -# Use mktemp to store exit codes -export TMP_BASTILLE_EXIT_CODE="$(mktemp)" -echo 0 > "${TMP_BASTILLE_EXIT_CODE}" +ERRORS=0 bastille_root_check set_target "${TARGET}" @@ -104,9 +102,14 @@ for _jail in ${JAILS}; do jexec -l "${_jail}" /usr/sbin/service "$@" - bastille_check_exit_code "${_jail}" "$?" - -done -echo + if [ "$?" -ne 0 ]; then + ERRORS=$((ERRORS + 1)) + fi -bastille_return_exit_code +done + +if [ "${ERRORS}" -ne 0 ]; then + error_exit "[ERROR]: Command failed on ${ERRORS} jails." +fi + +echo \ No newline at end of file diff --git a/usr/local/share/bastille/start.sh b/usr/local/share/bastille/start.sh index 93805d99..f36e5f00 100644 --- a/usr/local/share/bastille/start.sh +++ b/usr/local/share/bastille/start.sh @@ -104,8 +104,6 @@ set_target "${TARGET}" for _jail in ${JAILS}; do - ( - # Continue if '-b|--boot' is set and 'boot=off' if [ "${BOOT}" -eq 1 ]; then BOOT_ENABLED="$(sysrc -f ${bastille_jailsdir}/${_jail}/settings.conf -n boot)" @@ -219,10 +217,5 @@ for _jail in ${JAILS}; do # Delay between jail action sleep "${DELAY_TIME}" - - ) & - bastille_running_jobs "${bastille_process_limit}" - -done -wait \ No newline at end of file +done \ No newline at end of file diff --git a/usr/local/share/bastille/stop.sh b/usr/local/share/bastille/stop.sh index 09707da9..15a2c736 100644 --- a/usr/local/share/bastille/stop.sh +++ b/usr/local/share/bastille/stop.sh @@ -87,8 +87,6 @@ set_target "${TARGET}" "reverse" for _jail in ${JAILS}; do - ( - # Validate that all jails that 'depend' on this one are stopped for _depend_jail in $(ls --color=never ${bastille_jailsdir} | sed -e 's/\n//g'); do if ! grep -hoqsw "depend=" ${bastille_jailsdir}/${_depend_jail}/settings.conf; then @@ -161,9 +159,4 @@ for _jail in ${JAILS}; do update_jail_syntax_v1 "${_jail}" - ) & - - bastille_running_jobs "${bastille_process_limit}" - done -wait diff --git a/usr/local/share/bastille/sysrc.sh b/usr/local/share/bastille/sysrc.sh index 72e1bafd..d8f2cc75 100644 --- a/usr/local/share/bastille/sysrc.sh +++ b/usr/local/share/bastille/sysrc.sh @@ -82,17 +82,13 @@ fi TARGET="${1}" shift -# Use mktemp to store exit codes -export TMP_BASTILLE_EXIT_CODE="$(mktemp)" -echo 0 > "${TMP_BASTILLE_EXIT_CODE}" +ERRORS=0 bastille_root_check set_target "${TARGET}" for _jail in ${JAILS}; do - ( - # Validate jail state check_target_is_running "${_jail}" || if [ "${AUTO}" -eq 1 ]; then bastille start "${_jail}" @@ -106,14 +102,14 @@ for _jail in ${JAILS}; do jexec -l "${_jail}" /usr/sbin/sysrc "$@" - bastille_check_exit_code "${_jail}" "$?" - - ) & - - bastille_running_jobs "${bastille_process_limit}" + if [ "$?" -ne 0 ]; then + ERRORS=$((ERRORS + 1)) + fi done -wait -echo -bastille_return_exit_code +if [ "${ERRORS}" -ne 0 ]; then + error_exit "[ERROR]: Command failed on ${ERRORS} jails." +fi + +echo \ No newline at end of file diff --git a/usr/local/share/bastille/tags.sh b/usr/local/share/bastille/tags.sh index 1f4d7cf8..7c6423d8 100644 --- a/usr/local/share/bastille/tags.sh +++ b/usr/local/share/bastille/tags.sh @@ -77,8 +77,6 @@ set_target "${TARGET}" for _jail in ${JAILS}; do - ( - bastille_jail_tags="${bastille_jailsdir}/${_jail}/tags" case ${ACTION} in add) @@ -120,9 +118,4 @@ for _jail in ${JAILS}; do ;; esac - ) & - - bastille_running_jobs "${bastille_process_limit}" - done -wait diff --git a/usr/local/share/bastille/template.sh b/usr/local/share/bastille/template.sh index f3a40cf1..bf05ebe8 100644 --- a/usr/local/share/bastille/template.sh +++ b/usr/local/share/bastille/template.sh @@ -272,8 +272,6 @@ fi for _jail in ${JAILS}; do - ( - check_target_is_running "${_jail}" || if [ "${AUTO}" -eq 1 ]; then bastille start "${_jail}" else @@ -475,10 +473,5 @@ for _jail in ${JAILS}; do done info "\nTemplate applied: ${TEMPLATE}" - - ) & - - bastille_running_jobs "${bastille_process_limit}" done -wait diff --git a/usr/local/share/bastille/umount.sh b/usr/local/share/bastille/umount.sh index 37d8d082..4aa1e421 100644 --- a/usr/local/share/bastille/umount.sh +++ b/usr/local/share/bastille/umount.sh @@ -88,8 +88,6 @@ set_target "${TARGET}" for _jail in ${JAILS}; do - ( - # Validate jail state check_target_is_running "${_jail}" || if [ "${AUTO}" -eq 1 ]; then bastille start "${_jail}" @@ -130,9 +128,6 @@ for _jail in ${JAILS}; do echo "Unmounted: ${_jailpath}" - ) & - - bastille_running_jobs "${bastille_process_limit}" - done -wait \ No newline at end of file + +echo \ No newline at end of file