#!@SHELL@ # # zfs-import This script will import/export zfs pools. # # chkconfig: 2345 01 99 # description: This script will import/export zfs pools during system # boot/shutdown. # It is also responsible for all userspace zfs services. # probe: true # ### BEGIN INIT INFO # Provides: zfs-import # Required-Start: mtab # Required-Stop: $local_fs mtab # Default-Start: S # Default-Stop: 0 1 6 # X-Start-Before: checkfs # X-Stop-After: zfs-mount # Short-Description: Import ZFS pools # Description: Run the `zpool import` or `zpool export` commands. ### END INIT INFO # # NOTE: Not having '$local_fs' on Required-Start but only on Required-Stop # is on purpose. If we have '$local_fs' in both (and X-Start-Before=checkfs) # we get conflicts - import needs to be started extremely early, # but not stopped too late. # # Released under the 2-clause BSD license. # # The original script that acted as a template for this script came from # the Debian GNU/Linux kFreeBSD ZFS packages (which did not include a # licensing stansa) in the commit dated Mar 24, 2011: # https://github.com/zfsonlinux/pkg-zfs/commit/80a3ae582b59c0250d7912ba794dca9e669e605a # Source the common init script . @sysconfdir@/zfs/zfs-functions # ---------------------------------------------------- do_depend() { after sysfs udev keyword -lxc -openvz -prefix -vserver } # Support function to get a list of all pools, separated with ';' find_pools() { local CMD="$*" local pools pools=$($CMD 2> /dev/null | \ grep -E "pool:|^[a-zA-Z0-9]" | \ sed 's@.*: @@' | \ sort | \ while read pool; do \ echo -n "$pool;" done) echo "${pools%%;}" # Return without the last ';'. } # Import all pools do_import() { local already_imported available_pools pool npools local exception dir ZPOOL_IMPORT_PATH RET=0 r=1 # In case not shutdown cleanly. [ -n "$init" ] && rm -f /etc/dfs/sharetab # Just simplify code later on. if [ -n "$USE_DISK_BY_ID" -a "$USE_DISK_BY_ID" != 'yes' ] then # It's something, but not 'yes' so it's no good to us. unset USE_DISK_BY_ID fi # Find list of already imported pools. already_imported=$(find_pools "$ZPOOL" list -H -oname) available_pools=$(find_pools "$ZPOOL" import) # Just in case - seen it happen (that a pool isn't visable/found # with a simple "zpool import" but only when using the "-d" # option or setting ZPOOL_IMPORT_PATH). if [ -d "/dev/disk/by-id" ] then npools=$(find_pools "$ZPOOL" import -d /dev/disk/by-id) if [ -n "$npools" ] then # Because we have found extra pool(s) here, which wasn't # found 'normaly', we need to force USE_DISK_BY_ID to # make sure we're able to actually import it/them later. USE_DISK_BY_ID='yes' if [ -n "$available_pools" ] then # Filter out duplicates (pools found with the simpl # "zpool import" but which is also found with the # "zpool import -d ..."). npools=$(echo "$npools" | sed "s,$available_pools,,") # Add the list to the existing list of # available pools available_pools="$available_pools;$npools" else available_pools="$npools" fi fi fi # Filter out any exceptions... if [ -n "$ZFS_POOL_EXCEPTIONS" ] then local found="" local apools="" OLD_IFS="$IFS" ; IFS=";" for pool in $available_pools do for exception in $ZFS_POOL_EXCEPTIONS do [ "$pool" = "$exception" ] && continue 2 found="$pool" done if [ -n "$found" ] then if [ -n "$apools" ] then apools="$apools;$pool" else apools="$pool" fi fi done IFS="$OLD_IFS" available_pools="$apools" fi # For backwards compability, make sure that ZPOOL_IMPORT_PATH is set # to something we can use later with the real import(s). We want to # make sure we find all by* dirs, BUT by-vdev should be first (if it # exists). if [ -n "$USE_DISK_BY_ID" -a -z "$ZPOOL_IMPORT_PATH" ] then local dirs dirs="$(for dir in $(echo /dev/disk/by-*) do # Ignore by-vdev here - we wan't it first! echo "$dir" | grep -q /by-vdev && continue [ ! -d "$dir" ] && continue echo -n "$dir:" done | sed 's,:$,,g')" if [ -d "/dev/disk/by-vdev" ] then # Add by-vdev at the beginning. ZPOOL_IMPORT_PATH="/dev/disk/by-vdev:" fi # Help with getting LUKS partitions etc imported. if [ -d "/dev/mapper" ]; then if [ -n "$ZPOOL_IMPORT_PATH" ]; then ZPOOL_IMPORT_PATH="$ZPOOL_IMPORT_PATH:/dev/mapper:" else ZPOOL_IMPORT_PATH="/dev/mapper:" fi fi # ... and /dev at the very end, just for good measure. ZPOOL_IMPORT_PATH="$ZPOOL_IMPORT_PATH$dirs:/dev" fi # Needs to be exported for "zpool" to catch it. [ -n "$ZPOOL_IMPORT_PATH" ] && export ZPOOL_IMPORT_PATH # Mount all availible pools (except those set in ZFS_POOL_EXCEPTIONS. # # If not interactive (run from init - variable init='/sbin/init') # we get ONE line for all pools being imported, with just a dot # as status for each pool. # Example: Importing ZFS pool(s)... [OK] # # If it IS interactive (started from the shell manually), then we # get one line per pool importing. # Example: Importing ZFS pool pool1 [OK] # Importing ZFS pool pool2 [OK] # [etc] [ -n "$init" ] && zfs_log_begin_msg "Importing ZFS pool(s)" OLD_IFS="$IFS" ; IFS=";" for pool in $available_pools do [ -z "$pool" ] && continue # We have pools that haven't been imported - import them if [ -n "$init" ] then # Not interactive - a dot for each pool. # Except on Gentoo where this doesn't work. zfs_log_progress_msg "." else # Interactive - one 'Importing ...' line per pool zfs_log_begin_msg "Importing ZFS pool $pool" fi # Import by using ZPOOL_IMPORT_PATH (either set above or in # the config file) _or_ with the 'built in' default search # paths. This is the prefered way. "$ZPOOL" import -N ${ZPOOL_IMPORT_OPTS} "$pool" 2> /dev/null r="$?" ; RET=$((RET + r)) if [ "$r" -eq 0 ] then # Output success and process the next pool [ -z "$init" ] && zfs_log_end_msg 0 continue fi # We don't want a fail msg here, we're going to try import # using the cache file soon and that might succeed. [ ! -f "$ZPOOL_CACHE" ] && zfs_log_end_msg "$RET" if [ "$r" -gt 0 -a -f "$ZPOOL_CACHE" ] then # Failed to import without a cache file. Try WITH... if [ -z "$init" ] && check_boolean "$VERBOSE_MOUNT" then # Interactive + Verbose = more information zfs_log_progress_msg " using cache file" fi "$ZPOOL" import -c "$ZPOOL_CACHE" -N ${ZPOOL_IMPORT_OPTS} \ "$pool" 2> /dev/null r="$?" ; RET=$((RET + r)) if [ "$r" -eq 0 ] then [ -z "$init" ] && zfs_log_end_msg 0 continue 3 # Next pool fi zfs_log_end_msg "$RET" fi done [ -n "$init" ] && zfs_log_end_msg "$RET" IFS="$OLD_IFS" [ -n "$already_imported" -a -z "$available_pools" ] && return 0 return "$RET" } # Export all pools do_export() { local already_imported pool root_pool RET r RET=0 root_pool=$(get_root_pool) [ -n "$init" ] && zfs_log_begin_msg "Exporting ZFS pool(s)" # Find list of already imported pools. already_imported=$(find_pools "$ZPOOL" list -H -oname) OLD_IFS="$IFS" ; IFS=";" for pool in $already_imported; do [ "$pool" = "$root_pool" ] && continue if [ -z "$init" ] then # Interactive - one 'Importing ...' line per pool zfs_log_begin_msg "Exporting ZFS pool $pool" else # Not interactive - a dot for each pool. zfs_log_progress_msg "." fi "$ZPOOL" export "$pool" r="$?" ; RET=$((RET + r)) [ -z "$init" ] && zfs_log_end_msg "$r" done IFS="$OLD_IFS" [ -n "$init" ] && zfs_log_end_msg "$RET" return "$RET" } # Output the status and list of pools do_status() { check_module_loaded "zfs" || exit 0 "$ZPOOL" status && echo "" && "$ZPOOL" list } do_start() { if check_boolean "$VERBOSE_MOUNT" then zfs_log_begin_msg "Checking if ZFS userspace tools present" fi if checksystem then check_boolean "$VERBOSE_MOUNT" && zfs_log_end_msg 0 check_boolean "$VERBOSE_MOUNT" && \ zfs_log_begin_msg "Loading kernel ZFS infrastructure" if ! load_module "zfs" then check_boolean "$VERBOSE_MOUNT" && zfs_log_end_msg 1 return 5 fi check_boolean "$VERBOSE_MOUNT" && zfs_log_end_msg 0 do_import && udev_trigger # just to make sure we get zvols. return 0 else return 1 fi } do_stop() { # Check to see if the module is even loaded. check_module_loaded "zfs" || exit 0 do_export } # ---------------------------------------------------- if [ ! -e /etc/gentoo-release ] then case "$1" in start) do_start ;; stop) do_stop ;; status) do_status ;; force-reload|condrestart|reload|restart) # no-op ;; *) [ -n "$1" ] && echo "Error: Unknown command $1." echo "Usage: $0 {start|stop|status}" exit 3 ;; esac exit $? else # Create wrapper functions since Gentoo don't use the case part. depend() { do_depend; } start() { do_start; } stop() { do_stop; } status() { do_status; } fi