package svcmgr import ( "fmt" "os/exec" "runtime" "strings" ) type ServiceInfo struct { Name string `json:"name"` Status string `json:"status"` Enabled bool `json:"enabled"` } func ListServices() ([]ServiceInfo, error) { switch runtime.GOOS { case "windows": return listWindowsServices() case "darwin": return listDarwinServices() default: return listLinuxServices() } } func GetServiceStatus(name string) (string, bool, error) { switch runtime.GOOS { case "windows": return getWindowsServiceStatus(name) case "darwin": return getDarwinServiceStatus(name) default: return getLinuxServiceStatus(name) } } func StartService(name string) (string, error) { switch runtime.GOOS { case "windows": return startWindowsService(name) case "darwin": return startDarwinService(name) default: return startLinuxService(name) } } func StopService(name string) (string, error) { switch runtime.GOOS { case "windows": return stopWindowsService(name) case "darwin": return stopDarwinService(name) default: return stopLinuxService(name) } } func RestartService(name string) (string, error) { switch runtime.GOOS { case "windows": return restartWindowsService(name) case "darwin": return restartDarwinService(name) default: return restartLinuxService(name) } } func Reboot() error { switch runtime.GOOS { case "windows": return exec.Command("shutdown", "/r", "/t", "0").Run() case "darwin": return exec.Command("sudo", "shutdown", "-r", "now").Run() default: return exec.Command("sudo", "reboot").Run() } } func Shutdown() error { switch runtime.GOOS { case "windows": return exec.Command("shutdown", "/s", "/t", "0").Run() case "darwin": return exec.Command("sudo", "shutdown", "-h", "now").Run() default: return exec.Command("sudo", "poweroff").Run() } } func listWindowsServices() ([]ServiceInfo, error) { out, err := exec.Command("powershell", "-NoProfile", "-NonInteractive", "-Command", "Get-Service -ErrorAction SilentlyContinue | ForEach-Object { '{0}`t{1}`t{2}' -f $_.Name, $_.Status, $_.StartType }").Output() if err != nil { return nil, fmt.Errorf("Get-Service failed: %w", err) } var services []ServiceInfo for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") { fields := strings.Split(strings.TrimSpace(line), "\t") if len(fields) < 3 { continue } services = append(services, ServiceInfo{ Name: fields[0], Status: strings.ToLower(fields[1]), Enabled: strings.EqualFold(fields[2], "Automatic"), }) } return services, nil } func getWindowsServiceStatus(name string) (string, bool, error) { out, err := exec.Command("powershell", "-NoProfile", "-NonInteractive", "-Command", fmt.Sprintf("$s = Get-Service -Name '%s' -ErrorAction Stop; '{0}`t{1}' -f $s.Status, $s.StartType", name)).Output() if err != nil { return "", false, fmt.Errorf("Get-Service failed: %w", err) } fields := strings.Split(strings.TrimSpace(string(out)), "\t") if len(fields) < 2 { return "", false, fmt.Errorf("unexpected Get-Service output: %s", strings.TrimSpace(string(out))) } return strings.ToLower(fields[0]), strings.EqualFold(fields[1], "Automatic"), nil } func startWindowsService(name string) (string, error) { cmd := exec.Command("powershell", "-NoProfile", "-NonInteractive", "-Command", fmt.Sprintf("Start-Service -Name '%s' -ErrorAction Stop", name)) if out, err := cmd.CombinedOutput(); err != nil { return string(out), fmt.Errorf("start failed: %w\nOutput: %s", err, string(out)) } return "started", nil } func stopWindowsService(name string) (string, error) { cmd := exec.Command("powershell", "-NoProfile", "-NonInteractive", "-Command", fmt.Sprintf("Stop-Service -Name '%s' -ErrorAction Stop", name)) if out, err := cmd.CombinedOutput(); err != nil { return string(out), fmt.Errorf("stop failed: %w\nOutput: %s", err, string(out)) } return "stopped", nil } func restartWindowsService(name string) (string, error) { cmd := exec.Command("powershell", "-NoProfile", "-NonInteractive", "-Command", fmt.Sprintf("Restart-Service -Name '%s' -ErrorAction Stop", name)) if out, err := cmd.CombinedOutput(); err != nil { return string(out), fmt.Errorf("restart failed: %w\nOutput: %s", err, string(out)) } return "restarted", nil } func listDarwinServices() ([]ServiceInfo, error) { out, err := exec.Command("launchctl", "list").Output() if err != nil { return nil, fmt.Errorf("launchctl list failed: %w", err) } var services []ServiceInfo for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n")[1:] { fields := strings.Fields(line) if len(fields) < 3 { continue } status := "unknown" if fields[0] != "-" { status = "running" } services = append(services, ServiceInfo{ Name: fields[2], Status: status, }) } return services, nil } func getDarwinServiceStatus(name string) (string, bool, error) { out, err := exec.Command("launchctl", "list").Output() if err != nil { return "", false, fmt.Errorf("launchctl list failed: %w", err) } for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n")[1:] { fields := strings.Fields(line) if len(fields) >= 3 && fields[2] == name { if fields[0] != "-" { return "running", true, nil } return "inactive", false, nil } } return "not_found", false, nil } func startDarwinService(name string) (string, error) { cmd := exec.Command("launchctl", "load", fmt.Sprintf("/Library/LaunchDaemons/%s.plist", name)) if out, err := cmd.CombinedOutput(); err != nil { return string(out), fmt.Errorf("start failed: %w\nOutput: %s", err, string(out)) } return "started", nil } func stopDarwinService(name string) (string, error) { cmd := exec.Command("launchctl", "unload", fmt.Sprintf("/Library/LaunchDaemons/%s.plist", name)) if out, err := cmd.CombinedOutput(); err != nil { return string(out), fmt.Errorf("stop failed: %w\nOutput: %s", err, string(out)) } return "stopped", nil } func restartDarwinService(name string) (string, error) { stopDarwinService(name) return startDarwinService(name) } func listLinuxServices() ([]ServiceInfo, error) { cmd := exec.Command("systemctl", "list-units", "--type=service", "--all", "--no-pager", "--no-legend", "--plain", "--no-accept-unknown") out, err := cmd.Output() if err != nil { return nil, fmt.Errorf("systemctl list-units failed: %w", err) } var services []ServiceInfo for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") { line = strings.TrimSpace(line) if line == "" { continue } fields := strings.Fields(line) if len(fields) < 4 { continue } svcName := strings.TrimSuffix(fields[0], ".service") status := fields[2] enabled := fields[3] == "loaded" services = append(services, ServiceInfo{ Name: svcName, Status: status, Enabled: enabled, }) } return services, nil } func getLinuxServiceStatus(name string) (string, bool, error) { cmd := exec.Command("systemctl", "is-active", name) out, err := cmd.Output() status := strings.TrimSpace(string(out)) enabledCmd := exec.Command("systemctl", "is-enabled", name) enabledOut, _ := enabledCmd.Output() enabled := strings.TrimSpace(string(enabledOut)) == "enabled" if err != nil && status != "inactive" { return status, enabled, fmt.Errorf("systemctl status failed: %w", err) } return status, enabled, nil } func startLinuxService(name string) (string, error) { cmd := exec.Command("sudo", "systemctl", "start", name) out, err := cmd.CombinedOutput() if err != nil { return string(out), fmt.Errorf("start failed: %w\nOutput: %s", err, string(out)) } return "started", nil } func stopLinuxService(name string) (string, error) { cmd := exec.Command("sudo", "systemctl", "stop", name) out, err := cmd.CombinedOutput() if err != nil { return string(out), fmt.Errorf("stop failed: %w\nOutput: %s", err, string(out)) } return "stopped", nil } func restartLinuxService(name string) (string, error) { cmd := exec.Command("sudo", "systemctl", "restart", name) out, err := cmd.CombinedOutput() if err != nil { return string(out), fmt.Errorf("restart failed: %w\nOutput: %s", err, string(out)) } return "restarted", nil }