Update zfs.fedora init script
[zfs.git] / etc / init.d / zfs.fedora
index 2751603..8e48efb 100644 (file)
@@ -11,8 +11,8 @@
 #
 ### BEGIN INIT INFO
 # Provides: zfs
-# Required-Start: $local_fs
-# Required-Stop: $local_fs
+# Required-Start:
+# Required-Stop:
 # Should-Start:
 # Should-Stop:
 # Default-Start: 2 3 4 5
 #              filesystems and starts all related zfs services.
 ### END INIT INFO
 
-# Source function library.
-. /etc/rc.d/init.d/functions
+export PATH=/usr/local/sbin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
 
-# Source zfs configuration.
-[ -f /etc/sysconfig/zfs ] &&  . /etc/sysconfig/zfs
+# Source function library & LSB routines
+. /etc/rc.d/init.d/functions
 
+# script variables
 RETVAL=0
+ZPOOL=zpool
+ZFS=zfs
+servicename=zfs
+LOCKFILE=/var/lock/subsys/$servicename
+
+# functions
+zfs_installed() {
+       modinfo zfs > /dev/null 2>&1 || return 5
+       $ZPOOL  > /dev/null 2>&1
+       [ $? == 127 ] && return 5
+       $ZFS    > /dev/null 2>&1
+       [ $? == 127 ] && return 5
+       return 0
+}
 
-LOCKFILE=/var/lock/subsys/zfs
-CACHEFILE=/etc/zfs/zpool.cache
-ZPOOL=/usr/sbin/zpool
-ZFS=/usr/sbin/zfs
+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 -q "^/dev/zd" ; 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
+}
 
-[ -x $ZPOOL ] || exit 1
-[ -x $ZFS ] || exit 2
+# 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
 
-start()
-{
-       [ -f $LOCKFILE ] && return 3
+declare -A MTAB
+declare -A FSTAB
 
-       # Requires selinux policy which has not been written.
-       if [ -r "/selinux/enforce" ] &&
-          [ "$(cat /selinux/enforce)" = "1" ]; then
-               action "SELinux ZFS policy required: " /bin/false
-               return 4
-       fi
+# 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 "$1" /etc/mtab)
+}
 
-       # Load the zfs module stack
-       /sbin/modprobe zfs
+in_mtab() {
+        [ "${MTAB[$1]}" != "" ]
+        return $?
+}
 
-       # 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
+# first parameter is a regular expression that filters fstab
+read_fstab() {
+        for fs in "${!FSTAB[@]}" ; do unset FSTAB["$fs"] ; done
+        while read -r fs mntpnt fstype opts blah ; do
+                fs=`printf '%b\n' "$fs"`
+                FSTAB["$fs"]=$mntpnt
+        done < <(grep "$1" /etc/fstab)
+}
 
-       # Import all pools described by the cache file, and then mount
-       # all filesystem based on their properties.
-        if [ -f $CACHEFILE ] ; then
-               action $"Importing ZFS pools: " \
-                       $ZPOOL import -c $CACHEFILE -aN 2>/dev/null
-               action $"Mounting ZFS filesystems: " \
-                       $ZFS mount -a
-       fi
-       
-       touch $LOCKFILE
+in_fstab() {
+        [ "${FSTAB[$1]}" != "" ]
+        return $?
 }
 
-stop()
+start()
 {
-       [ ! -f $LOCKFILE ] && return 3
+       if [ -f "$LOCKFILE" ] ; then return 0 ; fi
+
+       # check if ZFS is installed.  If not, comply to FC standards and bail
+       zfs_installed || {
+               action $"Checking if ZFS is installed: not installed" /bin/false
+               return 5
+       }
+
+        # Requires selinux policy which has not been written.
+        if [ -r "/selinux/enforce" ] &&
+           [ "$(cat /selinux/enforce)" = "1" ]; then
+                action $"SELinux ZFS policy required: " /bin/false || return 6
+        fi
+
+       # load kernel module infrastructure
+       if ! grep -q zfs /proc/modules ; then
+               action $"Loading kernel ZFS infrastructure: " modprobe zfs || return 5
+       fi
 
-       action $"Unmounting ZFS filesystems: " $ZFS umount -a
+       # 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| zfs )" /proc/mounts ; then
+                       action $"Registering already-mounted ZFS filesystems and volumes: " reregister_mounts || return 150
+               fi
+       fi
 
-       rm -f $LOCKFILE
+        if [ -f /etc/zfs/zpool.cache ] ; then
+       
+               echo -n $"Importing ZFS pools not yet imported: "
+               $ZPOOL import -c /etc/zfs/zpool.cache -aN || true # stupid zpool will fail if all pools are already imported
+               RETVAL=$?
+               if [ $RETVAL -ne 0 ]; then
+                       failure "Importing ZFS pools not yet imported: "
+                       return 151
+               fi
+               success "Importing ZFS pools not yet imported: "
+       
+       fi
+       
+       action $"Mounting ZFS filesystems not yet mounted: " $ZFS mount -a || return 152
+
+       # hack to read mounted file systems because otherwise
+       # zfs returns EPERM when a non-root user reads a mounted filesystem before root did
+       savepwd="$PWD"
+       mount | grep " type zfs " | sed 's/.*on //' | sed 's/ type zfs.*$//' | while read line ; do
+               cd "$line" > /dev/null 2>&1
+               ls > /dev/null
+       done
+       cd "$savepwd"
+
+       read_mtab  "^/dev/zd"
+       read_fstab "^/dev/zd"
+
+       template=$"Mounting volume %s registered in fstab: "
+       for volume in "${!FSTAB[@]}" ; do
+               if in_mtab "$volume" ; then continue ; fi
+               string=`printf "$template" "$volume"`
+               action "$string" mount "$volume"
+       done
+       
+       touch "$LOCKFILE"
 }
 
-status()
+stop()
 {
-       [ ! -f $LOCKFILE ] && return 3
-
-       $ZPOOL status && echo && $ZPOOL list
+       if [ ! -f "$LOCKFILE" ] ; then return 0 ; fi
+
+       # check if ZFS is installed.  If not, comply to FC standards and bail
+       zfs_installed || {
+               action $"Checking if ZFS is installed: not installed" /bin/false
+               return 5
+       }
+
+       # the poweroff of the system takes care of this
+       # but it never unmounts the root filesystem itself
+       # shit
+
+       action $"Syncing ZFS filesystems: " sync
+            # about the only thing we can do, and then we
+            # hope that the umount process will succeed
+            # unfortunately the umount process does not dismount
+            # the root file system, there ought to be some way
+            # we can tell zfs to just flush anything in memory
+            # when a request to remount,ro comes in
+
+       #echo -n $"Unmounting ZFS filesystems: "
+       #$ZFS umount -a
+       #RETVAL=$?
+       #if [ $RETVAL -ne 0 ]; then
+       #       failure
+
+       #       return 8
+       #fi
+       #success
+       
+       rm -f "$LOCKFILE"
 }
 
+# See how we are called
 case "$1" in
        start)
                start
@@ -99,21 +223,24 @@ case "$1" in
                RETVAL=$?
                ;;
        status)
-               status
-               RETVAL=$?
+               lsmod | grep -q zfs || RETVAL=3
+               $ZPOOL status && echo && $ZFS list || {
+                       [ -f "$LOCKFILE" ] && RETVAL=2 || RETVAL=4
+               }
                ;;
        restart)
                stop
                start
                ;;
        condrestart)
-               if [ -f $LOCKFILE ]; then
+               if [ -f "$LOCKFILE" ] ; then
                        stop
                        start
                fi
                ;;
        *)
                echo $"Usage: $0 {start|stop|status|restart|condrestart}"
+               RETVAL=3
                ;;
 esac