functions.sh 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. #!/bin/sh
  2. # useful functions
  3. # 2013-09-26 11:00 created by niujiuru
  4. # 2026-01-05 13:40 updated by niujiuru
  5. # 2026-03-10 09:20 updated by niujiuru
  6. # export envionment variables
  7. export_env()
  8. {
  9. PATH="/bin:/sbin:/usr/bin:/usr/sbin"
  10. CWD=$(cd "$(dirname "$0")" && pwd) || exit 1
  11. export PATH CWD
  12. }
  13. # load module by name
  14. # pass THIS_MODULE to module
  15. # $1: module name (no path, no '..')
  16. load_module()
  17. {
  18. local module="$1"
  19. [ -n "$module" ] || return 1
  20. case "$module" in
  21. */*|*..*) return 1 ;;
  22. esac
  23. THIS_MODULE="${module}"
  24. [ -f "${CWD}/modules/${module}" ] || return 1
  25. . "${CWD}/modules/${module}"
  26. }
  27. # load module & call module's method
  28. # $1: module name
  29. # $2: method name (function defined in module)
  30. # $...: method params
  31. call_module()
  32. {
  33. [ $# -ge 2 ] || return 1
  34. local module="$1"
  35. local method="$2"
  36. shift 2
  37. load_module "$module" || return 1
  38. type "$method" >/dev/null 2>&1 || return 1
  39. "$method" "$@"
  40. return $?
  41. }
  42. # check if the program is currently running
  43. # $1: program's executable path
  44. # return 0 if running, 1 otherwise
  45. is_running()
  46. {
  47. local target="$1" pid exe
  48. [ -n "$target" ] || return 1
  49. case "$target" in
  50. /*) ;; # 必须是绝对路径
  51. *) return 1 ;;
  52. esac
  53. for pid in /proc/[0-9]*; do
  54. exe=$(readlink "$pid/exe" 2>/dev/null) || continue
  55. exe="${exe% (deleted)}"
  56. [ "$exe" = "$target" ] && return 0
  57. done
  58. return 1
  59. }
  60. # kill program(s) by path
  61. # $1: program's executable path
  62. # $2: signal to send (default: 15)
  63. kill_by_path()
  64. {
  65. local target="$1" pid exe
  66. local sig=${2:-15}
  67. [ -n "$target" ] || return 1
  68. case "$sig" in
  69. ''|*[!0-9]*) return 1 ;;
  70. esac
  71. [ "$sig" -ge 1 ] && [ "$sig" -le 64 ] 2>/dev/null || return 1
  72. for pid in /proc/[0-9]*; do
  73. exe=$(readlink "$pid/exe" 2>/dev/null) || continue
  74. exe="${exe% (deleted)}"
  75. if [ "$exe" = "$target" ]; then
  76. kill -$sig "${pid##*/}" 2>/dev/null
  77. fi
  78. done
  79. }
  80. # gracefully terminate program by executable path
  81. # send SIGTERM and wait, then SIGKILL if timeout
  82. # $1: program's executable path
  83. # $2: timeout in seconds (default: 5)
  84. # return 0 if terminated gracefully
  85. # return 1 function failed
  86. # return 2 if force killed after timeout
  87. graceful_kill() {
  88. local target="$1" timeout="${2:-5}"
  89. [ -n "$target" ] || return 1
  90. kill_by_path "$target" 15 || return 1
  91. if ! wait_for_exit "$target" "$timeout"; then
  92. kill_by_path "$target" 9
  93. return 2
  94. fi
  95. return 0
  96. }
  97. # wait until a program exits
  98. # $1: program's executable path
  99. # $2: timeout in seconds (default: 5)
  100. # return 0 if the program exited within timeout
  101. # return 1 if still running after timeout
  102. wait_for_exit()
  103. {
  104. local target="$1" timeout="${2:-5}" waited=0
  105. while is_running "$target" && [ "$waited" -lt "$timeout" ]; do
  106. sleep 1
  107. waited=$((waited + 1))
  108. done
  109. is_running "$target" && return 1
  110. return 0
  111. }