summaryrefslogtreecommitdiff
path: root/sd_daemon/notify.go
diff options
context:
space:
mode:
Diffstat (limited to 'sd_daemon/notify.go')
-rw-r--r--sd_daemon/notify.go95
1 files changed, 7 insertions, 88 deletions
diff --git a/sd_daemon/notify.go b/sd_daemon/notify.go
index 917e2d4..9591613 100644
--- a/sd_daemon/notify.go
+++ b/sd_daemon/notify.go
@@ -3,7 +3,7 @@
//
// Copyright 2013, 2015 Docker, Inc.
// Copyright 2014 CoreOS, Inc.
-// Copyright 2015-2018 Luke Shumaker
+// Copyright 2015-2019 Luke Shumaker
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -17,16 +17,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build linux
-
package sd_daemon
import (
- "bytes"
- "net"
"os"
-
- "golang.org/x/sys/unix"
)
// Notification is a message to be sent to the service manager about
@@ -36,6 +30,11 @@ type Notification struct {
// If PID <= 0, or if the current process does not have
// privileges to send messages on behalf of other processes,
// then the message is simply sent from the current process.
+ //
+ // BUG(lukeshu): Spoofing the PID is not implemented on
+ // non-Linux kernels. If you are knowledgable about how to do
+ // this on other kernels, please let me know at
+ // <lukeshu@lukeshu.com>!
PID int
// State should contain a newline-separated list of variable
@@ -75,85 +74,5 @@ type Notification struct {
// support both service managers that support these notifications and
// those that do not.
func (msg Notification) Send(unsetEnv bool) error {
- if unsetEnv {
- defer func() { _ = os.Unsetenv("NOTIFY_SOCKET") }()
- }
-
- socketAddr := &net.UnixAddr{
- Name: os.Getenv("NOTIFY_SOCKET"),
- Net: "unixgram",
- }
-
- if socketAddr.Name == "" {
- return ErrDisabled
- }
-
- conn, err := socketUnixgram(socketAddr.Name)
- if err != nil {
- return err
- }
- defer func() { _ = conn.Close() }()
-
- var cmsgs [][]byte
-
- if len(msg.Files) > 0 {
- fds := make([]int, len(msg.Files))
- for i := range msg.Files {
- fds[i] = int(msg.Files[i].Fd())
- }
- cmsg := unix.UnixRights(fds...)
- cmsgs = append(cmsgs, cmsg)
- }
-
- havePid := msg.PID > 0 && msg.PID != os.Getpid()
- if havePid {
- cmsg := unix.UnixCredentials(&unix.Ucred{
- Pid: int32(msg.PID),
- Uid: uint32(os.Getuid()),
- Gid: uint32(os.Getgid()),
- })
- cmsgs = append(cmsgs, cmsg)
- }
-
- // If the 2nd argument is empty, this is equivalent to
- //
- // conn, _ := net.DialUnix(socketAddr.Net, nil, socketAddr)
- // conn.Write([]byte(msg.State))
- _, _, err = conn.WriteMsgUnix([]byte(msg.State), bytes.Join(cmsgs, nil), socketAddr)
-
- if err != nil && havePid {
- // Maybe it failed because we don't have privileges to
- // spoof our pid; retry without spoofing the pid.
- //
- // I'm not too happy that we do this silently without
- // notifying the caller, but that's what
- // sd_pid_notify_with_fds does.
- cmsgs = cmsgs[:len(cmsgs)-1]
- _, _, err = conn.WriteMsgUnix([]byte(msg.State), bytes.Join(cmsgs, nil), socketAddr)
- }
-
- return err
-}
-
-// socketUnixgram wraps socket(2), but doesn't bind(2) or connect(2)
-// the socket to anything. This is an ugly hack because none of the
-// functions in "net" actually allow you to get a AF_UNIX socket not
-// bound/connected to anything.
-//
-// At some point you begin to question if it is worth it to keep up
-// the high-level interface of "net", and messing around with FileConn
-// and UnixConn. Maybe we just drop to using unix.Socket and
-// unix.SendmsgN directly.
-func socketUnixgram(name string) (*net.UnixConn, error) {
- fd, err := unix.Socket(unix.AF_UNIX, unix.SOCK_DGRAM|unix.SOCK_CLOEXEC, 0)
- if err != nil {
- return nil, os.NewSyscallError("socket", err)
- }
- defer unix.Close(fd)
- conn, err := net.FileConn(os.NewFile(uintptr(fd), name))
- if err != nil {
- return nil, err
- }
- unixConn := conn.(*net.UnixConn)
- return unixConn, nil
+ return msg.send(unsetEnv)
}