1 # This is a script with common functions etc used by zfs-import, zfs-load-key,
2 # zfs-mount, zfs-share and zfs-zed.
3 #
4 # It is _NOT_ to be called independently
5 #
6 # Released under the 2-clause BSD license.
7 #
8 # This script is based on debian/zfsutils.zfs.init from the
9 # Debian GNU/kFreeBSD zfsutils 8.1-3 package, written by Aurelien Jarno.
10
11 PATH=/sbin:/bin:/usr/bin:/usr/sbin
12
13 # Source function library
14 if [ -f /etc/rc.d/init.d/functions ]; then
15 # RedHat and derivatives
16 . /etc/rc.d/init.d/functions
17 elif [ -L /etc/init.d/functions.sh ]; then
18 # Gentoo
19 . /etc/init.d/functions.sh
20 elif [ -f /lib/lsb/init-functions ]; then
21 # LSB, Debian, and derivatives
22 . /lib/lsb/init-functions
23 fi
24
25 # Of course the functions we need are called differently
26 # on different distributions - it would be way too easy
27 # otherwise!!
28 if type log_failure_msg > /dev/null 2>&1 ; then
29 # LSB functions - fall through
30 zfs_log_begin_msg() { log_begin_msg "$1"; }
31 zfs_log_end_msg() { log_end_msg "$1"; }
32 zfs_log_failure_msg() { log_failure_msg "$1"; }
33 zfs_log_progress_msg() { log_progress_msg "$1"; }
34 elif type success > /dev/null 2>&1 ; then
35 # Fedora/RedHat functions
36 zfs_set_ifs() {
37 # For some reason, the init function library have a problem
38 # with a changed IFS, so this function goes around that.
39 local tIFS="$1"
40 if [ -n "$tIFS" ]
41 then
42 TMP_IFS="$IFS"
43 IFS="$tIFS"
44 fi
45 }
46
47 zfs_log_begin_msg() { printf "%s" "$1 "; }
48 zfs_log_end_msg() {
49 # shellcheck disable=SC2154
50 zfs_set_ifs "$OLD_IFS"
51 if [ "$1" -eq 0 ]; then
52 success
53 else
54 failure
55 fi
56 echo
57 zfs_set_ifs "$TMP_IFS"
58 }
59 zfs_log_failure_msg() {
60 zfs_set_ifs "$OLD_IFS"
61 failure
62 echo
63 zfs_set_ifs "$TMP_IFS"
64 }
65 zfs_log_progress_msg() { printf "%s" "$""$1"; }
66 elif type einfo > /dev/null 2>&1 ; then
67 # Gentoo functions
68 zfs_log_begin_msg() { ebegin "$1"; }
69 zfs_log_end_msg() { eend "$1"; }
70 zfs_log_failure_msg() { eend "$1"; }
71 # zfs_log_progress_msg() { printf "%s" "$1"; }
72 zfs_log_progress_msg() { :; }
73 else
74 # Unknown - simple substitutes.
75 zfs_log_begin_msg() { printf "%s" "$1"; }
76 zfs_log_end_msg() {
77 ret=$1
78 if [ "$ret" -ge 1 ]; then
79 echo " failed!"
80 else
81 echo " success"
82 fi
83 return "$ret"
84 }
85 zfs_log_failure_msg() { echo "$1"; }
86 zfs_log_progress_msg() { printf "%s" "$1"; }
87 fi
88
89 # Paths to what we need
90 ZFS="@sbindir@/zfs"
91 ZED="@sbindir@/zed"
92 ZPOOL="@sbindir@/zpool"
93 ZPOOL_CACHE="@sysconfdir@/zfs/zpool.cache"
94
95 # Sensible defaults
96 ZFS_LOAD_KEY='yes'
97 ZFS_UNLOAD_KEY='no'
98 ZFS_MOUNT='yes'
99 ZFS_UNMOUNT='yes'
100 ZFS_SHARE='yes'
101 ZFS_UNSHARE='yes'
102
103 # Source zfs configuration, overriding the defaults
104 if [ -f @initconfdir@/zfs ]; then
105 . @initconfdir@/zfs
106 fi
107
108 # ----------------------------------------------------
109
110 export ZFS ZED ZPOOL ZPOOL_CACHE ZFS_LOAD_KEY ZFS_UNLOAD_KEY ZFS_MOUNT ZFS_UNMOUNT \
111 ZFS_SHARE ZFS_UNSHARE
112
113 zfs_action()
114 {
115 local MSG="$1"; shift
116 local CMD="$*"
117 local ret
118
119 zfs_log_begin_msg "$MSG "
120 $CMD
121 ret=$?
122 if [ "$ret" -eq 0 ]; then
123 zfs_log_end_msg "$ret"
124 else
125 zfs_log_failure_msg "$ret"
126 fi
127
128 return "$ret"
129 }
130
131 # Returns
132 # 0 if daemon has been started
133 # 1 if daemon was already running
134 # 2 if daemon could not be started
135 # 3 if unsupported
136 #
137 zfs_daemon_start()
138 {
139 local PIDFILE="$1"; shift
140 local DAEMON_BIN="$1"; shift
141
142 if type start-stop-daemon > /dev/null 2>&1 ; then
143 # LSB functions
144 start-stop-daemon --start --quiet --pidfile "$PIDFILE" \
145 --exec "$DAEMON_BIN" --test > /dev/null || return 1
146
147 # shellcheck disable=SC2086
148 start-stop-daemon --start --quiet --exec "$DAEMON_BIN" -- \
149 "$@" || return 2
150
151 # On Debian, there's a 'sendsigs' script that will
152 # kill basically everything quite early and zed is stopped
153 # much later than that. We don't want zed to be among them,
154 # so add the zed pid to list of pids to ignore.
155 if [ -f "$PIDFILE" ] && [ -d /run/sendsigs.omit.d ]
156 then
157 ln -sf "$PIDFILE" /run/sendsigs.omit.d/zed
158 fi
159 elif type daemon > /dev/null 2>&1 ; then
160 # Fedora/RedHat functions
161 # shellcheck disable=SC2086
162 daemon --pidfile "$PIDFILE" "$DAEMON_BIN" "$@"
163 return $?
164 else
165 # Unsupported
166 return 3
167 fi
168
169 return 0
170 }
171
172 # Returns
173 # 0 if daemon has been stopped
174 # 1 if daemon was already stopped
175 # 2 if daemon could not be stopped
176 # 3 if unsupported
177 #
178 zfs_daemon_stop()
179 {
180 local PIDFILE="$1"
181 local DAEMON_BIN="$2"
182 local DAEMON_NAME="$3"
183
184 if type start-stop-daemon > /dev/null 2>&1 ; then
185 # LSB functions
186 start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 \
187 --pidfile "$PIDFILE" --name "$DAEMON_NAME"
188 ret="$?"
189 [ "$ret" = 0 ] && rm -f "$PIDFILE"
190
191 return "$ret"
192 elif type killproc > /dev/null 2>&1 ; then
193 # Fedora/RedHat functions
194 killproc -p "$PIDFILE" "$DAEMON_NAME"
195 ret="$?"
196 [ "$ret" = 0 ] && rm -f "$PIDFILE"
197
198 return "$ret"
199 else
200 # Unsupported
201 return 3
202 fi
203
204 return 0
205 }
206
207 # Returns status
208 zfs_daemon_status()
209 {
210 local PIDFILE="$1"
211 local DAEMON_BIN="$2"
212 local DAEMON_NAME="$3"
213
214 if type status_of_proc > /dev/null 2>&1 ; then
215 # LSB functions
216 status_of_proc "$DAEMON_NAME" "$DAEMON_BIN"
217 return $?
218 elif type status > /dev/null 2>&1 ; then
219 # Fedora/RedHat functions
220 status -p "$PIDFILE" "$DAEMON_NAME"
221 return $?
222 else
223 # Unsupported
224 return 3
225 fi
226
227 return 0
228 }
229
230 zfs_daemon_reload()
231 {
232 local PIDFILE="$1"
233 local DAEMON_NAME="$2"
234
235 if type start-stop-daemon > /dev/null 2>&1 ; then
236 # LSB functions
237 start-stop-daemon --stop --signal 1 --quiet \
238 --pidfile "$PIDFILE" --name "$DAEMON_NAME"
239 return $?
240 elif type killproc > /dev/null 2>&1 ; then
241 # Fedora/RedHat functions
242 killproc -p "$PIDFILE" "$DAEMON_NAME" -HUP
243 return $?
244 else
245 # Unsupported
246 return 3
247 fi
248
249 return 0
250 }
251
252 zfs_installed()
253 {
254 if [ ! -x "$ZPOOL" ]; then
255 return 1
256 else
257 # Test if it works (will catch missing/broken libs etc)
258 "$ZPOOL" -? > /dev/null 2>&1
259 return $?
260 fi
261
262 if [ ! -x "$ZFS" ]; then
263 return 2
264 else
265 # Test if it works (will catch missing/broken libs etc)
266 "$ZFS" -? > /dev/null 2>&1
267 return $?
268 fi
269
270 return 0
271 }
272
273 # Trigger udev and wait for it to settle.
274 udev_trigger()
275 {
276 if [ -x /sbin/udevadm ]; then
277 /sbin/udevadm trigger --action=change --subsystem-match=block
278 /sbin/udevadm settle
279 elif [ -x /sbin/udevsettle ]; then
280 /sbin/udevtrigger
281 /sbin/udevsettle
282 fi
283 }
284
285 # Do a lot of checks to make sure it's 'safe' to continue with the import.
286 checksystem()
287 {
288 if grep -qiE '(^|[^\\](\\\\)* )zfs=(off|no|0)( |$)' /proc/cmdline;
289 then
290 # Called with zfs=(off|no|0) - bail because we don't
291 # want anything import, mounted or shared.
292 # HOWEVER, only do this if we're called at the boot up
293 # (from init), not if we're running interactively (as in
294 # from the shell - we know what we're doing).
295 # shellcheck disable=SC2154
296 [ -n "$init" ] && exit 3
297 fi
298
299 # Check if ZFS is installed.
300 zfs_installed || return 5
301
302 # Just make sure that /dev/zfs is created.
303 udev_trigger
304
305 return 0
306 }
307
308 get_root_pool()
309 {
310 # shellcheck disable=SC2046
311 set -- $(mount | grep ' on / ')
312 [ "$5" = "zfs" ] && echo "${1%%/*}"
313 }
314
315 # Check if a variable is 'yes' (any case) or '1'
316 # Returns TRUE if set.
317 check_boolean()
318 {
319 local var="$1"
320
321 echo "$var" | grep -Eiq "^yes$|^on$|^true$|^1$" && return 0 || return 1
322 }
323
324 check_module_loaded()
325 {
326 module="$1"
327
328 [ -r "/sys/module/${module}/version" ] && return 0 || return 1
329 }
330
331 load_module()
332 {
333 module="$1"
334
335 # Load the zfs module stack
336 if ! check_module_loaded "$module"; then
337 if ! /sbin/modprobe "$module"; then
338 return 5
339 fi
340 fi
341 return 0
342 }
343
344 # first parameter is a regular expression that filters mtab
345 read_mtab()
346 {
347 local match="$1"
348 local fs mntpnt fstype opts rest
349
350 # Unset all MTAB_* variables
351 # shellcheck disable=SC2046
352 unset $(env | sed -e '/^MTAB_/!d' -e 's,=.*,,')
353
354 while read -r fs mntpnt fstype opts rest; do
355 if echo "$fs $mntpnt $fstype $opts" | grep -qE "$match"; then
356 # * Fix problems (!?) in the mounts file. It will record
357 # 'rpool 1' as 'rpool\0401' instead of 'rpool\00401'
358 # which seems to be the correct (at least as far as
359 # 'printf' is concerned).
360 # * We need to use the external echo, because the
361 # internal one would interpret the backslash code
362 # (incorrectly), giving us a instead.
363 mntpnt=$(/bin/echo "$mntpnt" | sed 's,\\0,\\00,g')
364 fs=$(/bin/echo "$fs" | sed 's,\\0,\\00,')
365
366 # Remove 'unwanted' characters.
367 mntpnt=$(printf '%b' "$mntpnt" | tr -d '/. -')
368 fs=$(printf '%b' "$fs")
369
370 # Set the variable.
371 eval export "MTAB_$mntpnt=\"$fs\""
372 fi
373 done < /proc/self/mounts
374 }
375
376 in_mtab()
377 {
378 local mntpnt="$1"
379 # Remove 'unwanted' characters.
380 mntpnt=$(printf '%b' "$mntpnt" | tr -d '/. -')
381 local var
382
383 var="$(eval echo "MTAB_$mntpnt")"
384 [ "$(eval echo "$""$var")" != "" ]
385 return "$?"
386 }
387
388 # first parameter is a regular expression that filters fstab
389 read_fstab()
390 {
391 local match="$1"
392 local i var
393
394 # Unset all FSTAB_* variables
395 # shellcheck disable=SC2046
396 unset $(env | sed -e '/^FSTAB_/!d' -e 's,=.*,,')
397
398 i=0
399 while read -r fs mntpnt fstype opts; do
400 echo "$fs" | grep -qE '^#|^$' && continue
401 echo "$mntpnt" | grep -qE '^none|^swap' && continue
402 echo "$fstype" | grep -qE '^swap' && continue
403
404 if echo "$fs $mntpnt $fstype $opts" | grep -qE "$match"; then
405 eval export "FSTAB_dev_$i=$fs"
406 fs=$(printf '%b' "$fs" | tr '/' '_')
407 eval export "FSTAB_$i=$mntpnt"
408
409 i=$((i + 1))
410 fi
411 done < /etc/fstab
412 }
413
414 in_fstab()
415 {
416 local var
417
418 var="$(eval echo "FSTAB_$1")"
419 [ "${var}" != "" ]
420 return $?
421 }
422
423 is_mounted()
424 {
425 local mntpt="$1"
426 local mp
427
428 while read -r _ mp _; do
429 [ "$mp" = "$mntpt" ] && return 0
430 done < /proc/self/mounts
431
432 return 1
433 }
Cache object: d15de4df502e35d5ce401dbefbfe85e4
|