115 lines
3.0 KiB
Go
115 lines
3.0 KiB
Go
//go:build windows
|
|
// +build windows
|
|
|
|
package checks
|
|
|
|
import (
|
|
"fmt"
|
|
"syscall"
|
|
|
|
"golang.org/x/sys/windows"
|
|
"golang.org/x/sys/windows/svc"
|
|
"golang.org/x/sys/windows/svc/mgr"
|
|
)
|
|
|
|
var (
|
|
win windowsSystem = windowsOS{}
|
|
)
|
|
|
|
type OSServiceClient struct {
|
|
scHandle windows.Handle
|
|
}
|
|
|
|
func NewOSServiceClient() (*OSServiceClient, error) {
|
|
var s *uint16
|
|
scHandle, err := win.OpenSCManager(s, nil, windows.SC_MANAGER_CONNECT)
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error connecting to service manager: %w", err)
|
|
}
|
|
|
|
return &OSServiceClient{
|
|
scHandle: scHandle,
|
|
}, nil
|
|
}
|
|
|
|
func (client *OSServiceClient) Check(serviceName string) (err error) {
|
|
var isHealthy bool
|
|
|
|
m := win.getWindowsSvcMgr(client.scHandle)
|
|
defer func() {
|
|
errDisconnect := m.Disconnect()
|
|
if isHealthy || errDisconnect == nil || err != nil {
|
|
return
|
|
}
|
|
//unreachable at the moment but we might want to log this error. leaving here for code-review
|
|
err = errDisconnect
|
|
}()
|
|
|
|
svcHandle, err := win.OpenService(win.getWindowsSvcMgrHandle(m), syscall.StringToUTF16Ptr(serviceName), windows.SC_MANAGER_ENUMERATE_SERVICE)
|
|
if err != nil {
|
|
return fmt.Errorf("error accessing service: %w", err)
|
|
}
|
|
service := win.getWindowsSvc(serviceName, svcHandle)
|
|
defer func() {
|
|
errClose := service.Close()
|
|
if isHealthy || errClose == nil || err != nil {
|
|
return
|
|
}
|
|
//unreachable at the moment but we might want to log this error. leaving here for code-review
|
|
err = errClose
|
|
}()
|
|
status, err := service.Query()
|
|
if err != nil {
|
|
return fmt.Errorf("error querying service status: %w", err)
|
|
}
|
|
|
|
switch status.State {
|
|
case svc.Running:
|
|
err = nil
|
|
isHealthy = true
|
|
case svc.Paused, svc.Stopped:
|
|
err = ErrOSServiceStatusCritical
|
|
default:
|
|
err = fmt.Errorf("service status: %v", status.State)
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
type windowsOS struct{}
|
|
|
|
func (windowsOS) OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle windows.Handle, err error) {
|
|
return windows.OpenSCManager(machineName, databaseName, access)
|
|
}
|
|
func (windowsOS) OpenService(mgr windows.Handle, serviceName *uint16, access uint32) (handle windows.Handle, err error) {
|
|
return windows.OpenService(mgr, serviceName, access)
|
|
}
|
|
|
|
func (windowsOS) getWindowsSvcMgr(h windows.Handle) windowsSvcMgr { return &mgr.Mgr{Handle: h} }
|
|
func (windowsOS) getWindowsSvcMgrHandle(sm windowsSvcMgr) windows.Handle {
|
|
return sm.(*mgr.Mgr).Handle
|
|
}
|
|
|
|
func (windowsOS) getWindowsSvc(name string, h windows.Handle) windowsSvc {
|
|
return &mgr.Service{Name: name, Handle: h}
|
|
}
|
|
|
|
type windowsSystem interface {
|
|
OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle windows.Handle, err error)
|
|
OpenService(mgr windows.Handle, serviceName *uint16, access uint32) (handle windows.Handle, err error)
|
|
|
|
getWindowsSvcMgr(h windows.Handle) windowsSvcMgr
|
|
getWindowsSvcMgrHandle(sm windowsSvcMgr) windows.Handle
|
|
getWindowsSvc(name string, h windows.Handle) windowsSvc
|
|
}
|
|
|
|
type windowsSvcMgr interface {
|
|
Disconnect() error
|
|
}
|
|
|
|
type windowsSvc interface {
|
|
Close() error
|
|
Query() (svc.Status, error)
|
|
}
|