Release new version 0.105.0
[grml-terminalserver.git] / grml-terminalserver
index 7b990d2..1314205 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 # Filename:      terminalserver
 # Purpose:       Program to do something
 # Authors:       grml-team (grml.org), (c) Michael Gebetsroither <gebi@grml.org>
@@ -20,6 +20,7 @@
 ### __VARIABLES
 ###
 
+FORCE_='false'
 verbose_=0
 
 # this file holds all variable definitions
@@ -37,41 +38,76 @@ function printUsage
   cat <<EOT
 Usage: "$PROG_NAME__" [OPTIONS] <command>
 
-$PROG_NAME__ is the config program for the terminalserver
-comming with grml.
+$PROG_NAME__ is the configuration program for the terminalserver
+provided by Grml.
 
 COMMANDS:
    help             This help text
-   start <service>  Start services
+   start <service>  Start services (if all services are started, configs will be updated)
    stop <service>   Stop services
+   config <service> Update config of given service (or from all if no services given)
    clean            Stop all + remove config and boot files from services
    <default>        interactive
 
 SERVICES:
   tftp        Tftp daemon
   dhcp        Dhcp daemon
+  ipt         Iptables setup (snat for clients)
   nfs         All necessary nfs daemons
   <>          ALL services
-  
+
 OPTIONS:
    -v         verbose (show what is going on, v++)
    -h         this help text
+   -f         Force
 
 EOT
 }
 
+function killPortmapper
+{
+  if [ -f /etc/init.d/portmap ] ; then
+    /etc/init.d/portmap stop >/dev/null &>/dev/null
+  elif [ -f /etc/init.d/rpcbind ] ; then
+    /etc/init.d/rpcbind stop >/dev/null &>/dev/null
+  fi
+  killall -9 portmap &>/dev/null
+  killall -9 rpcbind &>/dev/null
+}
 
 # DHCP SERVICE {{{
 function createDhcpConf
 {
-  execute "mv -fb \"$DHCPD_CONFIG_FILE_\" \"$DHCPD_CONFIG_FILE_.old\"" eprint &>/dev/null
-
-  execute "source $TEMPLATE_CONFIG_DIR_/dhcpd_config" die
+  if [ -e "$DHCPD_CONFIG_FILE_" ]; then
+    if grep $CONFIG_PATTERN_ $DHCPD_CONFIG_FILE_ &>/dev/null; then
+      execute "mv -fb \"$DHCPD_CONFIG_FILE_\" \"$DHCPD_CONFIG_FILE_.old\"" eprint &>/dev/null
+      execute "source $TEMPLATE_CONFIG_DIR_/dhcpd_config" die
+    else
+      if [[ $FORCE_ == "true" ]]; then
+        execute "mv -fb \"$DHCPD_CONFIG_FILE_\" \"$DHCPD_CONFIG_FILE_.old\"" eprint &>/dev/null
+        execute "source $TEMPLATE_CONFIG_DIR_/dhcpd_config" die
+      else
+        warn "Not updating user edited configfile $DHCPD_CONFIG_FILE_, user -f to override"
+      fi
+    fi
+  else
+    execute "source $TEMPLATE_CONFIG_DIR_/dhcpd_config" die
+  fi
 }
 
 function removeDhcpConf
 {
-  rm -f "$DHCPD_CONFIG_FILE_"
+  if [ -e "$DHCPD_CONFIG_FILE_" ]; then
+    if grep $CONFIG_PATTERN_ $DHCPD_CONFIG_FILE_ &>/dev/null; then
+      rm -f "$DHCPD_CONFIG_FILE_"
+    else
+      if [[ $FORCE_ == "true" ]]; then
+        rm -f "$DHCPD_CONFIG_FILE_"
+      else
+        warn "Not deleting user edited configfile $DHCPD_CONFIG_FILE_, user -f to override"
+      fi
+    fi
+  fi
 }
 
 
@@ -79,17 +115,23 @@ function stopDhcp
 {
   start-stop-daemon --stop --quiet --pidfile "$DHCPD_PID_"
   rm -f $DHCPD_PID_
-  rm -f /var/lib/dhcp3/dhcpd.leases* 2>/dev/null    #FIXME
-  touch /var/lib/dhcp3/dhcpd.leases
+  # ugly but necessary :-/
+  find  /var/lib/dhcp* -type f -name dhcpd.leases -delete
+  local dhcpdir
+  for dhcpdir in /var/lib/dhcp* ; do
+    touch ${dhcpdir}/dhcpd.leases
+  done
 }
+
 function startDhcp
 {
   local conf_file_="$DHCPD_CONFIG_FILE_"
-  
+
   test -f $DHCPD_BIN_ || die "could not find dhcpd \"$DHCPD_BIN_\""
   start-stop-daemon --start --quiet --pidfile "$DHCPD_PID_" \
     --exec "$DHCPD_BIN_" -- -cf "$conf_file_" -q "$INTERFACE_" || warn "problems starting dhcpd"
 }
+
 function runDhcp
 {
   isExistent "$DHCPD_CONFIG_FILE_" || \
@@ -101,6 +143,62 @@ function runDhcp
 }
 # }}}
 
+# IPTABLES {{{
+function runIptables
+{
+  if [[ $IPTABLES_SNAT_ != "true" ]]; then
+    return
+  fi
+  startIptables
+}
+
+function startIptables
+{
+  if [ -x $(command -v iptables) ] ; then
+    if [[ $NAT_INTERFACE_ != "" ]]; then
+       local nat_source_ip_=`netGetIp "$NAT_INTERFACE_" warn`
+
+       if iptables -t nat -vnL POSTROUTING | grep -q "SNAT.*${NAT_INTERFACE_}.*to:${nat_source_ip_}" ; then
+          echo "Rule for SNAT already present, nothing to be done."
+       else
+          echo "Setting up SNAT for terminalserver clients on ${NAT_INTERFACE_}:"
+          echo    "* iptables -t nat -F POSTROUTING"
+          echo -n "* iptables -t nat -A POSTROUTING -o $NAT_INTERFACE_ -j SNAT --to-source $nat_source_ip_ ... "
+          { iptables -t nat -F POSTROUTING && \
+            iptables -t nat -A POSTROUTING -o "$NAT_INTERFACE_" -j SNAT --to-source "$nat_source_ip_" ; } && \
+            echo done || echo failed
+       fi
+       if [ `cat /proc/sys/net/ipv4/ip_forward` -eq 1 ]; then
+          echo "IP-Forwarding already enabled, nothing to be done."
+       else
+          echo -n "Enabling IP-Forwarding: "
+          echo 1 > /proc/sys/net/ipv4/ip_forward && echo done || echo failed
+       fi
+    fi
+  else
+    warn "iptables executable not available"
+  fi
+}
+
+function stopIptables
+{
+  if [[ $IPTABLES_SNAT_ != "true" ]]; then
+    return
+  fi
+  if [ -x $(command -v iptables) ] ; then
+    if [[ $NAT_INTERFACE_ != "" ]]; then
+       local nat_source_ip_=`netGetIp "$NAT_INTERFACE_" warn`
+
+       if iptables -t nat -vnL POSTROUTING | grep -q "SNAT.*${NAT_INTERFACE_}.*to:${nat_source_ip_}" ; then
+         iptables -t nat -F POSTROUTING &>/dev/null && \
+           iptables -t nat -D POSTROUTING -o "$NAT_INTERFACE_" -j SNAT --to-source "$nat_source_ip_"
+       fi
+       echo 0 > /proc/sys/net/ipv4/ip_forward
+    fi
+  fi
+}
+# }}}
+
 # TFTP SERVICE {{{
 function removeTftpConf
 {
@@ -109,26 +207,35 @@ function removeTftpConf
 function createTftpConf
 {
   removeTftpConf
-  
-  execute "mkdir $TFTPD_DATA_DIR_/pxelinux.cfg" die
-  execute "install -m 644 /usr/lib/syslinux/pxelinux.0 $TFTPD_DATA_DIR_" die
-  execute "install -m 644 $PATH_/minirt26.gz $TFTPD_DATA_DIR_" die
-  execute "install -m 644 $KERNEL_IMAGE_ $TFTPD_DATA_DIR_/linux26" die
-  execute "install -m 644 $MEMTEST_IMAGE_ $TFTPD_DATA_DIR_/memtest" die
+
+  execute "mkdir -p $TFTPD_DATA_DIR_/pxelinux.cfg" die
+  if [ -r /usr/lib/PXELINUX/pxelinux.0 ] ; then
+    execute "install -m 644 /usr/lib/PXELINUX/pxelinux.0 $TFTPD_DATA_DIR_" die
+  else # older versions of syslinux-common (<= 2:4.05+dfsg-6+deb7u1):
+    execute "install -m 644 /usr/lib/syslinux/pxelinux.0 $TFTPD_DATA_DIR_" die
+  fi
+  if [ -d "$MOUNT_POINT_"/boot/release ] ; then
+    cp -r "$MOUNT_POINT_"/boot/release "$TFTPD_DATA_DIR_"
+  fi
+  [ -f "$MEMTEST_IMAGE" ] && execute "install -m 644 $MEMTEST_IMAGE_ $TFTPD_DATA_DIR_/memtest" die
   execute "install -m 644 $PXE_BOOT_MSG_ $TFTPD_DATA_DIR_" die
-  execute "install -m 644 $PXE_BOOT_LOGO_ $TFTPD_DATA_DIR_" die
+  [ -f "$PXE_BOOT_LOGO_" ] && execute "install -m 644 $PXE_BOOT_LOGO_ $TFTPD_DATA_DIR_" die
 
+  # PXE / BIOS boot (pxelinux)
   execute "source $TEMPLATE_CONFIG_DIR_/grub-pxelinux_config" die
+
+  # PXE / EFI boot (GRUB)
+  execute "source $TEMPLATE_CONFIG_DIR_/grub-shim_config" die
 }
 
 function stopTftp
 {
-  start-stop-daemon --stop --quiet --name "${TFTPD_BIN_##*/}"
+  start-stop-daemon --stop --quiet -p "$TFTPD_PID_" --user nobody
 }
 function startTftp
 {
   test -f $TFTPD_BIN_ || die "could not find \"$TFTPD_BIN_\""
-  start-stop-daemon --start --quiet --exec "$TFTPD_BIN_" -- -l -a "$IP_" -s "$TFTPD_DATA_DIR_" || \
+  start-stop-daemon --start --quiet --exec "$TFTPD_BIN_" -- --daemon --no-multicast --pidfile "$TFTPD_PID_" --bind-address "$IP_" "$TFTPD_DATA_DIR_" || \
     warn "problems starting tftpd server"
 }
 function runTftp
@@ -141,36 +248,45 @@ function runTftp
 
 
 # NFS  {{{
+function createNfsConfig
+{
+  execute "exportfs -o ro,no_root_squash,async,nohide,fsid=42 $NETWORK_/$NETMASK_:$MOUNT_POINT_" warn
+}
+
+function removeNfsConfig
+{
+  execute "exportfs -u -o ro,no_root_squash,async,nohide,fsid=42 $NETWORK_/$NETMASK_:$MOUNT_POINT_" warn
+}
+
 function startNfs
 {
-  /etc/init.d/portmap start
+  if [ -f /etc/init.d/portmap ] ; then
+    /etc/init.d/portmap start
+  elif [ -f /etc/init.d/rpcbind ] ; then
+    /etc/init.d/rpcbind start
+  else
+    echo "Warning: Could not start portmapper/rpcbind" >&2
+  fi
   /etc/init.d/nfs-common start
   # FIXME /etc/init.d/nfs-kernel-server start
   $USR_SHARE_/nfs-kernel-server start
+  echo
 
-  # FIXME Silly "/etc/init.d/nfs-kernel-server start"
-  # FIXME #246904 (init script does not start if no exports in /etc/exports)
-  execute "exportfs -o ro,no_root_squash,async,nohide $NETWORK_/$NETMASK_:$MOUNT_POINT_" warn
-  #execute "echo -e \"\n$MOUNT_POINT_   $NETWORK_/$NETMASK_(ro,no_root_squash,async)\" >> /etc/exports" warn
+  createNfsConfig
 }
 function stopNfs
 {
-  execute "exportfs -u -o ro,no_root_squash,async,nohide $NETWORK_/$NETMASK_:$MOUNT_POINT_" warn
+  removeNfsConfig
   if [[ `exportfs |wc -l` > 0 ]]; then
     dprint "There are other exports, not stopping NFS serivces"
   else
     /etc/init.d/nfs-kernel-server stop >/dev/null 2>&1
     /etc/init.d/nfs-common stop >/dev/null 2>&1
-    /etc/init.d/portmap stop >/dev/null 2>&1
+    killPortmapper
   fi
 }
 # }}}
 
-function allreadyConfigured
-{
-  isExistent "$CONF_FILE_" dprint || return 1
-  return 0
-}
 
 function createConfig
 {
@@ -185,22 +301,24 @@ function createConfig
 function actionStart
 {
   createConfig
-  
-  echo -n "Starting tftpd..."
-  runTftp
-  echo "done"
-  echo -n "Starting dhcpd..."
-  runDhcp
-  echo "done"
-  echo -n "Starting nfs..."
-  startNfs
-  echo "done"
+
+  echo -n "Starting tftpd: "
+  runTftp && echo done || echo failed
+
+  echo -n "Starting dhcpd: "
+  runDhcp && echo done || echo failed
+
+  runIptables
+
+  echo "Finally starting nfs services..."
+  startNfs && echo "Successfully finished startup of grml-terminalserver." || echo 'Startup of grml-terminalserver failed!'
 }
 
 function actionStop
 {
   stopTftp
   stopDhcp
+  stopIptables
   stopNfs
   notice "Terminal-server stopped"
 }
@@ -213,6 +331,19 @@ function actionClean
   stopNfs
 }
 
+function updateConfig
+{
+  local service_="$1"
+
+  case "$service_" in
+    "") createConfig ;;
+    tftp) createTftpConf ;;
+    dhcp) createDhcpConf ;;
+    nfs) removeNfsConfig; createNfsConfig ;;
+    *) warn "Service $service_ not available" ;;
+  esac
+}
+
 # SERVICES {{{
 function serviceStart
 {
@@ -222,6 +353,7 @@ function serviceStart
     "") actionStart ;;
     tftp) runTftp ;;
     dhcp) runDhcp ;;
+    ipt) startIptables ;;
     nfs) startNfs ;;
     *) warn "Service $service_ not available" ;;
   esac
@@ -235,6 +367,7 @@ function serviceStop
     "") actionStop ;;
     tftp) stopTftp ;;
     dhcp) stopDhcp ;;
+    ipt) stopIptables ;;
     nfs) stopNfs ;;
     *) warn "Service $service_ not available" ;;
   esac
@@ -245,8 +378,9 @@ function serviceStop
 ### __MAIN
 ###
 
-while getopts "i:hv" opt; do
+while getopts "fi:hv" opt; do
   case "$opt" in
+    f) FORCE_='true' ;;
     h) printUsage; exit ;;
     v) let verbose_=$verbose_+1 ;;
     ?) printUsage; exit 64 ;;
@@ -267,20 +401,18 @@ isExistent $DEFAULT_CONFIG_ die
 . $CONFIG_
 # used config vars:
 # MOUNT_POINT_
-# KERNEL_IMAGE_
 # MEMTEST_IMAGE_
 # PXE_BOOT_MSG_
 # PXE_BOOT_LOGO_
-if [[ $MOUNT_POINT_ == "" || $KERNEL_IMAGE_ == "" || $MEMTEST_IMAGE_ == "" || \
+if [[ $MOUNT_POINT_ == "" || $MEMTEST_IMAGE_ == "" || \
   $PXE_BOOT_MSG_ == "" || $PXE_BOOT_MSG_ == "" ]]; then
   warn "MOUNT_POINT_=\"$MOUNT_POINT_\" \
-KERNEL_IMAGE_=\"$KERNEL_IMAGE_\" \
 MEMTEST_IMAGE_=\"$MEMTEST_IMAGE_\"
 PXE_BOOT_MSG_=\"$PXE_BOOT_MSG_\"
 PXE_BOOT_LOGO_=\"$PXE_BOOT_LOGO_\""
   die "False configuration, please update $CONFIG_"
 fi
-  
+
 case "$1" in
   clean) actionClean; exit 0 ;;
 esac
@@ -294,7 +426,7 @@ while true; do
       "grml-terminalserver-config returned an error, do you want to quit now?" 5 75 && exit 1
   else
     break
-  fi  
+  fi
 done
 source $CONF_FILE_
 
@@ -306,9 +438,9 @@ if [ "$1" == 'start' ]; then
   esac
 fi
 if [ $check_necessary_files_ == 'yes' ]; then
-  # test for files absolutly necessary for grml-terminalserver and created from -config
+  # test for files absolutely necessary for grml-terminalserver and created from -config
   problem_=0
-  for i in $PATH_/minirt26.gz; do
+  for i in $PATH_/initrd.img; do
     isExistent $i warn || problem_=1
   done
   if [ $problem_ -eq 1 ]; then
@@ -320,10 +452,11 @@ fi
 case "$1" in
   start) serviceStart "$2" ;;
   stop) serviceStop "$2" ;;
+  config) updateConfig "$2" ;;
   "")  actionStart ;;
   *)  printUsage ;;
 esac
 
 # END OF FILE
 ################################################################################
-# vim:foldmethod=marker
+# vim:foldmethod=marker tabstop=2 expandtab shiftwidth=2