Skip to content

Commit

Permalink
Base init scripts for SYSV systems
Browse files Browse the repository at this point in the history
* Based on the init scripts included with Debian GNU/Linux, then take code from the
  already existing ones, trying to merge them into one for better maintainability.
  + Merge openzfs#2148 - Inform OpenRC that ZFS uses mtab.
  + Add a configurable ZFS_INITRD_POST_MODPROBE_SLEEP used in the initrd to sleep after the modprobe.
  + The import function, do_import(), imports pools by name instead of '-a' [all].
    + Test all '/dev/disk/by-*' dirs for import. Include /dev as a last ditch attempt.
  + Fallback on importing the pool using the cache file (if it exists) if the
    'by-id' didn't work.
  + Add exceptions to pool imports.
  + ZED script from the Debian GNU/Linux packages added.

Signed-off-by: Turbo Fredriksson turbo@bayour.com
Closes: openzfs#2974, openzfs#2107.
  • Loading branch information
FransUrbo committed Apr 30, 2015
1 parent 6186e29 commit 9dd15b4
Show file tree
Hide file tree
Showing 14 changed files with 962 additions and 786 deletions.
9 changes: 9 additions & 0 deletions config/zfs-build.m4
Expand Up @@ -311,6 +311,15 @@ AC_DEFUN([ZFS_AC_DEFAULT_PACKAGE], [
AC_MSG_RESULT([$DEFAULT_INIT_SCRIPT])
AC_SUBST(DEFAULT_INIT_SCRIPT)
AC_MSG_CHECKING([default init config direectory])
AS_IF([test -d "/etc/default"], [
DEFAULT_INITCONF_DIR="/etc/default"
], [test -d "/etc/sysconfig"], [
DEFAULT_INITCONF_DIR="/etc/sysconfig"
])
AC_MSG_RESULT([$DEFAULT_INITCONF_DIR])
AC_SUBST(DEFAULT_INITCONF_DIR)
])

dnl #
Expand Down
5 changes: 5 additions & 0 deletions etc/init.d/.gitignore
@@ -1 +1,6 @@
common.init
zfs-import
zfs-mount
zfs-share
zfs-zed
zfs
47 changes: 31 additions & 16 deletions etc/init.d/Makefile.am
@@ -1,22 +1,37 @@
initdir = $(DEFAULT_INIT_DIR)
init_SCRIPTS = zfs
init_SCRIPTS = zfs-import zfs-mount zfs-share zfs-zed

initcommondir = $(sysconfdir)/zfs
initcommon_SCRIPTS = common.init

initconfdir = $(DEFAULT_INITCONF_DIR)
initconf_SCRIPTS = zfs

EXTRA_DIST = \
$(top_srcdir)/etc/init.d/zfs.fedora.in \
$(top_srcdir)/etc/init.d/zfs.gentoo.in \
$(top_srcdir)/etc/init.d/zfs.lsb.in \
$(top_srcdir)/etc/init.d/zfs.lunar.in \
$(top_srcdir)/etc/init.d/zfs.redhat.in
$(top_srcdir)/etc/init.d/common.init.in \
$(top_srcdir)/etc/init.d/zfs-share.in \
$(top_srcdir)/etc/init.d/zfs-import.in \
$(top_srcdir)/etc/init.d/zfs-mount.in \
$(top_srcdir)/etc/init.d/zfs-zed.in \
$(top_srcdir)/etc/init.d/zfs.in

$(init_SCRIPTS): $(init_SCRIPTS).$(DEFAULT_INIT_SCRIPT).in
-$(SED) -e 's,@bindir\@,$(bindir),g' \
-e 's,@sbindir\@,$(sbindir),g' \
-e 's,@udevdir\@,$(udevdir),g' \
-e 's,@udevruledir\@,$(udevruledir),g' \
-e 's,@sysconfdir\@,$(sysconfdir),g' \
-e 's,@initdir\@,$(initdir),g' \
-e 's,@runstatedir\@,$(runstatedir),g' \
'$@.$(DEFAULT_INIT_SCRIPT).in' >'$@'
$(init_SCRIPTS) $(initconf_SCRIPTS) $(initcommon_SCRIPTS):
-(if [ -e /etc/debian_version ]; then \
NFS_SRV=nfs-kernel-server; \
else \
NFS_SRV=nfs; \
fi; \
$(SED) -e 's,@bindir\@,$(bindir),g' \
-e 's,@sbindir\@,$(sbindir),g' \
-e 's,@udevdir\@,$(udevdir),g' \
-e 's,@udevruledir\@,$(udevruledir),g' \
-e 's,@sysconfdir\@,$(sysconfdir),g' \
-e 's,@initconfdir\@,$(initconfdir),g' \
-e 's,@initdir\@,$(initdir),g' \
-e 's,@runstatedir\@,$(runstatedir),g' \
-e "s,@NFS_SRV\@,$$NFS_SRV,g" \
'$@.in' >'$@'; \
chmod +x '$@')

distclean-local::
-$(RM) $(init_SCRIPTS)
-$(RM) $(init_SCRIPTS) $(initcommon_SCRIPTS) $(initconf_SCRIPTS)
249 changes: 249 additions & 0 deletions etc/init.d/common.init.in
@@ -0,0 +1,249 @@
# This is a script with common functions etc used by zfs-mount and zfs-share.
#
# It is _NOT_ to be called independently

PATH=/sbin:/bin:/usr/bin:/usr/sbin

# Source function library
if [ -f /lib/lsb/init-functions ]; then
. /lib/lsb/init-functions
elif [ -f /etc/rc.d/init.d/functions ]; then
. /etc/rc.d/init.d/functions
fi

# Of course the functions we need is called differently
# on different distributions - it would be way to easy
# otherwise!!
if type log_failure_msg > /dev/null ; then
# LSB functions
log_begin_msg=log_begin_msg
log_failure_msg=log_failure_msg
log_progress_msg=log_progress_msg
elif type success > /dev/null ; then
# Fedora/RedHat functions
log_begin_msg=success
log_failure_msg=failure
log_progress_msg=echo -n
elif type einfo > /dev/null ; then
# Gentoo functions
log_begin_msg=einfo
log_failure_msg=eerror
log_progress_msg=echo -n
else
log_begin_msg=echo -n
log_failure_msg=echo
log_progress_msg=echo -n
fi

# The log_end_msg is a little different - it's both an
# echo of a failed message and a return of a code number.
# So if it doesn't exist, we define a very simple one
# that would do the work.
if ! type log_end_msg > /dev/null ; then
log_end_msg() {
ret=$1
if [ "$ret" -ge 1 ]; then
echo " failed!"
else
echo " success"
fi
return $ret
}
fi
log_end_msg=log_end_msg

# Paths to what we need
ZFS="@sbindir@/zfs"
ZPOOL="@sbindir@/zpool"
ZPOOL_CACHE="@sysconfdir@/zfs/zpool.cache"

# Sensible defaults
ZFS_MOUNT='yes'
ZFS_UNMOUNT='yes'
LOCKDIR=/run/lock

# Source zfs configuration, overriding the defaults
if [ -f /etc/@initconfdir@/zfs ]; then
. /etc/@initconfdir@/zfs
fi

[ ! -d "$LOCKDIR" ] && mkdir $LOCKDIR

# ----------------------------------------------------

zfs_installed() {
$log_begin_msg "Checking if zfs userspace tools present"
if [ ! -x $ZPOOL ]; then
$log_failure_msg "$ZPOOL binary not found."
$log_end_msg 1
fi
if [ ! -x $ZFS ]; then
$log_failure_msg "$ZFS binary not found."
$log_end_msg 1
fi
$log_end_msg 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
}

# From scripts/common.sh
wait_udev() {
local DEVICE=$1
local DELAY=$2
local COUNT=0

udev_trigger
while [ ! -e ${DEVICE} ]; do
if [ ${COUNT} -gt ${DELAY} ]; then
return 1
fi

let COUNT=${COUNT}+1
sleep 1
done

return 0
}

# Do a lot of checks to make sure it's 'safe' to continue with import/mount etc
checksystem()
{
if [ -z "$init" ]; then
# Not interactive and we don't want to import pool or mount filesystems.
# Won't of course work if you're booting from ZFS...
grep -qiE '(^|[^\\](\\\\)* )zfs=(off|no|0)( |$)' /proc/cmdline && exit 3
fi

[ -f "$LOCKDIR/$servicename" ] && return 3

# Check if ZFS is installed. If not, comply to FC standards and bail
zfs_installed || {
$log_failure_msg "not installed"
return 5
}

# Delay until all required block devices are present.
if [ -x /sbin/udevadm ]; then
/sbin/udevadm settle
elif [ -x /sbin/udevsettle ]; then
/sbin/udevsettle
fi

# Load the zfs module stack
if ! grep -q zfs /proc/modules ; then
$log_begin_msg "Loading kernel ZFS infrastructure: "
modprobe zfs || {
$log_failure_msg "Could not load zfs module"
$log_end_msg 1
return 5
}
$log_end_msg 0
fi

# Just make sure that /dev/zfs is created.
wait_udev /dev/zfs 15

# fix mtab to include already-mounted fs filesystems, in case there are any
# we ONLY do this if mtab does not point to /proc/mounts
# which is the case in some systems (systemd may bring that soon)
if ! readlink /etc/mtab | grep -q /proc ; then
if grep -qE "(^/dev/zd|^/dev/zvol| zfs )" /proc/mounts ; then
$log_begin_msg "Registering already-mounted ZFS filesystems and volumes: "
reregister_mounts || {
$log_end_msg 1
return 150
}
fi
fi

# Ensure / exists in /etc/mtab, if not update mtab accordingly.
# This should be handled by rc.sysinit but lets be paranoid.
awk '$2 == "/" { exit 1 }' /etc/mtab
RETVAL=$?
if [ "$RETVAL" -eq 0 ]; then
/bin/mount -f /
fi

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
}

reregister_mounts() {
cat /etc/mtab | 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 / /removethismountpointhoweverpossible
umount --fake /removethismountpointhoweverpossible
else
umount --fake "$mntpnt"
fi
elif echo "$fs" | grep -qE "^/dev/(zd|zvol)" ; then
if [ "$mntpnt" == "/" ] ; then
mount -f -t "$fstype" --move / /removethismountpointhoweverpossible
umount --fake /removethismountpointhoweverpossible
else
umount --fake "$mntpnt"
fi
fi
done
cat /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
}

# i need a bash guru to simplify this, since this is copy and paste, but donno how
# to correctly dereference variable names in bash, or how to do this right

declare -A MTAB
declare -A FSTAB

# first parameter is a regular expression that filters mtab
read_mtab() {
for fs in "${!MTAB[@]}" ; do unset MTAB["$fs"] ; done
while read -r fs mntpnt fstype opts blah ; do
fs=`printf '%b\n' "$fs"`
MTAB["$fs"]=$mntpnt
done < <(grep -E "$1" /etc/mtab)
}

in_mtab() {
[ "${MTAB[$1]}" != "" ]
return $?
}

# first parameter is a regular expression that filters fstab
read_fstab() {
local i=0
for fs in "${!FSTAB[@]}" ; do unset FSTAB["$fs"] ; done
while read -r fs mntpnt fstype opts blah ; do
fs=`printf '%b\n' "$fs"`
FSTAB["$i"]=$mntpnt
i=$((i + 1))
done < <(grep -E "$1" /etc/fstab)
}

in_fstab() {
[ "${FSTAB[$1]}" != "" ]
return $?
}

0 comments on commit 9dd15b4

Please sign in to comment.