1
2
3
4
5
6
7 package mgr
8
9 import (
10 "errors"
11 "syscall"
12 "time"
13 "unsafe"
14
15 "golang.org/x/sys/windows"
16 )
17
18 const (
19
20 NoAction = windows.SC_ACTION_NONE
21 ComputerReboot = windows.SC_ACTION_REBOOT
22 ServiceRestart = windows.SC_ACTION_RESTART
23 RunCommand = windows.SC_ACTION_RUN_COMMAND
24 )
25
26
27
28 type RecoveryAction struct {
29 Type int
30 Delay time.Duration
31 }
32
33
34
35
36 func (s *Service) SetRecoveryActions(recoveryActions []RecoveryAction, resetPeriod uint32) error {
37 if recoveryActions == nil {
38 return errors.New("recoveryActions cannot be nil")
39 }
40 actions := []windows.SC_ACTION{}
41 for _, a := range recoveryActions {
42 action := windows.SC_ACTION{
43 Type: uint32(a.Type),
44 Delay: uint32(a.Delay.Nanoseconds() / 1000000),
45 }
46 actions = append(actions, action)
47 }
48 rActions := windows.SERVICE_FAILURE_ACTIONS{
49 ActionsCount: uint32(len(actions)),
50 Actions: &actions[0],
51 ResetPeriod: resetPeriod,
52 }
53 return windows.ChangeServiceConfig2(s.Handle, windows.SERVICE_CONFIG_FAILURE_ACTIONS, (*byte)(unsafe.Pointer(&rActions)))
54 }
55
56
57
58
59
60
61 func (s *Service) RecoveryActions() ([]RecoveryAction, error) {
62 b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_FAILURE_ACTIONS)
63 if err != nil {
64 return nil, err
65 }
66 p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
67 if p.Actions == nil {
68 return nil, err
69 }
70
71 actions := unsafe.Slice(p.Actions, int(p.ActionsCount))
72 var recoveryActions []RecoveryAction
73 for _, action := range actions {
74 recoveryActions = append(recoveryActions, RecoveryAction{Type: int(action.Type), Delay: time.Duration(action.Delay) * time.Millisecond})
75 }
76 return recoveryActions, nil
77 }
78
79
80 func (s *Service) ResetRecoveryActions() error {
81 actions := make([]windows.SC_ACTION, 1)
82 rActions := windows.SERVICE_FAILURE_ACTIONS{
83 Actions: &actions[0],
84 }
85 return windows.ChangeServiceConfig2(s.Handle, windows.SERVICE_CONFIG_FAILURE_ACTIONS, (*byte)(unsafe.Pointer(&rActions)))
86 }
87
88
89
90 func (s *Service) ResetPeriod() (uint32, error) {
91 b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_FAILURE_ACTIONS)
92 if err != nil {
93 return 0, err
94 }
95 p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
96 return p.ResetPeriod, nil
97 }
98
99
100
101 func (s *Service) SetRebootMessage(msg string) error {
102 rActions := windows.SERVICE_FAILURE_ACTIONS{
103 RebootMsg: syscall.StringToUTF16Ptr(msg),
104 }
105 return windows.ChangeServiceConfig2(s.Handle, windows.SERVICE_CONFIG_FAILURE_ACTIONS, (*byte)(unsafe.Pointer(&rActions)))
106 }
107
108
109 func (s *Service) RebootMessage() (string, error) {
110 b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_FAILURE_ACTIONS)
111 if err != nil {
112 return "", err
113 }
114 p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
115 return windows.UTF16PtrToString(p.RebootMsg), nil
116 }
117
118
119
120 func (s *Service) SetRecoveryCommand(cmd string) error {
121 rActions := windows.SERVICE_FAILURE_ACTIONS{
122 Command: syscall.StringToUTF16Ptr(cmd),
123 }
124 return windows.ChangeServiceConfig2(s.Handle, windows.SERVICE_CONFIG_FAILURE_ACTIONS, (*byte)(unsafe.Pointer(&rActions)))
125 }
126
127
128 func (s *Service) RecoveryCommand() (string, error) {
129 b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_FAILURE_ACTIONS)
130 if err != nil {
131 return "", err
132 }
133 p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
134 return windows.UTF16PtrToString(p.Command), nil
135 }
136
137
138
139
140
141
142 func (s *Service) SetRecoveryActionsOnNonCrashFailures(flag bool) error {
143 var setting windows.SERVICE_FAILURE_ACTIONS_FLAG
144 if flag {
145 setting.FailureActionsOnNonCrashFailures = 1
146 }
147 return windows.ChangeServiceConfig2(s.Handle, windows.SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, (*byte)(unsafe.Pointer(&setting)))
148 }
149
150
151
152
153
154
155 func (s *Service) RecoveryActionsOnNonCrashFailures() (bool, error) {
156 b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_FAILURE_ACTIONS_FLAG)
157 if err != nil {
158 return false, err
159 }
160 p := (*windows.SERVICE_FAILURE_ACTIONS_FLAG)(unsafe.Pointer(&b[0]))
161 return p.FailureActionsOnNonCrashFailures != 0, nil
162 }
163
View as plain text