]> git.proxmox.com Git - mirror_frr.git/blame - lib/systemd.c
Merge pull request #10987 from opensourcerouting/fix/bgp_conditional_advertisements_r...
[mirror_frr.git] / lib / systemd.c
CommitLineData
ddd82ff6 1/* lib/systemd Code
896014f4
DL
2 * Copyright (C) 2016 Cumulus Networks, Inc.
3 * Donald Sharp
4 *
5 * This file is part of Quagga.
6 *
7 * Quagga is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * Quagga is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
ddd82ff6
DS
21
22#include <zebra.h>
247898d5 23#include <sys/un.h>
ddd82ff6
DS
24
25#include "thread.h"
26#include "systemd.h"
247898d5 27#include "lib_errors.h"
ddd82ff6 28
247898d5
DL
29/* these are cleared from env so they don't "leak" into things we fork(),
30 * particularly for watchfrr starting individual daemons
31 *
32 * watchdog_pid is currently not used since watchfrr starts forking.
33 * (TODO: handle that better, somehow?)
34 */
35static pid_t watchdog_pid = -1;
36static intmax_t watchdog_msec;
37
38/* not used yet, but can trigger auto-switch to journald logging */
39bool sd_stdout_is_journal;
40bool sd_stderr_is_journal;
41
42static char *notify_socket;
ddd82ff6 43
247898d5
DL
44/* talk to whatever entity claims to be systemd ;)
45 *
46 * refer to sd_notify docs for messages systemd accepts over this socket.
47 * This function should be functionally equivalent to sd_notify().
ddd82ff6 48 */
eb51bb9b 49static void systemd_send_information(const char *info)
ddd82ff6 50{
247898d5
DL
51 int sock;
52 struct sockaddr_un sun;
ddd82ff6 53
247898d5
DL
54 if (!notify_socket)
55 return;
56
57 sock = socket(AF_UNIX, SOCK_DGRAM, 0);
58 if (sock < 0)
59 return;
60
61 sun.sun_family = AF_UNIX;
62 strlcpy(sun.sun_path, notify_socket, sizeof(sun.sun_path));
d62a17ae 63
247898d5
DL
64 /* linux abstract unix socket namespace */
65 if (sun.sun_path[0] == '@')
66 sun.sun_path[0] = '\0';
67
68 /* nothing we can do if this errors out... */
f49e0be7
DL
69 (void)sendto(sock, info, strlen(info), 0, (struct sockaddr *)&sun,
70 sizeof(sun));
247898d5
DL
71
72 close(sock);
ddd82ff6
DS
73}
74
d62a17ae 75void systemd_send_stopping(void)
ddd82ff6 76{
b3ee8bcc 77 systemd_send_information("STATUS=");
d62a17ae 78 systemd_send_information("STOPPING=1");
ddd82ff6
DS
79}
80
1b3e9a21 81static struct thread_master *systemd_master = NULL;
ddd82ff6 82
cc9f21da 83static void systemd_send_watchdog(struct thread *t)
ddd82ff6 84{
d62a17ae 85 systemd_send_information("WATCHDOG=1");
ddd82ff6 86
247898d5
DL
87 assert(watchdog_msec > 0);
88 thread_add_timer_msec(systemd_master, systemd_send_watchdog, NULL,
89 watchdog_msec, NULL);
ddd82ff6
DS
90}
91
247898d5 92void systemd_send_started(struct thread_master *m)
ddd82ff6 93{
d62a17ae 94 assert(m != NULL);
ddd82ff6 95
d62a17ae 96 systemd_master = m;
ddd82ff6 97
d62a17ae 98 systemd_send_information("READY=1");
247898d5
DL
99 if (watchdog_msec > 0)
100 systemd_send_watchdog(NULL);
ddd82ff6 101}
b3ee8bcc
DS
102
103void systemd_send_status(const char *status)
104{
105 char buffer[1024];
106
107 snprintf(buffer, sizeof(buffer), "STATUS=%s", status);
108 systemd_send_information(buffer);
109}
247898d5
DL
110
111static intmax_t getenv_int(const char *varname, intmax_t dflt)
112{
113 char *val, *err;
114 intmax_t intval;
115
116 val = getenv(varname);
117 if (!val)
118 return dflt;
119
120 intval = strtoimax(val, &err, 0);
121 if (*err || !*val)
122 return dflt;
123 return intval;
124}
125
126void systemd_init_env(void)
127{
128 char *tmp;
129 uintmax_t dev, ino;
130 int len;
131 struct stat st;
132
133 notify_socket = getenv("NOTIFY_SOCKET");
134
135 /* no point in setting up watchdog w/o notify socket */
136 if (notify_socket) {
137 intmax_t watchdog_usec;
138
139 watchdog_pid = getenv_int("WATCHDOG_PID", -1);
140 if (watchdog_pid <= 0)
141 watchdog_pid = -1;
142
143 /* note this is the deadline, hence the divide by 3 */
144 watchdog_usec = getenv_int("WATCHDOG_USEC", 0);
145 if (watchdog_usec >= 3000)
146 watchdog_msec = watchdog_usec / 3000;
147 else {
148 if (watchdog_usec != 0)
149 flog_err(
150 EC_LIB_UNAVAILABLE,
151 "systemd expects a %jd microsecond watchdog timer, but FRR only supports millisecond resolution!",
152 watchdog_usec);
153 watchdog_msec = 0;
154 }
155 }
156
157 tmp = getenv("JOURNAL_STREAM");
158 if (tmp && sscanf(tmp, "%ju:%ju%n", &dev, &ino, &len) == 2
159 && (size_t)len == strlen(tmp)) {
160 if (fstat(1, &st) == 0 && st.st_dev == (dev_t)dev
161 && st.st_ino == (ino_t)ino)
162 sd_stdout_is_journal = true;
163 if (fstat(2, &st) == 0 && st.st_dev == (dev_t)dev
164 && st.st_ino == (ino_t)ino)
165 sd_stderr_is_journal = true;
166 }
167
168 /* these should *not* be passed to any other process we start */
169 unsetenv("WATCHDOG_PID");
170 unsetenv("WATCHDOG_USEC");
171}