49 lines
1.3 KiB
Go
49 lines
1.3 KiB
Go
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
// Package sdnotify implements the small systemd notification subset needed by
|
|
// the service binary without adding a runtime dependency.
|
|
package sdnotify
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
// Notifier sends state records to the socket inherited from systemd. An empty
|
|
// socket makes Notify a no-op so the agent behaves identically outside a unit.
|
|
type Notifier struct {
|
|
socket string
|
|
}
|
|
|
|
// FromEnvironment returns a notifier for systemd's NOTIFY_SOCKET contract.
|
|
func FromEnvironment() Notifier {
|
|
return New(os.Getenv("NOTIFY_SOCKET"))
|
|
}
|
|
|
|
// New constructs a notifier for an explicit socket, primarily for tests.
|
|
func New(socket string) Notifier {
|
|
return Notifier{socket: socket}
|
|
}
|
|
|
|
// Notify sends one newline-delimited systemd state record.
|
|
func (n Notifier) Notify(state string) error {
|
|
if n.socket == "" {
|
|
return nil
|
|
}
|
|
if state == "" || strings.ContainsRune(state, '\x00') {
|
|
return fmt.Errorf("invalid empty or NUL-containing notification")
|
|
}
|
|
connection, err := net.DialUnix(
|
|
"unixgram", nil, &net.UnixAddr{Name: n.socket, Net: "unixgram"},
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("connect notify socket: %w", err)
|
|
}
|
|
defer connection.Close()
|
|
if _, err := connection.Write([]byte(state)); err != nil {
|
|
return fmt.Errorf("write notify socket: %w", err)
|
|
}
|
|
return nil
|
|
}
|