--- /dev/null
+#!/bin/sh
+# init fragment for O2CB.
+#
+# chkconfig: 2345 24 20
+# description: Load O2CB cluster services at system boot.
+#
+### BEGIN INIT INFO
+# Provides: o2cb
+# Required-Start: $network
+# Should-Start:
+# Required-Stop:
+# Default-Start: 2 3 5
+# Default-Stop:
+# Description: Load O2CB cluster services at system boot.
+### END INIT INFO
+
+# Force LC_ALL=C
+export LC_ALL=C
+
+CLUSTERCONF=/etc/ocfs2/cluster.conf
+
+if [ -f /etc/sysconfig/o2cb ]
+then
+ # Red Hat and Novell
+ CONFIGURATION=/etc/sysconfig/o2cb
+elif [ -f /etc/default/o2cb ]
+then
+ # Debian
+ CONFIGURATION=/etc/default/o2cb
+elif [ -d /etc/sysconfig ]
+then
+ CONFIGURATION=/etc/sysconfig/o2cb
+else
+ CONFIGURATION=/etc/default/o2cb
+fi
+
+# Source configuration,
+[ -f "${CONFIGURATION}" ] && . "${CONFIGURATION}"
+
+configfs_path()
+{
+ # Note that this is only valid *after* configfs is loaded
+ if [ -d /sys/kernel/config ]
+ then
+ echo /sys/kernel/config
+ else
+ echo /config
+ fi
+}
+
+#
+# This is a tricky bit of eval work. There are many steps involved in
+# O2CB startup/shutdown, so we collect them here. Each line is a line
+# of shell code that needs to be run. The code is run via eval as
+# follows:
+#
+# start/load:
+# Eval of the exact lines, in order. So, the first call is
+# "eval load_module configfs".
+#
+# status:
+# Eval of the lines with "check_" prepended, in order. So the first
+# call is "eval check_load_module configfs".
+#
+# stop/unload:
+# Eval of the lines with "un" prepened, in reverse order. So the
+# *last* call is "eval unload_module configfs".
+#
+# To provide an action, create a set of shell functions or commands
+# "foo", "check_foo", and "unfoo". Then add "foo arguments" to the
+# appropriate place. Be careful, eval requires quoting to be right.
+#
+LOAD_ACTIONS=("load_module configfs"
+ "mount_fs configfs "'$(configfs_path)'
+ "load_module ocfs2_nodemanager"
+ "load_module ocfs2_dlm"
+ "load_module ocfs2_dlmfs"
+ "mount_fs ocfs2_dlmfs /dlm")
+
+
+#
+# if_fail()
+#
+# Evaluates return codes. If 0, prints "OK", if 1, prints "Failed"
+# and exits. If 2, status is "already done" and nothing is printed.
+# The rest of the functions in here all honor this convention.
+#
+if_fail()
+{
+ RC="$1"
+ REASON="$2"
+ if [ "$RC" = "0" ]
+ then
+ echo "OK"
+ return
+ elif [ "$RC" = "2" ]
+ then
+ return
+ fi
+ echo "Failed"
+ if [ -n "${REASON}" ]
+ then
+ echo "${REASON}" >&2
+ fi
+ exit 1
+}
+
+
+#
+# write_sysconfig()
+#
+# Writes the system configuration out
+#
+write_sysconfig()
+{
+ echo -n "Writing O2CB configuration: "
+ cat >"${CONFIGURATION}" <<EOF
+#
+# This is a configuration file for automatic startup of the O2CB
+# driver. It is generated by running /etc/init.d/o2cb configure.
+# Please use that method to modify this file
+#
+
+# O2CB_ENABELED: 'true' means to load the driver on boot.
+O2CB_ENABLED=${O2CB_ENABLED:-false}
+
+# O2CB_BOOTCLUSTER: If not empty, the name of a cluster to start.
+O2CB_BOOTCLUSTER=${O2CB_BOOTCLUSTER}
+
+# O2CB_HEARTBEAT_THRESHOLD: Iterations before a node is considered dead.
+O2CB_HEARTBEAT_THRESHOLD=${O2CB_HEARTBEAT_THRESHOLD}
+
+EOF
+
+ if [ $? != 0 ]
+ then
+ return 1
+ fi
+ return 0
+}
+
+#
+# configure_ask()
+#
+# Ask configuration questions, setting the shell vars.
+#
+configure_ask()
+{
+ cat <<EOF
+Configuring the O2CB driver.
+
+This will configure the on-boot properties of the O2CB driver.
+The following questions will determine whether the driver is loaded on
+boot. The current values will be shown in brackets ('[]'). Hitting
+<ENTER> without typing an answer will keep that current value. Ctrl-C
+will abort.
+
+EOF
+
+ while :
+ do
+ if [ "$O2CB_ENABLED" = "true" ]
+ then
+ CUR=y
+ else
+ CUR=n
+ fi
+ echo -n "Load O2CB driver on boot (y/n) [$CUR]: "
+ read LINE
+ case "$LINE" in
+ "")
+ break
+ ;;
+ y|Y)
+ O2CB_ENABLED=true
+ break
+ ;;
+ n|N)
+ O2CB_ENABLED=false
+ break
+ ;;
+ *)
+ echo "Invalid answer: $LINE" >&2
+ ;;
+ esac
+ done
+
+ while :
+ do
+ echo -n "Cluster to start on boot (Enter \"none\" to clear) [$O2CB_BOOTCLUSTER]: "
+ read LINE
+ case "$LINE" in
+ "")
+ break
+ ;;
+ none)
+ O2CB_BOOTCLUSTER=
+ break
+ ;;
+
+ *[^a-zA-Z0-9]*)
+ echo "Invalid cluster name: $LINE" >&2
+ ;;
+ *)
+ O2CB_BOOTCLUSTER="$LINE"
+ break
+ ;;
+ esac
+ done
+
+ # XXX ask about mount point base
+}
+
+
+#
+# make_dir()
+#
+# Create $1
+# Returns 0 on success, 1 on error, 2 if it already exists.
+#
+make_dir()
+{
+ if [ "$#" -lt "1" -o -z "$1" ]
+ then
+ echo "make_dir(): Requires an argument" >&2
+ return 1
+ fi
+ DIR="$1"
+ if [ -e "$DIR" ]
+ then
+ if [ -d "$DIR" ]
+ then
+ return 2
+ fi
+ echo "make_dir(): File $DIR is not a directory" >&2
+ return 1
+ fi
+
+ echo -n "Creating directory '$DIR': "
+ mkdir -p "$DIR" 2>/dev/null
+ if [ $? != 0 ]
+ then
+ echo "Unable to create directory '$DIR'" >&2
+ return 1
+ fi
+ return 0
+}
+
+
+#
+# load_module()
+# Load a module
+#
+# 0 is success, 1 is error, 2 is already loaded
+#
+load_module()
+{
+ if [ "$#" -lt "1" -o -z "$1" ]
+ then
+ echo "load_module(): Requires an argument" >&2
+ return 1
+ fi
+ MODNAME="$1"
+
+ MODOUT="`awk '$1 ~ /^'$MODNAME'$/{print $1;exit}' < /proc/modules 2>/dev/null`"
+ if [ -n "$MODOUT" ]
+ then
+ return 2
+ fi
+
+ echo -n "Loading module \"$MODNAME\": "
+ modprobe -s "$MODNAME"
+ if [ "$?" != 0 ]
+ then
+ echo "Unable to load module \"$MODNAME\"" >&2
+ return 1
+ fi
+
+ return 0
+}
+
+#
+# check_heartbeat()
+#
+# 0 is hb not active, 1 is error, 2 is hb active
+#
+check_heartbeat()
+{
+ if [ "$#" -lt "1" -o -z "$1" ]
+ then
+ echo "check_heartbeat(): Requires an argument" >&2
+ return 1
+ fi
+ CLUSTER="$1"
+
+ RC=0
+ if [ -d "$(configfs_path)/cluster/${CLUSTER}/heartbeat/" ]
+ then
+ ls -1 "$(configfs_path)/cluster/${CLUSTER}/heartbeat/" | while read HBUUID
+ do
+ if [ -d "$(configfs_path)/cluster/${CLUSTER}/heartbeat/${HBUUID}" ]
+ then
+ return 2;
+ fi
+ done
+ if [ $? = 2 ]
+ then
+ RC=2
+ fi
+ fi
+
+ return $RC
+}
+
+#
+# clean_heartbeat()
+# Removes the inactive heartbeat regions
+#
+clean_heartbeat()
+{
+ if [ "$#" -lt "1" -o -z "$1" ]
+ then
+ echo "clean_heartbeat(): Requires an argument" >&2
+ return 1
+ fi
+ CLUSTER="$1"
+
+ echo -n "Cleaning heartbeat on ${CLUSTER}: "
+
+ if [ ! -d "$(configfs_path)/cluster/${CLUSTER}/heartbeat/" ]
+ then
+ echo "OK"
+ return
+ fi
+
+ ls -1 "$(configfs_path)/cluster/${CLUSTER}/heartbeat/" | while read HBUUID
+ do
+ if [ ! -d "$(configfs_path)/cluster/${CLUSTER}/heartbeat/${HBUUID}" ]
+ then
+ continue
+ fi
+
+ OUTPUT="`ocfs2_hb_ctl -I -u ${HBUUID} 2>&1`"
+ if [ $? != 0 ]
+ then
+ echo "Failed"
+ echo "${OUTPUT}" >&2
+ exit 1
+ fi
+
+ REF="`echo ${OUTPUT} | awk '/refs/ {print $2; exit;}' 2>&1`"
+ if [ $REF != 0 ]
+ then
+ echo "Failed"
+ echo "At least one heartbeat region still active" >&2
+ exit 1
+ else
+ OUTPUT="`ocfs2_hb_ctl -K -u ${HBUUID} 2>&1`"
+ fi
+ done
+ if [ $? = 1 ]
+ then
+ exit 1
+ fi
+ echo "OK"
+}
+
+#
+# unload_module()
+# Unload a module
+#
+# 0 is success, 1 is error, 2 is not loaded
+#
+unload_module()
+{
+ if [ "$#" -lt "1" -o -z "$1" ]
+ then
+ echo "unload_module(): Requires an argument" >&2
+ return 1
+ fi
+ MODNAME="$1"
+
+ MODOUT="`awk '$1 ~ /^'$MODNAME'$/{print $1,$3;exit}' < /proc/modules 2>/dev/null`"
+ if [ -z "$MODOUT" ]
+ then
+ return 2
+ fi
+ case "$MODOUT" in
+ $MODNAME\ 0)
+ ;;
+ $MODNAME\ *)
+ return 2
+ ;;
+ *)
+ echo -n "Invalid module parsing! "
+ return 1
+ ;;
+ esac
+
+ echo -n "Unloading module \"$MODNAME\": "
+ modprobe -rs "$MODNAME"
+ if [ "$?" != 0 ]
+ then
+ echo "Unable to unload module \"$MODNAME\"" >&2
+ return 1
+ fi
+
+ return 0
+}
+
+#
+# check_load_module()
+#
+# 0 is not loaded, 1 is error, 2 is already loaded
+#
+check_load_module()
+{
+ if [ "$#" -lt "1" -o -z "$1" ]
+ then
+ echo "check_load_module(): Requires an argument" >&2
+ return 1
+ fi
+ MODNAME="$1"
+
+ echo -n "Module \"$MODNAME\": "
+ MODOUT="`awk '$1 ~ /^'$MODNAME'$/{print $1,$3;exit}' < /proc/modules 2>/dev/null`"
+ if [ -z "$MODOUT" ]
+ then
+ echo "Not loaded"
+ return 0
+ fi
+ echo "Loaded"
+ return 2
+}
+
+
+#
+# mount_fs()
+# Mount a filesystem.
+#
+# 0 is success, 1 is error, 2 is already mounted
+#
+mount_fs()
+{
+ TYPE="$1"
+ FULL_MOUNT="$2"
+ FULL_MOUNTSEARCH="`echo "$FULL_MOUNT" | sed -e 's/\//\\\\\//g'`"
+ MOUNTOUT="`awk '$2 ~ /^'$FULL_MOUNTSEARCH'$/{print $2; exit}' < /proc/mounts 2>/dev/null`"
+
+ if [ -n "$MOUNTOUT" ]
+ then
+ return 2
+ fi
+
+ # XXX some policy?
+ if [ ! -e "$FULL_MOUNT" ]; then
+ make_dir $FULL_MOUNT
+ if_fail "$?"
+ fi
+
+ echo -n "Mounting ${TYPE} filesystem at $FULL_MOUNT: "
+ mount -t ${TYPE} ${TYPE} $FULL_MOUNT
+ if [ $? != 0 ]
+ then
+ echo "Unable to mount ${TYPE} filesystem" >&2
+ return 1
+ fi
+
+ return 0
+}
+
+#
+# check_mount_fs()
+#
+# 0 is not mounted, 1 is error, 2 is already mounted
+#
+check_mount_fs()
+{
+ TYPE="$1"
+ FULL_MOUNT="$2"
+ FULL_MOUNTSEARCH="`echo "$FULL_MOUNT" | sed -e 's/\//\\\\\//g'`"
+ MOUNTOUT="`awk '$2 ~ /^'$FULL_MOUNTSEARCH'$/{print $2; exit}' < /proc/mounts 2>/dev/null`"
+
+ echo -n "Filesystem \"$TYPE\": "
+ if [ -n "$MOUNTOUT" ]
+ then
+ echo "Mounted"
+ return 2
+ fi
+ echo "Not mounted"
+ return 0
+}
+
+#
+# unmount_fs()
+# Unmount a filesystem
+#
+# 0 is success, 1 is error, 2 is not mounted
+#
+unmount_fs()
+{
+ TYPE="$1"
+ FULL_MOUNT="$2"
+ FULL_MOUNTSEARCH="`echo "$FULL_MOUNT" | sed -e 's/\//\\\\\//g'`"
+ MOUNTOUT="`awk '$2 ~ /^'$FULL_MOUNTSEARCH'$/{print $2; exit}' < /proc/mounts 2>/dev/null`"
+
+ if [ -z "$MOUNTOUT" ]
+ then
+ return 2
+ fi
+
+ echo -n "Unmounting ${TYPE} filesystem: "
+ umount $FULL_MOUNT
+ if [ $? != 0 ]
+ then
+ echo "Unable to unmount ${TYPE} filesystem" >&2
+ return 1
+ fi
+
+ return 0
+}
+
+load()
+{
+ for i in $(seq 0 $((${#LOAD_ACTIONS[*]} - 1)) ); do
+ eval ${LOAD_ACTIONS[i]}
+ if_fail "$?"
+ done
+}
+
+load_status()
+{
+ for i in $(seq 0 $((${#LOAD_ACTIONS[*]} - 1)) ); do
+ eval "check_${LOAD_ACTIONS[i]}"
+ done
+ return "$?"
+}
+
+online()
+{
+ CLUSTER="${1:-${O2CB_BOOTCLUSTER}}"
+ if [ -z "$CLUSTER" ]
+ then
+ echo "Cluster not known"
+ return
+ fi
+
+ check_online $CLUSTER
+ if [ $? = 2 ]
+ then
+ echo "Cluster ${CLUSTER} already online"
+ return
+ fi
+
+ if ! [ -f ${CLUSTERCONF} ]
+ then
+ echo -n "Checking cluster configuration : "
+ if_fail 1
+ fi
+
+ echo -n "Starting cluster ${CLUSTER}: "
+ OUTPUT="`o2cb_ctl -H -n "${CLUSTER}" -t cluster -a online=yes 2>&1`"
+ if [ $? = 0 ]
+ then
+ O2CB_HEARTBEAT_THRESHOLD_FILE_OLD=/proc/fs/ocfs2_nodemanager/hb_dead_threshold
+ O2CB_HEARTBEAT_THRESHOLD_FILE=$(configfs_path)/cluster/${CLUSTER}/heartbeat/dead_threshold
+ if [ -n "$O2CB_HEARTBEAT_THRESHOLD" ]; then
+ if [ -f "$O2CB_HEARTBEAT_THRESHOLD_FILE" ]; then
+ echo "$O2CB_HEARTBEAT_THRESHOLD" > "$O2CB_HEARTBEAT_THRESHOLD_FILE"
+ elif [ -f "$O2CB_HEARTBEAT_THRESHOLD_FILE_OLD" ]; then
+ echo "$O2CB_HEARTBEAT_THRESHOLD" > "$O2CB_HEARTBEAT_THRESHOLD_FILE_OLD"
+ else
+ echo "WARNING: Unable to set heartbeat dead threshold" >&2
+ fi
+ fi
+
+ echo "OK"
+ return
+ else
+ echo "Failed"
+ echo "$OUTPUT"
+ fi
+
+ echo -n "Stopping cluster ${CLUSTER}: "
+ OUTPUT="`o2cb_ctl -H -n "${CLUSTER}" -t cluster -a online=no 2>&1`"
+ if_fail "$?" "$OUTPUT"
+}
+
+#
+# check_online()
+#
+# 0 is not online, 1 is error, 2 is online
+#
+check_online()
+{
+ if [ "$#" -lt "1" -o -z "$1" ]
+ then
+ echo "check_online(): Requires an argument" >&2
+ return 1
+ fi
+ CLUSTER="$1"
+
+ RC=0
+ if [ -d "$(configfs_path)/cluster/${CLUSTER}/node/" ]
+ then
+ ls -1 "$(configfs_path)/cluster/${CLUSTER}/node/" | while read NODE
+ do
+ LOCAL="`cat \"$(configfs_path)/cluster/${CLUSTER}/node/${NODE}/local\"`"
+ if [ $LOCAL = 1 ]
+ then
+ return 2
+ fi
+ done
+ if [ $? = 2 ]
+ then
+ RC=2
+ fi
+ fi
+ return $RC
+}
+
+offline()
+{
+ CLUSTER="${1:-${O2CB_BOOTCLUSTER}}"
+ if [ -z "$CLUSTER" ]
+ then
+ return
+ fi
+
+ if [ ! -e "$(configfs_path)/cluster/${CLUSTER}" ]
+ then
+ return
+ fi
+
+ clean_heartbeat $CLUSTER
+
+ echo -n "Stopping cluster ${CLUSTER}: "
+ check_heartbeat $CLUSTER
+ if [ $? != 0 ]
+ then
+ echo "Failed"
+ echo "Unable to stop cluster as heartbeat region still active" >&2
+ fi
+
+ OUTPUT="`o2cb_ctl -H -n "${CLUSTER}" -t cluster -a online=no 2>&1`"
+ if_fail "$?" "$OUTPUT"
+
+ unload_module ocfs2
+ if_fail "$?"
+}
+
+start()
+{
+ if [ "$O2CB_ENABLED" != "true" ]
+ then
+ exit 0
+ fi
+
+ load
+ online "$1"
+}
+
+unload()
+{
+ if [ -d "$(configfs_path)/cluster/" ]
+ then
+ ls -1 $(configfs_path)/cluster/ | while read CLUSTER
+ do
+ echo "Unable to unload modules as Cluster ${CLUSTER} is still online" >&2
+ exit 1
+ done
+ if [ $? = 1 ]
+ then
+ exit 1
+ fi
+ fi
+
+ for i in $(seq $((${#LOAD_ACTIONS[*]} - 1)) -1 0); do
+ eval "un${LOAD_ACTIONS[i]}"
+ if_fail "$?"
+ done
+}
+
+stop()
+{
+ offline "$1"
+ unload
+}
+
+configure()
+{
+ configure_ask
+ write_sysconfig
+ if_fail "$?" "Unable to write the driver configuration"
+}
+
+status()
+{
+ load_status
+ if [ $? != 2 ]
+ then
+ return 0;
+ fi
+
+ CLUSTER="${1:-${O2CB_BOOTCLUSTER}}"
+ if [ -z "$CLUSTER" ]
+ then
+ return 1;
+ fi
+
+ echo -n "Checking cluster $CLUSTER: "
+ check_online $CLUSTER
+ if [ $? = 2 ]
+ then
+ echo "Online"
+ else
+ echo "Offline"
+ return 0;
+ fi
+
+ echo -n "Checking heartbeat: "
+ check_heartbeat $CLUSTER
+ if [ $? = 2 ]
+ then
+ echo "Active"
+ else
+ echo "Not active"
+ return 0;
+ fi
+
+ return
+
+ echo -n "Checking if O2CB is loaded: "
+ RC=0
+ for MODSPEC in $MODULE_LIST
+ do
+ MODULE_NAME="`echo $MODSPEC | cut -d: -f1`"
+ FSTYPE="`echo $MODSPEC | cut -d: -f2`"
+ MOUNT_POINT="`echo $MODSPEC | cut -d: -f3`"
+
+ if grep "^${MODULE_NAME} " /proc/modules >/dev/null 2>&1
+ then
+ echo -n "${MODULE_NAME} "
+ else
+ RC=1
+ break
+ fi
+ done
+ if_fail "$RC"
+
+ echo -n "Checking O2CB mount points: "
+ for MODSPEC in $MODULE_LIST
+ do
+ MODULE_NAME="`echo $MODSPEC | cut -d: -f1`"
+ FSTYPE="`echo $MODSPEC | cut -d: -f2`"
+ MOUNT_POINT="`echo $MODSPEC | cut -d: -f3`"
+
+ if [ -z "$FSTYPE" -o -z "$MOUNT_POINT" ]
+ then
+ continue
+ fi
+
+ FULL_MOUNT="${O2CB_MANAGER}/${MOUNT_POINT}"
+ FULL_MOUNTSEARCH="`echo "$FULL_MOUNT" | sed -e 's/\//\\\\\//g'`"
+ if grep "^${FSTYPE} ${FULL_MOUNTSEARCH} ${FSTYPE}" /proc/mounts >/dev/null 2>&1
+ then
+ echo -n "${MOUNT_POINT} "
+ else
+ RC=1
+ break
+ fi
+ done
+ if_fail "$RC"
+}
+
+
+
+case "$1" in
+ start)
+ start "$2"
+ ;;
+
+ status)
+ status "$2"
+ ;;
+
+ stop)
+ stop "$2"
+ ;;
+
+ restart)
+ stop "$2"
+ start "$2"
+ ;;
+
+ force-reload)
+ stop "$2"
+ start "$2"
+ ;;
+
+ load)
+ load
+ ;;
+
+ online)
+ load
+ online "$2"
+ ;;
+
+ offline)
+ offline "$2"
+ ;;
+
+ unload)
+ offline "$2"
+ unload
+ ;;
+
+ configure)
+ configure
+ if [ "$O2CB_ENABLED" = "true" ]
+ then
+ start
+ else
+ stop
+ fi
+ ;;
+
+ enable)
+ O2CB_ENABLED=true
+ write_sysconfig
+ if_fail "$?" "Unable to write the driver configuration"
+ start
+ ;;
+
+ disable)
+ O2CB_ENABLED=false
+ write_sysconfig
+ if_fail "$?" "Unable to write the driver configuration"
+ stop
+ ;;
+
+ *)
+ echo "Usage: $0 {start|stop|restart|force-reload|enable|disable|configure|load|unload|online|offline|status}"
+ exit 1
+ ;;
+esac
+
+exit 0