]> git.proxmox.com Git - mirror_frr.git/blob - lib/systemd.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / lib / systemd.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* lib/systemd Code
3 * Copyright (C) 2016 Cumulus Networks, Inc.
4 * Donald Sharp
5 */
6
7 #include <zebra.h>
8 #include <sys/un.h>
9
10 #include "thread.h"
11 #include "systemd.h"
12 #include "lib_errors.h"
13
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;
28
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().
33 */
34 static void systemd_send_information(const char *info)
35 {
36 int sock;
37 struct sockaddr_un sun;
38
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));
48
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... */
54 (void)sendto(sock, info, strlen(info), 0, (struct sockaddr *)&sun,
55 sizeof(sun));
56
57 close(sock);
58 }
59
60 void systemd_send_stopping(void)
61 {
62 systemd_send_information("STATUS=");
63 systemd_send_information("STOPPING=1");
64 }
65
66 static struct thread_master *systemd_master = NULL;
67
68 static void systemd_send_watchdog(struct thread *t)
69 {
70 systemd_send_information("WATCHDOG=1");
71
72 assert(watchdog_msec > 0);
73 thread_add_timer_msec(systemd_master, systemd_send_watchdog, NULL,
74 watchdog_msec, NULL);
75 }
76
77 void systemd_send_started(struct thread_master *m)
78 {
79 assert(m != NULL);
80
81 systemd_master = m;
82
83 systemd_send_information("READY=1");
84 if (watchdog_msec > 0)
85 systemd_send_watchdog(NULL);
86 }
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 }
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 }