From 3b3fa217c5387928e55116ceae50de1839df7a8e Mon Sep 17 00:00:00 2001 From: tschettervictor Date: Sat, 22 Nov 2025 13:07:46 -0700 Subject: [PATCH] export/import: support zstd --- docs/chapters/subcommands/export.rst | 22 +- docs/chapters/subcommands/import.rst | 10 +- usr/local/etc/bastille/bastille.conf.sample | 4 +- usr/local/share/bastille/export.sh | 289 ++++++++++++-------- usr/local/share/bastille/import.sh | 87 ++++-- 5 files changed, 262 insertions(+), 150 deletions(-) diff --git a/docs/chapters/subcommands/export.rst b/docs/chapters/subcommands/export.rst index 873db8a7..abbbeac8 100644 --- a/docs/chapters/subcommands/export.rst +++ b/docs/chapters/subcommands/export.rst @@ -26,14 +26,16 @@ Available options are: Options: - -a | --auto Auto mode. Start/stop jail(s) if required. - --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. - --xz Export a ZFS jail using XZ(.xz) compressed image. - -x | --debug Enable debug mode. + -a | --auto Auto mode. Start/stop jail(s) if required. + -l | --live Export a running jail (ZFS only). + --gz Export to '.gz' compressed image (ZFS only). + --xz Export to a '.xz' compressed image (ZFS only). + --zst Export to a .zst compressed image (ZFS only). + --raw Export to an uncompressed RAW image (ZFS only). + --tgz Export to a '.tgz' compressed archive. + --txz Export to a '.txz' compressed archive. + --tzst Export to a '.tzst' compressed archive. + -v | --verbose Enable verbose mode (ZFS only). + -x | --debug Enable debug mode. - Note: If no export option specified, the container should be redirected to standard output. + Note: If no export option specified, the container should be redirected to standard output. diff --git a/docs/chapters/subcommands/import.rst b/docs/chapters/subcommands/import.rst index 0fed6b2f..cc2fa504 100644 --- a/docs/chapters/subcommands/import.rst +++ b/docs/chapters/subcommands/import.rst @@ -19,9 +19,9 @@ To import to a specified release, specify it as the last argument. Options: - -f | --force Force an archive import regardless if the checksum file does not match or missing. - -M | --static-mac Generate static MAC for jail when importing foreign jails like iocage. - -v | --verbose Be more verbose during the ZFS receive operation. - -x | --debug Enable debug mode. + -f | --force Force an archive import regardless if the checksum file does not match or missing. + -M | --static-mac Generate static MAC for jail when importing foreign jails like iocage. + -v | --verbose Enable verbose mode (ZFS only). + -x | --debug Enable debug mode. - Tip: If no option specified, container should be imported from standard input. \ No newline at end of file + Tip: If no option specified, container should be imported from standard input. \ No newline at end of file diff --git a/usr/local/etc/bastille/bastille.conf.sample b/usr/local/etc/bastille/bastille.conf.sample index a39b22ae..da2c1a1f 100644 --- a/usr/local/etc/bastille/bastille.conf.sample +++ b/usr/local/etc/bastille/bastille.conf.sample @@ -67,7 +67,9 @@ bastille_compress_xz_options="-0 -v" ## default 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" -bastille_export_options="" ## default "" predefined export options, e.g. "--safe --gz" +bastille_compress_zst_options="-3 -v" ## default "-3 -v" +bastille_decompress_zst_options="-k -d -c -v" ## default "-k -d -c -v" +bastille_export_options="" ## default "" predefined export options, e.g. "--live --gz" ## Networking bastille_network_vnet_type="if_bridge" ## default: "if_bridge" diff --git a/usr/local/share/bastille/export.sh b/usr/local/share/bastille/export.sh index 5d61dcfe..34f0cc75 100644 --- a/usr/local/share/bastille/export.sh +++ b/usr/local/share/bastille/export.sh @@ -42,15 +42,17 @@ usage() { Options: - -a | --auto Auto mode. Start/stop jail(s) if required. - --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. - --xz Export a ZFS jail using XZ(.xz) compressed image. - -x | --debug Enable debug mode. + -a | --auto Auto mode. Start/stop jail(s) if required. + -l | --live Export a running jail (ZFS only). + --gz Export to '.gz' compressed image (ZFS only). + --xz Export to a '.xz' compressed image (ZFS only). + --zst Export to a .zst compressed image (ZFS only). + --raw Export to an uncompressed RAW image (ZFS only). + --tgz Export to a '.tgz' compressed archive. + --txz Export to a '.txz' compressed archive. + --tzst Export to a '.tzst' compressed archive. + -v | --verbose Enable verbose mode (ZFS only). + -x | --debug Enable debug mode. Note: If no export option specified, the jail should be redirected to standard output. @@ -72,17 +74,18 @@ opt_count() { # Reset export options AUTO=0 -GZIP_EXPORT= -XZ_EXPORT= -SAFE_EXPORT= -USER_EXPORT= -RAW_EXPORT= -DIR_EXPORT= -TXZ_EXPORT= -TGZ_EXPORT= +LIVE=0 +GZIP_EXPORT=0 +XZ_EXPORT=0 +ZST_EXPORT=0 +RAW_EXPORT=0 OPT_ZSEND="-R" -COMP_OPTION="0" - +TXZ_EXPORT=0 +TGZ_EXPORT=0 +TZST_EXPORT=0 +USER_EXPORT=0 +DIR_EXPORT="" +COMP_OPTION=0 if [ -n "${bastille_export_options}" ]; then # Overrides the case options by the user defined option(s) automatically. # Add bastille_export_options="--optionA --optionB" to bastille.conf, or simply `export bastille_export_options="--optionA --optionB"` environment variable. @@ -99,6 +102,9 @@ if [ -n "${bastille_export_options}" ]; then -a|--auto) AUTO="1" ;; + -l|--live) + LIVE="1" + ;; --gz) GZIP_EXPORT="1" opt_count @@ -107,6 +113,14 @@ if [ -n "${bastille_export_options}" ]; then XZ_EXPORT="1" opt_count ;; + --zst) + ZST_EXPORT="1" + opt_count + ;; + -r|--raw) + RAW_EXPORT="1" + opt_count + ;; --tgz) TGZ_EXPORT="1" opt_count @@ -117,21 +131,21 @@ if [ -n "${bastille_export_options}" ]; then opt_count zfs_enable_check ;; - -s|--safe) - SAFE_EXPORT="1" - ;; - -r|--raw) - RAW_EXPORT="1" + --tzst) + TZST_EXPORT="1" opt_count + zfs_enable_check ;; -v|--verbose) OPT_ZSEND="-Rv" ;; -x) - enable_debug - ;; - -*) error_notify "[ERROR]: Unknown Option: \"${1}\"" - usage;; + enable_debug + ;; + -*) + error_notify "[ERROR]: Unknown Option: \"${1}\"" + usage + ;; esac done @@ -147,6 +161,10 @@ else AUTO=1 shift ;; + -l|--live) + LIVE="1" + shift + ;; --gz) GZIP_EXPORT="1" opt_count @@ -157,6 +175,16 @@ else opt_count shift ;; + --zst) + ZST_EXPORT="1" + opt_count + shift + ;; + -r|--raw) + RAW_EXPORT="1" + opt_count + shift + ;; --tgz) TGZ_EXPORT="1" opt_count @@ -169,13 +197,10 @@ else zfs_enable_check shift ;; - -s|--safe) - SAFE_EXPORT="1" - shift - ;; - -r|--raw) - RAW_EXPORT="1" + --tzst) + TZST_EXPORT="1" opt_count + zfs_enable_check shift ;; -v|--verbose) @@ -183,13 +208,14 @@ else shift ;; -x) - enable_debug - shift - ;; + enable_debug + shift + ;; -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in a) AUTO=1 ;; + l) LIVE=1 ;; x) enable_debug ;; *) error_exit "[ERROR]: Unknown Option: \"${1}\"" esac @@ -203,12 +229,11 @@ else done fi -if [ $# -gt 2 ] || [ $# -lt 1 ]; then +if [ $# -lt 1 ] || [ $# -gt 2 ]; then usage fi TARGET="${1}" - # Check for directory export if echo "${2}" | grep -q "\/"; then DIR_EXPORT="${2}" @@ -217,39 +242,34 @@ fi bastille_root_check set_target_single "${TARGET}" -# Validate for combined options +# Only allow a single compression option if [ "${COMP_OPTION}" -gt "1" ]; then error_exit "[ERROR]: Only one compression format can be used during export." fi -if { [ -n "${TXZ_EXPORT}" ] || [ -n "${TGZ_EXPORT}" ]; } && [ -n "${SAFE_EXPORT}" ]; then - error_exit "[ERROR]: Simple archive modes with safe ZFS export can't be used together." -fi - +# Validate LIVE and AUTO if ! checkyesno bastille_zfs_enable; then - if [ -n "${XZ_EXPORT}" ] || - [ -n "${GZIP_EXPORT}" ] || - [ -n "${RAW_EXPORT}" ] || - [ -n "${SAFE_EXPORT}" ] || + if [ "${LIVE}" -eq 1 ]; then + error_exit "[ERROR]: [-l|--live] can only be used with ZFS." + fi +elif [ "${AUTO}" -eq 1 ] && [ "${LIVE}" -eq 1 ]; then + error_exit "[ERROR]: [-a|--auto] cannot be used with [-l|--live]." +fi + +# Don't allow LIVE with TXZ_EXPORT or TGZ_EXPORT +if { [ "${TXZ_EXPORT}" -eq 1 ] || [ "${TGZ_EXPORT}" -eq 1 ] || "${TZST_EXPORT}" -eq 1 ]; } && [ "${LIVE}" -eq 1 ]; then + error_exit "[ERROR]: Archive mode cannot be used with [-l|--live]." +fi + +# Don't allow ZFS specific options if not enabled +if ! checkyesno bastille_zfs_enable; then + if [ "${XZ_EXPORT}" -eq 1 ] || + [ "${GZIP_EXPORT}" -eq 1 ] || + [ "${RAW_EXPORT}" -eq 1 ] || + [ "${LIVE}" -eq 1 ] || + [ "${ZST_EXPORT}" -eq 1 ] || [ "${OPT_ZSEND}" = "-Rv" ]; then - error_exit "[ERROR]: Options --xz, --gz, --raw, --safe, and --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 "$(/usr/sbin/jls name | awk "/^${TARGET}$/")" ]; then - SAFE_EXPORT= - fi -fi - -# Export directory check -if [ -n "${DIR_EXPORT}" ]; then - if [ -d "${DIR_EXPORT}" ]; then - # Set the user defined export directory - bastille_backupsdir="${DIR_EXPORT}" - else - error_exit "[ERROR]: Path not found." + error_exit "[ERROR]: Options --xz, --gz, --raw, -l|--live, --zst and --verbose are only valid for ZFS configured systems." fi fi @@ -260,10 +280,50 @@ fi if [ -z "${bastille_compress_gz_options}" ]; then bastille_compress_gz_options="-1 -v" fi +if [ -z "${bastille_compress_zst_options}" ]; then + bastille_compress_zst_options="-3 -v" +fi + +# Export directory check +if [ -n "${DIR_EXPORT}" ]; then + if [ -d "${DIR_EXPORT}" ]; then + # Set the user defined export directory + bastille_backupsdir="${DIR_EXPORT}" + else + error_exit "[ERROR]: Path not found." + fi +elif [ ! -d "${bastille_backupsdir}" ]; then + error_exit "[ERROR]: Backups directory/dataset does not exist. See 'bastille bootstrap'." +fi + +# Validate jail state +if checkyesno bastille_zfs_enable; then + if [ "${LIVE}" -eq 1 ]; then + if ! check_target_is_running "${TARGET}"; then + error_exit "[ERROR]: [-l|--live] can only be used with a running jail." + fi + elif check_target_is_running "${TARGET}"; then + if [ "${AUTO}" -eq 1 ]; then + bastille stop "${TARGET}" + else + info "\n[${TARGET}]:" + error_notify "[ERROR]: Jail is running." + error_exit "Use [-a|--auto] to auto-stop the jail, or [-l|--live] (ZFS only) to migrate a running jail." + fi + fi +else + check_target_is_stopped "${TARGET}" || if [ "${AUTO}" -eq 1 ]; then + bastille stop "${TARGET}" + else + info "\n[${TARGET}]:" + error_notify "Jail is running." + error_exit "Use [-a|--auto] to auto-stop the jail." + fi +fi create_zfs_snap() { # Take a recursive temporary snapshot - if [ -z "${USER_EXPORT}" ]; then + if [ "${USER_EXPORT}" -eq 0 ]; then info "\nCreating temporary ZFS snapshot for export..." fi zfs snapshot -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_${TARGET}_${DATE}" @@ -276,19 +336,20 @@ clean_zfs_snap() { } export_check() { + # Inform the user about the exporting method - if [ -z "${USER_EXPORT}" ]; then - if [ -n "$(/usr/sbin/jls name | awk "/^${TARGET}$/")" ]; then - if [ -n "${SAFE_EXPORT}" ]; then - EXPORT_AS="Safely exporting" - else + if [ "${USER_EXPORT}" -eq 0 ]; then + if check_target_is_running "${TARGET}" 2>/dev/null; then + if [ "${LIVE}" -eq 1 ]; then EXPORT_AS="Hot exporting" + else + EXPORT_AS="Safely exporting" fi else EXPORT_AS="Exporting" fi - if [ "${FILE_EXT}" = ".xz" ] || [ "${FILE_EXT}" = ".gz" ] || [ "${FILE_EXT}" = "" ]; then + if [ "${FILE_EXT}" = ".xz" ] || [ "${FILE_EXT}" = ".gz" ] || [ "${FILE_EXT}" = ".zst" ] || [ "${FILE_EXT}" = "" ]; then EXPORT_TYPE="image" else EXPORT_TYPE="archive" @@ -303,19 +364,15 @@ export_check() { info "\n${EXPORT_AS} '${TARGET}' ${EXPORT_INFO}..." fi - # 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 checkyesno bastille_zfs_enable; then - if [ -z "${USER_EXPORT}" ]; then + + # Create snapshot + create_zfs_snap + + if [ "${USER_EXPORT}" -eq 0 ]; then info "\nSending ZFS data stream..." fi + fi } @@ -331,7 +388,8 @@ jail_export() { if [ "$(zfs get -H -o value encryption ${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET})" = "on" ]; then error_exit "[ERROR]: Exporting jails in encryoted datasets is not supported." fi - if [ -n "${RAW_EXPORT}" ]; then + + if [ "${RAW_EXPORT}" -eq 1 ]; then FILE_EXT="" @@ -345,7 +403,7 @@ jail_export() { clean_zfs_snap fi - elif [ -n "${GZIP_EXPORT}" ]; then + elif [ "${GZIP_EXPORT}" -eq 1 ]; then FILE_EXT=".gz" @@ -359,7 +417,7 @@ jail_export() { clean_zfs_snap fi - elif [ -n "${XZ_EXPORT}" ]; then + elif [ "${XZ_EXPORT}" -eq 1 ]; then FILE_EXT=".xz" @@ -373,6 +431,20 @@ jail_export() { clean_zfs_snap fi + elif [ "${ZST_EXPORT}" -eq 1 ]; then + + FILE_EXT=".zst" + + export_check + + # Export the container recursively and cleanup temporary snapshots + if ! zfs send ${OPT_ZSEND} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_${TARGET}_${DATE}" | zstd ${bastille_compress_zst_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}"; then + clean_zfs_snap + error_exit "[ERROR]: Failed to export jail: ${TARGET}" + else + clean_zfs_snap + fi + else FILE_EXT="" @@ -390,7 +462,7 @@ jail_export() { fi fi else - if [ -n "${TGZ_EXPORT}" ]; then + if [ "${TGZ_EXPORT}" -eq 1 ]; then FILE_EXT=".tgz" @@ -402,7 +474,7 @@ jail_export() { error_exit "[ERROR]: Failed to export jail: ${TARGET}" fi - elif [ -n "${TXZ_EXPORT}" ]; then + elif [ "${TXZ_EXPORT}" -eq 1 ]; then FILE_EXT=".txz" @@ -414,6 +486,18 @@ jail_export() { error_exit "[ERROR]: Failed to export jail: ${TARGET}" fi + elif [ "${TZST_EXPORT}" -eq 1 ]; then + + FILE_EXT=".tzst" + + # Create standard txz backup archive + info "\nExporting '${TARGET}' to a compressed ${FILE_EXT} archive..." + + cd "${bastille_jailsdir}" || error_exit "[ERROR]: Failed to change to directory: ${bastille_jailssdir}" + if ! tar -cf - "${TARGET}" | zstd ${bastille_compress_tzst_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}"; then + error_exit "[ERROR]: Failed to export jail: ${TARGET}" + fi + else error_exit "[ERROR]: export option required" fi @@ -423,7 +507,7 @@ jail_export() { if [ "$?" -ne 0 ]; then error_exit "[ERROR]: Failed to export jail: ${TARGET}" else - if [ -z "${USER_EXPORT}" ]; then + if [ "${USER_EXPORT}" -eq 0 ]; then # Generate container checksum file cd "${bastille_backupsdir}" || error_exit "[ERROR]: Failed to change to directory: ${bastille_backupsdir}" if ! sha256 -q "${TARGET}_${DATE}${FILE_EXT}" > "${TARGET}_${DATE}.sha256"; then @@ -435,29 +519,4 @@ jail_export() { fi } -# Check if backups directory/dataset exist -if [ ! -d "${bastille_backupsdir}" ]; then - error_exit "[ERROR]: Backups directory/dataset does not exist. See 'bastille bootstrap'." -fi - -if [ -n "${TARGET}" ]; then - - # Validate jail existence - if [ ! -d "${bastille_jailsdir}/${TARGET}" ]; then - error_exit "[ERROR]: Jail not found: ${TARGET}" - fi - - # Jail needs to be stopped on non-ZFS systems - if ! checkyesno bastille_zfs_enable; then - # Validate jail state - check_target_is_stopped "${TARGET}" || if [ "${AUTO}" -eq 1 ]; then - bastille stop "${TARGET}" - else - info "\n[${TARGET}]:" - error_notify "Jail is running." - error_exit "Use [-a|--auto] to auto-stop the jail." - fi - fi - - jail_export -fi +jail_export diff --git a/usr/local/share/bastille/import.sh b/usr/local/share/bastille/import.sh index 8b97d870..95ff5d76 100644 --- a/usr/local/share/bastille/import.sh +++ b/usr/local/share/bastille/import.sh @@ -40,12 +40,12 @@ usage() { Options: - -f | --force Force an archive import regardless if the checksum file does not match or missing. - -M | --static-mac Generate static MAC for jail when importing foreign jails like iocage. - -v | --verbose Be more verbose during the ZFS receive operation. - -x | --debug Enable debug mode. + -f | --force Force an archive import regardless if the checksum file does not match or missing. + -M | --static-mac Generate static MAC for jail when importing foreign jails like iocage. + -v | --verbose Enable verbose mode (ZFS only). + -x | --debug Enable debug mode. -Tip: If no option specified, container should be imported from standard input. + Tip: If no option specified, container should be imported from standard input. EOF exit 1 @@ -58,9 +58,9 @@ OPT_STATIC_MAC="" USER_IMPORT= while [ "$#" -gt 0 ]; do case "${1}" in - -h|--help|help) + -h|--help|help) usage - ;; + ;; -f|--force) OPT_FORCE="1" shift @@ -81,7 +81,7 @@ while [ "$#" -gt 0 ]; do for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in f) OPT_FORCE=1 ;; - M) OPT_STATIC_MAC=1 ;; + M) OPT_STATIC_MAC=1 ;; v) OPT_ZRECV="-u -v" ;; x) enable_debug ;; *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; @@ -111,8 +111,12 @@ fi if [ -z "${bastille_decompress_gz_options}" ]; then bastille_decompress_gz_options="-k -d -c -v" fi +if [ -z "${bastille_decompress_zst_options}" ]; then + bastille_decompress_zst_options="-k -d -c -v" +fi validate_archive() { + # Compare checksums on the target archive # Skip validation for unsupported archive if [ -f "${bastille_backupsdir}/${TARGET}" ]; then @@ -438,6 +442,7 @@ update_config() { } workout_components() { + if [ "${FILE_EXT}" = ".tar" ]; then # Workaround to determine the tarball path/components before extract(assumes path/jails/target) JAIL_PATH=$(tar -tvf ${bastille_backupsdir}/${TARGET} | grep -wo "/.*/jails/${TARGET_TRIM}" | tail -n1) @@ -451,6 +456,7 @@ workout_components() { } vnet_requirements() { + # VNET jib script requirement if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then if [ ! "$(command -v jib)" ]; then @@ -472,6 +478,7 @@ vnet_requirements() { } config_netif() { + # Get interface from bastille configuration if [ -n "${bastille_network_loopback}" ]; then NETIF_CONFIG="${bastille_network_loopback}" @@ -509,8 +516,9 @@ update_symlinks() { } create_zfs_datasets() { + # Prepare the ZFS environment and restore from file - info "\nImporting '${TARGET_TRIM}' from foreign compressed ${FILE_EXT} archive." + info "\nImporting '${TARGET_TRIM}' from compressed ${FILE_EXT} archive." echo "Preparing ZFS environment..." # Create required ZFS datasets, mountpoint inherited from system @@ -526,12 +534,14 @@ remove_zfs_datasets() { } 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_TRIM=$(echo "${TARGET}" | sed 's/\.xz//g;s/\.gz//g;s/\.zst//g;s/\.tgz//g;s/\.txz//g;s/\.tzst//g;s/\.zip//g;s/\.tar\.gz//g;s/\.tar//g') FILE_EXT=$(echo "${TARGET}" | sed "s/${FILE_TRIM}//g") if [ -d "${bastille_jailsdir}" ]; then if checkyesno bastille_zfs_enable; then if [ -n "${bastille_zfs_zpool}" ]; then + if [ "${FILE_EXT}" = ".xz" ]; then validate_archive # Import from compressed xz on ZFS systems @@ -539,9 +549,9 @@ jail_import() { echo "Receiving ZFS data stream..." xz ${bastille_decompress_xz_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 + elif [ "${FILE_EXT}" = ".gz" ]; then validate_archive # Import from compressed xz on ZFS systems @@ -549,7 +559,16 @@ jail_import() { echo "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 + elif [ "${FILE_EXT}" = ".zst" ]; then + validate_archive + # Import from compressed zst on ZFS systems + info "\nImporting '${TARGET_TRIM}' from compressed ${FILE_EXT} image." + echo "Receiving ZFS data stream..." + zstd ${bastille_decompress_zst_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 @@ -557,7 +576,6 @@ jail_import() { validate_archive # Prepare the ZFS environment and restore from existing .txz file create_zfs_datasets - # Extract required files to the new datasets info "\nExtracting files from '${TARGET}' archive..." tar --exclude='root' -Jxf "${bastille_backupsdir}/${TARGET}" --strip-components 1 -C "${bastille_jailsdir}/${TARGET_TRIM}" @@ -565,11 +583,11 @@ jail_import() { if [ "$?" -ne 0 ]; then remove_zfs_datasets fi + elif [ "${FILE_EXT}" = ".tgz" ]; then validate_archive # Prepare the ZFS environment and restore from existing .tgz file create_zfs_datasets - # Extract required files to the new datasets info "\nExtracting files from '${TARGET}' archive..." tar --exclude='root' -xf "${bastille_backupsdir}/${TARGET}" --strip-components 1 -C "${bastille_jailsdir}/${TARGET_TRIM}" @@ -577,7 +595,21 @@ jail_import() { if [ "$?" -ne 0 ]; then remove_zfs_datasets fi + + elif [ "${FILE_EXT}" = ".tzst" ]; then + validate_archive + # Prepare the ZFS environment and restore from existing .tgz file + create_zfs_datasets + # Extract required files to the new datasets + info "\nExtracting 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 + validate_archive # Attempt to import a foreign/iocage container info "\nImporting '${TARGET_TRIM}' from foreign compressed ${FILE_EXT} archive." @@ -608,7 +640,9 @@ jail_import() { # Generate fstab and jail.conf files generate_config + elif [ "${FILE_EXT}" = ".tar.gz" ]; then + # Attempt to import a foreign/ezjail container # Prepare the ZFS environment and restore from existing .tar.gz file create_zfs_datasets @@ -622,12 +656,13 @@ jail_import() { else generate_config fi + elif [ "${FILE_EXT}" = ".tar" ]; then + # Attempt to import a foreign/qjail container # Prepare the ZFS environment and restore from existing .tar file create_zfs_datasets workout_components - # Extract required files to the new datasets info "\nExtracting files from '${TARGET}' archive..." tar -xf "${bastille_backupsdir}/${TARGET}" --strip-components "${CONF_TRIM}" -C "${bastille_jailsdir}/${TARGET_TRIM}" "${JAIL_CONF}" @@ -641,7 +676,9 @@ 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 validate_archive # Based on the file name, looks like we are importing a raw bastille image @@ -669,19 +706,31 @@ jail_import() { else # Import from standard supported archives on UFS systems if [ "${FILE_EXT}" = ".txz" ]; then + info "\nExtracting files from '${TARGET}' archive..." - tar -Jxf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}" + tar -xf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}" + elif [ "${FILE_EXT}" = ".tgz" ]; then + info "\nExtracting files from '${TARGET}' archive..." - tar -xf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}" + tar -xf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}" + + elif [ "${FILE_EXT}" = ".tzst" ]; then + + info "\nExtracting 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 "\nExtracting files from '${TARGET}' archive..." mkdir "${bastille_jailsdir}/${TARGET_TRIM}" tar -xf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}/${TARGET_TRIM}" mv "${bastille_jailsdir}/${TARGET_TRIM}/ezjail" "${bastille_jailsdir}/${TARGET_TRIM}/root" generate_config + elif [ "${FILE_EXT}" = ".tar" ]; then + # Attempt to import/configure foreign/qjail container info "\nExtracting files from '${TARGET}' archive..." mkdir -p "${bastille_jailsdir}/${TARGET_TRIM}/root" @@ -729,9 +778,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\}$\|_[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 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\}.zst$\|_[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\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.tzst$\|_[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]*.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]*//") + 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]*.zst//;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]*-[0-9]*.tzst//;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 "[ERROR]: Unrecognized archive name." @@ -754,4 +803,4 @@ fi if [ -n "${TARGET}" ]; then info "\nAttempting to import jail: ${TARGET_TRIM}..." jail_import -fi +fi \ No newline at end of file