#!/bin/dash
# Filename:      scanpartitions
# Purpose:       scan for partitions and return table of the form useful for generation of /etc/fstab entries
# Authors:       (c) Klaus Knopper 2002, (c) Michael Prokop <mika@grml.org>
# Bug-Reports:   see http://grml.org/bugs/
# License:       This file is licensed under the GPL v2.
################################################################################
# Original Knoppix notes:
# Reads /proc/partitions, returns table of the form
# basename(devicefile) mountpoint filesystemtype additional_info
# Useful for automatic generation of /etc/fstab entries (you still may have to add noauto 0 0).

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

MNT='/mnt'
TMP="$(mktemp)"
trap "rm -f $TMP" 2 3 11

# cmdline handling
while : ; do
  case $# in 0) break ;; esac
  case "$1" in
    -h | --help | --h* )
      echo "Usage: $0 [-h|--help] [-l|--labels] [--nolabels] [-u|--uuids] [device]" 1>&2
      exit 1
     ;;
    -u | --uuids | --u* )
      USE_UUID=1
      shift
     ;;
    -l | --labels | --l* )
      USE_LABEL=1
      shift
     ;;
    --nolabels )
      NOLABEL=1
      shift
     ;;
    -- ) # stop option processing
      shift
      break
     ;;
    * )
      PART="$1"
      break
     ;;
  esac
done

# check fs-label
check_for_label()
{
  if [ -x /lib/udev/vol_id ] ; then
     # notice: vol_id -l returns FS_LABEL_SAFE which does not work for mount:
     PARTINFO="$(/lib/udev/vol_id $p 2>/dev/null)"
     label="$(/lib/udev/vol_id $p 2>/dev/null | awk -F'=' '/ID_FS_LABEL=/ {print $2}' 2>/dev/null)"
     case $label in
       *\ *)
        addinfo=" # space inside label ($label) not supported" && label=''
        ;;
       # this would make it necessary to mount '/mnt/' which is:
       # a) dangerous (mount over existing mount points)
       # b) zsh completion might prevent the user from using the trailing /
       # -> therefor disable it instead:
       /)
	addinfo=" # label '/' not supported" && label=''
        ;;
     esac
     case $PARTINFO in
       *ID_FS_TYPE=ntfs*)
         [ -n "$label" ] && addinfo=" # ntfs does not support mount by label ($label)" && label=''
         ;;
       *ID_FS_TYPE=ufs*)
         [ -n "$label" ] && addinfo=" # ufs does not support mount by label ($label)" && label=''
         ;;
     esac
  else
     label=''
  fi
  if [ -n "$label" ] ; then
    part="LABEL=$label"
    addinfo=" # $p"
    # check for multiple devices with same label
    warn="$(awk -F" " '{s[$NF]++}END{for(i in s)if(s[i]>1)print s[i], "labels " i}' $TMP)"
    if expr "$(echo ${warn} | awk '{print $3}')" = "$label" 1>/dev/null 2>&1 ; then
      # use UUID if we have several devices with same label
      UUID="$(/lib/udev/vol_id -u $p 2>/dev/null)"
      if [ -n "$UUID" ] ; then
         part="UUID=$UUID"
         mountpoint="$MNT/${part##*UUID=}"
         SKIPUUIDPART=1 # make sure $part is correct
      else
         part="$p"
         addinfo=" # duplicate labels but no UUID found"
         mountpoint="$MNT/${part##*/}"
         SKIPLABELPART=1 # make sure $part is correct
      fi
    fi
    if [ -z "$SKIPLABELPART" -a -z "$SKIPUUIDPART" ] ; then
       labelpart=$(echo $part | sed 's,/,,g') # strip slashes from FS-Label
       mountpoint="$MNT/${labelpart##*=}"
    fi
  else
    part="$p"
    [ -n "$addinfo" ] || addinfo=''
    mountpoint="$MNT/${part##*/}"
  fi
}

# search for partitions
if [ -z "$PART" ]; then
  partitions=""
  disks=""
  disksize=0
  blocksum=0
  pold="none"
  while read major minor blocks partition relax; do
    partition="${partition#/dev/}"
    [ -z "$partition" -o ! -e "/dev/$partition" ] && continue
    [ "$blocks" -lt 2 ] 2>/dev/null && continue

    case "$partition" in
      ?d?|ub?|ataraid/d?|rd/c?d?|cciss/c?d?|mmc*p*) disks="$disks $partition"; disksize="$blocks"; blocksum=0;;
      ram*|cloop*|loop*) ;; # blacklist
      *) blocksum="$(($blocksum + $blocks))"; [ "$blocksum" -gt "$disksize" ] >/dev/null 2>&1 || partitions="$partitions /dev/$partition";;
    esac
  done <<EOT
  $(mawk 'BEGIN{old="__start"}{if($0==old){exit}else{old=$0;if($4&&$4!="name"){print $0}}}' /proc/partitions)
EOT

  # add disks without partition table (probably ZIP drives)
  for d in $disks; do
    case "$partitions" in */dev/$d*) continue;; esac
    partitions="$partitions /dev/$d"
  done

else # use provided partition only:
  partitions="$PART"
  check_blockdevice=1
fi

# if the user provided a partition as argument but it's not a block device print warning:
if [ -n "$check_blockdevice" -a ! -b "$PART" ] ; then
   echo "Warning: given $PART does not seem to be a valid block device!" >&2
fi

# check for *duplicate* fs-label
if [ -z "$NOLABEL" ] ; then
   if [ -x /lib/udev/vol_id ] ; then
     for p in $partitions; do
      echo -n "$p: " >> $TMP
      echo "$(/lib/udev/vol_id $p 2>/dev/null | awk -F'=' '/ID_FS_LABEL=/ {print $2}' 2>/dev/null)" >> $TMP
     done
   fi
fi

for p in $partitions; do
  addinfo=''
  fs=''
  mountpoint=''
  if [ -n "$USE_UUID" ] ; then
     UUID="$(/lib/udev/vol_id -u $p 2>/dev/null)"
     part="UUID=$UUID"
     mountpoint="$MNT/${p##/dev/}"
  elif [ -n "$USE_LABEL" ] ; then
     check_for_label
  else
     # unless $NOLABEL is set check for fs-labels
    if [ -z "$NOLABEL" ] ; then
       check_for_label
    else
      part="$p"
      [ -n "$addinfo" ] || addinfo=''
      mountpoint="$MNT/${part##*/}"
    fi
  fi

  # fstype is an external script
  # send "unknown volume type" message to /dev/null
  fs="auto"
  scanfs="$(fstype $p 2>/dev/null | uniq)"
  [ -n "$scanfs" ] && fs="$scanfs"
  [ "$fs" = "swap" ] && mountpoint="none"
  [ "$fs" = "auto" ] && addinfo=" # no known filesystem detected"

  # finally print text for use in [grml-]rebuildfstab:
  echo "${part}" "${mountpoint}" "${fs}${addinfo}"
done

rm -f "$TMP"

exit 0

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