Added preliminary armbianmonitor code

This commit is contained in:
Thomas Kaiser 2016-03-04 00:32:07 +01:00
parent 97600327f9
commit cf07fb0ad8
3 changed files with 893 additions and 0 deletions

View File

@ -23,6 +23,7 @@ Armbian supports starting with release 5.04 all available H3 based Orange Pi boa
- Auto detection for the Orange Pi 2 doesn't work properly. Please have a look [for a manual fix](http://forum.armbian.com/index.php/topic/617-wip-orange-pi-one-support-for-the-upcoming-orange-pi-one/?p=5718) or wait for 5.05 where this will be fixed
- Mali acceleration currently only working for root user. Please apply [a fix](http://forum.armbian.com/index.php/topic/617-wip-orange-pi-one-support-for-the-upcoming-orange-pi-one/?p=5719) manually or wait for 5.05 to fix this
- Booting from NAND on OPi Plus currently not supported
***Important to know***

View File

@ -0,0 +1,417 @@
#!/bin/bash
#
# armbianmonitor
#
# This script serves different purposes based on how it is called:
#
# - toggle boot verbosity (works)
# - monitoring mode: continually print monitoring info (WiP)
# - uploading /var/log/armhwinfo.log to online pastebin service
#
# Without arguments called it should present a simple user
# interface that guides through:
#
# - installation of RPi-Monitor if not already installed by user
# - active basic or more verbose monitoring mode
# - provides monitoring parameters for connected disks
#
# The second part is WiP and all the user interaction part
# still completely missing.
#
# This script is used to configure armbianmonitor behaviour.
# It will ask the user whether to activate monitoring or not,
# whether to enable debug monitoring and also how to deal with
# connected disks. In fact it walks through the list of available
# disks, checks them, tries to patch hddtemp.db if necessary
# and provides a proposal for /etc/armbianmonitor/disks.conf
# when a new disk is found.
#
# In case monitoring should be activated the following file
# will be created: /etc/armbianmonitor/start-monitoring. If
# debug output has been chosen, then DEBUG will be written to
# the file.
#
# The script will install smartmontools/gdisk if not already
# installed and patches smartmontools' update-smart-drivedb
# script if necessary. For disks the 'device model' will be
# shown but internally we rely always on the GUID. This is the
# key for entry in /etc/armbianmonitor/disks.conf
#
# When the script exits and the user activated monitoring it
# recommends doing a restart since on the next reboot the
# setup-armbian-monitoring-environment script will configure
# monitoring sources and decides based on the existence and
# contents of /etc/armbianmonitor/start-monitoring whether
# rpimonitord should be started or not.
#
# The format of /etc/armbianmonitor/disks.conf is as follows:
#
# ${GUID}:${Name}:${smartctl prefix}:${temp call}:${CRC}:${LCC}
#
# Two examples:
#
# A57BF307-7D82-4783-BD1D-B346CA8C195B:WD Green::199:193 # WD HDD on SATA
# F8D372DC-63DB-494B-B802-87DC47FAD4E1:Samsung EVO:sat::199: # SSD in USB enclosure
#
# - GUID is the GUID as determined by gdisk
# - 'Name': The name as it will later be shown in RPi-Monitor, defaults to
# the 'device model' read out through smartctl but can be changed to
# be more significant (beware that this string must contain colons!)
# - "smartctl prefix" can be empty or should be the the necessary prefix for
# USB disks, eg. '-d sat' or '-d usbjmicron' and so on -- please have a
# look at https://www.smartmontools.org/wiki/Supported_USB-Devices
# - "temp call" when being omitted indicates that hddtemp should be used.
# Otherwise it should contain the complete command line ('DISK' will be
# dynamically replaced by the device node when the actual monitoring
# happens), for example:
# /sbin/hdparm -C DISK | egrep -q "standby|sleeping" || /usr/sbin/smartctl -d sat -a DISK | awk -F" " '/Temperature_Cel/ {printf $10}'
# - 'CRC attribute': The decimal value of the S.M.A.R.T. attribute that
# is used to store the count of checksum errors between disk and host
# controller (might be omitted if the drive doesn't support it)
# - 'LCC attribute': The decimal value of the S.M.A.R.T. attribute that
# should contain the load cycle counter value (might be omitted
# if the drive doesn't support it)
#
# TODO:
#
# - develop main functionality ;) asking the user regarding monitoring
# - deal with 'SMART overall-health self-assessment test result:'
# - write documentation
#
############################################################################
Main() {
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ParseOptions "$@"
PreRequisits
# check whether user runs rpimonitord on his own or we activated it
if [ -f /etc/armbianmonitor/start-monitoring ]; then
# we should already provide monitoring, check whether DEBUG
# is also set
ArmbianMonitoring=TRUE
read DebugMode </etc/armbianmonitor/start-monitoring
fi
# check whether rpimonitord is running and compare with ${ArmbianMonitoring}
# In case the user chose to run rpimonitord on his own, we skip the config
# part and only output disk info
:
# check available disk devices
CheckDisks
} # Main
ParseOptions() {
while getopts 'hHbBuUm:M:' c ; do
case ${c} in
H)
# display full help test
export FullUsage=TRUE
DisplayUsage
exit 0
;;
h)
# display short help
DisplayUsage
exit 0
;;
b|B)
# toggle boot verbosity
if [ -f /boot/.force-verbose ]; then
rm /boot/.force-verbose
echo -e "Verbose kernel messages have been disabled. Needs a reboot"
else
date "+%s" >/boot/.force-verbose
echo -e "Verbose kernel messages have been enabled. Needs a reboot"
fi
exit 0
;;
m|M)
# monitoring mode
MonitorMode ${OPTARG}
exit 0
;;
u|U)
# Upload /var/log/armhwinfo.log to be of help in support forum.
# TODO: ping sprunge.us before to detect network/firewall problems
which curl >/dev/null 2>&1 || apt-get -f -qq -y install curl
echo -e "/var/log/armhwinfo.log has been uploaded to \c"
(cat /var/log/armhwinfo.log ; echo -e "\n### dmesg now:\n$(dmesg)") \
| curl -F 'sprunge=<-' http://sprunge.us
echo -e "Please post the URL in the Armbian forum where you've been asked for"
exit 0
;;
esac
done
} # ParseOptions
DisplayUsage() {
# check if stdout is a terminal...
if test -t 1; then
# see if it supports colors...
ncolors=$(tput colors)
if test -n "$ncolors" && test $ncolors -ge 8; then
BOLD="$(tput bold)"
NC='\033[0m' # No Color
LGREEN='\033[1;32m'
fi
fi
echo -e "Usage: ${BOLD}${0##*/} [-h/-H] [-b] [-m] [-u]${NC}\n"
echo -e "############################################################################"
if [ ${FullUsage} ]; then
echo -e "\nDetailed Description:"
grep "^#" "$0" | grep -v "^#\!/bin/bash" | sed 's/^#//'
fi
echo -e "\n This is WiP now\n"
echo -e "############################################################################\n"
} # DisplayUsage
MonitorMode() {
# $1 is the time in seconds to pause between two prints, defaults to 5 seconds
# This functions prints out endlessly:
# - time/date
# - average 1m load
# - detailed CPU statistics
# - Soc temperature if available
# - PMIC temperature if available
# TODO: Format output nicely
Sensors="/etc/armbianmonitor/datasources/"
while true ; do
LoadAvg=$(cut -f1 </proc/loadavg)
echo -e "$(date "+%Y-%m-%d %H:%M:%S"):\t${LoadAvg}\t$(ProcessStats)\c"
[ -f "${Sensors}/soctemp" ] && echo -e "\t$(awk '{printf ("%0.1f",$1/1000); }' <"${Sensors}/soctemp")°C\c"
[ -f "${Sensors}/pmictemp" ] && echo -e "\t$(awk '{printf ("%0.1f",$1/1000); }' <"${Sensors}/pmictemp")°C"
sleep ${1:-5}
done
} # MonitorMode
ProcessStats() {
set $(awk -F" " '/^cpu / {print $2"\t"$3"\t"$4"\t"$5"\t"$6"\t"$7"\t"$8}' </proc/stat)
UserStat=$1
NiceStat=$2
SystemStat=$3
IdleStat=$4
IOWaitStat=$5
IrqStat=$6
SoftIrqStat=$7
UserDiff=$(( ${UserStat} - ${LastUserStat} ))
NiceDiff=$(( ${NiceStat} - ${LastNiceStat} ))
SystemDiff=$(( ${SystemStat} - ${LastSystemStat} ))
IdleDiff=$(( ${IdleStat} - ${LastIdleStat} ))
IOWaitDiff=$(( ${IOWaitStat} - ${LastIOWaitStat} ))
IrqDiff=$(( ${IrqStat} - ${LastIrqStat} ))
SoftIrqDiff=$(( ${SoftIrqStat} - ${LastSoftIrqStat} ))
Total=$(( ${UserDiff} + ${NiceDiff} + ${SystemDiff} + ${IdleDiff} + ${IOWaitDiff} + ${IrqDiff} + ${SoftIrqDiff} ))
CPULoad=$(( ( ${Total} - ${IdleDiff} ) * 100 / ${Total} ))
UserLoad=$(( ${UserDiff} *100 / ${Total} ))
SystemLoad=$(( ${SystemDiff} *100 / ${Total} ))
NiceLoad=$(( ${NiceDiff} *100 / ${Total} ))
IOWaitLoad=$(( ${IOWaitDiff} *100 / ${Total} ))
IrqCombinedLoad=$(( ( ${IrqDiff} + ${SoftIrqDiff} ) *100 / ${Total} ))
echo "${CPULoad} ${SystemLoad} ${UserLoad} ${NiceLoad} ${IOWaitLoad} ${IrqCombinedLoad}"
LastUserStat=${UserStat}
LastNiceStat=${NiceStat}
LastSystemStat=${SystemStat}
LastIdleStat=${IdleStat}
LastIOWaitStat=${IOWaitStat}
LastIrqStat=${IrqStat}
LastSoftIrqStat=${SoftIrqStat}
} # ProcessStats
CheckDisks() {
# This function walks through all block devices whose name starts with sd* and
# then gets the name hddtemp expects, the model name from smartctl, looks whether
# the drive only lists one temperature value and patches hddtemp.db if necessary
# and also tries to get CRC and LCC S.M.A.R.T. attributes to provide the user
# with the necessary config file contents for /etc/armbianmonitor/disks.conf:
ls /sys/block/sd* >/dev/null 2>&1 || exit 0
for i in /sys/block/sd* ; do
DeviceNode=/dev/${i##*/}
# get GUID/UUID for disk and check whether a partition table is existent. If
# not GUID will always be random
gdisk -l ${DeviceNode} >"${MyTempDir}/gdisk.txt"
GUID=$(awk -F" " '/^Disk identifier/ {print $4}' <"${MyTempDir}/gdisk.txt")
CountOfUnavailablePartitionTables=$(grep ': not present' "${MyTempDir}/gdisk.txt" | wc -l)
if [ ${CountOfUnavailablePartitionTables} -eq 4 ]; then
echo -e "\nSkipping ${DeviceNode} due to missing partition table. Use parted to create one."
break
else
echo -e "\nExamining ${DeviceNode} with GUID ${GUID}\c"
fi
# get name hddtemp needs
HddtempName="$(hddtemp --debug ${DeviceNode} | awk -F": " '/^Model: / {print $2}' | \
cut -c-40 | sed 's/^[ \t]*//;s/[ \t]*$//')"
# store smartctl output in temporary file
smartctl -q noserial -s on -a ${DeviceNode} >"${MyTempDir}/smartctl.txt" 2>&1
DeviceModel="$(awk -F": " '/^Device Model/ {print $2}' <"${MyTempDir}/smartctl.txt" | \
sed 's/^[ \t]*//;s/[ \t]*$//')"
if [ "X${DeviceModel}" = "X" ]; then
# Reading S.M.A.R.T. failed, we try autodetect mode iterating through all
# known smartctl modes (-d auto|sat|usbcypress|usbjmicron|usbprolific|usbsunplus)
SMARTPrefix="$(CheckSMARTModes ${DeviceNode} 2>/dev/null)"
if [ "X${SMARTPrefix}" = "X" ]; then
# we can't query the disk. Time to give up
echo -e ". Unable to query the disk through S.M.A.R.T.\nPlease investigate manually using smartctl\n"
break
fi
fi
# user feedback
if [ "X${SMARTPrefix}" = "X" ]; then
echo -e " (accessible through S.M.A.R.T.)"
else
echo -e " (can be queried with \"-d ${SMARTPrefix}\" through S.M.A.R.T.)"
fi
# check for CRC and LCC attributes
CRCAttribute=$(awk -F" " '/CRC_Error_Count/ {print $1}' <"${MyTempDir}/smartctl.txt")
LCCAttribute=$(grep -i "load.cycle" "${MyTempDir}/smartctl.txt" | awk -F" " '{print $1}')
# check whether /etc/hddtemp.db should be patched
grep -q "${HddtempName}" /etc/hddtemp.db
if [ $? -ne 0 ]; then
# No entry into hddtemp database, we've a look whether there's a 'temperature'
# attribute available (we take the 1st we find) and if that's the case we use this
DiskTemp=$(awk -F" " '/Temperature/ {print $1}' <"${MyTempDir}/smartctl.txt" | head -n1)
if [[ ${DiskTemp} -gt 0 ]]; then
echo -e "\"${HddtempName}\" ${DiskTemp} C \"${DeviceModel}\"" >>/etc/hddtemp.db
echo -e "\nAdded disk \"${DeviceModel}\"/\"${HddtempName}\" to /etc/hddtemp.db using S.M.A.R.T. attribute ${DiskTemp}\nbased on the following available thermal values:"
grep "Temperature" "${MyTempDir}/smartctl.txt"
# check hddtemp result
HddtempResult=$(hddtemp -n ${DeviceNode} | awk -F" " '{print $1}')
if [ "X${HddtempResult}" = "X${DeviceNode}:" ]; then
# hddtemp isn't able to query the disk
HddtempStatus="does not work. Please check with smartctl and adjust config accordingly"
echo -e "\nhddtemp output: $(hddtemp ${DeviceNode})"
echo -e "\nIt seems we can not rely on hddtemp to query this disk. Please try smartctl instead\n"
else
HddtempStatus="will work"
echo -e "\nhddtemp output: ${HddtempResult})"
echo -e "\nIn case this seems not to be correct please adjust /etc/hddtemp.db manually\n"
fi
else
HddtempStatus="does not work. Please check with smartctl and adjust config accordingly"
fi
else
HddtempStatus="will work"
fi
# check for firmware updates
FirmwareUpdate="$(grep "^http" "${MyTempDir}/smartctl.txt")"
# Check whether the disk (based on GUID) is already configured in our config file
# /etc/armbianmonitor/disks.conf or not
grep -q "^${GUID}:" /etc/armbianmonitor/disks.conf >/dev/null 2>/dev/null
case $? in
0)
# already listed, we provide just infos:
echo -e "Disk is already configured by the following monitoring config:\n$(grep "^${GUID}:" /etc/armbianmonitor/disks.conf)\n"
;;
*)
# new disk, we recommend an entry for /etc/armbianmonitor/disks.conf
echo -e "Disk not configured for monitoring. We were able to extract the following information:\nGUID: ${GUID}"
if [ "X${SMARTPrefix}" != "X" ]; then
echo -e "QueryMode: -d ${SMARTPrefix}"
fi
echo -e "hddtemp: ${HddtempStatus}\nCRC attribute: ${CRCAttribute}\nLCC Attribute: ${LCCAttribute}"
case ${HddtempStatus} in
"will work")
echo -e "If you want to monitor the disk please add to /etc/armbianmonitor/disks.conf:\n${GUID}:${DeviceModel}:${SMARTPrefix}::${CRCAttribute}:${LCCAttribute}"
;;
*)
echo -e "Proposal for /etc/armbianmonitor/disks.conf:\n${GUID}:${DeviceModel}:${SMARTPrefix}:FIXME:${CRCAttribute}:${LCCAttribute}"
echo -e "You have to figure out how to query the disk for its thermal sensor."
echo -e "Please check the output of \"hddtemp --debug ${DeviceNode}\" and smartctl\n"
;;
esac
;;
esac
if [ "X${FirmwareUpdate}" != "X" ]; then
echo -e "\nWARNING: A firmware update seems to be available:\n${FirmwareUpdate}\n"
fi
done
} # CheckDisks
CheckSMARTModes() {
# This function tries to access USB disks through S.M.A.R.T. and returns the necessary
# '-d' call as well as fills in ${MyTempDir}/smartctl.txt
for i in auto sat usbcypress usbjmicron usbprolific usbsunplus ; do
# user feedback
echo -n "." >/dev/tty
# query disk using the specific protocol
echo -n "" >"${MyTempDir}/smartctl.txt"
smartctl -q noserial -s on -d ${i} -a ${1} >"${MyTempDir}/smartctl.txt" 2>/dev/null
DeviceModel="$(awk -F": " '/^Device Model/ {print $2}' <"${MyTempDir}/smartctl.txt" | \
sed 's/^[ \t]*//;s/[ \t]*$//')"
if [ "X${DeviceModel}" != "X" ]; then
echo ${i}
break
fi
done
} # CheckSMARTModes
PreRequisits() {
# Ensure that we're running as root since otherwise querying SATA/USB disks won't work
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root" >&2
exit 1
fi
export PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
unset LANG
DISTROCODE=$(lsb_release -s -c)
# check whether gdisk/smartctl are available and up to date
echo -e "Check whether necessary software is available\c"
which gdisk >/dev/null 2>&1 || (echo -e " Installing gdisk\c" ; apt-get -f -qq -y install gdisk)
which smartctl >/dev/null 2>&1 || (echo -e " Installing smartmontools\c" ; apt-get -f -qq -y install smartmontools)
echo -e " [done]\nUpdating smartmontools' drivedb\c"
/usr/sbin/update-smart-drivedb >/dev/null 2>&1
if [ $? -ne 0 -a "X${DISTROCODE}" = "Xwheezy" ]; then
sed -i "/^SRCEXPR/{s#=.*#='http://sourceforge.net/p/smartmontools/code/HEAD/tree/\$location/smartmontools/drivedb.h?format=raw'#}" /usr/sbin/update-smart-drivedb
/usr/sbin/update-smart-drivedb
fi
echo -e " [done]"
CreateTempDir
} # PreRequisits
CreateTempDir() {
# create a safe temporary dir
MyTempDir=$(mktemp -d /tmp/${0##*/}.XXXXXX)
if [ ! -d "${MyTempDir}" ]; then
MyTempDir=/tmp/${0##*/}.$RANDOM.$RANDOM.$RANDOM.$$
(umask 066 && mkdir ${MyTempDir}) || (echo "Failed to create temp dir. Aborting" >&2 ; exit 1)
fi
chmod 711 "${MyTempDir}"
trap "rm -rf \"${MyTempDir}\" ; exit 0" 0 1 2 3 15
for file in smartctl.txt gdisk.txt ; do
touch "${MyTempDir}/${file}"
chmod 644 "${MyTempDir}/${file}"
done
} #CreateTempFiles
InstallRPiMonitor() {
# Installs rpimonitord based on the official instructions from
# http://rpi-experiences.blogspot.fr/p/rpi-monitor-installation.html
apt-get -qq -y update
apt-get -f -qq -y install apt-transport-https ca-certificates
wget -q http://goo.gl/rsel0F -O /etc/apt/sources.list.d/rpimonitor.list
apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 2C0D3C0F
apt-get -qq -y update
apt-get -f -qq -y install rpimonitor
/usr/share/rpimonitor/scripts/updatePackagesStatus.pl &
} # InstallRPiMonitor
Main "$@"

View File

@ -0,0 +1,475 @@
#!/bin/bash
#
# armbianmonitor-daemon
#
# This script relies on information gathered in armhwinfo. It
# calls armhwinfo in query mode and relies then on the exported
# variables: HARDWARE ARCH KERNELID MACHINE ID VERSION
#
# The purpose is to create an environment for rpimonitord so that
# relevant hardware informations can be monitored easily. This
# script starts uses configuration files in /etc/armbianmonitor/,
# collects data sources below /etc/armbianmonitor/datasources/ and
# adjusts templates for RPi-Monitor on the fly. Only if the file
# /etc/armbianmonitor/start-monitoring exists this script relinks
# /etc/rpimonitor/data.conf and starts rpimonitord if not already
# running.
#
# In case the script detects that not all necessary data sources
# are available through sysfs it will act as a daemon to collect
# data on its own and to write it to the approriate file. As an
# example the SoC's temperature: Running on an AXP209 based board
# the script will check /sys/class/thermal/thermal_zone0/temp and
# if existing link it to /etc/armbianmonitor/datasources/soctemp.
# In case it does not exist the script will create a normal file
# at this location and writes the thermal value to it using the
# sunxi_axp209_temp binary in an endless loop.
#
# At least the following files/symlinks will be provided below
# /etc/armbianmonitor/datasources/ depending on SoC/PMIC in question:
#
# soctemp (SoC's internal temp in degree Celsius * 1000)
# pmictemp (PMIC's internal temp in degree Celsius * 1000)
# ac_voltage (DC-IN voltage in V * 1000000)
# usb_voltage (USB OTG voltage in V * 1000000)
# battery_voltage (battery voltage in V * 1000000)
# ac_current (DC-IN current in A * 1000000)
# usb_current (USB OTG current in A * 1000000)
# battery_current (battery current in A * 1000000)
#
# When extended debugging has been chosen (using _armbian-monitoring_
# this can be configured. Then /etc/armbianmonitor/start-monitoring
# contains DEBUG) this script will also provide a few more files:
#
# cpustat (cpu_stat,system_stat,user_stat,nice_stat,iowait_stat,irq_stat
# collected through /proc/cpustat in daemon mode)
# cpu_count (number of active CPU cores)
# vcorevoltage (Vcore in V * 1000 based on sysfs or script.bin/.dtb)
#
# Disk monitoring: For configured disks the following parameters can be
# monitored: temperature, S.M.A.R.T. health, load cycle count and CRC
# errors indicating connection/cable problems. The config file used is
# /etc/armbianmonitoring/disks.conf
#
# Filesystem monitoring: In /etc/armbianmonitoring/filesystems.conf
# mountpoints and trigger values can be defined that will be used to
# create the template stuff for these fs at startup of this script.
#
# The behaviour of this script can be configured through another tool
# called armbian-monitoring. The latter will also check for connected
# disks, get their name and GUID and let the user choose whether the
# disk should be monitored or not. The information has to be stored in
# /etc/armbianmonitor/disks.conf relying on the GUIDs of the disks.
# define some variables:
CheckInterval=7.5 # time in seconds between two checks
DiskCheckInterval=60 # time in seconds between disk checks
Main() {
PreRequisits
case ${ID} in
Cubieboard|Cubietruck|Orange|"Lamobo R1"|"Lime 2"|Lime|Banana|Micro)
DealWithAXP209
;;
"Banana M2")
DealWithNewBoard
# DealWithAXP221
;;
"Cubietruck Plus"|"Banana Pi M3"|"pcDuino8 Uno")
DealWithNewBoard
# DealWithAXP818
;;
Guitar|"Roseapple Pi")
DealWithNewBoard
# DealWithS500
;;
"Odroid XU4"|"Odroid XU3")
DealWithNewBoard
# DealWithExynos4
;;
"Odroid C1")
DealWithNewBoard
# DealWithS805
;;
Clearfog|"Turris Omnia")
DealWithNewBoard
# DealWithArmada38x
;;
"Cubox i4"|"HB i2eX"|"Cubox i2eX"|"HB i1"|"HB i2"|"Wandboard")
DealWithNewBoard
# DealWithiMX6
;;
"Orange Pi PC"|"Orange Pi Plus"|"Orange Pi 2"|"Orange Pi One"|"Orange Pi Lite")
DealWithNewBoard
# DealWithH3
;;
Geekbox)
DealWithNewBoard
# DealWithRK3368
;;
*)
# No templates exist now. Combine sane defaults with some guessing
DealWithNewBoard
;;
esac
# Create the Armbian templates
CreateTemplates
exit 0
# Decide depending on existence of /etc/armbianmonitor/start-monitoring
ShouldMonitoringBeStarted
# Provide missing data in daemon mode
LoopEndlessly
} # Main
LoopEndlessly() {
while true ; do
# get VCore
read CPUFreq </sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
GetVCore ${CPUFreq} >/tmp/VCore
# check disk temperature(s). We execute this only every ${DiskCheckInterval} since
# it's a bit costly (S.M.A.R.T. queries).
TimeNow=$(( $(date "+%s") / ${DiskCheckInterval} ))
if [[ ${TimeNow} -gt ${LastDiskCheck} ]]; then
# time for a disk check. If ${CheckAllDisks} is FALSE and /dev/sda exists we
# only query this device otherwise all available (might be none)
CheckDisks
# update check timestamp
LastDiskCheck=${TimeNow}
fi
# External temperature from weather stations
# TimeNow=$(( $(date "+%s") / ${TempCheckInterval} ))
# if [[ ${TimeNow} -gt ${LastTempCheck} ]]; then
# read in external temp values from 2 different web sources
# ExternalTemp=$(GetExternalTemp)
# LastExternalTemp=$(SanitizeValue ${ExternalTemp} ${LastExternalTemp} | tee /tmp/externaltemp)
# LastTempCheck=${TimeNow}
# fi
# cpustat
TimeNow=$(( $(date "+%s") / ${CpuStatCheckInterval} ))
if [[ ${TimeNow} -gt ${LastCpuStatCheck} ]]; then
ProcessStats
LastCpuStatCheck=${TimeNow}
fi
sleep ${CheckInterval}
done
} # LoopEndlessly
CheckDisks() {
# To be done based on new /etc/armbianmonitoring/disks.conf config file
:
} # CheckDisks
DealWithAXP209() {
# check existence of sysfs nodes
if [ -f /sys/devices/virtual/thermal/thermal_zone0/temp ]; then
ln -fs /sys/devices/virtual/thermal/thermal_zone0/temp /etc/armbianmonitor/datasources/soctemp
else
if [ -L /etc/armbianmonitor/datasources/soctemp ]; then
rm -f /etc/armbianmonitor/datasources/soctemp
fi
echo -n 25000 >/etc/armbianmonitor/datasources/soctemp
export GetSoCTemp="${ARCH}-${ID}"
fi
if [ -d /sys/devices/platform/soc@01c00000/1c2ac00.i2c/i2c-0/0-0034 ]; then
# mainline kernel and 'axp209 mainline sysfs interface' patch applied
ln -fs /sys/power/axp_pmu/ac/voltage /etc/armbianmonitor/datasources/ac_voltage
ln -fs /sys/power/axp_pmu/ac/amperage /etc/armbianmonitor/datasources/ac_current
ln -fs /sys/power/axp_pmu/vbus/voltage /etc/armbianmonitor/datasources/usb_voltage
ln -fs /sys/power/axp_pmu/vbus/amperage /etc/armbianmonitor/datasources/usb_current
ln -fs /sys/power/axp_pmu/battery/voltage /etc/armbianmonitor/datasources/battery_voltage
ln -fs /sys/power/axp_pmu/battery/amperage /etc/armbianmonitor/datasources/battery_current
ln -fs /sys/power/axp_pmu/pmu/temp /etc/armbianmonitor/datasources/pmictemp
ln -fs /sys/power/axp_pmu/battery/capacity /etc/armbianmonitor/datasources/battery_percent
ln -fs /sys/power/axp_pmu/battery/charging /etc/armbianmonitor/datasources/battery_charging
ln -fs /sys/power/axp_pmu/charger/amperage /etc/armbianmonitor/datasources/charger_current
ln -fs /sys/power/axp_pmu/battery/connected /etc/armbianmonitor/datasources/battery_connected
ln -fs /sys/power/axp_pmu/battery/charge /etc/armbianmonitor/datasources/battery_charge
fi
if [ -d /sys/devices/platform/sunxi-i2c.0/i2c-0/0-0034/axp20-supplyer.28/power_supply ]; then
# sunxi 3.4 kernel
SysFSPrefix=/sys/devices/platform/sunxi-i2c.0/i2c-0/0-0034/axp20-supplyer.28/power_supply
ln -fs "${SysFSPrefix}"/ac/voltage_now /etc/armbianmonitor/datasources/ac_voltage
ln -fs "${SysFSPrefix}"/ac/current_now /etc/armbianmonitor/datasources/ac_current
ln -fs "${SysFSPrefix}"/usb/voltage_now /etc/armbianmonitor/datasources/usb_voltage
ln -fs "${SysFSPrefix}"/usb/current_now /etc/armbianmonitor/datasources/usb_current
ln -fs "${SysFSPrefix}"/battery/voltage_now /etc/armbianmonitor/datasources/battery_voltage
ln -fs "${SysFSPrefix}"/battery/current_now /etc/armbianmonitor/datasources/battery_current
ln -fs /sys/devices/platform/sunxi-i2c.0/i2c-0/0-0034/temp1_input /etc/armbianmonitor/datasources/pmictemp
ln -fs /sys/class/power_supply/battery/capacity /etc/armbianmonitor/datasources/battery_percent
ln -fs /sys/class/power_supply/battery/charging /etc/armbianmonitor/datasources/battery_charging
ln -fs /sys/class/power_supply/battery/connected /etc/armbianmonitor/datasources/battery_connected
ln -fs /sys/class/power_supply/battery/charge /etc/armbianmonitor/datasources/battery_charge
fi
# relink template
if [ "X${DebugMode}" = "XDEBUG" ]; then
ln -sf /etc/armbianmonitor/templates/axp209_template_debug.conf /etc/armbianmonitor/templates/cpu_pmic.conf
else
ln -sf /etc/armbianmonitor/templates/axp209_template.conf /etc/armbianmonitor/templates/cpu_pmic.conf
fi
} # DealWithAXP209
DealWithNewBoard() {
# check existence of sysfs nodes
if [ -f /sys/devices/virtual/thermal/thermal_zone0/temp ]; then
ln -fs /sys/devices/virtual/thermal/thermal_zone0/temp /etc/armbianmonitor/datasources/soctemp
elif [ -f /sys/devices/virtual/thermal/thermal_zone1/temp ]; then
ln -fs /sys/devices/virtual/thermal/thermal_zone1/temp /etc/armbianmonitor/datasources/soctemp
fi
# relink template
if [ "X${DebugMode}" = "XDEBUG" ]; then
ln -sf /etc/armbianmonitor/templates/unknown_board_template_debug.conf /etc/armbianmonitor/templates/cpu_pmic.conf
else
ln -sf /etc/armbianmonitor/templates/unknown_board_template.conf /etc/armbianmonitor/templates/cpu_pmic.conf
fi
} # DealWithNewBoard
CreateTemplates() {
# check whether templates we write aren't symlinks to somewhere else
for i in armbian.conf uptime.conf version.conf ; do
if [ -L /etc/armbianmonitor/templates/${i} ]; then
rm /etc/armbianmonitor/templates/${i}
touch /etc/armbianmonitor/templates/${i}
chmod 711 /etc/armbianmonitor/templates/${i}
fi
done
# check whether our logo is available
if [ ! -f /usr/share/rpimonitor/web/img/armbian.png ]; then
if [ -L /usr/share/rpimonitor/web/img/armbian.png ]; then
rm /usr/share/rpimonitor/web/img/armbian.png
fi
cp -p /etc/armbianmonitor/templates/armbian.png /usr/share/rpimonitor/web/img/
fi
# create main template
echo "web.page.icon='img/armbian.png'
web.page.menutitle='RPi-Monitor <sub>('+data.hostname+')</sub>'
web.page.pagetitle='RPi-Monitor ('+data.hostname+')'
web.status.1.name=$ID
web.statistics.1.name=$ID
web.addons.1.name=Addons
web.addons.1.addons=about
include=/etc/armbianmonitor/templates/version.conf
include=/etc/armbianmonitor/templates/uptime.conf
include=/etc/armbianmonitor/templates/cpu_pmic.conf
include=/etc/rpimonitor/template/memory.conf" >/etc/armbianmonitor/armbian.conf
# remove firmware line in version info:
grep -v "Firmware" /etc/rpimonitor/template/version.conf | sed 's|line.5|line.4|' >/etc/armbianmonitor/templates/version.conf
# uptime template with correct machine name:
sed "s/Raspberry Pi/$ID/" < /etc/rpimonitor/template/uptime.conf >/etc/armbianmonitor/templates/uptime.conf
# check swap settings. In case we're using swap then add template
HowManySwapDevices=$(swapon -s | wc -l)
if [[ ${HowManySwapDevices} -gt 1 ]]; then
echo "include=/etc/rpimonitor/template/swap.conf" >>/etc/armbianmonitor/armbian.conf
fi
echo "include=/etc/armbianmonitor/template/filesystems.conf
include=/etc/armbianmonitor/template/disks.conf
include=/etc/rpimonitor/template/network.conf" >>/etc/armbianmonitor/armbian.conf
UpdateFileSystems
UpdateDisks
} #
UpdateFileSystems() {
# Generates /etc/armbianmonitor/template/filesystems.conf dynamically
# based on the contents of /etc/armbianmonitoring/filesystems.conf
# if not existing, create config file with single entry for /
if [ ! -f /etc/armbianmonitoring/filesystems.conf ]; then
echo '/' >/etc/armbianmonitoring/filesystems.conf
chmod 711 /etc/armbianmonitoring/filesystems.conf
fi
# Update template:
} # UpdateFileSystems
UpdateDisks() {
# Generates /etc/armbianmonitor/template/disks.conf dynamically
# based on the contents of /etc/armbianmonitor/disks.conf. The
# current mapping between GUIDs and /dev/sd* nodes will be stored
# in /etc/armbianmonitor/datasources/disk-by-guid
# ensure lookup file is empty:
if [ -L /etc/armbianmonitor/datasources/disk-by-guid ]; then
rm -f /etc/armbianmonitor/datasources/disk-by-guid
fi
echo -n "" >/etc/armbianmonitor/datasources/disk-by-guid
chmod 711 /etc/armbianmonitor/datasources/disk-by-guid
OIFS=${IFS}
IFS=:
cat /etc/armbianmonitor/disks.conf | while read ; do
IFS=:
set ${REPLY}
GUID="$1"
DiskName="$2"
SMARTPrefix="$3"
TempCommand="$4"
CRCAttribute="$5"
LCCAttribute="$6"
IFS=${OIFS}
# try to resolve device node (when not present, then disk's
# not mounted -- we then create the entry without device node)
DeviceNode="$(ResolveGUID ${GUID})"
echo -e "${GUID}\t${DiskName}\t${DeviceNode}" >>/etc/armbianmonitor/datasources/disk-by-guid
# create template stuff for every listed disk
:
done
IFS=${OIFS}
} # UpdateDisks
ResolveGUID() {
# function that will be supplied with a GUID and returns the device node, eg.
# translating 637B7677-18E7-4C7B-8DF3-CFED96EA55C3 to /dev/sdb
# check whether disks are existent
ls /sys/block/sd* >/dev/null 2>&1 || return
for i in /sys/block/sd* ; do
DeviceNode=/dev/${i##*/}
GUID=$(gdisk -l ${DeviceNode} | awk -F" " '/^Disk identifier/ {print $4}')
if [ "X${GUID}" = "X${1}" ]; then
echo -n ${DeviceNode}
break
fi
done
} # GetGUIDforDisk
PreRequisits() {
export PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
unset LANG
LastDiskCheck=0
# we need the informations gathered from armhwinfo. In case we're not called
# from there, get the variables on our own
if [ "X${ID}" = "X" ]; then
. /etc/init.d/armhwinfo start >/dev/null 2>&1
fi
# check/create /etc/armbianmonitor and /etc/armbianmonitor/datasources
if [ ! -d /etc/armbianmonitor ]; then
mkdir -p -m 755 /etc/armbianmonitor
else
chmod 755 /etc/armbianmonitor
fi
if [ ! -d /etc/armbianmonitor/datasources ]; then
mkdir -p -m 755 /etc/armbianmonitor/datasources
else
chmod 755 /etc/armbianmonitor/datasources
fi
# check whether we should do debug monitoring or normal
read DebugMode </etc/armbianmonitor/start-monitoring
# set default variables
unset LANG
LastDiskCheck=0
LastTempCheck=0
LastUserStat=0
LastNiceStat=0
LastSystemStat=0
LastIdleStat=0
LastIOWaitStat=0
LastIrqStat=0
LastSoftIrqStat=0
LastCpuStatCheck=0
} # PreRequisits
ParseDVFSTable() {
# extract DRAM and dvfs settings from script.bin
bin2fex <"${Path2ScriptBin}/script.bin" 2>/dev/null | \
egrep "^LV._|^LV_|extrem|boot_clock|_freq|^dram_" | \
egrep -v "cpu_freq|dram_freq" | while read ; do
echo "# ${REPLY}"
done >/tmp/dvfs-table
echo -e '\nGetVCore() {' >>/tmp/dvfs-table
# parse /tmp/dvfs-table to get dvfs entries
grep "^# LV._freq" /tmp/dvfs-table | sort -r | while read ; do
set ${REPLY}
CPUFreq=$4
# if [ ${CPUFreq} -eq 0 ]; then
# echo -e "if [ \$1 -ge $(( ${CPUFreq} / 1000 )) ]; then\n\techo -n ${VCore}\nel\c" >>/tmp/dvfs-table
# break
# else
# VCore=$(grep -A1 "^# $2" /tmp/dvfs-table | tail -n1 | awk -F" " '{print $4}')
# echo -e "if [ \$1 -ge $(( ${CPUFreq} / 1000 )) ]; then\n\techo -n ${VCore}\nel\c" >>/tmp/dvfs-table
if [ ${CPUFreq} -ne 0 ]; then
VCore=$(grep -A1 "^# $2" /tmp/dvfs-table | tail -n1 | awk -F" " '{print $4}')
echo -e "if [ \$1 -le $(( ${CPUFreq} / 1000 )) ]; then\n\techo -n ${VCore}\nel\c" >>/tmp/dvfs-table
fi
done
# VCore=$(grep -A1 "^# LV1_freq" /tmp/dvfs-table | tail -n1 | awk -F" " '{print $4}')
echo -e "se\n\techo -n ${VCore}\nfi\n}" >>/tmp/dvfs-table
} # ParseDVFSTable
ProcessStats() {
set $(awk -F" " '/^cpu / {print $2"\t"$3"\t"$4"\t"$5"\t"$6"\t"$7"\t"$8}' </proc/stat)
UserStat=$1
NiceStat=$2
SystemStat=$3
IdleStat=$4
IOWaitStat=$5
IrqStat=$6
SoftIrqStat=$7
UserDiff=$(( ${UserStat} - ${LastUserStat} ))
NiceDiff=$(( ${NiceStat} - ${LastNiceStat} ))
SystemDiff=$(( ${SystemStat} - ${LastSystemStat} ))
IdleDiff=$(( ${IdleStat} - ${LastIdleStat} ))
IOWaitDiff=$(( ${IOWaitStat} - ${LastIOWaitStat} ))
IrqDiff=$(( ${IrqStat} - ${LastIrqStat} ))
SoftIrqDiff=$(( ${SoftIrqStat} - ${LastSoftIrqStat} ))
Total=$(( ${UserDiff} + ${NiceDiff} + ${SystemDiff} + ${IdleDiff} + ${IOWaitDiff} + ${IrqDiff} + ${SoftIrqDiff} ))
CPULoad=$(( ( ${Total} - ${IdleDiff} ) * 100 / ${Total} ))
UserLoad=$(( ${UserDiff} *100 / ${Total} ))
SystemLoad=$(( ${SystemDiff} *100 / ${Total} ))
NiceLoad=$(( ${NiceDiff} *100 / ${Total} ))
IOWaitLoad=$(( ${IOWaitDiff} *100 / ${Total} ))
IrqCombinedLoad=$(( ( ${IrqDiff} + ${SoftIrqDiff} ) *100 / ${Total} ))
echo "${CPULoad} ${SystemLoad} ${UserLoad} ${NiceLoad} ${IOWaitLoad} ${IrqCombinedLoad}" >/tmp/cpustat
LastUserStat=${UserStat}
LastNiceStat=${NiceStat}
LastSystemStat=${SystemStat}
LastIdleStat=${IdleStat}
LastIOWaitStat=${IOWaitStat}
LastIrqStat=${IrqStat}
LastSoftIrqStat=${SoftIrqStat}
} # ProcessStats
GetExternalTemp() {
# example function that parses meteo.physik.uni-muenchen.de and mingaweda.de
# temperature values for Munich and compares them. When values are out
# of bounds then only the other value will be returned otherwise the average
ExternalTemp1=$(/usr/bin/links -http.fake-user-agent 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/600.7.12 (KHTML, like Gecko) Version/8.0.7 Safari/600.7.12' -dump "http://www.meteo.physik.uni-muenchen.de/dokuwiki/doku.php?id=wetter:stadt:messung" | awk -F" " '/Lufttemperatur/ {printf ("%0.0f",$4*1000); }')
ExternalTemp2=$(/usr/bin/links -http.fake-user-agent 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/600.7.12 (KHTML, like Gecko) Version/8.0.7 Safari/600.7.12' -dump "http://www.mingaweda.de/wetterdaten/" | awk -F" " '/Ausfu:hrliche/ {printf ("%0.0f",$2*1000); }')
if [ "X${ExternalTemp2}" = "X" ]; then
ExternalTemp2=${ExternalTemp1}
elif [ "X${ExternalTemp1}" = "X" ]; then
ExternalTemp1=${ExternalTemp2}
fi
echo $(( ( ${ExternalTemp1} + ${ExternalTemp2} ) / 2 ))
} # GetExternalTemp
Main