]>
Commit | Line | Data |
---|---|---|
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 | */ | |
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; | |
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 | 49 | static 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 | 75 | void systemd_send_stopping(void) |
ddd82ff6 | 76 | { |
b3ee8bcc | 77 | systemd_send_information("STATUS="); |
d62a17ae | 78 | systemd_send_information("STOPPING=1"); |
ddd82ff6 DS |
79 | } |
80 | ||
1b3e9a21 | 81 | static struct thread_master *systemd_master = NULL; |
ddd82ff6 | 82 | |
cc9f21da | 83 | static 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 | 92 | void 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 | |
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 | } | |
247898d5 DL |
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 | } |