-
Notifications
You must be signed in to change notification settings - Fork 1
/
systemd_sockets.go
76 lines (64 loc) · 1.7 KB
/
systemd_sockets.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package util
import (
"errors"
"net"
"os"
"strconv"
"strings"
"syscall"
)
const (
// listenFdsStart corresponds to `SD_LISTEN_FDS_START`.
listenFdsStart = 3
)
var ErrSocketNotFound = errors.New("socket not found")
var socketFiles []*os.File
// socketFiles returns a slice containing a `os.File` object for each file
// descriptor passed to this process via systemd fd-passing protocol. I stole
// this code from the go-systemd project
func getSocketFiles() []*os.File {
if socketFiles != nil {
return socketFiles
}
pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
if err != nil || pid != os.Getpid() {
return nil
}
nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS"))
if err != nil || nfds == 0 {
return nil
}
names := strings.Split(os.Getenv("LISTEN_FDNAMES"), ":")
files := make([]*os.File, 0, nfds)
for fd := listenFdsStart; fd < listenFdsStart+nfds; fd++ {
syscall.CloseOnExec(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))
}
socketFiles = files
return files
}
// SystemdSocketByName returns a net.Listener if there is a systemd socket with
// that name available
func SystemdListenerByName(name string) (net.Listener, error) {
for _, f := range getSocketFiles() {
if f.Name() == name {
return net.FileListener(f)
}
}
return nil, ErrSocketNotFound
}
// SystemdFileByName returns a *os.File if there is a systemd socket with that
// name available
func SystemdFileByName(name string) (*os.File, error) {
for _, f := range getSocketFiles() {
if f.Name() == name {
return f, nil
}
}
return nil, ErrSocketNotFound
}