]>
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 | |
d62a17ae | 83 | static int 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); | |
d62a17ae | 90 | return 1; |
ddd82ff6 DS |
91 | } |
92 | ||
247898d5 | 93 | void systemd_send_started(struct thread_master *m) |
ddd82ff6 | 94 | { |
d62a17ae | 95 | assert(m != NULL); |
ddd82ff6 | 96 | |
d62a17ae | 97 | systemd_master = m; |
ddd82ff6 | 98 | |
d62a17ae | 99 | systemd_send_information("READY=1"); |
247898d5 DL |
100 | if (watchdog_msec > 0) |
101 | systemd_send_watchdog(NULL); | |
ddd82ff6 | 102 | } |
b3ee8bcc DS |
103 | |
104 | void systemd_send_status(const char *status) | |
105 | { | |
106 | char buffer[1024]; | |
107 | ||
108 | snprintf(buffer, sizeof(buffer), "STATUS=%s", status); | |
109 | systemd_send_information(buffer); | |
110 | } | |
247898d5 DL |
111 | |
112 | static intmax_t getenv_int(const char *varname, intmax_t dflt) | |
113 | { | |
114 | char *val, *err; | |
115 | intmax_t intval; | |
116 | ||
117 | val = getenv(varname); | |
118 | if (!val) | |
119 | return dflt; | |
120 | ||
121 | intval = strtoimax(val, &err, 0); | |
122 | if (*err || !*val) | |
123 | return dflt; | |
124 | return intval; | |
125 | } | |
126 | ||
127 | void systemd_init_env(void) | |
128 | { | |
129 | char *tmp; | |
130 | uintmax_t dev, ino; | |
131 | int len; | |
132 | struct stat st; | |
133 | ||
134 | notify_socket = getenv("NOTIFY_SOCKET"); | |
135 | ||
136 | /* no point in setting up watchdog w/o notify socket */ | |
137 | if (notify_socket) { | |
138 | intmax_t watchdog_usec; | |
139 | ||
140 | watchdog_pid = getenv_int("WATCHDOG_PID", -1); | |
141 | if (watchdog_pid <= 0) | |
142 | watchdog_pid = -1; | |
143 | ||
144 | /* note this is the deadline, hence the divide by 3 */ | |
145 | watchdog_usec = getenv_int("WATCHDOG_USEC", 0); | |
146 | if (watchdog_usec >= 3000) | |
147 | watchdog_msec = watchdog_usec / 3000; | |
148 | else { | |
149 | if (watchdog_usec != 0) | |
150 | flog_err( | |
151 | EC_LIB_UNAVAILABLE, | |
152 | "systemd expects a %jd microsecond watchdog timer, but FRR only supports millisecond resolution!", | |
153 | watchdog_usec); | |
154 | watchdog_msec = 0; | |
155 | } | |
156 | } | |
157 | ||
158 | tmp = getenv("JOURNAL_STREAM"); | |
159 | if (tmp && sscanf(tmp, "%ju:%ju%n", &dev, &ino, &len) == 2 | |
160 | && (size_t)len == strlen(tmp)) { | |
161 | if (fstat(1, &st) == 0 && st.st_dev == (dev_t)dev | |
162 | && st.st_ino == (ino_t)ino) | |
163 | sd_stdout_is_journal = true; | |
164 | if (fstat(2, &st) == 0 && st.st_dev == (dev_t)dev | |
165 | && st.st_ino == (ino_t)ino) | |
166 | sd_stderr_is_journal = true; | |
167 | } | |
168 | ||
169 | /* these should *not* be passed to any other process we start */ | |
170 | unsetenv("WATCHDOG_PID"); | |
171 | unsetenv("WATCHDOG_USEC"); | |
172 | } |