1
2
3
4
5
6
7 package mgr
8
9 import (
10 "syscall"
11 "unsafe"
12
13 "golang.org/x/sys/windows"
14 )
15
16 const (
17
18 StartManual = windows.SERVICE_DEMAND_START
19 StartAutomatic = windows.SERVICE_AUTO_START
20 StartDisabled = windows.SERVICE_DISABLED
21
22
23
24 ErrorCritical = windows.SERVICE_ERROR_CRITICAL
25 ErrorIgnore = windows.SERVICE_ERROR_IGNORE
26 ErrorNormal = windows.SERVICE_ERROR_NORMAL
27 ErrorSevere = windows.SERVICE_ERROR_SEVERE
28 )
29
30
31
32 type Config struct {
33 ServiceType uint32
34 StartType uint32
35 ErrorControl uint32
36 BinaryPathName string
37 LoadOrderGroup string
38 TagId uint32
39 Dependencies []string
40 ServiceStartName string
41 DisplayName string
42 Password string
43 Description string
44 SidType uint32
45 DelayedAutoStart bool
46 }
47
48 func toStringSlice(ps *uint16) []string {
49 r := make([]string, 0)
50 p := unsafe.Pointer(ps)
51
52 for {
53 s := windows.UTF16PtrToString((*uint16)(p))
54 if len(s) == 0 {
55 break
56 }
57
58 r = append(r, s)
59 offset := unsafe.Sizeof(uint16(0)) * (uintptr)(len(s)+1)
60 p = unsafe.Pointer(uintptr(p) + offset)
61 }
62
63 return r
64 }
65
66
67 func (s *Service) Config() (Config, error) {
68 var p *windows.QUERY_SERVICE_CONFIG
69 n := uint32(1024)
70 for {
71 b := make([]byte, n)
72 p = (*windows.QUERY_SERVICE_CONFIG)(unsafe.Pointer(&b[0]))
73 err := windows.QueryServiceConfig(s.Handle, p, n, &n)
74 if err == nil {
75 break
76 }
77 if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER {
78 return Config{}, err
79 }
80 if n <= uint32(len(b)) {
81 return Config{}, err
82 }
83 }
84
85 b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_DESCRIPTION)
86 if err != nil {
87 return Config{}, err
88 }
89 p2 := (*windows.SERVICE_DESCRIPTION)(unsafe.Pointer(&b[0]))
90
91 b, err = s.queryServiceConfig2(windows.SERVICE_CONFIG_DELAYED_AUTO_START_INFO)
92 if err != nil {
93 return Config{}, err
94 }
95 p3 := (*windows.SERVICE_DELAYED_AUTO_START_INFO)(unsafe.Pointer(&b[0]))
96 delayedStart := false
97 if p3.IsDelayedAutoStartUp != 0 {
98 delayedStart = true
99 }
100
101 b, err = s.queryServiceConfig2(windows.SERVICE_CONFIG_SERVICE_SID_INFO)
102 if err != nil {
103 return Config{}, err
104 }
105 sidType := *(*uint32)(unsafe.Pointer(&b[0]))
106
107 return Config{
108 ServiceType: p.ServiceType,
109 StartType: p.StartType,
110 ErrorControl: p.ErrorControl,
111 BinaryPathName: windows.UTF16PtrToString(p.BinaryPathName),
112 LoadOrderGroup: windows.UTF16PtrToString(p.LoadOrderGroup),
113 TagId: p.TagId,
114 Dependencies: toStringSlice(p.Dependencies),
115 ServiceStartName: windows.UTF16PtrToString(p.ServiceStartName),
116 DisplayName: windows.UTF16PtrToString(p.DisplayName),
117 Description: windows.UTF16PtrToString(p2.Description),
118 DelayedAutoStart: delayedStart,
119 SidType: sidType,
120 }, nil
121 }
122
123 func updateDescription(handle windows.Handle, desc string) error {
124 d := windows.SERVICE_DESCRIPTION{Description: toPtr(desc)}
125 return windows.ChangeServiceConfig2(handle,
126 windows.SERVICE_CONFIG_DESCRIPTION, (*byte)(unsafe.Pointer(&d)))
127 }
128
129 func updateSidType(handle windows.Handle, sidType uint32) error {
130 return windows.ChangeServiceConfig2(handle, windows.SERVICE_CONFIG_SERVICE_SID_INFO, (*byte)(unsafe.Pointer(&sidType)))
131 }
132
133 func updateStartUp(handle windows.Handle, isDelayed bool) error {
134 var d windows.SERVICE_DELAYED_AUTO_START_INFO
135 if isDelayed {
136 d.IsDelayedAutoStartUp = 1
137 }
138 return windows.ChangeServiceConfig2(handle,
139 windows.SERVICE_CONFIG_DELAYED_AUTO_START_INFO, (*byte)(unsafe.Pointer(&d)))
140 }
141
142
143 func (s *Service) UpdateConfig(c Config) error {
144 err := windows.ChangeServiceConfig(s.Handle, c.ServiceType, c.StartType,
145 c.ErrorControl, toPtr(c.BinaryPathName), toPtr(c.LoadOrderGroup),
146 nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName),
147 toPtr(c.Password), toPtr(c.DisplayName))
148 if err != nil {
149 return err
150 }
151 err = updateSidType(s.Handle, c.SidType)
152 if err != nil {
153 return err
154 }
155
156 err = updateStartUp(s.Handle, c.DelayedAutoStart)
157 if err != nil {
158 return err
159 }
160
161 return updateDescription(s.Handle, c.Description)
162 }
163
164
165 func (s *Service) queryServiceConfig2(infoLevel uint32) ([]byte, error) {
166 n := uint32(1024)
167 for {
168 b := make([]byte, n)
169 err := windows.QueryServiceConfig2(s.Handle, infoLevel, &b[0], n, &n)
170 if err == nil {
171 return b, nil
172 }
173 if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER {
174 return nil, err
175 }
176 if n <= uint32(len(b)) {
177 return nil, err
178 }
179 }
180 }
181
View as plain text