zfs/etc/init.d/zfs-functions.in

442 lines
9.5 KiB
Plaintext

# This is a script with common functions etc used by zfs-import, zfs-mount,
# zfs-share and zfs-zed.
#
# It is _NOT_ to be called independently
#
# Released under the 2-clause BSD license.
#
# The original script that acted as a template for this script came from
# the Debian GNU/Linux kFreeBSD ZFS packages (which did not include a
# licensing stansa) in the commit dated Mar 24, 2011:
# https://github.com/zfsonlinux/pkg-zfs/commit/80a3ae582b59c0250d7912ba794dca9e669e605a
PATH=/sbin:/bin:/usr/bin:/usr/sbin
# Source function library
if [ -f /etc/rc.d/init.d/functions ]; then
# RedHat and derivates
. /etc/rc.d/init.d/functions
elif [ -L /etc/init.d/functions.sh ]; then
# Gentoo
. /etc/init.d/functions.sh
elif [ -f /lib/lsb/init-functions ]; then
# LSB, Debian GNU/Linux and derivates
. /lib/lsb/init-functions
fi
# Of course the functions we need are called differently
# on different distributions - it would be way too easy
# otherwise!!
if type log_failure_msg > /dev/null 2>&1 ; then
# LSB functions - fall through
zfs_log_begin_msg() { log_begin_msg "$1"; }
zfs_log_end_msg() { log_end_msg "$1"; }
zfs_log_failure_msg() { log_failure_msg "$1"; }
zfs_log_progress_msg() { log_progress_msg "$1"; }
elif type success > /dev/null 2>&1 ; then
# Fedora/RedHat functions
zfs_set_ifs() {
# For some reason, the init function library have a problem
# with a changed IFS, so this function goes around that.
local tIFS="$1"
if [ -n "$tIFS" ]
then
TMP_IFS="$IFS"
IFS="$tIFS"
fi
}
zfs_log_begin_msg() { echo -n "$1 "; }
zfs_log_end_msg() {
zfs_set_ifs "$OLD_IFS"
if [ "$1" -eq 0 ]; then
success
else
failure
fi
echo
zfs_set_ifs "$TMP_IFS"
}
zfs_log_failure_msg() {
zfs_set_ifs "$OLD_IFS"
failure
echo
zfs_set_ifs "$TMP_IFS"
}
zfs_log_progress_msg() { echo -n $"$1"; }
elif type einfo > /dev/null 2>&1 ; then
# Gentoo functions
zfs_log_begin_msg() { ebegin "$1"; }
zfs_log_end_msg() { eend "$1"; }
zfs_log_failure_msg() { eerror "$1"; }
# zfs_log_progress_msg() { echo -n "$1"; }
zfs_log_progress_msg() { echo -n; }
else
# Unknown - simple substitues.
zfs_log_begin_msg() { echo -n "$1"; }
zfs_log_end_msg() {
ret=$1
if [ "$ret" -ge 1 ]; then
echo " failed!"
else
echo " success"
fi
return "$ret"
}
zfs_log_failure_msg() { echo "$1"; }
zfs_log_progress_msg() { echo -n "$1"; }
fi
# Paths to what we need
ZFS="@sbindir@/zfs"
ZED="@sbindir@/zed"
ZPOOL="@sbindir@/zpool"
ZPOOL_CACHE="@sysconfdir@/zfs/zpool.cache"
# Sensible defaults
ZFS_MOUNT='yes'
ZFS_UNMOUNT='yes'
export ZFS ZED ZPOOL ZPOOL_CACHE ZFS_MOUNT ZFS_UNMOUNT
# Source zfs configuration, overriding the defaults
if [ -f @initconfdir@/zfs ]; then
. @initconfdir@/zfs
fi
# ----------------------------------------------------
zfs_action()
{
local MSG="$1"; shift
local CMD="$*"
local ret
zfs_log_begin_msg "$MSG "
$CMD
ret=$?
if [ "$ret" -eq 0 ]; then
zfs_log_end_msg $ret
else
zfs_log_failure_msg $ret
fi
return $ret
}
# Returns
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
# 3 if unsupported
#
zfs_daemon_start()
{
local PIDFILE="$1"; shift
local DAEMON_BIN="$1"; shift
local DAEMON_ARGS="$*"
if type start-stop-daemon > /dev/null 2>&1 ; then
# LSB functions
start-stop-daemon --start --quiet --pidfile "$PIDFILE" \
--exec "$DAEMON_BIN" --test > /dev/null || return 1
start-stop-daemon --start --quiet --exec "$DAEMON_BIN" -- \
$DAEMON_ARGS || return 2
# On Debian GNU/Linux, there's a 'sendsigs' script that will
# kill basically everything quite early and zed is stopped
# much later than that. We don't want zed to be among them,
# so add the zed pid to list of pids to ignore.
if [ -f "$PIDFILE" -a -d /run/sendsigs.omit.d ]
then
ln -s "$PIDFILE" /run/sendsigs.omit.d/zed
fi
elif type daemon > /dev/null 2>&1 ; then
# Fedora/RedHat functions
daemon --pidfile "$PIDFILE" "$DAEMON_BIN" $DAEMON_ARGS
return $?
else
# Unsupported
return 3
fi
return 0
}
# Returns
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# 3 if unsupported
#
zfs_daemon_stop()
{
local PIDFILE="$1"
local DAEMON_BIN="$2"
local DAEMON_NAME="$3"
if type start-stop-daemon > /dev/null 2>&1 ; then
# LSB functions
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 \
--pidfile "$PIDFILE" --name "$DAEMON_NAME"
[ "$?" = 0 ] && rm -f "$PIDFILE"
return $?
elif type killproc > /dev/null 2>&1 ; then
# Fedora/RedHat functions
killproc -p "$PIDFILE" "$DAEMON_NAME"
[ "$?" = 0 ] && rm -f "$PIDFILE"
return $?
else
# Unsupported
return 3
fi
return 0
}
# Returns status
zfs_daemon_status()
{
local PIDFILE="$1"
local DAEMON_BIN="$2"
local DAEMON_NAME="$3"
if type status_of_proc > /dev/null 2>&1 ; then
# LSB functions
status_of_proc "$DAEMON_NAME" "$DAEMON_BIN"
return $?
elif type status > /dev/null 2>&1 ; then
# Fedora/RedHat functions
status -p "$PIDFILE" "$DAEMON_NAME"
return $?
else
# Unsupported
return 3
fi
return 0
}
zfs_daemon_reload()
{
local PIDFILE="$1"
local DAEMON_NAME="$2"
if type start-stop-daemon > /dev/null 2>&1 ; then
# LSB functions
start-stop-daemon --stop -signal 1 --quiet \
--pidfile "$PIDFILE" --name "$DAEMON_NAME"
return $?
elif type killproc > /dev/null 2>&1 ; then
# Fedora/RedHat functions
killproc -p "$PIDFILE" "$DAEMON_NAME" -HUP
return $?
else
# Unsupported
return 3
fi
return 0
}
zfs_installed()
{
if [ ! -x "$ZPOOL" ]; then
return 1
else
# Test if it works (will catch missing/broken libs etc)
"$ZPOOL" -? > /dev/null 2>&1
return $?
fi
if [ ! -x "$ZFS" ]; then
return 2
else
# Test if it works (will catch missing/broken libs etc)
"$ZFS" -? > /dev/null 2>&1
return $?
fi
return 0
}
# Trigger udev and wait for it to settle.
udev_trigger()
{
if [ -x /sbin/udevadm ]; then
/sbin/udevadm trigger --action=change --subsystem-match=block
/sbin/udevadm settle
elif [ -x /sbin/udevsettle ]; then
/sbin/udevtrigger
/sbin/udevsettle
fi
}
# Do a lot of checks to make sure it's 'safe' to continue with the import.
checksystem()
{
if grep -qiE '(^|[^\\](\\\\)* )zfs=(off|no|0)( |$)' /proc/cmdline;
then
# Called with zfs=(off|no|0) - bail because we don't
# want anything import, mounted or shared.
# HOWEVER, only do this if we're called at the boot up
# (from init), not if we're running interactivly (as in
# from the shell - we know what we're doing).
[ -n "$init" ] && exit 3
fi
# Check if ZFS is installed.
zfs_installed || return 5
# Just make sure that /dev/zfs is created.
udev_trigger
if ! [ "$(uname -m)" = "x86_64" ]; then
echo "Warning: You're not running 64bit. Currently native zfs in";
echo " Linux is only supported and tested on 64bit.";
# should we break here? People doing this should know what they
# do, thus i'm not breaking here.
fi
return 0
}
reregister_mounts()
{
local fs mntpnt fstype opts rest tmpdir
tmpdir=removethismountpointhoweverpossible
while read -r fs mntpnt fstype opts rest ; do
fs=$(printf '%b\n' "$fs")
mntpnt=$(printf '%b\n' "$mntpnt")
if [ "$fstype" = "zfs" ] ; then
if [ "$mntpnt" = "/" ] ; then
mount -f -o zfsutil -t zfs --move / /$tmpdir
umount --fake /$tmpdir
else
umount --fake "$mntpnt"
fi
elif echo "$fs" | grep -qE "^/dev/(zd|zvol)" ; then
if [ "$mntpnt" = "/" ] ; then
mount -f -t "$fstype" --move / /$tmpdir
umount --fake /$tmpdir
else
umount --fake "$mntpnt"
fi
fi
done < /proc/mounts
while read -r fs mntpnt fstype opts rest ; do
fs=$(printf '%b\n' "$fs")
mntpnt=$(printf '%b\n' "$mntpnt")
if [ "$fstype" = "zfs" ] ; then
mount -f -t zfs -o zfsutil "$fs" "$mntpnt"
elif echo "$fs" | grep -q "^/dev/zd" ; then
mount -f -t "$fstype" -o "$opts" "$fs" "$mntpnt"
fi
done < /proc/mounts
}
get_root_pool()
{
set -- $(mount | grep ' on / ')
[ "$5" = "zfs" ] && echo "${1%%/*}"
}
check_module_loaded()
{
[ -r /sys/module/zfs/version ] && return 0 || return 1
}
load_module()
{
# Load the zfs module stack
if ! check_module_loaded; then
if ! modprobe zfs; then
return 5
fi
fi
return 0
}
# first parameter is a regular expression that filters mtab
read_mtab()
{
local match="$1"
local fs mntpnt fstype opts rest TMPFILE
# Unset all MTAB_* variables
unset $(env | grep ^MTAB_ | sed 's,=.*,,')
mount | \
grep -E "$match" | \
sed "s,\(.*\) on \(.*\) type .*,\1;\2," | \
while read line; do
mntpnt=$(echo "$line" | sed -e 's,;.*,,' -e 's,/,_,g' \
-e 's,-,_,g' -e 's,\.,_,g' -e 's, ,_,g')
fs=$(echo "$line" | sed 's,.*;,,')
eval export MTAB_$mntpnt="'$fs'"
done
}
in_mtab()
{
local fs="$(echo "$1" | sed 's,/,_,g')"
local var
var="$(eval echo MTAB_$fs)"
[ "$(eval echo "$""$var")" != "" ]
return "$?"
}
# first parameter is a regular expression that filters fstab
read_fstab()
{
local match="$1"
local i var TMPFILE
# Unset all FSTAB_* variables
unset $(env | grep ^FSTAB_ | sed 's,=.*,,')
i=0
while read -r fs mntpnt fstype opts; do
echo "$fs" | egrep -qE '^#|^$' && continue
if echo "$fs $mntpnt $fstype $opts" | grep -qE "$match"; then
eval export FSTAB_dev_$i="$fs"
fs=$(printf '%b\n' "$fs" | sed 's,/,_,g')
eval export FSTAB_$i="$mntpnt"
i=$((i + 1))
fi
done < /etc/fstab
}
in_fstab()
{
local var
var="$(eval echo FSTAB_$1)"
[ "${var}" != "" ]
return $?
}
is_mounted()
{
local mntpt="$1"
local line
mount | \
while read line; do
if echo "$line" | grep -q " on $mntpt "; then
return 0
fi
done
return 1
}