You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

97 lines
3.8 KiB

  1. // Copyright 2018 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build windows
  5. package mgr
  6. import (
  7. "errors"
  8. "time"
  9. "unsafe"
  10. "golang.org/x/sys/windows"
  11. )
  12. const (
  13. // Possible recovery actions that the service control manager can perform.
  14. NoAction = windows.SC_ACTION_NONE // no action
  15. ComputerReboot = windows.SC_ACTION_REBOOT // reboot the computer
  16. ServiceRestart = windows.SC_ACTION_RESTART // restart the service
  17. RunCommand = windows.SC_ACTION_RUN_COMMAND // run a command
  18. )
  19. // RecoveryAction represents an action that the service control manager can perform when service fails.
  20. // A service is considered failed when it terminates without reporting a status of SERVICE_STOPPED to the service controller.
  21. type RecoveryAction struct {
  22. Type int // one of NoAction, ComputerReboot, ServiceRestart or RunCommand
  23. Delay time.Duration // the time to wait before performing the specified action
  24. }
  25. // SetRecoveryActions sets actions that service controller performs when service fails and
  26. // the time after which to reset the service failure count to zero if there are no failures, in seconds.
  27. // Specify INFINITE to indicate that service failure count should never be reset.
  28. func (s *Service) SetRecoveryActions(recoveryActions []RecoveryAction, resetPeriod uint32) error {
  29. if recoveryActions == nil {
  30. return errors.New("recoveryActions cannot be nil")
  31. }
  32. actions := []windows.SC_ACTION{}
  33. for _, a := range recoveryActions {
  34. action := windows.SC_ACTION{
  35. Type: uint32(a.Type),
  36. Delay: uint32(a.Delay.Nanoseconds() / 1000000),
  37. }
  38. actions = append(actions, action)
  39. }
  40. rActions := windows.SERVICE_FAILURE_ACTIONS{
  41. ActionsCount: uint32(len(actions)),
  42. Actions: &actions[0],
  43. ResetPeriod: resetPeriod,
  44. }
  45. return windows.ChangeServiceConfig2(s.Handle, windows.SERVICE_CONFIG_FAILURE_ACTIONS, (*byte)(unsafe.Pointer(&rActions)))
  46. }
  47. // RecoveryActions returns actions that service controller performs when service fails.
  48. // The service control manager counts the number of times service s has failed since the system booted.
  49. // The count is reset to 0 if the service has not failed for ResetPeriod seconds.
  50. // When the service fails for the Nth time, the service controller performs the action specified in element [N-1] of returned slice.
  51. // If N is greater than slice length, the service controller repeats the last action in the slice.
  52. func (s *Service) RecoveryActions() ([]RecoveryAction, error) {
  53. b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_FAILURE_ACTIONS)
  54. if err != nil {
  55. return nil, err
  56. }
  57. p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
  58. if p.Actions == nil {
  59. return nil, err
  60. }
  61. var recoveryActions []RecoveryAction
  62. actions := (*[1024]windows.SC_ACTION)(unsafe.Pointer(p.Actions))[:p.ActionsCount]
  63. for _, action := range actions {
  64. recoveryActions = append(recoveryActions, RecoveryAction{Type: int(action.Type), Delay: time.Duration(action.Delay) * time.Millisecond})
  65. }
  66. return recoveryActions, nil
  67. }
  68. // ResetRecoveryActions deletes both reset period and array of failure actions.
  69. func (s *Service) ResetRecoveryActions() error {
  70. actions := make([]windows.SC_ACTION, 1)
  71. rActions := windows.SERVICE_FAILURE_ACTIONS{
  72. Actions: &actions[0],
  73. }
  74. return windows.ChangeServiceConfig2(s.Handle, windows.SERVICE_CONFIG_FAILURE_ACTIONS, (*byte)(unsafe.Pointer(&rActions)))
  75. }
  76. // ResetPeriod is the time after which to reset the service failure
  77. // count to zero if there are no failures, in seconds.
  78. func (s *Service) ResetPeriod() (uint32, error) {
  79. b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_FAILURE_ACTIONS)
  80. if err != nil {
  81. return 0, err
  82. }
  83. p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
  84. return p.ResetPeriod, nil
  85. }