.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / sys@v0.0.0-20210124154548-22da62e12c0c / windows / svc / mgr / mgr.go
1 // Copyright 2012 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
5 // +build windows
6
7 // Package mgr can be used to manage Windows service programs.
8 // It can be used to install and remove them. It can also start,
9 // stop and pause them. The package can query / change current
10 // service state and config parameters.
11 //
12 package mgr
13
14 import (
15         "syscall"
16         "time"
17         "unicode/utf16"
18         "unsafe"
19
20         "golang.org/x/sys/internal/unsafeheader"
21         "golang.org/x/sys/windows"
22 )
23
24 // Mgr is used to manage Windows service.
25 type Mgr struct {
26         Handle windows.Handle
27 }
28
29 // Connect establishes a connection to the service control manager.
30 func Connect() (*Mgr, error) {
31         return ConnectRemote("")
32 }
33
34 // ConnectRemote establishes a connection to the
35 // service control manager on computer named host.
36 func ConnectRemote(host string) (*Mgr, error) {
37         var s *uint16
38         if host != "" {
39                 s = syscall.StringToUTF16Ptr(host)
40         }
41         h, err := windows.OpenSCManager(s, nil, windows.SC_MANAGER_ALL_ACCESS)
42         if err != nil {
43                 return nil, err
44         }
45         return &Mgr{Handle: h}, nil
46 }
47
48 // Disconnect closes connection to the service control manager m.
49 func (m *Mgr) Disconnect() error {
50         return windows.CloseServiceHandle(m.Handle)
51 }
52
53 type LockStatus struct {
54         IsLocked bool          // Whether the SCM has been locked.
55         Age      time.Duration // For how long the SCM has been locked.
56         Owner    string        // The name of the user who has locked the SCM.
57 }
58
59 // LockStatus returns whether the service control manager is locked by
60 // the system, for how long, and by whom. A locked SCM indicates that
61 // most service actions will block until the system unlocks the SCM.
62 func (m *Mgr) LockStatus() (*LockStatus, error) {
63         bytesNeeded := uint32(unsafe.Sizeof(windows.QUERY_SERVICE_LOCK_STATUS{}) + 1024)
64         for {
65                 bytes := make([]byte, bytesNeeded)
66                 lockStatus := (*windows.QUERY_SERVICE_LOCK_STATUS)(unsafe.Pointer(&bytes[0]))
67                 err := windows.QueryServiceLockStatus(m.Handle, lockStatus, uint32(len(bytes)), &bytesNeeded)
68                 if err == windows.ERROR_INSUFFICIENT_BUFFER && bytesNeeded >= uint32(unsafe.Sizeof(windows.QUERY_SERVICE_LOCK_STATUS{})) {
69                         continue
70                 }
71                 if err != nil {
72                         return nil, err
73                 }
74                 status := &LockStatus{
75                         IsLocked: lockStatus.IsLocked != 0,
76                         Age:      time.Duration(lockStatus.LockDuration) * time.Second,
77                         Owner:    windows.UTF16PtrToString(lockStatus.LockOwner),
78                 }
79                 return status, nil
80         }
81 }
82
83 func toPtr(s string) *uint16 {
84         if len(s) == 0 {
85                 return nil
86         }
87         return syscall.StringToUTF16Ptr(s)
88 }
89
90 // toStringBlock terminates strings in ss with 0, and then
91 // concatenates them together. It also adds extra 0 at the end.
92 func toStringBlock(ss []string) *uint16 {
93         if len(ss) == 0 {
94                 return nil
95         }
96         t := ""
97         for _, s := range ss {
98                 if s != "" {
99                         t += s + "\x00"
100                 }
101         }
102         if t == "" {
103                 return nil
104         }
105         t += "\x00"
106         return &utf16.Encode([]rune(t))[0]
107 }
108
109 // CreateService installs new service name on the system.
110 // The service will be executed by running exepath binary.
111 // Use config c to specify service parameters.
112 // Any args will be passed as command-line arguments when
113 // the service is started; these arguments are distinct from
114 // the arguments passed to Service.Start or via the "Start
115 // parameters" field in the service's Properties dialog box.
116 func (m *Mgr) CreateService(name, exepath string, c Config, args ...string) (*Service, error) {
117         if c.StartType == 0 {
118                 c.StartType = StartManual
119         }
120         if c.ServiceType == 0 {
121                 c.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS
122         }
123         s := syscall.EscapeArg(exepath)
124         for _, v := range args {
125                 s += " " + syscall.EscapeArg(v)
126         }
127         h, err := windows.CreateService(m.Handle, toPtr(name), toPtr(c.DisplayName),
128                 windows.SERVICE_ALL_ACCESS, c.ServiceType,
129                 c.StartType, c.ErrorControl, toPtr(s), toPtr(c.LoadOrderGroup),
130                 nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName), toPtr(c.Password))
131         if err != nil {
132                 return nil, err
133         }
134         if c.SidType != windows.SERVICE_SID_TYPE_NONE {
135                 err = updateSidType(h, c.SidType)
136                 if err != nil {
137                         windows.DeleteService(h)
138                         windows.CloseServiceHandle(h)
139                         return nil, err
140                 }
141         }
142         if c.Description != "" {
143                 err = updateDescription(h, c.Description)
144                 if err != nil {
145                         windows.DeleteService(h)
146                         windows.CloseServiceHandle(h)
147                         return nil, err
148                 }
149         }
150         if c.DelayedAutoStart {
151                 err = updateStartUp(h, c.DelayedAutoStart)
152                 if err != nil {
153                         windows.DeleteService(h)
154                         windows.CloseServiceHandle(h)
155                         return nil, err
156                 }
157         }
158         return &Service{Name: name, Handle: h}, nil
159 }
160
161 // OpenService retrieves access to service name, so it can
162 // be interrogated and controlled.
163 func (m *Mgr) OpenService(name string) (*Service, error) {
164         h, err := windows.OpenService(m.Handle, syscall.StringToUTF16Ptr(name), windows.SERVICE_ALL_ACCESS)
165         if err != nil {
166                 return nil, err
167         }
168         return &Service{Name: name, Handle: h}, nil
169 }
170
171 // ListServices enumerates services in the specified
172 // service control manager database m.
173 // If the caller does not have the SERVICE_QUERY_STATUS
174 // access right to a service, the service is silently
175 // omitted from the list of services returned.
176 func (m *Mgr) ListServices() ([]string, error) {
177         var err error
178         var bytesNeeded, servicesReturned uint32
179         var buf []byte
180         for {
181                 var p *byte
182                 if len(buf) > 0 {
183                         p = &buf[0]
184                 }
185                 err = windows.EnumServicesStatusEx(m.Handle, windows.SC_ENUM_PROCESS_INFO,
186                         windows.SERVICE_WIN32, windows.SERVICE_STATE_ALL,
187                         p, uint32(len(buf)), &bytesNeeded, &servicesReturned, nil, nil)
188                 if err == nil {
189                         break
190                 }
191                 if err != syscall.ERROR_MORE_DATA {
192                         return nil, err
193                 }
194                 if bytesNeeded <= uint32(len(buf)) {
195                         return nil, err
196                 }
197                 buf = make([]byte, bytesNeeded)
198         }
199         if servicesReturned == 0 {
200                 return nil, nil
201         }
202
203         var services []windows.ENUM_SERVICE_STATUS_PROCESS
204         hdr := (*unsafeheader.Slice)(unsafe.Pointer(&services))
205         hdr.Data = unsafe.Pointer(&buf[0])
206         hdr.Len = int(servicesReturned)
207         hdr.Cap = int(servicesReturned)
208
209         var names []string
210         for _, s := range services {
211                 name := windows.UTF16PtrToString(s.ServiceName)
212                 names = append(names, name)
213         }
214         return names, nil
215 }