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.
|
// 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
|
||||||
|
|
22
mgr/mgr.go
22
mgr/mgr.go
|
@ -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
|
||||||
|
|
Загрузка…
Ссылка в новой задаче