]> git.proxmox.com Git - mirror_frr.git/blob - lib/systemd.c
Merge pull request #10400 from opensourcerouting/pim6-compilefix
[mirror_frr.git] / lib / systemd.c
1 /* lib/systemd Code
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 */
21
22 #include <zebra.h>
23 #include <sys/un.h>
24
25 #include "thread.h"
26 #include "systemd.h"
27 #include "lib_errors.h"
28
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 */
35 static pid_t watchdog_pid = -1;
36 static intmax_t watchdog_msec;
37
38 /* not used yet, but can trigger auto-switch to journald logging */
39 bool sd_stdout_is_journal;
40 bool sd_stderr_is_journal;
41
42 static char *notify_socket;
43
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().
48 */
49 static void systemd_send_information(const char *info)
50 {
51 int sock;
52 struct sockaddr_un sun;
53
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));
63
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... */
69 (void)sendto(sock, info, strlen(info), 0, (struct sockaddr *)&sun,
70 sizeof(sun));
71
72 close(sock);
73 }
74
75 void systemd_send_stopping(void)
76 {
77 systemd_send_information("STATUS=");
78 systemd_send_information("STOPPING=1");
79 }
80
81 static struct thread_master *systemd_master = NULL;
82
83 static void systemd_send_watchdog(struct thread *t)
84 {
85 systemd_send_information("WATCHDOG=1");
86
87 assert(watchdog_msec > 0);
88 thread_add_timer_msec(systemd_master, systemd_send_watchdog, NULL,
89 watchdog_msec, NULL);
90 }
91
92 void systemd_send_started(struct thread_master *m)
93 {
94 assert(m != NULL);
95
96 systemd_master = m;
97
98 systemd_send_information("READY=1");
99 if (watchdog_msec > 0)
100 systemd_send_watchdog(NULL);
101 }
102
103 void 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 }
110
111 static 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
126 void 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 }