Debug auto_replace_001_pos failures
[zfs.git] / etc / zfs / zfs-functions.in
blob2ff1a186188f2ce17bae9703b7771f921ba1e4af
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
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
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         }
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"; }
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"
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'
103 # Source zfs configuration, overriding the defaults
104 if [ -f @initconfdir@/zfs ]; then
105         . @initconfdir@/zfs
108 # ----------------------------------------------------
110 export ZFS ZED ZPOOL ZPOOL_CACHE ZFS_LOAD_KEY ZFS_UNLOAD_KEY ZFS_MOUNT ZFS_UNMOUNT \
111     ZFS_SHARE ZFS_UNSHARE
113 zfs_action()
115         local MSG="$1"; shift
116         local CMD="$*"
117         local ret
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
128         return "$ret"
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
137 zfs_daemon_start()
139         local PIDFILE="$1";     shift
140         local DAEMON_BIN="$1";  shift
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
147                 # shellcheck disable=SC2086
148                 start-stop-daemon --start --quiet --exec "$DAEMON_BIN" -- \
149                     "$@" || return 2
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
169         return 0
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
178 zfs_daemon_stop()
180         local PIDFILE="$1"
181         local DAEMON_BIN="$2"
182         local DAEMON_NAME="$3"
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"
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"
198                 return "$ret"
199         else
200                 # Unsupported
201                 return 3
202         fi
204         return 0
207 # Returns status
208 zfs_daemon_status()
210         local PIDFILE="$1"
211         local DAEMON_BIN="$2"
212         local DAEMON_NAME="$3"
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
227         return 0
230 zfs_daemon_reload()
232         local PIDFILE="$1"
233         local DAEMON_NAME="$2"
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
249         return 0
252 zfs_installed()
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
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
270         return 0
273 # Trigger udev and wait for it to settle.
274 udev_trigger()
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
285 # Do a lot of checks to make sure it's 'safe' to continue with the import.
286 checksystem()
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
299         # Check if ZFS is installed.
300         zfs_installed || return 5
302         # Just make sure that /dev/zfs is created.
303         udev_trigger
305         return 0
308 get_root_pool()
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.
317 check_boolean()
319         local var="$1"
321         echo "$var" | grep -Eiq "^yes$|^on$|^true$|^1$" && return 0 || return 1
324 check_module_loaded()
326         module="$1"
328         [ -r "/sys/module/${module}/version" ] && return 0 || return 1
331 load_module()
333         module="$1"
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
344 # first parameter is a regular expression that filters mtab
345 read_mtab()
347         local match="$1"
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")
370                         # Set the variable.
371                         eval export "MTAB_$mntpnt=\"$fs\""
372                 fi
373         done < /proc/self/mounts
376 in_mtab()
378         local mntpnt="$1"
379         # Remove 'unwanted' characters.
380         mntpnt=$(printf '%b' "$mntpnt" | tr -d '/. -')
381         local var
383         var="$(eval echo "MTAB_$mntpnt")"
384         [ "$(eval echo "$""$var")" != "" ]
385         return "$?"
388 # first parameter is a regular expression that filters fstab
389 read_fstab()
391         local match="$1"
392         local i var
394         # Unset all FSTAB_* variables
395         # shellcheck disable=SC2046
396         unset $(env | sed -e '/^FSTAB_/!d' -e 's,=.*,,')
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
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"
409                         i=$((i + 1))
410                 fi
411         done < /etc/fstab
414 in_fstab()
416         local var
418         var="$(eval echo "FSTAB_$1")"
419         [ "${var}" != "" ]
420         return $?
423 is_mounted()
425         local mntpt="$1"
426         local mp
428         while read -r _ mp _; do
429                 [ "$mp" = "$mntpt" ] && return 0
430         done < /proc/self/mounts
432         return 1