github.com/safing/portbase@v0.19.5/utils/osdetail/service_windows.go (about) 1 package osdetail 2 3 import ( 4 "errors" 5 "fmt" 6 "os/exec" 7 "strings" 8 "time" 9 ) 10 11 // Service Status 12 const ( 13 StatusUnknown uint8 = iota 14 StatusRunningStoppable 15 StatusRunningNotStoppable 16 StatusStartPending 17 StatusStopPending 18 StatusStopped 19 ) 20 21 // Exported errors 22 var ( 23 ErrServiceNotStoppable = errors.New("the service is not stoppable") 24 ) 25 26 // GetServiceStatus returns the current status of a Windows Service (limited implementation). 27 func GetServiceStatus(name string) (status uint8, err error) { 28 29 output, err := exec.Command("sc", "query", name).Output() 30 if err != nil { 31 return StatusUnknown, fmt.Errorf("failed to query service: %s", err) 32 } 33 outputString := string(output) 34 35 switch { 36 case strings.Contains(outputString, "RUNNING"): 37 if strings.Contains(outputString, "NOT_STOPPABLE") { 38 return StatusRunningNotStoppable, nil 39 } 40 return StatusRunningStoppable, nil 41 case strings.Contains(outputString, "STOP_PENDING"): 42 return StatusStopPending, nil 43 case strings.Contains(outputString, "STOPPED"): 44 return StatusStopped, nil 45 case strings.Contains(outputString, "START_PENDING"): 46 return StatusStopPending, nil 47 } 48 49 return StatusUnknown, errors.New("unknown service status") 50 } 51 52 // StopService stops a Windows Service. 53 func StopService(name string) (err error) { 54 pendingCnt := 0 55 for { 56 57 // get status 58 status, err := GetServiceStatus(name) 59 if err != nil { 60 return err 61 } 62 63 switch status { 64 case StatusRunningStoppable: 65 err := exec.Command("sc", "stop", name).Run() 66 if err != nil { 67 return fmt.Errorf("failed to stop service: %s", err) 68 } 69 case StatusRunningNotStoppable: 70 return ErrServiceNotStoppable 71 case StatusStartPending, StatusStopPending: 72 pendingCnt++ 73 if pendingCnt > 50 { 74 return errors.New("service stuck in pending status (5s)") 75 } 76 case StatusStopped: 77 return nil 78 } 79 80 time.Sleep(100 * time.Millisecond) 81 } 82 } 83 84 // SartService starts a Windows Service. 85 func SartService(name string) (err error) { 86 pendingCnt := 0 87 for { 88 89 // get status 90 status, err := GetServiceStatus(name) 91 if err != nil { 92 return err 93 } 94 95 switch status { 96 case StatusRunningStoppable, StatusRunningNotStoppable: 97 return nil 98 case StatusStartPending, StatusStopPending: 99 pendingCnt++ 100 if pendingCnt > 50 { 101 return errors.New("service stuck in pending status (5s)") 102 } 103 case StatusStopped: 104 err := exec.Command("sc", "start", name).Run() 105 if err != nil { 106 return fmt.Errorf("failed to stop service: %s", err) 107 } 108 } 109 110 time.Sleep(100 * time.Millisecond) 111 } 112 }