diff options
| -rw-r--r-- | example_test.go | 28 | ||||
| -rw-r--r-- | go.mod | 3 | ||||
| -rw-r--r-- | go.sum | 0 | ||||
| -rw-r--r-- | socket.go | 24 | ||||
| -rw-r--r-- | socket_dummy.go | 13 | ||||
| -rw-r--r-- | socket_linux.go | 59 |
6 files changed, 127 insertions, 0 deletions
diff --git a/example_test.go b/example_test.go new file mode 100644 index 0000000..e12eaa7 --- /dev/null +++ b/example_test.go @@ -0,0 +1,28 @@ +package gosdd_test + +import ( + "log" + "net" + "net/http" + + "go.awhk.org/gosdd" +) + +// This example gets the file descriptors passed to the process by +// systemd and starts a server using it. +func ExampleSDListenFDs() { + fds, err := gosdd.SDListenFDs(true) + if err != nil { + log.Fatalf("Error while getting file descriptors: %s.", err) + } + if len(fds) != 1 { + log.Fatalln("Exactly one file descriptor can be handled.") + } + + ln, err := net.FileListener(fds[0]) + if err != nil { + log.Fatalf("Failed to create listener: %s.", err) + } + srv := http.Server{Handler: http.FileServer(http.Dir("/tmp"))} + log.Println(srv.Serve(ln)) +} @@ -0,0 +1,3 @@ +module go.awhk.org/gosdd + +go 1.16 diff --git a/socket.go b/socket.go new file mode 100644 index 0000000..941d5f0 --- /dev/null +++ b/socket.go @@ -0,0 +1,24 @@ +// Package gosdd provides simple wrappers around useful functions +// provided by systemd. +// +// On systems that are not Linux, or if the nosystemd build tag is set, +// safe defaults are returned: zero or nil values, and no error will be +// returned. +// +// Reference +// +// https://www.freedesktop.org/software/systemd/man/sd_listen_fds.html +// is the documentation for the C API. +package gosdd + +import "os" + +// SDListenFDs is a wrapper around sd_listen_fds. +func SDListenFDs(unsetenv bool) ([]*os.File, error) { + return sdListenFDs(unsetenv) +} + +// SDListenFDsWithNames is a wrapper around sd_listen_fds_with_names. +func SDListenFDsWithNames(unsetenv bool) (map[string]*os.File, error) { + return sdListenFDsWithNames(unsetenv) +} diff --git a/socket_dummy.go b/socket_dummy.go new file mode 100644 index 0000000..d540f1b --- /dev/null +++ b/socket_dummy.go @@ -0,0 +1,13 @@ +// +build !linux nosystemd + +package gosdd + +import "os" + +func sdListenFDs(bool) ([]*os.File, error) { + return nil, nil +} + +func sdListenFDsWithNames(bool) (map[string]*os.File, error) { + return nil, nil +} diff --git a/socket_linux.go b/socket_linux.go new file mode 100644 index 0000000..8360318 --- /dev/null +++ b/socket_linux.go @@ -0,0 +1,59 @@ +// +build linux,!nosystemd + +package gosdd + +// #cgo LDFLAGS: -lsystemd +// #include <stdlib.h> +// #include <string.h> +// #include <systemd/sd-daemon.h> +import "C" + +import ( + "fmt" + "os" + "unsafe" +) + +func sdListenFDs(unsetenv bool) ([]*os.File, error) { + i := C.int(0) + if unsetenv { + i = C.int(1) + } + c := C.sd_listen_fds(i) + if c < 0 { + return nil, fmt.Errorf("sd_listen_fds: %s", C.GoString(C.strerror(-c))) + } + if c == 0 { + return nil, nil + } + fds := make([]*os.File, 0, c) + for fd := uintptr(C.SD_LISTEN_FDS_START); fd < uintptr(C.SD_LISTEN_FDS_START+c); fd++ { + fds = append(fds, os.NewFile(fd, "")) + } + return fds, nil +} + +func sdListenFDsWithNames(unsetenv bool) (map[string]*os.File, error) { + i := C.int(0) + if unsetenv { + i = C.int(1) + } + var arr **C.char + c := C.sd_listen_fds_with_names(i, &arr) + if c < 0 { + return nil, fmt.Errorf("sd_listen_fds_with_names: %s", C.GoString(C.strerror(-c))) + } + if c == 0 { + return nil, nil + } + // See https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices. + names := (*[1 << 28]*C.char)(unsafe.Pointer(arr))[:c:c] + fds := make(map[string]*os.File) + for fd := uintptr(C.SD_LISTEN_FDS_START); fd < uintptr(C.SD_LISTEN_FDS_START+c); fd++ { + name := C.GoString(names[int(fd-C.SD_LISTEN_FDS_START)]) + fds[name] = os.NewFile(fd, name) + C.free(unsafe.Pointer(names[int(fd-C.SD_LISTEN_FDS_START)])) + } + C.free(unsafe.Pointer(arr)) + return fds, nil +} |
