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