]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
ddd82ff6 | 2 | /* lib/systemd Code |
896014f4 DL |
3 | * Copyright (C) 2016 Cumulus Networks, Inc. |
4 | * Donald Sharp | |
896014f4 | 5 | */ |
ddd82ff6 DS |
6 | |
7 | #include <zebra.h> | |
247898d5 | 8 | #include <sys/un.h> |
ddd82ff6 DS |
9 | |
10 | #include "thread.h" | |
11 | #include "systemd.h" | |
247898d5 | 12 | #include "lib_errors.h" |
ddd82ff6 | 13 | |
247898d5 DL |
14 | /* these are cleared from env so they don't "leak" into things we fork(), |
15 | * particularly for watchfrr starting individual daemons | |
16 | * | |
17 | * watchdog_pid is currently not used since watchfrr starts forking. | |
18 | * (TODO: handle that better, somehow?) | |
19 | */ | |
20 | static pid_t watchdog_pid = -1; | |
21 | static intmax_t watchdog_msec; | |
22 | ||
23 | /* not used yet, but can trigger auto-switch to journald logging */ | |
24 | bool sd_stdout_is_journal; | |
25 | bool sd_stderr_is_journal; | |
26 | ||
27 | static char *notify_socket; | |
ddd82ff6 | 28 | |
247898d5 DL |
29 | /* talk to whatever entity claims to be systemd ;) |
30 | * | |
31 | * refer to sd_notify docs for messages systemd accepts over this socket. | |
32 | * This function should be functionally equivalent to sd_notify(). | |
ddd82ff6 | 33 | */ |
eb51bb9b | 34 | static void systemd_send_information(const char *info) |
ddd82ff6 | 35 | { |
247898d5 DL |
36 | int sock; |
37 | struct sockaddr_un sun; | |
ddd82ff6 | 38 | |
247898d5 DL |
39 | if (!notify_socket) |
40 | return; | |
41 | ||
42 | sock = socket(AF_UNIX, SOCK_DGRAM, 0); | |
43 | if (sock < 0) | |
44 | return; | |
45 | ||
46 | sun.sun_family = AF_UNIX; | |
47 | strlcpy(sun.sun_path, notify_socket, sizeof(sun.sun_path)); | |
d62a17ae | 48 | |
247898d5 DL |
49 | /* linux abstract unix socket namespace */ |
50 | if (sun.sun_path[0] == '@') | |
51 | sun.sun_path[0] = '\0'; | |
52 | ||
53 | /* nothing we can do if this errors out... */ | |
f49e0be7 DL |
54 | (void)sendto(sock, info, strlen(info), 0, (struct sockaddr *)&sun, |
55 | sizeof(sun)); | |
247898d5 DL |
56 | |
57 | close(sock); | |
ddd82ff6 DS |
58 | } |
59 | ||
d62a17ae | 60 | void systemd_send_stopping(void) |
ddd82ff6 | 61 | { |
b3ee8bcc | 62 | systemd_send_information("STATUS="); |
d62a17ae | 63 | systemd_send_information("STOPPING=1"); |
ddd82ff6 DS |
64 | } |
65 | ||
1b3e9a21 | 66 | static struct thread_master *systemd_master = NULL; |
ddd82ff6 | 67 | |
cc9f21da | 68 | static void systemd_send_watchdog(struct thread *t) |
ddd82ff6 | 69 | { |
d62a17ae | 70 | systemd_send_information("WATCHDOG=1"); |
ddd82ff6 | 71 | |
247898d5 DL |
72 | assert(watchdog_msec > 0); |
73 | thread_add_timer_msec(systemd_master, systemd_send_watchdog, NULL, | |
74 | watchdog_msec, NULL); | |
ddd82ff6 DS |
75 | } |
76 | ||
247898d5 | 77 | void systemd_send_started(struct thread_master *m) |
ddd82ff6 | 78 | { |
d62a17ae | 79 | assert(m != NULL); |
ddd82ff6 | 80 | |
d62a17ae | 81 | systemd_master = m; |
ddd82ff6 | 82 | |
d62a17ae | 83 | systemd_send_information("READY=1"); |
247898d5 DL |
84 | if (watchdog_msec > 0) |
85 | systemd_send_watchdog(NULL); | |
ddd82ff6 | 86 | } |
b3ee8bcc DS |
87 | |
88 | void systemd_send_status(const char *status) | |
89 | { | |
90 | char buffer[1024]; | |
91 | ||
92 | snprintf(buffer, sizeof(buffer), "STATUS=%s", status); | |
93 | systemd_send_information(buffer); | |
94 | } | |
247898d5 DL |
95 | |
96 | static intmax_t getenv_int(const char *varname, intmax_t dflt) | |
97 | { | |
98 | char *val, *err; | |
99 | intmax_t intval; | |
100 | ||
101 | val = getenv(varname); | |
102 | if (!val) | |
103 | return dflt; | |
104 | ||
105 | intval = strtoimax(val, &err, 0); | |
106 | if (*err || !*val) | |
107 | return dflt; | |
108 | return intval; | |
109 | } | |
110 | ||
111 | void systemd_init_env(void) | |
112 | { | |
113 | char *tmp; | |
114 | uintmax_t dev, ino; | |
115 | int len; | |
116 | struct stat st; | |
117 | ||
118 | notify_socket = getenv("NOTIFY_SOCKET"); | |
119 | ||
120 | /* no point in setting up watchdog w/o notify socket */ | |
121 | if (notify_socket) { | |
122 | intmax_t watchdog_usec; | |
123 | ||
124 | watchdog_pid = getenv_int("WATCHDOG_PID", -1); | |
125 | if (watchdog_pid <= 0) | |
126 | watchdog_pid = -1; | |
127 | ||
128 | /* note this is the deadline, hence the divide by 3 */ | |
129 | watchdog_usec = getenv_int("WATCHDOG_USEC", 0); | |
130 | if (watchdog_usec >= 3000) | |
131 | watchdog_msec = watchdog_usec / 3000; | |
132 | else { | |
133 | if (watchdog_usec != 0) | |
134 | flog_err( | |
135 | EC_LIB_UNAVAILABLE, | |
136 | "systemd expects a %jd microsecond watchdog timer, but FRR only supports millisecond resolution!", | |
137 | watchdog_usec); | |
138 | watchdog_msec = 0; | |
139 | } | |
140 | } | |
141 | ||
142 | tmp = getenv("JOURNAL_STREAM"); | |
143 | if (tmp && sscanf(tmp, "%ju:%ju%n", &dev, &ino, &len) == 2 | |
144 | && (size_t)len == strlen(tmp)) { | |
145 | if (fstat(1, &st) == 0 && st.st_dev == (dev_t)dev | |
146 | && st.st_ino == (ino_t)ino) | |
147 | sd_stdout_is_journal = true; | |
148 | if (fstat(2, &st) == 0 && st.st_dev == (dev_t)dev | |
149 | && st.st_ino == (ino_t)ino) | |
150 | sd_stderr_is_journal = true; | |
151 | } | |
152 | ||
153 | /* these should *not* be passed to any other process we start */ | |
154 | unsetenv("WATCHDOG_PID"); | |
155 | unsetenv("WATCHDOG_USEC"); | |
156 | } |