Raw
 1package sdnotify
 2
 3import (
 4	"fmt"
 5	"math"
 6	"net"
 7	"os"
 8	"strconv"
 9	"time"
10)
11
12const (
13	SocketEnv       = "NOTIFY_SOCKET"
14	WatchdogUsecEnv = "WATCHDOG_USEC"
15	WatchdogPIDEnv  = "WATCHDOG_PID"
16)
17
18const (
19	Ready    = "READY=1"
20	Stopping = "STOPPING=1"
21	Watchdog = "WATCHDOG=1"
22)
23
24func WatchdogInterval() (time.Duration, bool) {
25	usec, err := strconv.ParseInt(os.Getenv(WatchdogUsecEnv), 10, 64)
26	if err != nil || usec <= 0 || usec > math.MaxInt64/int64(time.Microsecond) {
27		return 0, false
28	}
29	if pid := os.Getenv(WatchdogPIDEnv); pid != "" && pid != strconv.Itoa(os.Getpid()) {
30		return 0, false
31	}
32	return time.Duration(usec) * time.Microsecond, true
33}
34
35func Notify(state string) error {
36	name := os.Getenv(SocketEnv)
37	if name == "" {
38		return nil
39	}
40	if name[0] != '/' && name[0] != '@' {
41		return fmt.Errorf("%s=%q is neither an absolute path nor an abstract socket (@name)", SocketEnv, name)
42	}
43	conn, err := net.DialUnix("unixgram", nil, &net.UnixAddr{Name: name, Net: "unixgram"})
44	if err != nil {
45		return fmt.Errorf("notify %s: %w", state, err)
46	}
47	defer conn.Close()
48	if _, err := conn.Write([]byte(state)); err != nil {
49		return fmt.Errorf("notify %s: %w", state, err)
50	}
51	return nil
52}