diff --git a/edge/agent/internal/procctl/systemctl.go b/edge/agent/internal/procctl/systemctl.go index 0cf3eae..7a4c71d 100644 --- a/edge/agent/internal/procctl/systemctl.go +++ b/edge/agent/internal/procctl/systemctl.go @@ -29,24 +29,24 @@ func (s *SystemCtlController) Status() (Status, error) { // 检查服务是否运行 cmd := exec.Command("systemctl", "is-active", "--quiet", s.serviceName) err := cmd.Run() - + if err != nil { - // 服务未运行 - return Status{Running: false}, nil + // 服务未运行:附带失败原因(退出码/重启次数),供 UI 展示 + return Status{Running: false, LastError: s.failureHint()}, nil } - + // 获取 PID pidCmd := exec.Command("systemctl", "show", "--property=MainPID", "--value", s.serviceName) out, err := pidCmd.Output() if err != nil { return Status{Running: true}, nil // 运行但无法获取 PID } - + pid, _ := strconv.Atoi(strings.TrimSpace(string(out))) if pid <= 0 { return Status{Running: true}, nil } - + return Status{ Running: true, Pid: pid, @@ -54,6 +54,36 @@ func (s *SystemCtlController) Status() (Status, error) { }, nil } +// failureHint 查询 systemctl 状态,给出服务未运行的可用原因(如启动失败/退出码) +func (s *SystemCtlController) failureHint() string { + out, err := exec.Command("systemctl", "show", "--property=ActiveState,SubState,Result,ExecMainStatus,NRestarts", s.serviceName).Output() + if err != nil { + return fmt.Sprintf("媒体服务未运行 (%s)", s.serviceName) + } + props := map[string]string{} + for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") { + if idx := strings.IndexByte(line, '='); idx > 0 { + props[strings.TrimSpace(line[:idx])] = strings.TrimSpace(line[idx+1:]) + } + } + switch { + case props["SubState"] == "failed" || props["Result"] == "exit-code": + code := props["ExecMainStatus"] + if code == "" { + code = "?" + } + restarts := props["NRestarts"] + if restarts == "" { + restarts = "0" + } + return fmt.Sprintf("媒体服务启动失败(退出码 %s,已重启 %s 次)", code, restarts) + case props["ActiveState"] != "" || props["SubState"] != "": + return fmt.Sprintf("媒体服务未运行(systemctl: %s/%s)", props["ActiveState"], props["SubState"]) + default: + return fmt.Sprintf("媒体服务未运行 (%s)", s.serviceName) + } +} + func (s *SystemCtlController) Version() (string, error) { // 从 systemctl 获取 ExecStart 路径,再调用 --version // Output format: { path=/path/to/binary ; argv[]=... }