#!/bin/dash

# vdev helper to set up symlinks to optical (CD, DVD) devices, based on capability

. "$VDEV_HELPERS/subr.sh"

PATH=/sbin:/bin:/usr/sbin:/usr/bin

vdev_parse_block_device() {
   
   # if we're removing this disk, just blow away its symlinks
   if [ "$VDEV_ACTION" = "remove" ]; then 

      vdev_cleanup "$VDEV_METADATA"
      exit 0
   fi

   # otherwise, we're adding links.  Make sure...
   #if [ "$VDEV_ACTION" != "add" ]; then 

   #   vdev_error "Unknown action '$VDEV_ACTION'"
   #   exit 10
   #fi
   
   # only /dev/srXXX devices
   test -n "$(echo "$VDEV_OS_DEVNAME" | grep "sr[0-9]*")" || return 0
   
   ## is this superfluous in case of CD/DVDs?
   if [ -e "$SYSFS_PATH/whole_disk" ]; then 
      
      # we don't support whole-disk partitions 
      vdev_error "Nothing to do for whole-disk partition $VDEV_OS_DEVPATH"
      exit 0
   fi
}

# conditionally set the symlink if the capability is given 
# $1    the optical device path
# $2    the capability bit (0 or 1)
# $3    the symlink to create
add_capability_link() {

   OPTICAL_DEV="$1"
   CAPABILITY="$2"
   TARGET="$3"

   if [ $CAPABILITY = "1" ]; then

      vdev_symlink "$VDEV_PATH" "$VDEV_MOUNTPOINT/$TARGET" "$VDEV_METADATA"
   fi

   return 0
}	 

# entry point
# return 0 on success
# return 2 on disk helper failure
# return 3 on unknown disk type
# return 5 on unknown partition
# return 10 on unknown action
main() {

   local DISK_TYPE DISK_ID DISK_SERIAL DISK_NAME 
   local VDEV_BUS VDEV_USB VDEV_MODEL VDEV_MODEL_ENC VDEV_SERIAL VDEV_SERIAL_SHORT VDEV_REVISION VDEV_WWN VDEV_WWN_WITH_EXTENSION
   local VDEV_PROPERTIES
   local HELPER STAT_RET OUTPUT
   
   # blkid
   local UUID LABEL PARTUUID PARTLABEL PTUUID PTTYPE TYPE USAGE SYSTEM_ID VERSION WWN BLKID_DATA
   
   # properties
   local VDEV_FS_TYPE VDEV_FS_USAGE VDEV_FS_SYSTEM_ID VDEV_FS_VERSION VDEV_TYPE ALL_PROPS
   local VDEV_USB_INTERFACES VDEV_USB_INTERFACE_NUM     
   
   local VDEV_ATA VDEV_ATA_MODEL VDEV_ATA_MODEL_ENC VDEV_ATA_TYPE VDEV_ATA_MODEL VDEV_ATA_MODEL_ENC VDEV_ATA_SERIAL VDEV_ATA_SERIAL_SHORT VDEV_ATA_REVISION VDEV_ATA_WWN VDEV_ATA_WWN_WITH_EXTENSION
      
   local ALL_CDROM	
   local VDEV_CDROM VDEV_CDROM_CD VDEV_CDROM_CD_R VDEV_CDROM_CD_RW VDEV_CDROM_DVD VDEV_CDROM_DVD_R VDEV_CDROM_DVD_RW VDEV_CDROM_DVD_RAM VDEV_CDROM_DVD_PLUS_R VDEV_CDROM_DVD_PLUS_RW \
         VDEV_CDROM_DVD_PLUS_R_DL VDEV_CDROM_DVD_PLUS_RW_DL VDEV_CDROM_BD VDEV_CDROM_BD_R VDEV_CDROM_BD_RE VDEV_CDROM_HDDVD VDEV_CDROM_HDDVD_R VDEV_CDROM_HDDVD_RW VDEV_CDROM_MO \
         VDEV_CDROM_MRW VDEV_CDROM_MRW_W VDEV_CDROM_MEDIA VDEV_CDROM_MEDIA_MO VDEV_CDROM_MEDIA_MRW VDEV_CDROM_MEDIA_MRW_W VDEV_CDROM_MEDIA_CD VDEV_CDROM_MEDIA_CD_R VDEV_CDROM_MEDIA_CD_RW \
         VDEV_CDROM_MEDIA_DVD VDEV_CDROM_MEDIA_DVD_R VDEV_CDROM_MEDIA_DVD_RAM VDEV_CDROM_MEDIA_DVD_RW VDEV_CDROM_MEDIA_DVD_PLUS_R VDEV_CDROM_MEDIA_DVD_PLUS_RW VDEV_CDROM_MEDIA_DVD_PLUS_RW_DL \
         VDEV_CDROM_MEDIA_DVD_PLUS_R_DL VDEV_CDROM_MEDIA_BD VDEV_CDROM_MEDIA_BD_R VDEV_CDROM_MEDIA_BD_RE VDEV_CDROM_MEDIA_HDDVD VDEV_CDROM_MEDIA_HDDVD_R VDEV_CDROM_MEDIA_HDDVD_RW VDEV_CDROM_MEDIA_STATE \
         VDEV_CDROM_MEDIA_SESSION_NEXT VDEV_CDROM_MEDIA_SESSION_COUNT VDEV_CDROM_MEDIA_SESSION_LAST_OFFSET VDEV_CDROM_MEDIA_TRACK_COUNT VDEV_CDROM_MEDIA_TRACK_COUNT_AUDIO VDEV_CDROM_MEDIA_TRACK_COUNT_DATA

   ALL_CDROM="VDEV_CDROM VDEV_CDROM_CD VDEV_CDROM_CD_R VDEV_CDROM_CD_RW VDEV_CDROM_DVD VDEV_CDROM_DVD_R VDEV_CDROM_DVD_RW VDEV_CDROM_DVD_RAM VDEV_CDROM_DVD_PLUS_R VDEV_CDROM_DVD_PLUS_RW \
              VDEV_CDROM_DVD_PLUS_R_DL VDEV_CDROM_DVD_PLUS_RW_DL VDEV_CDROM_BD VDEV_CDROM_BD_R VDEV_CDROM_BD_RE VDEV_CDROM_HDDVD VDEV_CDROM_HDDVD_R VDEV_CDROM_HDDVD_RW VDEV_CDROM_MO \
              VDEV_CDROM_MRW VDEV_CDROM_MRW_W VDEV_CDROM_MEDIA VDEV_CDROM_MEDIA_MO VDEV_CDROM_MEDIA_MRW VDEV_CDROM_MEDIA_MRW_W VDEV_CDROM_MEDIA_CD VDEV_CDROM_MEDIA_CD_R VDEV_CDROM_MEDIA_CD_RW \
              VDEV_CDROM_MEDIA_DVD VDEV_CDROM_MEDIA_DVD_R VDEV_CDROM_MEDIA_DVD_RAM VDEV_CDROM_MEDIA_DVD_RW VDEV_CDROM_MEDIA_DVD_PLUS_R VDEV_CDROM_MEDIA_DVD_PLUS_RW VDEV_CDROM_MEDIA_DVD_PLUS_RW_DL \
              VDEV_CDROM_MEDIA_DVD_PLUS_R_DL VDEV_CDROM_MEDIA_BD VDEV_CDROM_MEDIA_BD_R VDEV_CDROM_MEDIA_BD_RE VDEV_CDROM_MEDIA_HDDVD VDEV_CDROM_MEDIA_HDDVD_R VDEV_CDROM_MEDIA_HDDVD_RW VDEV_CDROM_MEDIA_STATE \
              VDEV_CDROM_MEDIA_SESSION_NEXT VDEV_CDROM_MEDIA_SESSION_COUNT VDEV_CDROM_MEDIA_SESSION_LAST_OFFSET VDEV_CDROM_MEDIA_TRACK_COUNT VDEV_CDROM_MEDIA_TRACK_COUNT_AUDIO VDEV_CDROM_MEDIA_TRACK_COUNT_DATA"
   
   SYSFS_PATH="$VDEV_OS_SYSFS_MOUNTPOINT/$VDEV_OS_DEVPATH"
   
   vdev_parse_block_device

   # determine disk type, serial, and other tidbits
   for item in DISK_TYPE DISK_ID DISK_SERIAL DISK_NAME; do
      eval $item=""
   done

   VDEV_TYPE=""
   VDEV_BUS=""
   VDEV_ATA=""
   VDEV_USB=""
   VDEV_WWN=""
   
   VDEV_SERIAL=""
   VDEV_SERIAL_SHORT=""
   VDEV_REVISION=""

   VDEV_PROPERTIES=""
   
   # scsi, (s)ata, ieee1394, or USB disk
   if [ -n "$(vdev_subsystems "$SYSFS_PATH" | /bin/grep "scsi")" ]; then 

      # part of a scsi device
            
      if [ -f "$SYSFS_PATH/device/vendor" ] && [ -n "$(/bin/cat "$SYSFS_PATH/device/vendor" | /bin/grep "ATA")" ]; then 

         # ATA disk using the scsi subsystem 
         DISK_TYPE="ata"
            
      elif [ -f "$SYSFS_PATH/device/type" ] && [ -f "$SYSFS_PATH/device/scsi_level" ] && 
           [ -n "$(/bin/fgrep "5" "$SYSFS_PATH/device/type")" ] && \
           [ -n "$(/bin/egrep "[6-9]+" "$SYSFS_PATH/device/scsi_level")" ]; then 

         # ATA/ATAPI devices (SPC-3 or later) using the scsi subsystem 
         DISK_TYPE="ata"
      fi
   fi 
         
   # maybe a usb device instead?
   if [ -z "$DISK_TYPE" ] && [ -n "$(vdev_subsystems "$SYSFS_PATH" | /bin/grep "usb")" ]; then 

      # part of a USB device
            
      if ! [ -f "$SYSFS_PATH/removable" ] || [ -n "$(/bin/fgrep "0" "$SYSFS_PATH/removable")" ]; then

         # non-removable USB mass storage in a (S)ATA enclosure
         # see if we can probe with stat_ata; otherwise fall back to stat_usb
         OUTPUT="$($VDEV_HELPERS/stat_ata "$VDEV_MOUNTPOINT/$VDEV_PATH")"

         if [ $? -eq 0 ]; then

            # can treat as ATA disk
            DISK_TYPE="ata""$($VDEV_HELPERS/cdrom_id "$VDEV_MOUNTPOINT/$VDEV_PATH")"
         else

            # fall back to USB 
            DISK_TYPE="usb"
         fi
            
      else

         # usb mass-removable storage disk 
         DISK_TYPE="usb"
      fi 

      DISK_ID="$(vdev_getattrs "$DISK_TYPE" "$SYSFS_PATH")"
   fi
      
   ## This should not happen
   if [ -z "$DISK_TYPE" ]; then
   
      vdev_error "Unable to determine DISK_TYPE"
      return 2
   fi
   
   ##########
   OUTPUT=
   STAT_RET=
   
   for item in $ALL_CDROM; do
      
      eval $item=""
   done    
   
   VDEV_USB_INTERFACES=
   VDEV_USB_INTERFACE_NUM=   

   # query information about the disk
   case "$DISK_TYPE" in

      ata)
      
         # (S)ATA disk--probe if we haven't already
         OUTPUT="$($VDEV_HELPERS/stat_ata "$VDEV_MOUNTPOINT/$VDEV_PATH")" 
         STAT_RET=$?

         if [ $STAT_RET -eq 0 ]; then
            # success!
            eval "$OUTPUT"

            # disk id is the serial number
            DISK_ID="$VDEV_ATA_SERIAL"
            DISK_SERIAL="$VDEV_ATA_SERIAL"
            
            # vdev properties 
            VDEV_ATA="1"
            VDEV_BUS="ata"
            VDEV_TYPE="$VDEV_ATA_TYPE"
            VDEV_MODEL="$VDEV_ATA_MODEL"
            VDEV_MODEL_ENC="$VDEV_ATA_MODEL_ENC"
            VDEV_SERIAL="$VDEV_ATA_SERIAL"
            VDEV_SERIAL_SHORT="$VDEV_ATA_SERIAL_SHORT"
            VDEV_REVISION="$VDEV_ATA_REVISION"
            VDEV_WWN="$VDEV_ATA_WWN"
            VDEV_WWN_WITH_EXTENSION="$VDEV_ATA_WWN_WITH_EXTENSION"
         
         else 
            vdev_error "$VDEV_HELPERS/stat_ata exited with $STAT_RET"
            return 2
         fi
         
         ;;

      usb)
      
         # USB disk
         VDEV_SERIAL=""
         OUTPUT="$($VDEV_HELPERS/stat_usb "$VDEV_OS_SYSFS_MOUNTPOINT/$VDEV_OS_DEVPATH")" 
         STAT_RET=$?

         if [ $STAT_RET -eq 0 ]; then
            # success!
            eval "$OUTPUT"

            # disk id is the serial number
            DISK_ID="$VDEV_SERIAL"
            DISK_SERIAL="$VDEV_SERIAL"

            # vdev properties 
            VDEV_USB="1"
            VDEV_BUS="usb"
            
            VDEV_TYPE="cd"

         else 
            vdev_error "$VDEV_HELPERS/stat_usb exited with $STAT_RET"
            return 2
         fi
         
         ;;
         
      *)
         # unknown type
         vdev_error "Unknown disk type '$DISK_TYPE'"
         return 3
         ;;

   esac
   
   
   ############
   OUTPUT="$($VDEV_HELPERS/cdrom_id "$VDEV_MOUNTPOINT/$VDEV_PATH")" 
   STAT_RET=$?
   if [ $STAT_RET -eq 0 ]; then
      eval "$OUTPUT"
   else
      vdev_error "cdrom_id exited with $STAT_RET"
      return 2
   fi

   # put label into place
   if [ "$DISK_TYPE" = "usb" ]; then
      DISK_NAME="$DISK_TYPE-$VDEV_SERIAL"
   else
      DISK_NAME="$DISK_TYPE-$DISK_ID"
   fi
   
   # device properties
   UUID=""
   LABEL=""
   PARTUUID=""
   PARTLABEL=""
   PTUUID=""
   PTTYPE=""
   TYPE=""
   USAGE=""
   SYSTEM_ID=""
   VERSION=""
   WWN=""
   BLKID_DATA=""

   ## HACK
   ##if [ -x /sbin/blkid ] && [ -e "$VDEV_MOUNTPOINT/$VDEV_PATH" ]; then
   
      BLKID_DATA="$(vdev_blkid "$VDEV_MOUNTPOINT/$VDEV_PATH")" 
      STAT_RET=$?

      if [ $STAT_RET -ne 0 ]; then

         # exit 2 means that we didn't get any information (this is okay by us)
         vdev_warn "/sbin/blkid failed on $VDEV_MOUNTPOINT/$VDEV_PATH, exit status $?"
      else

         eval "$BLKID_DATA"
      fi
   ##else
    ##  vdev_warn "Could not find blkid in /sbin/blkid.  $VDEV_MOUNTPOINT/disk/by-*/ symlinks will not be added."
   ##fi

   # get disk WWN, if set 
   if [ -n "$VDEV_WWN" ]; then
      WWN="wwn-$VDEV_WWN"
   fi
   
   # add the disk links
   if [ -n "$DISK_NAME" ] && [ -n  "$DISK_ID" ] || [ -n "$VDEV_SERIAL" ]; then   
      vdev_symlink "../../$VDEV_PATH" "$VDEV_MOUNTPOINT/disk/by-id/$DISK_NAME" "$VDEV_METADATA"
   fi

   if [ -n "$UUID" ] && [ "x" != "x$UUID" ]; then
      vdev_symlink "../../$VDEV_PATH" "$VDEV_MOUNTPOINT/disk/by-uuid/$UUID" "$VDEV_METADATA"
   fi

   if [ -n "$LABEL" ] && [ "x" != "x$LABEL" ]; then 
      vdev_symlink "../../$VDEV_PATH" "$VDEV_MOUNTPOINT/disk/by-label/$LABEL" "$VDEV_METADATA"
   fi

   if [ -n "$WWN" ] && [ "x" != "x$WWN" ]; then
      vdev_symlink "../../$VDEV_PATH" "$VDEV_MOUNTPOINT/disk/by-id/$WWN" "$VDEV_METADATA"
   fi
   
   # device properties 
   VDEV_FS_TYPE="$TYPE"
   VDEV_FS_USAGE="$USAGE"
   VDEV_FS_SYSTEM_ID="$SYSTEM_ID"
   VDEV_FS_VERSION="$VERSION"
   
   ALL_PROPS="VDEV_BUS VDEV_SERIAL VDEV_SERIAL_SHORT VDEV_REVISION VDEV_FS_TYPE VDEV_FS_USAGE VDEV_FS_SYSTEM_ID VDEV_FS_VERSION VDEV_TYPE VDEV_MAJOR VDEV_MINOR VDEV_OS_SUBSYSTEM VDEV_OS_DEVTYPE VDEV_OS_DEVPATH VDEV_OS_DEVNAME VDEV_USB_INTERFACES VDEV_USB_INTERFACE_NUM $VDEV_PROPERTIES"

   # identify type as a type-specific flag
   case "$DISK_TYPE" in

      ata)
         
         ALL_PROPS="VDEV_ATA VDEV_WWN $ALL_PROPS"
         ;;

      usb)

         ALL_PROPS="VDEV_USB $ALL_PROPS"      
         ;;

   esac 
      
   VDEV_ATA_MODEL=""
   VDEV_ATA_MODEL_ENC=""
   VDEV_ATA_TYPE=""
   VDEV_ATA_MODEL=""
   VDEV_ATA_MODEL_ENC=""
   VDEV_ATA_SERIAL=""
   VDEV_ATA_SERIAL_SHORT=""
   VDEV_ATA_REVISION=""
   VDEV_ATA_WWN=""
   VDEV_ATA_WWN_WITH_EXTENSION=""

   # set all device properties
   rm -f "$VDEV_METADATA/properties"
   
   ALL_PROPS="$ALL_CDROM $ALL_PROPS"
   vdev_add_properties "$VDEV_METADATA" $ALL_PROPS

   # always add 'cdrom'
   vdev_symlink "$VDEV_PATH" "$VDEV_MOUNTPOINT/cdrom" "$VDEV_METADATA"

   # conditionally add symlinks, based on capability
   add_capability_link "$VDEV_PATH" $VDEV_CDROM_CD_R "cdrw"
   add_capability_link "$VDEV_PATH" $VDEV_CDROM_CD_RW "cdrw"
   add_capability_link "$VDEV_PATH" $VDEV_CDROM_DVD "dvd"
   add_capability_link "$VDEV_PATH" $VDEV_CDROM_DVD_R "dvdrw"
   add_capability_link "$VDEV_PATH" $VDEV_CDROM_DVD_RAM "dvdrw"

   # set ownership and bits 
   vdev_permissions $VDEV_VAR_OPTICAL_OWNER:$VDEV_VAR_OPTICAL_GROUP $VDEV_VAR_OPTICAL_MODE "$VDEV_MOUNTPOINT/$VDEV_PATH"

   return 0
}

if [ $VDEV_DAEMONLET -eq 0 ]; then 
   main 
   exit $?
fi
