Merge pull request #2 from darkliquid/merge-from-upstream
Merge from upstream
This commit is contained in:
Коммит
682969e2f2
|
@ -24,9 +24,10 @@ const addKeyName = `SYSTEM\CurrentControlSet\Services\EventLog\Application`
|
|||
|
||||
// Install modifies PC registry to allow logging with event source src.
|
||||
// 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
|
||||
// to specify events supported.
|
||||
func Install(src, msgFile string, eventsSupported uint32) error {
|
||||
// as event message file, creating key as REG_EXPAND_SZ, if useExpandKey
|
||||
// is true, otherwise as REG_SZ. Use bitwise of log.Error, log.Warning
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -44,7 +45,11 @@ func Install(src, msgFile string, eventsSupported uint32) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = sk.SetString("EventMessageFile", msgFile)
|
||||
if useExpandKey {
|
||||
err = sk.SetStringExpand("EventMessageFile", msgFile)
|
||||
} else {
|
||||
err = sk.SetString("EventMessageFile", msgFile)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -58,7 +63,7 @@ func Install(src, msgFile string, eventsSupported uint32) error {
|
|||
// InstallAsEventCreate is the same as Install, but uses
|
||||
// %SystemRoot%\System32\EventCreate.exe as event message file.
|
||||
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.
|
||||
|
|
|
@ -9,6 +9,7 @@ package mgr
|
|||
import (
|
||||
"github.com/multiplay/winsvc/winapi"
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
|
@ -35,7 +36,7 @@ type Config struct {
|
|||
BinaryPathName string
|
||||
LoadOrderGroup string
|
||||
TagId uint32
|
||||
Dependencies string
|
||||
Dependencies []string
|
||||
ServiceStartName string // name of the account under which the service should run
|
||||
DisplayName string
|
||||
Password string
|
||||
|
@ -49,6 +50,24 @@ func toString(p *uint16) string {
|
|||
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) {
|
||||
b := make([]byte, 1024)
|
||||
p := (*winapi.QUERY_SERVICE_CONFIG)(unsafe.Pointer(&b[0]))
|
||||
|
@ -87,7 +106,7 @@ func (s *Service) Config() (Config, error) {
|
|||
BinaryPathName: toString(p.BinaryPathName),
|
||||
LoadOrderGroup: toString(p.LoadOrderGroup),
|
||||
TagId: p.TagId,
|
||||
Dependencies: toString(p.Dependencies),
|
||||
Dependencies: toStringSlice(p.Dependencies),
|
||||
ServiceStartName: toString(p.ServiceStartName),
|
||||
DisplayName: toString(p.DisplayName),
|
||||
Description: toString(p2.Description),
|
||||
|
@ -107,7 +126,7 @@ func updateDescription(handle syscall.Handle, desc string) error {
|
|||
func (s *Service) UpdateConfig(c Config) error {
|
||||
err := winapi.ChangeServiceConfig(s.Handle, c.ServiceType, c.StartType,
|
||||
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))
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
22
mgr/mgr.go
22
mgr/mgr.go
|
@ -14,6 +14,7 @@ package mgr
|
|||
import (
|
||||
"github.com/multiplay/winsvc/winapi"
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
)
|
||||
|
||||
// Mgr is used to manage Windows service.
|
||||
|
@ -52,6 +53,25 @@ func toPtr(s string) *uint16 {
|
|||
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,
|
||||
// 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),
|
||||
winapi.SERVICE_ALL_ACCESS, winapi.SERVICE_WIN32_OWN_PROCESS,
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ import (
|
|||
"github.com/multiplay/winsvc/mgr"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -19,7 +21,7 @@ func TestOpenLanManServer(t *testing.T) {
|
|||
t.Fatalf("SCM connection failed: %s", err)
|
||||
}
|
||||
defer m.Disconnect()
|
||||
s, err := m.OpenService("lanmanserver")
|
||||
s, err := m.OpenService("LanmanServer")
|
||||
if err != nil {
|
||||
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()
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -58,6 +72,9 @@ func testConfig(t *testing.T, s *mgr.Service, should mgr.Config) mgr.Config {
|
|||
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
|
||||
}
|
||||
|
||||
|
@ -78,9 +95,10 @@ func TestMyService(t *testing.T) {
|
|||
defer m.Disconnect()
|
||||
|
||||
c := mgr.Config{
|
||||
StartType: mgr.StartDisabled,
|
||||
DisplayName: "my service",
|
||||
Description: "my service is just a test",
|
||||
StartType: mgr.StartDisabled,
|
||||
DisplayName: "my service",
|
||||
Description: "my service is just a test",
|
||||
Dependencies: []string{"LanmanServer", "W32Time"},
|
||||
}
|
||||
|
||||
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)))
|
||||
}
|
||||
|
||||
func (k *Key) SetString(name string, value string) error {
|
||||
func (k *Key) setString(name string, value string, valtype uint32) error {
|
||||
buf := syscall.StringToUTF16(value)
|
||||
return winapi.RegSetValueEx(
|
||||
k.Handle, syscall.StringToUTF16Ptr(name),
|
||||
0, syscall.REG_SZ,
|
||||
0, valtype,
|
||||
(*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
|
||||
}
|
||||
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 {
|
||||
if winapi.EqualSid(g.Sid, interSid) {
|
||||
return true, nil
|
||||
|
|
Загрузка…
Ссылка в новой задаче