From 5583ab1d7888a2ef3c3fcb5d33cc6d885c73bacd Mon Sep 17 00:00:00 2001 From: Jose Date: Wed, 3 Feb 2021 18:31:41 -0400 Subject: [PATCH 01/21] Add support bastille RAW image exports/imports, also extended help usage --- usr/local/share/bastille/export.sh | 134 +++++++++++++++++++---------- usr/local/share/bastille/import.sh | 38 ++++++-- 2 files changed, 120 insertions(+), 52 deletions(-) diff --git a/usr/local/share/bastille/export.sh b/usr/local/share/bastille/export.sh index 0397785..ed16851 100644 --- a/usr/local/share/bastille/export.sh +++ b/usr/local/share/bastille/export.sh @@ -32,7 +32,13 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille export TARGET [option] | PATH" + error_exit "Usage: bastille export TARGET [options] | PATH + \n + \nOptions: + \n + -t|--txz -- Export to a standard .txz archive even if bastille is configured for zfs\n + -s|--safe -- Safely stop the jail to snapshot it then start it again to proceed exporting\n + -r|--raw -- Export the jail to an uncompressed raw image\n" } # Handle special-case commands first @@ -47,40 +53,47 @@ if [ "${TARGET}" = "ALL" ]; then error_exit "Batch export is unsupported." fi -if [ $# -gt 2 ] || [ $# -lt 0 ]; then +if [ $# -gt 4 ] || [ $# -lt 0 ]; then usage fi -OPTION="${1}" -EXPATH="${2}" SAFE_EXPORT= +RAW_EXPORT= +DIR_EXPORT= -# Handle some options -if [ -n "${OPTION}" ]; then - if [ "${OPTION}" = "-t" -o "${OPTION}" = "--txz" ]; then - if [ "${bastille_zfs_enable}" = "YES" ]; then - # Temporarily disable ZFS so we can create a standard backup archive - bastille_zfs_enable="NO" - fi - elif [ "${OPTION}" = "-s" -o "${OPTION}" = "--safe" ]; then - SAFE_EXPORT="1" - elif echo "${OPTION}" | grep -q "\/"; then - if [ -d "${OPTION}" ]; then - EXPATH="${OPTION}" - else - error_exit "Error: Path not found." - fi - else - error_notify "Invalid option!" - usage - fi -fi +# Handle and parse option args +while [ $# -gt 0 ]; do + case "${1}" in + -t|--txz) + if [ "${bastille_zfs_enable}" = "YES" ]; then + bastille_zfs_enable="NO" + fi + shift + ;; + -s|--safe) + SAFE_EXPORT="1" + shift + ;; + -r|--raw) + RAW_EXPORT="1" + shift + ;; + *) + if echo "${1}" | grep -q "\/"; then + DIR_EXPORT="${1}" + else + usage + fi + shift + ;; + esac +done # Export directory check -if [ -n "${EXPATH}" ]; then - if [ -d "${EXPATH}" ]; then +if [ -n "${DIR_EXPORT}" ]; then + if [ -d "${DIR_EXPORT}" ]; then # Set the user defined export directory - bastille_backupsdir="${EXPATH}" + bastille_backupsdir="${DIR_EXPORT}" else error_exit "Error: Path not found." fi @@ -92,36 +105,63 @@ create_zfs_snap(){ zfs snapshot -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" } +export_check(){ + # Inform the user about the exporting method + if [ -n "$(jls name | awk "/^${TARGET}$/")" ]; then + EXPORT_AS="Hot exporting" + else + EXPORT_AS="Exporting" + fi + if [ -n "${RAW_EXPORT}" ]; then + EXPORT_INFO="to a raw" + else + EXPORT_INFO="to a compressed ${FILE_EXT}" + fi + + # Safely stop and snapshot the jail + if [ -n "${SAFE_EXPORT}" ]; then + info "Safely exporting '${TARGET}' ${EXPORT_INFO} archive." + bastille stop ${TARGET} + create_zfs_snap + bastille start ${TARGET} + else + info "${EXPORT_AS} '${TARGET}' ${EXPORT_INFO} archive." + create_zfs_snap + fi + info "Sending ZFS data stream..." +} + jail_export() { # Attempt to export the container DATE=$(date +%F-%H%M%S) if [ "${bastille_zfs_enable}" = "YES" ]; then if [ -n "${bastille_zfs_zpool}" ]; then - FILE_EXT="xz" + if [ -n "${RAW_EXPORT}" ]; then + FILE_EXT="" + export_check - if [ -n "${SAFE_EXPORT}" ]; then - info "Safely exporting '${TARGET}' to a compressed .${FILE_EXT} archive." - bastille stop ${TARGET} - create_zfs_snap - bastille start ${TARGET} + # Export the raw container recursively and cleanup temporary snapshots + zfs send -R "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" \ + > "${bastille_backupsdir}/${TARGET}_${DATE}" + zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}/root@bastille_export_${DATE}" + zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" else - info "Hot exporting '${TARGET}' to a compressed .${FILE_EXT} archive." - create_zfs_snap - fi + FILE_EXT=".xz" + export_check - info "Sending ZFS data stream..." - # Export the container recursively and cleanup temporary snapshots - zfs send -R "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" | \ - xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}.${FILE_EXT}" - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}/root@bastille_export_${DATE}" - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" + # Export the container recursively and cleanup temporary snapshots + zfs send -R "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" | \ + xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}" + zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}/root@bastille_export_${DATE}" + zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" + fi fi else # Create standard backup archive - FILE_EXT="txz" - info "Exporting '${TARGET}' to a compressed .${FILE_EXT} archive..." - cd "${bastille_jailsdir}" && tar -cf - "${TARGET}" | xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}.${FILE_EXT}" + FILE_EXT=".txz" + info "Exporting '${TARGET}' to a compressed ${FILE_EXT} archive..." + cd "${bastille_jailsdir}" && tar -cf - "${TARGET}" | xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}" fi if [ "$?" -ne 0 ]; then @@ -129,8 +169,8 @@ jail_export() else # Generate container checksum file cd "${bastille_backupsdir}" - sha256 -q "${TARGET}_${DATE}.${FILE_EXT}" > "${TARGET}_${DATE}.sha256" - info "Exported '${bastille_backupsdir}/${TARGET}_${DATE}.${FILE_EXT}' successfully." + sha256 -q "${TARGET}_${DATE}${FILE_EXT}" > "${TARGET}_${DATE}.sha256" + info "Exported '${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}' successfully." exit 0 fi } diff --git a/usr/local/share/bastille/import.sh b/usr/local/share/bastille/import.sh index 4a77352..e0b5643 100644 --- a/usr/local/share/bastille/import.sh +++ b/usr/local/share/bastille/import.sh @@ -32,7 +32,11 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille import file [option]" + error_exit "Usage: bastille import FILE [option] + \n + \nOptions: + \n + -f|--force -- Force an archive import even if the checksum file is missing or don't match\n" } # Handle special-case commands first @@ -47,8 +51,21 @@ if [ $# -gt 2 ] || [ $# -lt 1 ]; then fi TARGET="${1}" -OPTION="${2}" shift +OPT_FORCE= + +# Handle and parse option args +while [ $# -gt 0 ]; do + case "${1}" in + -f|force|--force) + OPT_FORCE="1" + shift + ;; + *) + usage + ;; + esac +done validate_archive() { # Compare checksums on the target archive @@ -66,7 +83,7 @@ validate_archive() { fi else # Check if user opt to force import - if [ "${OPTION}" = "-f" -o "${OPTION}" = "force" ]; then + if [ -n "${OPT_FORCE}" ]; then warn "Warning: Skipping archive validation!" else error_exit "Checksum file not found. See 'bastille import TARGET -f'." @@ -403,6 +420,17 @@ jail_import() { else update_config fi + elif [ -z "${FILE_EXT}" ]; then + if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$'; then + # Based on the file name, looks like we are importing a raw bastille image + # Import from uncompressed image file + info "Importing '${TARGET_TRIM}' from uncompressed image archive." + info "Receiving ZFS data stream..." + zfs receive -u "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" < "${bastille_backupsdir}/${TARGET}" + + # Update ZFS mountpoint property if required + update_zfsmount + fi else error_exit "Unknown archive format." fi @@ -465,9 +493,9 @@ fi # Check if archive exist then trim archive name if [ -f "${bastille_backupsdir}/${TARGET}" ]; then # Filter unsupported/unknown archives - if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.xz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.txz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}.zip$\|-[0-9]\{12\}.[0-9]\{2\}.tar.gz$\|@[0-9]\{12\}.[0-9]\{2\}.tar$'; then + if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.xz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.txz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}.zip$\|-[0-9]\{12\}.[0-9]\{2\}.tar.gz$\|@[0-9]\{12\}.[0-9]\{2\}.tar$'; then if ls "${bastille_backupsdir}" | awk "/^${TARGET}$/" >/dev/null; then - TARGET_TRIM=$(echo "${TARGET}" | sed "s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.xz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.txz//;s/_[0-9]*-[0-9]*-[0-9]*.zip//;s/-[0-9]\{12\}.[0-9]\{2\}.tar.gz//;s/@[0-9]\{12\}.[0-9]\{2\}.tar//") + TARGET_TRIM=$(echo "${TARGET}" | sed "s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.xz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.txz//;s/_[0-9]*-[0-9]*-[0-9]*.zip//;s/-[0-9]\{12\}.[0-9]\{2\}.tar.gz//;s/@[0-9]\{12\}.[0-9]\{2\}.tar//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*//") fi else error_exit "Unrecognized archive name." From b31c8d514b66944046a5beb15d9d8e40c90cf86b Mon Sep 17 00:00:00 2001 From: Jose Date: Wed, 3 Feb 2021 20:39:30 -0400 Subject: [PATCH 02/21] Simplify options parsing and better handling for combined options --- usr/local/share/bastille/create.sh | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/usr/local/share/bastille/create.sh b/usr/local/share/bastille/create.sh index a92b41e..ce3cf6d 100644 --- a/usr/local/share/bastille/create.sh +++ b/usr/local/share/bastille/create.sh @@ -430,32 +430,36 @@ EMPTY_JAIL="" THICK_JAIL="" VNET_JAIL="" -## handle combined options then shift -if [ "${1}" = "-T" -o "${1}" = "--thick" -o "${1}" = "thick" ] && \ - [ "${2}" = "-V" -o "${2}" = "--vnet" -o "${2}" = "vnet" ]; then - THICK_JAIL="1" - VNET_JAIL="1" - shift 2 -else - ## handle single options +# Handle and parse options +while [ $# -gt 0 ]; do case "${1}" in -E|--empty|empty) - shift EMPTY_JAIL="1" + shift ;; -T|--thick|thick) - shift THICK_JAIL="1" + shift ;; -V|--vnet|vnet) - shift VNET_JAIL="1" + shift ;; - -*) + -*|--*) error_notify "Unknown Option." usage ;; + *) + break + ;; esac +done + +## validate for combined options +if [ -n "${EMPTY_JAIL}" ]; then + if [ -n "${THICK_JAIL}" ] || [ -n "${VNET_JAIL}" ]; then + error_exit "Error: Empty jail option can't be used with other options." + fi fi NAME="$1" From 80639062d7ec21bcee8e3cc28a82ff09ffe75cf1 Mon Sep 17 00:00:00 2001 From: Jose Date: Fri, 5 Feb 2021 13:59:09 -0400 Subject: [PATCH 03/21] Fix and improve the convert command --- usr/local/share/bastille/convert.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/usr/local/share/bastille/convert.sh b/usr/local/share/bastille/convert.sh index ae492ef..30d3469 100644 --- a/usr/local/share/bastille/convert.sh +++ b/usr/local/share/bastille/convert.sh @@ -57,6 +57,7 @@ convert_symlinks() { done # Copy new files to destination jail + info "Copying required base files to container..." for _link in ${SYMLINKS}; do if [ ! -d "${_link}" ]; then if [ -d "${bastille_releasesdir}/${RELEASE}/${_link}" ]; then @@ -100,13 +101,15 @@ revert_convert() { start_convert() { # Attempt container conversion and handle some errors + DATE=$(date) if [ -d "${bastille_jailsdir}/${TARGET}" ]; then info "Converting '${TARGET}' into a thickjail. This may take a while..." # Set some variables - RELEASE=$(grep -owE '([1-9]{2,2})\.[0-9](-RELEASE|-RELEASE-i386|-RC[1-2])|([0-9]{1,2}-stable-build-[0-9]{1,3})|(current-build)-([0-9]{1,3})|(current-BUILD-LATEST)|([0-9]{1,2}-stable-BUILD-LATEST)|(current-BUILD-LATEST)' "${bastille_jailsdir}/${TARGET}/fstab") + RELEASE=$(grep -w "${bastille_releasesdir}/.* ${bastille_jailsdir}/${TARGET}/root/.bastille" ${bastille_jailsdir}/${TARGET}/fstab | sed "s|${bastille_releasesdir}/||;s| .*||") FSTABMOD=$(grep -w "${bastille_releasesdir}/${RELEASE} ${bastille_jailsdir}/${TARGET}/root/.bastille" "${bastille_jailsdir}/${TARGET}/fstab") SYMLINKS="bin boot lib libexec rescue sbin usr/bin usr/include usr/lib usr/lib32 usr/libdata usr/libexec usr/ports usr/sbin usr/share usr/src" + HASPORTS=$(grep -w ${bastille_releasesdir}/${RELEASE}/usr/ports ${bastille_jailsdir}/${TARGET}/fstab) if [ -n "${RELEASE}" ]; then cd "${bastille_jailsdir}/${TARGET}/root" @@ -115,7 +118,12 @@ start_convert() { convert_symlinks # Comment the line containing .bastille and rename mountpoint - sed -i '' -E "s|${FSTABMOD}|# Converted from thin to thick container on $(date)|g" "${bastille_jailsdir}/${TARGET}/fstab" + sed -i '' -E "s|${FSTABMOD}|# Converted from thin to thick container on ${DATE}|g" "${bastille_jailsdir}/${TARGET}/fstab" + if [ -n "${HASPORTS}" ]; then + sed -i '' -E "s|${HASPORTS}|# Ports copied from base to container on ${DATE}|g" "${bastille_jailsdir}/${TARGET}/fstab" + info "Copying ports to container..." + cp -a "${bastille_releasesdir}/${RELEASE}/usr/ports" "${bastille_jailsdir}/${TARGET}/root/usr" + fi mv "${bastille_jailsdir}/${TARGET}/root/.bastille" "${bastille_jailsdir}/${TARGET}/root/.bastille.old" info "Conversion of '${TARGET}' completed successfully!" From 75ed5b3ce4c13a9d15fe07330ad732c4bd429873 Mon Sep 17 00:00:00 2001 From: Jose Date: Mon, 8 Feb 2021 04:17:32 -0400 Subject: [PATCH 04/21] Add quick check for pfctl command --- usr/local/share/bastille/stop.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/usr/local/share/bastille/stop.sh b/usr/local/share/bastille/stop.sh index c310655..b5ce8ee 100644 --- a/usr/local/share/bastille/stop.sh +++ b/usr/local/share/bastille/stop.sh @@ -55,9 +55,12 @@ for _jail in ${JAILS}; do pfctl -q -t jails -T delete "$(jls -j ${_jail} ip4.addr)" fi fi - - if [ "$(bastille rdr ${_jail} list)" ]; then - bastille rdr ${_jail} clear + + # Check if pfctl is present + if test -f /sbin/pfctl; then + if [ "$(bastille rdr ${_jail} list)" ]; then + bastille rdr ${_jail} clear + fi fi ## remove rctl limits From 211a268c36ecad5db055f260e43ce6133748513c Mon Sep 17 00:00:00 2001 From: Jose Date: Mon, 8 Feb 2021 05:31:16 -0400 Subject: [PATCH 05/21] Use which since shell built-in and search for paths --- usr/local/share/bastille/stop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/stop.sh b/usr/local/share/bastille/stop.sh index b5ce8ee..60a33e0 100644 --- a/usr/local/share/bastille/stop.sh +++ b/usr/local/share/bastille/stop.sh @@ -57,7 +57,7 @@ for _jail in ${JAILS}; do fi # Check if pfctl is present - if test -f /sbin/pfctl; then + if which -s pfctl; then if [ "$(bastille rdr ${_jail} list)" ]; then bastille rdr ${_jail} clear fi From 674e8ff087d1d360c77c248f688237e8f12ee404 Mon Sep 17 00:00:00 2001 From: Jose Date: Thu, 18 Feb 2021 06:48:43 -0400 Subject: [PATCH 06/21] More validation/checks for export command --- usr/local/share/bastille/export.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/usr/local/share/bastille/export.sh b/usr/local/share/bastille/export.sh index ed16851..9d935cc 100644 --- a/usr/local/share/bastille/export.sh +++ b/usr/local/share/bastille/export.sh @@ -60,11 +60,13 @@ fi SAFE_EXPORT= RAW_EXPORT= DIR_EXPORT= +TXZ_EXPORT= # Handle and parse option args while [ $# -gt 0 ]; do case "${1}" in -t|--txz) + TXZ_EXPORT="1" if [ "${bastille_zfs_enable}" = "YES" ]; then bastille_zfs_enable="NO" fi @@ -89,6 +91,17 @@ while [ $# -gt 0 ]; do esac done +## validate for combined options +if [ -n "${TXZ_EXPORT}" ] && [ -n "${SAFE_EXPORT}" ]; then + error_exit "Error: Archive mode and Safe mode exports can't be used together." +fi +if [ -n "${SAFE_EXPORT}" ]; then + # Check if container is running, otherwise don't try to stop/start the jail + if [ -z "$(jls name | awk "/^${TARGET}$/")" ]; then + SAFE_EXPORT= + fi +fi + # Export directory check if [ -n "${DIR_EXPORT}" ]; then if [ -d "${DIR_EXPORT}" ]; then From 9984101e1b0f30cebd05f7146eb101f895d1764a Mon Sep 17 00:00:00 2001 From: Jose Date: Sat, 20 Mar 2021 06:12:07 -0400 Subject: [PATCH 07/21] Don't share ports across the jails, just copy them A security concern into the jail could affect the shared ports for all the child, and/or multiple jails accessing/managing/updating the same source could lead into conflicts. Due the above mentioned issues, the optional distfiles will be copied to the newly created thinjail if they exist on the base release, thus being secure and more granular management. --- usr/local/share/bastille/create.sh | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/usr/local/share/bastille/create.sh b/usr/local/share/bastille/create.sh index ce3cf6d..8aa2126 100644 --- a/usr/local/share/bastille/create.sh +++ b/usr/local/share/bastille/create.sh @@ -259,17 +259,25 @@ create_jail() { echo if [ -z "${THICK_JAIL}" ]; then - LINK_LIST="bin boot lib libexec rescue sbin usr/bin usr/include usr/lib usr/lib32 usr/libdata usr/libexec usr/sbin usr/share usr/src" + LINK_LIST="bin boot lib libexec rescue sbin usr/bin usr/include usr/lib usr/lib32 usr/libdata usr/libexec usr/sbin usr/share" for _link in ${LINK_LIST}; do ln -sf /.bastille/${_link} ${_link} done - # Properly link shared ports on thin jails in read-write. + # Copy optional distfiles if they exist on the base release. if [ -d "${bastille_releasesdir}/${RELEASE}/usr/ports" ]; then if [ ! -d "${bastille_jail_path}/usr/ports" ]; then - mkdir ${bastille_jail_path}/usr/ports + info "Copying ports tree..." + cp -a ${bastille_releasesdir}/${RELEASE}/usr/ports ${bastille_jail_path}/usr fi - echo -e "${bastille_releasesdir}/${RELEASE}/usr/ports ${bastille_jail_path}/usr/ports nullfs rw 0 0" >> "${bastille_jail_fstab}" fi + if [ -d "${bastille_releasesdir}/${RELEASE}/usr/src" ]; then + if [ ! -d "${bastille_jail_path}/usr/src" ]; then + info "Copying source tree..." + ln -sf usr/src sys + cp -a ${bastille_releasesdir}/${RELEASE}/usr/src ${bastille_jail_path}/usr + fi + fi + echo fi if [ -z "${THICK_JAIL}" ]; then From 2c87c58a5b71f6753b79810f7a34144694e2b54f Mon Sep 17 00:00:00 2001 From: Jose Date: Thu, 29 Apr 2021 16:35:38 -0400 Subject: [PATCH 08/21] Prevent mount command fstab entry nesting --- usr/local/share/bastille/mount.sh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index 8214735..a33e9c1 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -93,26 +93,27 @@ for _jail in ${JAILS}; do info "[${_jail}]:" ## aggregate variables into FSTAB entry - _jailpath="${bastille_jailsdir}/${_jail}/root/${_jailpath}" - _fstab_entry="${_hostpath} ${_jailpath} ${_type} ${_perms} ${_checks}" + _jailpath_entry="${bastille_jailsdir}/${_jail}/root${_jailpath}" + _fstab_entry="${_hostpath} ${_jailpath_entry} ${_type} ${_perms} ${_checks}" ## Create mount point if it does not exist. -- cwells - if [ ! -d "${bastille_jailsdir}/${_jail}/root/${_jailpath}" ]; then - if ! mkdir -p "${bastille_jailsdir}/${_jail}/root/${_jailpath}"; then + if [ ! -d "${bastille_jailsdir}/${_jail}/root${_jailpath}" ]; then + if ! mkdir -p "${bastille_jailsdir}/${_jail}/root${_jailpath}"; then error_exit "Failed to create mount point inside jail." fi fi ## if entry doesn't exist, add; else show existing entry - if ! egrep -q "[[:blank:]]${_jailpath}[[:blank:]]" "${bastille_jailsdir}/${_jail}/fstab" 2> /dev/null; then + if ! egrep -q "[[:blank:]]${_jailpath_entry}[[:blank:]]" "${bastille_jailsdir}/${_jail}/fstab" 2> /dev/null; then if ! echo "${_fstab_entry}" >> "${bastille_jailsdir}/${_jail}/fstab"; then error_exit "Failed to create fstab entry: ${_fstab_entry}" fi echo "Added: ${_fstab_entry}" else warn "Mountpoint already present in ${bastille_jailsdir}/${_jail}/fstab" - egrep "[[:blank:]]${_jailpath}[[:blank:]]" "${bastille_jailsdir}/${_jail}/fstab" + egrep "[[:blank:]]${_jailpath_entry}[[:blank:]]" "${bastille_jailsdir}/${_jail}/fstab" fi mount -F "${bastille_jailsdir}/${_jail}/fstab" -a + _jailpath_entry= echo done From bfaa2681e0069f676cc6b0627fce086486b932bd Mon Sep 17 00:00:00 2001 From: Jose Date: Sat, 15 May 2021 08:13:14 -0400 Subject: [PATCH 09/21] Revert the improved `export` command due conflicts, later re add. --- usr/local/share/bastille/export.sh | 143 +++++++++-------------------- 1 file changed, 45 insertions(+), 98 deletions(-) diff --git a/usr/local/share/bastille/export.sh b/usr/local/share/bastille/export.sh index 9d935cc..1a0a1d5 100644 --- a/usr/local/share/bastille/export.sh +++ b/usr/local/share/bastille/export.sh @@ -32,13 +32,7 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille export TARGET [options] | PATH - \n - \nOptions: - \n - -t|--txz -- Export to a standard .txz archive even if bastille is configured for zfs\n - -s|--safe -- Safely stop the jail to snapshot it then start it again to proceed exporting\n - -r|--raw -- Export the jail to an uncompressed raw image\n" + error_exit "Usage: bastille export TARGET [safe|tarball] | PATH" } # Handle special-case commands first @@ -53,60 +47,40 @@ if [ "${TARGET}" = "ALL" ]; then error_exit "Batch export is unsupported." fi -if [ $# -gt 4 ] || [ $# -lt 0 ]; then +if [ $# -gt 2 ] || [ $# -lt 0 ]; then usage fi +OPTION="${1}" +EXPATH="${2}" SAFE_EXPORT= -RAW_EXPORT= -DIR_EXPORT= -TXZ_EXPORT= -# Handle and parse option args -while [ $# -gt 0 ]; do - case "${1}" in - -t|--txz) - TXZ_EXPORT="1" - if [ "${bastille_zfs_enable}" = "YES" ]; then - bastille_zfs_enable="NO" - fi - shift - ;; - -s|--safe) - SAFE_EXPORT="1" - shift - ;; - -r|--raw) - RAW_EXPORT="1" - shift - ;; - *) - if echo "${1}" | grep -q "\/"; then - DIR_EXPORT="${1}" - else - usage - fi - shift - ;; - esac -done - -## validate for combined options -if [ -n "${TXZ_EXPORT}" ] && [ -n "${SAFE_EXPORT}" ]; then - error_exit "Error: Archive mode and Safe mode exports can't be used together." -fi -if [ -n "${SAFE_EXPORT}" ]; then - # Check if container is running, otherwise don't try to stop/start the jail - if [ -z "$(jls name | awk "/^${TARGET}$/")" ]; then - SAFE_EXPORT= +# Handle some options +if [ -n "${OPTION}" ]; then + if [ "${OPTION}" = "-t" -o "${OPTION}" = "--txz" -o ${OPTION} = "tarball" ]; then + if [ "${bastille_zfs_enable}" = "YES" ]; then + # Temporarily disable ZFS so we can create a standard backup archive + bastille_zfs_enable="NO" + fi + elif [ "${OPTION}" = "-s" -o "${OPTION}" = "--safe" -o ${OPTION} = "safe" ]; then + SAFE_EXPORT="1" + elif echo "${OPTION}" | grep -q "\/"; then + if [ -d "${OPTION}" ]; then + EXPATH="${OPTION}" + else + error_exit "Error: Path not found." + fi + else + error_notify "Invalid option!" + usage fi fi # Export directory check -if [ -n "${DIR_EXPORT}" ]; then - if [ -d "${DIR_EXPORT}" ]; then +if [ -n "${EXPATH}" ]; then + if [ -d "${EXPATH}" ]; then # Set the user defined export directory - bastille_backupsdir="${DIR_EXPORT}" + bastille_backupsdir="${EXPATH}" else error_exit "Error: Path not found." fi @@ -118,63 +92,36 @@ create_zfs_snap(){ zfs snapshot -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" } -export_check(){ - # Inform the user about the exporting method - if [ -n "$(jls name | awk "/^${TARGET}$/")" ]; then - EXPORT_AS="Hot exporting" - else - EXPORT_AS="Exporting" - fi - if [ -n "${RAW_EXPORT}" ]; then - EXPORT_INFO="to a raw" - else - EXPORT_INFO="to a compressed ${FILE_EXT}" - fi - - # Safely stop and snapshot the jail - if [ -n "${SAFE_EXPORT}" ]; then - info "Safely exporting '${TARGET}' ${EXPORT_INFO} archive." - bastille stop ${TARGET} - create_zfs_snap - bastille start ${TARGET} - else - info "${EXPORT_AS} '${TARGET}' ${EXPORT_INFO} archive." - create_zfs_snap - fi - info "Sending ZFS data stream..." -} - jail_export() { # Attempt to export the container DATE=$(date +%F-%H%M%S) if [ "${bastille_zfs_enable}" = "YES" ]; then if [ -n "${bastille_zfs_zpool}" ]; then - if [ -n "${RAW_EXPORT}" ]; then - FILE_EXT="" - export_check + FILE_EXT="xz" - # Export the raw container recursively and cleanup temporary snapshots - zfs send -R "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" \ - > "${bastille_backupsdir}/${TARGET}_${DATE}" - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}/root@bastille_export_${DATE}" - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" + if [ -n "${SAFE_EXPORT}" ]; then + info "Safely exporting '${TARGET}' to a compressed .${FILE_EXT} archive." + bastille stop ${TARGET} + create_zfs_snap + bastille start ${TARGET} else - FILE_EXT=".xz" - export_check - - # Export the container recursively and cleanup temporary snapshots - zfs send -R "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" | \ - xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}" - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}/root@bastille_export_${DATE}" - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" + info "Hot exporting '${TARGET}' to a compressed .${FILE_EXT} archive." + create_zfs_snap fi + + info "Sending ZFS data stream..." + # Export the container recursively and cleanup temporary snapshots + zfs send -R "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" | \ + xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}.${FILE_EXT}" + zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}/root@bastille_export_${DATE}" + zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" fi else # Create standard backup archive - FILE_EXT=".txz" - info "Exporting '${TARGET}' to a compressed ${FILE_EXT} archive..." - cd "${bastille_jailsdir}" && tar -cf - "${TARGET}" | xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}" + FILE_EXT="txz" + info "Exporting '${TARGET}' to a compressed .${FILE_EXT} archive..." + cd "${bastille_jailsdir}" && tar -cf - "${TARGET}" | xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}.${FILE_EXT}" fi if [ "$?" -ne 0 ]; then @@ -182,8 +129,8 @@ jail_export() else # Generate container checksum file cd "${bastille_backupsdir}" - sha256 -q "${TARGET}_${DATE}${FILE_EXT}" > "${TARGET}_${DATE}.sha256" - info "Exported '${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}' successfully." + sha256 -q "${TARGET}_${DATE}.${FILE_EXT}" > "${TARGET}_${DATE}.sha256" + info "Exported '${bastille_backupsdir}/${TARGET}_${DATE}.${FILE_EXT}' successfully." exit 0 fi } From 89c6ce9e7897ae4a11c83df1d3418ed4e113c4fc Mon Sep 17 00:00:00 2001 From: Jose Date: Sat, 15 May 2021 08:16:10 -0400 Subject: [PATCH 10/21] Revert the improved `import` command due conflicts, later re add. --- usr/local/share/bastille/import.sh | 38 ++++-------------------------- 1 file changed, 5 insertions(+), 33 deletions(-) diff --git a/usr/local/share/bastille/import.sh b/usr/local/share/bastille/import.sh index e0b5643..fa542ba 100644 --- a/usr/local/share/bastille/import.sh +++ b/usr/local/share/bastille/import.sh @@ -32,11 +32,7 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille import FILE [option] - \n - \nOptions: - \n - -f|--force -- Force an archive import even if the checksum file is missing or don't match\n" + error_exit "Usage: bastille import file [force]" } # Handle special-case commands first @@ -51,21 +47,8 @@ if [ $# -gt 2 ] || [ $# -lt 1 ]; then fi TARGET="${1}" +OPTION="${2}" shift -OPT_FORCE= - -# Handle and parse option args -while [ $# -gt 0 ]; do - case "${1}" in - -f|force|--force) - OPT_FORCE="1" - shift - ;; - *) - usage - ;; - esac -done validate_archive() { # Compare checksums on the target archive @@ -83,7 +66,7 @@ validate_archive() { fi else # Check if user opt to force import - if [ -n "${OPT_FORCE}" ]; then + if [ "${OPTION}" = "-f" -o "${OPTION}" = "force" ]; then warn "Warning: Skipping archive validation!" else error_exit "Checksum file not found. See 'bastille import TARGET -f'." @@ -420,17 +403,6 @@ jail_import() { else update_config fi - elif [ -z "${FILE_EXT}" ]; then - if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$'; then - # Based on the file name, looks like we are importing a raw bastille image - # Import from uncompressed image file - info "Importing '${TARGET_TRIM}' from uncompressed image archive." - info "Receiving ZFS data stream..." - zfs receive -u "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" < "${bastille_backupsdir}/${TARGET}" - - # Update ZFS mountpoint property if required - update_zfsmount - fi else error_exit "Unknown archive format." fi @@ -493,9 +465,9 @@ fi # Check if archive exist then trim archive name if [ -f "${bastille_backupsdir}/${TARGET}" ]; then # Filter unsupported/unknown archives - if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.xz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.txz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}.zip$\|-[0-9]\{12\}.[0-9]\{2\}.tar.gz$\|@[0-9]\{12\}.[0-9]\{2\}.tar$'; then + if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.xz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.txz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}.zip$\|-[0-9]\{12\}.[0-9]\{2\}.tar.gz$\|@[0-9]\{12\}.[0-9]\{2\}.tar$'; then if ls "${bastille_backupsdir}" | awk "/^${TARGET}$/" >/dev/null; then - TARGET_TRIM=$(echo "${TARGET}" | sed "s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.xz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.txz//;s/_[0-9]*-[0-9]*-[0-9]*.zip//;s/-[0-9]\{12\}.[0-9]\{2\}.tar.gz//;s/@[0-9]\{12\}.[0-9]\{2\}.tar//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*//") + TARGET_TRIM=$(echo "${TARGET}" | sed "s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.xz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.txz//;s/_[0-9]*-[0-9]*-[0-9]*.zip//;s/-[0-9]\{12\}.[0-9]\{2\}.tar.gz//;s/@[0-9]\{12\}.[0-9]\{2\}.tar//") fi else error_exit "Unrecognized archive name." From b517d3aece1f97eac85854c8592beba99a8d0271 Mon Sep 17 00:00:00 2001 From: JRGTH Date: Wed, 7 Jul 2021 04:53:33 -0400 Subject: [PATCH 11/21] File reverted due conflicts --- usr/local/share/bastille/mount.sh | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index a33e9c1..298d42a 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -93,27 +93,26 @@ for _jail in ${JAILS}; do info "[${_jail}]:" ## aggregate variables into FSTAB entry - _jailpath_entry="${bastille_jailsdir}/${_jail}/root${_jailpath}" - _fstab_entry="${_hostpath} ${_jailpath_entry} ${_type} ${_perms} ${_checks}" + _jailpath="${bastille_jailsdir}/${_jail}/root/${_jailpath}" + _fstab_entry="${_hostpath} ${_jailpath} ${_type} ${_perms} ${_checks}" ## Create mount point if it does not exist. -- cwells - if [ ! -d "${bastille_jailsdir}/${_jail}/root${_jailpath}" ]; then - if ! mkdir -p "${bastille_jailsdir}/${_jail}/root${_jailpath}"; then + if [ ! -d "${_jailpath}" ]; then + if ! mkdir -p "${_jailpath}"; then error_exit "Failed to create mount point inside jail." fi fi ## if entry doesn't exist, add; else show existing entry - if ! egrep -q "[[:blank:]]${_jailpath_entry}[[:blank:]]" "${bastille_jailsdir}/${_jail}/fstab" 2> /dev/null; then + if ! egrep -q "[[:blank:]]${_jailpath}[[:blank:]]" "${bastille_jailsdir}/${_jail}/fstab" 2> /dev/null; then if ! echo "${_fstab_entry}" >> "${bastille_jailsdir}/${_jail}/fstab"; then error_exit "Failed to create fstab entry: ${_fstab_entry}" fi echo "Added: ${_fstab_entry}" else warn "Mountpoint already present in ${bastille_jailsdir}/${_jail}/fstab" - egrep "[[:blank:]]${_jailpath_entry}[[:blank:]]" "${bastille_jailsdir}/${_jail}/fstab" + egrep "[[:blank:]]${_jailpath}[[:blank:]]" "${bastille_jailsdir}/${_jail}/fstab" fi mount -F "${bastille_jailsdir}/${_jail}/fstab" -a - _jailpath_entry= echo done From 961731b063ddcbae35a6ab138858363326777fad Mon Sep 17 00:00:00 2001 From: JRGTH Date: Wed, 7 Jul 2021 05:05:38 -0400 Subject: [PATCH 12/21] New features and improvements revised and re-added --- usr/local/etc/bastille/bastille.conf.sample | 2 + usr/local/share/bastille/create.sh | 16 +- usr/local/share/bastille/export.sh | 232 +++++++++++++++----- usr/local/share/bastille/import.sh | 93 +++++++- 4 files changed, 268 insertions(+), 75 deletions(-) diff --git a/usr/local/etc/bastille/bastille.conf.sample b/usr/local/etc/bastille/bastille.conf.sample index 08bbfb0..c618ef3 100644 --- a/usr/local/etc/bastille/bastille.conf.sample +++ b/usr/local/etc/bastille/bastille.conf.sample @@ -44,6 +44,8 @@ bastille_zfs_options="-o compress=lz4 -o atime=off" ## default ## Export/Import options bastille_compress_xz_options="-0 -v" ## default "-0 -v" bastille_decompress_xz_options="-c -d -v" ## default "-c -d -v" +bastille_compress_gz_options="-1 -v" ## default "-1 -v" +bastille_decompress_gz_options="-k -d -c -v" ## default "-k -d -c -v" ## Networking bastille_network_loopback="bastille0" ## default: "bastille0" diff --git a/usr/local/share/bastille/create.sh b/usr/local/share/bastille/create.sh index fdd3951..2f56c09 100644 --- a/usr/local/share/bastille/create.sh +++ b/usr/local/share/bastille/create.sh @@ -259,25 +259,17 @@ create_jail() { echo if [ -z "${THICK_JAIL}" ]; then - LINK_LIST="bin boot lib libexec rescue sbin usr/bin usr/include usr/lib usr/lib32 usr/libdata usr/libexec usr/sbin usr/share" + LINK_LIST="bin boot lib libexec rescue sbin usr/bin usr/include usr/lib usr/lib32 usr/libdata usr/libexec usr/sbin usr/share usr/src" for _link in ${LINK_LIST}; do ln -sf /.bastille/${_link} ${_link} done - # Copy optional distfiles if they exist on the base release. + # Properly link shared ports on thin jails in read-write. if [ -d "${bastille_releasesdir}/${RELEASE}/usr/ports" ]; then if [ ! -d "${bastille_jail_path}/usr/ports" ]; then - info "Copying ports tree..." - cp -a ${bastille_releasesdir}/${RELEASE}/usr/ports ${bastille_jail_path}/usr + mkdir ${bastille_jail_path}/usr/ports fi + echo -e "${bastille_releasesdir}/${RELEASE}/usr/ports ${bastille_jail_path}/usr/ports nullfs rw 0 0" >> "${bastille_jail_fstab}" fi - if [ -d "${bastille_releasesdir}/${RELEASE}/usr/src" ]; then - if [ ! -d "${bastille_jail_path}/usr/src" ]; then - info "Copying source tree..." - ln -sf usr/src sys - cp -a ${bastille_releasesdir}/${RELEASE}/usr/src ${bastille_jail_path}/usr - fi - fi - echo fi if [ -z "${THICK_JAIL}" ]; then diff --git a/usr/local/share/bastille/export.sh b/usr/local/share/bastille/export.sh index 1a0a1d5..3e1bd77 100644 --- a/usr/local/share/bastille/export.sh +++ b/usr/local/share/bastille/export.sh @@ -32,7 +32,23 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille export TARGET [safe|tarball] | PATH" + # Build an independent usage for the export command + # Valid compress/options for ZFS systems are raw, .gz, .tgz, .txz and .xz(default) + # Valid compress/options for non ZFS configured systems are .tgz and .txz(default) + echo -e "${COLOR_RED}Usage: bastille export TARGET | option(s) | PATH${COLOR_RESET}" + + cat << EOF + Options: + + gz | --gz -- Export a ZFS jail using GZIP(.gz) compressed image. + -r | raw | --raw -- Export a ZFS jail to an uncompressed RAW image. + -s | safe | --safe -- Safely stop and start a ZFS jail before the exporting process. + tgz | --tgz -- Export a jail using simple .tgz compressed archive instead. + txz | --txz -- Export a jail using simple .txz compressed archive instead. + -v | verbose | --verbose -- Be more verbose during the ZFS send operation. + +EOF + exit 1 } # Handle special-case commands first @@ -47,81 +63,193 @@ if [ "${TARGET}" = "ALL" ]; then error_exit "Batch export is unsupported." fi -if [ $# -gt 2 ] || [ $# -lt 0 ]; then +if [ $# -gt 4 ] || [ $# -lt 0 ]; then usage fi -OPTION="${1}" -EXPATH="${2}" -SAFE_EXPORT= +zfs_enable_check() { + # Temporarily disable ZFS so we can create a standard backup archive + if [ "${bastille_zfs_enable}" = "YES" ]; then + bastille_zfs_enable="NO" + fi +} -# Handle some options -if [ -n "${OPTION}" ]; then - if [ "${OPTION}" = "-t" -o "${OPTION}" = "--txz" -o ${OPTION} = "tarball" ]; then - if [ "${bastille_zfs_enable}" = "YES" ]; then - # Temporarily disable ZFS so we can create a standard backup archive - bastille_zfs_enable="NO" - fi - elif [ "${OPTION}" = "-s" -o "${OPTION}" = "--safe" -o ${OPTION} = "safe" ]; then - SAFE_EXPORT="1" - elif echo "${OPTION}" | grep -q "\/"; then - if [ -d "${OPTION}" ]; then - EXPATH="${OPTION}" - else - error_exit "Error: Path not found." - fi - else - error_notify "Invalid option!" - usage +GZIP_EXPORT= +SAFE_EXPORT= +RAW_EXPORT= +DIR_EXPORT= +TXZ_EXPORT= +TGZ_EXPORT= +OPT_ZSEND="-R" + +# Handle and parse option args +while [ $# -gt 0 ]; do + case "${1}" in + gz|--gz) + GZIP_EXPORT="1" + shift + ;; + tgz|--tgz) + TGZ_EXPORT="1" + zfs_enable_check + shift + ;; + txz|--txz) + TXZ_EXPORT="1" + zfs_enable_check + shift + ;; + -s|safe|--safe) + SAFE_EXPORT="1" + shift + ;; + -r|raw|--raw) + RAW_EXPORT="1" + shift + ;; + -v|verbose|--verbose) + OPT_ZSEND="-Rv" + shift + ;; + *) + if echo "${1}" | grep -q "\/"; then + DIR_EXPORT="${1}" + else + usage + fi + shift + ;; + esac +done + +# Validate for combined options +if [ -n "${TXZ_EXPORT}" -o -n "${TGZ_EXPORT}" ] && [ -n "${SAFE_EXPORT}" ]; then + error_exit "Error: Simple archive modes with safe ZFS export can't be used together." +fi +if [ -z "${bastille_zfs_enable}" ]; then + if [ -n "${GZIP_EXPORT}" -o -n "${RAW_EXPORT}" -o "${SAFE_EXPORT}" ]; then + error_exit "Options --gz, --raw, --safe are valid for ZFS configured systems only." + fi +fi +if [ -n "${SAFE_EXPORT}" ]; then + # Check if container is running, otherwise just ignore + if [ -z "$(jls name | awk "/^${TARGET}$/")" ]; then + SAFE_EXPORT= fi fi # Export directory check -if [ -n "${EXPATH}" ]; then - if [ -d "${EXPATH}" ]; then +if [ -n "${DIR_EXPORT}" ]; then + if [ -d "${DIR_EXPORT}" ]; then # Set the user defined export directory - bastille_backupsdir="${EXPATH}" + bastille_backupsdir="${DIR_EXPORT}" else error_exit "Error: Path not found." fi fi -create_zfs_snap(){ +# Fallback to default if missing config parameters +if [ -z "${bastille_compress_xz_options}" ]; then + bastille_compress_xz_options="-0 -v" +fi +if [ -z "${bastille_compress_gz_options}" ]; then + bastille_compress_gz_options="-1 -v" +fi + +create_zfs_snap() { # Take a recursive temporary snapshot info "Creating temporary ZFS snapshot for export..." zfs snapshot -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" } -jail_export() -{ +export_check() { + # Inform the user about the exporting method + if [ -n "$(jls name | awk "/^${TARGET}$/")" ]; then + if [ -n "${SAFE_EXPORT}" ]; then + EXPORT_AS="Safely exporting" + else + EXPORT_AS="Hot exporting" + fi + else + EXPORT_AS="Exporting" + fi + + if [ "${FILE_EXT}" = ".xz" -o "${FILE_EXT}" = ".gz" -o "${FILE_EXT}" = "" ]; then + EXPORT_TYPE="image" + else + EXPORT_TYPE="archive" + fi + + if [ -n "${RAW_EXPORT}" ]; then + EXPORT_INFO="to a raw ${EXPORT_TYPE}" + else + EXPORT_INFO="to a compressed ${FILE_EXT} ${EXPORT_TYPE}" + fi + + info "${EXPORT_AS} '${TARGET}' ${EXPORT_INFO}..." + + # Safely stop and snapshot the jail + if [ -n "${SAFE_EXPORT}" ]; then + bastille stop ${TARGET} + create_zfs_snap + bastille start ${TARGET} + else + create_zfs_snap + fi + + if [ "${bastille_zfs_enable}" = "YES" ]; then + info "Sending ZFS data stream..." + fi +} + +jail_export() { # Attempt to export the container DATE=$(date +%F-%H%M%S) if [ "${bastille_zfs_enable}" = "YES" ]; then if [ -n "${bastille_zfs_zpool}" ]; then - FILE_EXT="xz" + if [ -n "${RAW_EXPORT}" ]; then + FILE_EXT="" + export_check - if [ -n "${SAFE_EXPORT}" ]; then - info "Safely exporting '${TARGET}' to a compressed .${FILE_EXT} archive." - bastille stop ${TARGET} - create_zfs_snap - bastille start ${TARGET} + # Export the raw container recursively and cleanup temporary snapshots + zfs send ${OPT_ZSEND} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" \ + > "${bastille_backupsdir}/${TARGET}_${DATE}" + zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}/root@bastille_export_${DATE}" + zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" + elif [ -n "${GZIP_EXPORT}" ]; then + FILE_EXT=".gz" + export_check + + # Export the raw container recursively and cleanup temporary snapshots + zfs send ${OPT_ZSEND} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" | \ + gzip ${bastille_compress_gz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}" + zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}/root@bastille_export_${DATE}" + zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" else - info "Hot exporting '${TARGET}' to a compressed .${FILE_EXT} archive." - create_zfs_snap - fi + FILE_EXT=".xz" + export_check - info "Sending ZFS data stream..." - # Export the container recursively and cleanup temporary snapshots - zfs send -R "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" | \ - xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}.${FILE_EXT}" - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}/root@bastille_export_${DATE}" - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" + # Export the container recursively and cleanup temporary snapshots(default) + zfs send ${OPT_ZSEND} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" | \ + xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}" + zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}/root@bastille_export_${DATE}" + zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" + fi fi else - # Create standard backup archive - FILE_EXT="txz" - info "Exporting '${TARGET}' to a compressed .${FILE_EXT} archive..." - cd "${bastille_jailsdir}" && tar -cf - "${TARGET}" | xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}.${FILE_EXT}" + if [ -n "${TGZ_EXPORT}" ]; then + FILE_EXT=".tgz" + + # Create standard tgz backup archive + info "Exporting '${TARGET}' to a compressed ${FILE_EXT} archive..." + cd "${bastille_jailsdir}" && tar -cf - "${TARGET}" | gzip ${bastille_compress_gz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}" + else + FILE_EXT=".txz" + + # Create standard txz backup archive(default) + info "Exporting '${TARGET}' to a compressed ${FILE_EXT} archive..." + cd "${bastille_jailsdir}" && tar -cf - "${TARGET}" | xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}" + fi fi if [ "$?" -ne 0 ]; then @@ -129,8 +257,8 @@ jail_export() else # Generate container checksum file cd "${bastille_backupsdir}" - sha256 -q "${TARGET}_${DATE}.${FILE_EXT}" > "${TARGET}_${DATE}.sha256" - info "Exported '${bastille_backupsdir}/${TARGET}_${DATE}.${FILE_EXT}' successfully." + sha256 -q "${TARGET}_${DATE}${FILE_EXT}" > "${TARGET}_${DATE}.sha256" + info "Exported '${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}' successfully." exit 0 fi } @@ -148,4 +276,6 @@ if [ "${bastille_zfs_enable}" != "YES" ]; then fi fi -jail_export +if [ -n "${TARGET}" ]; then + jail_export +fi diff --git a/usr/local/share/bastille/import.sh b/usr/local/share/bastille/import.sh index fa542ba..1c815b7 100644 --- a/usr/local/share/bastille/import.sh +++ b/usr/local/share/bastille/import.sh @@ -32,7 +32,17 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille import file [force]" + # Build an independent usage for the import command + echo -e "${COLOR_RED}Usage: bastille import FILE [option]${COLOR_RESET}" + + cat << EOF + Options: + + -f | force | --force -- Force an archive import regardless if the checksum file does not match or missing. + -v | verbose | --verbose -- Be more verbose during the ZFS receive operation. + +EOF + exit 1 } # Handle special-case commands first @@ -42,13 +52,39 @@ help|-h|--help) ;; esac -if [ $# -gt 2 ] || [ $# -lt 1 ]; then +if [ $# -gt 3 ] || [ $# -lt 1 ]; then usage fi TARGET="${1}" -OPTION="${2}" shift +OPT_FORCE= +OPT_ZRECV="-u" + +# Handle and parse option args +while [ $# -gt 0 ]; do + case "${1}" in + -f|force|--force) + OPT_FORCE="1" + shift + ;; + -v|verbose|--verbose) + OPT_ZRECV="-u -v" + shift + ;; + *) + usage + ;; + esac +done + +# Fallback to default if missing config parameters +if [ -z "${bastille_decompress_xz_options}" ]; then + bastille_decompress_xz_options="-c -d -v" +fi +if [ -z "${bastille_decompress_gz_options}" ]; then + bastille_decompress_gz_options="-k -d -c -v" +fi validate_archive() { # Compare checksums on the target archive @@ -66,7 +102,7 @@ validate_archive() { fi else # Check if user opt to force import - if [ "${OPTION}" = "-f" -o "${OPTION}" = "force" ]; then + if [ -n "${OPT_FORCE}" ]; then warn "Warning: Skipping archive validation!" else error_exit "Checksum file not found. See 'bastille import TARGET -f'." @@ -313,7 +349,7 @@ remove_zfs_datasets() { jail_import() { # Attempt to import container from file - FILE_TRIM=$(echo "${TARGET}" | sed 's/\.xz//g;s/\.txz//g;s/\.zip//g;s/\.tar\.gz//g;s/\.tar//g') + FILE_TRIM=$(echo "${TARGET}" | sed 's/\.xz//g;s/\.gz//g;s/\.tgz//g;s/\.txz//g;s/\.zip//g;s/\.tar\.gz//g;s/\.tar//g') FILE_EXT=$(echo "${TARGET}" | sed "s/${FILE_TRIM}//g") validate_archive if [ -d "${bastille_jailsdir}" ]; then @@ -321,10 +357,19 @@ jail_import() { if [ -n "${bastille_zfs_zpool}" ]; then if [ "${FILE_EXT}" = ".xz" ]; then # Import from compressed xz on ZFS systems - info "Importing '${TARGET_TRIM}' from compressed ${FILE_EXT} archive." + info "Importing '${TARGET_TRIM}' from compressed ${FILE_EXT} image." info "Receiving ZFS data stream..." xz ${bastille_decompress_xz_options} "${bastille_backupsdir}/${TARGET}" | \ - zfs receive -u "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" + zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" + + # Update ZFS mountpoint property if required + update_zfsmount + elif [ "${FILE_EXT}" = ".gz" ]; then + # Import from compressed xz on ZFS systems + info "Importing '${TARGET_TRIM}' from compressed ${FILE_EXT} image." + info "Receiving ZFS data stream..." + gzip ${bastille_decompress_gz_options} "${bastille_backupsdir}/${TARGET}" | \ + zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" # Update ZFS mountpoint property if required update_zfsmount @@ -340,6 +385,17 @@ jail_import() { if [ "$?" -ne 0 ]; then remove_zfs_datasets fi + elif [ "${FILE_EXT}" = ".tgz" ]; then + # Prepare the ZFS environment and restore from existing .tgz file + create_zfs_datasets + + # Extract required files to the new datasets + info "Extracting files from '${TARGET}' archive..." + tar --exclude='root' -xf "${bastille_backupsdir}/${TARGET}" --strip-components 1 -C "${bastille_jailsdir}/${TARGET_TRIM}" + tar -xf "${bastille_backupsdir}/${TARGET}" --strip-components 2 -C "${bastille_jailsdir}/${TARGET_TRIM}/root" "${TARGET_TRIM}/root" + if [ "$?" -ne 0 ]; then + remove_zfs_datasets + fi elif [ "${FILE_EXT}" = ".zip" ]; then # Attempt to import a foreign/iocage container info "Importing '${TARGET_TRIM}' from foreign compressed ${FILE_EXT} archive." @@ -353,9 +409,9 @@ jail_import() { rm -f "${FILE_TRIM}" "${FILE_TRIM}_root" fi info "Receiving ZFS data stream..." - zfs receive -u "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" < "${FILE_TRIM}" + zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" < "${FILE_TRIM}" zfs set ${ZFS_OPTIONS} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" - zfs receive -u "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}/root" < "${FILE_TRIM}_root" + zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}/root" < "${FILE_TRIM}_root" # Update ZFS mountpoint property if required update_zfsmount @@ -403,6 +459,17 @@ jail_import() { else update_config fi + elif [ -z "${FILE_EXT}" ]; then + if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$'; then + # Based on the file name, looks like we are importing a raw bastille image + # Import from uncompressed image file + info "Importing '${TARGET_TRIM}' from uncompressed image archive." + info "Receiving ZFS data stream..." + zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" < "${bastille_backupsdir}/${TARGET}" + + # Update ZFS mountpoint property if required + update_zfsmount + fi else error_exit "Unknown archive format." fi @@ -465,9 +532,9 @@ fi # Check if archive exist then trim archive name if [ -f "${bastille_backupsdir}/${TARGET}" ]; then # Filter unsupported/unknown archives - if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.xz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.txz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}.zip$\|-[0-9]\{12\}.[0-9]\{2\}.tar.gz$\|@[0-9]\{12\}.[0-9]\{2\}.tar$'; then + if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.xz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.gz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.tgz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.txz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}.zip$\|-[0-9]\{12\}.[0-9]\{2\}.tar.gz$\|@[0-9]\{12\}.[0-9]\{2\}.tar$'; then if ls "${bastille_backupsdir}" | awk "/^${TARGET}$/" >/dev/null; then - TARGET_TRIM=$(echo "${TARGET}" | sed "s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.xz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.txz//;s/_[0-9]*-[0-9]*-[0-9]*.zip//;s/-[0-9]\{12\}.[0-9]\{2\}.tar.gz//;s/@[0-9]\{12\}.[0-9]\{2\}.tar//") + TARGET_TRIM=$(echo "${TARGET}" | sed "s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.xz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.gz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.tgz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.txz//;s/_[0-9]*-[0-9]*-[0-9]*.zip//;s/-[0-9]\{12\}.[0-9]\{2\}.tar.gz//;s/@[0-9]\{12\}.[0-9]\{2\}.tar//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*//") fi else error_exit "Unrecognized archive name." @@ -483,4 +550,6 @@ elif [ -d "${bastille_jailsdir}/${TARGET_TRIM}" ]; then error_exit "Container: ${TARGET_TRIM} already exists." fi -jail_import +if [ -n "${TARGET}" ]; then + jail_import +fi From 8938d03f47304fb512090ed54e0e455d5a28648c Mon Sep 17 00:00:00 2001 From: JRGTH Date: Wed, 7 Jul 2021 05:21:28 -0400 Subject: [PATCH 13/21] Revert to original file before re-add new --- usr/local/share/bastille/create.sh | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/usr/local/share/bastille/create.sh b/usr/local/share/bastille/create.sh index 2f56c09..e46109e 100644 --- a/usr/local/share/bastille/create.sh +++ b/usr/local/share/bastille/create.sh @@ -438,36 +438,32 @@ EMPTY_JAIL="" THICK_JAIL="" VNET_JAIL="" -# Handle and parse options -while [ $# -gt 0 ]; do +## handle combined options then shift +if [ "${1}" = "-T" -o "${1}" = "--thick" -o "${1}" = "thick" ] && \ + [ "${2}" = "-V" -o "${2}" = "--vnet" -o "${2}" = "vnet" ]; then + THICK_JAIL="1" + VNET_JAIL="1" + shift 2 +else + ## handle single options case "${1}" in -E|--empty|empty) - EMPTY_JAIL="1" shift + EMPTY_JAIL="1" ;; -T|--thick|thick) - THICK_JAIL="1" shift + THICK_JAIL="1" ;; -V|--vnet|vnet) - VNET_JAIL="1" shift + VNET_JAIL="1" ;; - -*|--*) + -*) error_notify "Unknown Option." usage ;; - *) - break - ;; esac -done - -## validate for combined options -if [ -n "${EMPTY_JAIL}" ]; then - if [ -n "${THICK_JAIL}" ] || [ -n "${VNET_JAIL}" ]; then - error_exit "Error: Empty jail option can't be used with other options." - fi fi NAME="$1" From 9e3ad27ecf110d995ad186f23b4b40dcd38b0f42 Mon Sep 17 00:00:00 2001 From: JRGTH Date: Wed, 7 Jul 2021 05:22:35 -0400 Subject: [PATCH 14/21] Re-added new and improved create.sh file --- usr/local/share/bastille/create.sh | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/usr/local/share/bastille/create.sh b/usr/local/share/bastille/create.sh index e46109e..2f56c09 100644 --- a/usr/local/share/bastille/create.sh +++ b/usr/local/share/bastille/create.sh @@ -438,32 +438,36 @@ EMPTY_JAIL="" THICK_JAIL="" VNET_JAIL="" -## handle combined options then shift -if [ "${1}" = "-T" -o "${1}" = "--thick" -o "${1}" = "thick" ] && \ - [ "${2}" = "-V" -o "${2}" = "--vnet" -o "${2}" = "vnet" ]; then - THICK_JAIL="1" - VNET_JAIL="1" - shift 2 -else - ## handle single options +# Handle and parse options +while [ $# -gt 0 ]; do case "${1}" in -E|--empty|empty) - shift EMPTY_JAIL="1" + shift ;; -T|--thick|thick) - shift THICK_JAIL="1" + shift ;; -V|--vnet|vnet) - shift VNET_JAIL="1" + shift ;; - -*) + -*|--*) error_notify "Unknown Option." usage ;; + *) + break + ;; esac +done + +## validate for combined options +if [ -n "${EMPTY_JAIL}" ]; then + if [ -n "${THICK_JAIL}" ] || [ -n "${VNET_JAIL}" ]; then + error_exit "Error: Empty jail option can't be used with other options." + fi fi NAME="$1" From b0f947ca00d2a0c43ab3f83c09c2829dead25734 Mon Sep 17 00:00:00 2001 From: JRGTH Date: Thu, 8 Jul 2021 13:48:02 -0400 Subject: [PATCH 15/21] Standardized options position in export/import commands, improve option checks --- usr/local/bin/bastille | 4 +-- usr/local/share/bastille/export.sh | 57 +++++++++++++++++++++++------- usr/local/share/bastille/import.sh | 18 +++++++--- 3 files changed, 59 insertions(+), 20 deletions(-) diff --git a/usr/local/bin/bastille b/usr/local/bin/bastille index b526e42..cf65d86 100755 --- a/usr/local/bin/bastille +++ b/usr/local/bin/bastille @@ -135,10 +135,10 @@ version|-v|--version) help|-h|--help) usage ;; -bootstrap|create|destroy|import|list|rdr|restart|start|update|upgrade|verify) +bootstrap|create|destroy|export|import|list|rdr|restart|start|update|upgrade|verify) # Nothing "extra" to do for these commands. -- cwells ;; -clone|config|cmd|console|convert|cp|edit|export|htop|limits|mount|pkg|rename|service|stop|sysrc|template|top|umount|zfs) +clone|config|cmd|console|convert|cp|edit|htop|limits|mount|pkg|rename|service|stop|sysrc|template|top|umount|zfs) # Parse the target and ensure it exists. -- cwells if [ $# -eq 0 ]; then # No target was given, so show the command's help. -- cwells PARAMS='help' diff --git a/usr/local/share/bastille/export.sh b/usr/local/share/bastille/export.sh index 3e1bd77..66faad3 100644 --- a/usr/local/share/bastille/export.sh +++ b/usr/local/share/bastille/export.sh @@ -35,7 +35,7 @@ usage() { # Build an independent usage for the export command # Valid compress/options for ZFS systems are raw, .gz, .tgz, .txz and .xz(default) # Valid compress/options for non ZFS configured systems are .tgz and .txz(default) - echo -e "${COLOR_RED}Usage: bastille export TARGET | option(s) | PATH${COLOR_RESET}" + echo -e "${COLOR_RED}Usage: bastille export | option(s) | TARGET | PATH${COLOR_RESET}" cat << EOF Options: @@ -63,7 +63,7 @@ if [ "${TARGET}" = "ALL" ]; then error_exit "Batch export is unsupported." fi -if [ $# -gt 4 ] || [ $# -lt 0 ]; then +if [ $# -gt 5 ] || [ $# -lt 1 ]; then usage fi @@ -74,6 +74,7 @@ zfs_enable_check() { fi } +TARGET="${1}" GZIP_EXPORT= SAFE_EXPORT= RAW_EXPORT= @@ -81,41 +82,62 @@ DIR_EXPORT= TXZ_EXPORT= TGZ_EXPORT= OPT_ZSEND="-R" +COMP_OPTION="0" + +opt_count() { + COMP_OPTION=$(expr ${COMP_OPTION} + 1) +} # Handle and parse option args while [ $# -gt 0 ]; do case "${1}" in gz|--gz) GZIP_EXPORT="1" + TARGET="${2}" + opt_count shift ;; tgz|--tgz) TGZ_EXPORT="1" + TARGET="${2}" + opt_count zfs_enable_check shift ;; txz|--txz) TXZ_EXPORT="1" + TARGET="${2}" + opt_count zfs_enable_check shift ;; -s|safe|--safe) SAFE_EXPORT="1" + TARGET="${2}" shift ;; -r|raw|--raw) RAW_EXPORT="1" + TARGET="${2}" + opt_count shift ;; -v|verbose|--verbose) OPT_ZSEND="-Rv" + TARGET="${2}" shift ;; + -*|--*) + error_notify "Unknown Option." + usage + ;; *) if echo "${1}" | grep -q "\/"; then DIR_EXPORT="${1}" else - usage + if [ $# -gt 2 ] || [ $# -lt 1 ]; then + usage + fi fi shift ;; @@ -123,14 +145,20 @@ while [ $# -gt 0 ]; do done # Validate for combined options +if [ "${COMP_OPTION}" -gt "1" ]; then + error_exit "Error: Only one compression format can be used during export." +fi + if [ -n "${TXZ_EXPORT}" -o -n "${TGZ_EXPORT}" ] && [ -n "${SAFE_EXPORT}" ]; then error_exit "Error: Simple archive modes with safe ZFS export can't be used together." fi + if [ -z "${bastille_zfs_enable}" ]; then - if [ -n "${GZIP_EXPORT}" -o -n "${RAW_EXPORT}" -o "${SAFE_EXPORT}" ]; then - error_exit "Options --gz, --raw, --safe are valid for ZFS configured systems only." + if [ -n "${GZIP_EXPORT}" -o -n "${RAW_EXPORT}" -o "${SAFE_EXPORT}" -o "${OPT_ZSEND}" ]; then + error_exit "Options --gz, --raw, --safe, --verbose are valid for ZFS configured systems only." fi fi + if [ -n "${SAFE_EXPORT}" ]; then # Check if container is running, otherwise just ignore if [ -z "$(jls name | awk "/^${TARGET}$/")" ]; then @@ -268,14 +296,17 @@ if [ ! -d "${bastille_backupsdir}" ]; then error_exit "Backups directory/dataset does not exist. See 'bastille bootstrap'." fi -# Check if is a ZFS system -if [ "${bastille_zfs_enable}" != "YES" ]; then - # Check if container is running and ask for stop in UFS systems - if [ -n "$(jls name | awk "/^${TARGET}$/")" ]; then - error_exit "${TARGET} is running. See 'bastille stop'." - fi -fi - if [ -n "${TARGET}" ]; then + if [ ! -d "${bastille_jailsdir}/${TARGET}" ]; then + error_exit "[${TARGET}]: Not found." + fi + + # Check if is a ZFS system + if [ "${bastille_zfs_enable}" != "YES" ]; then + # Check if container is running and ask for stop in non ZFS systems + if [ -n "$(jls name | awk "/^${TARGET}$/")" ]; then + error_exit "${TARGET} is running. See 'bastille stop'." + fi + fi jail_export fi diff --git a/usr/local/share/bastille/import.sh b/usr/local/share/bastille/import.sh index 1c815b7..5501904 100644 --- a/usr/local/share/bastille/import.sh +++ b/usr/local/share/bastille/import.sh @@ -33,11 +33,11 @@ usage() { # Build an independent usage for the import command - echo -e "${COLOR_RED}Usage: bastille import FILE [option]${COLOR_RESET}" + echo -e "${COLOR_RED}Usage: bastille import [option(s)] FILE${COLOR_RESET}" cat << EOF Options: - + -f | force | --force -- Force an archive import regardless if the checksum file does not match or missing. -v | verbose | --verbose -- Be more verbose during the ZFS receive operation. @@ -57,7 +57,6 @@ if [ $# -gt 3 ] || [ $# -lt 1 ]; then fi TARGET="${1}" -shift OPT_FORCE= OPT_ZRECV="-u" @@ -66,15 +65,24 @@ while [ $# -gt 0 ]; do case "${1}" in -f|force|--force) OPT_FORCE="1" + TARGET="${2}" shift ;; -v|verbose|--verbose) OPT_ZRECV="-u -v" + TARGET="${2}" shift ;; - *) + -*|--*) + error_notify "Unknown Option." usage ;; + *) + if [ $# -gt 1 ] || [ $# -lt 1 ]; then + usage + fi + shift + ;; esac done @@ -369,7 +377,7 @@ jail_import() { info "Importing '${TARGET_TRIM}' from compressed ${FILE_EXT} image." info "Receiving ZFS data stream..." gzip ${bastille_decompress_gz_options} "${bastille_backupsdir}/${TARGET}" | \ - zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" + zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" # Update ZFS mountpoint property if required update_zfsmount From 5c4d69775faf42db336223ead6a86ddba81bddcd Mon Sep 17 00:00:00 2001 From: JRGTH Date: Thu, 8 Jul 2021 15:29:31 -0400 Subject: [PATCH 16/21] Deprecate command parameters not starting with dash --- usr/local/share/bastille/export.sh | 12 ++++++------ usr/local/share/bastille/import.sh | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/usr/local/share/bastille/export.sh b/usr/local/share/bastille/export.sh index 66faad3..400db63 100644 --- a/usr/local/share/bastille/export.sh +++ b/usr/local/share/bastille/export.sh @@ -40,12 +40,12 @@ usage() { cat << EOF Options: - gz | --gz -- Export a ZFS jail using GZIP(.gz) compressed image. - -r | raw | --raw -- Export a ZFS jail to an uncompressed RAW image. - -s | safe | --safe -- Safely stop and start a ZFS jail before the exporting process. - tgz | --tgz -- Export a jail using simple .tgz compressed archive instead. - txz | --txz -- Export a jail using simple .txz compressed archive instead. - -v | verbose | --verbose -- Be more verbose during the ZFS send operation. + --gz -- Export a ZFS jail using GZIP(.gz) compressed image. + -r | --raw -- Export a ZFS jail to an uncompressed RAW image. + -s | --safe -- Safely stop and start a ZFS jail before the exporting process. + --tgz -- Export a jail using simple .tgz compressed archive instead. + --txz -- Export a jail using simple .txz compressed archive instead. + -v | --verbose -- Be more verbose during the ZFS send operation. EOF exit 1 diff --git a/usr/local/share/bastille/import.sh b/usr/local/share/bastille/import.sh index 5501904..feba602 100644 --- a/usr/local/share/bastille/import.sh +++ b/usr/local/share/bastille/import.sh @@ -38,8 +38,8 @@ usage() { cat << EOF Options: - -f | force | --force -- Force an archive import regardless if the checksum file does not match or missing. - -v | verbose | --verbose -- Be more verbose during the ZFS receive operation. + -f | --force -- Force an archive import regardless if the checksum file does not match or missing. + -v | --verbose -- Be more verbose during the ZFS receive operation. EOF exit 1 From 17ea19bf65424de625411f1ab5cd5fa5164b7609 Mon Sep 17 00:00:00 2001 From: JRGTH Date: Thu, 8 Jul 2021 15:37:36 -0400 Subject: [PATCH 17/21] Deprecate command parameters not starting with dash here too --- usr/local/share/bastille/export.sh | 12 ++++++------ usr/local/share/bastille/import.sh | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/usr/local/share/bastille/export.sh b/usr/local/share/bastille/export.sh index 400db63..a76708b 100644 --- a/usr/local/share/bastille/export.sh +++ b/usr/local/share/bastille/export.sh @@ -91,38 +91,38 @@ opt_count() { # Handle and parse option args while [ $# -gt 0 ]; do case "${1}" in - gz|--gz) + --gz) GZIP_EXPORT="1" TARGET="${2}" opt_count shift ;; - tgz|--tgz) + --tgz) TGZ_EXPORT="1" TARGET="${2}" opt_count zfs_enable_check shift ;; - txz|--txz) + --txz) TXZ_EXPORT="1" TARGET="${2}" opt_count zfs_enable_check shift ;; - -s|safe|--safe) + -s|--safe) SAFE_EXPORT="1" TARGET="${2}" shift ;; - -r|raw|--raw) + -r|--raw) RAW_EXPORT="1" TARGET="${2}" opt_count shift ;; - -v|verbose|--verbose) + -v|--verbose) OPT_ZSEND="-Rv" TARGET="${2}" shift diff --git a/usr/local/share/bastille/import.sh b/usr/local/share/bastille/import.sh index feba602..a68387e 100644 --- a/usr/local/share/bastille/import.sh +++ b/usr/local/share/bastille/import.sh @@ -63,12 +63,12 @@ OPT_ZRECV="-u" # Handle and parse option args while [ $# -gt 0 ]; do case "${1}" in - -f|force|--force) + -f|--force) OPT_FORCE="1" TARGET="${2}" shift ;; - -v|verbose|--verbose) + -v|--verbose) OPT_ZRECV="-u -v" TARGET="${2}" shift From d73645facb398b78e940855bf121e451ef4f350c Mon Sep 17 00:00:00 2001 From: JRGTH Date: Thu, 8 Jul 2021 17:41:27 -0400 Subject: [PATCH 18/21] Add the new tgz compress format to UFS systems too --- usr/local/share/bastille/export.sh | 2 +- usr/local/share/bastille/import.sh | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/usr/local/share/bastille/export.sh b/usr/local/share/bastille/export.sh index a76708b..a8f678c 100644 --- a/usr/local/share/bastille/export.sh +++ b/usr/local/share/bastille/export.sh @@ -154,7 +154,7 @@ if [ -n "${TXZ_EXPORT}" -o -n "${TGZ_EXPORT}" ] && [ -n "${SAFE_EXPORT}" ]; then fi if [ -z "${bastille_zfs_enable}" ]; then - if [ -n "${GZIP_EXPORT}" -o -n "${RAW_EXPORT}" -o "${SAFE_EXPORT}" -o "${OPT_ZSEND}" ]; then + if [ -n "${GZIP_EXPORT}" -o -n "${RAW_EXPORT}" -o -n "${SAFE_EXPORT}" -o "${OPT_ZSEND}" = "-Rv" ]; then error_exit "Options --gz, --raw, --safe, --verbose are valid for ZFS configured systems only." fi fi diff --git a/usr/local/share/bastille/import.sh b/usr/local/share/bastille/import.sh index a68387e..fb9b1a9 100644 --- a/usr/local/share/bastille/import.sh +++ b/usr/local/share/bastille/import.sh @@ -487,6 +487,9 @@ jail_import() { if [ "${FILE_EXT}" = ".txz" ]; then info "Extracting files from '${TARGET}' archive..." tar -Jxf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}" + elif [ "${FILE_EXT}" = ".tgz" ]; then + info "Extracting files from '${TARGET}' archive..." + tar -xf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}" elif [ "${FILE_EXT}" = ".tar.gz" ]; then # Attempt to import/configure foreign/ezjail container info "Extracting files from '${TARGET}' archive..." From f0c3620fac4ac64946131a55980afa6e42bb3a7f Mon Sep 17 00:00:00 2001 From: JRGTH Date: Sat, 10 Jul 2021 08:35:50 -0400 Subject: [PATCH 19/21] Add export/import standard I/O redirection This update enhances the export and import command to fully support jail export/import user standard input/output redirection --- usr/local/share/bastille/export.sh | 102 +++++++++++++++++++---------- usr/local/share/bastille/import.sh | 55 ++++++++++++---- 2 files changed, 107 insertions(+), 50 deletions(-) diff --git a/usr/local/share/bastille/export.sh b/usr/local/share/bastille/export.sh index a8f678c..af1d284 100644 --- a/usr/local/share/bastille/export.sh +++ b/usr/local/share/bastille/export.sh @@ -33,8 +33,9 @@ usage() { # Build an independent usage for the export command - # Valid compress/options for ZFS systems are raw, .gz, .tgz, .txz and .xz(default) - # Valid compress/options for non ZFS configured systems are .tgz and .txz(default) + # Valid compress/options for ZFS systems are raw, .gz, .tgz, .txz and .xz + # Valid compress/options for non ZFS configured systems are .tgz and .txz + # If no compression option specified, user must redirect standard output echo -e "${COLOR_RED}Usage: bastille export | option(s) | TARGET | PATH${COLOR_RESET}" cat << EOF @@ -46,6 +47,7 @@ usage() { --tgz -- Export a jail using simple .tgz compressed archive instead. --txz -- Export a jail using simple .txz compressed archive instead. -v | --verbose -- Be more verbose during the ZFS send operation. + --xz -- Export a ZFS jail using XZ(.xz) compressed image. EOF exit 1 @@ -77,6 +79,7 @@ zfs_enable_check() { TARGET="${1}" GZIP_EXPORT= SAFE_EXPORT= +USER_EXPORT= RAW_EXPORT= DIR_EXPORT= TXZ_EXPORT= @@ -97,6 +100,12 @@ while [ $# -gt 0 ]; do opt_count shift ;; + --xz) + XZ_EXPORT="1" + TARGET="${2}" + opt_count + shift + ;; --tgz) TGZ_EXPORT="1" TARGET="${2}" @@ -186,35 +195,45 @@ fi create_zfs_snap() { # Take a recursive temporary snapshot - info "Creating temporary ZFS snapshot for export..." + if [ -z "${USER_EXPORT}" ]; then + info "Creating temporary ZFS snapshot for export..." + fi zfs snapshot -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" } +clean_zfs_snap() { + # Cleanup the recursive temporary snapshot + zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}/root@bastille_export_${DATE}" + zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" +} + export_check() { # Inform the user about the exporting method - if [ -n "$(jls name | awk "/^${TARGET}$/")" ]; then - if [ -n "${SAFE_EXPORT}" ]; then - EXPORT_AS="Safely exporting" + if [ -z "${USER_EXPORT}" ]; then + if [ -n "$(jls name | awk "/^${TARGET}$/")" ]; then + if [ -n "${SAFE_EXPORT}" ]; then + EXPORT_AS="Safely exporting" + else + EXPORT_AS="Hot exporting" + fi else - EXPORT_AS="Hot exporting" + EXPORT_AS="Exporting" fi - else - EXPORT_AS="Exporting" - fi - if [ "${FILE_EXT}" = ".xz" -o "${FILE_EXT}" = ".gz" -o "${FILE_EXT}" = "" ]; then - EXPORT_TYPE="image" - else - EXPORT_TYPE="archive" - fi + if [ "${FILE_EXT}" = ".xz" -o "${FILE_EXT}" = ".gz" -o "${FILE_EXT}" = "" ]; then + EXPORT_TYPE="image" + else + EXPORT_TYPE="archive" + fi - if [ -n "${RAW_EXPORT}" ]; then - EXPORT_INFO="to a raw ${EXPORT_TYPE}" - else - EXPORT_INFO="to a compressed ${FILE_EXT} ${EXPORT_TYPE}" - fi + if [ -n "${RAW_EXPORT}" ]; then + EXPORT_INFO="to a raw ${EXPORT_TYPE}" + else + EXPORT_INFO="to a compressed ${FILE_EXT} ${EXPORT_TYPE}" + fi - info "${EXPORT_AS} '${TARGET}' ${EXPORT_INFO}..." + info "${EXPORT_AS} '${TARGET}' ${EXPORT_INFO}..." + fi # Safely stop and snapshot the jail if [ -n "${SAFE_EXPORT}" ]; then @@ -226,7 +245,9 @@ export_check() { fi if [ "${bastille_zfs_enable}" = "YES" ]; then - info "Sending ZFS data stream..." + if [ -z "${USER_EXPORT}" ]; then + info "Sending ZFS data stream..." + fi fi } @@ -242,8 +263,7 @@ jail_export() { # Export the raw container recursively and cleanup temporary snapshots zfs send ${OPT_ZSEND} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" \ > "${bastille_backupsdir}/${TARGET}_${DATE}" - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}/root@bastille_export_${DATE}" - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" + clean_zfs_snap elif [ -n "${GZIP_EXPORT}" ]; then FILE_EXT=".gz" export_check @@ -251,17 +271,23 @@ jail_export() { # Export the raw container recursively and cleanup temporary snapshots zfs send ${OPT_ZSEND} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" | \ gzip ${bastille_compress_gz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}" - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}/root@bastille_export_${DATE}" - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" - else + clean_zfs_snap + elif [ -n "${XZ_EXPORT}" ]; then FILE_EXT=".xz" export_check - # Export the container recursively and cleanup temporary snapshots(default) + # Export the container recursively and cleanup temporary snapshots zfs send ${OPT_ZSEND} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" | \ xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}" - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}/root@bastille_export_${DATE}" - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" + clean_zfs_snap + else + FILE_EXT="" + USER_EXPORT="1" + export_check + + # Quietly export the container recursively, user must redirect standard output + zfs send ${OPT_ZSEND} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" + clean_zfs_snap fi fi else @@ -271,22 +297,26 @@ jail_export() { # Create standard tgz backup archive info "Exporting '${TARGET}' to a compressed ${FILE_EXT} archive..." cd "${bastille_jailsdir}" && tar -cf - "${TARGET}" | gzip ${bastille_compress_gz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}" - else + elif [ -n "${TXZ_EXPORT}" ]; then FILE_EXT=".txz" - # Create standard txz backup archive(default) + # Create standard txz backup archive info "Exporting '${TARGET}' to a compressed ${FILE_EXT} archive..." cd "${bastille_jailsdir}" && tar -cf - "${TARGET}" | xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}" + else + error_exit "Error: export option required" fi fi if [ "$?" -ne 0 ]; then error_exit "Failed to export '${TARGET}' container." else - # Generate container checksum file - cd "${bastille_backupsdir}" - sha256 -q "${TARGET}_${DATE}${FILE_EXT}" > "${TARGET}_${DATE}.sha256" - info "Exported '${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}' successfully." + if [ -z "${USER_EXPORT}" ]; then + # Generate container checksum file + cd "${bastille_backupsdir}" + sha256 -q "${TARGET}_${DATE}${FILE_EXT}" > "${TARGET}_${DATE}.sha256" + info "Exported '${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}' successfully." + fi exit 0 fi } diff --git a/usr/local/share/bastille/import.sh b/usr/local/share/bastille/import.sh index fb9b1a9..5c64938 100644 --- a/usr/local/share/bastille/import.sh +++ b/usr/local/share/bastille/import.sh @@ -33,6 +33,7 @@ usage() { # Build an independent usage for the import command + # If no file/extension specified, will import from standard input echo -e "${COLOR_RED}Usage: bastille import [option(s)] FILE${COLOR_RESET}" cat << EOF @@ -53,11 +54,12 @@ help|-h|--help) esac if [ $# -gt 3 ] || [ $# -lt 1 ]; then - usage + #usage fi TARGET="${1}" OPT_FORCE= +USER_IMPORT= OPT_ZRECV="-u" # Handle and parse option args @@ -113,7 +115,7 @@ validate_archive() { if [ -n "${OPT_FORCE}" ]; then warn "Warning: Skipping archive validation!" else - error_exit "Checksum file not found. See 'bastille import TARGET -f'." + error_exit "Checksum file not found. See 'bastille import [option(s)] FILE'." fi fi fi @@ -359,11 +361,12 @@ jail_import() { # Attempt to import container from file FILE_TRIM=$(echo "${TARGET}" | sed 's/\.xz//g;s/\.gz//g;s/\.tgz//g;s/\.txz//g;s/\.zip//g;s/\.tar\.gz//g;s/\.tar//g') FILE_EXT=$(echo "${TARGET}" | sed "s/${FILE_TRIM}//g") - validate_archive + #validate_archive if [ -d "${bastille_jailsdir}" ]; then if [ "${bastille_zfs_enable}" = "YES" ]; then if [ -n "${bastille_zfs_zpool}" ]; then if [ "${FILE_EXT}" = ".xz" ]; then + validate_archive # Import from compressed xz on ZFS systems info "Importing '${TARGET_TRIM}' from compressed ${FILE_EXT} image." info "Receiving ZFS data stream..." @@ -373,6 +376,7 @@ jail_import() { # Update ZFS mountpoint property if required update_zfsmount elif [ "${FILE_EXT}" = ".gz" ]; then + validate_archive # Import from compressed xz on ZFS systems info "Importing '${TARGET_TRIM}' from compressed ${FILE_EXT} image." info "Receiving ZFS data stream..." @@ -383,6 +387,7 @@ jail_import() { update_zfsmount elif [ "${FILE_EXT}" = ".txz" ]; then + validate_archive # Prepare the ZFS environment and restore from existing .txz file create_zfs_datasets @@ -394,6 +399,7 @@ jail_import() { remove_zfs_datasets fi elif [ "${FILE_EXT}" = ".tgz" ]; then + validate_archive # Prepare the ZFS environment and restore from existing .tgz file create_zfs_datasets @@ -405,6 +411,7 @@ jail_import() { remove_zfs_datasets fi elif [ "${FILE_EXT}" = ".zip" ]; then + validate_archive # Attempt to import a foreign/iocage container info "Importing '${TARGET_TRIM}' from foreign compressed ${FILE_EXT} archive." # Sane bastille ZFS options @@ -469,14 +476,24 @@ jail_import() { fi elif [ -z "${FILE_EXT}" ]; then if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$'; then - # Based on the file name, looks like we are importing a raw bastille image - # Import from uncompressed image file - info "Importing '${TARGET_TRIM}' from uncompressed image archive." - info "Receiving ZFS data stream..." - zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" < "${bastille_backupsdir}/${TARGET}" + validate_archive + # Based on the file name, looks like we are importing a raw bastille image + # Import from uncompressed image file + info "Importing '${TARGET_TRIM}' from uncompressed image archive." + info "Receiving ZFS data stream..." + zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" < "${bastille_backupsdir}/${TARGET}" - # Update ZFS mountpoint property if required - update_zfsmount + # Update ZFS mountpoint property if required + update_zfsmount + else + # Based on the file name, looks like we are importing from previous redirected bastille image + # Quietly import from previous redirected bastille image + if ! zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}"; then + exit 1 + else + # Update ZFS mountpoint property if required + update_zfsmount + fi fi else error_exit "Unknown archive format." @@ -520,7 +537,9 @@ jail_import() { # This is required on foreign imports only update_jailconf update_fstab - info "Container '${TARGET_TRIM}' imported successfully." + if [ -z "${USER_IMPORT}" ]; then + info "Container '${TARGET_TRIM}' imported successfully." + fi exit 0 fi else @@ -551,14 +570,22 @@ if [ -f "${bastille_backupsdir}/${TARGET}" ]; then error_exit "Unrecognized archive name." fi else - error_exit "Archive '${TARGET}' not found." + if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.*$'; then + error_exit "Archive '${TARGET}' not found." + else + # Assume user will import from standard input + TARGET_TRIM=${TARGET} + USER_IMPORT="1" + fi fi # Check if a running jail matches name or already exist if [ -n "$(jls name | awk "/^${TARGET_TRIM}$/")" ]; then error_exit "A running jail matches name." -elif [ -d "${bastille_jailsdir}/${TARGET_TRIM}" ]; then - error_exit "Container: ${TARGET_TRIM} already exists." +elif [ -n "${TARGET_TRIM}" ]; then + if [ -d "${bastille_jailsdir}/${TARGET_TRIM}" ]; then + error_exit "Container: ${TARGET_TRIM} already exists." + fi fi if [ -n "${TARGET}" ]; then From 0a7db324905fc98740d6a6afc45c1446cc61ec39 Mon Sep 17 00:00:00 2001 From: JRGTH Date: Sat, 10 Jul 2021 08:52:08 -0400 Subject: [PATCH 20/21] Restored usage after file debug --- usr/local/share/bastille/import.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/import.sh b/usr/local/share/bastille/import.sh index 5c64938..970f4a7 100644 --- a/usr/local/share/bastille/import.sh +++ b/usr/local/share/bastille/import.sh @@ -54,7 +54,7 @@ help|-h|--help) esac if [ $# -gt 3 ] || [ $# -lt 1 ]; then - #usage + usage fi TARGET="${1}" From ee2c25697c334b38ac5d91b47d4fbc4fad24a19a Mon Sep 17 00:00:00 2001 From: JRGTH Date: Sat, 10 Jul 2021 09:01:28 -0400 Subject: [PATCH 21/21] Cleanup obsolete code --- usr/local/share/bastille/import.sh | 37 +++++++++++++----------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/usr/local/share/bastille/import.sh b/usr/local/share/bastille/import.sh index 970f4a7..48e88df 100644 --- a/usr/local/share/bastille/import.sh +++ b/usr/local/share/bastille/import.sh @@ -98,29 +98,25 @@ fi validate_archive() { # Compare checksums on the target archive - # Skip validation for unsupported archives - if [ "${FILE_EXT}" != ".tar.gz" ] && [ "${FILE_EXT}" != ".tar" ]; then - if [ -f "${bastille_backupsdir}/${TARGET}" ]; then - if [ -f "${bastille_backupsdir}/${FILE_TRIM}.sha256" ]; then - info "Validating file: ${TARGET}..." - SHA256_DIST=$(cat "${bastille_backupsdir}/${FILE_TRIM}.sha256") - SHA256_FILE=$(sha256 -q "${bastille_backupsdir}/${TARGET}") - if [ "${SHA256_FILE}" != "${SHA256_DIST}" ]; then - error_exit "Failed validation for ${TARGET}." - else - info "File validation successful!" - fi + # Skip validation for unsupported archive + if [ -f "${bastille_backupsdir}/${TARGET}" ]; then + if [ -f "${bastille_backupsdir}/${FILE_TRIM}.sha256" ]; then + info "Validating file: ${TARGET}..." + SHA256_DIST=$(cat "${bastille_backupsdir}/${FILE_TRIM}.sha256") + SHA256_FILE=$(sha256 -q "${bastille_backupsdir}/${TARGET}") + if [ "${SHA256_FILE}" != "${SHA256_DIST}" ]; then + error_exit "Failed validation for ${TARGET}." else - # Check if user opt to force import - if [ -n "${OPT_FORCE}" ]; then - warn "Warning: Skipping archive validation!" - else - error_exit "Checksum file not found. See 'bastille import [option(s)] FILE'." - fi + info "File validation successful!" + fi + else + # Check if user opt to force import + if [ -n "${OPT_FORCE}" ]; then + warn "Warning: Skipping archive validation!" + else + error_exit "Checksum file not found. See 'bastille import [option(s)] FILE'." fi fi - else - warn "Warning: Skipping archive validation!" fi } @@ -361,7 +357,6 @@ jail_import() { # Attempt to import container from file FILE_TRIM=$(echo "${TARGET}" | sed 's/\.xz//g;s/\.gz//g;s/\.tgz//g;s/\.txz//g;s/\.zip//g;s/\.tar\.gz//g;s/\.tar//g') FILE_EXT=$(echo "${TARGET}" | sed "s/${FILE_TRIM}//g") - #validate_archive if [ -d "${bastille_jailsdir}" ]; then if [ "${bastille_zfs_enable}" = "YES" ]; then if [ -n "${bastille_zfs_zpool}" ]; then