From 51bf51283557671f88543171c4897da638786ef3 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 22 Feb 2025 12:14:04 -0700 Subject: [PATCH 1/4] destroy: New functions --- usr/local/share/bastille/destroy.sh | 302 +++++++++++++++------------- 1 file changed, 166 insertions(+), 136 deletions(-) diff --git a/usr/local/share/bastille/destroy.sh b/usr/local/share/bastille/destroy.sh index 56d8d7f3..c2a725ea 100644 --- a/usr/local/share/bastille/destroy.sh +++ b/usr/local/share/bastille/destroy.sh @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: BSD-3-Clause # -# Copyright (c) 2018-2025, Christer Edwards +# Copyright (c) 2018-2024, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -34,79 +34,88 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille destroy [force] | [container|release]" + error_notify "Usage: bastille destroy [option(s)] [JAIL|RELEASE]" + cat << EOF + Options: + + -a | --auto Auto mode. Start/stop jail(s) if required. + -f | --force Force unmount any mounted datasets when destroying a jail or release (ZFS only). + -c | --no-cache Do no destroy cache when destroying a release. + -x | --debug Enable debug mode. + +EOF + exit 1 } destroy_jail() { - local OPTIONS - bastille_jail_base="${bastille_jailsdir}/${TARGET}" ## dir - bastille_jail_log="${bastille_logsdir}/${TARGET}_console.log" ## file - if [ "$(/usr/sbin/jls name | awk "/^${TARGET}$/")" ]; then - if [ "${FORCE}" = "1" ]; then - bastille stop "${TARGET}" - else - error_notify "Jail running." - error_exit "See 'bastille stop ${TARGET}'." - fi - fi + local OPTIONS - if [ ! -d "${bastille_jail_base}" ]; then - error_exit "Jail not found." - fi - - if [ -d "${bastille_jail_base}" ]; then - ## make sure no filesystem is currently mounted in the jail directory - mount_points=$(mount | cut -d ' ' -f 3 | grep "${bastille_jail_base}"/root/) - if [ -n "${mount_points}" ]; then - error_notify "Failed to destroy jail: ${TARGET}" - error_exit "Jail has mounted filesystems:\n$mount_points" - fi - info "Deleting Jail: ${TARGET}." - if checkyesno bastille_zfs_enable; then - if [ -n "${bastille_zfs_zpool}" ]; then - if [ -n "${TARGET}" ]; then - OPTIONS="-r" - if [ "${FORCE}" = "1" ]; then - OPTIONS="-rf" - fi - ## remove jail zfs dataset recursively - zfs destroy "${OPTIONS}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}" - fi - fi + for _jail in ${JAILS}; do + + bastille_jail_base="${bastille_jailsdir}/${_jail}" ## dir + bastille_jail_log="${bastille_logsdir}/${_jail}_console.log" ## file + + check_target_is_stopped "${_jail}" || if [ "${AUTO}" -eq 1 ]; then + bastille stop "${_jail}" + else + error_notify "Jail is running." + error_continue "Use [-a|--auto] to auto-stop the jail." fi if [ -d "${bastille_jail_base}" ]; then - ## removing all flags - chflags -R noschg "${bastille_jail_base}" + ## make sure no filesystem is currently mounted in the jail directory + mount_points="$(mount | cut -d ' ' -f 3 | grep ${bastille_jail_base}/root/)" + if [ -n "${mount_points}" ]; then + error_notify "Failed to destroy jail: ${_jail}" + error_continue "Jail has mounted filesystems:\n$mount_points" + fi + info "Deleting Jail: ${_jail}." + if checkyesno bastille_zfs_enable; then + if [ -n "${bastille_zfs_zpool}" ]; then + if [ -n "${_jail}" ]; then + OPTIONS="-r" + if [ "${FORCE}" = "1" ]; then + OPTIONS="-rf" + fi + ## remove jail zfs dataset recursively + zfs destroy "${OPTIONS}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}" + fi + fi + fi - ## remove jail base - rm -rf "${bastille_jail_base}" - fi + if [ -d "${bastille_jail_base}" ]; then + ## removing all flags + chflags -R noschg "${bastille_jail_base}" + + ## remove jail base + rm -rf "${bastille_jail_base}" + fi - # Remove target from bastille_list if exist - # Mute sysrc output here as it may be undesirable on large startup list - if [ -n "$(sysrc -qn bastille_list | tr -s " " "\n" | awk "/^${TARGET}$/")" ]; then - sysrc bastille_list-="${TARGET}" > /dev/null - fi + # Remove target from bastille_list if exist + # Mute sysrc output here as it may be undesirable on large startup list + if [ -n "$(sysrc -qn bastille_list | tr -s " " "\n" | awk "/^${_jail}$/")" ]; then + sysrc bastille_list-="${_jail}" > /dev/null + fi - ## archive jail log - if [ -f "${bastille_jail_log}" ]; then - mv "${bastille_jail_log}" "${bastille_jail_log}"-"$(date +%F)" - info "Note: jail console logs archived." - info "${bastille_jail_log}-$(date +%F)" - fi + ## archive jail log + if [ -f "${bastille_jail_log}" ]; then + mv "${bastille_jail_log}" "${bastille_jail_log}"-"$(date +%F)" + info "Note: jail console logs archived." + info "${bastille_jail_log}-$(date +%F)" + fi - ## clear any active rdr rules - if [ ! -z "$(pfctl -a "rdr/${TARGET}" -Psn 2>/dev/null)" ]; then - info "Clearing RDR rules:" - pfctl -a "rdr/${TARGET}" -Fn + ## clear any active rdr rules + if [ ! -z "$(pfctl -a "rdr/${_jail}" -Psn 2>/dev/null)" ]; then + info "Clearing RDR rules:" + pfctl -a "rdr/${_jail}" -Fn + fi fi - echo - fi + done } destroy_rel() { + local OPTIONS ## check release name match before destroy @@ -160,7 +169,7 @@ destroy_rel() { OPTIONS="-rf" fi zfs destroy "${OPTIONS}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/releases/${TARGET}" - if [ "${FORCE}" = "1" ]; then + if [ "${NO_CACHE}" = "0" ]; then if [ -d "${bastille_cachedir}/${TARGET}" ]; then zfs destroy "${OPTIONS}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/cache/${TARGET}" fi @@ -177,98 +186,119 @@ destroy_rel() { rm -rf "${bastille_rel_base}" fi - if [ "${FORCE}" = "1" ]; then - ## remove cache on force + if [ "${NO_CACHE}" = "0" ]; then + ## remove cache by default if [ -d "${bastille_cachedir}/${TARGET}" ]; then - rm -rf "${bastille_cachedir:?}/${TARGET}" + rm -rf "${bastille_cachedir:?}/${TARGET:?}" fi fi - echo else error_notify "Cannot destroy base with child containers." fi fi } -# Handle special-case commands first. -case "$1" in -help|-h|--help) - usage - ;; -esac +# Handle options. +AUTO=0 +FORCE=0 +NO_CACHE=0 +while [ "$#" -gt 0 ]; do + case "${1}" in + -h|--help|help) + usage + ;; + -a|--auto) + AUTO=1 + shift + ;; + -c|--no-cache) + NO_CACHE=1 + shift + ;; + -f|--force) + FORCE=1 + shift + ;; + -x|--debug) + enable_debug + shift + ;; + -*) + for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do + case ${_opt} in + a) AUTO=1 ;; + c) NO_CACHE=1 ;; + f) FORCE=1 ;; + x) enable_debug ;; + *) error_exit "Unknown Option: \"${1}\"" ;; + esac + done + shift + ;; + *) + break + ;; + esac +done -## reset this options -FORCE="" - -## handle additional options -case "${1}" in - -f|--force|force) - FORCE="1" - shift - ;; - -*) - error_notify "Unknown Option." - usage - ;; -esac - -TARGET="${1}" - -if [ $# -gt 1 ] || [ $# -lt 1 ]; then +if [ "$#" -ne 1 ]; then usage fi +TARGET="${1}" + bastille_root_check ## check what should we clean case "${TARGET}" in -*-CURRENT|*-CURRENT-I386|*-CURRENT-i386|*-current) - ## check for FreeBSD releases name - NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([1-9]{2,2})\.[0-9](-CURRENT|-CURRENT-i386)$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') - destroy_rel - ;; -*-RELEASE|*-RELEASE-I386|*-RELEASE-i386|*-release|*-RC[1-9]|*-rc[1-9]|*-BETA[1-9]) - ## check for FreeBSD releases name - NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([1-9]{2,2})\.[0-9](-RELEASE|-RELEASE-i386|-RC[1-9]|-BETA[1-9])$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') - destroy_rel - ;; -*-stable-LAST|*-STABLE-last|*-stable-last|*-STABLE-LAST) - ## check for HardenedBSD releases name - NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([1-9]{2,2})(-stable-last)$' | sed 's/STABLE/stable/g;s/last/LAST/g') - destroy_rel - ;; -*-stable-build-[0-9]*|*-STABLE-BUILD-[0-9]*) - ## check for HardenedBSD(specific stable build releases) - NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '([0-9]{1,2})(-stable-build)-([0-9]{1,3})$' | sed 's/BUILD/build/g;s/STABLE/stable/g') - destroy_rel - ;; -*-stable-build-latest|*-stable-BUILD-LATEST|*-STABLE-BUILD-LATEST) - ## check for HardenedBSD(latest stable build release) - NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '([0-9]{1,2})(-stable-build-latest)$' | sed 's/STABLE/stable/;s/build/BUILD/g;s/latest/LATEST/g') - destroy_rel - ;; -current-build-[0-9]*|CURRENT-BUILD-[0-9]*) - ## check for HardenedBSD(specific current build releases) - NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '(current-build)-([0-9]{1,3})' | sed 's/BUILD/build/g;s/CURRENT/current/g') - destroy_rel - ;; -current-build-latest|current-BUILD-LATEST|CURRENT-BUILD-LATEST) - ## check for HardenedBSD(latest current build release) - NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '(current-build-latest)$' | sed 's/CURRENT/current/;s/build/BUILD/g;s/latest/LATEST/g') - destroy_rel - ;; -Ubuntu_1804|Ubuntu_2004|Ubuntu_2204|UBUNTU_1804|UBUNTU_2004|UBUNTU_2204) - ## check for Linux releases - NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '(Ubuntu_1804)$|(Ubuntu_2004)$|(Ubuntu_2204)$' | sed 's/UBUNTU/Ubuntu/g;s/ubuntu/Ubuntu/g') - destroy_rel - ;; -Debian10|Debian11|Debian12|DEBIAN10|DEBIAN11|DEBIAN12) - ## check for Linux releases - NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '(Debian10)$|(Debian11)$|(Debian12)$' | sed 's/DEBIAN/Debian/g') - destroy_rel - ;; -*) - ## just destroy a jail - destroy_jail - ;; + *-CURRENT|*-CURRENT-I386|*-CURRENT-i386|*-current) + ## check for FreeBSD releases name + NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([1-9]{2,2})\.[0-9](-CURRENT|-CURRENT-i386)$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') + destroy_rel + ;; + *-RELEASE|*-RELEASE-I386|*-RELEASE-i386|*-release|*-RC[1-9]|*-rc[1-9]|*-BETA[1-9]) + ## check for FreeBSD releases name + NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([1-9]{2,2})\.[0-9](-RELEASE|-RELEASE-i386|-RC[1-9]|-BETA[1-9])$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') + destroy_rel + ;; + *-stable-LAST|*-STABLE-last|*-stable-last|*-STABLE-LAST) + ## check for HardenedBSD releases name + NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([1-9]{2,2})(-stable-last)$' | sed 's/STABLE/stable/g;s/last/LAST/g') + destroy_rel + ;; + *-stable-build-[0-9]*|*-STABLE-BUILD-[0-9]*) + ## check for HardenedBSD(specific stable build releases) + NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '([0-9]{1,2})(-stable-build)-([0-9]{1,3})$' | sed 's/BUILD/build/g;s/STABLE/stable/g') + destroy_rel + ;; + *-stable-build-latest|*-stable-BUILD-LATEST|*-STABLE-BUILD-LATEST) + ## check for HardenedBSD(latest stable build release) + NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '([0-9]{1,2})(-stable-build-latest)$' | sed 's/STABLE/stable/;s/build/BUILD/g;s/latest/LATEST/g') + destroy_rel + ;; + current-build-[0-9]*|CURRENT-BUILD-[0-9]*) + ## check for HardenedBSD(specific current build releases) + NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '(current-build)-([0-9]{1,3})' | sed 's/BUILD/build/g;s/CURRENT/current/g') + destroy_rel + ;; + current-build-latest|current-BUILD-LATEST|CURRENT-BUILD-LATEST) + ## check for HardenedBSD(latest current build release) + NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '(current-build-latest)$' | sed 's/CURRENT/current/;s/build/BUILD/g;s/latest/LATEST/g') + destroy_rel + ;; + Ubuntu_1804|Ubuntu_2004|Ubuntu_2204|UBUNTU_1804|UBUNTU_2004|UBUNTU_2204) + ## check for Linux releases + NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '(Ubuntu_1804)$|(Ubuntu_2004)$|(Ubuntu_2204)$' | sed 's/UBUNTU/Ubuntu/g;s/ubuntu/Ubuntu/g') + destroy_rel + ;; + Debian10|Debian11|Debian12|DEBIAN10|DEBIAN11|DEBIAN12) + ## check for Linux releases + NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '(Debian10)$|(Debian11)$|(Debian12)$' | sed 's/DEBIAN/Debian/g') + destroy_rel + ;; + *) + ## just destroy a jail + set_target "${TARGET}" + destroy_jail "${JAILS}" + ;; esac From 90a6445e353e0ed4afad16844a70a8e1199c4e71 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 22 Feb 2025 12:27:04 -0700 Subject: [PATCH 2/4] destroy: Copyright year > 2025 --- usr/local/share/bastille/destroy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/destroy.sh b/usr/local/share/bastille/destroy.sh index c2a725ea..b18a670a 100644 --- a/usr/local/share/bastille/destroy.sh +++ b/usr/local/share/bastille/destroy.sh @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: BSD-3-Clause # -# Copyright (c) 2018-2024, Christer Edwards +# Copyright (c) 2018-2025, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without From 20785971457bf735749319200279e5b852c355f4 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sun, 23 Feb 2025 09:40:08 -0700 Subject: [PATCH 3/4] docs: Document -c for destroy --- docs/chapters/subcommands/destroy.rst | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/docs/chapters/subcommands/destroy.rst b/docs/chapters/subcommands/destroy.rst index f800e386..2ef18414 100644 --- a/docs/chapters/subcommands/destroy.rst +++ b/docs/chapters/subcommands/destroy.rst @@ -2,26 +2,29 @@ destroy ======= -Containers can be destroyed and thrown away just as easily as they were -created. Note: containers must be stopped before destroyed. +Jails can be destroyed and thrown away just as easily as they were +created. Note: containers must be stopped before destroyed. Using +the `-a|--auto` option will automatically stop the jail before destroying it. .. code-block:: shell - ishmael ~ # bastille stop folsom + ishmael ~ # bastille destroy -a folsom [folsom]: folsom: removed - -.. code-block:: shell - - ishmael ~ # bastille destroy folsom Deleting Container: folsom. Note: containers console logs not destroyed. /usr/local/bastille/logs/folsom_console.log -Release can be destroyed provided there are no child jails. The `force` option -deletes the release cache directory as well: +Release can be destroyed provided there are no child jails. The `-c|--no-cache` option +will retain the releas cache directory, if you choose to keep it. .. code-block:: shell - ishmael ~ # bastille destroy force 14.0-RELEASE - Deleting base: 14.0-RELEASE + ishmael ~ # bastille destroy help + Usage: bastille destroy [option(s)] [JAIL|RELEASE] + Options: + + -a | --auto Auto mode. Start/stop jail(s) if required. + -f | --force Force unmount any mounted datasets when destroying a jail or release (ZFS only). + -c | --no-cache Do no destroy cache when destroying a release. + -x | --debug Enable debug mode. From ed255296d95d3712caf2bc796e8056ac1ace1b59 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sun, 23 Feb 2025 09:44:20 -0700 Subject: [PATCH 4/4] docs: More -c docs --- docs/chapters/upgrading.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/chapters/upgrading.rst b/docs/chapters/upgrading.rst index 1d9161eb..e78ff9a4 100644 --- a/docs/chapters/upgrading.rst +++ b/docs/chapters/upgrading.rst @@ -95,6 +95,6 @@ After upgrading all jails from one release to the next you may find that you now `bastille list releases` to list all bootstrapped releases. -`bastille destroy X.Y-RELEASE` to fully delete the release. +`bastille destroy X.Y-RELEASE` to fully delete the release, including the cache. -`bastille destroy [-f|--force] X.Y-RELEASE` to delete the cache directory as well. +`bastille destroy [-c|--no-cache] X.Y-RELEASE` to retain the cache directory.