#!/bin/sh
# Filename:      rebuildfstab
# Purpose:       calls scanpartitions as root and adds entries to /etc/fstab
# Authors:       grml-team (grml.org),  (c) Klaus Knopper Nov 2002, (c) Michael Prokop <mika@grml.org>
# Bug-Reports:   see http://grml.org/bugs/
# License:       This file is licensed under the GPL v2.
################################################################################
# This script is based on the package rebuildfstab-knoppix_0.5-4 of Klaus Knopper.
# (C) Klaus Knopper Nov 2002

logit() {
  if [ -x /usr/bin/logger ] ; then
     /usr/bin/logger -i -t rebuildfstab "$*"
  fi
}

bailout() {
   [ -n "$1" ] && EXITCODE="$1" || EXITCODE=1
   rm -f $TMP $TMPFILE /var/run/rebuildfstab.pid
   exit $EXITCODE
}

# exit if we have an already instance:
if [ -e /var/run/rebuildfstab.pid ] ; then
   pgrep rebuildfstab >/dev/null 2>&1 && bailout 0
fi

echo "$$" > /var/run/rebuildfstab.pid

[ ! -e /proc/partitions ] && {
  echo "$0: /proc not mounted, exiting" >&2
  logit "fatal - /proc not mounted, exiting"
  bailout 1
}

[ "`id -u`" != "0" ] && {
  exec sudo $0 "$@"
}

PATH="/bin:/sbin:/usr/bin:/usr/sbin"
MNTFILE="/mnt/.grml-auto-created_do-not-delete-this-file"
TMP=$(mktemp 2>/dev/null)
TMPFILE=$(mktemp 2>/dev/null)
ADDEDBYGRML="# Added by GRML"
umask 022

if ! [ -w "$(dirname $MNTFILE)" ] ; then
   echo "$0: can not write to $MNTFILE">&2
   logit "can not write to $MNTFILE"
   bailout 10
fi

if [ -z "$TMP" -o -z "$TMPFILE" ] ; then
   echo "$0: could not create tmpfile (is / mounted read-only?), exiting" >&2
   logit 'fatal - could not create tmpfile (is / mounted read-only?), exiting'
   bailout 3
fi

trap "rm -f $TMP $TMPFILE" 2 3 11

# check for bootoption nolabel to disable fs-label feature, but
# allow running 'LABEL=1 grml-rebuildfstab' even though booted with 'nolabel'
if [ -n "$LABEL" ] ; then
  LABEL=''
else
  grep -q 'nolabel' /proc/cmdline && LABEL='NOLABEL=1' || LABEL=''
fi

if grep -q " nofstab" /proc/cmdline ; then
   NO_FSTAB=1
   MESSAGE='bootoption nofstab found'
fi

if [ -r /etc/grml/autoconfig ] ; then
   if grep -qi '^CONFIG_FSTAB.*no' /etc/grml/autoconfig ; then
      NO_FSTAB=1
      MESSAGE='CONFIG_FSTAB=no in /etc/grml/autoconfig found'
   fi
fi

# make sure we have the $MNTFILE before reading/writing into it
[ -r $MNTFILE ] || touch $MNTFILE

# make sure we have a /etc/fstab at all
if ! [ -f /etc/fstab ] ; then
  cat > /etc/fstab << EOF
# /etc/fstab - static file system information
# <filesystem> <mountpoint>   <type> <options>                             <dump> <pass>
proc           /proc          proc   rw,nosuid,nodev,noexec                 0      0
none           /proc/bus/usb  usbfs  defaults,noauto                        0      0
sysfs          /sys           sysfs  rw,nosuid,nodev,noexec                 0      0
devpts         /dev/pts       devpts noauto,mode=0622                       0      0
/dev/fd0       /mnt/floppy    auto   user,noauto,exec                       0      0
/dev/external  /mnt/external  auto   user,noauto,exec,rw,uid=grml,gid=grml  0      0
/dev/external1 /mnt/external1 auto   user,noauto,exec,rw,uid=grml,gid=grml  0      0
/dev/cdrom     /mnt/cdrom     auto   user,noauto,exec,ro                    0      0
/dev/dvd       /mnt/dvd       auto   user,noauto,exec,ro                    0      0
# some other examples:
# /dev/hda1      /Grml         ext3    dev,suid,user,noauto 0  2
# //1.2.3.4/pub  /smb/pub      smbfs   defaults,user,noauto,uid=grml,gid=grml 0 0
# linux:/pub     /beer         nfs     defaults             0  0
# tmpfs          /tmp          tmpfs   size=300M            0  0
# none           /proc/bus/usb usbfs   defaults,nodev,noexec,nosuid,noauto,devgid=1001,devmode=664 0 0
# 192.168.1.101:/backups /mnt/nfs nfs  defaults,user,wsize=8192,rsize=8192 0 0
#
# Warning! Please do *not* change any lines below because they are auto-generated by rebuildfstab!
# If you want to disable rebuildfstab set CONFIG_FSTAB='no' in /etc/grml/autoconfig!
# See 'man grml-rebuildfstab' for more details about the following entries.
EOF
fi

[ ! -w /etc/fstab ] && {
  echo "$0: /etc/fstab not writeable, exiting" >&2
  logit "fatal - /etc/fstab not writeable, exiting"
  bailout 2
}

# Simple shell grep, searches for lines STARTING with string
stringinfile () {
  while read line ;do
    case "$line" in
            ($1*) return 0 ;;
    esac
  done < "$2"
  return 1
}

# Remove comment line $1 and the following line from file $2
# sed '/^# Added by GRML/{N;d;}'
removeentries () {
  while read line; do
    case "$line" in
            ($1) read line
                    continue ;;
    esac
    echo "$line"
  done < "$2"
}

verbose=""
remove=""
user=""
group=""
arg="$1"
while [ -n "$arg" ] ; do
  case "$arg" in
          (-v*) verbose="yes"  ;;
          (-r*) remove="yes"  ;;
          (-f*) force="yes"  ;;
          (-c*) config="yes" ;;
          (-u*) shift
                  user="$1"  ;;
          (-g*) shift
                  group="$1"  ;;
          (*) echo "Usage: $0 [-v[erbose]] [-config] [-r[emove_old]] [-u[ser] uid] [ -g[roup] gid]" ; bailout 4 ;;
  esac
  shift
  arg="$1"
done

logit "re-generating /etc/fstab - see 'man rebuildfstab'"

if [ -n "$config" ] ; then
   if [ -r /etc/grml/autoconfig ] ; then
      . /etc/grml/autoconfig
      if [ -n "$CONFIG_FSTAB_USER" ] ; then
         user="$CONFIG_FSTAB_USER"
      else
         user='1000' # take default
         logit 'warning: CONFIG_FSTAB_USER not set via /etc/grml/autoconfig but used option -config, assuming default'
      fi
      if [ -n "$CONFIG_FSTAB_GROUP" ] ; then
         group="$CONFIG_FSTAB_GROUP"
      else
         group='users' # take default
         logit 'warning: CONFIG_FSTAB_GROUP not set via /etc/grml/autoconfig but used option -config, assuming default'
      fi
   else
      logit 'warning: option -config found but /etc/grml/autoconfig could not be read'
   fi
fi

if [ -n "$NO_FSTAB" ] ; then
   if [ -z "$force" ] ; then
      echo "Warning: ${MESSAGE}, ignoring request to re-generate /etc/fstab without force option" >&2
      echo "Use the -f option to force re-generatation of /etc/fstab." >&2
      logit "${MESSAGE}, ignoring request to re-generate /etc/fstab without force option"
      bailout 5
   else
     echo "Warning: ${MESSAGE}, re-generating /etc/fstab anyway due to use of force option." >&2
   fi
fi

[ -n "$verbose" ] && echo "Scanning for new harddisks/partitions/devices." >& 2

if [ -n "$remove" ] ; then
   removeentries "$ADDEDBYGRML" /etc/fstab > "$TMP"
else
   cat /etc/fstab > "$TMP"
fi

count=0


$LABEL scanpartitions | while read device mountpoint fstype addinfo; do
        test -n "$mountpoint" || continue
        case :$alldevices: in
        *:$device:*) continue ;;
        esac
        alldevices=$alldevices:$device

        options=noauto,user,dev,suid,exec
        case $fstype in
        ntfs)
                options=$options,ro,umask=000
                ;;
        vfat|msdos)
                options=$options,umask=000
                ;;
        ufs)
                options=$options,ro
                ;;
        swap)
                options=defaults
                ;;
        esac
        case $fstype in
        ntfs|vfat|msdos)
                test -n "$user" && options=$options,uid=$user
                test -n "$group" && options=$options,gid=$group
                ;;
        esac
        echo $ADDEDBYGRML
        echo $device $mountpoint $fstype $options 0 0 $addinfo
        # printf "%-14s %-14s %-6s %-15s %-6s %s\n" "$device" "$mountpoint" "$fstype" "$options" "0" "0";
done >"$TMPFILE"
count=$(( $(wc -l <"$TMPFILE") / 2 ))
cat "$TMPFILE" >>"$TMP"

# Handling of CD-ROM devices
for cdrom in /dev/cdrom /dev/cdrom*[0-9] ; do
  stringinfile "$cdrom " "$TMP" || {
    [ -d "/mnt/cdrom${cdrom#*cdrom}" ] || mkdir -m 755 -p "/mnt/cdrom${cdrom#*cdrom}"
    echo "$ADDEDBYGRML" >> $TMP
    echo "$cdrom /mnt/cdrom${cdrom#*cdrom} auto user,noauto,exec,ro 0 0" >> $TMP
  }
done

# Handling of DVD devices
for dvd in /dev/dvd /dev/dvd*[0-9] ; do
  stringinfile "$dvd " "$TMP" || {
    [ -d "/mnt/dvd${dvd#*dvd}" ] || mkdir -m 755 -p "/mnt/dvd${dvd#*dvd}"
    echo "$ADDEDBYGRML" >> $TMP
    echo "$dvd /mnt/dvd${dvd#*dvd} auto user,noauto,exec,ro 0 0" >> $TMP
  }
done

# Handling of external USB devices (handled by grml's udev)
for usb in `ls /dev/usb-sd[a-z] /dev/usb-sd*[0-9] 2>/dev/null` ; do
  stringinfile "$usb " "$TMP" || {
    if ! [ -d "/mnt/usb${usb#*usb}" ] ; then
      if mkdir -m 755 -p "/mnt/usb${usb#*usb}" ; then
         [ -r "$MNTFILE" ] && grep -q "/mnt/usb${usb#*usb}" $MNTFILE || echo "/mnt/usb${usb#*usb}" >> $MNTFILE
      fi
    fi
    echo "$ADDEDBYGRML" >> $TMP
    echo "$usb /mnt/usb${usb#*usb} auto user,noauto,nodev,noatime,nosuid,noexec,rw,uid=$user,gid=$user 0 0" >> $TMP
  }
done

[ -n "$verbose" ] && {
  [ "$count" -gt 0 ] && echo "Adding $count new partitions to /etc/fstab." >&2 || echo "No new partitions found." >&2
}

# make sure we have a backup
if ! cp /etc/fstab /etc/fstab.grmlrebuildfstab.old ; then
   echo "Fatal: can not create backup of /etc/fstab, exiting therefor." >&2
   logit "fatal - can not create backup of /etc/fstab, exiting"
   bailout 6
fi

# first clean up old fstab.local entry
sed -i '/# Begin of fstab.local/,/# End of fstab.local/ d' $TMP

if [ -r /etc/fstab.local ]; then
   [ -n "$verbose" ] && echo "/etc/fstab.local found, adding to /etc/fstab." >& 2
   echo "# Begin of fstab.local" >> $TMP
   cat /etc/fstab.local >> $TMP
   echo "# End of fstab.local" >> $TMP
fi

if grep -q '/etc/fstab' $TMP ; then
   cp -f "$TMP" /etc/fstab
else
   logit "fatal: keyword /etc/fstab not found in file /etc/fstab, assuming a corrupt file"
   echo "fatal: keyword /etc/fstab not found in file /etc/fstab, assuming a corrupt file">&2
   bailout 7
fi

# Clean /mnt/... according to info $MNTFILE
if [ -r "$MNTFILE" ] ; then
   [ -n "$verbose" ] && echo "Clean up /mnt/* directories as defined in ${MNTFILE}." >& 2
   for directory in $(cat $MNTFILE) ; do
     rmdir $directory 2>/dev/null && sed -i "s#$directory##" $MNTFILE
   done
   grep '^/.*$' $MNTFILE | sort -u > $TMPFILE
   cat $TMPFILE > $MNTFILE
fi

# Make sure we have all /mnt/* directories
[ -n "$verbose" ] && echo "Creating directories in /mnt/... based on /etc/fstab entries." >&2
while read p m f relax; do
  case "$m" in *none*|*proc*|*sys*|'') continue ;; esac
  if ! grep -q "$m" /proc/mounts ; then
     if ! [ -d "$m" ] ; then
        if mkdir -m 755 -p "$m" ; then
          [ -r "$MNTFILE" ] && grep -q "$m" $MNTFILE || echo "$m" >> $MNTFILE
        fi
     fi
  fi
done <<EOT
$(cat /etc/fstab | grep -v '^#')
EOT

# sort the file again...
if [ -r "$MNTFILE" ] ; then
   grep '^/.*$' $MNTFILE | sort -u > $TMPFILE
   cat $TMPFILE > $MNTFILE
fi

bailout 0

## END OF FILE #################################################################
