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