#!/bin/bash

. /etc/profile >/dev/null
. /etc/tos/scripts/scripts

usb_position=1
ntfs_fix=$(which ntfsfix)
ntfs_mount=ntfs-3g
ntfs_mount_opt="-o rw,noatime,big_writes,async,iocharset=utf8"
exfat_mount=mount
exfat_mount_opt="-o fmask=000,dmask=000"
vfat_mount=mount
vfat_mount_opt="-o umask=000,iocharset=utf8,shortname=mixed,quiet,utf8,flush"
hfs_mount=mount
hfs_mount_opt="-t hfsplus -o force,rw,umask=0,nls=utf8,nodecompose"
ext4_mount=mount
ext4_mount_opt="-o rw,noatime,jqfmt=vfsv1,usrjquota=quota.user,grpjquota=quota.group"
btrfs_mount=mount
btrfs_mount_opt="-o rw,noatime,datasum,datacow,barrier,space_cache=v2,noautodefrag,subvolid=5,subvol=/"

usb_config=/etc/usbcopyauto

action=$1
if [ "${action}" = "" ]; then
  echo "eg: ${0} {insert|remove|delete|format} {sda|sdb|sdc|...} {ntfs|ext4|vfat}"
  exit 1
fi

if [ -e /sys/block/$2/size ]; then
  size=$(cat /sys/block/$2/size)
  [ $size -eq 0 ] && exit 1
fi
tmpdev="/dev/${2}1"
if [ -b $tmpdev ]; then
  fs=$(blkid -o value -s TYPE ${tmpdev})
  if [ "$fs" = "ext4" ]; then
    e2label $tmpdev 2>/dev/null | grep "$TOS_BOOT_SIGN" >/dev/null
    [ $? -eq 0 ] && exit 1
  fi
fi

mainVolume=$(get_main_volume)
if [ -z "$mainVolume" ]; then
  exit 1
fi
usbRoot="$mainVolume/@usb"
[ ! -d "$usbRoot" ] && mkdir -m 777 "$usbRoot"

while [ 1 ]; do
  script_get_lock >/dev/null
  [ $? -eq 0 ] && break
done

USBSORT=/tmp/usbsort
[ ! -e $USBSORT ] && mkdir -m 777 $USBSORT
log_path="/tmp/usb_${action}_$2"
echo "operation ${action} $2 by $(whoami) $(pwd)" >${log_path}

db_share() {
  [ -z "$1" ] && return 1
  local mntpath=$1
  local foldername=$(basename "${mntpath}")
  # delete from db
  tersql -sql "delete from share where foldername='$foldername'"
  # insert into db
  tersql -sql "insert into share (foldername,device,mntpath,owner,oplock,hidden,type,description,extend) VALUES('$foldername', '@usb', '$mntpath', 'admin', '0', '0', 'LFS', '', '$2');"
}

db_share_delete() {
  [ -z "$1" ] && return 1
  local mntpath=$1
  local foldername=$(basename "$mntpath")
  tersql -sql "delete from share where foldername='$foldername';"
}

usb_disk_pos() {
  # as sda, sdb, ...
  while [ 1 ]; do
    local rulepath="/Volume[0-9]+/@usb/usbshare${usb_position}"
    local result=$(df-json | egrep "$rulepath" | awk -v OFS=',' '{print $1,$8}')
    [ -z "$result" ] && break
    local blk=$(echo $result | awk -F',' '{print $1}')
    local mntpath=$(echo $result | awk -F',' '{print $2}')
    if [ ! -b "$blk" ]; then
      umount -fl "${mntpath}" >/dev/null 2>&1
      break
    fi
    let usb_position=usb_position+1
  done
  echo "$usbRoot/usbshare${usb_position}"
}

disk_filesystem() {
  local blk=$1
  local fs=$(blkid -o value -s TYPE ${blk})
  if [ "$fs" = "hfsplus" ]; then
    echo "hfsplus"
  elif [ "$fs" = "ntfs" ]; then
    echo "ntfs"
  elif [ "$fs" = "vfat" ]; then
    echo "vfat"
  elif [ "$fs" = "exfat" ]; then
    echo "exfat"
  elif [ "$fs" = "btrfs" ]; then
    echo "btrfs"
  else
    echo "ext4"
  fi
  return 0
}

usb_slaves_scan() {
  local blk=/dev/$1
  local slaves=""
  for sd in $(ls -1d ${blk}?); do
    slaves="${slaves} ${sd}"
  done
  [ "${slaves}" = "" ] && slaves=$blk
  echo $slaves
}

usb_disk_insert() {
  local slaves=$(usb_slaves_scan ${1})
  local restart=0

  for part_name in $slaves; do
    local mountpath=$(usb_disk_pos ${1})
    umount -fl ${mountpath} >/dev/null 2>&1
    local fs=$(disk_filesystem ${part_name})
    df-json | grep ${part_name} >/dev/null 2>&1
    [ $? -eq 0 -o ! -b ${part_name} ] && continue
    restart=1
    mkdir -p ${mountpath}
    chmod 777 $(dirname "${mountpath}")

    if [ "$fs" = "ntfs" ]; then
      $ntfs_fix -d ${part_name}
      ${ntfs_mount} ${ntfs_mount_opt} ${part_name} "${mountpath}" >>"$log_path"
    elif [ "$fs" = "vfat" ]; then
      ${vfat_mount} ${vfat_mount_opt} ${part_name} "${mountpath}" >>"$log_path"
    elif [ "$fs" = "exfat" ]; then
      ${exfat_mount} ${exfat_mount_opt} ${part_name} "${mountpath}" >>"$log_path"
    elif [ "$fs" = "hfsplus" ]; then
      fsck.hfsplus -f ${part_name} >/dev/null
      ${hfs_mount} ${hfs_mount_opt} ${part_name} "${mountpath}" >>"$log_path"
    elif [ "$fs" = "btrfs" ]; then
      $btrfs_mount $btrfs_mount_opt $part_name "$mountpath" >>"$log_path"
    else
      ${ext4_mount} ${ext4_mount_opt} ${part_name} "$mountpath" >>"$log_path"
    fi

    if [ $? -eq 0 ]; then
      db_share "${mountpath}" "${part_name}"
      echo "mount ${part_name} to ${mountpath} with $fs" >>${log_path}
      chmod 777 ${mountpath}
    else
      echo "mount ${part_name} to ${mountpath} failed with $fs" >>${log_path}
      rm -fr ${mountpath}
      continue
    fi

    #set usb acl
    local usbUuid=$(blkid -o value -s UUID "$part_name")
    tersql -sql "select * from external_acl where uuid='${usbUuid}';"
    if [ $? -eq 0 ]; then
      #若存在则更新挂载路径
      local timestamp=$(date +%s)
      tersql -sql "update external_acl set path='$mountpath',timestamp='$timestamp' where uuid=$usbUuid;"
    else
      #若不存在历史数据则设置默认usb权限并写入数据库
      local users=$(tersql -sql "select username from user_table where password not in ('group','adgroup','admin')")
      if [ $? -ne 0 ]; then
        continue
      fi
      # first delete acl
      local foldername=$(basename "$mountpath")
      tersql -sql "delete from external_acl where uuid='${usbUuid}';"
      for line in $(echo $users | jq -c -r .[]); do
        [ -z "$line" ] && continue
        local username=$(echo "$line" | jq -r .username)
        local timestamp=$(date +%s)
        # insert into db
        tersql -sql "insert into external_acl (username,groupname,path,type,acl,uuid,timestamp) VALUES('$username', '', '$mountpath', 'usb', 'rwx','$usbUuid','$timestamp');"
      done
    fi

    # set usb copy ...
    if [ -f ${usb_config} ]; then
      if [ -e /etc/tos/scripts/usb_auto_backup ]; then
        /etc/tos/scripts/usb_auto_backup ${mountpath} &
      fi
    fi
  done

  if [ $restart -eq 1 ]; then
    [ ! -z "$(pidof smbftpd)" ] && /etc/init.d/ftp restart
    [ ! -z "$(pidof smbd)" ] && /etc/init.d/samba restart
  fi
}

usb_disk_remove() {
  local device_name=$1
  local skip=$2
  local blk=/dev/${device_name}

  local list=$(tersql -sql "select foldername,mntpath,extend from share where extend like '%${device_name}%'")
  if [ $? -ne 0 ]; then
    return
  fi
  for line in $(echo $list | jq -c -r .[]); do
    [ -z "$line" ] && continue
    local foldername=$(echo "$line" | jq -r .foldername)
    local mntpath=$(echo "$line" | jq -r .mntpath)
    local slaveblk=$(echo "$line" | jq -r .extend)
    [ -z "${foldername}" -o -z "${slaveblk}" ] && continue
    local try=0
    local stat=1
    while [ $try -lt 5 ]; do
      local realpath=$(df-json | egrep "/Volume[0-9]+/@usb/$foldername" | awk '{print $8}')
      if [ -z "$realpath" ]; then
        stat=0
        break
      else
        mntpath=$realpath
        fuser -k "$mntpath"
        umount -fl "$mntpath" >>"$log_path"
      fi
      let try=try+1
    done
    if [ $stat -ne 0 ]; then
      if [ ! -b "$slaveblk" ]; then
        db_share_delete "$mntpath"
      else
        echo "umount -fl ${mntpath} failed" >>${log_path}
      fi
    else
      echo "umount -fl ${mntpath} successful" >>${log_path}
      db_share_delete "$mntpath"
    fi
    #移除后更新外接设备权限数据库path字段为空。
    local usbUuid=$(blkid -o value -s UUID "$slaveblk")
    tersql -sql "update external_acl set path='' where uuid=$usbUuid;"
  done
  local blkname=${device_name:0:3}
  local path=/sys/block/${blkname}/device/delete
  [ -e $path -a "${skip}" = "" ] && echo 0 >$path

  #usb拔出，删除usb缓存cache
  rm -r /run/cache/diskinfo/${device_name}

  [ ! -z "$(pidof smbftpd)" ] && /etc/init.d/ftp restart
  [ ! -z "$(pidof smbd)" ] && /etc/init.d/samba restart
}

usb_disk_format() {
  local device_name=$1
  local filesystem=$2
  local blk=$device_name
  local partnumber=$(grep '^[[:digit:]]*$' <<<${device_name:0-1})
  [ ! -z "$partnumber" ] && blk=${device_name:0:0-1}

  usb_disk_remove ${device_name} ${blk}
  if [ "X${blk}" = "X${device_name}" ]; then
    parted -s /dev/$device_name "mktable gpt"
    parted -s /dev/$device_name "mkpart primary ext2 0% 100%"
    partnumber=1
    device_name="${device_name}${partnumber}"
  fi

  case $filesystem in
  exfat)
    [ ! -z "$partnumber" ] && parted -s /dev/$blk "set $partnumber msftdata on"
    mkfs.exfat /dev/$device_name >/dev/null 2>&1
    ;;
  ntfs)
    mkfs.ntfs -f /dev/$device_name >/dev/null 2>&1 #ntfs快速格式化
    ;;
  btrfs)
    echo -e "y\n" | mkfs.btrfs -n 64k -f /dev/$device_name >/dev/null 2>&1 #btrfs强制格式化并修改nodesize为64k
    ;;
  ext4)
    echo -e "y\n" | mkfs.ext4 -E lazy_itable_init=1,lazy_journal_init=1 /dev/$device_name >/dev/null 2>&1 #ext4格式化并延迟初始化
    tune2fs -O ea_inode /dev/$device_name >/dev/null 2>&1                                                 #打开ea_inode支持
    ;;
  *)
    echo -e "y\n" | mkfs.$filesystem /dev/$device_name >/dev/null 2>&1
    ;;
  esac

  usb_disk_insert $blk
  script_put_lock
  exit 0
}

#更新外接设备数据库，历史记录超过30天则清除数据
clearData_InTimeout() {
  local timestamp=$(date +"%s" -d '-30 day')
  tersql -sql "delete from external_acl where timestamp < $timestamp and path = '';"
}

case "${action}" in
insert)
  usb_init_position $2
  usb_disk_insert $2
  clearData_InTimeout
  ;;
saferemove)
  touch /var/lock/usb_$2
  usb_remove_position $2
  usb_disk_remove $2
  ;;
remove)
  # handle usb abnormal eject
  if [ ! -e /var/lock/usb_$2 ]; then
    ter_msg_add -c storage -l warning -s notification -k sot_USBAbnormal_eject
  fi
  rm -f /var/lock/usb_$2 >/dev/null 2>&1
  usb_remove_position $2
  usb_disk_remove $2
  ;;
delete)
  usb_disk_remove $2
  ;;
format)
  if [ -z "${3}" ]; then
    echo "eg: ${0} [format] [sda|sdb|sdc|...] [NTFS|VFAT|EXT4]"
    script_put_lock
    exit 1
  fi
  usb_disk_format $2 $3
  ;;
esac
script_put_lock
exit 0
