#!/bin/bash

PROGRAM=/bin/false
RUNLEVEL=3
NEEDS="+network +portmap"

. /etc/init.d/smgl_init
. /etc/sysconfig/nfs

if [[ ! -e /etc/exports ]]; then
  $FAILURE
  echo "Please create an /etc/exports file. Exiting without starting nfs..."
  $NORMAL
  exit 1
fi

if [[ -e /usr/sbin/rpc.idmapd ]]; then
  HASNFS4=1
fi

# pseudo fs stuff
mount_nfsd()
{
  if grep -q 'nfsd' /proc/filesystems; then
    if ! grep -q 'nfsd' /etc/mtab; then
      required_executable /bin/mount
      echo "mounting nfsd"
      mount -t nfsd nfsd /proc/fs/nfsd
      evaluate_retval
    fi
  fi
}
umount_nfsd()
{
  if grep -q 'nfsd' /etc/mtab; then
    required_executable /bin/umount
    echo "unmounting nfsd"
    umount /proc/fs/nfsd
    evaluate_retval
  fi
}
mount_pipefs()
{
  if grep -q 'rpc_pipefs' /proc/filesystems; then
    if ! grep -q 'rpc_pipefs' /etc/mtab; then
      required_executable /bin/mount
      echo "mounting pipefs"
      mount -t rpc_pipefs rpc_pipefs /var/lib/nfs/rpc_pipefs
      evaluate_retval
    fi
  fi
}
umount_pipefs()
{
  if grep -q 'rpc_pipefs' /etc/mtab; then
    required_executable /bin/umount
    echo "unmounting pipefs"
    umount /var/lib/nfs/rpc_pipefs
    evaluate_retval
  fi
}

# for making sure these exist
mknfsdirs() {
  local d
  for d in /var/lib/nfs/{rpc_pipefs,v4recovery,v4root}; do
    [[ ! -d "${d}" ]] && mkdir -p "${d}"
  done
}

# may be outsourced
get_kernel_pids()
{
  local rval=1
  for pid in $(pidof $1)
  do
    if [[ -z $(</proc/$pid/cmdline) ]]; then
      builtin echo $pid
      rval=0
    fi
  done
  return $rval
}

start()
{
  local bins
  echo "Starting NFS services (client & server)"

  bins="statd nfsd mountd"
  mount_nfsd
  if [[ ! -z $HASNFS4 ]]; then
    mknfsdirs
    mount_pipefs
    bins="${bins} idmapd"
  fi

  for b in $bins; do
    required_executable /usr/sbin/rpc.$b
  done

  # nfs-howto says: these daemons in this order
  # userspace does not bother about lockd since linux 2.2.18
  for d in ${bins} rquotad; do
    if [[ -x /usr/sbin/rpc.$d ]]; then
      local opts=

      if [[ $d == 'mountd' ]]; then
        opts="$MOUNTDOPTS"

        if [[ ! -z "$MOUNTD_PORT" ]]; then
          opts="$opts -p $MOUNTD_PORT"
        fi
      elif [[ $d == 'nfsd' ]]; then
        opts="$NUMSERVERS"
      elif [[ $d == 'statd' && ! -z $STATD_PORT ]]; then
        opts="-p $STATD_PORT"
      fi

      echo -n $d
      loadproc /usr/sbin/rpc.$d $opts
    fi
  done

  required_executable /usr/sbin/exportfs
  echo -n "exportfs"
  /usr/sbin/exportfs -r 
  evaluate_retval
}

stop()
{
  local bins
  echo "Stopping NFS services (client & server)"
  echo -n "unexporting filesystems"
  /usr/sbin/exportfs -au
  evaluate_retval

  bins="statd nfsd mountd"
  umount_nfsd
  if [[ ! -z $HASNFS4 ]]; then
    umount_pipefs
    bins="${bins} idmapd"
  fi

  for b in $bins; do
    required_executable /usr/sbin/rpc.$b
  done
  
  # all in one loop to simplify code, reversed order
  # atm. only nfsd is really in-kernel (and lockd self-managed)
  for d in ${bins} rquotad; do
    if [[ -x /usr/sbin/rpc.$d ]]; then
      local kpid=$(get_kernel_pids $d)

      if [[ -z $kpid ]]; then
        echo -n "killing $d"
        killproc /usr/sbin/rpc.$d
      else
        if [[ $d == 'nfsd' ]]; then
          echo "Removing kernel nfsd"
          /usr/sbin/rpc.nfsd 0
        else
          echo "not killing kernel $d (PID=${kpid})"
        fi
      fi
    fi
  done
}

status()
{
  for d in mountd nfsd statd rquotad
  do
    local kpid=$(get_kernel_pids $d)
    [[ -n $kpid ]] && echo "kernel $d there with PIDs $kpid" ||
    statusproc /usr/sbin/rpc.$d
  done
  echo -n "kernel lockd "
  kpid=$(get_kernel_pids lockd)
  [[ -n $kpid ]] && echo "is active (PID $kpid)" || echo "is not active (but hopefully ready)" 
}

restart()
{
  stop &&
  sleep 1 &&
  start
}
