Advertisement
Guest User

Untitled

a guest
Apr 24th, 2018
1,473
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 14.77 KB | None | 0 0
  1. #!/bin/bash
  2.  
  3. ####################################################################################
  4. # s3_sleep
  5. # A utility to set conditional S3 sleep mode
  6. # This script has been adapted from the original S3 script available on the Limetech
  7. # forum. It accepts parameter options to overwrite the default settings.
  8. # Copied some parts from "cache_dirs" to get a similar background behaviour.
  9. #
  10. # Version 1.0.0   Initial version
  11. # Version 1.1.0   Corrections in HDD, TCP and IP monitoring and other adjustments
  12. # Version 1.1.1   Added -t <time> option to set network/device inactivity interval
  13. # Version 1.1.2   Added -e <eth> option to set ethernet interface to monitor
  14. # Version 1.1.3   Added -w option to set wol options prior to sleep
  15. #                 Added -S option to sleep now
  16. # Version 1.1.4   Added -b option to execute shell script before sleep
  17. #                 Added -p option to execute shell script after wake-up
  18. #
  19. # Version 1.2.0   Added program logging upon start
  20. # Version 2.0.0   Added action "sleep" or "shutdown"
  21. # Version 2.1.0   Added improvements for TCP and session monitoring, debugging option
  22. #                 Added -c option to exclude cache drive from array monitoring
  23. #                 Added -L option to allow remote session monitoring (SSH)
  24. #                 Added -l option to allow local session monitoring (TTY)
  25. #                 Added -N option to set idle threshold for TCP monitoring
  26. #                 Added -D option to allow debugging (troubleshooting)
  27. #                 Based on suggestions made by 'Bagpuss'
  28. # Version 2.1.1   SlrG added feature to include/exclude drives outside of array
  29. # Version 2.1.2   SlrG fix cache drive list inclusion
  30. # Version 3.0.0   Code rewrite, remove bwm-ng dependency
  31. # Version 3.0.1   Move immediate sleep to front
  32. # Version 3.0.2   Include SCSI attached drives in array list
  33. # Version 3.0.3   Changed HDD activity check to allow RAID controllers (courtesy Michael A.)
  34. # Version 3.0.4   Fixed full path to powerdown script
  35. # Version 3.0.5   HDD activity check includes both disk state and disk I/O activity
  36. # Version 3.0.6   Support for unRAID 6.4
  37. #                 Correction for Cache pool
  38. # Version 3.0.6.1 Remove hdparm activity check
  39. #
  40. # Bergware International
  41. ####################################################################################
  42. version=3.0.6.1
  43. program=$(basename $0)
  44. ini=/var/local/emhttp/disks.ini
  45.  
  46. # Get flash device
  47. getFlash() {
  48.   flash=$(grep -A1 '^name="flash' $ini|sed -r '/^--/d;/^name=/d;s/"//g;s/^device=//')
  49. }
  50.  
  51. # Get list of cache devices (if present)
  52. getCache() {
  53.   cache=$(grep -A1 '^name="cache' $ini|sed -r '/^--/d;/^name=/d;s/"//g;s/^device=//')
  54. }
  55.  
  56. # Get list of array devices
  57. getArray() {
  58.   array=($(grep -PA1 '^name="(parity|disk)' $ini|sed -r '/^--/d;/^name=/d;s/"//g;s/^device=//'))
  59. }
  60.  
  61. # Get list of all devices
  62. getDisks() {
  63.   disks=($(ls -l /dev/disk/by-id/[asu]*|awk -F/ '$0!~/part1/{print $7"="$5}'|sed 's/\(usb\|ata\|scsi|ide\)-//;s/ -> ..$//'))
  64. }
  65.  
  66. # list devices outside of array
  67. if [[ $1 == -ED ]]; then
  68.   getFlash
  69.   getCache
  70.   getArray
  71.   array+=($flash);
  72.   [[ -n $cache ]] && array+=($cache)
  73.   getDisks
  74.   # Remove not excludable devices from list
  75.   for dev in ${array[@]}; do
  76.     disks=(${disks[@]//*$dev=*})
  77.   done
  78.   [[ -n $disks ]] && echo ${disks[@]}|sort
  79.   exit 0
  80. fi
  81.  
  82. usage() {
  83.  echo
  84.  echo "Usage: $program [-acnRFSLlVq] [-I disk] [-N idle] [-i ip] [-d day] [-h hour] [-m time] [-t time] [-e eth] [-w wol] [-b name] [-p name] [-C case] [-D 0-4] [-ED]"
  85.  echo " -a          wait for array inactivity"
  86.  echo " -c          exclude cache drive from array monitoring"
  87.  echo " -I disk     include outside of array disk (may be repeated for other disks)"
  88.  echo " -n          wait for network inactivity"
  89.  echo " -N idle     set TCP idle threshold"
  90.  echo " -R          do DHCP renewal after wake-up"
  91.  echo " -F          force gigabit speed after wake-up"
  92.  echo " -S          sleep NOW"
  93.  echo " -i ip       IP address to ping (may be repeated as many times as desired)"
  94.  echo " -L          check remotely logged in users (SSH)"
  95.  echo " -l          check locally logged in users"
  96.  echo " -d day      Excluded day (may be repeated as many times as desired)"
  97.  echo " -h hour     Excluded hour (may be repeated as many times as desired)"
  98.  echo " -m time     extra delay after array inactivity"
  99.  echo " -t time     interval of network / device inactivity"
  100.  echo " -e eth      select interface to monitor"
  101.  echo " -w wol      set WOL options before sleep"
  102.  echo " -b name     execute shell script 'name' before sleep"
  103.  echo " -p name     execute shell script 'name' after wake-up"
  104.  echo " -C case     execute case (1) sleep or (2) shutdown"
  105.  echo " -D 0-4      set debug reporting (0-4)"
  106.  echo " -ED         print drives outside of array and exit"
  107.  echo " -V          print program version and exit"
  108.  echo " -q          terminate running background instance of s3_sleep"
  109. }
  110.  
  111. # default settings
  112. action=sleep
  113. debug=0
  114. checkCache=yes
  115.  
  116. # before going to sleep/shutdown
  117. delayInit=30          # delay in minutes after HDD spindown and before checking for external activity
  118.  
  119. # control of internal conditions
  120. checkHDD=no           # check if HDDs are parked before counting down towards sleep
  121. outside=()            # list of drives outside array to include in monitoring
  122. skipDay=()            # only countdown towards sleep outside these days
  123.                       # example: <skipDay="0 6"> (skip Sunday and Saturday)
  124. skipHour=()           # only countdown towards sleep outside these hours
  125.                       # example: <skipHour="07 08 19 20">
  126.  
  127. # control of external conditions
  128. checkTCP=no           # check for TCP activity
  129. eth=eth0              # interface to monitor TCP activity
  130. idle=0                # threshold of TCP activity in KB
  131. checkSSH=no           # check for remote login sessions (telnet or SSH)
  132. checkTTY=no           # check for local login sessions (if "no" allows console debugging)
  133. hosts=()              # do not sleep when 'hosts' are pingable
  134.                       # example: <hosts="192.168.1.1 172.16.1.1">
  135.  
  136. # before sleep
  137. setWol=               # set wol options before sleep
  138. preRun=               # no additional commands to run
  139.  
  140. # after waking up
  141. dhcpRenew=no          # <no> for servers w/static IP address
  142. forceGb=no            # might not be needed; probably always safe
  143. postRun=              # no additional commands to run
  144.  
  145. # program control
  146. quit_flag=no          # signal program exit
  147. sleepNow=no           # force immediate sleep now
  148.  
  149. # options to overwrite defaults
  150. while getopts "acnN:i:I:d:h:m:t:e:C:w:RFqVSLlb:p:D:" opt; do
  151.   case $opt in
  152.     a) checkHDD=yes ;;
  153.     c) checkCache=no ;;
  154.     I) outside+=($OPTARG) ;;
  155.     n) checkTCP=yes ;;
  156.     N) idle=$OPTARG ;;
  157.     i) hosts+=($OPTARG) ;;
  158.     d) skipDay+=($OPTARG) ;;
  159.     h) skipHour+=($OPTARG) ;;
  160.     m) delayInit=$OPTARG ;;
  161.     t) timerInit=$OPTARG ;;
  162.     e) eth=$OPTARG ;;
  163.     C) case $OPTARG in
  164.          1) action=sleep ;;
  165.          2) action=shutdown ;;
  166.        esac ;;
  167.     w) setWol=$OPTARG ;;
  168.     R) dhcpRenew=yes ;;
  169.     F) forceGb=yes ;;
  170.     S) sleepNow=yes ;;
  171.     L) checkSSH=yes ;;
  172.     l) checkTTY=yes ;;
  173.     b) preRun=$OPTARG ;;
  174.     p) postRun=$OPTARG ;;
  175.     D) debug=$OPTARG ;;
  176.     q) quit_flag=yes ;;
  177.    \?) usage; exit ;;
  178.     V) echo $program version: $version ; exit ;;
  179.   esac
  180. done
  181.  
  182. # Debug logging options for troubleshooting (use -D option)
  183. # debug=0 - no logging (default)
  184. # debug=1 - log to syslog and s3_sleep.log
  185. # debug=2 - log to syslog
  186. # debug=3 - log to s3_sleep.log
  187. # debug=4 - log to console
  188.  
  189. # Use this feature only in case of sleep not working
  190. # It is intended to help in troubleshooting
  191. log() {
  192.   case $debug in
  193.     1) logger -t "$program" "$1"
  194.        echo "`date`: $1" >>/boot/logs/$program.log ;;
  195.     2) logger -t "$program" "$1" ;;
  196.     3) echo "`date`: $1" >>/boot/logs/$program.log ;;
  197.     4) echo "`date`: $1" ;;
  198.   esac
  199. }
  200.  
  201. exclude_period() {
  202.   result=
  203.   if [[ -n $skipDay ]]; then
  204.     day=$(date +%w)
  205.     for now in ${skipDay[@]}; do
  206.       if [[ $now == $day ]]; then
  207.         result=1
  208.         break
  209.       fi
  210.     done
  211.   fi
  212.   if [[ -n $skipHour && -z $result ]]; then
  213.     hour=$(date +%H)
  214.     for now in ${skipHour[@]}; do
  215.       if [[ $now == $hour ]]; then
  216.         result=1
  217.         break
  218.       fi
  219.     done
  220.   fi
  221.   if [[ -n $result ]]; then
  222.     log "Excluded day [$day] or hour [$hour]."
  223.     echo $result
  224.   fi
  225. }
  226.  
  227. HDD_activity() {
  228.   result=
  229.   if [[ $checkHDD == yes ]]; then
  230.     [[ -f /dev/shm/2 ]] && cp -f /dev/shm/2 /dev/shm/1 || touch /dev/shm/1
  231.     awk '/(sd[a-z]*|nvme[0-9]n1) /{print $3,$6+$10}' /proc/diskstats >/dev/shm/2
  232.     for dev in ${array[@]}; do
  233.         if [[ -n $(diff /dev/shm/1 /dev/shm/2|grep -m1 "$dev ") ]]; then
  234.       # active=$(hdparm -C /dev/$dev 2>/dev/null|grep active)
  235.       # diskio=($(grep -Pho "^$dev \K\d+" /dev/shm/1 /dev/shm/2))
  236.       # if [[ -n $active || ${diskio[0]} != ${diskio[1]} ]]; then
  237.         result=1
  238.         break;
  239.       fi
  240.     done
  241.   fi
  242.   if [[ -n $result ]]; then
  243.     log "Disk activity on going: $dev"
  244.     echo $result
  245.   fi
  246. }
  247.  
  248. txrx_bytes() {
  249.   echo $(awk "/$eth:/{print \$2+\$10}" /proc/net/dev)
  250. }
  251.  
  252. TCP_activity() {
  253.   result=
  254.   if [[ $checkTCP == yes ]]; then
  255.     delta=$((($(txrx_bytes)-$start)/120))
  256.     [[ $delta -gt $idle ]] && result=1
  257.   fi
  258.   if [[ -n $result ]]; then
  259.     log "Network activity on going: $(($delta*8)) b/s"
  260.     echo $result
  261.   fi
  262. }
  263.  
  264. IP_activity() {
  265.   result=
  266.   if [[ -n $hosts ]]; then
  267.     for ip in ${hosts[@]}; do
  268.       if [[ $(ping -n -q -c 2 $ip|awk '/received/ {print $4}') -gt 0 ]]; then
  269.         result=1
  270.         break
  271.       fi
  272.     done
  273.   fi
  274.   if [[ -n $result ]]; then
  275.     log "Host activity on going: $ip"
  276.     echo $result
  277.   fi
  278. }
  279.  
  280. TTY_activity() {
  281.   result=
  282.   [[ $checkTTY == yes && $(ps -o command,tty|grep '^\-bash'|grep 'tty'|wc -l) -gt 0 ]] && result=1
  283.   if [[ -n $result ]]; then
  284.     log "Local activity on going: console"
  285.     echo $result
  286.   fi
  287. }
  288.  
  289. SSH_activity() {
  290.   result=
  291.   [[ $checkSSH == yes && $(lsof -O -w -l -i -n -P|awk '/:(22|23)-.*\(ESTABLISHED\)$/'|wc -l) -gt 0 ]] && result=1
  292.   if [[ -n $result ]]; then
  293.     log "Remote activity on going: telnet/ssh"
  294.     echo $result
  295.   fi
  296. }
  297.  
  298. pre_sleep_activity() {
  299. # Set WOL MagicPacket options
  300.   if [[ -n $setWol ]]; then
  301.     log "Send WOL commands: $setWol"
  302.     ethtool -s $eth wol $setWol
  303.   fi
  304. # Additional commands to run
  305.   if [[ -x $preRun ]]; then
  306.     log "Execute custom commands before sleep"
  307.     $preRun
  308.   fi
  309. }
  310.  
  311. post_sleep_activity() {
  312. # Force NIC to use gigabit networking
  313.   if [[ $forceGb == yes ]]; then
  314.     log "Set NIC to forced gigabit speed"
  315.     ethtool -s $eth speed 1000
  316.     sleep 2
  317.   fi
  318. # Force a DHCP renewal (do not use for static-ip assignments)
  319.   if [[ $dhcpRenew == yes ]]; then
  320.     log "Perform DHCP renewal"
  321.     /sbin/dhcpcd -n
  322.     sleep 5
  323.   fi
  324. # Additional commands to run
  325.   if [[ -x $postRun ]]; then
  326.     log "Execute custom commands after wake-up"
  327.     $postRun
  328.   fi
  329. }
  330.  
  331. system_sleep() {
  332. # Do pre-sleep activities
  333.   pre_sleep_activity
  334. # Go to sleep
  335.   log "Enter sleep state now"
  336.   echo -n mem >/sys/power/state
  337. # Do post-sleep activities
  338.   log "Wake-up now"
  339.   post_sleep_activity
  340. }
  341.  
  342. system_down() {
  343.   log "Shutdown system now"
  344. # Perform a 'clean' powerdown
  345.   if [[ -x /sbin/poweroff ]]; then
  346.     /sbin/poweroff
  347.   elif [[ -x /user/local/sbin/powerdown ]]; then
  348.     /usr/local/sbin/powerdown
  349.   else
  350.     log "No powerdown script present"
  351.   fi
  352. }
  353.  
  354. # Immediate sleep or shutdown
  355. if [[ $sleepNow == yes ]]; then
  356.   [[ $action == sleep ]] && system_sleep || system_down
  357.   exit 0
  358. fi
  359.  
  360. # Get all available devices
  361. getFlash
  362. getCache
  363. getArray
  364. getDisks
  365. [[ $checkCache == yes ]] && array+=($cache)
  366. for dev in ${outside[@]}; do
  367.   array+=($dev)
  368. done
  369. for dev in ${array[@]}; do
  370.   disks=(${disks[@]//*$dev=*})
  371. done
  372. for dev in ${disks[@]}; do
  373.   disks=(${disks[@]//=*})
  374. done
  375. array=($(echo ${array[@]}|tr ' ' '\n'|sort))
  376. disks=($(echo ${disks[@]}|tr ' ' '\n'|sort))
  377. [[ -n $hosts ]] && devices=${hosts[@]} || devices=no
  378.  
  379. echo "----------------------------------------------
  380. command-args=$*
  381. action mode=$action
  382. check disks status=$checkHDD
  383. check network activity=$checkTCP
  384. check active devices=$devices
  385. check local login=$checkTTY
  386. check remote login=$checkSSH
  387. version=$version
  388. ----------------------------------------------
  389. included disks=${array[@]}
  390. excluded disks=${disks[@]}
  391. ----------------------------------------------" | logger -t$program
  392.  
  393. lockfile=/var/lock/s3_sleep.lck
  394. if [[ -f $lockfile ]]; then
  395.   # The file exists so read the PID to see if it is still running
  396.   lock_pid=$(head -n 1 $lockfile)
  397.   if [[ -z $(ps -p $lock_pid|grep $lock_pid) ]]; then
  398.     if [[ $quit_flag == no ]]; then
  399.       # The process is not running, echo current PID into lock file
  400.       echo $$ >$lockfile
  401.     else
  402.       echo "$program $lock_pid is not currently running "
  403.       rm -f $lockfile
  404.       exit 0
  405.     fi
  406.   else
  407.     if [[ $quit_flag == yes ]]; then
  408.       echo killing $program process $lock_pid
  409.       echo killing $program process $lock_pid | logger -t$program
  410.       kill $lock_pid
  411.       rm -f $lockfile
  412.       exit 0
  413.     else
  414.       echo "$program is already running [$lock_pid]"
  415.       exit 1
  416.     fi
  417.   fi
  418. else
  419.   if [[ $quit_flag == yes ]]; then
  420.     echo "$program not currently running "
  421.     exit 0
  422.   else
  423.     echo $$ >$lockfile
  424.   fi
  425. fi
  426.  
  427. # main (continuous loop)
  428. extraDelay=$delayInit
  429. [[ $checkTCP == yes ]] && start=0 || start=-1
  430. while [[ -f $lockfile ]]; do
  431.   if [[ -z $(exclude_period) ]]; then
  432.     if [[ -z $(HDD_activity) ]]; then
  433.       log "All monitored HDDs are spun down"
  434.       if [[ $extraDelay -ge 0 ]]; then
  435.         log "Extra delay period running: $extraDelay minute(s)"
  436.         ((extraDelay--))
  437.       fi
  438.     else
  439.       log "Disk activity detected. Reset timers."
  440.       extraDelay=$delayInit
  441.     fi
  442.     if [[ $extraDelay -lt 0 ]]; then
  443.       if [[ $start -eq 0 ]]; then
  444.         log "Initialize TCP activity counter"
  445.         start=$(txrx_bytes)
  446.       else
  447.         log "Check TCP/SSH/TTY/IP activity"
  448.         if [[ -z $(TCP_activity) && -z $(SSH_activity) && -z $(TTY_activity) && -z $(IP_activity) ]]; then
  449.           log "Communication state is idle"
  450.           [[ $action == sleep ]] && system_sleep || system_down
  451.           log "System woken-up. Reset timers"
  452.           extraDelay=$delayInit
  453.           [[ $checkTCP == yes ]] && start=0 || start=-1
  454.         fi
  455.         [[ $start -gt 0 ]] && start=$(txrx_bytes)
  456.       fi
  457.     fi
  458.   fi
  459.   sleep 60
  460. done &
  461.  
  462. # while loop was put into background, now disown it, so it will continue to run when user is logged off
  463. background_pid=$!
  464. echo $background_pid >$lockfile
  465. echo "$program process ID $background_pid started, To terminate it, type: $program -q"
  466. echo "$program process ID $background_pid started, To terminate it, type: $program -q"|logger -t$program
  467. disown %%
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement