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