mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 02:33:34 +00:00
11
vendor/golang.org/x/sys/windows/registry/export_test.go
generated
vendored
11
vendor/golang.org/x/sys/windows/registry/export_test.go
generated
vendored
@ -1,11 +0,0 @@
|
||||
// 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
|
||||
|
||||
func (k Key) SetValue(name string, valtype uint32, data []byte) error {
|
||||
return k.setValue(name, valtype, data)
|
||||
}
|
198
vendor/golang.org/x/sys/windows/registry/key.go
generated
vendored
198
vendor/golang.org/x/sys/windows/registry/key.go
generated
vendored
@ -1,198 +0,0 @@
|
||||
// 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
|
||||
}
|
7
vendor/golang.org/x/sys/windows/registry/mksyscall.go
generated
vendored
7
vendor/golang.org/x/sys/windows/registry/mksyscall.go
generated
vendored
@ -1,7 +0,0 @@
|
||||
// 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
|
756
vendor/golang.org/x/sys/windows/registry/registry_test.go
generated
vendored
756
vendor/golang.org/x/sys/windows/registry/registry_test.go
generated
vendored
@ -1,756 +0,0 @@
|
||||
// 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_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
func randKeyName(prefix string) string {
|
||||
const numbers = "0123456789"
|
||||
buf := make([]byte, 10)
|
||||
rand.Read(buf)
|
||||
for i, b := range buf {
|
||||
buf[i] = numbers[b%byte(len(numbers))]
|
||||
}
|
||||
return prefix + string(buf)
|
||||
}
|
||||
|
||||
func TestReadSubKeyNames(t *testing.T) {
|
||||
k, err := registry.OpenKey(registry.CLASSES_ROOT, "TypeLib", registry.ENUMERATE_SUB_KEYS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer k.Close()
|
||||
|
||||
names, err := k.ReadSubKeyNames(-1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var foundStdOle bool
|
||||
for _, name := range names {
|
||||
// Every PC has "stdole 2.0 OLE Automation" library installed.
|
||||
if name == "{00020430-0000-0000-C000-000000000046}" {
|
||||
foundStdOle = true
|
||||
}
|
||||
}
|
||||
if !foundStdOle {
|
||||
t.Fatal("could not find stdole 2.0 OLE Automation")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateOpenDeleteKey(t *testing.T) {
|
||||
k, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer k.Close()
|
||||
|
||||
testKName := randKeyName("TestCreateOpenDeleteKey_")
|
||||
|
||||
testK, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer testK.Close()
|
||||
|
||||
if exist {
|
||||
t.Fatalf("key %q already exists", testKName)
|
||||
}
|
||||
|
||||
testKAgain, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer testKAgain.Close()
|
||||
|
||||
if !exist {
|
||||
t.Fatalf("key %q should already exist", testKName)
|
||||
}
|
||||
|
||||
testKOpened, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer testKOpened.Close()
|
||||
|
||||
err = registry.DeleteKey(k, testKName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testKOpenedAgain, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS)
|
||||
if err == nil {
|
||||
defer testKOpenedAgain.Close()
|
||||
t.Fatalf("key %q should already been deleted", testKName)
|
||||
}
|
||||
if err != registry.ErrNotExist {
|
||||
t.Fatalf(`unexpected error ("not exist" expected): %v`, err)
|
||||
}
|
||||
}
|
||||
|
||||
func equalStringSlice(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
if a == nil {
|
||||
return true
|
||||
}
|
||||
for i := range a {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type ValueTest struct {
|
||||
Type uint32
|
||||
Name string
|
||||
Value interface{}
|
||||
WillFail bool
|
||||
}
|
||||
|
||||
var ValueTests = []ValueTest{
|
||||
{Type: registry.SZ, Name: "String1", Value: ""},
|
||||
{Type: registry.SZ, Name: "String2", Value: "\000", WillFail: true},
|
||||
{Type: registry.SZ, Name: "String3", Value: "Hello World"},
|
||||
{Type: registry.SZ, Name: "String4", Value: "Hello World\000", WillFail: true},
|
||||
{Type: registry.EXPAND_SZ, Name: "ExpString1", Value: ""},
|
||||
{Type: registry.EXPAND_SZ, Name: "ExpString2", Value: "\000", WillFail: true},
|
||||
{Type: registry.EXPAND_SZ, Name: "ExpString3", Value: "Hello World"},
|
||||
{Type: registry.EXPAND_SZ, Name: "ExpString4", Value: "Hello\000World", WillFail: true},
|
||||
{Type: registry.EXPAND_SZ, Name: "ExpString5", Value: "%PATH%"},
|
||||
{Type: registry.EXPAND_SZ, Name: "ExpString6", Value: "%NO_SUCH_VARIABLE%"},
|
||||
{Type: registry.EXPAND_SZ, Name: "ExpString7", Value: "%PATH%;."},
|
||||
{Type: registry.BINARY, Name: "Binary1", Value: []byte{}},
|
||||
{Type: registry.BINARY, Name: "Binary2", Value: []byte{1, 2, 3}},
|
||||
{Type: registry.BINARY, Name: "Binary3", Value: []byte{3, 2, 1, 0, 1, 2, 3}},
|
||||
{Type: registry.DWORD, Name: "Dword1", Value: uint64(0)},
|
||||
{Type: registry.DWORD, Name: "Dword2", Value: uint64(1)},
|
||||
{Type: registry.DWORD, Name: "Dword3", Value: uint64(0xff)},
|
||||
{Type: registry.DWORD, Name: "Dword4", Value: uint64(0xffff)},
|
||||
{Type: registry.QWORD, Name: "Qword1", Value: uint64(0)},
|
||||
{Type: registry.QWORD, Name: "Qword2", Value: uint64(1)},
|
||||
{Type: registry.QWORD, Name: "Qword3", Value: uint64(0xff)},
|
||||
{Type: registry.QWORD, Name: "Qword4", Value: uint64(0xffff)},
|
||||
{Type: registry.QWORD, Name: "Qword5", Value: uint64(0xffffff)},
|
||||
{Type: registry.QWORD, Name: "Qword6", Value: uint64(0xffffffff)},
|
||||
{Type: registry.MULTI_SZ, Name: "MultiString1", Value: []string{"a", "b", "c"}},
|
||||
{Type: registry.MULTI_SZ, Name: "MultiString2", Value: []string{"abc", "", "cba"}},
|
||||
{Type: registry.MULTI_SZ, Name: "MultiString3", Value: []string{""}},
|
||||
{Type: registry.MULTI_SZ, Name: "MultiString4", Value: []string{"abcdef"}},
|
||||
{Type: registry.MULTI_SZ, Name: "MultiString5", Value: []string{"\000"}, WillFail: true},
|
||||
{Type: registry.MULTI_SZ, Name: "MultiString6", Value: []string{"a\000b"}, WillFail: true},
|
||||
{Type: registry.MULTI_SZ, Name: "MultiString7", Value: []string{"ab", "\000", "cd"}, WillFail: true},
|
||||
{Type: registry.MULTI_SZ, Name: "MultiString8", Value: []string{"\000", "cd"}, WillFail: true},
|
||||
{Type: registry.MULTI_SZ, Name: "MultiString9", Value: []string{"ab", "\000"}, WillFail: true},
|
||||
}
|
||||
|
||||
func setValues(t *testing.T, k registry.Key) {
|
||||
for _, test := range ValueTests {
|
||||
var err error
|
||||
switch test.Type {
|
||||
case registry.SZ:
|
||||
err = k.SetStringValue(test.Name, test.Value.(string))
|
||||
case registry.EXPAND_SZ:
|
||||
err = k.SetExpandStringValue(test.Name, test.Value.(string))
|
||||
case registry.MULTI_SZ:
|
||||
err = k.SetStringsValue(test.Name, test.Value.([]string))
|
||||
case registry.BINARY:
|
||||
err = k.SetBinaryValue(test.Name, test.Value.([]byte))
|
||||
case registry.DWORD:
|
||||
err = k.SetDWordValue(test.Name, uint32(test.Value.(uint64)))
|
||||
case registry.QWORD:
|
||||
err = k.SetQWordValue(test.Name, test.Value.(uint64))
|
||||
default:
|
||||
t.Fatalf("unsupported type %d for %s value", test.Type, test.Name)
|
||||
}
|
||||
if test.WillFail {
|
||||
if err == nil {
|
||||
t.Fatalf("setting %s value %q should fail, but succeeded", test.Name, test.Value)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func enumerateValues(t *testing.T, k registry.Key) {
|
||||
names, err := k.ReadValueNames(-1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
haveNames := make(map[string]bool)
|
||||
for _, n := range names {
|
||||
haveNames[n] = false
|
||||
}
|
||||
for _, test := range ValueTests {
|
||||
wantFound := !test.WillFail
|
||||
_, haveFound := haveNames[test.Name]
|
||||
if wantFound && !haveFound {
|
||||
t.Errorf("value %s is not found while enumerating", test.Name)
|
||||
}
|
||||
if haveFound && !wantFound {
|
||||
t.Errorf("value %s is found while enumerating, but expected to fail", test.Name)
|
||||
}
|
||||
if haveFound {
|
||||
delete(haveNames, test.Name)
|
||||
}
|
||||
}
|
||||
for n, v := range haveNames {
|
||||
t.Errorf("value %s (%v) is found while enumerating, but has not been cretaed", n, v)
|
||||
}
|
||||
}
|
||||
|
||||
func testErrNotExist(t *testing.T, name string, err error) {
|
||||
if err == nil {
|
||||
t.Errorf("%s value should not exist", name)
|
||||
return
|
||||
}
|
||||
if err != registry.ErrNotExist {
|
||||
t.Errorf("reading %s value should return 'not exist' error, but got: %s", name, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func testErrUnexpectedType(t *testing.T, test ValueTest, gottype uint32, err error) {
|
||||
if err == nil {
|
||||
t.Errorf("GetXValue(%q) should not succeed", test.Name)
|
||||
return
|
||||
}
|
||||
if err != registry.ErrUnexpectedType {
|
||||
t.Errorf("reading %s value should return 'unexpected key value type' error, but got: %s", test.Name, err)
|
||||
return
|
||||
}
|
||||
if gottype != test.Type {
|
||||
t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func testGetStringValue(t *testing.T, k registry.Key, test ValueTest) {
|
||||
got, gottype, err := k.GetStringValue(test.Name)
|
||||
if err != nil {
|
||||
t.Errorf("GetStringValue(%s) failed: %v", test.Name, err)
|
||||
return
|
||||
}
|
||||
if got != test.Value {
|
||||
t.Errorf("want %s value %q, got %q", test.Name, test.Value, got)
|
||||
return
|
||||
}
|
||||
if gottype != test.Type {
|
||||
t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
|
||||
return
|
||||
}
|
||||
if gottype == registry.EXPAND_SZ {
|
||||
_, err = registry.ExpandString(got)
|
||||
if err != nil {
|
||||
t.Errorf("ExpandString(%s) failed: %v", got, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testGetIntegerValue(t *testing.T, k registry.Key, test ValueTest) {
|
||||
got, gottype, err := k.GetIntegerValue(test.Name)
|
||||
if err != nil {
|
||||
t.Errorf("GetIntegerValue(%s) failed: %v", test.Name, err)
|
||||
return
|
||||
}
|
||||
if got != test.Value.(uint64) {
|
||||
t.Errorf("want %s value %v, got %v", test.Name, test.Value, got)
|
||||
return
|
||||
}
|
||||
if gottype != test.Type {
|
||||
t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func testGetBinaryValue(t *testing.T, k registry.Key, test ValueTest) {
|
||||
got, gottype, err := k.GetBinaryValue(test.Name)
|
||||
if err != nil {
|
||||
t.Errorf("GetBinaryValue(%s) failed: %v", test.Name, err)
|
||||
return
|
||||
}
|
||||
if !bytes.Equal(got, test.Value.([]byte)) {
|
||||
t.Errorf("want %s value %v, got %v", test.Name, test.Value, got)
|
||||
return
|
||||
}
|
||||
if gottype != test.Type {
|
||||
t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func testGetStringsValue(t *testing.T, k registry.Key, test ValueTest) {
|
||||
got, gottype, err := k.GetStringsValue(test.Name)
|
||||
if err != nil {
|
||||
t.Errorf("GetStringsValue(%s) failed: %v", test.Name, err)
|
||||
return
|
||||
}
|
||||
if !equalStringSlice(got, test.Value.([]string)) {
|
||||
t.Errorf("want %s value %#v, got %#v", test.Name, test.Value, got)
|
||||
return
|
||||
}
|
||||
if gottype != test.Type {
|
||||
t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func testGetValue(t *testing.T, k registry.Key, test ValueTest, size int) {
|
||||
if size <= 0 {
|
||||
return
|
||||
}
|
||||
// read data with no buffer
|
||||
gotsize, gottype, err := k.GetValue(test.Name, nil)
|
||||
if err != nil {
|
||||
t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err)
|
||||
return
|
||||
}
|
||||
if gotsize != size {
|
||||
t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize)
|
||||
return
|
||||
}
|
||||
if gottype != test.Type {
|
||||
t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
|
||||
return
|
||||
}
|
||||
// read data with short buffer
|
||||
gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size-1))
|
||||
if err == nil {
|
||||
t.Errorf("GetValue(%s, [%d]byte) should fail, but succeeded", test.Name, size-1)
|
||||
return
|
||||
}
|
||||
if err != registry.ErrShortBuffer {
|
||||
t.Errorf("reading %s value should return 'short buffer' error, but got: %s", test.Name, err)
|
||||
return
|
||||
}
|
||||
if gotsize != size {
|
||||
t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize)
|
||||
return
|
||||
}
|
||||
if gottype != test.Type {
|
||||
t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
|
||||
return
|
||||
}
|
||||
// read full data
|
||||
gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size))
|
||||
if err != nil {
|
||||
t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err)
|
||||
return
|
||||
}
|
||||
if gotsize != size {
|
||||
t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize)
|
||||
return
|
||||
}
|
||||
if gottype != test.Type {
|
||||
t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
|
||||
return
|
||||
}
|
||||
// check GetValue returns ErrNotExist as required
|
||||
_, _, err = k.GetValue(test.Name+"_not_there", make([]byte, size))
|
||||
if err == nil {
|
||||
t.Errorf("GetValue(%q) should not succeed", test.Name)
|
||||
return
|
||||
}
|
||||
if err != registry.ErrNotExist {
|
||||
t.Errorf("GetValue(%q) should return 'not exist' error, but got: %s", test.Name, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func testValues(t *testing.T, k registry.Key) {
|
||||
for _, test := range ValueTests {
|
||||
switch test.Type {
|
||||
case registry.SZ, registry.EXPAND_SZ:
|
||||
if test.WillFail {
|
||||
_, _, err := k.GetStringValue(test.Name)
|
||||
testErrNotExist(t, test.Name, err)
|
||||
} else {
|
||||
testGetStringValue(t, k, test)
|
||||
_, gottype, err := k.GetIntegerValue(test.Name)
|
||||
testErrUnexpectedType(t, test, gottype, err)
|
||||
// Size of utf16 string in bytes is not perfect,
|
||||
// but correct for current test values.
|
||||
// Size also includes terminating 0.
|
||||
testGetValue(t, k, test, (len(test.Value.(string))+1)*2)
|
||||
}
|
||||
_, _, err := k.GetStringValue(test.Name + "_string_not_created")
|
||||
testErrNotExist(t, test.Name+"_string_not_created", err)
|
||||
case registry.DWORD, registry.QWORD:
|
||||
testGetIntegerValue(t, k, test)
|
||||
_, gottype, err := k.GetBinaryValue(test.Name)
|
||||
testErrUnexpectedType(t, test, gottype, err)
|
||||
_, _, err = k.GetIntegerValue(test.Name + "_int_not_created")
|
||||
testErrNotExist(t, test.Name+"_int_not_created", err)
|
||||
size := 8
|
||||
if test.Type == registry.DWORD {
|
||||
size = 4
|
||||
}
|
||||
testGetValue(t, k, test, size)
|
||||
case registry.BINARY:
|
||||
testGetBinaryValue(t, k, test)
|
||||
_, gottype, err := k.GetStringsValue(test.Name)
|
||||
testErrUnexpectedType(t, test, gottype, err)
|
||||
_, _, err = k.GetBinaryValue(test.Name + "_byte_not_created")
|
||||
testErrNotExist(t, test.Name+"_byte_not_created", err)
|
||||
testGetValue(t, k, test, len(test.Value.([]byte)))
|
||||
case registry.MULTI_SZ:
|
||||
if test.WillFail {
|
||||
_, _, err := k.GetStringsValue(test.Name)
|
||||
testErrNotExist(t, test.Name, err)
|
||||
} else {
|
||||
testGetStringsValue(t, k, test)
|
||||
_, gottype, err := k.GetStringValue(test.Name)
|
||||
testErrUnexpectedType(t, test, gottype, err)
|
||||
size := 0
|
||||
for _, s := range test.Value.([]string) {
|
||||
size += len(s) + 1 // nil terminated
|
||||
}
|
||||
size += 1 // extra nil at the end
|
||||
size *= 2 // count bytes, not uint16
|
||||
testGetValue(t, k, test, size)
|
||||
}
|
||||
_, _, err := k.GetStringsValue(test.Name + "_strings_not_created")
|
||||
testErrNotExist(t, test.Name+"_strings_not_created", err)
|
||||
default:
|
||||
t.Errorf("unsupported type %d for %s value", test.Type, test.Name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testStat(t *testing.T, k registry.Key) {
|
||||
subk, _, err := registry.CreateKey(k, "subkey", registry.CREATE_SUB_KEY)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
defer subk.Close()
|
||||
|
||||
defer registry.DeleteKey(k, "subkey")
|
||||
|
||||
ki, err := k.Stat()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if ki.SubKeyCount != 1 {
|
||||
t.Error("key must have 1 subkey")
|
||||
}
|
||||
if ki.MaxSubKeyLen != 6 {
|
||||
t.Error("key max subkey name length must be 6")
|
||||
}
|
||||
if ki.ValueCount != 24 {
|
||||
t.Errorf("key must have 24 values, but is %d", ki.ValueCount)
|
||||
}
|
||||
if ki.MaxValueNameLen != 12 {
|
||||
t.Errorf("key max value name length must be 10, but is %d", ki.MaxValueNameLen)
|
||||
}
|
||||
if ki.MaxValueLen != 38 {
|
||||
t.Errorf("key max value length must be 38, but is %d", ki.MaxValueLen)
|
||||
}
|
||||
if mt, ct := ki.ModTime(), time.Now(); ct.Sub(mt) > 100*time.Millisecond {
|
||||
t.Errorf("key mod time is not close to current time: mtime=%v current=%v delta=%v", mt, ct, ct.Sub(mt))
|
||||
}
|
||||
}
|
||||
|
||||
func deleteValues(t *testing.T, k registry.Key) {
|
||||
for _, test := range ValueTests {
|
||||
if test.WillFail {
|
||||
continue
|
||||
}
|
||||
err := k.DeleteValue(test.Name)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
names, err := k.ReadValueNames(-1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if len(names) != 0 {
|
||||
t.Errorf("some values remain after deletion: %v", names)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValues(t *testing.T) {
|
||||
softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer softwareK.Close()
|
||||
|
||||
testKName := randKeyName("TestValues_")
|
||||
|
||||
k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer k.Close()
|
||||
|
||||
if exist {
|
||||
t.Fatalf("key %q already exists", testKName)
|
||||
}
|
||||
|
||||
defer registry.DeleteKey(softwareK, testKName)
|
||||
|
||||
setValues(t, k)
|
||||
|
||||
enumerateValues(t, k)
|
||||
|
||||
testValues(t, k)
|
||||
|
||||
testStat(t, k)
|
||||
|
||||
deleteValues(t, k)
|
||||
}
|
||||
|
||||
func walkKey(t *testing.T, k registry.Key, kname string) {
|
||||
names, err := k.ReadValueNames(-1)
|
||||
if err != nil {
|
||||
t.Fatalf("reading value names of %s failed: %v", kname, err)
|
||||
}
|
||||
for _, name := range names {
|
||||
_, valtype, err := k.GetValue(name, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("reading value type of %s of %s failed: %v", name, kname, err)
|
||||
}
|
||||
switch valtype {
|
||||
case registry.NONE:
|
||||
case registry.SZ:
|
||||
_, _, err := k.GetStringValue(name)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
case registry.EXPAND_SZ:
|
||||
s, _, err := k.GetStringValue(name)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = registry.ExpandString(s)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
case registry.DWORD, registry.QWORD:
|
||||
_, _, err := k.GetIntegerValue(name)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
case registry.BINARY:
|
||||
_, _, err := k.GetBinaryValue(name)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
case registry.MULTI_SZ:
|
||||
_, _, err := k.GetStringsValue(name)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
case registry.FULL_RESOURCE_DESCRIPTOR, registry.RESOURCE_LIST, registry.RESOURCE_REQUIREMENTS_LIST:
|
||||
// TODO: not implemented
|
||||
default:
|
||||
t.Fatalf("value type %d of %s of %s failed: %v", valtype, name, kname, err)
|
||||
}
|
||||
}
|
||||
|
||||
names, err = k.ReadSubKeyNames(-1)
|
||||
if err != nil {
|
||||
t.Fatalf("reading sub-keys of %s failed: %v", kname, err)
|
||||
}
|
||||
for _, name := range names {
|
||||
func() {
|
||||
subk, err := registry.OpenKey(k, name, registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE)
|
||||
if err != nil {
|
||||
if err == syscall.ERROR_ACCESS_DENIED {
|
||||
// ignore error, if we are not allowed to access this key
|
||||
return
|
||||
}
|
||||
t.Fatalf("opening sub-keys %s of %s failed: %v", name, kname, err)
|
||||
}
|
||||
defer subk.Close()
|
||||
|
||||
walkKey(t, subk, kname+`\`+name)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func TestWalkFullRegistry(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping long running test in short mode")
|
||||
}
|
||||
walkKey(t, registry.CLASSES_ROOT, "CLASSES_ROOT")
|
||||
walkKey(t, registry.CURRENT_USER, "CURRENT_USER")
|
||||
walkKey(t, registry.LOCAL_MACHINE, "LOCAL_MACHINE")
|
||||
walkKey(t, registry.USERS, "USERS")
|
||||
walkKey(t, registry.CURRENT_CONFIG, "CURRENT_CONFIG")
|
||||
}
|
||||
|
||||
func TestExpandString(t *testing.T) {
|
||||
got, err := registry.ExpandString("%PATH%")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := os.Getenv("PATH")
|
||||
if got != want {
|
||||
t.Errorf("want %q string expanded, got %q", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidValues(t *testing.T) {
|
||||
softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer softwareK.Close()
|
||||
|
||||
testKName := randKeyName("TestInvalidValues_")
|
||||
|
||||
k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer k.Close()
|
||||
|
||||
if exist {
|
||||
t.Fatalf("key %q already exists", testKName)
|
||||
}
|
||||
|
||||
defer registry.DeleteKey(softwareK, testKName)
|
||||
|
||||
var tests = []struct {
|
||||
Type uint32
|
||||
Name string
|
||||
Data []byte
|
||||
}{
|
||||
{registry.DWORD, "Dword1", nil},
|
||||
{registry.DWORD, "Dword2", []byte{1, 2, 3}},
|
||||
{registry.QWORD, "Qword1", nil},
|
||||
{registry.QWORD, "Qword2", []byte{1, 2, 3}},
|
||||
{registry.QWORD, "Qword3", []byte{1, 2, 3, 4, 5, 6, 7}},
|
||||
{registry.MULTI_SZ, "MultiString1", nil},
|
||||
{registry.MULTI_SZ, "MultiString2", []byte{0}},
|
||||
{registry.MULTI_SZ, "MultiString3", []byte{'a', 'b', 0}},
|
||||
{registry.MULTI_SZ, "MultiString4", []byte{'a', 0, 0, 'b', 0}},
|
||||
{registry.MULTI_SZ, "MultiString5", []byte{'a', 0, 0}},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
err := k.SetValue(test.Name, test.Type, test.Data)
|
||||
if err != nil {
|
||||
t.Fatalf("SetValue for %q failed: %v", test.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
switch test.Type {
|
||||
case registry.DWORD, registry.QWORD:
|
||||
value, valType, err := k.GetIntegerValue(test.Name)
|
||||
if err == nil {
|
||||
t.Errorf("GetIntegerValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value)
|
||||
}
|
||||
case registry.MULTI_SZ:
|
||||
value, valType, err := k.GetStringsValue(test.Name)
|
||||
if err == nil {
|
||||
if len(value) != 0 {
|
||||
t.Errorf("GetStringsValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value)
|
||||
}
|
||||
}
|
||||
default:
|
||||
t.Errorf("unsupported type %d for %s value", test.Type, test.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMUIStringValue(t *testing.T) {
|
||||
if err := registry.LoadRegLoadMUIString(); err != nil {
|
||||
t.Skip("regLoadMUIString not supported; skipping")
|
||||
}
|
||||
if err := procGetDynamicTimeZoneInformation.Find(); err != nil {
|
||||
t.Skipf("%s not supported; skipping", procGetDynamicTimeZoneInformation.Name)
|
||||
}
|
||||
var dtzi DynamicTimezoneinformation
|
||||
if _, err := GetDynamicTimeZoneInformation(&dtzi); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tzKeyName := syscall.UTF16ToString(dtzi.TimeZoneKeyName[:])
|
||||
timezoneK, err := registry.OpenKey(registry.LOCAL_MACHINE,
|
||||
`SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\`+tzKeyName, registry.READ)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer timezoneK.Close()
|
||||
|
||||
type testType struct {
|
||||
name string
|
||||
want string
|
||||
}
|
||||
var tests = []testType{
|
||||
{"MUI_Std", syscall.UTF16ToString(dtzi.StandardName[:])},
|
||||
}
|
||||
if dtzi.DynamicDaylightTimeDisabled == 0 {
|
||||
tests = append(tests, testType{"MUI_Dlt", syscall.UTF16ToString(dtzi.DaylightName[:])})
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
got, err := timezoneK.GetMUIStringValue(test.name)
|
||||
if err != nil {
|
||||
t.Error("GetMUIStringValue:", err)
|
||||
}
|
||||
|
||||
if got != test.want {
|
||||
t.Errorf("GetMUIStringValue: %s: Got %q, want %q", test.name, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type DynamicTimezoneinformation struct {
|
||||
Bias int32
|
||||
StandardName [32]uint16
|
||||
StandardDate syscall.Systemtime
|
||||
StandardBias int32
|
||||
DaylightName [32]uint16
|
||||
DaylightDate syscall.Systemtime
|
||||
DaylightBias int32
|
||||
TimeZoneKeyName [128]uint16
|
||||
DynamicDaylightTimeDisabled uint8
|
||||
}
|
||||
|
||||
var (
|
||||
kernel32DLL = syscall.NewLazyDLL("kernel32")
|
||||
|
||||
procGetDynamicTimeZoneInformation = kernel32DLL.NewProc("GetDynamicTimeZoneInformation")
|
||||
)
|
||||
|
||||
func GetDynamicTimeZoneInformation(dtzi *DynamicTimezoneinformation) (rc uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGetDynamicTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(dtzi)), 0, 0)
|
||||
rc = uint32(r0)
|
||||
if rc == 0xffffffff {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
32
vendor/golang.org/x/sys/windows/registry/syscall.go
generated
vendored
32
vendor/golang.org/x/sys/windows/registry/syscall.go
generated
vendored
@ -1,32 +0,0 @@
|
||||
// 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
384
vendor/golang.org/x/sys/windows/registry/value.go
generated
vendored
@ -1,384 +0,0 @@
|
||||
// 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
|
||||
}
|
120
vendor/golang.org/x/sys/windows/registry/zsyscall_windows.go
generated
vendored
120
vendor/golang.org/x/sys/windows/registry/zsyscall_windows.go
generated
vendored
@ -1,120 +0,0 @@
|
||||
// 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
56
vendor/golang.org/x/sys/windows/svc/debug/log.go
generated
vendored
@ -1,56 +0,0 @@
|
||||
// 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
45
vendor/golang.org/x/sys/windows/svc/debug/service.go
generated
vendored
@ -1,45 +0,0 @@
|
||||
// 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
|
||||
}
|
48
vendor/golang.org/x/sys/windows/svc/event.go
generated
vendored
48
vendor/golang.org/x/sys/windows/svc/event.go
generated
vendored
@ -1,48 +0,0 @@
|
||||
// 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 svc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// event represents auto-reset, initially non-signaled Windows event.
|
||||
// It is used to communicate between go and asm parts of this package.
|
||||
type event struct {
|
||||
h windows.Handle
|
||||
}
|
||||
|
||||
func newEvent() (*event, error) {
|
||||
h, err := windows.CreateEvent(nil, 0, 0, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &event{h: h}, nil
|
||||
}
|
||||
|
||||
func (e *event) Close() error {
|
||||
return windows.CloseHandle(e.h)
|
||||
}
|
||||
|
||||
func (e *event) Set() error {
|
||||
return windows.SetEvent(e.h)
|
||||
}
|
||||
|
||||
func (e *event) Wait() error {
|
||||
s, err := windows.WaitForSingleObject(e.h, windows.INFINITE)
|
||||
switch s {
|
||||
case windows.WAIT_OBJECT_0:
|
||||
break
|
||||
case windows.WAIT_FAILED:
|
||||
return err
|
||||
default:
|
||||
return errors.New("unexpected result from WaitForSingleObject")
|
||||
}
|
||||
return nil
|
||||
}
|
80
vendor/golang.org/x/sys/windows/svc/eventlog/install.go
generated
vendored
80
vendor/golang.org/x/sys/windows/svc/eventlog/install.go
generated
vendored
@ -1,80 +0,0 @@
|
||||
// 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
70
vendor/golang.org/x/sys/windows/svc/eventlog/log.go
generated
vendored
@ -1,70 +0,0 @@
|
||||
// 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)
|
||||
}
|
51
vendor/golang.org/x/sys/windows/svc/eventlog/log_test.go
generated
vendored
51
vendor/golang.org/x/sys/windows/svc/eventlog/log_test.go
generated
vendored
@ -1,51 +0,0 @@
|
||||
// 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_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"golang.org/x/sys/windows/svc/eventlog"
|
||||
)
|
||||
|
||||
func TestLog(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode - it modifies system logs")
|
||||
}
|
||||
|
||||
const name = "mylog"
|
||||
const supports = eventlog.Error | eventlog.Warning | eventlog.Info
|
||||
err := eventlog.InstallAsEventCreate(name, supports)
|
||||
if err != nil {
|
||||
t.Fatalf("Install failed: %s", err)
|
||||
}
|
||||
defer func() {
|
||||
err = eventlog.Remove(name)
|
||||
if err != nil {
|
||||
t.Fatalf("Remove failed: %s", err)
|
||||
}
|
||||
}()
|
||||
|
||||
l, err := eventlog.Open(name)
|
||||
if err != nil {
|
||||
t.Fatalf("Open failed: %s", err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
err = l.Info(1, "info")
|
||||
if err != nil {
|
||||
t.Fatalf("Info failed: %s", err)
|
||||
}
|
||||
err = l.Warning(2, "warning")
|
||||
if err != nil {
|
||||
t.Fatalf("Warning failed: %s", err)
|
||||
}
|
||||
err = l.Error(3, "error")
|
||||
if err != nil {
|
||||
t.Fatalf("Error failed: %s", err)
|
||||
}
|
||||
}
|
22
vendor/golang.org/x/sys/windows/svc/example/beep.go
generated
vendored
22
vendor/golang.org/x/sys/windows/svc/example/beep.go
generated
vendored
@ -1,22 +0,0 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// BUG(brainman): MessageBeep Windows api is broken on Windows 7,
|
||||
// so this example does not beep when runs as service on Windows 7.
|
||||
|
||||
var (
|
||||
beepFunc = syscall.MustLoadDLL("user32.dll").MustFindProc("MessageBeep")
|
||||
)
|
||||
|
||||
func beep() {
|
||||
beepFunc.Call(0xffffffff)
|
||||
}
|
92
vendor/golang.org/x/sys/windows/svc/example/install.go
generated
vendored
92
vendor/golang.org/x/sys/windows/svc/example/install.go
generated
vendored
@ -1,92 +0,0 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/sys/windows/svc/eventlog"
|
||||
"golang.org/x/sys/windows/svc/mgr"
|
||||
)
|
||||
|
||||
func exePath() (string, error) {
|
||||
prog := os.Args[0]
|
||||
p, err := filepath.Abs(prog)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fi, err := os.Stat(p)
|
||||
if err == nil {
|
||||
if !fi.Mode().IsDir() {
|
||||
return p, nil
|
||||
}
|
||||
err = fmt.Errorf("%s is directory", p)
|
||||
}
|
||||
if filepath.Ext(p) == "" {
|
||||
p += ".exe"
|
||||
fi, err := os.Stat(p)
|
||||
if err == nil {
|
||||
if !fi.Mode().IsDir() {
|
||||
return p, nil
|
||||
}
|
||||
err = fmt.Errorf("%s is directory", p)
|
||||
}
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
func installService(name, desc string) error {
|
||||
exepath, err := exePath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m, err := mgr.Connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer m.Disconnect()
|
||||
s, err := m.OpenService(name)
|
||||
if err == nil {
|
||||
s.Close()
|
||||
return fmt.Errorf("service %s already exists", name)
|
||||
}
|
||||
s, err = m.CreateService(name, exepath, mgr.Config{DisplayName: desc}, "is", "auto-started")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
err = eventlog.InstallAsEventCreate(name, eventlog.Error|eventlog.Warning|eventlog.Info)
|
||||
if err != nil {
|
||||
s.Delete()
|
||||
return fmt.Errorf("SetupEventLogSource() failed: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeService(name string) error {
|
||||
m, err := mgr.Connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer m.Disconnect()
|
||||
s, err := m.OpenService(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("service %s is not installed", name)
|
||||
}
|
||||
defer s.Close()
|
||||
err = s.Delete()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = eventlog.Remove(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("RemoveEventLogSource() failed: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
76
vendor/golang.org/x/sys/windows/svc/example/main.go
generated
vendored
76
vendor/golang.org/x/sys/windows/svc/example/main.go
generated
vendored
@ -1,76 +0,0 @@
|
||||
// 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
|
||||
|
||||
// Example service program that beeps.
|
||||
//
|
||||
// The program demonstrates how to create Windows service and
|
||||
// install / remove it on a computer. It also shows how to
|
||||
// stop / start / pause / continue any service, and how to
|
||||
// write to event log. It also shows how to use debug
|
||||
// facilities available in debug package.
|
||||
//
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/windows/svc"
|
||||
)
|
||||
|
||||
func usage(errmsg string) {
|
||||
fmt.Fprintf(os.Stderr,
|
||||
"%s\n\n"+
|
||||
"usage: %s <command>\n"+
|
||||
" where <command> is one of\n"+
|
||||
" install, remove, debug, start, stop, pause or continue.\n",
|
||||
errmsg, os.Args[0])
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
func main() {
|
||||
const svcName = "myservice"
|
||||
|
||||
isIntSess, err := svc.IsAnInteractiveSession()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to determine if we are running in an interactive session: %v", err)
|
||||
}
|
||||
if !isIntSess {
|
||||
runService(svcName, false)
|
||||
return
|
||||
}
|
||||
|
||||
if len(os.Args) < 2 {
|
||||
usage("no command specified")
|
||||
}
|
||||
|
||||
cmd := strings.ToLower(os.Args[1])
|
||||
switch cmd {
|
||||
case "debug":
|
||||
runService(svcName, true)
|
||||
return
|
||||
case "install":
|
||||
err = installService(svcName, "my service")
|
||||
case "remove":
|
||||
err = removeService(svcName)
|
||||
case "start":
|
||||
err = startService(svcName)
|
||||
case "stop":
|
||||
err = controlService(svcName, svc.Stop, svc.Stopped)
|
||||
case "pause":
|
||||
err = controlService(svcName, svc.Pause, svc.Paused)
|
||||
case "continue":
|
||||
err = controlService(svcName, svc.Continue, svc.Running)
|
||||
default:
|
||||
usage(fmt.Sprintf("invalid command %s", cmd))
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalf("failed to %s %s: %v", cmd, svcName, err)
|
||||
}
|
||||
return
|
||||
}
|
62
vendor/golang.org/x/sys/windows/svc/example/manage.go
generated
vendored
62
vendor/golang.org/x/sys/windows/svc/example/manage.go
generated
vendored
@ -1,62 +0,0 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/windows/svc"
|
||||
"golang.org/x/sys/windows/svc/mgr"
|
||||
)
|
||||
|
||||
func startService(name string) error {
|
||||
m, err := mgr.Connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer m.Disconnect()
|
||||
s, err := m.OpenService(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not access service: %v", err)
|
||||
}
|
||||
defer s.Close()
|
||||
err = s.Start("is", "manual-started")
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not start service: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func controlService(name string, c svc.Cmd, to svc.State) error {
|
||||
m, err := mgr.Connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer m.Disconnect()
|
||||
s, err := m.OpenService(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not access service: %v", err)
|
||||
}
|
||||
defer s.Close()
|
||||
status, err := s.Control(c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not send control=%d: %v", c, err)
|
||||
}
|
||||
timeout := time.Now().Add(10 * time.Second)
|
||||
for status.State != to {
|
||||
if timeout.Before(time.Now()) {
|
||||
return fmt.Errorf("timeout waiting for service to go to state=%d", to)
|
||||
}
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
status, err = s.Query()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not retrieve service status: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
84
vendor/golang.org/x/sys/windows/svc/example/service.go
generated
vendored
84
vendor/golang.org/x/sys/windows/svc/example/service.go
generated
vendored
@ -1,84 +0,0 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/windows/svc"
|
||||
"golang.org/x/sys/windows/svc/debug"
|
||||
"golang.org/x/sys/windows/svc/eventlog"
|
||||
)
|
||||
|
||||
var elog debug.Log
|
||||
|
||||
type myservice struct{}
|
||||
|
||||
func (m *myservice) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) {
|
||||
const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue
|
||||
changes <- svc.Status{State: svc.StartPending}
|
||||
fasttick := time.Tick(500 * time.Millisecond)
|
||||
slowtick := time.Tick(2 * time.Second)
|
||||
tick := fasttick
|
||||
changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
|
||||
elog.Info(1, strings.Join(args, "-"))
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case <-tick:
|
||||
beep()
|
||||
elog.Info(1, "beep")
|
||||
case c := <-r:
|
||||
switch c.Cmd {
|
||||
case svc.Interrogate:
|
||||
changes <- c.CurrentStatus
|
||||
// Testing deadlock from https://code.google.com/p/winsvc/issues/detail?id=4
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
changes <- c.CurrentStatus
|
||||
case svc.Stop, svc.Shutdown:
|
||||
break loop
|
||||
case svc.Pause:
|
||||
changes <- svc.Status{State: svc.Paused, Accepts: cmdsAccepted}
|
||||
tick = slowtick
|
||||
case svc.Continue:
|
||||
changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
|
||||
tick = fasttick
|
||||
default:
|
||||
elog.Error(1, fmt.Sprintf("unexpected control request #%d", c))
|
||||
}
|
||||
}
|
||||
}
|
||||
changes <- svc.Status{State: svc.StopPending}
|
||||
return
|
||||
}
|
||||
|
||||
func runService(name string, isDebug bool) {
|
||||
var err error
|
||||
if isDebug {
|
||||
elog = debug.New(name)
|
||||
} else {
|
||||
elog, err = eventlog.Open(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
defer elog.Close()
|
||||
|
||||
elog.Info(1, fmt.Sprintf("starting %s service", name))
|
||||
run := svc.Run
|
||||
if isDebug {
|
||||
run = debug.Run
|
||||
}
|
||||
err = run(name, &myservice{})
|
||||
if err != nil {
|
||||
elog.Error(1, fmt.Sprintf("%s service failed: %v", name, err))
|
||||
return
|
||||
}
|
||||
elog.Info(1, fmt.Sprintf("%s service stopped", name))
|
||||
}
|
24
vendor/golang.org/x/sys/windows/svc/go12.c
generated
vendored
24
vendor/golang.org/x/sys/windows/svc/go12.c
generated
vendored
@ -1,24 +0,0 @@
|
||||
// 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
|
||||
// +build !go1.3
|
||||
|
||||
// copied from pkg/runtime
|
||||
typedef unsigned int uint32;
|
||||
typedef unsigned long long int uint64;
|
||||
#ifdef _64BIT
|
||||
typedef uint64 uintptr;
|
||||
#else
|
||||
typedef uint32 uintptr;
|
||||
#endif
|
||||
|
||||
// from sys_386.s or sys_amd64.s
|
||||
void ·servicemain(void);
|
||||
|
||||
void
|
||||
·getServiceMain(uintptr *r)
|
||||
{
|
||||
*r = (uintptr)·servicemain;
|
||||
}
|
11
vendor/golang.org/x/sys/windows/svc/go12.go
generated
vendored
11
vendor/golang.org/x/sys/windows/svc/go12.go
generated
vendored
@ -1,11 +0,0 @@
|
||||
// Copyright 2014 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
|
||||
// +build !go1.3
|
||||
|
||||
package svc
|
||||
|
||||
// from go12.c
|
||||
func getServiceMain(r *uintptr)
|
31
vendor/golang.org/x/sys/windows/svc/go13.go
generated
vendored
31
vendor/golang.org/x/sys/windows/svc/go13.go
generated
vendored
@ -1,31 +0,0 @@
|
||||
// Copyright 2014 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
|
||||
// +build go1.3
|
||||
|
||||
package svc
|
||||
|
||||
import "unsafe"
|
||||
|
||||
const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
|
||||
|
||||
// Should be a built-in for unsafe.Pointer?
|
||||
func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
|
||||
return unsafe.Pointer(uintptr(p) + x)
|
||||
}
|
||||
|
||||
// funcPC returns the entry PC of the function f.
|
||||
// It assumes that f is a func value. Otherwise the behavior is undefined.
|
||||
func funcPC(f interface{}) uintptr {
|
||||
return **(**uintptr)(add(unsafe.Pointer(&f), ptrSize))
|
||||
}
|
||||
|
||||
// from sys_386.s and sys_amd64.s
|
||||
func servicectlhandler(ctl uint32) uintptr
|
||||
func servicemain(argc uint32, argv **uint16)
|
||||
|
||||
func getServiceMain(r *uintptr) {
|
||||
*r = funcPC(servicemain)
|
||||
}
|
145
vendor/golang.org/x/sys/windows/svc/mgr/config.go
generated
vendored
145
vendor/golang.org/x/sys/windows/svc/mgr/config.go
generated
vendored
@ -1,145 +0,0 @@
|
||||
// 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
162
vendor/golang.org/x/sys/windows/svc/mgr/mgr.go
generated
vendored
@ -1,162 +0,0 @@
|
||||
// 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
|
||||
}
|
282
vendor/golang.org/x/sys/windows/svc/mgr/mgr_test.go
generated
vendored
282
vendor/golang.org/x/sys/windows/svc/mgr/mgr_test.go
generated
vendored
@ -1,282 +0,0 @@
|
||||
// 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_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/windows/svc/mgr"
|
||||
)
|
||||
|
||||
func TestOpenLanManServer(t *testing.T) {
|
||||
m, err := mgr.Connect()
|
||||
if err != nil {
|
||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERROR_ACCESS_DENIED {
|
||||
t.Skip("Skipping test: we don't have rights to manage services.")
|
||||
}
|
||||
t.Fatalf("SCM connection failed: %s", err)
|
||||
}
|
||||
defer m.Disconnect()
|
||||
|
||||
s, err := m.OpenService("LanmanServer")
|
||||
if err != nil {
|
||||
t.Fatalf("OpenService(lanmanserver) failed: %s", err)
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
_, err = s.Config()
|
||||
if err != nil {
|
||||
t.Fatalf("Config failed: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func install(t *testing.T, m *mgr.Mgr, name, exepath string, c mgr.Config) {
|
||||
// Sometimes it takes a while for the service to get
|
||||
// removed after previous test run.
|
||||
for i := 0; ; i++ {
|
||||
s, err := m.OpenService(name)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
s.Close()
|
||||
|
||||
if i > 10 {
|
||||
t.Fatalf("service %s already exists", name)
|
||||
}
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
}
|
||||
|
||||
s, err := m.CreateService(name, exepath, c)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateService(%s) failed: %v", name, err)
|
||||
}
|
||||
defer s.Close()
|
||||
}
|
||||
|
||||
func depString(d []string) string {
|
||||
if len(d) == 0 {
|
||||
return ""
|
||||
}
|
||||
for i := range d {
|
||||
d[i] = strings.ToLower(d[i])
|
||||
}
|
||||
ss := sort.StringSlice(d)
|
||||
ss.Sort()
|
||||
return strings.Join([]string(ss), " ")
|
||||
}
|
||||
|
||||
func testConfig(t *testing.T, s *mgr.Service, should mgr.Config) mgr.Config {
|
||||
is, err := s.Config()
|
||||
if err != nil {
|
||||
t.Fatalf("Config failed: %s", err)
|
||||
}
|
||||
if should.DisplayName != is.DisplayName {
|
||||
t.Fatalf("config mismatch: DisplayName is %q, but should have %q", is.DisplayName, should.DisplayName)
|
||||
}
|
||||
if should.StartType != is.StartType {
|
||||
t.Fatalf("config mismatch: StartType is %v, but should have %v", is.StartType, should.StartType)
|
||||
}
|
||||
if should.Description != is.Description {
|
||||
t.Fatalf("config mismatch: Description is %q, but should have %q", is.Description, should.Description)
|
||||
}
|
||||
if depString(should.Dependencies) != depString(is.Dependencies) {
|
||||
t.Fatalf("config mismatch: Dependencies is %v, but should have %v", is.Dependencies, should.Dependencies)
|
||||
}
|
||||
return is
|
||||
}
|
||||
|
||||
func testRecoveryActions(t *testing.T, s *mgr.Service, should []mgr.RecoveryAction) {
|
||||
is, err := s.RecoveryActions()
|
||||
if err != nil {
|
||||
t.Fatalf("RecoveryActions failed: %s", err)
|
||||
}
|
||||
if len(should) != len(is) {
|
||||
t.Errorf("recovery action mismatch: contains %v actions, but should have %v", len(is), len(should))
|
||||
}
|
||||
for i, _ := range is {
|
||||
if should[i].Type != is[i].Type {
|
||||
t.Errorf("recovery action mismatch: Type is %v, but should have %v", is[i].Type, should[i].Type)
|
||||
}
|
||||
if should[i].Delay != is[i].Delay {
|
||||
t.Errorf("recovery action mismatch: Delay is %v, but should have %v", is[i].Delay, should[i].Delay)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testResetPeriod(t *testing.T, s *mgr.Service, should uint32) {
|
||||
is, err := s.ResetPeriod()
|
||||
if err != nil {
|
||||
t.Fatalf("ResetPeriod failed: %s", err)
|
||||
}
|
||||
if should != is {
|
||||
t.Errorf("reset period mismatch: reset period is %v, but should have %v", is, should)
|
||||
}
|
||||
}
|
||||
|
||||
func testSetRecoveryActions(t *testing.T, s *mgr.Service) {
|
||||
r := []mgr.RecoveryAction{
|
||||
mgr.RecoveryAction{
|
||||
Type: mgr.NoAction,
|
||||
Delay: 60000 * time.Millisecond,
|
||||
},
|
||||
mgr.RecoveryAction{
|
||||
Type: mgr.ServiceRestart,
|
||||
Delay: 4 * time.Minute,
|
||||
},
|
||||
mgr.RecoveryAction{
|
||||
Type: mgr.ServiceRestart,
|
||||
Delay: time.Minute,
|
||||
},
|
||||
mgr.RecoveryAction{
|
||||
Type: mgr.RunCommand,
|
||||
Delay: 4000 * time.Millisecond,
|
||||
},
|
||||
}
|
||||
|
||||
// 4 recovery actions with reset period
|
||||
err := s.SetRecoveryActions(r, uint32(10000))
|
||||
if err != nil {
|
||||
t.Fatalf("SetRecoveryActions failed: %v", err)
|
||||
}
|
||||
testRecoveryActions(t, s, r)
|
||||
testResetPeriod(t, s, uint32(10000))
|
||||
|
||||
// Infinite reset period
|
||||
err = s.SetRecoveryActions(r, syscall.INFINITE)
|
||||
if err != nil {
|
||||
t.Fatalf("SetRecoveryActions failed: %v", err)
|
||||
}
|
||||
testRecoveryActions(t, s, r)
|
||||
testResetPeriod(t, s, syscall.INFINITE)
|
||||
|
||||
// nil recovery actions
|
||||
err = s.SetRecoveryActions(nil, 0)
|
||||
if err.Error() != "recoveryActions cannot be nil" {
|
||||
t.Fatalf("SetRecoveryActions failed with unexpected error message of %q", err)
|
||||
}
|
||||
|
||||
// Delete all recovery actions and reset period
|
||||
err = s.ResetRecoveryActions()
|
||||
if err != nil {
|
||||
t.Fatalf("ResetRecoveryActions failed: %v", err)
|
||||
}
|
||||
testRecoveryActions(t, s, nil)
|
||||
testResetPeriod(t, s, 0)
|
||||
}
|
||||
|
||||
func testRebootMessage(t *testing.T, s *mgr.Service, should string) {
|
||||
err := s.SetRebootMessage(should)
|
||||
if err != nil {
|
||||
t.Fatalf("SetRebootMessage failed: %v", err)
|
||||
}
|
||||
is, err := s.RebootMessage()
|
||||
if err != nil {
|
||||
t.Fatalf("RebootMessage failed: %v", err)
|
||||
}
|
||||
if should != is {
|
||||
t.Errorf("reboot message mismatch: message is %q, but should have %q", is, should)
|
||||
}
|
||||
}
|
||||
|
||||
func testRecoveryCommand(t *testing.T, s *mgr.Service, should string) {
|
||||
err := s.SetRecoveryCommand(should)
|
||||
if err != nil {
|
||||
t.Fatalf("SetRecoveryCommand failed: %v", err)
|
||||
}
|
||||
is, err := s.RecoveryCommand()
|
||||
if err != nil {
|
||||
t.Fatalf("RecoveryCommand failed: %v", err)
|
||||
}
|
||||
if should != is {
|
||||
t.Errorf("recovery command mismatch: command is %q, but should have %q", is, should)
|
||||
}
|
||||
}
|
||||
|
||||
func remove(t *testing.T, s *mgr.Service) {
|
||||
err := s.Delete()
|
||||
if err != nil {
|
||||
t.Fatalf("Delete failed: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMyService(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode - it modifies system services")
|
||||
}
|
||||
|
||||
const name = "myservice"
|
||||
|
||||
m, err := mgr.Connect()
|
||||
if err != nil {
|
||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERROR_ACCESS_DENIED {
|
||||
t.Skip("Skipping test: we don't have rights to manage services.")
|
||||
}
|
||||
t.Fatalf("SCM connection failed: %s", err)
|
||||
}
|
||||
defer m.Disconnect()
|
||||
|
||||
c := mgr.Config{
|
||||
StartType: mgr.StartDisabled,
|
||||
DisplayName: "my service",
|
||||
Description: "my service is just a test",
|
||||
Dependencies: []string{"LanmanServer", "W32Time"},
|
||||
}
|
||||
|
||||
exename := os.Args[0]
|
||||
exepath, err := filepath.Abs(exename)
|
||||
if err != nil {
|
||||
t.Fatalf("filepath.Abs(%s) failed: %s", exename, err)
|
||||
}
|
||||
|
||||
install(t, m, name, exepath, c)
|
||||
|
||||
s, err := m.OpenService(name)
|
||||
if err != nil {
|
||||
t.Fatalf("service %s is not installed", name)
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
c.BinaryPathName = exepath
|
||||
c = testConfig(t, s, c)
|
||||
|
||||
c.StartType = mgr.StartManual
|
||||
err = s.UpdateConfig(c)
|
||||
if err != nil {
|
||||
t.Fatalf("UpdateConfig failed: %v", err)
|
||||
}
|
||||
|
||||
testConfig(t, s, c)
|
||||
|
||||
svcnames, err := m.ListServices()
|
||||
if err != nil {
|
||||
t.Fatalf("ListServices failed: %v", err)
|
||||
}
|
||||
var myserviceIsInstalled bool
|
||||
for _, sn := range svcnames {
|
||||
if sn == name {
|
||||
myserviceIsInstalled = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !myserviceIsInstalled {
|
||||
t.Errorf("ListServices failed to find %q service", name)
|
||||
}
|
||||
|
||||
testSetRecoveryActions(t, s)
|
||||
testRebootMessage(t, s, "myservice failed")
|
||||
testRebootMessage(t, s, "") // delete reboot message
|
||||
testRecoveryCommand(t, s, "sc query myservice")
|
||||
testRecoveryCommand(t, s, "") // delete recovery command
|
||||
|
||||
remove(t, s)
|
||||
}
|
135
vendor/golang.org/x/sys/windows/svc/mgr/recovery.go
generated
vendored
135
vendor/golang.org/x/sys/windows/svc/mgr/recovery.go
generated
vendored
@ -1,135 +0,0 @@
|
||||
// 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"
|
||||
"syscall"
|
||||
"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
|
||||
}
|
||||
|
||||
// SetRebootMessage sets service s reboot message.
|
||||
// If msg is "", the reboot message is deleted and no message is broadcast.
|
||||
func (s *Service) SetRebootMessage(msg string) error {
|
||||
rActions := windows.SERVICE_FAILURE_ACTIONS{
|
||||
RebootMsg: syscall.StringToUTF16Ptr(msg),
|
||||
}
|
||||
return windows.ChangeServiceConfig2(s.Handle, windows.SERVICE_CONFIG_FAILURE_ACTIONS, (*byte)(unsafe.Pointer(&rActions)))
|
||||
}
|
||||
|
||||
// RebootMessage is broadcast to server users before rebooting in response to the ComputerReboot service controller action.
|
||||
func (s *Service) RebootMessage() (string, error) {
|
||||
b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_FAILURE_ACTIONS)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
|
||||
return toString(p.RebootMsg), nil
|
||||
}
|
||||
|
||||
// SetRecoveryCommand sets the command line of the process to execute in response to the RunCommand service controller action.
|
||||
// If cmd is "", the command is deleted and no program is run when the service fails.
|
||||
func (s *Service) SetRecoveryCommand(cmd string) error {
|
||||
rActions := windows.SERVICE_FAILURE_ACTIONS{
|
||||
Command: syscall.StringToUTF16Ptr(cmd),
|
||||
}
|
||||
return windows.ChangeServiceConfig2(s.Handle, windows.SERVICE_CONFIG_FAILURE_ACTIONS, (*byte)(unsafe.Pointer(&rActions)))
|
||||
}
|
||||
|
||||
// RecoveryCommand is the command line of the process to execute in response to the RunCommand service controller action. This process runs under the same account as the service.
|
||||
func (s *Service) RecoveryCommand() (string, error) {
|
||||
b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_FAILURE_ACTIONS)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
|
||||
return toString(p.Command), nil
|
||||
}
|
72
vendor/golang.org/x/sys/windows/svc/mgr/service.go
generated
vendored
72
vendor/golang.org/x/sys/windows/svc/mgr/service.go
generated
vendored
@ -1,72 +0,0 @@
|
||||
// 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
|
||||
}
|
62
vendor/golang.org/x/sys/windows/svc/security.go
generated
vendored
62
vendor/golang.org/x/sys/windows/svc/security.go
generated
vendored
@ -1,62 +0,0 @@
|
||||
// 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 svc
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func allocSid(subAuth0 uint32) (*windows.SID, error) {
|
||||
var sid *windows.SID
|
||||
err := windows.AllocateAndInitializeSid(&windows.SECURITY_NT_AUTHORITY,
|
||||
1, subAuth0, 0, 0, 0, 0, 0, 0, 0, &sid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sid, nil
|
||||
}
|
||||
|
||||
// IsAnInteractiveSession determines if calling process is running interactively.
|
||||
// It queries the process token for membership in the Interactive group.
|
||||
// http://stackoverflow.com/questions/2668851/how-do-i-detect-that-my-application-is-running-as-service-or-in-an-interactive-s
|
||||
func IsAnInteractiveSession() (bool, error) {
|
||||
interSid, err := allocSid(windows.SECURITY_INTERACTIVE_RID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer windows.FreeSid(interSid)
|
||||
|
||||
serviceSid, err := allocSid(windows.SECURITY_SERVICE_RID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer windows.FreeSid(serviceSid)
|
||||
|
||||
t, err := windows.OpenCurrentProcessToken()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer t.Close()
|
||||
|
||||
gs, err := t.GetTokenGroups()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
p := unsafe.Pointer(&gs.Groups[0])
|
||||
groups := (*[2 << 20]windows.SIDAndAttributes)(p)[:gs.GroupCount]
|
||||
for _, g := range groups {
|
||||
if windows.EqualSid(g.Sid, interSid) {
|
||||
return true, nil
|
||||
}
|
||||
if windows.EqualSid(g.Sid, serviceSid) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
363
vendor/golang.org/x/sys/windows/svc/service.go
generated
vendored
363
vendor/golang.org/x/sys/windows/svc/service.go
generated
vendored
@ -1,363 +0,0 @@
|
||||
// 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 svc provides everything required to build Windows service.
|
||||
//
|
||||
package svc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// State describes service execution state (Stopped, Running and so on).
|
||||
type State uint32
|
||||
|
||||
const (
|
||||
Stopped = State(windows.SERVICE_STOPPED)
|
||||
StartPending = State(windows.SERVICE_START_PENDING)
|
||||
StopPending = State(windows.SERVICE_STOP_PENDING)
|
||||
Running = State(windows.SERVICE_RUNNING)
|
||||
ContinuePending = State(windows.SERVICE_CONTINUE_PENDING)
|
||||
PausePending = State(windows.SERVICE_PAUSE_PENDING)
|
||||
Paused = State(windows.SERVICE_PAUSED)
|
||||
)
|
||||
|
||||
// Cmd represents service state change request. It is sent to a service
|
||||
// by the service manager, and should be actioned upon by the service.
|
||||
type Cmd uint32
|
||||
|
||||
const (
|
||||
Stop = Cmd(windows.SERVICE_CONTROL_STOP)
|
||||
Pause = Cmd(windows.SERVICE_CONTROL_PAUSE)
|
||||
Continue = Cmd(windows.SERVICE_CONTROL_CONTINUE)
|
||||
Interrogate = Cmd(windows.SERVICE_CONTROL_INTERROGATE)
|
||||
Shutdown = Cmd(windows.SERVICE_CONTROL_SHUTDOWN)
|
||||
ParamChange = Cmd(windows.SERVICE_CONTROL_PARAMCHANGE)
|
||||
NetBindAdd = Cmd(windows.SERVICE_CONTROL_NETBINDADD)
|
||||
NetBindRemove = Cmd(windows.SERVICE_CONTROL_NETBINDREMOVE)
|
||||
NetBindEnable = Cmd(windows.SERVICE_CONTROL_NETBINDENABLE)
|
||||
NetBindDisable = Cmd(windows.SERVICE_CONTROL_NETBINDDISABLE)
|
||||
DeviceEvent = Cmd(windows.SERVICE_CONTROL_DEVICEEVENT)
|
||||
HardwareProfileChange = Cmd(windows.SERVICE_CONTROL_HARDWAREPROFILECHANGE)
|
||||
PowerEvent = Cmd(windows.SERVICE_CONTROL_POWEREVENT)
|
||||
SessionChange = Cmd(windows.SERVICE_CONTROL_SESSIONCHANGE)
|
||||
)
|
||||
|
||||
// Accepted is used to describe commands accepted by the service.
|
||||
// Note that Interrogate is always accepted.
|
||||
type Accepted uint32
|
||||
|
||||
const (
|
||||
AcceptStop = Accepted(windows.SERVICE_ACCEPT_STOP)
|
||||
AcceptShutdown = Accepted(windows.SERVICE_ACCEPT_SHUTDOWN)
|
||||
AcceptPauseAndContinue = Accepted(windows.SERVICE_ACCEPT_PAUSE_CONTINUE)
|
||||
AcceptParamChange = Accepted(windows.SERVICE_ACCEPT_PARAMCHANGE)
|
||||
AcceptNetBindChange = Accepted(windows.SERVICE_ACCEPT_NETBINDCHANGE)
|
||||
AcceptHardwareProfileChange = Accepted(windows.SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
|
||||
AcceptPowerEvent = Accepted(windows.SERVICE_ACCEPT_POWEREVENT)
|
||||
AcceptSessionChange = Accepted(windows.SERVICE_ACCEPT_SESSIONCHANGE)
|
||||
)
|
||||
|
||||
// Status combines State and Accepted commands to fully describe running service.
|
||||
type Status struct {
|
||||
State State
|
||||
Accepts Accepted
|
||||
CheckPoint uint32 // used to report progress during a lengthy operation
|
||||
WaitHint uint32 // estimated time required for a pending operation, in milliseconds
|
||||
}
|
||||
|
||||
// ChangeRequest is sent to the service Handler to request service status change.
|
||||
type ChangeRequest struct {
|
||||
Cmd Cmd
|
||||
EventType uint32
|
||||
EventData uintptr
|
||||
CurrentStatus Status
|
||||
}
|
||||
|
||||
// Handler is the interface that must be implemented to build Windows service.
|
||||
type Handler interface {
|
||||
|
||||
// Execute will be called by the package code at the start of
|
||||
// the service, and the service will exit once Execute completes.
|
||||
// Inside Execute you must read service change requests from r and
|
||||
// act accordingly. You must keep service control manager up to date
|
||||
// about state of your service by writing into s as required.
|
||||
// args contains service name followed by argument strings passed
|
||||
// to the service.
|
||||
// You can provide service exit code in exitCode return parameter,
|
||||
// with 0 being "no error". You can also indicate if exit code,
|
||||
// if any, is service specific or not by using svcSpecificEC
|
||||
// parameter.
|
||||
Execute(args []string, r <-chan ChangeRequest, s chan<- Status) (svcSpecificEC bool, exitCode uint32)
|
||||
}
|
||||
|
||||
var (
|
||||
// These are used by asm code.
|
||||
goWaitsH uintptr
|
||||
cWaitsH uintptr
|
||||
ssHandle uintptr
|
||||
sName *uint16
|
||||
sArgc uintptr
|
||||
sArgv **uint16
|
||||
ctlHandlerExProc uintptr
|
||||
cSetEvent uintptr
|
||||
cWaitForSingleObject uintptr
|
||||
cRegisterServiceCtrlHandlerExW uintptr
|
||||
)
|
||||
|
||||
func init() {
|
||||
k := syscall.MustLoadDLL("kernel32.dll")
|
||||
cSetEvent = k.MustFindProc("SetEvent").Addr()
|
||||
cWaitForSingleObject = k.MustFindProc("WaitForSingleObject").Addr()
|
||||
a := syscall.MustLoadDLL("advapi32.dll")
|
||||
cRegisterServiceCtrlHandlerExW = a.MustFindProc("RegisterServiceCtrlHandlerExW").Addr()
|
||||
}
|
||||
|
||||
// The HandlerEx prototype also has a context pointer but since we don't use
|
||||
// it at start-up time we don't have to pass it over either.
|
||||
type ctlEvent struct {
|
||||
cmd Cmd
|
||||
eventType uint32
|
||||
eventData uintptr
|
||||
errno uint32
|
||||
}
|
||||
|
||||
// service provides access to windows service api.
|
||||
type service struct {
|
||||
name string
|
||||
h windows.Handle
|
||||
cWaits *event
|
||||
goWaits *event
|
||||
c chan ctlEvent
|
||||
handler Handler
|
||||
}
|
||||
|
||||
func newService(name string, handler Handler) (*service, error) {
|
||||
var s service
|
||||
var err error
|
||||
s.name = name
|
||||
s.c = make(chan ctlEvent)
|
||||
s.handler = handler
|
||||
s.cWaits, err = newEvent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.goWaits, err = newEvent()
|
||||
if err != nil {
|
||||
s.cWaits.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
func (s *service) close() error {
|
||||
s.cWaits.Close()
|
||||
s.goWaits.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
type exitCode struct {
|
||||
isSvcSpecific bool
|
||||
errno uint32
|
||||
}
|
||||
|
||||
func (s *service) updateStatus(status *Status, ec *exitCode) error {
|
||||
if s.h == 0 {
|
||||
return errors.New("updateStatus with no service status handle")
|
||||
}
|
||||
var t windows.SERVICE_STATUS
|
||||
t.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS
|
||||
t.CurrentState = uint32(status.State)
|
||||
if status.Accepts&AcceptStop != 0 {
|
||||
t.ControlsAccepted |= windows.SERVICE_ACCEPT_STOP
|
||||
}
|
||||
if status.Accepts&AcceptShutdown != 0 {
|
||||
t.ControlsAccepted |= windows.SERVICE_ACCEPT_SHUTDOWN
|
||||
}
|
||||
if status.Accepts&AcceptPauseAndContinue != 0 {
|
||||
t.ControlsAccepted |= windows.SERVICE_ACCEPT_PAUSE_CONTINUE
|
||||
}
|
||||
if status.Accepts&AcceptParamChange != 0 {
|
||||
t.ControlsAccepted |= windows.SERVICE_ACCEPT_PARAMCHANGE
|
||||
}
|
||||
if status.Accepts&AcceptNetBindChange != 0 {
|
||||
t.ControlsAccepted |= windows.SERVICE_ACCEPT_NETBINDCHANGE
|
||||
}
|
||||
if status.Accepts&AcceptHardwareProfileChange != 0 {
|
||||
t.ControlsAccepted |= windows.SERVICE_ACCEPT_HARDWAREPROFILECHANGE
|
||||
}
|
||||
if status.Accepts&AcceptPowerEvent != 0 {
|
||||
t.ControlsAccepted |= windows.SERVICE_ACCEPT_POWEREVENT
|
||||
}
|
||||
if status.Accepts&AcceptSessionChange != 0 {
|
||||
t.ControlsAccepted |= windows.SERVICE_ACCEPT_SESSIONCHANGE
|
||||
}
|
||||
if ec.errno == 0 {
|
||||
t.Win32ExitCode = windows.NO_ERROR
|
||||
t.ServiceSpecificExitCode = windows.NO_ERROR
|
||||
} else if ec.isSvcSpecific {
|
||||
t.Win32ExitCode = uint32(windows.ERROR_SERVICE_SPECIFIC_ERROR)
|
||||
t.ServiceSpecificExitCode = ec.errno
|
||||
} else {
|
||||
t.Win32ExitCode = ec.errno
|
||||
t.ServiceSpecificExitCode = windows.NO_ERROR
|
||||
}
|
||||
t.CheckPoint = status.CheckPoint
|
||||
t.WaitHint = status.WaitHint
|
||||
return windows.SetServiceStatus(s.h, &t)
|
||||
}
|
||||
|
||||
const (
|
||||
sysErrSetServiceStatusFailed = uint32(syscall.APPLICATION_ERROR) + iota
|
||||
sysErrNewThreadInCallback
|
||||
)
|
||||
|
||||
func (s *service) run() {
|
||||
s.goWaits.Wait()
|
||||
s.h = windows.Handle(ssHandle)
|
||||
argv := (*[100]*int16)(unsafe.Pointer(sArgv))[:sArgc]
|
||||
args := make([]string, len(argv))
|
||||
for i, a := range argv {
|
||||
args[i] = syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(a))[:])
|
||||
}
|
||||
|
||||
cmdsToHandler := make(chan ChangeRequest)
|
||||
changesFromHandler := make(chan Status)
|
||||
exitFromHandler := make(chan exitCode)
|
||||
|
||||
go func() {
|
||||
ss, errno := s.handler.Execute(args, cmdsToHandler, changesFromHandler)
|
||||
exitFromHandler <- exitCode{ss, errno}
|
||||
}()
|
||||
|
||||
status := Status{State: Stopped}
|
||||
ec := exitCode{isSvcSpecific: true, errno: 0}
|
||||
var outch chan ChangeRequest
|
||||
inch := s.c
|
||||
var cmd Cmd
|
||||
var evtype uint32
|
||||
var evdata uintptr
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case r := <-inch:
|
||||
if r.errno != 0 {
|
||||
ec.errno = r.errno
|
||||
break loop
|
||||
}
|
||||
inch = nil
|
||||
outch = cmdsToHandler
|
||||
cmd = r.cmd
|
||||
evtype = r.eventType
|
||||
evdata = r.eventData
|
||||
case outch <- ChangeRequest{cmd, evtype, evdata, status}:
|
||||
inch = s.c
|
||||
outch = nil
|
||||
case c := <-changesFromHandler:
|
||||
err := s.updateStatus(&c, &ec)
|
||||
if err != nil {
|
||||
// best suitable error number
|
||||
ec.errno = sysErrSetServiceStatusFailed
|
||||
if err2, ok := err.(syscall.Errno); ok {
|
||||
ec.errno = uint32(err2)
|
||||
}
|
||||
break loop
|
||||
}
|
||||
status = c
|
||||
case ec = <-exitFromHandler:
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
s.updateStatus(&Status{State: Stopped}, &ec)
|
||||
s.cWaits.Set()
|
||||
}
|
||||
|
||||
func newCallback(fn interface{}) (cb uintptr, err error) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
cb = 0
|
||||
switch v := r.(type) {
|
||||
case string:
|
||||
err = errors.New(v)
|
||||
case error:
|
||||
err = v
|
||||
default:
|
||||
err = errors.New("unexpected panic in syscall.NewCallback")
|
||||
}
|
||||
}()
|
||||
return syscall.NewCallback(fn), nil
|
||||
}
|
||||
|
||||
// BUG(brainman): There is no mechanism to run multiple services
|
||||
// inside one single executable. Perhaps, it can be overcome by
|
||||
// using RegisterServiceCtrlHandlerEx Windows api.
|
||||
|
||||
// Run executes service name by calling appropriate handler function.
|
||||
func Run(name string, handler Handler) error {
|
||||
runtime.LockOSThread()
|
||||
|
||||
tid := windows.GetCurrentThreadId()
|
||||
|
||||
s, err := newService(name, handler)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctlHandler := func(ctl uint32, evtype uint32, evdata uintptr, context uintptr) uintptr {
|
||||
e := ctlEvent{cmd: Cmd(ctl), eventType: evtype, eventData: evdata}
|
||||
// We assume that this callback function is running on
|
||||
// the same thread as Run. Nowhere in MS documentation
|
||||
// I could find statement to guarantee that. So putting
|
||||
// check here to verify, otherwise things will go bad
|
||||
// quickly, if ignored.
|
||||
i := windows.GetCurrentThreadId()
|
||||
if i != tid {
|
||||
e.errno = sysErrNewThreadInCallback
|
||||
}
|
||||
s.c <- e
|
||||
// Always return NO_ERROR (0) for now.
|
||||
return 0
|
||||
}
|
||||
|
||||
var svcmain uintptr
|
||||
getServiceMain(&svcmain)
|
||||
t := []windows.SERVICE_TABLE_ENTRY{
|
||||
{ServiceName: syscall.StringToUTF16Ptr(s.name), ServiceProc: svcmain},
|
||||
{ServiceName: nil, ServiceProc: 0},
|
||||
}
|
||||
|
||||
goWaitsH = uintptr(s.goWaits.h)
|
||||
cWaitsH = uintptr(s.cWaits.h)
|
||||
sName = t[0].ServiceName
|
||||
ctlHandlerExProc, err = newCallback(ctlHandler)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go s.run()
|
||||
|
||||
err = windows.StartServiceCtrlDispatcher(&t[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StatusHandle returns service status handle. It is safe to call this function
|
||||
// from inside the Handler.Execute because then it is guaranteed to be set.
|
||||
// This code will have to change once multiple services are possible per process.
|
||||
func StatusHandle() windows.Handle {
|
||||
return windows.Handle(ssHandle)
|
||||
}
|
131
vendor/golang.org/x/sys/windows/svc/svc_test.go
generated
vendored
131
vendor/golang.org/x/sys/windows/svc/svc_test.go
generated
vendored
@ -1,131 +0,0 @@
|
||||
// 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 svc_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/windows/svc"
|
||||
"golang.org/x/sys/windows/svc/mgr"
|
||||
)
|
||||
|
||||
func getState(t *testing.T, s *mgr.Service) svc.State {
|
||||
status, err := s.Query()
|
||||
if err != nil {
|
||||
t.Fatalf("Query(%s) failed: %s", s.Name, err)
|
||||
}
|
||||
return status.State
|
||||
}
|
||||
|
||||
func testState(t *testing.T, s *mgr.Service, want svc.State) {
|
||||
have := getState(t, s)
|
||||
if have != want {
|
||||
t.Fatalf("%s state is=%d want=%d", s.Name, have, want)
|
||||
}
|
||||
}
|
||||
|
||||
func waitState(t *testing.T, s *mgr.Service, want svc.State) {
|
||||
for i := 0; ; i++ {
|
||||
have := getState(t, s)
|
||||
if have == want {
|
||||
return
|
||||
}
|
||||
if i > 10 {
|
||||
t.Fatalf("%s state is=%d, waiting timeout", s.Name, have)
|
||||
}
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExample(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode - it modifies system services")
|
||||
}
|
||||
|
||||
const name = "myservice"
|
||||
|
||||
m, err := mgr.Connect()
|
||||
if err != nil {
|
||||
t.Fatalf("SCM connection failed: %s", err)
|
||||
}
|
||||
defer m.Disconnect()
|
||||
|
||||
dir, err := ioutil.TempDir("", "svc")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp directory: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
exepath := filepath.Join(dir, "a.exe")
|
||||
o, err := exec.Command("go", "build", "-o", exepath, "golang.org/x/sys/windows/svc/example").CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to build service program: %v\n%v", err, string(o))
|
||||
}
|
||||
|
||||
s, err := m.OpenService(name)
|
||||
if err == nil {
|
||||
err = s.Delete()
|
||||
if err != nil {
|
||||
s.Close()
|
||||
t.Fatalf("Delete failed: %s", err)
|
||||
}
|
||||
s.Close()
|
||||
}
|
||||
s, err = m.CreateService(name, exepath, mgr.Config{DisplayName: "my service"}, "is", "auto-started")
|
||||
if err != nil {
|
||||
t.Fatalf("CreateService(%s) failed: %v", name, err)
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
args := []string{"is", "manual-started", fmt.Sprintf("%d", rand.Int())}
|
||||
|
||||
testState(t, s, svc.Stopped)
|
||||
err = s.Start(args...)
|
||||
if err != nil {
|
||||
t.Fatalf("Start(%s) failed: %s", s.Name, err)
|
||||
}
|
||||
waitState(t, s, svc.Running)
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// testing deadlock from issues 4.
|
||||
_, err = s.Control(svc.Interrogate)
|
||||
if err != nil {
|
||||
t.Fatalf("Control(%s) failed: %s", s.Name, err)
|
||||
}
|
||||
_, err = s.Control(svc.Interrogate)
|
||||
if err != nil {
|
||||
t.Fatalf("Control(%s) failed: %s", s.Name, err)
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
_, err = s.Control(svc.Stop)
|
||||
if err != nil {
|
||||
t.Fatalf("Control(%s) failed: %s", s.Name, err)
|
||||
}
|
||||
waitState(t, s, svc.Stopped)
|
||||
|
||||
err = s.Delete()
|
||||
if err != nil {
|
||||
t.Fatalf("Delete failed: %s", err)
|
||||
}
|
||||
|
||||
out, err := exec.Command("wevtutil.exe", "qe", "Application", "/q:*[System[Provider[@Name='myservice']]]", "/rd:true", "/c:10").CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("wevtutil failed: %v\n%v", err, string(out))
|
||||
}
|
||||
if want := strings.Join(append([]string{name}, args...), "-"); !strings.Contains(string(out), want) {
|
||||
t.Errorf("%q string does not contain %q", string(out), want)
|
||||
}
|
||||
}
|
68
vendor/golang.org/x/sys/windows/svc/sys_386.s
generated
vendored
68
vendor/golang.org/x/sys/windows/svc/sys_386.s
generated
vendored
@ -1,68 +0,0 @@
|
||||
// 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
|
||||
|
||||
// func servicemain(argc uint32, argv **uint16)
|
||||
TEXT ·servicemain(SB),7,$0
|
||||
MOVL argc+0(FP), AX
|
||||
MOVL AX, ·sArgc(SB)
|
||||
MOVL argv+4(FP), AX
|
||||
MOVL AX, ·sArgv(SB)
|
||||
|
||||
PUSHL BP
|
||||
PUSHL BX
|
||||
PUSHL SI
|
||||
PUSHL DI
|
||||
|
||||
SUBL $12, SP
|
||||
|
||||
MOVL ·sName(SB), AX
|
||||
MOVL AX, (SP)
|
||||
MOVL $·servicectlhandler(SB), AX
|
||||
MOVL AX, 4(SP)
|
||||
MOVL $0, 8(SP)
|
||||
MOVL ·cRegisterServiceCtrlHandlerExW(SB), AX
|
||||
MOVL SP, BP
|
||||
CALL AX
|
||||
MOVL BP, SP
|
||||
CMPL AX, $0
|
||||
JE exit
|
||||
MOVL AX, ·ssHandle(SB)
|
||||
|
||||
MOVL ·goWaitsH(SB), AX
|
||||
MOVL AX, (SP)
|
||||
MOVL ·cSetEvent(SB), AX
|
||||
MOVL SP, BP
|
||||
CALL AX
|
||||
MOVL BP, SP
|
||||
|
||||
MOVL ·cWaitsH(SB), AX
|
||||
MOVL AX, (SP)
|
||||
MOVL $-1, AX
|
||||
MOVL AX, 4(SP)
|
||||
MOVL ·cWaitForSingleObject(SB), AX
|
||||
MOVL SP, BP
|
||||
CALL AX
|
||||
MOVL BP, SP
|
||||
|
||||
exit:
|
||||
ADDL $12, SP
|
||||
|
||||
POPL DI
|
||||
POPL SI
|
||||
POPL BX
|
||||
POPL BP
|
||||
|
||||
MOVL 0(SP), CX
|
||||
ADDL $12, SP
|
||||
JMP CX
|
||||
|
||||
// I do not know why, but this seems to be the only way to call
|
||||
// ctlHandlerProc on Windows 7.
|
||||
|
||||
// func servicectlhandler(ctl uint32, evtype uint32, evdata uintptr, context uintptr) uintptr {
|
||||
TEXT ·servicectlhandler(SB),7,$0
|
||||
MOVL ·ctlHandlerExProc(SB), CX
|
||||
JMP CX
|
42
vendor/golang.org/x/sys/windows/svc/sys_amd64.s
generated
vendored
42
vendor/golang.org/x/sys/windows/svc/sys_amd64.s
generated
vendored
@ -1,42 +0,0 @@
|
||||
// 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
|
||||
|
||||
// func servicemain(argc uint32, argv **uint16)
|
||||
TEXT ·servicemain(SB),7,$0
|
||||
MOVL CX, ·sArgc(SB)
|
||||
MOVQ DX, ·sArgv(SB)
|
||||
|
||||
SUBQ $32, SP // stack for the first 4 syscall params
|
||||
|
||||
MOVQ ·sName(SB), CX
|
||||
MOVQ $·servicectlhandler(SB), DX
|
||||
// BUG(pastarmovj): Figure out a way to pass in context in R8.
|
||||
MOVQ ·cRegisterServiceCtrlHandlerExW(SB), AX
|
||||
CALL AX
|
||||
CMPQ AX, $0
|
||||
JE exit
|
||||
MOVQ AX, ·ssHandle(SB)
|
||||
|
||||
MOVQ ·goWaitsH(SB), CX
|
||||
MOVQ ·cSetEvent(SB), AX
|
||||
CALL AX
|
||||
|
||||
MOVQ ·cWaitsH(SB), CX
|
||||
MOVQ $4294967295, DX
|
||||
MOVQ ·cWaitForSingleObject(SB), AX
|
||||
CALL AX
|
||||
|
||||
exit:
|
||||
ADDQ $32, SP
|
||||
RET
|
||||
|
||||
// I do not know why, but this seems to be the only way to call
|
||||
// ctlHandlerProc on Windows 7.
|
||||
|
||||
// func ·servicectlhandler(ctl uint32, evtype uint32, evdata uintptr, context uintptr) uintptr {
|
||||
TEXT ·servicectlhandler(SB),7,$0
|
||||
MOVQ ·ctlHandlerExProc(SB), AX
|
||||
JMP AX
|
38
vendor/golang.org/x/sys/windows/svc/sys_arm.s
generated
vendored
38
vendor/golang.org/x/sys/windows/svc/sys_arm.s
generated
vendored
@ -1,38 +0,0 @@
|
||||
// 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
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func servicemain(argc uint32, argv **uint16)
|
||||
TEXT ·servicemain(SB),NOSPLIT|NOFRAME,$0
|
||||
MOVM.DB.W [R4, R14], (R13) // push {r4, lr}
|
||||
MOVW R13, R4
|
||||
BIC $0x7, R13 // alignment for ABI
|
||||
|
||||
MOVW R0, ·sArgc(SB)
|
||||
MOVW R1, ·sArgv(SB)
|
||||
|
||||
MOVW ·sName(SB), R0
|
||||
MOVW ·ctlHandlerExProc(SB), R1
|
||||
MOVW $0, R2
|
||||
MOVW ·cRegisterServiceCtrlHandlerExW(SB), R3
|
||||
BL (R3)
|
||||
CMP $0, R0
|
||||
BEQ exit
|
||||
MOVW R0, ·ssHandle(SB)
|
||||
|
||||
MOVW ·goWaitsH(SB), R0
|
||||
MOVW ·cSetEvent(SB), R1
|
||||
BL (R1)
|
||||
|
||||
MOVW ·cWaitsH(SB), R0
|
||||
MOVW $-1, R1
|
||||
MOVW ·cWaitForSingleObject(SB), R2
|
||||
BL (R2)
|
||||
|
||||
exit:
|
||||
MOVW R4, R13 // free extra stack space
|
||||
MOVM.IA.W (R13), [R4, R15] // pop {r4, pc}
|
53
vendor/golang.org/x/sys/windows/syscall_test.go
generated
vendored
53
vendor/golang.org/x/sys/windows/syscall_test.go
generated
vendored
@ -1,53 +0,0 @@
|
||||
// Copyright 2013 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 windows_test
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func testSetGetenv(t *testing.T, key, value string) {
|
||||
err := windows.Setenv(key, value)
|
||||
if err != nil {
|
||||
t.Fatalf("Setenv failed to set %q: %v", value, err)
|
||||
}
|
||||
newvalue, found := windows.Getenv(key)
|
||||
if !found {
|
||||
t.Fatalf("Getenv failed to find %v variable (want value %q)", key, value)
|
||||
}
|
||||
if newvalue != value {
|
||||
t.Fatalf("Getenv(%v) = %q; want %q", key, newvalue, value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnv(t *testing.T) {
|
||||
testSetGetenv(t, "TESTENV", "AVALUE")
|
||||
// make sure TESTENV gets set to "", not deleted
|
||||
testSetGetenv(t, "TESTENV", "")
|
||||
}
|
||||
|
||||
func TestGetProcAddressByOrdinal(t *testing.T) {
|
||||
// Attempt calling shlwapi.dll:IsOS, resolving it by ordinal, as
|
||||
// suggested in
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb773795.aspx
|
||||
h, err := windows.LoadLibrary("shlwapi.dll")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to load shlwapi.dll: %s", err)
|
||||
}
|
||||
procIsOS, err := windows.GetProcAddressByOrdinal(h, 437)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not find shlwapi.dll:IsOS by ordinal: %s", err)
|
||||
}
|
||||
const OS_NT = 1
|
||||
r, _, _ := syscall.Syscall(procIsOS, 1, OS_NT, 0, 0)
|
||||
if r == 0 {
|
||||
t.Error("shlwapi.dll:IsOS(OS_NT) returned 0, expected non-zero value")
|
||||
}
|
||||
}
|
92
vendor/golang.org/x/sys/windows/syscall_windows_test.go
generated
vendored
92
vendor/golang.org/x/sys/windows/syscall_windows_test.go
generated
vendored
@ -1,92 +0,0 @@
|
||||
// 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.
|
||||
|
||||
package windows_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func TestWin32finddata(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "go-build")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp directory: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
path := filepath.Join(dir, "long_name.and_extension")
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create %v: %v", path, err)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
type X struct {
|
||||
fd windows.Win32finddata
|
||||
got byte
|
||||
pad [10]byte // to protect ourselves
|
||||
|
||||
}
|
||||
var want byte = 2 // it is unlikely to have this character in the filename
|
||||
x := X{got: want}
|
||||
|
||||
pathp, _ := windows.UTF16PtrFromString(path)
|
||||
h, err := windows.FindFirstFile(pathp, &(x.fd))
|
||||
if err != nil {
|
||||
t.Fatalf("FindFirstFile failed: %v", err)
|
||||
}
|
||||
err = windows.FindClose(h)
|
||||
if err != nil {
|
||||
t.Fatalf("FindClose failed: %v", err)
|
||||
}
|
||||
|
||||
if x.got != want {
|
||||
t.Fatalf("memory corruption: want=%d got=%d", want, x.got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatMessage(t *testing.T) {
|
||||
dll := windows.MustLoadDLL("netevent.dll")
|
||||
|
||||
const TITLE_SC_MESSAGE_BOX uint32 = 0xC0001B75
|
||||
const flags uint32 = syscall.FORMAT_MESSAGE_FROM_HMODULE | syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY | syscall.FORMAT_MESSAGE_IGNORE_INSERTS
|
||||
buf := make([]uint16, 300)
|
||||
_, err := windows.FormatMessage(flags, uintptr(dll.Handle), TITLE_SC_MESSAGE_BOX, 0, buf, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("FormatMessage for handle=%x and errno=%x failed: %v", dll.Handle, TITLE_SC_MESSAGE_BOX, err)
|
||||
}
|
||||
}
|
||||
|
||||
func abort(funcname string, err error) {
|
||||
panic(funcname + " failed: " + err.Error())
|
||||
}
|
||||
|
||||
func ExampleLoadLibrary() {
|
||||
h, err := windows.LoadLibrary("kernel32.dll")
|
||||
if err != nil {
|
||||
abort("LoadLibrary", err)
|
||||
}
|
||||
defer windows.FreeLibrary(h)
|
||||
proc, err := windows.GetProcAddress(h, "GetVersion")
|
||||
if err != nil {
|
||||
abort("GetProcAddress", err)
|
||||
}
|
||||
r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0)
|
||||
major := byte(r)
|
||||
minor := uint8(r >> 8)
|
||||
build := uint16(r >> 16)
|
||||
print("windows version ", major, ".", minor, " (Build ", build, ")\n")
|
||||
}
|
||||
|
||||
func TestTOKEN_ALL_ACCESS(t *testing.T) {
|
||||
if windows.TOKEN_ALL_ACCESS != 0xF01FF {
|
||||
t.Errorf("TOKEN_ALL_ACCESS = %x, want 0xF01FF", windows.TOKEN_ALL_ACCESS)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user