Merge pull request #2 from darkliquid/merge-from-upstream

Merge from upstream
This commit is contained in:
Steven Hartland 2015-05-11 13:54:10 +01:00
Родитель e4eca0c38e 8657a64cdf
Коммит 682969e2f2
6 изменённых файлов: 86 добавлений и 16 удалений

Просмотреть файл

@ -24,9 +24,10 @@ const addKeyName = `SYSTEM\CurrentControlSet\Services\EventLog\Application`
// Install modifies PC registry to allow logging with event source src. // Install modifies PC registry to allow logging with event source src.
// It adds all required keys/values to event log key. Install uses msgFile // It adds all required keys/values to event log key. Install uses msgFile
// as event message file. Use bitwise of log.Error, log.Warning and log.Info // as event message file, creating key as REG_EXPAND_SZ, if useExpandKey
// to specify events supported. // is true, otherwise as REG_SZ. Use bitwise of log.Error, log.Warning
func Install(src, msgFile string, eventsSupported uint32) error { // and log.Info to specify events supported.
func Install(src, msgFile string, useExpandKey bool, eventsSupported uint32) error {
appkey, err := registry.OpenKey(syscall.HKEY_LOCAL_MACHINE, addKeyName) appkey, err := registry.OpenKey(syscall.HKEY_LOCAL_MACHINE, addKeyName)
if err != nil { if err != nil {
return err return err
@ -44,7 +45,11 @@ func Install(src, msgFile string, eventsSupported uint32) error {
if err != nil { if err != nil {
return err return err
} }
err = sk.SetString("EventMessageFile", msgFile) if useExpandKey {
err = sk.SetStringExpand("EventMessageFile", msgFile)
} else {
err = sk.SetString("EventMessageFile", msgFile)
}
if err != nil { if err != nil {
return err return err
} }
@ -58,7 +63,7 @@ func Install(src, msgFile string, eventsSupported uint32) error {
// InstallAsEventCreate is the same as Install, but uses // InstallAsEventCreate is the same as Install, but uses
// %SystemRoot%\System32\EventCreate.exe as event message file. // %SystemRoot%\System32\EventCreate.exe as event message file.
func InstallAsEventCreate(src string, eventsSupported uint32) error { func InstallAsEventCreate(src string, eventsSupported uint32) error {
return Install(src, "%SystemRoot%\\System32\\EventCreate.exe", eventsSupported) return Install(src, "%SystemRoot%\\System32\\EventCreate.exe", true, eventsSupported)
} }
// Remove deletes all registry elements installed by correspondent Install. // Remove deletes all registry elements installed by correspondent Install.

Просмотреть файл

@ -9,6 +9,7 @@ package mgr
import ( import (
"github.com/multiplay/winsvc/winapi" "github.com/multiplay/winsvc/winapi"
"syscall" "syscall"
"unicode/utf16"
"unsafe" "unsafe"
) )
@ -35,7 +36,7 @@ type Config struct {
BinaryPathName string BinaryPathName string
LoadOrderGroup string LoadOrderGroup string
TagId uint32 TagId uint32
Dependencies string Dependencies []string
ServiceStartName string // name of the account under which the service should run ServiceStartName string // name of the account under which the service should run
DisplayName string DisplayName string
Password string Password string
@ -49,6 +50,24 @@ func toString(p *uint16) string {
return syscall.UTF16ToString((*[4096]uint16)(unsafe.Pointer(p))[:]) 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
}
func (s *Service) Config() (Config, error) { func (s *Service) Config() (Config, error) {
b := make([]byte, 1024) b := make([]byte, 1024)
p := (*winapi.QUERY_SERVICE_CONFIG)(unsafe.Pointer(&b[0])) p := (*winapi.QUERY_SERVICE_CONFIG)(unsafe.Pointer(&b[0]))
@ -87,7 +106,7 @@ func (s *Service) Config() (Config, error) {
BinaryPathName: toString(p.BinaryPathName), BinaryPathName: toString(p.BinaryPathName),
LoadOrderGroup: toString(p.LoadOrderGroup), LoadOrderGroup: toString(p.LoadOrderGroup),
TagId: p.TagId, TagId: p.TagId,
Dependencies: toString(p.Dependencies), Dependencies: toStringSlice(p.Dependencies),
ServiceStartName: toString(p.ServiceStartName), ServiceStartName: toString(p.ServiceStartName),
DisplayName: toString(p.DisplayName), DisplayName: toString(p.DisplayName),
Description: toString(p2.Description), Description: toString(p2.Description),
@ -107,7 +126,7 @@ func updateDescription(handle syscall.Handle, desc string) error {
func (s *Service) UpdateConfig(c Config) error { func (s *Service) UpdateConfig(c Config) error {
err := winapi.ChangeServiceConfig(s.Handle, c.ServiceType, c.StartType, err := winapi.ChangeServiceConfig(s.Handle, c.ServiceType, c.StartType,
c.ErrorControl, toPtr(c.BinaryPathName), toPtr(c.LoadOrderGroup), c.ErrorControl, toPtr(c.BinaryPathName), toPtr(c.LoadOrderGroup),
nil, toPtr(c.Dependencies), toPtr(c.ServiceStartName), nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName),
toPtr(c.Password), toPtr(c.DisplayName)) toPtr(c.Password), toPtr(c.DisplayName))
if err != nil { if err != nil {
return err return err

Просмотреть файл

@ -14,6 +14,7 @@ package mgr
import ( import (
"github.com/multiplay/winsvc/winapi" "github.com/multiplay/winsvc/winapi"
"syscall" "syscall"
"unicode/utf16"
) )
// Mgr is used to manage Windows service. // Mgr is used to manage Windows service.
@ -52,6 +53,25 @@ func toPtr(s string) *uint16 {
return syscall.StringToUTF16Ptr(s) 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. // CreateService installs new service name on the system.
// The service will be executed by running exepath binary, // The service will be executed by running exepath binary,
// while service settings are specified in config c. // while service settings are specified in config c.
@ -66,7 +86,7 @@ func (m *Mgr) CreateService(name, exepath string, c Config) (*Service, error) {
h, err := winapi.CreateService(m.Handle, toPtr(name), toPtr(c.DisplayName), h, err := winapi.CreateService(m.Handle, toPtr(name), toPtr(c.DisplayName),
winapi.SERVICE_ALL_ACCESS, winapi.SERVICE_WIN32_OWN_PROCESS, winapi.SERVICE_ALL_ACCESS, winapi.SERVICE_WIN32_OWN_PROCESS,
c.StartType, c.ErrorControl, toPtr(exepath), toPtr(c.LoadOrderGroup), c.StartType, c.ErrorControl, toPtr(exepath), toPtr(c.LoadOrderGroup),
nil, toPtr(c.Dependencies), toPtr(c.ServiceStartName), toPtr(c.Password)) nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName), toPtr(c.Password))
if err != nil { if err != nil {
return nil, err return nil, err
} }

Просмотреть файл

@ -10,6 +10,8 @@ import (
"github.com/multiplay/winsvc/mgr" "github.com/multiplay/winsvc/mgr"
"os" "os"
"path/filepath" "path/filepath"
"sort"
"strings"
"testing" "testing"
) )
@ -19,7 +21,7 @@ func TestOpenLanManServer(t *testing.T) {
t.Fatalf("SCM connection failed: %s", err) t.Fatalf("SCM connection failed: %s", err)
} }
defer m.Disconnect() defer m.Disconnect()
s, err := m.OpenService("lanmanserver") s, err := m.OpenService("LanmanServer")
if err != nil { if err != nil {
t.Fatalf("OpenService(lanmanserver) failed: %s", err) t.Fatalf("OpenService(lanmanserver) failed: %s", err)
} }
@ -44,6 +46,18 @@ func install(t *testing.T, m *mgr.Mgr, name, exepath string, c mgr.Config) {
defer s.Close() 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 { func testConfig(t *testing.T, s *mgr.Service, should mgr.Config) mgr.Config {
is, err := s.Config() is, err := s.Config()
if err != nil { if err != nil {
@ -58,6 +72,9 @@ func testConfig(t *testing.T, s *mgr.Service, should mgr.Config) mgr.Config {
if should.Description != is.Description { if should.Description != is.Description {
t.Fatalf("config mismatch: Description is %q, but should have %q", is.Description, should.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 return is
} }
@ -78,9 +95,10 @@ func TestMyService(t *testing.T) {
defer m.Disconnect() defer m.Disconnect()
c := mgr.Config{ c := mgr.Config{
StartType: mgr.StartDisabled, StartType: mgr.StartDisabled,
DisplayName: "my service", DisplayName: "my service",
Description: "my service is just a test", Description: "my service is just a test",
Dependencies: []string{"LanmanServer", "W32Time"},
} }
exename := os.Args[0] exename := os.Args[0]

Просмотреть файл

@ -57,10 +57,18 @@ func (k *Key) SetUInt32(name string, value uint32) error {
(*byte)(unsafe.Pointer(&value)), uint32(unsafe.Sizeof(value))) (*byte)(unsafe.Pointer(&value)), uint32(unsafe.Sizeof(value)))
} }
func (k *Key) SetString(name string, value string) error { func (k *Key) setString(name string, value string, valtype uint32) error {
buf := syscall.StringToUTF16(value) buf := syscall.StringToUTF16(value)
return winapi.RegSetValueEx( return winapi.RegSetValueEx(
k.Handle, syscall.StringToUTF16Ptr(name), k.Handle, syscall.StringToUTF16Ptr(name),
0, syscall.REG_SZ, 0, valtype,
(*byte)(unsafe.Pointer(&buf[0])), uint32(len(buf)*2)) (*byte)(unsafe.Pointer(&buf[0])), uint32(len(buf)*2))
} }
func (k *Key) SetString(name string, value string) error {
return k.setString(name, value, syscall.REG_SZ)
}
func (k *Key) SetStringExpand(name string, value string) error {
return k.setString(name, value, syscall.REG_EXPAND_SZ)
}

Просмотреть файл

@ -79,7 +79,7 @@ func IsAnInteractiveSession() (bool, error) {
return false, err return false, err
} }
p := unsafe.Pointer(&gs.Groups[0]) p := unsafe.Pointer(&gs.Groups[0])
groups := (*[256]syscall.SIDAndAttributes)(p)[:gs.GroupCount] groups := (*[2 << 20]syscall.SIDAndAttributes)(p)[:gs.GroupCount]
for _, g := range groups { for _, g := range groups {
if winapi.EqualSid(g.Sid, interSid) { if winapi.EqualSid(g.Sid, interSid) {
return true, nil return true, nil