Skip to content

Commit 9524d49

Browse files
craig65535alexbrainman
authored andcommitted
windows/svc/mgr: Service.Control: populate Status when returning certain errors
Fixes golang/go#59015 Change-Id: I45f22049f3a05f807f78d20c9ed67c6c79e3d3c1 GitHub-Last-Rev: 929aeb4 GitHub-Pull-Request: #156 Reviewed-on: https://go-review.googlesource.com/c/sys/+/484895 Reviewed-by: Alex Brainman <alex.brainman@gmail.com> Run-TryBot: Alex Brainman <alex.brainman@gmail.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Bryan Mills <bcmills@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
1 parent 2a33a30 commit 9524d49

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

windows/svc/mgr/mgr_test.go

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"testing"
1818
"time"
1919

20+
"golang.org/x/sys/windows"
2021
"golang.org/x/sys/windows/svc"
2122
"golang.org/x/sys/windows/svc/mgr"
2223
)
@@ -109,7 +110,7 @@ func testRecoveryActions(t *testing.T, s *mgr.Service, should []mgr.RecoveryActi
109110
if len(should) != len(is) {
110111
t.Errorf("recovery action mismatch: contains %v actions, but should have %v", len(is), len(should))
111112
}
112-
for i, _ := range is {
113+
for i := range is {
113114
if should[i].Type != is[i].Type {
114115
t.Errorf("recovery action mismatch: Type is %v, but should have %v", is[i].Type, should[i].Type)
115116
}
@@ -131,19 +132,19 @@ func testResetPeriod(t *testing.T, s *mgr.Service, should uint32) {
131132

132133
func testSetRecoveryActions(t *testing.T, s *mgr.Service) {
133134
r := []mgr.RecoveryAction{
134-
mgr.RecoveryAction{
135+
{
135136
Type: mgr.NoAction,
136137
Delay: 60000 * time.Millisecond,
137138
},
138-
mgr.RecoveryAction{
139+
{
139140
Type: mgr.ServiceRestart,
140141
Delay: 4 * time.Minute,
141142
},
142-
mgr.RecoveryAction{
143+
{
143144
Type: mgr.ServiceRestart,
144145
Delay: time.Minute,
145146
},
146-
mgr.RecoveryAction{
147+
{
147148
Type: mgr.RunCommand,
148149
Delay: 4000 * time.Millisecond,
149150
},
@@ -208,6 +209,16 @@ func testRecoveryCommand(t *testing.T, s *mgr.Service, should string) {
208209
}
209210
}
210211

212+
func testControl(t *testing.T, s *mgr.Service, c svc.Cmd, expectedErr error, expectedStatus svc.Status) {
213+
status, err := s.Control(c)
214+
if err != expectedErr {
215+
t.Fatalf("Unexpected return from s.Control: %v (expected %v)", err, expectedErr)
216+
}
217+
if expectedStatus != status {
218+
t.Fatalf("Unexpected status from s.Control: %+v (expected %+v)", status, expectedStatus)
219+
}
220+
}
221+
211222
func remove(t *testing.T, s *mgr.Service) {
212223
err := s.Delete()
213224
if err != nil {
@@ -251,6 +262,7 @@ func TestMyService(t *testing.T) {
251262
t.Fatalf("service %s is not installed", name)
252263
}
253264
defer s.Close()
265+
defer s.Delete()
254266

255267
c.BinaryPathName = exepath
256268
c = testConfig(t, s, c)
@@ -293,6 +305,11 @@ func TestMyService(t *testing.T) {
293305
testRecoveryCommand(t, s, fmt.Sprintf("sc query %s", name))
294306
testRecoveryCommand(t, s, "") // delete recovery command
295307

308+
expectedStatus := svc.Status{
309+
State: svc.Stopped,
310+
}
311+
testControl(t, s, svc.Stop, windows.ERROR_SERVICE_NOT_ACTIVE, expectedStatus)
312+
296313
remove(t, s)
297314
}
298315

windows/svc/mgr/service.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,25 @@ func (s *Service) Start(args ...string) error {
4545
return windows.StartService(s.Handle, uint32(len(args)), p)
4646
}
4747

48-
// Control sends state change request c to the service s.
48+
// Control sends state change request c to the service s. It returns the most
49+
// recent status the service reported to the service control manager, and an
50+
// error if the state change request was not accepted.
51+
// Note that the returned service status is only set if the status change
52+
// request succeeded, or if it failed with error ERROR_INVALID_SERVICE_CONTROL,
53+
// ERROR_SERVICE_CANNOT_ACCEPT_CTRL, or ERROR_SERVICE_NOT_ACTIVE.
4954
func (s *Service) Control(c svc.Cmd) (svc.Status, error) {
5055
var t windows.SERVICE_STATUS
5156
err := windows.ControlService(s.Handle, uint32(c), &t)
52-
if err != nil {
57+
if err != nil &&
58+
err != windows.ERROR_INVALID_SERVICE_CONTROL &&
59+
err != windows.ERROR_SERVICE_CANNOT_ACCEPT_CTRL &&
60+
err != windows.ERROR_SERVICE_NOT_ACTIVE {
5361
return svc.Status{}, err
5462
}
5563
return svc.Status{
5664
State: svc.State(t.CurrentState),
5765
Accepts: svc.Accepted(t.ControlsAccepted),
58-
}, nil
66+
}, err
5967
}
6068

6169
// Query returns current status of service s.

0 commit comments

Comments
 (0)