1 # This is a script with common functions etc used by zfs-import, zfs-load-key,
2 # zfs-mount, zfs-share and zfs-zed.
4 # It is _NOT_ to be called independently
6 # Released under the 2-clause BSD license.
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.
11 PATH=/sbin:/bin:/usr/bin:/usr/sbin
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
19 . /etc/init.d/functions.sh
20 elif [ -f /lib/lsb/init-functions ]; then
21 # LSB, Debian, and derivatives
22 . /lib/lsb/init-functions
25 # Of course the functions we need are called differently
26 # on different distributions - it would be way too easy
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
37 # For some reason, the init function library have a problem
38 # with a changed IFS, so this function goes around that.
47 zfs_log_begin_msg() { printf "%s" "$1 "; }
49 # shellcheck disable=SC2154
50 zfs_set_ifs "$OLD_IFS"
51 if [ "$1" -eq 0 ]; then
57 zfs_set_ifs "$TMP_IFS"
59 zfs_log_failure_msg() {
60 zfs_set_ifs "$OLD_IFS"
63 zfs_set_ifs "$TMP_IFS"
65 zfs_log_progress_msg() { printf "%s" "$""$1"; }
66 elif type einfo > /dev/null 2>&1 ; then
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() { :; }
74 # Unknown - simple substitutes.
75 zfs_log_begin_msg() { printf "%s" "$1"; }
78 if [ "$ret" -ge 1 ]; then
85 zfs_log_failure_msg() { echo "$1"; }
86 zfs_log_progress_msg() { printf "%s" "$1"; }
89 # Paths to what we need
92 ZPOOL="@sbindir@/zpool"
93 ZPOOL_CACHE="@sysconfdir@/zfs/zpool.cache"
103 # Source zfs configuration, overriding the defaults
104 if [ -f @initconfdir@/zfs ]; then
108 # ----------------------------------------------------
110 export ZFS ZED ZPOOL ZPOOL_CACHE ZFS_LOAD_KEY ZFS_UNLOAD_KEY ZFS_MOUNT ZFS_UNMOUNT \
111 ZFS_SHARE ZFS_UNSHARE
115 local MSG="$1"; shift
119 zfs_log_begin_msg "$MSG "
122 if [ "$ret" -eq 0 ]; then
123 zfs_log_end_msg "$ret"
125 zfs_log_failure_msg "$ret"
132 # 0 if daemon has been started
133 # 1 if daemon was already running
134 # 2 if daemon could not be started
139 local PIDFILE="$1"; shift
140 local DAEMON_BIN="$1"; shift
142 if type start-stop-daemon > /dev/null 2>&1 ; then
144 start-stop-daemon --start --quiet --pidfile "$PIDFILE" \
145 --exec "$DAEMON_BIN" --test > /dev/null || return 1
147 # shellcheck disable=SC2086
148 start-stop-daemon --start --quiet --exec "$DAEMON_BIN" -- \
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 ]
157 ln -sf "$PIDFILE" /run/sendsigs.omit.d/zed
159 elif type daemon > /dev/null 2>&1 ; then
160 # Fedora/RedHat functions
161 # shellcheck disable=SC2086
162 daemon --pidfile "$PIDFILE" "$DAEMON_BIN" "$@"
173 # 0 if daemon has been stopped
174 # 1 if daemon was already stopped
175 # 2 if daemon could not be stopped
181 local DAEMON_BIN="$2"
182 local DAEMON_NAME="$3"
184 if type start-stop-daemon > /dev/null 2>&1 ; then
186 start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 \
187 --pidfile "$PIDFILE" --name "$DAEMON_NAME"
189 [ "$ret" = 0 ] && rm -f "$PIDFILE"
192 elif type killproc > /dev/null 2>&1 ; then
193 # Fedora/RedHat functions
194 killproc -p "$PIDFILE" "$DAEMON_NAME"
196 [ "$ret" = 0 ] && rm -f "$PIDFILE"
211 local DAEMON_BIN="$2"
212 local DAEMON_NAME="$3"
214 if type status_of_proc > /dev/null 2>&1 ; then
216 status_of_proc "$DAEMON_NAME" "$DAEMON_BIN"
218 elif type status > /dev/null 2>&1 ; then
219 # Fedora/RedHat functions
220 status -p "$PIDFILE" "$DAEMON_NAME"
233 local DAEMON_NAME="$2"
235 if type start-stop-daemon > /dev/null 2>&1 ; then
237 start-stop-daemon --stop --signal 1 --quiet \
238 --pidfile "$PIDFILE" --name "$DAEMON_NAME"
240 elif type killproc > /dev/null 2>&1 ; then
241 # Fedora/RedHat functions
242 killproc -p "$PIDFILE" "$DAEMON_NAME" -HUP
254 if [ ! -x "$ZPOOL" ]; then
257 # Test if it works (will catch missing/broken libs etc)
258 "$ZPOOL" -? > /dev/null 2>&1
262 if [ ! -x "$ZFS" ]; then
265 # Test if it works (will catch missing/broken libs etc)
266 "$ZFS" -? > /dev/null 2>&1
273 # Trigger udev and wait for it to settle.
276 if [ -x /sbin/udevadm ]; then
277 /sbin/udevadm trigger --action=change --subsystem-match=block
279 elif [ -x /sbin/udevsettle ]; then
285 # Do a lot of checks to make sure it's 'safe' to continue with the import.
288 if grep -qiE '(^|[^\\](\\\\)* )zfs=(off|no|0)( |$)' /proc/cmdline;
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
299 # Check if ZFS is installed.
300 zfs_installed || return 5
302 # Just make sure that /dev/zfs is created.
310 # shellcheck disable=SC2046
311 set -- $(mount | grep ' on / ')
312 [ "$5" = "zfs" ] && echo "${1%%/*}"
315 # Check if a variable is 'yes' (any case) or '1'
316 # Returns TRUE if set.
321 echo "$var" | grep -Eiq "^yes$|^on$|^true$|^1$" && return 0 || return 1
324 check_module_loaded()
328 [ -r "/sys/module/${module}/version" ] && return 0 || return 1
335 # Load the zfs module stack
336 if ! check_module_loaded "$module"; then
337 if ! /sbin/modprobe "$module"; then
344 # first parameter is a regular expression that filters mtab
348 local fs mntpnt fstype opts rest
350 # Unset all MTAB_* variables
351 # shellcheck disable=SC2046
352 unset $(env | sed -e '/^MTAB_/!d' -e 's,=.*,,')
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
\x01 instead.
363 mntpnt=$(/bin/echo "$mntpnt" | sed 's,\\0,\\00,g')
364 fs=$(/bin/echo "$fs" | sed 's,\\0,\\00,')
366 # Remove 'unwanted' characters.
367 mntpnt=$(printf '%b' "$mntpnt" | tr -d '/. -')
368 fs=$(printf '%b' "$fs")
371 eval export "MTAB_$mntpnt=\"$fs\""
373 done < /proc/self/mounts
379 # Remove 'unwanted' characters.
380 mntpnt=$(printf '%b' "$mntpnt" | tr -d '/. -')
383 var="$(eval echo "MTAB_$mntpnt")"
384 [ "$(eval echo "$""$var")" != "" ]
388 # first parameter is a regular expression that filters fstab
394 # Unset all FSTAB_* variables
395 # shellcheck disable=SC2046
396 unset $(env | sed -e '/^FSTAB_/!d' -e 's,=.*,,')
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
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"
418 var="$(eval echo "FSTAB_$1")"
428 while read -r _ mp _; do
429 [ "$mp" = "$mntpt" ] && return 0
430 done < /proc/self/mounts