#!/bin/sh

. /lib/functions.sh
. /lib/dyiot/bin/get_hardware

supervisor_trap() {
  echo "gets trap on supervisor"
  rm -rf /tmp/check_coredump
}
trap 'supervisor_trap; exit 1' INT TERM ABRT QUIT ALRM

critical_processes="frpc|frpc rathole|rathole"

all_installed=0
updated=0
rootfs_ro_chk=0 # Variable to indicate whether rootfs read-only checking should be performed
[ "$(uname -m)" = "x86_64" ] && \
	[ -n "$(grep -e '/dev/root / ext4' /proc/mounts)" ] && rootfs_ro_chk=1

rootfs_ro_check() {
	if [ ${rootfs_ro_chk} -eq 0 ] ; then
		# no need to check rootfs
		return 0
	fi

	local rootdev='/dev/sda2'
	if [ ! -b "${rootdev}" ] ; then
		# echo "Cannot find block device: ${rootdev}" | logger-t "supervisor" -p 5
		return 1
	fi

	local rfsro="$(grep -e '/dev/root / ext4' /proc/mounts)"
	if [ -z "${rfsro}" ] ; then
		echo "Cannot find ext4 mounted rootfs!" | logger -t "supervisor" -p 5
		return 2
	fi

	if [[ "${rfsro}" =~ "rw," ]] ; then
		# echo "Rootfs is being mounted as ext4, read-write" | logger -t "supervisor"
		return 0
	fi

	if [[ "${rfsro}" =~ "ro," ]] ; then
		echo "Rootfs is being mounted as ext4, read-only!" | logger -t "supervisor"
		if [ -d "/boot" ] ; then
			# write a logfile to /boot directory, /boot is not readonly
			local rolog='/boot/rootfs-readonly.log'
			if [ -e "${rolog}" ] ; then
				# check readonly logfile size
				local rosize="`ls -l ${rolog} | awk '{print $5}'`"
				if [ -z "${rosize}" ] ; then
					rm -rf "${rolog}"
					echo "Rootfs: removing logfile for readonly rootfs" | logger -t "supervisor"
				elif [ ${rosize} -gt 2097152 ] ; then # larger than 2MB
					rm -rf "${rolog}"
					echo "Rootfs: removing logfile for readonly rootfs, size: ${rosize}" | logger -t "supervisor"
				else
					echo "Rootfs: readonly logfile current size: ${rosize}" | logger -t "supervisor"
				fi
			fi
			echo '===============================================================' >> "${rolog}"
			echo "`date`: rootfs is now readonly, will check it now" >> "${rolog}"
			dmesg | tail -n 32 >> "${rolog}"
		fi
		fsck.ext4 -y "${rootdev}"
		sync ; sleep 5 ; reboot
		return 3
	fi

	echo "Error, unknown rootfs: ${rfsro}" | logger -t "supervisor" -p 5
	return 4
}

check_critical_processes() {
  for crit_proc in $critical_processes; do
    OIFS=$IFS
    IFS="|"
    set -- $crit_proc
    crit_proc_name=$1
    crit_initd_name=$2
    IFS=$OIFS
    [ ! -e "/etc/init.d/${crit_initd_name}" ] && continue
    pids=$(pgrep "$crit_proc_name")
    count=$(echo "$pids" | awk 'END{print NR}')
    if [ -z "$pids" -o "$count" -gt 1 ]; then
      echo "$crit_proc_name is abnormal, pids:${pids}, count:${count}" | logger -t "supervisor" -p 5
      /etc/init.d/${crit_initd_name} restart
    fi
  done
}

check_coredump() {
  lock -n /tmp/check_coredump
  [ "$?" != "0" ] && return 1
  cd /tmp/
  rm -rf gcom.*.core
  for core_file in $(ls *.core 2>/dev/null); do
    echo "Core file is abnormal:$core_file" | logger -t "supervisor" -p 5
    if [ $(free | awk '/Mem/{print $4}') -gt "20000" ]; then
      tar czvf /app/${core_file}.tar.gz "$core_file" /etc/issue
    fi
    rm -rf "$core_file"
  done
  cd -
  lock -u /tmp/check_coredump
}

check_df() {
  top_info="$1"
  df_info="$2"
  tmp_free=$(echo "$df_info" | awk '/\/tmp$/{print $4}')
  mem_free=$(cat /proc/meminfo | awk '/MemAvailable/{print $2}')
  flash_free=$(echo "$df_info" | awk '/\/overlay$/{print $4}')
  [ -z "$flash_free" ] && flash_free=$(echo "$df_info" | awk '/\/$/{print $4}')
  echo "tmp_free":$tmp_free "flash_free:"$flash_free "mem_free:"$mem_free | logger -t "supervisor"
  if [ "$mem_free" -lt "1024" ]; then
    echo 3 >/proc/sys/vm/drop_caches
    mem_free=$(cat /proc/meminfo | awk '/MemAvailable/{print $2}')
    if [ "$mem_free" -lt "1024" ]; then
      echo "$top_info" >/app/top_info
      echo "$(cat /proc/meminfo)" >/app/meminfo
      echo "$(find /proc/ -name status | xargs cat)" >/app/proc_status
      echo "reboot as less sys resource" | logger -t "supervisor" -p 3
      echo "reboot as less sys resource" >/dev/console
      sync
      sleep 10
      reboot -f
    fi
  fi
  if [ "$flash_free" -lt "2048" ]; then
    echo "du /app" >/app/du_info
    rm -rf /app/*.log /app/*.tar.gz
    /usr/bin/sqlite3 /app/collect.db "delete from data_table where report=1;"
    /usr/bin/sqlite3 /app/MQTT_REPORT_0.db "delete from data_table where report=1;"
    /usr/bin/sqlite3 /app/MQTT_REPORT_1.db "delete from data_table where report=1;"
    /usr/bin/sqlite3 /app/MQTT_REPORT_2.db "delete from data_table where report=1;"
    /usr/bin/sqlite3 /app/MQTT_REPORT_3.db "delete from data_table where report=1;"
    /usr/bin/sqlite3 /app/MQTT_REPORT_4.db "delete from data_table where report=1;"
  fi
  if [ "$tmp_free" -lt "2048" ]; then
    echo "$df_info" >/app/df_info
    echo "reboot as less sys resource" | logger -t "supervisor" -p 3
    echo "reboot as less sys resource" >/dev/console
    sleep 10
    reboot -f
  fi
}

check_sysstat() {
  top_info=$(top -n1 -b)
  # echo "$top_info" | logger -t "supervisor"
  echo "$top_info" >/tmp/top_info
  df_info=$(df)
  # echo "$df_info" | logger -t "supervisor"
  echo "$df_info" >/tmp/df_info
  check_df "$top_info" "$df_info"
}

check_installed_ipk() {

  if [[ "$all_installed" == "1" ]]; then
    echo "All IPK Installed" | logger -t "IPK CHECK" -p 3
    return
  fi

  local flag=0
  if [ -f "/app/config/ipk_installed" ]; then
    for line in $(cat /app/config/ipk_installed | awk '{print $1}'); do
      result=$(/bin/opkg list-installed | grep "^$line ")
      if [[ "$result" == "" ]]; then
        flag=1
        echo "$line not installed" | logger -t "IPK CHECK" -p 3
        [ "$updated" == 0 ] && {
          /bin/opkg update
          updated=1
        }
        str=$(cat /app/config/ipk_installed)
        args=${str#"$line "}
        /bin/opkg $args
      fi
    done
  fi
  if [ "$flag" -eq "0" ]; then
    all_installed=1
    echo "all installed" | logger -t "IPK CHECK" -p 3
  fi
}

modem_inited=0
function check_4g_modem() {
  if [[ "$modem_inited" == "1" ]]; then
    echo "4g mode inited" | logger -t "4G-modem-SUP" -p 3
    return
  fi
  dev=$(modem_dev)
  modem_inited=1

  result=$(gcom -d $dev -s /etc/gcom/checksim.gcom | grep "OK")
  if [[ "$result" != "" ]]; then
    ping -w3 -c2 -I usb0 mqtt.lnxall.com
    [ "$?" != 0 ] && {
      errcode=3
      rm /app/config/4g_modem
      init_usbdev
      echo "init hardware" logger -t "4G-modem-SUP" -p 3
    }
  fi
}

function check_can() {
  for line in $(ls /sys/class/net | grep can); do
    state=$(cat /sys/class/net/"$line"/operstate)
    if [[ "$state" == "down" ]]; then
      $(ifconfig "$line" down)
      sleep 1
      $(ifconfig "$line" up)
    fi
  done
}

while :; do
  sleep 60
  check_4g_modem
  check_critical_processes &
  check_sysstat &
  check_coredump &
  rootfs_ro_check
  check_can &
done
