Windows: Allow running as a service

Signed-off-by: John Howard <jhoward@microsoft.com>

Allows containerd.exe to run as a Windows service. eg

Register: `.\containerd.exe --register-service`

Start: `net start containerd`
...
Stop: `net stop containerd`

Unregister: `.\containerd.exe --unregister-service`

When running as a service, logs will go to the Windows application
event log.
This commit is contained in:
John Howard
2018-10-12 15:38:04 -07:00
parent dcb82064d3
commit 40d898a820
18 changed files with 2026 additions and 17 deletions

198
vendor/golang.org/x/sys/windows/registry/key.go generated vendored Normal file
View File

@@ -0,0 +1,198 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// Package registry provides access to the Windows registry.
//
// Here is a simple example, opening a registry key and reading a string value from it.
//
// k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
// if err != nil {
// log.Fatal(err)
// }
// defer k.Close()
//
// s, _, err := k.GetStringValue("SystemRoot")
// if err != nil {
// log.Fatal(err)
// }
// fmt.Printf("Windows system root is %q\n", s)
//
package registry
import (
"io"
"syscall"
"time"
)
const (
// Registry key security and access rights.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724878.aspx
// for details.
ALL_ACCESS = 0xf003f
CREATE_LINK = 0x00020
CREATE_SUB_KEY = 0x00004
ENUMERATE_SUB_KEYS = 0x00008
EXECUTE = 0x20019
NOTIFY = 0x00010
QUERY_VALUE = 0x00001
READ = 0x20019
SET_VALUE = 0x00002
WOW64_32KEY = 0x00200
WOW64_64KEY = 0x00100
WRITE = 0x20006
)
// Key is a handle to an open Windows registry key.
// Keys can be obtained by calling OpenKey; there are
// also some predefined root keys such as CURRENT_USER.
// Keys can be used directly in the Windows API.
type Key syscall.Handle
const (
// Windows defines some predefined root keys that are always open.
// An application can use these keys as entry points to the registry.
// Normally these keys are used in OpenKey to open new keys,
// but they can also be used anywhere a Key is required.
CLASSES_ROOT = Key(syscall.HKEY_CLASSES_ROOT)
CURRENT_USER = Key(syscall.HKEY_CURRENT_USER)
LOCAL_MACHINE = Key(syscall.HKEY_LOCAL_MACHINE)
USERS = Key(syscall.HKEY_USERS)
CURRENT_CONFIG = Key(syscall.HKEY_CURRENT_CONFIG)
PERFORMANCE_DATA = Key(syscall.HKEY_PERFORMANCE_DATA)
)
// Close closes open key k.
func (k Key) Close() error {
return syscall.RegCloseKey(syscall.Handle(k))
}
// OpenKey opens a new key with path name relative to key k.
// It accepts any open key, including CURRENT_USER and others,
// and returns the new key and an error.
// The access parameter specifies desired access rights to the
// key to be opened.
func OpenKey(k Key, path string, access uint32) (Key, error) {
p, err := syscall.UTF16PtrFromString(path)
if err != nil {
return 0, err
}
var subkey syscall.Handle
err = syscall.RegOpenKeyEx(syscall.Handle(k), p, 0, access, &subkey)
if err != nil {
return 0, err
}
return Key(subkey), nil
}
// OpenRemoteKey opens a predefined registry key on another
// computer pcname. The key to be opened is specified by k, but
// can only be one of LOCAL_MACHINE, PERFORMANCE_DATA or USERS.
// If pcname is "", OpenRemoteKey returns local computer key.
func OpenRemoteKey(pcname string, k Key) (Key, error) {
var err error
var p *uint16
if pcname != "" {
p, err = syscall.UTF16PtrFromString(`\\` + pcname)
if err != nil {
return 0, err
}
}
var remoteKey syscall.Handle
err = regConnectRegistry(p, syscall.Handle(k), &remoteKey)
if err != nil {
return 0, err
}
return Key(remoteKey), nil
}
// ReadSubKeyNames returns the names of subkeys of key k.
// The parameter n controls the number of returned names,
// analogous to the way os.File.Readdirnames works.
func (k Key) ReadSubKeyNames(n int) ([]string, error) {
names := make([]string, 0)
// Registry key size limit is 255 bytes and described there:
// https://msdn.microsoft.com/library/windows/desktop/ms724872.aspx
buf := make([]uint16, 256) //plus extra room for terminating zero byte
loopItems:
for i := uint32(0); ; i++ {
if n > 0 {
if len(names) == n {
return names, nil
}
}
l := uint32(len(buf))
for {
err := syscall.RegEnumKeyEx(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil)
if err == nil {
break
}
if err == syscall.ERROR_MORE_DATA {
// Double buffer size and try again.
l = uint32(2 * len(buf))
buf = make([]uint16, l)
continue
}
if err == _ERROR_NO_MORE_ITEMS {
break loopItems
}
return names, err
}
names = append(names, syscall.UTF16ToString(buf[:l]))
}
if n > len(names) {
return names, io.EOF
}
return names, nil
}
// CreateKey creates a key named path under open key k.
// CreateKey returns the new key and a boolean flag that reports
// whether the key already existed.
// The access parameter specifies the access rights for the key
// to be created.
func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool, err error) {
var h syscall.Handle
var d uint32
err = regCreateKeyEx(syscall.Handle(k), syscall.StringToUTF16Ptr(path),
0, nil, _REG_OPTION_NON_VOLATILE, access, nil, &h, &d)
if err != nil {
return 0, false, err
}
return Key(h), d == _REG_OPENED_EXISTING_KEY, nil
}
// DeleteKey deletes the subkey path of key k and its values.
func DeleteKey(k Key, path string) error {
return regDeleteKey(syscall.Handle(k), syscall.StringToUTF16Ptr(path))
}
// A KeyInfo describes the statistics of a key. It is returned by Stat.
type KeyInfo struct {
SubKeyCount uint32
MaxSubKeyLen uint32 // size of the key's subkey with the longest name, in Unicode characters, not including the terminating zero byte
ValueCount uint32
MaxValueNameLen uint32 // size of the key's longest value name, in Unicode characters, not including the terminating zero byte
MaxValueLen uint32 // longest data component among the key's values, in bytes
lastWriteTime syscall.Filetime
}
// ModTime returns the key's last write time.
func (ki *KeyInfo) ModTime() time.Time {
return time.Unix(0, ki.lastWriteTime.Nanoseconds())
}
// Stat retrieves information about the open key k.
func (k Key) Stat() (*KeyInfo, error) {
var ki KeyInfo
err := syscall.RegQueryInfoKey(syscall.Handle(k), nil, nil, nil,
&ki.SubKeyCount, &ki.MaxSubKeyLen, nil, &ki.ValueCount,
&ki.MaxValueNameLen, &ki.MaxValueLen, nil, &ki.lastWriteTime)
if err != nil {
return nil, err
}
return &ki, nil
}

View File

@@ -0,0 +1,7 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package registry
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go

32
vendor/golang.org/x/sys/windows/registry/syscall.go generated vendored Normal file
View File

@@ -0,0 +1,32 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package registry
import "syscall"
const (
_REG_OPTION_NON_VOLATILE = 0
_REG_CREATED_NEW_KEY = 1
_REG_OPENED_EXISTING_KEY = 2
_ERROR_NO_MORE_ITEMS syscall.Errno = 259
)
func LoadRegLoadMUIString() error {
return procRegLoadMUIStringW.Find()
}
//sys regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) = advapi32.RegCreateKeyExW
//sys regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) = advapi32.RegDeleteKeyW
//sys regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) = advapi32.RegSetValueExW
//sys regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegEnumValueW
//sys regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) = advapi32.RegDeleteValueW
//sys regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) = advapi32.RegLoadMUIStringW
//sys regConnectRegistry(machinename *uint16, key syscall.Handle, result *syscall.Handle) (regerrno error) = advapi32.RegConnectRegistryW
//sys expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) = kernel32.ExpandEnvironmentStringsW

384
vendor/golang.org/x/sys/windows/registry/value.go generated vendored Normal file
View File

@@ -0,0 +1,384 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package registry
import (
"errors"
"io"
"syscall"
"unicode/utf16"
"unsafe"
)
const (
// Registry value types.
NONE = 0
SZ = 1
EXPAND_SZ = 2
BINARY = 3
DWORD = 4
DWORD_BIG_ENDIAN = 5
LINK = 6
MULTI_SZ = 7
RESOURCE_LIST = 8
FULL_RESOURCE_DESCRIPTOR = 9
RESOURCE_REQUIREMENTS_LIST = 10
QWORD = 11
)
var (
// ErrShortBuffer is returned when the buffer was too short for the operation.
ErrShortBuffer = syscall.ERROR_MORE_DATA
// ErrNotExist is returned when a registry key or value does not exist.
ErrNotExist = syscall.ERROR_FILE_NOT_FOUND
// ErrUnexpectedType is returned by Get*Value when the value's type was unexpected.
ErrUnexpectedType = errors.New("unexpected key value type")
)
// GetValue retrieves the type and data for the specified value associated
// with an open key k. It fills up buffer buf and returns the retrieved
// byte count n. If buf is too small to fit the stored value it returns
// ErrShortBuffer error along with the required buffer size n.
// If no buffer is provided, it returns true and actual buffer size n.
// If no buffer is provided, GetValue returns the value's type only.
// If the value does not exist, the error returned is ErrNotExist.
//
// GetValue is a low level function. If value's type is known, use the appropriate
// Get*Value function instead.
func (k Key) GetValue(name string, buf []byte) (n int, valtype uint32, err error) {
pname, err := syscall.UTF16PtrFromString(name)
if err != nil {
return 0, 0, err
}
var pbuf *byte
if len(buf) > 0 {
pbuf = (*byte)(unsafe.Pointer(&buf[0]))
}
l := uint32(len(buf))
err = syscall.RegQueryValueEx(syscall.Handle(k), pname, nil, &valtype, pbuf, &l)
if err != nil {
return int(l), valtype, err
}
return int(l), valtype, nil
}
func (k Key) getValue(name string, buf []byte) (date []byte, valtype uint32, err error) {
p, err := syscall.UTF16PtrFromString(name)
if err != nil {
return nil, 0, err
}
var t uint32
n := uint32(len(buf))
for {
err = syscall.RegQueryValueEx(syscall.Handle(k), p, nil, &t, (*byte)(unsafe.Pointer(&buf[0])), &n)
if err == nil {
return buf[:n], t, nil
}
if err != syscall.ERROR_MORE_DATA {
return nil, 0, err
}
if n <= uint32(len(buf)) {
return nil, 0, err
}
buf = make([]byte, n)
}
}
// GetStringValue retrieves the string value for the specified
// value name associated with an open key k. It also returns the value's type.
// If value does not exist, GetStringValue returns ErrNotExist.
// If value is not SZ or EXPAND_SZ, it will return the correct value
// type and ErrUnexpectedType.
func (k Key) GetStringValue(name string) (val string, valtype uint32, err error) {
data, typ, err2 := k.getValue(name, make([]byte, 64))
if err2 != nil {
return "", typ, err2
}
switch typ {
case SZ, EXPAND_SZ:
default:
return "", typ, ErrUnexpectedType
}
if len(data) == 0 {
return "", typ, nil
}
u := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:]
return syscall.UTF16ToString(u), typ, nil
}
// GetMUIStringValue retrieves the localized string value for
// the specified value name associated with an open key k.
// If the value name doesn't exist or the localized string value
// can't be resolved, GetMUIStringValue returns ErrNotExist.
// GetMUIStringValue panics if the system doesn't support
// regLoadMUIString; use LoadRegLoadMUIString to check if
// regLoadMUIString is supported before calling this function.
func (k Key) GetMUIStringValue(name string) (string, error) {
pname, err := syscall.UTF16PtrFromString(name)
if err != nil {
return "", err
}
buf := make([]uint16, 1024)
var buflen uint32
var pdir *uint16
err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
if err == syscall.ERROR_FILE_NOT_FOUND { // Try fallback path
// Try to resolve the string value using the system directory as
// a DLL search path; this assumes the string value is of the form
// @[path]\dllname,-strID but with no path given, e.g. @tzres.dll,-320.
// This approach works with tzres.dll but may have to be revised
// in the future to allow callers to provide custom search paths.
var s string
s, err = ExpandString("%SystemRoot%\\system32\\")
if err != nil {
return "", err
}
pdir, err = syscall.UTF16PtrFromString(s)
if err != nil {
return "", err
}
err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
}
for err == syscall.ERROR_MORE_DATA { // Grow buffer if needed
if buflen <= uint32(len(buf)) {
break // Buffer not growing, assume race; break
}
buf = make([]uint16, buflen)
err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
}
if err != nil {
return "", err
}
return syscall.UTF16ToString(buf), nil
}
// ExpandString expands environment-variable strings and replaces
// them with the values defined for the current user.
// Use ExpandString to expand EXPAND_SZ strings.
func ExpandString(value string) (string, error) {
if value == "" {
return "", nil
}
p, err := syscall.UTF16PtrFromString(value)
if err != nil {
return "", err
}
r := make([]uint16, 100)
for {
n, err := expandEnvironmentStrings(p, &r[0], uint32(len(r)))
if err != nil {
return "", err
}
if n <= uint32(len(r)) {
u := (*[1 << 29]uint16)(unsafe.Pointer(&r[0]))[:]
return syscall.UTF16ToString(u), nil
}
r = make([]uint16, n)
}
}
// GetStringsValue retrieves the []string value for the specified
// value name associated with an open key k. It also returns the value's type.
// If value does not exist, GetStringsValue returns ErrNotExist.
// If value is not MULTI_SZ, it will return the correct value
// type and ErrUnexpectedType.
func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err error) {
data, typ, err2 := k.getValue(name, make([]byte, 64))
if err2 != nil {
return nil, typ, err2
}
if typ != MULTI_SZ {
return nil, typ, ErrUnexpectedType
}
if len(data) == 0 {
return nil, typ, nil
}
p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2]
if len(p) == 0 {
return nil, typ, nil
}
if p[len(p)-1] == 0 {
p = p[:len(p)-1] // remove terminating null
}
val = make([]string, 0, 5)
from := 0
for i, c := range p {
if c == 0 {
val = append(val, string(utf16.Decode(p[from:i])))
from = i + 1
}
}
return val, typ, nil
}
// GetIntegerValue retrieves the integer value for the specified
// value name associated with an open key k. It also returns the value's type.
// If value does not exist, GetIntegerValue returns ErrNotExist.
// If value is not DWORD or QWORD, it will return the correct value
// type and ErrUnexpectedType.
func (k Key) GetIntegerValue(name string) (val uint64, valtype uint32, err error) {
data, typ, err2 := k.getValue(name, make([]byte, 8))
if err2 != nil {
return 0, typ, err2
}
switch typ {
case DWORD:
if len(data) != 4 {
return 0, typ, errors.New("DWORD value is not 4 bytes long")
}
return uint64(*(*uint32)(unsafe.Pointer(&data[0]))), DWORD, nil
case QWORD:
if len(data) != 8 {
return 0, typ, errors.New("QWORD value is not 8 bytes long")
}
return uint64(*(*uint64)(unsafe.Pointer(&data[0]))), QWORD, nil
default:
return 0, typ, ErrUnexpectedType
}
}
// GetBinaryValue retrieves the binary value for the specified
// value name associated with an open key k. It also returns the value's type.
// If value does not exist, GetBinaryValue returns ErrNotExist.
// If value is not BINARY, it will return the correct value
// type and ErrUnexpectedType.
func (k Key) GetBinaryValue(name string) (val []byte, valtype uint32, err error) {
data, typ, err2 := k.getValue(name, make([]byte, 64))
if err2 != nil {
return nil, typ, err2
}
if typ != BINARY {
return nil, typ, ErrUnexpectedType
}
return data, typ, nil
}
func (k Key) setValue(name string, valtype uint32, data []byte) error {
p, err := syscall.UTF16PtrFromString(name)
if err != nil {
return err
}
if len(data) == 0 {
return regSetValueEx(syscall.Handle(k), p, 0, valtype, nil, 0)
}
return regSetValueEx(syscall.Handle(k), p, 0, valtype, &data[0], uint32(len(data)))
}
// SetDWordValue sets the data and type of a name value
// under key k to value and DWORD.
func (k Key) SetDWordValue(name string, value uint32) error {
return k.setValue(name, DWORD, (*[4]byte)(unsafe.Pointer(&value))[:])
}
// SetQWordValue sets the data and type of a name value
// under key k to value and QWORD.
func (k Key) SetQWordValue(name string, value uint64) error {
return k.setValue(name, QWORD, (*[8]byte)(unsafe.Pointer(&value))[:])
}
func (k Key) setStringValue(name string, valtype uint32, value string) error {
v, err := syscall.UTF16FromString(value)
if err != nil {
return err
}
buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
return k.setValue(name, valtype, buf)
}
// SetStringValue sets the data and type of a name value
// under key k to value and SZ. The value must not contain a zero byte.
func (k Key) SetStringValue(name, value string) error {
return k.setStringValue(name, SZ, value)
}
// SetExpandStringValue sets the data and type of a name value
// under key k to value and EXPAND_SZ. The value must not contain a zero byte.
func (k Key) SetExpandStringValue(name, value string) error {
return k.setStringValue(name, EXPAND_SZ, value)
}
// SetStringsValue sets the data and type of a name value
// under key k to value and MULTI_SZ. The value strings
// must not contain a zero byte.
func (k Key) SetStringsValue(name string, value []string) error {
ss := ""
for _, s := range value {
for i := 0; i < len(s); i++ {
if s[i] == 0 {
return errors.New("string cannot have 0 inside")
}
}
ss += s + "\x00"
}
v := utf16.Encode([]rune(ss + "\x00"))
buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
return k.setValue(name, MULTI_SZ, buf)
}
// SetBinaryValue sets the data and type of a name value
// under key k to value and BINARY.
func (k Key) SetBinaryValue(name string, value []byte) error {
return k.setValue(name, BINARY, value)
}
// DeleteValue removes a named value from the key k.
func (k Key) DeleteValue(name string) error {
return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name))
}
// ReadValueNames returns the value names of key k.
// The parameter n controls the number of returned names,
// analogous to the way os.File.Readdirnames works.
func (k Key) ReadValueNames(n int) ([]string, error) {
ki, err := k.Stat()
if err != nil {
return nil, err
}
names := make([]string, 0, ki.ValueCount)
buf := make([]uint16, ki.MaxValueNameLen+1) // extra room for terminating null character
loopItems:
for i := uint32(0); ; i++ {
if n > 0 {
if len(names) == n {
return names, nil
}
}
l := uint32(len(buf))
for {
err := regEnumValue(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil)
if err == nil {
break
}
if err == syscall.ERROR_MORE_DATA {
// Double buffer size and try again.
l = uint32(2 * len(buf))
buf = make([]uint16, l)
continue
}
if err == _ERROR_NO_MORE_ITEMS {
break loopItems
}
return names, err
}
names = append(names, syscall.UTF16ToString(buf[:l]))
}
if n > len(names) {
return names, io.EOF
}
return names, nil
}

View File

@@ -0,0 +1,120 @@
// Code generated by 'go generate'; DO NOT EDIT.
package registry
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return nil
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procRegCreateKeyExW = modadvapi32.NewProc("RegCreateKeyExW")
procRegDeleteKeyW = modadvapi32.NewProc("RegDeleteKeyW")
procRegSetValueExW = modadvapi32.NewProc("RegSetValueExW")
procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW")
procRegDeleteValueW = modadvapi32.NewProc("RegDeleteValueW")
procRegLoadMUIStringW = modadvapi32.NewProc("RegLoadMUIStringW")
procRegConnectRegistryW = modadvapi32.NewProc("RegConnectRegistryW")
procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW")
)
func regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) {
r0, _, _ := syscall.Syscall9(procRegCreateKeyExW.Addr(), 9, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(reserved), uintptr(unsafe.Pointer(class)), uintptr(options), uintptr(desired), uintptr(unsafe.Pointer(sa)), uintptr(unsafe.Pointer(result)), uintptr(unsafe.Pointer(disposition)))
if r0 != 0 {
regerrno = syscall.Errno(r0)
}
return
}
func regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) {
r0, _, _ := syscall.Syscall(procRegDeleteKeyW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(subkey)), 0)
if r0 != 0 {
regerrno = syscall.Errno(r0)
}
return
}
func regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) {
r0, _, _ := syscall.Syscall6(procRegSetValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(valueName)), uintptr(reserved), uintptr(vtype), uintptr(unsafe.Pointer(buf)), uintptr(bufsize))
if r0 != 0 {
regerrno = syscall.Errno(r0)
}
return
}
func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) {
r0, _, _ := syscall.Syscall9(procRegEnumValueW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)), 0)
if r0 != 0 {
regerrno = syscall.Errno(r0)
}
return
}
func regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) {
r0, _, _ := syscall.Syscall(procRegDeleteValueW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(name)), 0)
if r0 != 0 {
regerrno = syscall.Errno(r0)
}
return
}
func regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) {
r0, _, _ := syscall.Syscall9(procRegLoadMUIStringW.Addr(), 7, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(unsafe.Pointer(buflenCopied)), uintptr(flags), uintptr(unsafe.Pointer(dir)), 0, 0)
if r0 != 0 {
regerrno = syscall.Errno(r0)
}
return
}
func regConnectRegistry(machinename *uint16, key syscall.Handle, result *syscall.Handle) (regerrno error) {
r0, _, _ := syscall.Syscall(procRegConnectRegistryW.Addr(), 3, uintptr(unsafe.Pointer(machinename)), uintptr(key), uintptr(unsafe.Pointer(result)))
if r0 != 0 {
regerrno = syscall.Errno(r0)
}
return
}
func expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) {
r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size))
n = uint32(r0)
if n == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}

56
vendor/golang.org/x/sys/windows/svc/debug/log.go generated vendored Normal file
View File

@@ -0,0 +1,56 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package debug
import (
"os"
"strconv"
)
// Log interface allows different log implementations to be used.
type Log interface {
Close() error
Info(eid uint32, msg string) error
Warning(eid uint32, msg string) error
Error(eid uint32, msg string) error
}
// ConsoleLog provides access to the console.
type ConsoleLog struct {
Name string
}
// New creates new ConsoleLog.
func New(source string) *ConsoleLog {
return &ConsoleLog{Name: source}
}
// Close closes console log l.
func (l *ConsoleLog) Close() error {
return nil
}
func (l *ConsoleLog) report(kind string, eid uint32, msg string) error {
s := l.Name + "." + kind + "(" + strconv.Itoa(int(eid)) + "): " + msg + "\n"
_, err := os.Stdout.Write([]byte(s))
return err
}
// Info writes an information event msg with event id eid to the console l.
func (l *ConsoleLog) Info(eid uint32, msg string) error {
return l.report("info", eid, msg)
}
// Warning writes an warning event msg with event id eid to the console l.
func (l *ConsoleLog) Warning(eid uint32, msg string) error {
return l.report("warn", eid, msg)
}
// Error writes an error event msg with event id eid to the console l.
func (l *ConsoleLog) Error(eid uint32, msg string) error {
return l.report("error", eid, msg)
}

45
vendor/golang.org/x/sys/windows/svc/debug/service.go generated vendored Normal file
View File

@@ -0,0 +1,45 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// Package debug provides facilities to execute svc.Handler on console.
//
package debug
import (
"os"
"os/signal"
"syscall"
"golang.org/x/sys/windows/svc"
)
// Run executes service name by calling appropriate handler function.
// The process is running on console, unlike real service. Use Ctrl+C to
// send "Stop" command to your service.
func Run(name string, handler svc.Handler) error {
cmds := make(chan svc.ChangeRequest)
changes := make(chan svc.Status)
sig := make(chan os.Signal)
signal.Notify(sig)
go func() {
status := svc.Status{State: svc.Stopped}
for {
select {
case <-sig:
cmds <- svc.ChangeRequest{Cmd: svc.Stop, CurrentStatus: status}
case status = <-changes:
}
}
}()
_, errno := handler.Execute([]string{name}, cmds, changes)
if errno != 0 {
return syscall.Errno(errno)
}
return nil
}

View File

@@ -0,0 +1,80 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package eventlog
import (
"errors"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/registry"
)
const (
// Log levels.
Info = windows.EVENTLOG_INFORMATION_TYPE
Warning = windows.EVENTLOG_WARNING_TYPE
Error = windows.EVENTLOG_ERROR_TYPE
)
const addKeyName = `SYSTEM\CurrentControlSet\Services\EventLog\Application`
// Install modifies PC registry to allow logging with an event source src.
// It adds all required keys and values to the event log registry key.
// Install uses msgFile as the event message file. If useExpandKey is true,
// the event message file is installed as REG_EXPAND_SZ value,
// otherwise as REG_SZ. Use bitwise of log.Error, log.Warning and
// log.Info to specify events supported by the new event source.
func Install(src, msgFile string, useExpandKey bool, eventsSupported uint32) error {
appkey, err := registry.OpenKey(registry.LOCAL_MACHINE, addKeyName, registry.CREATE_SUB_KEY)
if err != nil {
return err
}
defer appkey.Close()
sk, alreadyExist, err := registry.CreateKey(appkey, src, registry.SET_VALUE)
if err != nil {
return err
}
defer sk.Close()
if alreadyExist {
return errors.New(addKeyName + `\` + src + " registry key already exists")
}
err = sk.SetDWordValue("CustomSource", 1)
if err != nil {
return err
}
if useExpandKey {
err = sk.SetExpandStringValue("EventMessageFile", msgFile)
} else {
err = sk.SetStringValue("EventMessageFile", msgFile)
}
if err != nil {
return err
}
err = sk.SetDWordValue("TypesSupported", eventsSupported)
if err != nil {
return err
}
return nil
}
// InstallAsEventCreate is the same as Install, but uses
// %SystemRoot%\System32\EventCreate.exe as the event message file.
func InstallAsEventCreate(src string, eventsSupported uint32) error {
return Install(src, "%SystemRoot%\\System32\\EventCreate.exe", true, eventsSupported)
}
// Remove deletes all registry elements installed by the correspondent Install.
func Remove(src string) error {
appkey, err := registry.OpenKey(registry.LOCAL_MACHINE, addKeyName, registry.SET_VALUE)
if err != nil {
return err
}
defer appkey.Close()
return registry.DeleteKey(appkey, src)
}

70
vendor/golang.org/x/sys/windows/svc/eventlog/log.go generated vendored Normal file
View File

@@ -0,0 +1,70 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// Package eventlog implements access to Windows event log.
//
package eventlog
import (
"errors"
"syscall"
"golang.org/x/sys/windows"
)
// Log provides access to the system log.
type Log struct {
Handle windows.Handle
}
// Open retrieves a handle to the specified event log.
func Open(source string) (*Log, error) {
return OpenRemote("", source)
}
// OpenRemote does the same as Open, but on different computer host.
func OpenRemote(host, source string) (*Log, error) {
if source == "" {
return nil, errors.New("Specify event log source")
}
var s *uint16
if host != "" {
s = syscall.StringToUTF16Ptr(host)
}
h, err := windows.RegisterEventSource(s, syscall.StringToUTF16Ptr(source))
if err != nil {
return nil, err
}
return &Log{Handle: h}, nil
}
// Close closes event log l.
func (l *Log) Close() error {
return windows.DeregisterEventSource(l.Handle)
}
func (l *Log) report(etype uint16, eid uint32, msg string) error {
ss := []*uint16{syscall.StringToUTF16Ptr(msg)}
return windows.ReportEvent(l.Handle, etype, 0, eid, 0, 1, 0, &ss[0], nil)
}
// Info writes an information event msg with event id eid to the end of event log l.
// When EventCreate.exe is used, eid must be between 1 and 1000.
func (l *Log) Info(eid uint32, msg string) error {
return l.report(windows.EVENTLOG_INFORMATION_TYPE, eid, msg)
}
// Warning writes an warning event msg with event id eid to the end of event log l.
// When EventCreate.exe is used, eid must be between 1 and 1000.
func (l *Log) Warning(eid uint32, msg string) error {
return l.report(windows.EVENTLOG_WARNING_TYPE, eid, msg)
}
// Error writes an error event msg with event id eid to the end of event log l.
// When EventCreate.exe is used, eid must be between 1 and 1000.
func (l *Log) Error(eid uint32, msg string) error {
return l.report(windows.EVENTLOG_ERROR_TYPE, eid, msg)
}

145
vendor/golang.org/x/sys/windows/svc/mgr/config.go generated vendored Normal file
View File

@@ -0,0 +1,145 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package mgr
import (
"syscall"
"unicode/utf16"
"unsafe"
"golang.org/x/sys/windows"
)
const (
// Service start types.
StartManual = windows.SERVICE_DEMAND_START // the service must be started manually
StartAutomatic = windows.SERVICE_AUTO_START // the service will start by itself whenever the computer reboots
StartDisabled = windows.SERVICE_DISABLED // the service cannot be started
// The severity of the error, and action taken,
// if this service fails to start.
ErrorCritical = windows.SERVICE_ERROR_CRITICAL
ErrorIgnore = windows.SERVICE_ERROR_IGNORE
ErrorNormal = windows.SERVICE_ERROR_NORMAL
ErrorSevere = windows.SERVICE_ERROR_SEVERE
)
// TODO(brainman): Password is not returned by windows.QueryServiceConfig, not sure how to get it.
type Config struct {
ServiceType uint32
StartType uint32
ErrorControl uint32
BinaryPathName string // fully qualified path to the service binary file, can also include arguments for an auto-start service
LoadOrderGroup string
TagId uint32
Dependencies []string
ServiceStartName string // name of the account under which the service should run
DisplayName string
Password string
Description string
}
func toString(p *uint16) string {
if p == nil {
return ""
}
return syscall.UTF16ToString((*[4096]uint16)(unsafe.Pointer(p))[:])
}
func toStringSlice(ps *uint16) []string {
if ps == nil {
return nil
}
r := make([]string, 0)
for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(ps)); true; i++ {
if p[i] == 0 {
// empty string marks the end
if i <= from {
break
}
r = append(r, string(utf16.Decode(p[from:i])))
from = i + 1
}
}
return r
}
// Config retrieves service s configuration paramteres.
func (s *Service) Config() (Config, error) {
var p *windows.QUERY_SERVICE_CONFIG
n := uint32(1024)
for {
b := make([]byte, n)
p = (*windows.QUERY_SERVICE_CONFIG)(unsafe.Pointer(&b[0]))
err := windows.QueryServiceConfig(s.Handle, p, n, &n)
if err == nil {
break
}
if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER {
return Config{}, err
}
if n <= uint32(len(b)) {
return Config{}, err
}
}
b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_DESCRIPTION)
if err != nil {
return Config{}, err
}
p2 := (*windows.SERVICE_DESCRIPTION)(unsafe.Pointer(&b[0]))
return Config{
ServiceType: p.ServiceType,
StartType: p.StartType,
ErrorControl: p.ErrorControl,
BinaryPathName: toString(p.BinaryPathName),
LoadOrderGroup: toString(p.LoadOrderGroup),
TagId: p.TagId,
Dependencies: toStringSlice(p.Dependencies),
ServiceStartName: toString(p.ServiceStartName),
DisplayName: toString(p.DisplayName),
Description: toString(p2.Description),
}, nil
}
func updateDescription(handle windows.Handle, desc string) error {
d := windows.SERVICE_DESCRIPTION{Description: toPtr(desc)}
return windows.ChangeServiceConfig2(handle,
windows.SERVICE_CONFIG_DESCRIPTION, (*byte)(unsafe.Pointer(&d)))
}
// UpdateConfig updates service s configuration parameters.
func (s *Service) UpdateConfig(c Config) error {
err := windows.ChangeServiceConfig(s.Handle, c.ServiceType, c.StartType,
c.ErrorControl, toPtr(c.BinaryPathName), toPtr(c.LoadOrderGroup),
nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName),
toPtr(c.Password), toPtr(c.DisplayName))
if err != nil {
return err
}
return updateDescription(s.Handle, c.Description)
}
// queryServiceConfig2 calls Windows QueryServiceConfig2 with infoLevel parameter and returns retrieved service configuration information.
func (s *Service) queryServiceConfig2(infoLevel uint32) ([]byte, error) {
n := uint32(1024)
for {
b := make([]byte, n)
err := windows.QueryServiceConfig2(s.Handle, infoLevel, &b[0], n, &n)
if err == nil {
return b, nil
}
if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER {
return nil, err
}
if n <= uint32(len(b)) {
return nil, err
}
}
}

162
vendor/golang.org/x/sys/windows/svc/mgr/mgr.go generated vendored Normal file
View File

@@ -0,0 +1,162 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// Package mgr can be used to manage Windows service programs.
// It can be used to install and remove them. It can also start,
// stop and pause them. The package can query / change current
// service state and config parameters.
//
package mgr
import (
"syscall"
"unicode/utf16"
"unsafe"
"golang.org/x/sys/windows"
)
// Mgr is used to manage Windows service.
type Mgr struct {
Handle windows.Handle
}
// Connect establishes a connection to the service control manager.
func Connect() (*Mgr, error) {
return ConnectRemote("")
}
// ConnectRemote establishes a connection to the
// service control manager on computer named host.
func ConnectRemote(host string) (*Mgr, error) {
var s *uint16
if host != "" {
s = syscall.StringToUTF16Ptr(host)
}
h, err := windows.OpenSCManager(s, nil, windows.SC_MANAGER_ALL_ACCESS)
if err != nil {
return nil, err
}
return &Mgr{Handle: h}, nil
}
// Disconnect closes connection to the service control manager m.
func (m *Mgr) Disconnect() error {
return windows.CloseServiceHandle(m.Handle)
}
func toPtr(s string) *uint16 {
if len(s) == 0 {
return nil
}
return syscall.StringToUTF16Ptr(s)
}
// toStringBlock terminates strings in ss with 0, and then
// concatenates them together. It also adds extra 0 at the end.
func toStringBlock(ss []string) *uint16 {
if len(ss) == 0 {
return nil
}
t := ""
for _, s := range ss {
if s != "" {
t += s + "\x00"
}
}
if t == "" {
return nil
}
t += "\x00"
return &utf16.Encode([]rune(t))[0]
}
// CreateService installs new service name on the system.
// The service will be executed by running exepath binary.
// Use config c to specify service parameters.
// Any args will be passed as command-line arguments when
// the service is started; these arguments are distinct from
// the arguments passed to Service.Start or via the "Start
// parameters" field in the service's Properties dialog box.
func (m *Mgr) CreateService(name, exepath string, c Config, args ...string) (*Service, error) {
if c.StartType == 0 {
c.StartType = StartManual
}
if c.ErrorControl == 0 {
c.ErrorControl = ErrorNormal
}
if c.ServiceType == 0 {
c.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS
}
s := syscall.EscapeArg(exepath)
for _, v := range args {
s += " " + syscall.EscapeArg(v)
}
h, err := windows.CreateService(m.Handle, toPtr(name), toPtr(c.DisplayName),
windows.SERVICE_ALL_ACCESS, c.ServiceType,
c.StartType, c.ErrorControl, toPtr(s), toPtr(c.LoadOrderGroup),
nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName), toPtr(c.Password))
if err != nil {
return nil, err
}
if c.Description != "" {
err = updateDescription(h, c.Description)
if err != nil {
return nil, err
}
}
return &Service{Name: name, Handle: h}, nil
}
// OpenService retrieves access to service name, so it can
// be interrogated and controlled.
func (m *Mgr) OpenService(name string) (*Service, error) {
h, err := windows.OpenService(m.Handle, syscall.StringToUTF16Ptr(name), windows.SERVICE_ALL_ACCESS)
if err != nil {
return nil, err
}
return &Service{Name: name, Handle: h}, nil
}
// ListServices enumerates services in the specified
// service control manager database m.
// If the caller does not have the SERVICE_QUERY_STATUS
// access right to a service, the service is silently
// omitted from the list of services returned.
func (m *Mgr) ListServices() ([]string, error) {
var err error
var bytesNeeded, servicesReturned uint32
var buf []byte
for {
var p *byte
if len(buf) > 0 {
p = &buf[0]
}
err = windows.EnumServicesStatusEx(m.Handle, windows.SC_ENUM_PROCESS_INFO,
windows.SERVICE_WIN32, windows.SERVICE_STATE_ALL,
p, uint32(len(buf)), &bytesNeeded, &servicesReturned, nil, nil)
if err == nil {
break
}
if err != syscall.ERROR_MORE_DATA {
return nil, err
}
if bytesNeeded <= uint32(len(buf)) {
return nil, err
}
buf = make([]byte, bytesNeeded)
}
if servicesReturned == 0 {
return nil, nil
}
services := (*[1 << 20]windows.ENUM_SERVICE_STATUS_PROCESS)(unsafe.Pointer(&buf[0]))[:servicesReturned]
var names []string
for _, s := range services {
name := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(s.ServiceName))[:])
names = append(names, name)
}
return names, nil
}

96
vendor/golang.org/x/sys/windows/svc/mgr/recovery.go generated vendored Normal file
View File

@@ -0,0 +1,96 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package mgr
import (
"errors"
"time"
"unsafe"
"golang.org/x/sys/windows"
)
const (
// Possible recovery actions that the service control manager can perform.
NoAction = windows.SC_ACTION_NONE // no action
ComputerReboot = windows.SC_ACTION_REBOOT // reboot the computer
ServiceRestart = windows.SC_ACTION_RESTART // restart the service
RunCommand = windows.SC_ACTION_RUN_COMMAND // run a command
)
// RecoveryAction represents an action that the service control manager can perform when service fails.
// A service is considered failed when it terminates without reporting a status of SERVICE_STOPPED to the service controller.
type RecoveryAction struct {
Type int // one of NoAction, ComputerReboot, ServiceRestart or RunCommand
Delay time.Duration // the time to wait before performing the specified action
}
// SetRecoveryActions sets actions that service controller performs when service fails and
// the time after which to reset the service failure count to zero if there are no failures, in seconds.
// Specify INFINITE to indicate that service failure count should never be reset.
func (s *Service) SetRecoveryActions(recoveryActions []RecoveryAction, resetPeriod uint32) error {
if recoveryActions == nil {
return errors.New("recoveryActions cannot be nil")
}
actions := []windows.SC_ACTION{}
for _, a := range recoveryActions {
action := windows.SC_ACTION{
Type: uint32(a.Type),
Delay: uint32(a.Delay.Nanoseconds() / 1000000),
}
actions = append(actions, action)
}
rActions := windows.SERVICE_FAILURE_ACTIONS{
ActionsCount: uint32(len(actions)),
Actions: &actions[0],
ResetPeriod: resetPeriod,
}
return windows.ChangeServiceConfig2(s.Handle, windows.SERVICE_CONFIG_FAILURE_ACTIONS, (*byte)(unsafe.Pointer(&rActions)))
}
// RecoveryActions returns actions that service controller performs when service fails.
// The service control manager counts the number of times service s has failed since the system booted.
// The count is reset to 0 if the service has not failed for ResetPeriod seconds.
// When the service fails for the Nth time, the service controller performs the action specified in element [N-1] of returned slice.
// If N is greater than slice length, the service controller repeats the last action in the slice.
func (s *Service) RecoveryActions() ([]RecoveryAction, error) {
b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_FAILURE_ACTIONS)
if err != nil {
return nil, err
}
p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
if p.Actions == nil {
return nil, err
}
var recoveryActions []RecoveryAction
actions := (*[1024]windows.SC_ACTION)(unsafe.Pointer(p.Actions))[:p.ActionsCount]
for _, action := range actions {
recoveryActions = append(recoveryActions, RecoveryAction{Type: int(action.Type), Delay: time.Duration(action.Delay) * time.Millisecond})
}
return recoveryActions, nil
}
// ResetRecoveryActions deletes both reset period and array of failure actions.
func (s *Service) ResetRecoveryActions() error {
actions := make([]windows.SC_ACTION, 1)
rActions := windows.SERVICE_FAILURE_ACTIONS{
Actions: &actions[0],
}
return windows.ChangeServiceConfig2(s.Handle, windows.SERVICE_CONFIG_FAILURE_ACTIONS, (*byte)(unsafe.Pointer(&rActions)))
}
// ResetPeriod is the time after which to reset the service failure
// count to zero if there are no failures, in seconds.
func (s *Service) ResetPeriod() (uint32, error) {
b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_FAILURE_ACTIONS)
if err != nil {
return 0, err
}
p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
return p.ResetPeriod, nil
}

72
vendor/golang.org/x/sys/windows/svc/mgr/service.go generated vendored Normal file
View File

@@ -0,0 +1,72 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package mgr
import (
"syscall"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/svc"
)
// TODO(brainman): Use EnumDependentServices to enumerate dependent services.
// Service is used to access Windows service.
type Service struct {
Name string
Handle windows.Handle
}
// Delete marks service s for deletion from the service control manager database.
func (s *Service) Delete() error {
return windows.DeleteService(s.Handle)
}
// Close relinquish access to the service s.
func (s *Service) Close() error {
return windows.CloseServiceHandle(s.Handle)
}
// Start starts service s.
// args will be passed to svc.Handler.Execute.
func (s *Service) Start(args ...string) error {
var p **uint16
if len(args) > 0 {
vs := make([]*uint16, len(args))
for i := range vs {
vs[i] = syscall.StringToUTF16Ptr(args[i])
}
p = &vs[0]
}
return windows.StartService(s.Handle, uint32(len(args)), p)
}
// Control sends state change request c to the servce s.
func (s *Service) Control(c svc.Cmd) (svc.Status, error) {
var t windows.SERVICE_STATUS
err := windows.ControlService(s.Handle, uint32(c), &t)
if err != nil {
return svc.Status{}, err
}
return svc.Status{
State: svc.State(t.CurrentState),
Accepts: svc.Accepted(t.ControlsAccepted),
}, nil
}
// Query returns current status of service s.
func (s *Service) Query() (svc.Status, error) {
var t windows.SERVICE_STATUS
err := windows.QueryServiceStatus(s.Handle, &t)
if err != nil {
return svc.Status{}, err
}
return svc.Status{
State: svc.State(t.CurrentState),
Accepts: svc.Accepted(t.ControlsAccepted),
}, nil
}