Line data Source code
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 0 : static void systemd_send_information(const char *info)
50 : {
51 0 : int sock;
52 0 : struct sockaddr_un sun;
53 :
54 0 : if (!notify_socket)
55 0 : return;
56 :
57 0 : sock = socket(AF_UNIX, SOCK_DGRAM, 0);
58 0 : if (sock < 0)
59 : return;
60 :
61 0 : sun.sun_family = AF_UNIX;
62 0 : strlcpy(sun.sun_path, notify_socket, sizeof(sun.sun_path));
63 :
64 : /* linux abstract unix socket namespace */
65 0 : if (sun.sun_path[0] == '@')
66 0 : sun.sun_path[0] = '\0';
67 :
68 : /* nothing we can do if this errors out... */
69 0 : (void)sendto(sock, info, strlen(info), 0, (struct sockaddr *)&sun,
70 : sizeof(sun));
71 :
72 0 : close(sock);
73 : }
74 :
75 0 : void systemd_send_stopping(void)
76 : {
77 0 : systemd_send_information("STATUS=");
78 0 : systemd_send_information("STOPPING=1");
79 0 : }
80 :
81 : static struct thread_master *systemd_master = NULL;
82 :
83 0 : static void systemd_send_watchdog(struct thread *t)
84 : {
85 0 : systemd_send_information("WATCHDOG=1");
86 :
87 0 : assert(watchdog_msec > 0);
88 0 : thread_add_timer_msec(systemd_master, systemd_send_watchdog, NULL,
89 : watchdog_msec, NULL);
90 0 : }
91 :
92 0 : void systemd_send_started(struct thread_master *m)
93 : {
94 0 : assert(m != NULL);
95 :
96 0 : systemd_master = m;
97 :
98 0 : systemd_send_information("READY=1");
99 0 : if (watchdog_msec > 0)
100 0 : systemd_send_watchdog(NULL);
101 0 : }
102 :
103 0 : void systemd_send_status(const char *status)
104 : {
105 0 : char buffer[1024];
106 :
107 0 : snprintf(buffer, sizeof(buffer), "STATUS=%s", status);
108 0 : systemd_send_information(buffer);
109 0 : }
110 :
111 0 : static intmax_t getenv_int(const char *varname, intmax_t dflt)
112 : {
113 0 : char *val, *err;
114 0 : intmax_t intval;
115 :
116 0 : val = getenv(varname);
117 0 : if (!val)
118 : return dflt;
119 :
120 0 : intval = strtoimax(val, &err, 0);
121 0 : if (*err || !*val)
122 : return dflt;
123 : return intval;
124 : }
125 :
126 8 : void systemd_init_env(void)
127 : {
128 8 : char *tmp;
129 8 : uintmax_t dev, ino;
130 8 : int len;
131 8 : struct stat st;
132 :
133 8 : notify_socket = getenv("NOTIFY_SOCKET");
134 :
135 : /* no point in setting up watchdog w/o notify socket */
136 8 : if (notify_socket) {
137 0 : intmax_t watchdog_usec;
138 :
139 0 : watchdog_pid = getenv_int("WATCHDOG_PID", -1);
140 0 : if (watchdog_pid <= 0)
141 0 : watchdog_pid = -1;
142 :
143 : /* note this is the deadline, hence the divide by 3 */
144 0 : watchdog_usec = getenv_int("WATCHDOG_USEC", 0);
145 0 : if (watchdog_usec >= 3000)
146 0 : watchdog_msec = watchdog_usec / 3000;
147 : else {
148 0 : if (watchdog_usec != 0)
149 0 : flog_err(
150 : EC_LIB_UNAVAILABLE,
151 : "systemd expects a %jd microsecond watchdog timer, but FRR only supports millisecond resolution!",
152 : watchdog_usec);
153 0 : watchdog_msec = 0;
154 : }
155 : }
156 :
157 8 : tmp = getenv("JOURNAL_STREAM");
158 8 : if (tmp && sscanf(tmp, "%ju:%ju%n", &dev, &ino, &len) == 2
159 8 : && (size_t)len == strlen(tmp)) {
160 8 : if (fstat(1, &st) == 0 && st.st_dev == (dev_t)dev
161 0 : && st.st_ino == (ino_t)ino)
162 0 : sd_stdout_is_journal = true;
163 8 : if (fstat(2, &st) == 0 && st.st_dev == (dev_t)dev
164 0 : && st.st_ino == (ino_t)ino)
165 0 : sd_stderr_is_journal = true;
166 : }
167 :
168 : /* these should *not* be passed to any other process we start */
169 8 : unsetenv("WATCHDOG_PID");
170 8 : unsetenv("WATCHDOG_USEC");
171 8 : }
|