#!/bin/bash
#
# filesystems - filesystems plugin for postplug
# Copyright (c) 2004-2007 by Davide Madrisan <davide.madrisan@qilinux.it>
# Copyright (c) 2007 by Stefano Cotta Ramusino <stefano.cotta@openmamba.org>
# Copyright (c) 2009-2013 by Silvan Calarco <silvan.calarco@mambasoft.it>

if [ $UID != 0 ]; then
   echo "$0: must be superuser." >&2
   exit 1
fi

me="filesystems"
rootmp="/mnt"

. /etc/postplug/postplug.defs

[ -r /etc/sysconfig/postplug ] && . /etc/sysconfig/postplug

fstab="/etc/fstab"

# list of known devices to be scanned
# note: the '/dev/floppy/[0-9]' and '/dev/ub[a-z][0-9]*' entries
#       has been removed
devs2scan='/dev/disk/by-uuid/*'

# function get_new_mp_name()
#    Find for a usable mount point in the form $rootmp/$1[0-9]*
#    or the current mount point if the device `$2' is already mounted
# args:
#    $1: mount point suffix (i.e. "cdrom", "floppy", ...)
#    $2: the device name (optional)
function get_new_mp_name() {
   local mp_suffix="${1/ /%20}"; devfs="$2"

   if [ -n "$devfs" ]; then
      # catch internal errors
      [ -e $devfs ] ||
       { logmsg "$me" $"error: ""device not found ($devfs)"
         exit 1; }
      # take care of root partition already mounted
      [ "`readlink -f /dev/root`" = "$devfs" ] && {
         echo "/"
	 return
      }
      set -- $(mount | grep "^$(readlink -f $devfs)")
      if [ "$3" != "" ]; then
         echo "$3"
         return
      fi
   fi

   # mountpoint FHS 2.3 compliant
   case "$1" in cdrom|floppy) rootmp="/media" ;; esac

   for dir in $(find "$rootmp/${mp_suffix}" "$rootmp/${mp_suffix}"[0-9]* \
      -maxdepth 0 -type d -printf "%f " 2>/dev/null); do
      # if `$dir' is not found in `$fstab' and
      # no fs has been manually mounted on this dir...
      [[ -z "$(grep "[[:space:]]$rootmp/$dir[[:space:]]" $fstab)" &&
         -z "$(mount | grep "[[:space:]]$rootmp/$dir[[:space:]]")" ]] &&
       { # ...we have found a good dir not yet used
         echo "$rootmp/$dir"; return; }
   done
   # no directory available, so a new one must be created
   case "$dir" in
   "") echo ""$rootmp/${mp_suffix}"" ;;
   $mp_suffix|$mp_suffix[0-9]*)
      # note: ${mp_suffix}<n> --> $rootmp/${mp_suffix}<n+1>
      echo "$rootmp/\
${dir/[0-9]*/}$((${dir/$mp_suffix/}+1))" ;;
   esac
}

if [ -d /run/systemd ]; then
   # With systemd only manage swap and disable everything else
   unset FS_FLOPPY_UPDATE FS_CDROM_UPDATE FS_VFS_UPDATE FS_NODEV_REMOVE FS_PARTS_UPDATE FS_PARTS_MOUNT
fi

tmpfstab=`mktemp -q -t $me.XXXXXXXX` ||
 { logmsg "$me" $"error: "$"cannot create temporary files"
   exit 1; }

trap "rm -f $tmpfstab" 0 1 2 5 15

# note: remove some directories not FHS 2.3 compliant
#find /mnt/ -type d \( \
#   -name floppy -o -name floppy[0-9]\* -o \
#   -name cdrom -o -name cdrom[0-9]\* \
#   -name cdrecording -o -name cdrecording[0-9]\* \
#\) -print | xargs rmdir 2>/dev/null

if [ "$FS_VFS_UPDATE" = "yes" ]; then
   # note: '[ \t]\+/proc[ \t]\+' does not work :(
   grep -q "/proc" $fstab 2>/dev/null ||
    { echo "proc /proc proc defaults 0 0" >> $fstab
      logmsg "$me" $"added an entry for \`proc' in $fstab"
      mount /proc &>/dev/null; }

   grep -q "/sys" $fstab 2>/dev/null ||
    { echo "none /sys sysfs defaults 0 0" >> $fstab
      logmsg "$me" $"added an entry for \`sys' in $fstab"
      mount /sys &>/dev/null; }

   grep -q "/dev/pts" $fstab 2>/dev/null ||
    { echo "devpts /dev/pts devpts gid=4,mode=620 0 0" >> $fstab
      logmsg "$me" $"added an entry for \`devpts' in $fstab"
      mount /dev/pts &>/dev/null; }

   # make sure directory /dev/shm still exists
   mkdir -p /dev/shm

   grep -q "/dev/shm" $fstab 2>/dev/null ||
    { echo "tmpfs /dev/shm tmpfs defaults 0 0" >> $fstab
      logmsg "$me" $"added an entry for \`tmpfs' in $fstab"
      mount /dev/shm &>/dev/null; }

   # probe for USB if the entry were not present in /etc/fstab
   if [ -d /proc/bus/usb ]; then
      grep -q "/proc/bus/usb" $fstab 2>/dev/null ||
       { echo "usbfs /proc/bus/usb usbfs devgid=30,devmode=664 0 0" >> $fstab
         logmsg "$me" $"added an entry for \`usbfs' in $fstab"
         mount /proc/bus/usb &>/dev/null; }
   fi
fi


if [ "$FS_NO_DEV_REMOVE" = "yes" ]; then
   [ -e $fstab ] && cp $fstab $tmpfstab || touch $fstab
   while read fs mount_point fstype options dump fsck_order ignore; do
      case $fs in
      /dev/*)
         # remove entries and mount points for nonexistent devices
         if [[ ! -e $fs ]]; then
            sed -i "\@^$fs[ \t]*@d" $fstab 2>/dev/null
            logmsg "$me" $"nonexistent entry removed (fs:$fs mp:$mount_point)"
            rmdir $mount_point 2>/dev/null
            continue
         fi
         [ ! -e $mount_point -a ${mount_point:0:${#rootmp}} = ${rootmp} ] && mkdir -p $mount_point

         ## if `/dev/root' exists use it instead of the real device name
         #[[ "$mount_point" = "/" && -e /dev/root ]] &&
         # { unset devlink; fs="/dev/root"; }
         ;;
      UUID=*)
         # remove entries and mount points for nonexistent devices
         fs=`echo ${fs/UUID=/}`
         if [[ ! -e /dev/disk/by-uuid/$fs ]]; then
            sed -i "\@^UUID=$fs[ \t]*@d" $fstab 2>/dev/null
            logmsg "$me" $"nonexistent entry removed (fs:$fs mp:$mount_point)"
            rmdir $mount_point 2>/dev/null
            continue
         fi
         [ ! -e $mount_point -a ${mount_point:0:${#rootmp}} = ${rootmp} ] && mkdir -p $mount_point
         ;;
      esac
   done < $tmpfstab
   > $tmpfstab
fi

let "swapon = 0"

# scan for new devices using the searching mask `$devs2scan'
[[ "$FS_PARTS_MOUNT"  = "yes" ]] && AUTO_ADD="" || AUTO_ADD="noauto,"

# disable automounting of swap partition if live to fix Calamares installation
[ -e /run/overlayfs ] && FS_SWAP_UPDATE="no"

[[ "$FS_PARTS_UPDATE" != "yes" && "$FS_SWAP_UPDATE" != "yes" ]] ||
blkid | while read line; do
   unset dev uuid devline devfstype TYPE UUID LABEL
   dev=${line/: *}
   devline=${line/*: }
   eval $devline
   label=$LABEL
   devfstype=$TYPE
   uuid=$UUID
   [ "$label" ] || label="disk"
   if [ -e $dev ]; then
      # skip removable partitions
      [ "`cat /sys/block/${dev:5:3}/removable 2>/dev/null`" = "1" \
        -a ! -e /sys/block/${dev:5:3}/device/unload_heads ] && {
         [ "$DEBUG" ] && logmsg "$me" $"skipped device $dev ($uuid): removable"
	 continue;
      }
      # skip the current device if already in $fstab
      grep -q "^[[:space:]]*$dev[[:space:]]\|^[[:space:]]*UUID=$uuid[[:space:]]" $fstab &&
       { [ "$DEBUG" ] &&
         logmsg "$me" $"skipped device $dev ($uuid): already in fstab"
         continue; }

      [ "$DEBUG" ] && logmsg "$me" $"scanning for $dev ($uuid)..."

      # append the new device to $fstab
      unset last_mp mount_point fstype options extra_options
      check_options="0	0"
      case $dev in
      /dev/fd[0-9]*|/dev/floppy/[0-9])   # floppy disk drives
         [ "$FS_FLOPPY_UPDATE" = "yes" ] || continue
         mount_point=$(get_new_mp_name floppy)
      ;;
      /dev/sr[0-9]*|\
      /dev/cdrom[0-9]*)
         # CDROM devices
         [ "$FS_CDROM_UPDATE" = "yes" ] || continue
         # check if the CD is already mounted
         devfs="$(readlink -f $dev)"
         mount | \
         while read fstab_dev skip; do
            echo "$(readlink -f $fstab_dev)"
         done | grep -qi "$devfs"
         # note: the CD is always mounted if automount is enabled
         if [ $? -eq 0 ]; then
            logmsg "$me" $"ignoring device \`$dev' (already mounted)"
            continue
         fi
         mount_point=$(get_new_mp_name cdrom)
      ;;
      /dev/sd[a-z][0-9]*|\
      /dev/vd[a-z][0-9]*|\
      /dev/hd[a-z][0-9]*|\
      /dev/mmcblk[0-9]*p[0-9]*|\
      /dev/ub[a-z][0-9]*|\
      /dev/ub/[a-z]*/part[0-9]*)
         ## if an USB device is detected add the 'sync' option
         #case "$devlink" in
         #    /dev/ub/[a-z]*/part[0-9]*) extra_options=",sync" ;;
         #esac

         # IDE, SCSI disks, CDRW, USB devices
         devdisk="${dev/[0-9]*/}"
	 devline=$( blkid $dev 2>/dev/null | sed "s|.*:||")
	 eval $devline
	 devfstype=$TYPE
#         devfstype=$( /sbin/fdisk -l $devdisk 2>/dev/null | \
#            sed -n "/^${dev//\//\\/}/{
#               s,\*,,;  # remove the star (bootable partition)
#               # select the 5th column (fs id)
#               s/\([^ ]*[ ]*\)\{4\}\([^ ]*\).*/\2/p}" )
         case $devfstype in
         linux-swap|swap) # Linux swap
            [ "$FS_SWAP_UPDATE" = "yes" ] || continue
            mount_point="swap	"
            fstype="swap"
            options="pri=1,nofail,x-systemd.device-timeout=4"
            let "swapon = 1" ;;
         ext*|reiserfs|reiser4) # Linux partition
            [ "$FS_PARTS_UPDATE" = "yes" ] || continue
            mount_point=$(get_new_mp_name "$label" $dev)
            if [[ "$mount_point" = "/" ]]; then
               # found a root partition already mounted but not in fstab!
	       check_options="1	1"
               fstype="$(mount | \
                  sed -n "/ \/ /{s,.*type \([^ ]*\).*,\1,;p}")"
              #[[ -e /dev/root ]] &&
              # { unset devlink; dev="/dev/root"; }
            fi
            options="defaults,noatime" ;;
         ntfs|hpfs) # HPFS/NTFS
            [ "$FS_PARTS_UPDATE" = "yes" ] || continue
            mount_point=$(get_new_mp_name "$label" $dev)
            if [ -x /sbin/mount.ntfs-3g ]; then
               fstype="ntfs-3g"
               options="${AUTO_ADD}user,gid=32,umask=002"
               [ "$LANG" ] && options="$options,locale=$LANG"
            else
               options="${AUTO_ADD}user,ro,gid=32,umask=002"
            fi ;;
         fat12|fat16|fat32|FAT|vfat)
            [ "$FS_PARTS_UPDATE" = "yes" ] || continue
            # FAT12, FAT16<32M, FAT16, FAT16 [LBA]
            # FAT32 [LBA]
            mount_point=$(get_new_mp_name "$label" $dev)
            options="${AUTO_ADD}user,gid=32,umask=002" ;;
         hfs|hfs+|hfsplus)
            [ "$FS_PARTS_UPDATE" = "yes" ] || continue
            mount_point=$(get_new_mp_name "$label" $dev)
            options="${AUTO_ADD}user" ;;
#         f) # W95 Ext'd (LBA)
#            [ "$FS_PARTS_UPDATE" = "yes" ] || continue
#            unset nblocks
#            nblocks=$( echo $(grep ${dev/\/dev\//} /proc/partitions) | \
#               cut -d" " -f3 )
#            [ "$nblocks" = 1 ] && continue
#            mount_point=$(get_new_mp_name "$label")
#            options="${AUTO_ADD}user,gid=32,umask=002" ;;
         *) # ignore unknown partitions
            [ "$FS_PARTS_UPDATE" = "yes" ] || continue
            logmsg "$me" $"ignoring unknown partition (id:$devfstype)"
            continue ;;
         esac
      ;;
      *) logmsg "$me" "FIXME: "$"unknown label for case ($dev)"
      ;;
      esac

      # note: if 'mount_point' is yet undefined there is a bug
      if [[ "$mount_point" ]]; then
         # default values: fstype="auto", options="noauto,user"
	 if [ "$uuid" ]; then
	    echo "# $dev \"$label\"" >> $fstab
            echo "\
UUID=${uuid}	$mount_point	\
${fstype:-"auto"}	${options:-"noauto,user"}${extra_options}	${check_options}" >> $fstab
           [ "$fstype" = "swap" ] && /sbin/swapon -p 1 UUID=${uuid}
         else
	    echo "\
$dev	$mount_point	\
${fstype:-"auto"}	${options:-"noauto,user"}${extra_options}	${check_options}" >> $fstab
           [ "$fstype" = "swap" ] && /sbin/swapon -p 1 ${dev}
	 fi
         # create the mount point and mount the new device
         [ "${mount_point:0:${#rootmp}}" = "${rootmp}" ] && {
	    mkdir -p "$mount_point"
	    mount "$mount_point"
	 }
         logmsg "$me" $"\
added device \`$dev' (${uuid}) mount point:\`$mount_point'"
      fi
   fi
done

grep "[[:space:]]/[[:space:]].*ext[2-9].*defaults,noatime[[:space:]]" /etc/fstab >/dev/null && {
    logmsg "$me" $"disabling \`noatime' option for root filesystem (previously added by postplug)"
    sed -i "s|\([[:space:]]/[[:space:]].*ext[2-9].*defaults\),noatime|\1|" /etc/fstab
}

exit 0
