1#!/bin/sh 2# 3# Copyright (c) 2018-2021, Christer Edwards <christer.edwards@gmail.com> 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 9# * Redistributions of source code must retain the above copyright notice, this 10# list of conditions and the following disclaimer. 11# 12# * Redistributions in binary form must reproduce the above copyright notice, 13# this list of conditions and the following disclaimer in the documentation 14# and/or other materials provided with the distribution. 15# 16# * Neither the name of the copyright holder nor the names of its 17# contributors may be used to endorse or promote products derived from 18# this software without specific prior written permission. 19# 20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31. /usr/local/share/bastille/common.sh 32. /usr/local/etc/bastille/bastille.conf 33 34usage() { 35 # Build an independent usage for the import command 36 # If no file/extension specified, will import from standard input 37 error_notify "Usage: bastille import [option(s)] FILE" 38 39 cat << EOF 40 Options: 41 42 -f | --force -- Force an archive import regardless if the checksum file does not match or missing. 43 -v | --verbose -- Be more verbose during the ZFS receive operation. 44 45Tip: If no option specified, container should be imported from standard input. 46 47EOF 48 exit 1 49} 50 51# Handle special-case commands first 52case "$1" in 53help|-h|--help) 54 usage 55 ;; 56esac 57 58if [ $# -gt 3 ] || [ $# -lt 1 ]; then 59 usage 60fi 61 62TARGET="${1}" 63OPT_FORCE= 64USER_IMPORT= 65OPT_ZRECV="-u" 66 67# Handle and parse option args 68while [ $# -gt 0 ]; do 69 case "${1}" in 70 -f|--force) 71 OPT_FORCE="1" 72 TARGET="${2}" 73 shift 74 ;; 75 -v|--verbose) 76 OPT_ZRECV="-u -v" 77 TARGET="${2}" 78 shift 79 ;; 80 -*|--*) 81 error_notify "Unknown Option." 82 usage 83 ;; 84 *) 85 if [ $# -gt 1 ] || [ $# -lt 1 ]; then 86 usage 87 fi 88 shift 89 ;; 90 esac 91done 92 93# Fallback to default if missing config parameters 94if [ -z "${bastille_decompress_xz_options}" ]; then 95 bastille_decompress_xz_options="-c -d -v" 96fi 97if [ -z "${bastille_decompress_gz_options}" ]; then 98 bastille_decompress_gz_options="-k -d -c -v" 99fi 100 101validate_archive() { 102 # Compare checksums on the target archive 103 # Skip validation for unsupported archive 104 if [ -f "${bastille_backupsdir}/${TARGET}" ]; then 105 if [ -f "${bastille_backupsdir}/${FILE_TRIM}.sha256" ]; then 106 info "Validating file: ${TARGET}..." 107 SHA256_DIST=$(cat "${bastille_backupsdir}/${FILE_TRIM}.sha256") 108 SHA256_FILE=$(sha256 -q "${bastille_backupsdir}/${TARGET}") 109 if [ "${SHA256_FILE}" != "${SHA256_DIST}" ]; then 110 error_exit "Failed validation for ${TARGET}." 111 else 112 info "File validation successful!" 113 fi 114 else 115 # Check if user opt to force import 116 if [ -n "${OPT_FORCE}" ]; then 117 warn "Warning: Skipping archive validation!" 118 else 119 error_exit "Checksum file not found. See 'bastille import [option(s)] FILE'." 120 fi 121 fi 122 fi 123} 124 125update_zfsmount() { 126 # Update the mountpoint property on the received ZFS data stream 127 OLD_ZFS_MOUNTPOINT=$(zfs get -H mountpoint "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}/root" | awk '{print $3}') 128 NEW_ZFS_MOUNTPOINT="${bastille_jailsdir}/${TARGET_TRIM}/root" 129 if [ "${NEW_ZFS_MOUNTPOINT}" != "${OLD_ZFS_MOUNTPOINT}" ]; then 130 info "Updating ZFS mountpoint..." 131 zfs set mountpoint="${bastille_jailsdir}/${TARGET_TRIM}/root" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}/root" 132 fi 133 134 # Mount new container ZFS datasets 135 if ! zfs mount | grep -qw "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}$"; then 136 zfs mount "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" 137 fi 138 if ! zfs mount | grep -qw "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}/root$"; then 139 zfs mount "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}/root" 140 fi 141} 142 143update_jailconf() { 144 # Update jail.conf paths 145 JAIL_CONFIG="${bastille_jailsdir}/${TARGET_TRIM}/jail.conf" 146 if [ -f "${JAIL_CONFIG}" ]; then 147 if ! grep -qw "path = ${bastille_jailsdir}/${TARGET_TRIM}/root;" "${JAIL_CONFIG}"; then 148 info "Updating jail.conf..." 149 sed -i '' "s|exec.consolelog.*=.*;|exec.consolelog = ${bastille_logsdir}/${TARGET_TRIM}_console.log;|" "${JAIL_CONFIG}" 150 sed -i '' "s|path.*=.*;|path = ${bastille_jailsdir}/${TARGET_TRIM}/root;|" "${JAIL_CONFIG}" 151 sed -i '' "s|mount.fstab.*=.*;|mount.fstab = ${bastille_jailsdir}/${TARGET_TRIM}/fstab;|" "${JAIL_CONFIG}" 152 fi 153 fi 154} 155 156update_fstab() { 157 # Update fstab .bastille mountpoint on thin containers only 158 # Set some variables 159 FSTAB_CONFIG="${bastille_jailsdir}/${TARGET_TRIM}/fstab" 160 FSTAB_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)' "${FSTAB_CONFIG}") 161 FSTAB_CURRENT=$(grep -w ".*/releases/.*/jails/${TARGET_TRIM}/root/.bastille" "${FSTAB_CONFIG}") 162 FSTAB_NEWCONF="${bastille_releasesdir}/${FSTAB_RELEASE} ${bastille_jailsdir}/${TARGET_TRIM}/root/.bastille nullfs ro 0 0" 163 if [ -n "${FSTAB_CURRENT}" ] && [ -n "${FSTAB_NEWCONF}" ]; then 164 # If both variables are set, compare and update as needed 165 if ! grep -qw "${bastille_releasesdir}/${FSTAB_RELEASE}.*${bastille_jailsdir}/${TARGET_TRIM}/root/.bastille" "${FSTAB_CONFIG}"; then 166 info "Updating fstab..." 167 sed -i '' "s|${FSTAB_CURRENT}|${FSTAB_NEWCONF}|" "${FSTAB_CONFIG}" 168 fi 169 fi 170} 171 172generate_config() { 173 # Attempt to read previous config file and set required variables accordingly 174 # If we can't get a valid interface, fallback to lo1 and warn user 175 info "Generating jail.conf..." 176 DEVFS_RULESET=4 177 178 if [ "${FILE_EXT}" = ".zip" ]; then 179 # Gather some bits from foreign/iocage config files 180 JSON_CONFIG="${bastille_jailsdir}/${TARGET_TRIM}/config.json" 181 if [ -n "${JSON_CONFIG}" ]; then 182 IPV4_CONFIG=$(grep -wo '\"ip4_addr\": \".*\"' "${JSON_CONFIG}" | tr -d '" ' | sed 's/ip4_addr://') 183 IPV6_CONFIG=$(grep -wo '\"ip6_addr\": \".*\"' "${JSON_CONFIG}" | tr -d '" ' | sed 's/ip6_addr://') 184 DEVFS_RULESET=$(grep -wo '\"devfs_ruleset\": \".*\"' "${JSON_CONFIG}" | tr -d '" ' | sed 's/devfs_ruleset://') 185 DEVFS_RULESET=${DEVFS_RULESET:-4} 186 fi 187 elif [ "${FILE_EXT}" = ".tar.gz" ]; then 188 # Gather some bits from foreign/ezjail config files 189 PROP_CONFIG="${bastille_jailsdir}/${TARGET_TRIM}/prop.ezjail-${FILE_TRIM}-*" 190 if [ -n "${PROP_CONFIG}" ]; then 191 IPVX_CONFIG=$(grep -wo "jail_${TARGET_TRIM}_ip=.*" ${PROP_CONFIG} | tr -d '" ' | sed "s/jail_${TARGET_TRIM}_ip=//") 192 fi 193 fi 194 195 # If there are multiple IP/NIC let the user configure network 196 if [ -n "${IPV4_CONFIG}" ]; then 197 if ! echo "${IPV4_CONFIG}" | grep -q '.*,.*'; then 198 NETIF_CONFIG=$(echo "${IPV4_CONFIG}" | grep '.*|' | sed 's/|.*//g') 199 if [ -z "${NETIF_CONFIG}" ]; then 200 config_netif 201 fi 202 IPX_ADDR="ip4.addr" 203 IP_CONFIG="${IPV4_CONFIG}" 204 IP6_MODE="disable" 205 fi 206 elif [ -n "${IPV6_CONFIG}" ]; then 207 if ! echo "${IPV6_CONFIG}" | grep -q '.*,.*'; then 208 NETIF_CONFIG=$(echo "${IPV6_CONFIG}" | grep '.*|' | sed 's/|.*//g') 209 if [ -z "${NETIF_CONFIG}" ]; then 210 config_netif 211 fi 212 IPX_ADDR="ip6.addr" 213 IP_CONFIG="${IPV6_CONFIG}" 214 IP6_MODE="new" 215 fi 216 elif [ -n "${IPVX_CONFIG}" ]; then 217 if ! echo "${IPVX_CONFIG}" | grep -q '.*,.*'; then 218 NETIF_CONFIG=$(echo "${IPVX_CONFIG}" | grep '.*|' | sed 's/|.*//g') 219 if [ -z "${NETIF_CONFIG}" ]; then 220 config_netif 221 fi 222 IPX_ADDR="ip4.addr" 223 IP_CONFIG="${IPVX_CONFIG}" 224 IP6_MODE="disable" 225 if echo "${IPVX_CONFIG}" | sed 's/.*|//' | grep -Eq '^(([a-fA-F0-9:]+$)|([a-fA-F0-9:]+\/[0-9]{1,3}$))'; then 226 IPX_ADDR="ip6.addr" 227 IP6_MODE="new" 228 fi 229 fi 230 fi 231 232 # Let the user configure network manually 233 if [ -z "${NETIF_CONFIG}" ]; then 234 NETIF_CONFIG="lo1" 235 IPX_ADDR="ip4.addr" 236 IP_CONFIG="-" 237 IP6_MODE="disable" 238 warn "Warning: See 'bastille edit ${TARGET_TRIM} jail.conf' for manual network configuration." 239 fi 240 241 if [ "${FILE_EXT}" = ".tar.gz" ]; then 242 CONFIG_RELEASE=$(echo ${PROP_CONFIG} | grep -o '[0-9]\{2\}\.[0-9]_RELEASE' | sed 's/_/-/g') 243 if [ -z "${CONFIG_RELEASE}" ]; then 244 # Fallback to host version 245 CONFIG_RELEASE=$(freebsd-version | sed 's/\-[pP].*//') 246 warn "Warning: ${CONFIG_RELEASE} was set by default!" 247 fi 248 mkdir "${bastille_jailsdir}/${TARGET_TRIM}/root/.bastille" 249 echo "${bastille_releasesdir}/${CONFIG_RELEASE} ${bastille_jailsdir}/${TARGET_TRIM}/root/.bastille nullfs ro 0 0" \ 250 >> "${bastille_jailsdir}/${TARGET_TRIM}/fstab" 251 252 # Work with the symlinks 253 cd "${bastille_jailsdir}/${TARGET_TRIM}/root" 254 update_symlinks 255 else 256 # Generate new empty fstab file 257 touch "${bastille_jailsdir}/${TARGET_TRIM}/fstab" 258 fi 259 260 # Generate a basic jail configuration file on foreign imports 261 cat << EOF > "${bastille_jailsdir}/${TARGET_TRIM}/jail.conf" 262${TARGET_TRIM} { 263 devfs_ruleset = ${DEVFS_RULESET}; 264 enforce_statfs = 2; 265 exec.clean; 266 exec.consolelog = ${bastille_logsdir}/${TARGET_TRIM}_console.log; 267 exec.start = '/bin/sh /etc/rc'; 268 exec.stop = '/bin/sh /etc/rc.shutdown'; 269 host.hostname = ${TARGET_TRIM}; 270 mount.devfs; 271 mount.fstab = ${bastille_jailsdir}/${TARGET_TRIM}/fstab; 272 path = ${bastille_jailsdir}/${TARGET_TRIM}/root; 273 securelevel = 2; 274 275 interface = ${NETIF_CONFIG}; 276 ${IPX_ADDR} = ${IP_CONFIG}; 277 ip6 = ${IP6_MODE}; 278} 279EOF 280} 281 282update_config() { 283 # Update an existing jail configuration 284 # The config on select archives does not provide a clear way to determine 285 # the base release, so lets try to get it from the base/COPYRIGHT file, 286 # otherwise warn user and fallback to host system release 287 CONFIG_RELEASE=$(grep -wo 'releng/[0-9]\{2\}.[0-9]/COPYRIGHT' "${bastille_jailsdir}/${TARGET_TRIM}/root/COPYRIGHT" | sed 's|releng/||;s|/COPYRIGHT|-RELEASE|') 288 if [ -z "${CONFIG_RELEASE}" ]; then 289 # Fallback to host version 290 CONFIG_RELEASE=$(freebsd-version | sed 's/\-[pP].*//') 291 warn "Warning: ${CONFIG_RELEASE} was set by default!" 292 fi 293 mkdir "${bastille_jailsdir}/${TARGET_TRIM}/root/.bastille" 294 echo "${bastille_releasesdir}/${CONFIG_RELEASE} ${bastille_jailsdir}/${TARGET_TRIM}/root/.bastille nullfs ro 0 0" \ 295 >> "${bastille_jailsdir}/${TARGET_TRIM}/fstab" 296 297 # Work with the symlinks 298 cd "${bastille_jailsdir}/${TARGET_TRIM}/root" 299 update_symlinks 300} 301 302workout_components() { 303 if [ "${FILE_EXT}" = ".tar" ]; then 304 # Workaround to determine the tarball path/components before extract(assumes path/jails/target) 305 JAIL_PATH=$(tar -tvf ${bastille_backupsdir}/${TARGET} | grep -wo "/.*/jails/${TARGET_TRIM}" | tail -n1) 306 JAIL_DIRS=$(echo ${JAIL_PATH} | grep -o '/' | wc -l) 307 DIRS_PLUS=$(expr ${JAIL_DIRS} + 1) 308 309 # Workaround to determine the jail.conf path before extract(assumes path/qjail.config/target) 310 JAIL_CONF=$(tar -tvf ${bastille_backupsdir}/${TARGET} | grep -wo "/.*/qjail.config/${TARGET_TRIM}") 311 CONF_TRIM=$(echo ${JAIL_CONF} | grep -o '/' | wc -l) 312 fi 313} 314 315config_netif() { 316 # Get interface from bastille configuration 317 if [ -n "${bastille_network_loopback}" ]; then 318 NETIF_CONFIG="${bastille_network_loopback}" 319 elif [ -n "${bastille_network_shared}" ]; then 320 NETIF_CONFIG="${bastille_network_shared}" 321 else 322 NETIF_CONFIG= 323 fi 324} 325 326update_symlinks() { 327 # Work with the symlinks 328 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" 329 330 # Just warn user to bootstrap the release if missing 331 if [ ! -d "${bastille_releasesdir}/${CONFIG_RELEASE}" ]; then 332 warn "Warning: ${CONFIG_RELEASE} must be bootstrapped. See 'bastille bootstrap'." 333 fi 334 335 # Update old symlinks 336 info "Updating symlinks..." 337 for _link in ${SYMLINKS}; do 338 if [ -L "${_link}" ]; then 339 ln -sf /.bastille/${_link} ${_link} 340 fi 341 done 342} 343 344create_zfs_datasets() { 345 # Prepare the ZFS environment and restore from file 346 info "Importing '${TARGET_TRIM}' from foreign compressed ${FILE_EXT} archive." 347 info "Preparing ZFS environment..." 348 349 # Create required ZFS datasets, mountpoint inherited from system 350 zfs create ${bastille_zfs_options} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" 351 zfs create ${bastille_zfs_options} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}/root" 352} 353 354remove_zfs_datasets() { 355 # Perform cleanup on failure 356 zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}/root" 357 zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" 358 error_exit "Failed to extract files from '${TARGET}' archive." 359} 360 361jail_import() { 362 # Attempt to import container from file 363 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') 364 FILE_EXT=$(echo "${TARGET}" | sed "s/${FILE_TRIM}//g") 365 if [ -d "${bastille_jailsdir}" ]; then 366 if [ "${bastille_zfs_enable}" = "YES" ]; then 367 if [ -n "${bastille_zfs_zpool}" ]; then 368 if [ "${FILE_EXT}" = ".xz" ]; then 369 validate_archive 370 # Import from compressed xz on ZFS systems 371 info "Importing '${TARGET_TRIM}' from compressed ${FILE_EXT} image." 372 info "Receiving ZFS data stream..." 373 xz ${bastille_decompress_xz_options} "${bastille_backupsdir}/${TARGET}" | \ 374 zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" 375 376 # Update ZFS mountpoint property if required 377 update_zfsmount 378 elif [ "${FILE_EXT}" = ".gz" ]; then 379 validate_archive 380 # Import from compressed xz on ZFS systems 381 info "Importing '${TARGET_TRIM}' from compressed ${FILE_EXT} image." 382 info "Receiving ZFS data stream..." 383 gzip ${bastille_decompress_gz_options} "${bastille_backupsdir}/${TARGET}" | \ 384 zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" 385 386 # Update ZFS mountpoint property if required 387 update_zfsmount 388 389 elif [ "${FILE_EXT}" = ".txz" ]; then 390 validate_archive 391 # Prepare the ZFS environment and restore from existing .txz file 392 create_zfs_datasets 393 394 # Extract required files to the new datasets 395 info "Extracting files from '${TARGET}' archive..." 396 tar --exclude='root' -Jxf "${bastille_backupsdir}/${TARGET}" --strip-components 1 -C "${bastille_jailsdir}/${TARGET_TRIM}" 397 tar -Jxf "${bastille_backupsdir}/${TARGET}" --strip-components 2 -C "${bastille_jailsdir}/${TARGET_TRIM}/root" "${TARGET_TRIM}/root" 398 if [ "$?" -ne 0 ]; then 399 remove_zfs_datasets 400 fi 401 elif [ "${FILE_EXT}" = ".tgz" ]; then 402 validate_archive 403 # Prepare the ZFS environment and restore from existing .tgz file 404 create_zfs_datasets 405 406 # Extract required files to the new datasets 407 info "Extracting files from '${TARGET}' archive..." 408 tar --exclude='root' -xf "${bastille_backupsdir}/${TARGET}" --strip-components 1 -C "${bastille_jailsdir}/${TARGET_TRIM}" 409 tar -xf "${bastille_backupsdir}/${TARGET}" --strip-components 2 -C "${bastille_jailsdir}/${TARGET_TRIM}/root" "${TARGET_TRIM}/root" 410 if [ "$?" -ne 0 ]; then 411 remove_zfs_datasets 412 fi 413 elif [ "${FILE_EXT}" = ".zip" ]; then 414 validate_archive 415 # Attempt to import a foreign/iocage container 416 info "Importing '${TARGET_TRIM}' from foreign compressed ${FILE_EXT} archive." 417 # Sane bastille ZFS options 418 ZFS_OPTIONS=$(echo ${bastille_zfs_options} | sed 's/-o//g') 419 420 # Extract required files from the zip archive 421 cd "${bastille_backupsdir}" && unzip -j "${TARGET}" 422 if [ "$?" -ne 0 ]; then 423 error_exit "Failed to extract files from '${TARGET}' archive." 424 rm -f "${FILE_TRIM}" "${FILE_TRIM}_root" 425 fi 426 info "Receiving ZFS data stream..." 427 zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" < "${FILE_TRIM}" 428 zfs set ${ZFS_OPTIONS} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" 429 zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}/root" < "${FILE_TRIM}_root" 430 431 # Update ZFS mountpoint property if required 432 update_zfsmount 433 434 # Keep old configuration files for user reference 435 if [ -f "${bastille_jailsdir}/${TARGET_TRIM}/fstab" ]; then 436 mv "${bastille_jailsdir}/${TARGET_TRIM}/fstab" "${bastille_jailsdir}/${TARGET_TRIM}/fstab.old" 437 fi 438 439 # Cleanup unwanted files 440 rm -f "${FILE_TRIM}" "${FILE_TRIM}_root" 441 442 # Generate fstab and jail.conf files 443 generate_config 444 elif [ "${FILE_EXT}" = ".tar.gz" ]; then 445 # Attempt to import a foreign/ezjail container 446 # Prepare the ZFS environment and restore from existing .tar.gz file 447 create_zfs_datasets 448 449 # Extract required files to the new datasets 450 info "Extracting files from '${TARGET}' archive..." 451 tar --exclude='ezjail/' -xf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}/${TARGET_TRIM}" 452 tar -xf "${bastille_backupsdir}/${TARGET}" --strip-components 1 -C "${bastille_jailsdir}/${TARGET_TRIM}/root" 453 if [ "$?" -ne 0 ]; then 454 remove_zfs_datasets 455 else 456 generate_config 457 fi 458 elif [ "${FILE_EXT}" = ".tar" ]; then 459 # Attempt to import a foreign/qjail container 460 # Prepare the ZFS environment and restore from existing .tar file 461 create_zfs_datasets 462 workout_components 463 464 # Extract required files to the new datasets 465 info "Extracting files from '${TARGET}' archive..." 466 tar -xf "${bastille_backupsdir}/${TARGET}" --strip-components "${CONF_TRIM}" -C "${bastille_jailsdir}/${TARGET_TRIM}" "${JAIL_CONF}" 467 tar -xf "${bastille_backupsdir}/${TARGET}" --strip-components "${DIRS_PLUS}" -C "${bastille_jailsdir}/${TARGET_TRIM}/root" "${JAIL_PATH}" 468 if [ -f "${bastille_jailsdir}/${TARGET_TRIM}/${TARGET_TRIM}" ]; then 469 mv "${bastille_jailsdir}/${TARGET_TRIM}/${TARGET_TRIM}" "${bastille_jailsdir}/${TARGET_TRIM}/jail.conf" 470 fi 471 472 if [ "$?" -ne 0 ]; then 473 remove_zfs_datasets 474 else 475 update_config 476 fi 477 elif [ -z "${FILE_EXT}" ]; then 478 if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$'; then 479 validate_archive 480 # Based on the file name, looks like we are importing a raw bastille image 481 # Import from uncompressed image file 482 info "Importing '${TARGET_TRIM}' from uncompressed image archive." 483 info "Receiving ZFS data stream..." 484 zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" < "${bastille_backupsdir}/${TARGET}" 485 486 # Update ZFS mountpoint property if required 487 update_zfsmount 488 else 489 # Based on the file name, looks like we are importing from previous redirected bastille image 490 # Quietly import from previous redirected bastille image 491 if ! zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}"; then 492 exit 1 493 else 494 # Update ZFS mountpoint property if required 495 update_zfsmount 496 fi 497 fi 498 else 499 error_exit "Unknown archive format." 500 fi 501 fi 502 else 503 # Import from standard supported archives on UFS systems 504 if [ "${FILE_EXT}" = ".txz" ]; then 505 info "Extracting files from '${TARGET}' archive..." 506 tar -Jxf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}" 507 elif [ "${FILE_EXT}" = ".tgz" ]; then 508 info "Extracting files from '${TARGET}' archive..." 509 tar -xf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}" 510 elif [ "${FILE_EXT}" = ".tar.gz" ]; then 511 # Attempt to import/configure foreign/ezjail container 512 info "Extracting files from '${TARGET}' archive..." 513 mkdir "${bastille_jailsdir}/${TARGET_TRIM}" 514 tar -xf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}/${TARGET_TRIM}" 515 mv "${bastille_jailsdir}/${TARGET_TRIM}/ezjail" "${bastille_jailsdir}/${TARGET_TRIM}/root" 516 generate_config 517 elif [ "${FILE_EXT}" = ".tar" ]; then 518 # Attempt to import/configure foreign/qjail container 519 info "Extracting files from '${TARGET}' archive..." 520 mkdir -p "${bastille_jailsdir}/${TARGET_TRIM}/root" 521 workout_components 522 tar -xf "${bastille_backupsdir}/${TARGET}" --strip-components "${CONF_TRIM}" -C "${bastille_jailsdir}/${TARGET_TRIM}" "${JAIL_CONF}" 523 tar -xf "${bastille_backupsdir}/${TARGET}" --strip-components "${DIRS_PLUS}" -C "${bastille_jailsdir}/${TARGET_TRIM}/root" "${JAIL_PATH}" 524 if [ -f "${bastille_jailsdir}/${TARGET_TRIM}/${TARGET_TRIM}" ]; then 525 mv "${bastille_jailsdir}/${TARGET_TRIM}/${TARGET_TRIM}" "${bastille_jailsdir}/${TARGET_TRIM}/jail.conf" 526 fi 527 update_config 528 else 529 error_exit "Unsupported archive format." 530 fi 531 fi 532 533 if [ "$?" -ne 0 ]; then 534 error_exit "Failed to import from '${TARGET}' archive." 535 else 536 # Update the jail.conf and fstab if required 537 # This is required on foreign imports only 538 update_jailconf 539 update_fstab 540 if [ -z "${USER_IMPORT}" ]; then 541 info "Container '${TARGET_TRIM}' imported successfully." 542 fi 543 exit 0 544 fi 545 else 546 error_exit "Jails directory/dataset does not exist. See 'bastille bootstrap'." 547 fi 548} 549 550# Check for user specified file location 551if echo "${TARGET}" | grep -q '\/'; then 552 GETDIR="${TARGET}" 553 TARGET=$(echo ${TARGET} | awk -F '\/' '{print $NF}') 554 bastille_backupsdir=$(echo ${GETDIR} | sed "s/${TARGET}//") 555fi 556 557# Check if backups directory/dataset exist 558if [ ! -d "${bastille_backupsdir}" ]; then 559 error_exit "Backups directory/dataset does not exist. See 'bastille bootstrap'." 560fi 561 562# Check if archive exist then trim archive name 563if [ -f "${bastille_backupsdir}/${TARGET}" ]; then 564 # Filter unsupported/unknown archives 565 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 566 if ls "${bastille_backupsdir}" | awk "/^${TARGET}$/" >/dev/null; then 567 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]*//") 568 fi 569 else 570 error_exit "Unrecognized archive name." 571 fi 572else 573 if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.*$'; then 574 error_exit "Archive '${TARGET}' not found." 575 else 576 # Assume user will import from standard input 577 TARGET_TRIM=${TARGET} 578 USER_IMPORT="1" 579 fi 580fi 581 582# Check if a running jail matches name or already exist 583if [ -n "$(/usr/sbin/jls name | awk "/^${TARGET_TRIM}$/")" ]; then 584 error_exit "A running jail matches name." 585elif [ -n "${TARGET_TRIM}" ]; then 586 if [ -d "${bastille_jailsdir}/${TARGET_TRIM}" ]; then 587 error_exit "Container: ${TARGET_TRIM} already exists." 588 fi 589fi 590 591if [ -n "${TARGET}" ]; then 592 jail_import 593fi 594