summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrégoire Duchêne <gduchene@awhk.org>2021-06-27 19:31:23 +0100
committerGrégoire Duchêne <gduchene@awhk.org>2021-06-27 19:31:23 +0100
commitc62f3e8b39e7d1ff3d46cc4d3d599b2450b3c097 (patch)
tree8d0667e9176cdbf359530a9efe85b12eaf4559a2
parent424618a7f2f253a0529e3462ceb69607ee3c8c88 (diff)
First draft
-rw-r--r--example_test.go28
-rw-r--r--go.mod3
-rw-r--r--go.sum0
-rw-r--r--socket.go24
-rw-r--r--socket_dummy.go13
-rw-r--r--socket_linux.go59
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))
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..832b735
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module go.awhk.org/gosdd
+
+go 1.16
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go.sum
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
+}