package collector import ( "os/exec" "path/filepath" "strings" ) type ServiceInfo struct { Name string `json:"name"` Description string `json:"description"` Status string `json:"status"` } func CollectServices() []ServiceInfo { // Versuche zuerst pluginctl -s (OPNsense-spezifisch) services := tryPluginctl() if len(services) > 0 { return services } // Fallback: service -e listet aktivierte Services return tryServiceList() } func tryPluginctl() []ServiceInfo { out, err := exec.Command("pluginctl", "-s").Output() if err != nil { return nil } var services []ServiceInfo for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") { name := strings.TrimSpace(line) if name == "" { continue } // pluginctl -s gibt nur Service-Namen, Status einzeln pruefen status := "stopped" statusOut, err := exec.Command("service", name, "status").CombinedOutput() if err == nil && strings.Contains(string(statusOut), "is running") { status = "running" } // Beschreibung aus rc.d Script extrahieren (# PROVIDE: name) desc := "" descOut, _ := exec.Command("grep", "-h", "PROVIDE:", "/etc/rc.d/"+name, "/usr/local/etc/rc.d/"+name).Output() if len(descOut) > 0 { parts := strings.SplitN(string(descOut), "PROVIDE:", 2) if len(parts) == 2 { desc = strings.TrimSpace(parts[1]) } } services = append(services, ServiceInfo{ Name: name, Description: desc, Status: status, }) } return services } func tryServiceList() []ServiceInfo { out, err := exec.Command("service", "-e").Output() if err != nil { return nil } var services []ServiceInfo for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") { if line == "" { continue } // service -e gibt volle Pfade: /etc/rc.d/sshd, /usr/local/etc/rc.d/openvpn name := filepath.Base(strings.TrimSpace(line)) // Status pruefen status := "running" // service -e listet nur laufende Services statusOut, err := exec.Command("service", name, "status").Output() if err != nil { status = "stopped" } else if strings.Contains(string(statusOut), "not running") { status = "stopped" } services = append(services, ServiceInfo{ Name: name, Status: status, }) } return services }