Deps update
This commit is contained in:
parent
b9764f8248
commit
cdfe7ba673
|
@ -46,8 +46,8 @@
|
||||||
"activation",
|
"activation",
|
||||||
"daemon"
|
"daemon"
|
||||||
]
|
]
|
||||||
revision = "40e2722dffead74698ca12a750f64ef313ddce05"
|
revision = "39ca1b05acc7ad1220e09f133283b8859a8b71ab"
|
||||||
version = "v16"
|
version = "v17"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -154,7 +154,7 @@
|
||||||
"poly1305",
|
"poly1305",
|
||||||
"salsa20/salsa"
|
"salsa20/salsa"
|
||||||
]
|
]
|
||||||
revision = "1a580b3eff7814fc9b40602fd35256c63b50f491"
|
revision = "ab813273cd59e1333f7ae7bff5d027d4aadf528c"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -170,7 +170,7 @@
|
||||||
"ipv4",
|
"ipv4",
|
||||||
"ipv6"
|
"ipv6"
|
||||||
]
|
]
|
||||||
revision = "2491c5de3490fced2f6cff376127c667efeed857"
|
revision = "1e491301e022f8f977054da4c2d852decd59571f"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -183,7 +183,7 @@
|
||||||
"windows/svc/eventlog",
|
"windows/svc/eventlog",
|
||||||
"windows/svc/mgr"
|
"windows/svc/mgr"
|
||||||
]
|
]
|
||||||
revision = "7c87d13f8e835d2fb3a70a2912c811ed0c1d241b"
|
revision = "c11f84a56e43e20a78cee75a7c034031ecf57d1f"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "golang.org/x/text"
|
name = "golang.org/x/text"
|
||||||
|
@ -215,6 +215,6 @@
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "2665fa9c725a2e63a6769a05e1da1b68dfc6ea2adcce5f2bf2fdfac975ec9574"
|
inputs-digest = "3addcda55a55bed25195ba087dd5485d24d206d58145633ed2e69bb55167c687"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/coreos/go-systemd"
|
name = "github.com/coreos/go-systemd"
|
||||||
version = "16.0.0"
|
version = "17.0.0"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/miekg/dns"
|
name = "github.com/miekg/dns"
|
||||||
version = "1.0.6"
|
version = "1.0.7"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
|
|
@ -10,7 +10,7 @@ env:
|
||||||
- GOPATH=/opt
|
- GOPATH=/opt
|
||||||
- BUILD_DIR=/opt/src/github.com/coreos/go-systemd
|
- BUILD_DIR=/opt/src/github.com/coreos/go-systemd
|
||||||
matrix:
|
matrix:
|
||||||
- DOCKER_BASE=ubuntu:16.04
|
- DOCKER_BASE=ubuntu:18.04
|
||||||
- DOCKER_BASE=debian:stretch
|
- DOCKER_BASE=debian:stretch
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
|
|
|
@ -6,9 +6,11 @@
|
||||||
Go bindings to systemd. The project has several packages:
|
Go bindings to systemd. The project has several packages:
|
||||||
|
|
||||||
- `activation` - for writing and using socket activation from Go
|
- `activation` - for writing and using socket activation from Go
|
||||||
|
- `daemon` - for notifying systemd of service status changes
|
||||||
- `dbus` - for starting/stopping/inspecting running services and units
|
- `dbus` - for starting/stopping/inspecting running services and units
|
||||||
- `journal` - for writing to systemd's logging service, journald
|
- `journal` - for writing to systemd's logging service, journald
|
||||||
- `sdjournal` - for reading from journald by wrapping its C API
|
- `sdjournal` - for reading from journald by wrapping its C API
|
||||||
|
- `login1` - for integration with the systemd logind API
|
||||||
- `machine1` - for registering machines/containers with systemd
|
- `machine1` - for registering machines/containers with systemd
|
||||||
- `unit` - for (de)serialization and comparison of unit files
|
- `unit` - for (de)serialization and comparison of unit files
|
||||||
|
|
||||||
|
@ -18,10 +20,9 @@ An example HTTP server using socket activation can be quickly set up by followin
|
||||||
|
|
||||||
https://github.com/coreos/go-systemd/tree/master/examples/activation/httpserver
|
https://github.com/coreos/go-systemd/tree/master/examples/activation/httpserver
|
||||||
|
|
||||||
## Journal
|
## systemd Service Notification
|
||||||
|
|
||||||
Using the pure-Go `journal` package you can submit journal entries directly to systemd's journal, taking advantage of features like indexed key/value pairs for each log entry.
|
The `daemon` package is an implementation of the [sd_notify protocol](https://www.freedesktop.org/software/systemd/man/sd_notify.html#Description). It can be used to inform systemd of service start-up completion, watchdog events, and other status changes.
|
||||||
The `sdjournal` package provides read access to the journal by wrapping around journald's native C API; consequently it requires cgo and the journal headers to be available.
|
|
||||||
|
|
||||||
## D-Bus
|
## D-Bus
|
||||||
|
|
||||||
|
@ -45,6 +46,20 @@ Create `/etc/dbus-1/system-local.conf` that looks like this:
|
||||||
</busconfig>
|
</busconfig>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Journal
|
||||||
|
|
||||||
|
### Writing to the Journal
|
||||||
|
|
||||||
|
Using the pure-Go `journal` package you can submit journal entries directly to systemd's journal, taking advantage of features like indexed key/value pairs for each log entry.
|
||||||
|
|
||||||
|
### Reading from the Journal
|
||||||
|
|
||||||
|
The `sdjournal` package provides read access to the journal by wrapping around journald's native C API; consequently it requires cgo and the journal headers to be available.
|
||||||
|
|
||||||
|
## logind
|
||||||
|
|
||||||
|
The `login1` package provides functions to integrate with the [systemd logind API](http://www.freedesktop.org/wiki/Software/systemd/logind/).
|
||||||
|
|
||||||
## machined
|
## machined
|
||||||
|
|
||||||
The `machine1` package allows interaction with the [systemd machined D-Bus API](http://www.freedesktop.org/wiki/Software/systemd/machined/).
|
The `machine1` package allows interaction with the [systemd machined D-Bus API](http://www.freedesktop.org/wiki/Software/systemd/machined/).
|
||||||
|
|
|
@ -18,18 +18,26 @@ package activation
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
// based on: https://gist.github.com/alberts/4640792
|
|
||||||
const (
|
const (
|
||||||
|
// listenFdsStart corresponds to `SD_LISTEN_FDS_START`.
|
||||||
listenFdsStart = 3
|
listenFdsStart = 3
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Files returns a slice containing a `os.File` object for each
|
||||||
|
// file descriptor passed to this process via systemd fd-passing protocol.
|
||||||
|
//
|
||||||
|
// The order of the file descriptors is preserved in the returned slice.
|
||||||
|
// `unsetEnv` is typically set to `true` in order to avoid clashes in
|
||||||
|
// fd usage and to avoid leaking environment flags to child processes.
|
||||||
func Files(unsetEnv bool) []*os.File {
|
func Files(unsetEnv bool) []*os.File {
|
||||||
if unsetEnv {
|
if unsetEnv {
|
||||||
defer os.Unsetenv("LISTEN_PID")
|
defer os.Unsetenv("LISTEN_PID")
|
||||||
defer os.Unsetenv("LISTEN_FDS")
|
defer os.Unsetenv("LISTEN_FDS")
|
||||||
|
defer os.Unsetenv("LISTEN_FDNAMES")
|
||||||
}
|
}
|
||||||
|
|
||||||
pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
|
pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
|
||||||
|
@ -42,10 +50,17 @@ func Files(unsetEnv bool) []*os.File {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
names := strings.Split(os.Getenv("LISTEN_FDNAMES"), ":")
|
||||||
|
|
||||||
files := make([]*os.File, 0, nfds)
|
files := make([]*os.File, 0, nfds)
|
||||||
for fd := listenFdsStart; fd < listenFdsStart+nfds; fd++ {
|
for fd := listenFdsStart; fd < listenFdsStart+nfds; fd++ {
|
||||||
syscall.CloseOnExec(fd)
|
syscall.CloseOnExec(fd)
|
||||||
files = append(files, os.NewFile(uintptr(fd), "LISTEN_FD_"+strconv.Itoa(fd)))
|
name := "LISTEN_FD_" + strconv.Itoa(fd)
|
||||||
|
offset := fd - listenFdsStart
|
||||||
|
if offset < len(names) && len(names[offset]) > 0 {
|
||||||
|
name = names[offset]
|
||||||
|
}
|
||||||
|
files = append(files, os.NewFile(uintptr(fd), name))
|
||||||
}
|
}
|
||||||
|
|
||||||
return files
|
return files
|
||||||
|
|
|
@ -48,15 +48,15 @@ func TestActivation(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Env = os.Environ()
|
cmd.Env = os.Environ()
|
||||||
cmd.Env = append(cmd.Env, "LISTEN_FDS=2", "FIX_LISTEN_PID=1")
|
cmd.Env = append(cmd.Env, "LISTEN_FDS=2", "LISTEN_FDNAMES=fd1", "FIX_LISTEN_PID=1")
|
||||||
|
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(err.Error())
|
t.Fatalf(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
correctStringWritten(t, r1, "Hello world")
|
correctStringWritten(t, r1, "Hello world: fd1")
|
||||||
correctStringWritten(t, r2, "Goodbye world")
|
correctStringWritten(t, r2, "Goodbye world: LISTEN_FD_4")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestActivationNoFix(t *testing.T) {
|
func TestActivationNoFix(t *testing.T) {
|
||||||
|
@ -65,7 +65,7 @@ func TestActivationNoFix(t *testing.T) {
|
||||||
cmd.Env = append(cmd.Env, "LISTEN_FDS=2")
|
cmd.Env = append(cmd.Env, "LISTEN_FDS=2")
|
||||||
|
|
||||||
out, _ := cmd.CombinedOutput()
|
out, _ := cmd.CombinedOutput()
|
||||||
if bytes.Contains(out, []byte("No files")) == false {
|
if !bytes.Contains(out, []byte("No files")) {
|
||||||
t.Fatalf("Child didn't error out as expected")
|
t.Fatalf("Child didn't error out as expected")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ func TestActivationNoFiles(t *testing.T) {
|
||||||
cmd.Env = append(cmd.Env, "LISTEN_FDS=0", "FIX_LISTEN_PID=1")
|
cmd.Env = append(cmd.Env, "LISTEN_FDS=0", "FIX_LISTEN_PID=1")
|
||||||
|
|
||||||
out, _ := cmd.CombinedOutput()
|
out, _ := cmd.CombinedOutput()
|
||||||
if bytes.Contains(out, []byte("No files")) == false {
|
if !bytes.Contains(out, []byte("No files")) {
|
||||||
t.Fatalf("Child didn't error out as expected")
|
t.Fatalf("Child didn't error out as expected")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,33 @@ import (
|
||||||
// The order of the file descriptors is preserved in the returned slice.
|
// The order of the file descriptors is preserved in the returned slice.
|
||||||
// Nil values are used to fill any gaps. For example if systemd were to return file descriptors
|
// Nil values are used to fill any gaps. For example if systemd were to return file descriptors
|
||||||
// corresponding with "udp, tcp, tcp", then the slice would contain {nil, net.Listener, net.Listener}
|
// corresponding with "udp, tcp, tcp", then the slice would contain {nil, net.Listener, net.Listener}
|
||||||
func Listeners(unsetEnv bool) ([]net.Listener, error) {
|
func Listeners() ([]net.Listener, error) {
|
||||||
files := Files(unsetEnv)
|
files := Files(true)
|
||||||
listeners := make([]net.Listener, len(files))
|
listeners := make([]net.Listener, len(files))
|
||||||
|
|
||||||
for i, f := range files {
|
for i, f := range files {
|
||||||
if pc, err := net.FileListener(f); err == nil {
|
if pc, err := net.FileListener(f); err == nil {
|
||||||
listeners[i] = pc
|
listeners[i] = pc
|
||||||
|
f.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listeners, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListenersWithNames maps a listener name to a set of net.Listener instances.
|
||||||
|
func ListenersWithNames() (map[string][]net.Listener, error) {
|
||||||
|
files := Files(true)
|
||||||
|
listeners := map[string][]net.Listener{}
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
if pc, err := net.FileListener(f); err == nil {
|
||||||
|
current, ok := listeners[f.Name()]
|
||||||
|
if !ok {
|
||||||
|
listeners[f.Name()] = []net.Listener{pc}
|
||||||
|
} else {
|
||||||
|
listeners[f.Name()] = append(current, pc)
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return listeners, nil
|
return listeners, nil
|
||||||
|
@ -40,8 +60,8 @@ func Listeners(unsetEnv bool) ([]net.Listener, error) {
|
||||||
// TLSListeners returns a slice containing a net.listener for each matching TCP socket type
|
// TLSListeners returns a slice containing a net.listener for each matching TCP socket type
|
||||||
// passed to this process.
|
// passed to this process.
|
||||||
// It uses default Listeners func and forces TCP sockets handlers to use TLS based on tlsConfig.
|
// It uses default Listeners func and forces TCP sockets handlers to use TLS based on tlsConfig.
|
||||||
func TLSListeners(unsetEnv bool, tlsConfig *tls.Config) ([]net.Listener, error) {
|
func TLSListeners(tlsConfig *tls.Config) ([]net.Listener, error) {
|
||||||
listeners, err := Listeners(unsetEnv)
|
listeners, err := Listeners()
|
||||||
|
|
||||||
if listeners == nil || err != nil {
|
if listeners == nil || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -58,3 +78,26 @@ func TLSListeners(unsetEnv bool, tlsConfig *tls.Config) ([]net.Listener, error)
|
||||||
|
|
||||||
return listeners, err
|
return listeners, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TLSListenersWithNames maps a listener name to a net.Listener with
|
||||||
|
// the associated TLS configuration.
|
||||||
|
func TLSListenersWithNames(tlsConfig *tls.Config) (map[string][]net.Listener, error) {
|
||||||
|
listeners, err := ListenersWithNames()
|
||||||
|
|
||||||
|
if listeners == nil || err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if tlsConfig != nil && err == nil {
|
||||||
|
for _, ll := range listeners {
|
||||||
|
// Activate TLS only for TCP sockets
|
||||||
|
for i, l := range ll {
|
||||||
|
if l.Addr().Network() == "tcp" {
|
||||||
|
ll[i] = tls.NewListener(l, tlsConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return listeners, err
|
||||||
|
}
|
||||||
|
|
|
@ -73,14 +73,14 @@ func TestListeners(t *testing.T) {
|
||||||
r2.Write([]byte("Hi"))
|
r2.Write([]byte("Hi"))
|
||||||
|
|
||||||
cmd.Env = os.Environ()
|
cmd.Env = os.Environ()
|
||||||
cmd.Env = append(cmd.Env, "LISTEN_FDS=2", "FIX_LISTEN_PID=1")
|
cmd.Env = append(cmd.Env, "LISTEN_FDS=2", "LISTEN_FDNAMES=fd1:fd2", "FIX_LISTEN_PID=1")
|
||||||
|
|
||||||
out, err := cmd.Output()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println(string(out))
|
println(string(out))
|
||||||
t.Fatalf(err.Error())
|
t.Fatalf(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
correctStringWrittenNet(t, r1, "Hello world")
|
correctStringWrittenNet(t, r1, "Hello world: fd1")
|
||||||
correctStringWrittenNet(t, r2, "Goodbye world")
|
correctStringWrittenNet(t, r2, "Goodbye world: fd2")
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,13 +24,14 @@ import (
|
||||||
// The order of the file descriptors is preserved in the returned slice.
|
// The order of the file descriptors is preserved in the returned slice.
|
||||||
// Nil values are used to fill any gaps. For example if systemd were to return file descriptors
|
// Nil values are used to fill any gaps. For example if systemd were to return file descriptors
|
||||||
// corresponding with "udp, tcp, udp", then the slice would contain {net.PacketConn, nil, net.PacketConn}
|
// corresponding with "udp, tcp, udp", then the slice would contain {net.PacketConn, nil, net.PacketConn}
|
||||||
func PacketConns(unsetEnv bool) ([]net.PacketConn, error) {
|
func PacketConns() ([]net.PacketConn, error) {
|
||||||
files := Files(unsetEnv)
|
files := Files(true)
|
||||||
conns := make([]net.PacketConn, len(files))
|
conns := make([]net.PacketConn, len(files))
|
||||||
|
|
||||||
for i, f := range files {
|
for i, f := range files {
|
||||||
if pc, err := net.FilePacketConn(f); err == nil {
|
if pc, err := net.FilePacketConn(f); err == nil {
|
||||||
conns[i] = pc
|
conns[i] = pc
|
||||||
|
f.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return conns, nil
|
return conns, nil
|
||||||
|
|
|
@ -56,7 +56,7 @@ func TestPacketConns(t *testing.T) {
|
||||||
r2.Write([]byte("Hi"))
|
r2.Write([]byte("Hi"))
|
||||||
|
|
||||||
cmd.Env = os.Environ()
|
cmd.Env = os.Environ()
|
||||||
cmd.Env = append(cmd.Env, "LISTEN_FDS=2", "FIX_LISTEN_PID=1")
|
cmd.Env = append(cmd.Env, "LISTEN_FDS=2", "LISTEN_FDNAMES=fd1:fd2", "FIX_LISTEN_PID=1")
|
||||||
|
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// Copyright 2014 Docker, Inc.
|
// Copyright 2014 Docker, Inc.
|
||||||
|
// Copyright 2015-2018 CoreOS, Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -13,7 +14,11 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
// Code forked from Docker project
|
// Package daemon provides a Go implementation of the sd_notify protocol.
|
||||||
|
// It can be used to inform systemd of service start-up completion, watchdog
|
||||||
|
// events, and other status changes.
|
||||||
|
//
|
||||||
|
// https://www.freedesktop.org/software/systemd/man/sd_notify.html#Description
|
||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -21,6 +26,25 @@ import (
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SdNotifyReady tells the service manager that service startup is finished
|
||||||
|
// or the service finished loading its configuration.
|
||||||
|
SdNotifyReady = "READY=1"
|
||||||
|
|
||||||
|
// SdNotifyStopping tells the service manager that the service is beginning
|
||||||
|
// its shutdown.
|
||||||
|
SdNotifyStopping = "STOPPING=1"
|
||||||
|
|
||||||
|
// SdNotifyReloading tells the service manager that this service is
|
||||||
|
// reloading its configuration. Note that you must call SdNotifyReady when
|
||||||
|
// it completed reloading.
|
||||||
|
SdNotifyReloading = "RELOADING=1"
|
||||||
|
|
||||||
|
// SdNotifyWatchdog tells the service manager to update the watchdog
|
||||||
|
// timestamp for the service.
|
||||||
|
SdNotifyWatchdog = "WATCHDOG=1"
|
||||||
|
)
|
||||||
|
|
||||||
// SdNotify sends a message to the init daemon. It is common to ignore the error.
|
// SdNotify sends a message to the init daemon. It is common to ignore the error.
|
||||||
// If `unsetEnvironment` is true, the environment variable `NOTIFY_SOCKET`
|
// If `unsetEnvironment` is true, the environment variable `NOTIFY_SOCKET`
|
||||||
// will be unconditionally unset.
|
// will be unconditionally unset.
|
||||||
|
@ -29,7 +53,7 @@ import (
|
||||||
// (false, nil) - notification not supported (i.e. NOTIFY_SOCKET is unset)
|
// (false, nil) - notification not supported (i.e. NOTIFY_SOCKET is unset)
|
||||||
// (false, err) - notification supported, but failure happened (e.g. error connecting to NOTIFY_SOCKET or while sending data)
|
// (false, err) - notification supported, but failure happened (e.g. error connecting to NOTIFY_SOCKET or while sending data)
|
||||||
// (true, nil) - notification supported, data has been sent
|
// (true, nil) - notification supported, data has been sent
|
||||||
func SdNotify(unsetEnvironment bool, state string) (sent bool, err error) {
|
func SdNotify(unsetEnvironment bool, state string) (bool, error) {
|
||||||
socketAddr := &net.UnixAddr{
|
socketAddr := &net.UnixAddr{
|
||||||
Name: os.Getenv("NOTIFY_SOCKET"),
|
Name: os.Getenv("NOTIFY_SOCKET"),
|
||||||
Net: "unixgram",
|
Net: "unixgram",
|
||||||
|
@ -41,11 +65,10 @@ func SdNotify(unsetEnvironment bool, state string) (sent bool, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if unsetEnvironment {
|
if unsetEnvironment {
|
||||||
err = os.Unsetenv("NOTIFY_SOCKET")
|
if err := os.Unsetenv("NOTIFY_SOCKET"); err != nil {
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr)
|
conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr)
|
||||||
// Error connecting to NOTIFY_SOCKET
|
// Error connecting to NOTIFY_SOCKET
|
||||||
|
@ -54,9 +77,7 @@ func SdNotify(unsetEnvironment bool, state string) (sent bool, err error) {
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
_, err = conn.Write([]byte(state))
|
if _, err = conn.Write([]byte(state)); err != nil {
|
||||||
// Error sending the message
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
|
|
|
@ -21,10 +21,11 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SdWatchdogEnabled return watchdog information for a service.
|
// SdWatchdogEnabled returns watchdog information for a service.
|
||||||
// Process should send daemon.SdNotify("WATCHDOG=1") every time / 2.
|
// Processes should call daemon.SdNotify(false, daemon.SdNotifyWatchdog) every
|
||||||
// If `unsetEnvironment` is true, the environment variables `WATCHDOG_USEC`
|
// time / 2.
|
||||||
// and `WATCHDOG_PID` will be unconditionally unset.
|
// If `unsetEnvironment` is true, the environment variables `WATCHDOG_USEC` and
|
||||||
|
// `WATCHDOG_PID` will be unconditionally unset.
|
||||||
//
|
//
|
||||||
// It returns one of the following:
|
// It returns one of the following:
|
||||||
// (0, nil) - watchdog isn't enabled or we aren't the watched PID.
|
// (0, nil) - watchdog isn't enabled or we aren't the watched PID.
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/net/http2/hpack"
|
"golang.org/x/net/http2/hpack"
|
||||||
)
|
)
|
||||||
|
@ -197,3 +198,30 @@ func TestSorterPoolAllocs(t *testing.T) {
|
||||||
t.Logf("Keys allocs = %v; want <1", allocs)
|
t.Logf("Keys allocs = %v; want <1", allocs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// waitCondition reports whether fn eventually returned true,
|
||||||
|
// checking immediately and then every checkEvery amount,
|
||||||
|
// until waitFor has elapsed, at which point it returns false.
|
||||||
|
func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
|
||||||
|
deadline := time.Now().Add(waitFor)
|
||||||
|
for time.Now().Before(deadline) {
|
||||||
|
if fn() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
time.Sleep(checkEvery)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// waitErrCondition is like waitCondition but with errors instead of bools.
|
||||||
|
func waitErrCondition(waitFor, checkEvery time.Duration, fn func() error) error {
|
||||||
|
deadline := time.Now().Add(waitFor)
|
||||||
|
var err error
|
||||||
|
for time.Now().Before(deadline) {
|
||||||
|
if err = fn(); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
time.Sleep(checkEvery)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -1608,7 +1608,10 @@ func (sc *serverConn) processData(f *DataFrame) error {
|
||||||
// Sender sending more than they'd declared?
|
// Sender sending more than they'd declared?
|
||||||
if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
|
if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
|
||||||
st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
|
st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
|
||||||
return streamError(id, ErrCodeStreamClosed)
|
// RFC 7540, sec 8.1.2.6: A request or response is also malformed if the
|
||||||
|
// value of a content-length header field does not equal the sum of the
|
||||||
|
// DATA frame payload lengths that form the body.
|
||||||
|
return streamError(id, ErrCodeProtocol)
|
||||||
}
|
}
|
||||||
if f.Length > 0 {
|
if f.Length > 0 {
|
||||||
// Check whether the client has flow control quota.
|
// Check whether the client has flow control quota.
|
||||||
|
|
|
@ -3764,3 +3764,22 @@ func TestIssue20704Race(t *testing.T) {
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServer_Rejects_TooSmall(t *testing.T) {
|
||||||
|
testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
return nil
|
||||||
|
}, func(st *serverTester) {
|
||||||
|
st.writeHeaders(HeadersFrameParam{
|
||||||
|
StreamID: 1, // clients send odd numbers
|
||||||
|
BlockFragment: st.encodeHeader(
|
||||||
|
":method", "POST",
|
||||||
|
"content-length", "4",
|
||||||
|
),
|
||||||
|
EndStream: false, // to say DATA frames are coming
|
||||||
|
EndHeaders: true,
|
||||||
|
})
|
||||||
|
st.writeData(1, true, []byte("12345"))
|
||||||
|
|
||||||
|
st.wantRSTStream(1, ErrCodeProtocol)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -2395,11 +2395,12 @@ func TestTransportHandlerBodyClose(t *testing.T) {
|
||||||
}
|
}
|
||||||
tr.CloseIdleConnections()
|
tr.CloseIdleConnections()
|
||||||
|
|
||||||
|
if !waitCondition(5*time.Second, 100*time.Millisecond, func() bool {
|
||||||
gd := runtime.NumGoroutine() - g0
|
gd := runtime.NumGoroutine() - g0
|
||||||
if gd > numReq/2 {
|
return gd < numReq/2
|
||||||
|
}) {
|
||||||
t.Errorf("appeared to leak goroutines")
|
t.Errorf("appeared to leak goroutines")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://golang.org/issue/15930
|
// https://golang.org/issue/15930
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).
|
// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).
|
||||||
package iana // import "golang.org/x/net/internal/iana"
|
package iana // import "golang.org/x/net/internal/iana"
|
||||||
|
|
||||||
// Differentiated Services Field Codepoints (DSCP), Updated: 2017-05-12
|
// Differentiated Services Field Codepoints (DSCP), Updated: 2018-05-04
|
||||||
const (
|
const (
|
||||||
DiffServCS0 = 0x0 // CS0
|
DiffServCS0 = 0x00 // CS0
|
||||||
DiffServCS1 = 0x20 // CS1
|
DiffServCS1 = 0x20 // CS1
|
||||||
DiffServCS2 = 0x40 // CS2
|
DiffServCS2 = 0x40 // CS2
|
||||||
DiffServCS3 = 0x60 // CS3
|
DiffServCS3 = 0x60 // CS3
|
||||||
|
@ -28,14 +28,10 @@ const (
|
||||||
DiffServAF43 = 0x98 // AF43
|
DiffServAF43 = 0x98 // AF43
|
||||||
DiffServEF = 0xb8 // EF
|
DiffServEF = 0xb8 // EF
|
||||||
DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT
|
DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT
|
||||||
)
|
NotECNTransport = 0x00 // Not-ECT (Not ECN-Capable Transport)
|
||||||
|
ECNTransport1 = 0x01 // ECT(1) (ECN-Capable Transport(1))
|
||||||
// IPv4 TOS Byte and IPv6 Traffic Class Octet, Updated: 2001-09-06
|
ECNTransport0 = 0x02 // ECT(0) (ECN-Capable Transport(0))
|
||||||
const (
|
CongestionExperienced = 0x03 // CE (Congestion Experienced)
|
||||||
NotECNTransport = 0x0 // Not-ECT (Not ECN-Capable Transport)
|
|
||||||
ECNTransport1 = 0x1 // ECT(1) (ECN-Capable Transport(1))
|
|
||||||
ECNTransport0 = 0x2 // ECT(0) (ECN-Capable Transport(0))
|
|
||||||
CongestionExperienced = 0x3 // CE (Congestion Experienced)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Protocol Numbers, Updated: 2017-10-13
|
// Protocol Numbers, Updated: 2017-10-13
|
||||||
|
@ -179,7 +175,7 @@ const (
|
||||||
ProtocolReserved = 255 // Reserved
|
ProtocolReserved = 255 // Reserved
|
||||||
)
|
)
|
||||||
|
|
||||||
// Address Family Numbers, Updated: 2016-10-25
|
// Address Family Numbers, Updated: 2018-04-02
|
||||||
const (
|
const (
|
||||||
AddrFamilyIPv4 = 1 // IP (IP version 4)
|
AddrFamilyIPv4 = 1 // IP (IP version 4)
|
||||||
AddrFamilyIPv6 = 2 // IP6 (IP version 6)
|
AddrFamilyIPv6 = 2 // IP6 (IP version 6)
|
||||||
|
|
|
@ -31,16 +31,12 @@ var registries = []struct {
|
||||||
"https://www.iana.org/assignments/dscp-registry/dscp-registry.xml",
|
"https://www.iana.org/assignments/dscp-registry/dscp-registry.xml",
|
||||||
parseDSCPRegistry,
|
parseDSCPRegistry,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"https://www.iana.org/assignments/ipv4-tos-byte/ipv4-tos-byte.xml",
|
|
||||||
parseTOSTCByte,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml",
|
"https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml",
|
||||||
parseProtocolNumbers,
|
parseProtocolNumbers,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"http://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml",
|
"https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml",
|
||||||
parseAddrFamilyNumbers,
|
parseAddrFamilyNumbers,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -85,13 +81,16 @@ func parseDSCPRegistry(w io.Writer, r io.Reader) error {
|
||||||
if err := dec.Decode(&dr); err != nil {
|
if err := dec.Decode(&dr); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
drs := dr.escape()
|
|
||||||
fmt.Fprintf(w, "// %s, Updated: %s\n", dr.Title, dr.Updated)
|
fmt.Fprintf(w, "// %s, Updated: %s\n", dr.Title, dr.Updated)
|
||||||
fmt.Fprintf(w, "const (\n")
|
fmt.Fprintf(w, "const (\n")
|
||||||
for _, dr := range drs {
|
for _, dr := range dr.escapeDSCP() {
|
||||||
fmt.Fprintf(w, "DiffServ%s = %#x", dr.Name, dr.Value)
|
fmt.Fprintf(w, "DiffServ%s = %#02x", dr.Name, dr.Value)
|
||||||
fmt.Fprintf(w, "// %s\n", dr.OrigName)
|
fmt.Fprintf(w, "// %s\n", dr.OrigName)
|
||||||
}
|
}
|
||||||
|
for _, er := range dr.escapeECN() {
|
||||||
|
fmt.Fprintf(w, "%s = %#02x", er.Descr, er.Value)
|
||||||
|
fmt.Fprintf(w, "// %s\n", er.OrigDescr)
|
||||||
|
}
|
||||||
fmt.Fprintf(w, ")\n")
|
fmt.Fprintf(w, ")\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -101,15 +100,20 @@ type dscpRegistry struct {
|
||||||
Title string `xml:"title"`
|
Title string `xml:"title"`
|
||||||
Updated string `xml:"updated"`
|
Updated string `xml:"updated"`
|
||||||
Note string `xml:"note"`
|
Note string `xml:"note"`
|
||||||
RegTitle string `xml:"registry>title"`
|
Registries []struct {
|
||||||
PoolRecords []struct {
|
Title string `xml:"title"`
|
||||||
Name string `xml:"name"`
|
Registries []struct {
|
||||||
Space string `xml:"space"`
|
Title string `xml:"title"`
|
||||||
} `xml:"registry>record"`
|
|
||||||
Records []struct {
|
Records []struct {
|
||||||
Name string `xml:"name"`
|
Name string `xml:"name"`
|
||||||
Space string `xml:"space"`
|
Space string `xml:"space"`
|
||||||
} `xml:"registry>registry>record"`
|
} `xml:"record"`
|
||||||
|
} `xml:"registry"`
|
||||||
|
Records []struct {
|
||||||
|
Value string `xml:"value"`
|
||||||
|
Descr string `xml:"description"`
|
||||||
|
} `xml:"record"`
|
||||||
|
} `xml:"registry"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type canonDSCPRecord struct {
|
type canonDSCPRecord struct {
|
||||||
|
@ -118,8 +122,17 @@ type canonDSCPRecord struct {
|
||||||
Value int
|
Value int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (drr *dscpRegistry) escape() []canonDSCPRecord {
|
func (drr *dscpRegistry) escapeDSCP() []canonDSCPRecord {
|
||||||
drs := make([]canonDSCPRecord, len(drr.Records))
|
var drs []canonDSCPRecord
|
||||||
|
for _, preg := range drr.Registries {
|
||||||
|
if !strings.Contains(preg.Title, "Differentiated Services Field Codepoints") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, reg := range preg.Registries {
|
||||||
|
if !strings.Contains(reg.Title, "Pool 1 Codepoints") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
drs = make([]canonDSCPRecord, len(reg.Records))
|
||||||
sr := strings.NewReplacer(
|
sr := strings.NewReplacer(
|
||||||
"+", "",
|
"+", "",
|
||||||
"-", "",
|
"-", "",
|
||||||
|
@ -127,7 +140,7 @@ func (drr *dscpRegistry) escape() []canonDSCPRecord {
|
||||||
".", "",
|
".", "",
|
||||||
" ", "",
|
" ", "",
|
||||||
)
|
)
|
||||||
for i, dr := range drr.Records {
|
for i, dr := range reg.Records {
|
||||||
s := strings.TrimSpace(dr.Name)
|
s := strings.TrimSpace(dr.Name)
|
||||||
drs[i].OrigName = s
|
drs[i].OrigName = s
|
||||||
drs[i].Name = sr.Replace(s)
|
drs[i].Name = sr.Replace(s)
|
||||||
|
@ -137,48 +150,30 @@ func (drr *dscpRegistry) escape() []canonDSCPRecord {
|
||||||
}
|
}
|
||||||
drs[i].Value = int(n) << 2
|
drs[i].Value = int(n) << 2
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return drs
|
return drs
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTOSTCByte(w io.Writer, r io.Reader) error {
|
type canonECNRecord struct {
|
||||||
dec := xml.NewDecoder(r)
|
OrigDescr string
|
||||||
var ttb tosTCByte
|
Descr string
|
||||||
if err := dec.Decode(&ttb); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
trs := ttb.escape()
|
|
||||||
fmt.Fprintf(w, "// %s, Updated: %s\n", ttb.Title, ttb.Updated)
|
|
||||||
fmt.Fprintf(w, "const (\n")
|
|
||||||
for _, tr := range trs {
|
|
||||||
fmt.Fprintf(w, "%s = %#x", tr.Keyword, tr.Value)
|
|
||||||
fmt.Fprintf(w, "// %s\n", tr.OrigKeyword)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, ")\n")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type tosTCByte struct {
|
|
||||||
XMLName xml.Name `xml:"registry"`
|
|
||||||
Title string `xml:"title"`
|
|
||||||
Updated string `xml:"updated"`
|
|
||||||
Note string `xml:"note"`
|
|
||||||
RegTitle string `xml:"registry>title"`
|
|
||||||
Records []struct {
|
|
||||||
Binary string `xml:"binary"`
|
|
||||||
Keyword string `xml:"keyword"`
|
|
||||||
} `xml:"registry>record"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type canonTOSTCByteRecord struct {
|
|
||||||
OrigKeyword string
|
|
||||||
Keyword string
|
|
||||||
Value int
|
Value int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ttb *tosTCByte) escape() []canonTOSTCByteRecord {
|
func (drr *dscpRegistry) escapeECN() []canonECNRecord {
|
||||||
trs := make([]canonTOSTCByteRecord, len(ttb.Records))
|
var ers []canonECNRecord
|
||||||
|
for _, reg := range drr.Registries {
|
||||||
|
if !strings.Contains(reg.Title, "ECN Field") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ers = make([]canonECNRecord, len(reg.Records))
|
||||||
sr := strings.NewReplacer(
|
sr := strings.NewReplacer(
|
||||||
"Capable", "",
|
"Capable", "",
|
||||||
|
"Not-ECT", "",
|
||||||
|
"ECT(1)", "",
|
||||||
|
"ECT(0)", "",
|
||||||
|
"CE", "",
|
||||||
"(", "",
|
"(", "",
|
||||||
")", "",
|
")", "",
|
||||||
"+", "",
|
"+", "",
|
||||||
|
@ -187,23 +182,24 @@ func (ttb *tosTCByte) escape() []canonTOSTCByteRecord {
|
||||||
".", "",
|
".", "",
|
||||||
" ", "",
|
" ", "",
|
||||||
)
|
)
|
||||||
for i, tr := range ttb.Records {
|
for i, er := range reg.Records {
|
||||||
s := strings.TrimSpace(tr.Keyword)
|
s := strings.TrimSpace(er.Descr)
|
||||||
trs[i].OrigKeyword = s
|
ers[i].OrigDescr = s
|
||||||
ss := strings.Split(s, " ")
|
ss := strings.Split(s, " ")
|
||||||
if len(ss) > 1 {
|
if len(ss) > 1 {
|
||||||
trs[i].Keyword = strings.Join(ss[1:], " ")
|
ers[i].Descr = strings.Join(ss[1:], " ")
|
||||||
} else {
|
} else {
|
||||||
trs[i].Keyword = ss[0]
|
ers[i].Descr = ss[0]
|
||||||
}
|
}
|
||||||
trs[i].Keyword = sr.Replace(trs[i].Keyword)
|
ers[i].Descr = sr.Replace(er.Descr)
|
||||||
n, err := strconv.ParseUint(tr.Binary, 2, 8)
|
n, err := strconv.ParseUint(er.Value, 2, 8)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
trs[i].Value = int(n)
|
ers[i].Value = int(n)
|
||||||
}
|
}
|
||||||
return trs
|
}
|
||||||
|
return ers
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseProtocolNumbers(w io.Writer, r io.Reader) error {
|
func parseProtocolNumbers(w io.Writer, r io.Reader) error {
|
||||||
|
|
|
@ -9,5 +9,5 @@
|
||||||
TEXT ·getprocaddress(SB), 7, $0-32
|
TEXT ·getprocaddress(SB), 7, $0-32
|
||||||
JMP syscall·getprocaddress(SB)
|
JMP syscall·getprocaddress(SB)
|
||||||
|
|
||||||
TEXT ·loadlibrary(SB), 7, $0-8
|
TEXT ·loadlibrary(SB), 7, $0-24
|
||||||
JMP syscall·loadlibrary(SB)
|
JMP syscall·loadlibrary(SB)
|
||||||
|
|
|
@ -162,3 +162,4 @@ type ENUM_SERVICE_STATUS_PROCESS struct {
|
||||||
//sys ChangeServiceConfig2(service Handle, infoLevel uint32, info *byte) (err error) = advapi32.ChangeServiceConfig2W
|
//sys ChangeServiceConfig2(service Handle, infoLevel uint32, info *byte) (err error) = advapi32.ChangeServiceConfig2W
|
||||||
//sys QueryServiceConfig2(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfig2W
|
//sys QueryServiceConfig2(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfig2W
|
||||||
//sys EnumServicesStatusEx(mgr Handle, infoLevel uint32, serviceType uint32, serviceState uint32, services *byte, bufSize uint32, bytesNeeded *uint32, servicesReturned *uint32, resumeHandle *uint32, groupName *uint16) (err error) = advapi32.EnumServicesStatusExW
|
//sys EnumServicesStatusEx(mgr Handle, infoLevel uint32, serviceType uint32, serviceState uint32, services *byte, bufSize uint32, bytesNeeded *uint32, servicesReturned *uint32, resumeHandle *uint32, groupName *uint16) (err error) = advapi32.EnumServicesStatusExW
|
||||||
|
//sys QueryServiceStatusEx(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceStatusEx
|
||||||
|
|
|
@ -65,6 +65,7 @@ var (
|
||||||
procChangeServiceConfig2W = modadvapi32.NewProc("ChangeServiceConfig2W")
|
procChangeServiceConfig2W = modadvapi32.NewProc("ChangeServiceConfig2W")
|
||||||
procQueryServiceConfig2W = modadvapi32.NewProc("QueryServiceConfig2W")
|
procQueryServiceConfig2W = modadvapi32.NewProc("QueryServiceConfig2W")
|
||||||
procEnumServicesStatusExW = modadvapi32.NewProc("EnumServicesStatusExW")
|
procEnumServicesStatusExW = modadvapi32.NewProc("EnumServicesStatusExW")
|
||||||
|
procQueryServiceStatusEx = modadvapi32.NewProc("QueryServiceStatusEx")
|
||||||
procGetLastError = modkernel32.NewProc("GetLastError")
|
procGetLastError = modkernel32.NewProc("GetLastError")
|
||||||
procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
|
procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
|
||||||
procLoadLibraryExW = modkernel32.NewProc("LoadLibraryExW")
|
procLoadLibraryExW = modkernel32.NewProc("LoadLibraryExW")
|
||||||
|
@ -472,6 +473,18 @@ func EnumServicesStatusEx(mgr Handle, infoLevel uint32, serviceType uint32, serv
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func QueryServiceStatusEx(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procQueryServiceStatusEx.Addr(), 5, uintptr(service), uintptr(infoLevel), uintptr(unsafe.Pointer(buff)), uintptr(buffSize), uintptr(unsafe.Pointer(bytesNeeded)), 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func GetLastError() (lasterr error) {
|
func GetLastError() (lasterr error) {
|
||||||
r0, _, _ := syscall.Syscall(procGetLastError.Addr(), 0, 0, 0, 0)
|
r0, _, _ := syscall.Syscall(procGetLastError.Addr(), 0, 0, 0, 0)
|
||||||
if r0 != 0 {
|
if r0 != 0 {
|
||||||
|
|
Loading…
Reference in New Issue