aboutsummaryrefslogtreecommitdiff
path: root/sys/contrib/openzfs/etc/init.d/zfs-import.in
blob: ff169eb96d86e79d2c98ca4cafb0ba843298e2e4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
#!@DEFAULT_INIT_SHELL@
# shellcheck disable=SC2154
#
# zfs-import    This script will import ZFS pools
#
# chkconfig:    2345 01 99
# description:  This script will perform a verbatim import of ZFS pools
#               during system boot.
# 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` command.
### 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.
#
# This script is based on debian/zfsutils.zfs.init from the
# Debian GNU/kFreeBSD zfsutils 8.1-3 package, written by Aurelien Jarno.

# Source the common init script
. @sysconfdir@/zfs/zfs-functions

# ----------------------------------------------------

do_depend()
{
	before swap
	after sysfs udev
	keyword -lxc -openvz -prefix -vserver
}

# Use the zpool cache file to import pools
do_verbatim_import()
{
	if [ -f "$ZPOOL_CACHE" ]
	then
		zfs_action "Importing ZFS pool(s)" \
			"$ZPOOL" import -c "$ZPOOL_CACHE" -N -a
	fi
}

# Support function to get a list of all pools, separated with ';'
find_pools()
{
	local pools

	pools=$("$@" 2> /dev/null | \
		sed -Ee '/pool:|^[a-zA-Z0-9]/!d' -e 's@.*: @@' | \
		sort | \
		tr '\n' ';')

	echo "${pools%%;}" # Return without the last ';'.
}

# Find and import all visible pools, even exported ones
do_import_all_visible()
{
	local already_imported available_pools pool npools
	local exception dir ZPOOL_IMPORT_PATH RET=0 r=1

	# In case not shutdown cleanly.
	# shellcheck disable=SC2154
	[ -n "$init" ] && rm -f /etc/dfs/sharetab

	# Just simplify code later on.
	if [ -n "$USE_DISK_BY_ID" ] && [ "$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 visible/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 'normally', 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 compatibility, 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" ] && [ -z "$ZPOOL_IMPORT_PATH" ]
	then
		local dirs
		dirs="$(for dir in $(echo /dev/disk/by-*)
		do
			# Ignore by-vdev here - we want it first!
			echo "$dir" | grep -q /by-vdev && continue
			[ ! -d "$dir" ] && continue

			printf "%s" "$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 available 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 preferred way.
		# shellcheck disable=SC2086
		"$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 ] && [ -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

			# shellcheck disable=SC2086
			"$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" ] && [ -z "$available_pools" ] && return 0

	return "$RET"
}

do_import()
{
	if check_boolean "$ZPOOL_IMPORT_ALL_VISIBLE"
	then
		do_import_all_visible
	else
		# This is the default option
		do_verbatim_import
	fi
}

# 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
}

# ----------------------------------------------------

if @IS_SYSV_RC@
then
	case "$1" in
		start)
			do_start
			;;
		stop)
			# no-op
			;;
		status)
			do_status
			;;
		force-reload|condrestart|reload|restart)
			# no-op
			;;
		*)
			[ -n "$1" ] && echo "Error: Unknown command $1."
			echo "Usage: $0 {start|status}"
			exit 3
			;;
	esac

	exit $?
else
	# Create wrapper functions since Gentoo don't use the case part.
	depend() { do_depend; }
	start() { do_start; }
	status() { do_status; }
fi