diff --git a/README.md b/README.md index 0d06036..24fc114 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,8 @@ To blink the `disk` LED when a block device is active, you can use the `ledtrig- #### Start at Boot (for Debian 12) +The configure file of `ugreen-diskiomon` and `ugreen-netdevmon` is `/etc/ugreen-led.conf`. Please see `scripts/ugreen-leds.conf` for an example. + - Edit `/etc/modules-load.d/ugreen-led.conf` and add the following lines: ``` i2c-dev @@ -163,27 +165,36 @@ ledtrig-netdev - Copy files in the `scripts` directory: ```bash +# copy the scripts scripts=(ugreen-diskiomon ugreen-netdevmon ugreen-probe-leds) for f in ${scripts[@]}; do chmod +x "scripts/$f" cp "scripts/$f" /usr/bin done +# copy the configuration file, you can change it if needed +cp scripts/ugreen-leds.conf /etc/ugreen-leds.conf + +# copy the systemd services cp scripts/*.service /etc/systemd/system/ systemctl daemon-reload # change enp2s0 to the network device you want to monitor -systemctl start ugreen-ledmon@enp2s0 +systemctl start ugreen-netdevmon@enp2s0 +systemctl start ugreen-diskiomon # if you confirm that everything works well, # run the command below to make the service start at boot -systemctl enable ugreen-ledmon@enp2s0 +systemctl enable ugreen-netdevmon@enp2s0 +systemctl enable ugreen-diskiomon ``` ## Disk Mapping -To make the disk LEDs useful, we should map the disk LEDs to correct disk slots. First of all, we should highlight that using `/dev/sdX` is never a smart idea, as it may change at every boot. In the script `ugreen-diskiomon` we provide two mapping methods: **by HCTL** and **by serial**. +To make the disk LEDs useful, we should map the disk LEDs to correct disk slots. First of all, we should highlight that using `/dev/sdX` is never a smart idea, as it may change at every boot. In the script `ugreen-diskiomon` we provide three mapping methods: **by ATA**, **by HCTL** and **by serial**. + +The best mapping method is using serial numbers, but it needs to record them manually and fill the `DISK_SERIAL` array in `/etc/ugreen-leds.conf`. We use ATA mapping by default, and find that UGOS also uses a similar mapping method (see [#15](https://github.com/miskcoo/ugreen_dx4600_leds_controller/pull/15)). See the comments in `scripts/ugreen-leds.conf` for more details. The HCTL mapping depends on how the SATA controllers are connected to the PCIe bus and the disk slots. To check the HCTL order, you can run the following command, and check the serial of your disks: @@ -200,7 +211,7 @@ sdg 6:0:0:0 XXKH3SXX sdh 7:0:0:0 XXJDB1XX ``` -As far as we know, the mapping between HCTL and the disk serial are stable at each boot (see [#4](https://github.com/miskcoo/ugreen_dx4600_leds_controller/pull/4) and [#9](https://github.com/miskcoo/ugreen_dx4600_leds_controller/issues/9)). However, it has been reported that the exact order is model-dependent (see [#9](https://github.com/miskcoo/ugreen_dx4600_leds_controller/issues/9)). In DX4600 Pro and DXP8800 Plus, the mapping is `X:0:0:0 -> diskX`, but In the DXP6800 Pro, `0:0:0:0` and `1:0:0:0` are mapped to `disk5` and `disk6`, and `2:0:0:0` to `6:0:0:0` are mapped to `disk1` to `disk4`, so you should change the array `hctl_map` in `ugreen-diskiomon` accordingly. +As far as we know, the mapping between HCTL and the disk serial are stable at each boot (see [#4](https://github.com/miskcoo/ugreen_dx4600_leds_controller/pull/4) and [#9](https://github.com/miskcoo/ugreen_dx4600_leds_controller/issues/9)). However, it has been reported that the exact order is model-dependent (see [#9](https://github.com/miskcoo/ugreen_dx4600_leds_controller/issues/9)). In DX4600 Pro and DXP8800 Plus, the mapping is `X:0:0:0 -> diskX`, but in DXP6800 Pro, `0:0:0:0` and `1:0:0:0` are mapped to `disk5` and `disk6`, and `2:0:0:0` to `6:0:0:0` are mapped to `disk1` to `disk4`. The script will use `dmidecode` to detect the device model, but I suggest to check the mapping outputed by the script manually. ## Communication Protocols diff --git a/scripts/ugreen-diskiomon b/scripts/ugreen-diskiomon index 24b0ab8..ff91ff5 100755 --- a/scripts/ugreen-diskiomon +++ b/scripts/ugreen-diskiomon @@ -6,6 +6,8 @@ exit-ugreen-diskiomon() { rm "/var/run/ugreen-diskiomon.lock" fi kill $smart_check_pid 2>/dev/null + kill $zpool_check_pid 2>/dev/null + kill $disk_online_check_pid 2>/dev/null } # trap exit and remove lockfile @@ -23,42 +25,55 @@ if [[ -f /boot/config/plugins/ugreenleds-driver/settings.cfg ]]; then source /boot/config/plugins/ugreenleds-driver/settings.cfg fi +# load environment variables +if [[ -f /etc/ugreen-leds.conf ]]; then + source /etc/ugreen-leds.conf +fi + # led-disk mapping (see https://github.com/miskcoo/ugreen_dx4600_leds_controller/pull/4) -MAPPING_METHOD=${MAPPING_METHOD:=hctl} # hctl, serial +MAPPING_METHOD=${MAPPING_METHOD:=ata} # ata, hctl, serial led_map=(disk1 disk2 disk3 disk4 disk5 disk6 disk7 disk8) # hctl, $> lsblk -S -x hctl -o hctl,serial,name # NOTE: It is reported that the order below should be adjusted for each model. # Please check the disk mapping section in https://github.com/miskcoo/ugreen_dx4600_leds_controller/blob/master/README.md. hctl_map=("0:0:0:0" "1:0:0:0" "2:0:0:0" "3:0:0:0" "4:0:0:0" "5:0:0:0" "6:0:0:0" "7:0:0:0") -if which dmidecode; then +# serial number, $> lsblk -S -x hctl -o hctl,serial,name +serial_map=(${DISK_SERIAL}) +# ata number, $> ls /sys/block | egrep ata\d +ata_map=("ata1" "ata2" "ata3" "ata4" "ata5" "ata6" "ata7" "ata8") + +if which dmidecode > /dev/null; then product_name=$(dmidecode --string system-product-name) case "${product_name}" in - "DXP6800 Pro") - echo "Found UGREEN DXP6800 Pro" - hctl_map=("2:0:0:0" "3:0:0:0" "4:0:0:0" "5:0:0:0" "0:0:0:0" "1:0:0:0") - ;; - "DX4600 Pro") - echo "Found UGREEN DX4600 Pro" - # using the default mapping - ;; - "DXP8800 Plus") - echo "Found UGREEN DXP8800 Plus" - # using the default mapping - ;; + DXP6800*) # tested on DXP6800 Pro + echo "Found UGREEN DXP6800 series" + hctl_map=("2:0:0:0" "3:0:0:0" "4:0:0:0" "5:0:0:0" "0:0:0:0" "1:0:0:0") + ata_map=("ata3" "ata4" "ata5" "ata6" "ata1" "ata2") + ;; + DX4600*) # tested on DX4600 Pro + echo "Found UGREEN DX4600 series" + ;; + DXP4800*) + echo "Found UGREEN DXP4800 series" + ;; + DXP8800*) # tested on DXP8800 Plus + echo "Found UGREEN DXP8800 series" + # using the default mapping + ;; *) - if [[ "${MAPPING_METHOD}" = "hctl" ]]; then - echo "Using the default HCTL order. Please check it maps to your disk slots correctly." - echo "If you confirm that the HCTL order is correct, or find it is different, you can submit an issue to let us know, so we can update the script." - echo "(Read the disk mapping section in https://github.com/miskcoo/ugreen_dx4600_leds_controller/blob/master/README.md for more details)" - fi - ;; + if [[ "${MAPPING_METHOD}" == "hctl" || "${MAPPING_METHOD}" == "ata" ]]; then + echo -e "\033[0;31mUsing the default HCTL order. Please check it maps to your disk slots correctly." + echo -e "If you confirm that the HCTL order is correct, or find it is different, you can " + echo -e "submit an issue to let us know, so we can update the script." + echo -e "Please read the disk mapping section in the link below for more details. " + echo -e " https://github.com/miskcoo/ugreen_dx4600_leds_controller/blob/master/README.md\033[0m" + fi + ;; esac -elif [[ "${MAPPING_METHOD}" = "hctl" ]]; then - echo "installing the tool `dmidecode` is suggested; otherwise the script cannot detect your device and adjust the hctl_map" +elif [[ "${MAPPING_METHOD}" == "hctl" || "${MAPPING_METHOD}" == "ata" ]]; then + echo -e "\033[0;31minstalling the tool `dmidecode` is suggested; otherwise the script cannot detect your device and adjust the hctl/ata_map\033[0m" fi -# serial number, $> lsblk -S -x hctl -o hctl,serial,name -serial_map=("placeholder0" "placeholder1" "placeholder2" "placeholder3" "placeholder4" "placeholder5" "placeholder6" "placeholder7") declare -A devices # set monitor SMART information to true by default if not running unRAID @@ -72,31 +87,55 @@ CHECK_SMART_INTERVAL=${CHECK_SMART_INTERVAL:=360} # refresh interval from disk leds LED_REFRESH_INTERVAL=${LED_REFRESH_INTERVAL:=0.1} +# whether to check zpool health +CHECK_ZPOOL=${CHECK_ZPOOL:=false} +# polling rate for checking zpool health. 5 seconds by default +CHECK_ZPOOL_INTERVAL=${CHECK_ZPOOL_INTERVAL:=5} + +# polling rate for checking disk online. 5 seconds by default +CHECK_DISK_ONLINE_INTERVAL=${CHECK_DISK_ONLINE_INTERVAL:=5} +COLOR_DISK_HEALTH=${COLOR_DISK_HEALTH:="255 255 255"} +COLOR_DISK_UNAVAIL=${COLOR_DISK_UNAVAIL:="255 0 0"} +COLOR_ZPOOL_FAIL=${COLOR_ZPOOL_FAIL:="255 0 0"} +COLOR_SMART_FAIL=${COLOR_SMART_FAIL:="255 0 0"} +BRIGHTNESS_DISK_LEDS=${BRIGHTNESS_DISK_LEDS:="255"} -{ lsmod | grep ledtrig_oneshot ; } || modprobe -v ledtrig_oneshot -sleep 2 +{ lsmod | grep ledtrig_oneshot > /dev/null; } || { modprobe -v ledtrig_oneshot && sleep 2; } + +function disk_enumerating_string() { + if [[ $MAPPING_METHOD == ata ]]; then + ls -ahl /sys/block | sed 's/\/$//' | awk '{ + if (match($0, /ata[0-9]+/)) { + ata = substr($0, RSTART, RLENGTH); + if (match($0, /[^\/]+$/)) { + basename = substr($0, RSTART, RLENGTH); + print basename, ata; + } + } + }' + elif [[ $MAPPING_METHOD == hctl || $MAPPING_METHOD == serial ]]; then + lsblk -S -o name,${MAPPING_METHOD},tran | grep sata + else + echo Unsupported mapping method: ${MAPPING_METHOD} + exit 1 + fi +} echo Enumerating disks based on $MAPPING_METHOD... declare -A dev_map while read line do blk_line=($line) - if [[ $MAPPING_METHOD = hctl ]]; then - key=${blk_line[1]} - val=${blk_line[0]} - elif [[ $MAPPING_METHOD = serial ]]; then - key=${blk_line[1]} - val=${blk_line[0]} - else - echo Unsupported mapping method: ${MAPPING_METHOD} - exit 1 - fi + key=${blk_line[1]} + val=${blk_line[0]} dev_map[${key}]=${val} echo $MAPPING_METHOD ${key} ">>" ${dev_map[${key}]} -done <<< "$(lsblk -S -o name,${MAPPING_METHOD} | tail -n +2)" +done <<< "$(disk_enumerating_string)" +# initialize LEDs +declare -A dev_to_led_map for i in "${!led_map[@]}"; do led=${led_map[i]} if [[ -d /sys/class/leds/$led ]]; then @@ -104,35 +143,116 @@ for i in "${!led_map[@]}"; do echo 1 > /sys/class/leds/$led/invert echo 100 > /sys/class/leds/$led/delay_on echo 100 > /sys/class/leds/$led/delay_off - echo "255 255 255" > /sys/class/leds/$led/color + echo "$COLOR_DISK_HEALTH" > /sys/class/leds/$led/color + echo "$BRIGHTNESS_DISK_LEDS" > /sys/class/leds/$led/brightness # find corresponding device _tmp_str=${MAPPING_METHOD}_map[@] _tmp_arr=(${!_tmp_str}) - dev=${dev_map[${_tmp_arr[i]}]} - if [[ -f /sys/class/block/${dev}/stat ]]; then - devices[$led]=${dev} - else - # turn off the led if no disk installed on this slot - echo 0 > /sys/class/leds/$led/brightness - echo none > /sys/class/leds/$led/trigger + + if [[ -v "dev_map[${_tmp_arr[i]}]" ]]; then + dev=${dev_map[${_tmp_arr[i]}]} + + if [[ -f /sys/class/block/${dev}/stat ]]; then + devices[$led]=${dev} + dev_to_led_map[$dev]=$led + else + # turn off the led if no disk installed on this slot + echo 0 > /sys/class/leds/$led/brightness + echo none > /sys/class/leds/$led/trigger + fi fi fi done +# construct zpool device mapping +declare -A zpool_ledmap +if [ "$CHECK_ZPOOL" = true ]; then + echo Enumerating zpool devices... + while read line + do + zpool_dev_line=($line) + zpool_dev_name=${zpool_dev_line[0]} + zpool_scsi_dev_name="unknown" + # zpool_dev_state=${zpool_dev_line[1]} + case "$zpool_dev_name" in + sd*) + # remove the trailing partition number + zpool_scsi_dev_name=$(echo $zpool_dev_name | sed 's/[0-9]*$//') + ;; + dm*) + # find the underlying block device of the encrypted device + dm_slaves=($(ls /sys/block/${zpool_dev_name}/slaves)) + zpool_scsi_dev_name=${dm_slaves[0]} + ;; + *) + echo Unsupported zpool device type ${zpool_dev_name}. + ;; + esac + + # if the detected scsi device can be found in the mapping array + #echo zpool $zpool_dev_name ">>" $zpool_scsi_dev_name ">>" ${dev_to_led_map[${zpool_scsi_dev_name}]} + if [[ -v "dev_to_led_map[${zpool_scsi_dev_name}]" ]]; then + zpool_ledmap[$zpool_dev_name]=${dev_to_led_map[${zpool_scsi_dev_name}]} + echo "zpool device" $zpool_dev_name ">>" $zpool_scsi_dev_name ">> LED:"${zpool_ledmap[$zpool_dev_name]} + fi + done <<< "$(zpool status -L | egrep ^\\s*\(sd\|dm\))" + + function zpool_check_loop() { + while true; do + while read line + do + zpool_dev_line=($line) + zpool_dev_name=${zpool_dev_line[0]} + zpool_dev_state=${zpool_dev_line[1]} + + # TODO: do something if the pool is unhealthy? + + if [[ -v "zpool_ledmap[${zpool_dev_name}]" ]]; then + led=${zpool_ledmap[$zpool_dev_name]} + + if [[ "$(cat /sys/class/leds/$led/color)" != "$COLOR_DISK_HEALTH" ]]; then + continue; + fi + + if [[ "${zpool_dev_state}" != "ONLINE" ]]; then + echo "$COLOR_ZPOOL_FAIL" > /sys/class/leds/$led/color + echo Disk failure detected on /dev/$dev at $(date +%Y-%m-%d' '%H:%M:%S) + fi + + # ==== To recover from an error, you should restart the script ==== + ## case "${zpool_dev_state}" in + ## ONLINE) + ## # echo "$COLOR_DISK_HEALTH" > /sys/class/leds/$led/color + ## ;; + ## *) + ## echo "255 0 0" > /sys/class/leds/$led/color + ## ;; + ## esac + fi + done <<< "$(zpool status -L | egrep ^\\s*\(sd\|dm\))" + + sleep ${CHECK_ZPOOL_INTERVAL}s + done + } + + zpool_check_loop & + zpool_check_pid=$! +fi + # check disk health if enabled if [ "$CHECK_SMART" = true ]; then ( while true; do for led in "${!devices[@]}"; do - if [[ "$(cat /sys/class/leds/$led/color)" = "255 0 0" ]]; then + if [[ "$(cat /sys/class/leds/$led/color)" != "$COLOR_DISK_HEALTH" ]]; then continue; fi dev=${devices[$led]} if [[ -z $(smartctl -H /dev/${dev} | grep PASSED) ]]; then - echo "255 0 0" > /sys/class/leds/$led/color + echo "$COLOR_SMART_FAIL" > /sys/class/leds/$led/color echo Disk failure detected on /dev/$dev at $(date +%Y-%m-%d' '%H:%M:%S) continue fi @@ -143,40 +263,42 @@ if [ "$CHECK_SMART" = true ]; then smart_check_pid=$! fi -# check for zpool-leds.sh and set variable -if [[ -f /usr/bin/zpool-leds.sh ]]; then - ZPOOL_LEDS="bash /usr/bin/zpool-leds.sh" -else - ZPOOL_LEDS="" -fi +# check disk online status +( + while true; do + for led in "${!devices[@]}"; do + dev=${devices[$led]} + + if [[ "$(cat /sys/class/leds/$led/color)" != "$COLOR_DISK_HEALTH" ]]; then + continue; + fi + if [[ ! -f /sys/class/block/${dev}/stat ]]; then + echo "$COLOR_DISK_UNAVAIL" > /sys/class/leds/$led/color 2>/dev/null + echo Disk /dev/$dev went offline at $(date +%Y-%m-%d' '%H:%M:%S) + continue + fi + done + sleep ${CHECK_DISK_ONLINE_INTERVAL}s + done +) & +disk_online_check_pid=$! + +# monitor disk activities declare -A diskio_data_rw while true; do for led in "${!devices[@]}"; do - dev=${devices[$led]} - diskio_old_rw="${diskio_data_rw[$led]}" - - if [[ "$(cat /sys/class/leds/$led/color)" = "255 0 0" ]]; then - continue; - fi - if [[ ! -f /sys/class/block/${dev}/stat ]]; then - echo "255 0 0" > /sys/class/leds/$led/color 2>/dev/null - echo Disk /dev/$dev went offline at $(date +%Y-%m-%d' '%H:%M:%S) - continue - fi - - diskio_new_rw="$(cat /sys/block/${dev}/stat)" + # if $dev does not exist, diskio_new_rw="", which will be safe + diskio_new_rw="$(cat /sys/block/${devices[$led]}/stat 2>/dev/null)" - if [ "${diskio_old_rw}" != "${diskio_new_rw}" ]; then + if [ "${diskio_data_rw[$led]}" != "${diskio_new_rw}" ]; then echo 1 > /sys/class/leds/$led/shot fi diskio_data_rw[$led]=$diskio_new_rw done - ${ZPOOL_LEDS} - sleep ${LED_REFRESH_INTERVAL}s done diff --git a/scripts/ugreen-ledmon.service b/scripts/ugreen-diskiomon.service similarity index 100% rename from scripts/ugreen-ledmon.service rename to scripts/ugreen-diskiomon.service diff --git a/scripts/ugreen-ledmon@.service b/scripts/ugreen-ledmon@.service deleted file mode 100644 index b969e65..0000000 --- a/scripts/ugreen-ledmon@.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=UGREEN LEDs daemon for monitoring diskio / netio (of %i) and blinking corresponding LEDs - -[Service] -ExecStartPre=/usr/bin/ugreen-probe-leds -ExecStartPre=/usr/bin/ugreen-netdevmon %i -ExecStart=/usr/bin/ugreen-diskiomon -StandardOutput=journal - -[Install] -WantedBy=multi-user.target - diff --git a/scripts/ugreen-leds.conf b/scripts/ugreen-leds.conf new file mode 100644 index 0000000..bdad232 --- /dev/null +++ b/scripts/ugreen-leds.conf @@ -0,0 +1,99 @@ + +# configuration file for ugreen-diskiomon and ugreen-netdevmon +# it should be put in /etc/ugreen-leds.conf + +# =========== parameters of disk activities monitoring =========== + +# The method of mapping disks to LEDs: ata, hctl, serial +# ata: default, also used in UGOS +# $> ls -ahl /sys/block | grep ata[0-9] --color +# * you should check whether it will change after reboot +# +# hctl: mapping by HCTL, +# $> lsblk -S -x hctl -o hctl,serial,name +# it will fail in some devices if you have USB disks inserted, but works well otherwise +# * you should check whether it will change after reboot +# ** see https://github.com/miskcoo/ugreen_dx4600_leds_controller/issues/14 +# +# serial: suggested, mapping by serial +# this method requires the user to check the disks' serial numbers +# and fill the DISK_SERIAL array below (see the comments therein). +MAPPING_METHOD=ata + +# The serial numbers of disks (used only when MAPPING_METHOD=serial) +# You need to record them before inserting to your NAS, and the corresponding disk slots. +# If you have 4 disks, with serial numbers: SN1 SN2 SN3 SN4, +# then the config below leads to the following mapping: +# SN1 -- disk1 +# SN2 -- disk2 +# SN3 -- disk3 +# SN4 -- disk4 +DISK_SERIAL="SN1 SN2 SN3 SN4" + +# The sleep time between two disk activities checks (default: 0.1 seconds) +LED_REFRESH_INTERVAL=0.1 + +# brightness of disk LEDs, taking value from 1 to 255 (default: 255) +BRIGHTNESS_DISK_LEDS="255" + +# color of a healthy disk (default: 255 255 255) +COLOR_DISK_HEALTH="255 255 255" + +# color of an unavailable disk (default: 255 0 0) +COLOR_DISK_UNAVAIL="255 0 0" + +# color of a failed zpool device (default: 255 0 0) +COLOR_ZPOOL_FAIL="255 0 0" + +# color of a device with unhealthy smart info (default: 255 0 0) +COLOR_SMART_FAIL="255 0 0" + +# Check the disk health by smartctl (default: true) +CHECK_SMART=true + +# The sleep time between two smart checks (default: 360 seconds) +CHECK_SMART_INTERVAL=360 + +# Check the zpool health (default: false) +CHECK_ZPOOL=false + +# The sleep time between two zpool checks (default: 5 seconds) +CHECK_ZPOOL_INTERVAL=5 + +# The sleep time between two disk online checks (default: 5 seconds) CHECK_DISK_ONLINE_INTERVAL=5 + + +# =========== parameters of network activities monitoring =========== + +# Blink the netdev light when sending data (default: 1) +NETDEV_BLINK_TX=1 + +# Blink the netdev light when receiving data (default: 1) +NETDEV_BLINK_RX=1 + +# A cycle of netdev blinking (default: 200 milliseconds) +NETDEV_BLINK_INTERVAL=200 + +# color of the netdev under the normal state (for CHECK_LINK_SPEED=false) +COLOR_NETDEV_NORMAL="255 255 255" + +# The sleep time between two netdev connectivity / link speed monitoring (default: 60 seconds) +CHECK_NETDEV_INTERVAL=60 + +# Monitor the gateway connectivity (default: false) +CHECK_GATEWAY_CONNECTIVITY=false + +# Monitor the link speed (default: false) +CHECK_LINK_SPEED=false + +# brightness of the netdev LED, taking value from 1 to 255 (default: 255) +BRIGHTNESS_NETDEV_LED="255" + +# color of the netdev under different link speeds (for CHECK_LINK_SPEED=true) +COLOR_NETDEV_LINK_100="255 255 255" +COLOR_NETDEV_LINK_1000="255 255 255" +COLOR_NETDEV_LINK_2500="255 255 255" +COLOR_NETDEV_LINK_10000="255 255 255" + +# color of the netdev when unable to ping the gateway +COLOR_NETDEV_GATEWAY_UNREACHABLE="255 0 0" diff --git a/scripts/ugreen-netdevmon b/scripts/ugreen-netdevmon index 8ff45c6..9348e33 100755 --- a/scripts/ugreen-netdevmon +++ b/scripts/ugreen-netdevmon @@ -1,13 +1,91 @@ #!/usr/bin/bash -{ lsmod | grep ledtrig_netdev ; } || modprobe -v ledtrig_netdev +# function for removing lockfile +exit-ugreen-netdevmon() { + if [[ -f "/var/run/ugreen-netdevmon.lock" ]]; then + rm "/var/run/ugreen-netdevmon.lock" + fi + kill $smart_check_pid 2>/dev/null + kill $zpool_check_pid 2>/dev/null + kill $disk_online_check_pid 2>/dev/null +} -sleep 2 +# trap exit and remove lockfile +trap 'exit-ugreen-netdevmon' EXIT + +# check if script is already running +if [[ -f "/var/run/ugreen-netdevmon.lock" ]]; then + echo "ugreen-netdevmon already running!" + exit 1 +fi +touch /var/run/ugreen-netdevmon.lock + +{ lsmod | grep ledtrig_netdev > /dev/null; } || { modprobe -v ledtrig_netdev && sleep 2; } + +# load environment variables +if [[ -f /etc/ugreen-leds.conf ]]; then + source /etc/ugreen-leds.conf +fi + +COLOR_NETDEV_NORMAL=${COLOR_NETDEV_NORMAL:="255 255 255"} +COLOR_NETDEV_GATEWAY_UNREACHABLE=${COLOR_NETDEV_GATEWAY_UNREACHABLE:="255 0 0"} + +BRIGHTNESS_NETDEV_LED=${BRIGHTNESS_NETDEV_LED:="255"} + +CHECK_NETDEV_INTERVAL=${CHECK_NETDEV_INTERVAL:=60} +CHECK_GATEWAY_CONNECTIVITY=${CHECK_GATEWAY_CONNECTIVITY:=false} +CHECK_LINK_SPEED=${CHECK_LINK_SPEED:=false} led="netdev" +netdev_name=$1 echo netdev > /sys/class/leds/$led/trigger -echo $1 > /sys/class/leds/$led/device_name +echo $netdev_name > /sys/class/leds/$led/device_name echo 1 > /sys/class/leds/$led/link -echo 1 > /sys/class/leds/$led/tx -echo 1 > /sys/class/leds/$led/rx -echo 200 > /sys/class/leds/$led/interval +echo ${NETDEV_BLINK_TX:=1} > /sys/class/leds/$led/tx +echo ${NETDEV_BLINK_RX:=1} > /sys/class/leds/$led/rx +echo ${NETDEV_BLINK_INTERVAL:=200} > /sys/class/leds/$led/interval +echo $COLOR_NETDEV_NORMAL > /sys/class/leds/$led/color +echo $BRIGHTNESS_NETDEV_LED > /sys/class/leds/$led/brightness + +function set_netdev_normal_color() { + color=$COLOR_NETDEV_NORMAL + + if [[ $CHECK_LINK_SPEED == true ]]; then + case $(cat /sys/class/net/$netdev_name/speed) in + 100) color=${COLOR_NETDEV_LINK_100:=$COLOR_NETDEV_NORMAL};; + 1000) color=${COLOR_NETDEV_LINK_1000:=$COLOR_NETDEV_NORMAL};; + 2500) color=${COLOR_NETDEV_LINK_2500:=$COLOR_NETDEV_NORMAL};; + 10000) color=${COLOR_NETDEV_LINK_10000:=$COLOR_NETDEV_NORMAL};; + esac + fi + + echo $color > /sys/class/leds/$led/color +} + +if [[ $CHECK_GATEWAY_CONNECTIVITY == false && $CHECK_LINK_SPEED == false ]]; then + exit 0 +fi + +gw_conn=1 + +while true; do + + if [[ $CHECK_GATEWAY_CONNECTIVITY == true ]]; then + gw=$(ip route | awk '/default/ { print $3 }') + if ping -q -c 1 -W 1 $gw >/dev/null; then + gw_conn=1 + else + gw_conn=0 + fi + fi + + if [[ $gw_conn == 1 ]]; then + set_netdev_normal_color + else + echo $COLOR_NETDEV_GATEWAY_UNREACHABLE > /sys/class/leds/$led/color + fi + + + sleep ${CHECK_NETDEV_INTERVAL}s + +done diff --git a/scripts/ugreen-netdevmon@.service b/scripts/ugreen-netdevmon@.service new file mode 100644 index 0000000..d0a2556 --- /dev/null +++ b/scripts/ugreen-netdevmon@.service @@ -0,0 +1,11 @@ +[Unit] +Description=UGREEN LEDs daemon for monitoring netio (of %i) and blinking corresponding LEDs + +[Service] +ExecStartPre=/usr/bin/ugreen-probe-leds +ExecStart=/usr/bin/ugreen-netdevmon %i +StandardOutput=journal + +[Install] +WantedBy=multi-user.target +