]> git.proxmox.com Git - mirror_frr.git/blame - lib/systemd.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / lib / systemd.c
CommitLineData
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 */
20static pid_t watchdog_pid = -1;
21static intmax_t watchdog_msec;
22
23/* not used yet, but can trigger auto-switch to journald logging */
24bool sd_stdout_is_journal;
25bool sd_stderr_is_journal;
26
27static 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 34static 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 60void systemd_send_stopping(void)
ddd82ff6 61{
b3ee8bcc 62 systemd_send_information("STATUS=");
d62a17ae 63 systemd_send_information("STOPPING=1");
ddd82ff6
DS
64}
65
1b3e9a21 66static struct thread_master *systemd_master = NULL;
ddd82ff6 67
cc9f21da 68static 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 77void 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
88void 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
96static 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
111void 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}