OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / sys / 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         "unicode/utf16"
17         "unsafe"
18
19         "golang.org/x/sys/windows"
20 )
21
22 // Mgr is used to manage Windows service.
23 type Mgr struct {
24         Handle windows.Handle
25 }
26
27 // Connect establishes a connection to the service control manager.
28 func Connect() (*Mgr, error) {
29         return ConnectRemote("")
30 }
31
32 // ConnectRemote establishes a connection to the
33 // service control manager on computer named host.
34 func ConnectRemote(host string) (*Mgr, error) {
35         var s *uint16
36         if host != "" {
37                 s = syscall.StringToUTF16Ptr(host)
38         }
39         h, err := windows.OpenSCManager(s, nil, windows.SC_MANAGER_ALL_ACCESS)
40         if err != nil {
41                 return nil, err
42         }
43         return &Mgr{Handle: h}, nil
44 }
45
46 // Disconnect closes connection to the service control manager m.
47 func (m *Mgr) Disconnect() error {
48         return windows.CloseServiceHandle(m.Handle)
49 }
50
51 func toPtr(s string) *uint16 {
52         if len(s) == 0 {
53                 return nil
54         }
55         return syscall.StringToUTF16Ptr(s)
56 }
57
58 // toStringBlock terminates strings in ss with 0, and then
59 // concatenates them together. It also adds extra 0 at the end.
60 func toStringBlock(ss []string) *uint16 {
61         if len(ss) == 0 {
62                 return nil
63         }
64         t := ""
65         for _, s := range ss {
66                 if s != "" {
67                         t += s + "\x00"
68                 }
69         }
70         if t == "" {
71                 return nil
72         }
73         t += "\x00"
74         return &utf16.Encode([]rune(t))[0]
75 }
76
77 // CreateService installs new service name on the system.
78 // The service will be executed by running exepath binary.
79 // Use config c to specify service parameters.
80 // Any args will be passed as command-line arguments when
81 // the service is started; these arguments are distinct from
82 // the arguments passed to Service.Start or via the "Start
83 // parameters" field in the service's Properties dialog box.
84 func (m *Mgr) CreateService(name, exepath string, c Config, args ...string) (*Service, error) {
85         if c.StartType == 0 {
86                 c.StartType = StartManual
87         }
88         if c.ErrorControl == 0 {
89                 c.ErrorControl = ErrorNormal
90         }
91         if c.ServiceType == 0 {
92                 c.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS
93         }
94         s := syscall.EscapeArg(exepath)
95         for _, v := range args {
96                 s += " " + syscall.EscapeArg(v)
97         }
98         h, err := windows.CreateService(m.Handle, toPtr(name), toPtr(c.DisplayName),
99                 windows.SERVICE_ALL_ACCESS, c.ServiceType,
100                 c.StartType, c.ErrorControl, toPtr(s), toPtr(c.LoadOrderGroup),
101                 nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName), toPtr(c.Password))
102         if err != nil {
103                 return nil, err
104         }
105         if c.Description != "" {
106                 err = updateDescription(h, c.Description)
107                 if err != nil {
108                         return nil, err
109                 }
110         }
111         return &Service{Name: name, Handle: h}, nil
112 }
113
114 // OpenService retrieves access to service name, so it can
115 // be interrogated and controlled.
116 func (m *Mgr) OpenService(name string) (*Service, error) {
117         h, err := windows.OpenService(m.Handle, syscall.StringToUTF16Ptr(name), windows.SERVICE_ALL_ACCESS)
118         if err != nil {
119                 return nil, err
120         }
121         return &Service{Name: name, Handle: h}, nil
122 }
123
124 // ListServices enumerates services in the specified
125 // service control manager database m.
126 // If the caller does not have the SERVICE_QUERY_STATUS
127 // access right to a service, the service is silently
128 // omitted from the list of services returned.
129 func (m *Mgr) ListServices() ([]string, error) {
130         var err error
131         var bytesNeeded, servicesReturned uint32
132         var buf []byte
133         for {
134                 var p *byte
135                 if len(buf) > 0 {
136                         p = &buf[0]
137                 }
138                 err = windows.EnumServicesStatusEx(m.Handle, windows.SC_ENUM_PROCESS_INFO,
139                         windows.SERVICE_WIN32, windows.SERVICE_STATE_ALL,
140                         p, uint32(len(buf)), &bytesNeeded, &servicesReturned, nil, nil)
141                 if err == nil {
142                         break
143                 }
144                 if err != syscall.ERROR_MORE_DATA {
145                         return nil, err
146                 }
147                 if bytesNeeded <= uint32(len(buf)) {
148                         return nil, err
149                 }
150                 buf = make([]byte, bytesNeeded)
151         }
152         if servicesReturned == 0 {
153                 return nil, nil
154         }
155         services := (*[1 << 20]windows.ENUM_SERVICE_STATUS_PROCESS)(unsafe.Pointer(&buf[0]))[:servicesReturned]
156         var names []string
157         for _, s := range services {
158                 name := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(s.ServiceName))[:])
159                 names = append(names, name)
160         }
161         return names, nil
162 }