1#!@DEFAULT_INIT_SHELL@ 2# SPDX-License-Identifier: BSD-2-Clause 3# shellcheck disable=SC2154 4# 5# zfs-import This script will import ZFS pools 6# 7# chkconfig: 2345 01 99 8# description: This script will perform a verbatim import of ZFS pools 9# during system boot. 10# probe: true 11# 12### BEGIN INIT INFO 13# Provides: zfs-import 14# Required-Start: mtab 15# Required-Stop: $local_fs mtab 16# Default-Start: S 17# Default-Stop: 0 1 6 18# X-Start-Before: checkfs 19# X-Stop-After: zfs-mount 20# Short-Description: Import ZFS pools 21# Description: Run the `zpool import` command. 22### END INIT INFO 23# 24# NOTE: Not having '$local_fs' on Required-Start but only on Required-Stop 25# is on purpose. If we have '$local_fs' in both (and X-Start-Before=checkfs) 26# we get conflicts - import needs to be started extremely early, 27# but not stopped too late. 28# 29# Released under the 2-clause BSD license. 30# 31# This script is based on debian/zfsutils.zfs.init from the 32# Debian GNU/kFreeBSD zfsutils 8.1-3 package, written by Aurelien Jarno. 33 34# Source the common init script 35. @sysconfdir@/zfs/zfs-functions 36 37# ---------------------------------------------------- 38 39do_depend() 40{ 41 before swap 42 after sysfs udev 43 keyword -lxc -openvz -prefix -vserver 44} 45 46# Use the zpool cache file to import pools 47do_verbatim_import() 48{ 49 if [ -f "$ZPOOL_CACHE" ] 50 then 51 zfs_action "Importing ZFS pool(s)" \ 52 "$ZPOOL" import -c "$ZPOOL_CACHE" -N -a 53 fi 54} 55 56# Support function to get a list of all pools, separated with ';' 57find_pools() 58{ 59 local pools 60 61 pools=$("$@" 2> /dev/null | \ 62 sed -Ee '/pool:|^[a-zA-Z0-9]/!d' -e 's@.*: @@' | \ 63 sort | \ 64 tr '\n' ';') 65 66 echo "${pools%%;}" # Return without the last ';'. 67} 68 69# Find and import all visible pools, even exported ones 70do_import_all_visible() 71{ 72 local already_imported available_pools pool npools 73 local exception dir ZPOOL_IMPORT_PATH RET=0 r=1 74 75 # In case not shutdown cleanly. 76 # shellcheck disable=SC2154 77 [ -n "$init" ] && rm -f /etc/dfs/sharetab 78 79 # Just simplify code later on. 80 if [ -n "$USE_DISK_BY_ID" ] && [ "$USE_DISK_BY_ID" != 'yes' ] 81 then 82 # It's something, but not 'yes' so it's no good to us. 83 unset USE_DISK_BY_ID 84 fi 85 86 # Find list of already imported pools. 87 already_imported=$(find_pools "$ZPOOL" list -H -oname) 88 available_pools=$(find_pools "$ZPOOL" import) 89 90 # Just in case - seen it happen (that a pool isn't visible/found 91 # with a simple "zpool import" but only when using the "-d" 92 # option or setting ZPOOL_IMPORT_PATH). 93 if [ -d "/dev/disk/by-id" ] 94 then 95 npools=$(find_pools "$ZPOOL" import -d /dev/disk/by-id) 96 if [ -n "$npools" ] 97 then 98 # Because we have found extra pool(s) here, which wasn't 99 # found 'normally', we need to force USE_DISK_BY_ID to 100 # make sure we're able to actually import it/them later. 101 USE_DISK_BY_ID='yes' 102 103 if [ -n "$available_pools" ] 104 then 105 # Filter out duplicates (pools found with the simpl 106 # "zpool import" but which is also found with the 107 # "zpool import -d ..."). 108 npools=$(echo "$npools" | sed "s,$available_pools,,") 109 110 # Add the list to the existing list of 111 # available pools 112 available_pools="$available_pools;$npools" 113 else 114 available_pools="$npools" 115 fi 116 fi 117 fi 118 119 # Filter out any exceptions... 120 if [ -n "$ZFS_POOL_EXCEPTIONS" ] 121 then 122 local found="" 123 local apools="" 124 OLD_IFS="$IFS" ; IFS=";" 125 126 for pool in $available_pools 127 do 128 for exception in $ZFS_POOL_EXCEPTIONS 129 do 130 [ "$pool" = "$exception" ] && continue 2 131 found="$pool" 132 done 133 134 if [ -n "$found" ] 135 then 136 if [ -n "$apools" ] 137 then 138 apools="$apools;$pool" 139 else 140 apools="$pool" 141 fi 142 fi 143 done 144 145 IFS="$OLD_IFS" 146 available_pools="$apools" 147 fi 148 149 # For backwards compatibility, make sure that ZPOOL_IMPORT_PATH is set 150 # to something we can use later with the real import(s). We want to 151 # make sure we find all by* dirs, BUT by-vdev should be first (if it 152 # exists). 153 if [ -n "$USE_DISK_BY_ID" ] && [ -z "$ZPOOL_IMPORT_PATH" ] 154 then 155 local dirs 156 dirs="$(for dir in $(echo /dev/disk/by-*) 157 do 158 # Ignore by-vdev here - we want it first! 159 echo "$dir" | grep -q /by-vdev && continue 160 [ ! -d "$dir" ] && continue 161 162 printf "%s" "$dir:" 163 done | sed 's,:$,,g')" 164 165 if [ -d "/dev/disk/by-vdev" ] 166 then 167 # Add by-vdev at the beginning. 168 ZPOOL_IMPORT_PATH="/dev/disk/by-vdev:" 169 fi 170 171 # Help with getting LUKS partitions etc imported. 172 if [ -d "/dev/mapper" ]; then 173 if [ -n "$ZPOOL_IMPORT_PATH" ]; then 174 ZPOOL_IMPORT_PATH="$ZPOOL_IMPORT_PATH:/dev/mapper:" 175 else 176 ZPOOL_IMPORT_PATH="/dev/mapper:" 177 fi 178 fi 179 180 # ... and /dev at the very end, just for good measure. 181 ZPOOL_IMPORT_PATH="$ZPOOL_IMPORT_PATH$dirs:/dev" 182 fi 183 184 # Needs to be exported for "zpool" to catch it. 185 [ -n "$ZPOOL_IMPORT_PATH" ] && export ZPOOL_IMPORT_PATH 186 187 # Mount all available pools (except those set in ZFS_POOL_EXCEPTIONS. 188 # 189 # If not interactive (run from init - variable init='/sbin/init') 190 # we get ONE line for all pools being imported, with just a dot 191 # as status for each pool. 192 # Example: Importing ZFS pool(s)... [OK] 193 # 194 # If it IS interactive (started from the shell manually), then we 195 # get one line per pool importing. 196 # Example: Importing ZFS pool pool1 [OK] 197 # Importing ZFS pool pool2 [OK] 198 # [etc] 199 [ -n "$init" ] && zfs_log_begin_msg "Importing ZFS pool(s)" 200 OLD_IFS="$IFS" ; IFS=";" 201 for pool in $available_pools 202 do 203 [ -z "$pool" ] && continue 204 205 # We have pools that haven't been imported - import them 206 if [ -n "$init" ] 207 then 208 # Not interactive - a dot for each pool. 209 # Except on Gentoo where this doesn't work. 210 zfs_log_progress_msg "." 211 else 212 # Interactive - one 'Importing ...' line per pool 213 zfs_log_begin_msg "Importing ZFS pool $pool" 214 fi 215 216 # Import by using ZPOOL_IMPORT_PATH (either set above or in 217 # the config file) _or_ with the 'built in' default search 218 # paths. This is the preferred way. 219 # shellcheck disable=SC2086 220 "$ZPOOL" import -N ${ZPOOL_IMPORT_OPTS} "$pool" 2> /dev/null 221 r="$?" ; RET=$((RET + r)) 222 if [ "$r" -eq 0 ] 223 then 224 # Output success and process the next pool 225 [ -z "$init" ] && zfs_log_end_msg 0 226 continue 227 fi 228 # We don't want a fail msg here, we're going to try import 229 # using the cache file soon and that might succeed. 230 [ ! -f "$ZPOOL_CACHE" ] && zfs_log_end_msg "$RET" 231 232 if [ "$r" -gt 0 ] && [ -f "$ZPOOL_CACHE" ] 233 then 234 # Failed to import without a cache file. Try WITH... 235 if [ -z "$init" ] && check_boolean "$VERBOSE_MOUNT" 236 then 237 # Interactive + Verbose = more information 238 zfs_log_progress_msg " using cache file" 239 fi 240 241 # shellcheck disable=SC2086 242 "$ZPOOL" import -c "$ZPOOL_CACHE" -N ${ZPOOL_IMPORT_OPTS} \ 243 "$pool" 2> /dev/null 244 r="$?" ; RET=$((RET + r)) 245 if [ "$r" -eq 0 ] 246 then 247 [ -z "$init" ] && zfs_log_end_msg 0 248 continue 3 # Next pool 249 fi 250 zfs_log_end_msg "$RET" 251 fi 252 done 253 [ -n "$init" ] && zfs_log_end_msg "$RET" 254 255 IFS="$OLD_IFS" 256 [ -n "$already_imported" ] && [ -z "$available_pools" ] && return 0 257 258 return "$RET" 259} 260 261do_import() 262{ 263 if check_boolean "$ZPOOL_IMPORT_ALL_VISIBLE" 264 then 265 do_import_all_visible 266 else 267 # This is the default option 268 do_verbatim_import 269 fi 270} 271 272# Output the status and list of pools 273do_status() 274{ 275 check_module_loaded "zfs" || exit 0 276 277 "$ZPOOL" status && echo "" && "$ZPOOL" list 278} 279 280do_start() 281{ 282 if check_boolean "$VERBOSE_MOUNT" 283 then 284 zfs_log_begin_msg "Checking if ZFS userspace tools present" 285 fi 286 287 if checksystem 288 then 289 check_boolean "$VERBOSE_MOUNT" && zfs_log_end_msg 0 290 291 check_boolean "$VERBOSE_MOUNT" && \ 292 zfs_log_begin_msg "Loading kernel ZFS infrastructure" 293 294 if ! load_module "zfs" 295 then 296 check_boolean "$VERBOSE_MOUNT" && zfs_log_end_msg 1 297 return 5 298 fi 299 check_boolean "$VERBOSE_MOUNT" && zfs_log_end_msg 0 300 301 do_import && udev_trigger # just to make sure we get zvols. 302 303 return 0 304 else 305 return 1 306 fi 307} 308 309# ---------------------------------------------------- 310 311if @IS_SYSV_RC@ 312then 313 case "$1" in 314 start) 315 do_start 316 ;; 317 stop) 318 # no-op 319 ;; 320 status) 321 do_status 322 ;; 323 force-reload|condrestart|reload|restart) 324 # no-op 325 ;; 326 *) 327 [ -n "$1" ] && echo "Error: Unknown command $1." 328 echo "Usage: $0 {start|status}" 329 exit 3 330 ;; 331 esac 332 333 exit $? 334else 335 # Create wrapper functions since Gentoo don't use the case part. 336 depend() { do_depend; } 337 start() { do_start; } 338 status() { do_status; } 339fi 340