소스 검색

1-优化控制脚本,使用全路径匹配控制程序的启动和退出,更加严谨; 2-优化控制脚本,避免serverdaemon守护进程同一时刻启动多个; 3-优化控制脚本,不再依赖ps、awk等命令,使得更加严谨,容错率更高,更便于移植;4,其它代码优化

niujiuru 6 일 전
부모
커밋
e71fdcaa32
6개의 변경된 파일177개의 추가작업 그리고 24개의 파일을 삭제
  1. 72 3
      main.go
  2. 8 1
      scripts/modules/daemon
  3. 77 14
      scripts/modules/funcs/functions.sh
  4. 2 1
      scripts/modules/myapp
  5. 12 1
      scripts/serverdaemon
  6. 6 4
      sshd/sshd.go

+ 72 - 3
main.go

@@ -2,6 +2,7 @@ package main
 
 import (
 	"fmt"
+	"os"
 	"time"
 
 	gps "hnyfkj.com.cn/rtu/linux/air530z"
@@ -11,6 +12,66 @@ import (
 	"hnyfkj.com.cn/rtu/linux/sshd"
 )
 
+const (
+	rcLocalTxt = `
+#!/bin/sh -e
+#
+# rc.local
+#
+# This script is executed at the end of each multiuser runlevel.
+# Make sure that the script will "exit 0" on success or any other
+# value on error.
+#
+# In order to enable or disable this script just change the execution
+# bits.
+#
+# By default this script does nothing.
+
+#设置系统主频
+echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
+echo 528000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
+
+#设置一秒落盘(是低功耗产品时, RTU数据板可能随时掉电, 长供电产品, 不需要设置)
+#echo 100 > /proc/sys/vm/dirty_writeback_centisecs
+#echo 100 > /proc/sys/vm/dirty_expire_centisecs
+
+#启动运行程序
+/home/root/rtu_linux_modules/script/stop
+/home/root/rtu_linux_modules/script/start
+
+exit 0
+`
+	rcLocalFile = "/etc/rc.local"
+)
+
+func enableAutoStartOnBoot() error {
+	if _, err := os.Stat(rcLocalFile); err == nil {
+		bakFile := rcLocalFile + "." + time.Now().Format("20060102150405")
+		err = os.Rename(rcLocalFile, bakFile)
+		if err != nil {
+			return err
+		}
+	}
+
+	f, err := os.OpenFile(rcLocalFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	_, err = f.WriteString(rcLocalTxt)
+	if err != nil {
+		return err
+	}
+
+	err = os.Chmod(rcLocalFile, 0755)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 func main() {
 	if baseapp.IsArgsParam("-h") {
 		help()
@@ -22,6 +83,16 @@ func main() {
 		return
 	}
 
+	if baseapp.GetArgsParamStr("-install", "") == "boot" {
+		err := enableAutoStartOnBoot()
+		if err != nil {
+			fmt.Printf("设置开机自启动失败: %v", err)
+		} else {
+			fmt.Println("设置开机自启动成功")
+		}
+		return
+	}
+
 	baseapp.ModuleInit()
 	baseapp.SingleInstanceRun() // 异步非阻塞
 	baseapp.Logger.Infof("程序版本: %s 构建时间: %s\n程序开始运行...",
@@ -40,9 +111,7 @@ func main() {
 	netmgrd.WaitAllOK(time.Duration(10) * time.Second) // 等待联网成功和网路时间同步成功
 
 	// 04, 初始化远程运维模块, Todo: 根据项目不同, 远程运维连接的MQTT服务器不同, 具体看情况
-	if err := sshd.ModuleInit("", "", ""); err != nil {
-		baseapp.Logger.Warnf("初始化远程运维模块失败: %v", err)
-	}
+	sshd.ModuleInit("", "", "")
 
 	// 05, 初始化相机拍照模块
 	if !camera1.ModuleInit() {

+ 8 - 1
scripts/modules/daemon

@@ -1,6 +1,7 @@
 #!/bin/sh
 # start up and monitor servers
 # 2013-09-27 10:28 created by niujiuru
+# 2026-01-05 13:40 updated by niujiuru
 
 start()
 {
@@ -9,5 +10,11 @@ start()
 
 stop()
 {
-  kill_programs serverdaemon
+  pidfile="${APPRUNS_PATH}/serverdaemon.pid"
+  [ -f "$pidfile" ] || return 0
+
+  pid=$(cat ${APPRUNS_PATH}/serverdaemon.pid)
+  kill -9 "$pid" 2>/dev/null
+
+  rm -f "$pidfile"
 }

+ 77 - 14
scripts/modules/funcs/functions.sh

@@ -1,55 +1,118 @@
 #!/bin/sh
 # useful functions
 # 2013-09-26 11:00 created by niujiuru
+# 2026-01-05 13:40 updated by niujiuru
 
 # export envionment variables
 export_env()
 {
   PATH="/bin:/sbin:/usr/bin:/usr/sbin"
-
-  CWD=$(dirname $0)
-  [ "${CWD%%[^/]*}" != "/" ] && CWD="${PWD}/${CWD}"
-
+  CWD=$(cd "$(dirname "$0")" && pwd) || exit 1
   export PATH CWD
 }
 
 # load module by name
 # pass THIS_MODULE to module
-# $1: module name
+# $1: module name (no path, no '..')
 load_module()
 {
   local module="$1"
+
+  [ -n "$module" ] || return 1
+
+  case "$module" in
+    */*|*..*) return 1 ;;
+  esac
+
   THIS_MODULE="${module}"
-  . ${CWD}/modules/${module}
+  [ -f "${CWD}/modules/${module}" ] || return 1
+
+  . "${CWD}/modules/${module}"
 }
 
 # load module & call module's method
 # $1: module name
-# $2: method name
+# $2: method name (function defined in module)
 # $...: method params
 call_module()
 {
+  [ $# -ge 2 ] || return 1
+
   local module="$1"
   local method="$2"
+
   shift 2
-  load_module "$module" && "$method" $*
+  load_module "$module" || return 1
+  type "$method" >/dev/null 2>&1 || return 1
+  "$method" "$@"
+ 
   return $?
 }
 
 # return true if program is running
-# $1: program's name
+# $1: program's executable path
+# return 0 if running, 1 otherwise
 is_running()
 {
-  ps | grep -w "$1" | grep -v "grep" &>/dev/null
+  local target="$1" pid exe
+
+  [ -n "$target" ] || return 1
+
+  for pid in /proc/[0-9]*; do
+    [ -r "$pid/exe" ] || continue
+    exe=$(readlink "$pid/exe" 2>/dev/null) || continue
+    [ "$exe" = "$target" ] && return 0
+  done
+
+  return 1
 }
 
 # kill program(s) by name
-# $1: program name
+# $1: program's executable path
+# $2: signal to send (default: 15)
 kill_programs()
 {
+  local target="$1" pid exe
   local sig=${2:-15}
-  for p in $(ps | grep -w "$1" | grep -v "grep" | awk '{print $1}')
-  do
-    kill -$sig $p
+
+  [ -n "$target" ] || return 1
+
+  case "$sig" in
+    ''|*[!0-9]*) return 1 ;;
+  esac
+  [ "$sig" -ge 1 -a "$sig" -le 64 ] 2>/dev/null || return 1
+
+  for pid in /proc/[0-9]*; do
+    [ -r "$pid/exe" ] || continue
+    exe=$(readlink "$pid/exe" 2>/dev/null) || continue
+    if [ "$exe" = "$target" ]; then
+      kill -$sig "${pid##*/}" 2>/dev/null
+    fi
+  done
+}
+
+# gracefully terminate program by executable path
+# send SIGTERM and wait, then SIGKILL if timeout
+# $1: program's executable path
+# $2: timeout in seconds (default: 5)
+# return 0 if terminated gracefully
+# return 2 if force killed after timeout
+graceful_kill() {
+  local target="$1" timeout="${2:-5}" waited=0
+
+  [ -n "$target" ] || return 1
+
+  kill_programs "$target" 15 || return 1
+
+  while is_running "$target" && [ "$waited" -lt "$timeout" ]; do
+    sleep 1
+    waited=$((waited + 1))
   done
+
+  if is_running "$target"; then
+    kill_programs "$target" 9
+    return 2
+  fi
+
+  return 0
 }

+ 2 - 1
scripts/modules/myapp

@@ -1,6 +1,7 @@
 #!/bin/sh
 # start/stop an application
 # 2014-07-29 09:45 created by niujiuru
+# 2026-01-05 13:40 updated by niujiuru
 
 start()
 {
@@ -10,5 +11,5 @@ start()
 
 stop()
 {
-  kill_programs ${APPNAME} 9
+  graceful_kill ${APPBINS_PATH}/${APPNAME}
 }

+ 12 - 1
scripts/serverdaemon

@@ -1,16 +1,27 @@
 #!/bin/sh
 # a daemon, start and monitor servers
 # 2013-09-27 09:28 created by niujiuru
+# 2026-01-05 13:40 updated by niujiuru
 
 . $(dirname $0)/set_env
 . $(dirname $0)/modules/funcs/functions.sh
 export_env
 
 INTERVAL=60
+pidfile="${APPRUNS_PATH}/serverdaemon.pid"
+
+if [ -f "$pidfile" ]; then
+  pid=$(cat "$pidfile")
+  kill -0 "$pid" 2>/dev/null && exit 0
+  rm -f "$pidfile"
+fi
+
+mkdir -p "$(dirname "$pidfile")"
+echo $$ > "$pidfile"
 
 while true
 do
-  if ! is_running "${APPNAME}"
+  if ! is_running "${APPBINS_PATH}/${APPNAME}"
   then
     echo "starting ${APPNAME}: ${APPBINS_PATH}/${APPNAME} &"
     rm -rf ${APPRUNS_PATH}/*.lock

+ 6 - 4
sshd/sshd.go

@@ -49,9 +49,10 @@ type MQTTCoupler struct {
 	registerRpcMeths *singletask.OnceTask // 注册方法, 单实例
 }
 
-func ModuleInit(mqttBroker, mqttUsername, mqttPassword string) error {
+func ModuleInit(mqttBroker, mqttUsername, mqttPassword string) bool {
 	if mqttBroker == "" {
-		return ErrBrokerAddressEmpty
+		baseapp.Logger.Errorf("[%s] 初始化远程运维模块失败: %v!!", MODULE_NAME, ErrBrokerAddressEmpty)
+		return false
 	}
 
 	ctx, cancel := context.WithCancel(context.Background())
@@ -71,11 +72,12 @@ func ModuleInit(mqttBroker, mqttUsername, mqttPassword string) error {
 	}
 
 	if err := Coupler.init(); err != nil {
-		return err
+		baseapp.Logger.Errorf("[%s] 初始化远程运维模块失败: %v!!", MODULE_NAME, err)
+		return false
 	}
 	go Coupler.keepOnline()
 
-	return nil
+	return true
 }
 
 func ModuleExit() {