Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <errno.h>
4 : : #include <poll.h>
5 : : #include <string.h>
6 : : #include <sys/inotify.h>
7 : :
8 : : #include "sd-network.h"
9 : :
10 : : #include "alloc-util.h"
11 : : #include "env-file.h"
12 : : #include "fd-util.h"
13 : : #include "fs-util.h"
14 : : #include "macro.h"
15 : : #include "parse-util.h"
16 : : #include "stdio-util.h"
17 : : #include "string-util.h"
18 : : #include "strv.h"
19 : : #include "util.h"
20 : :
21 : 0 : static int network_get_string(const char *field, char **ret) {
22 : 0 : _cleanup_free_ char *s = NULL;
23 : : int r;
24 : :
25 [ # # # # ]: 0 : assert_return(ret, -EINVAL);
26 : :
27 : 0 : r = parse_env_file(NULL, "/run/systemd/netif/state", field, &s);
28 [ # # ]: 0 : if (r == -ENOENT)
29 : 0 : return -ENODATA;
30 [ # # ]: 0 : if (r < 0)
31 : 0 : return r;
32 [ # # ]: 0 : if (isempty(s))
33 : 0 : return -ENODATA;
34 : :
35 : 0 : *ret = TAKE_PTR(s);
36 : :
37 : 0 : return 0;
38 : : }
39 : :
40 : 0 : _public_ int sd_network_get_operational_state(char **state) {
41 : 0 : return network_get_string("OPER_STATE", state);
42 : : }
43 : :
44 : 0 : _public_ int sd_network_get_carrier_state(char **state) {
45 : 0 : return network_get_string("CARRIER_STATE", state);
46 : : }
47 : :
48 : 0 : _public_ int sd_network_get_address_state(char **state) {
49 : 0 : return network_get_string("ADDRESS_STATE", state);
50 : : }
51 : :
52 : 4 : static int network_get_strv(const char *key, char ***ret) {
53 : 4 : _cleanup_strv_free_ char **a = NULL;
54 : 4 : _cleanup_free_ char *s = NULL;
55 : : int r;
56 : :
57 [ - + - + ]: 4 : assert_return(ret, -EINVAL);
58 : :
59 : 4 : r = parse_env_file(NULL, "/run/systemd/netif/state", key, &s);
60 [ + - ]: 4 : if (r == -ENOENT)
61 : 4 : return -ENODATA;
62 [ # # ]: 0 : if (r < 0)
63 : 0 : return r;
64 [ # # ]: 0 : if (isempty(s)) {
65 : 0 : *ret = NULL;
66 : 0 : return 0;
67 : : }
68 : :
69 : 0 : a = strv_split(s, " ");
70 [ # # ]: 0 : if (!a)
71 : 0 : return -ENOMEM;
72 : :
73 : 0 : strv_uniq(a);
74 : 0 : r = (int) strv_length(a);
75 : :
76 : 0 : *ret = TAKE_PTR(a);
77 : :
78 : 0 : return r;
79 : : }
80 : :
81 : 0 : _public_ int sd_network_get_dns(char ***ret) {
82 : 0 : return network_get_strv("DNS", ret);
83 : : }
84 : :
85 : 4 : _public_ int sd_network_get_ntp(char ***ret) {
86 : 4 : return network_get_strv("NTP", ret);
87 : : }
88 : :
89 : 0 : _public_ int sd_network_get_search_domains(char ***ret) {
90 : 0 : return network_get_strv("DOMAINS", ret);
91 : : }
92 : :
93 : 0 : _public_ int sd_network_get_route_domains(char ***ret) {
94 : 0 : return network_get_strv("ROUTE_DOMAINS", ret);
95 : : }
96 : :
97 : 0 : static int network_link_get_string(int ifindex, const char *field, char **ret) {
98 : : char path[STRLEN("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
99 : 0 : _cleanup_free_ char *s = NULL;
100 : : int r;
101 : :
102 [ # # # # ]: 0 : assert_return(ifindex > 0, -EINVAL);
103 [ # # # # ]: 0 : assert_return(ret, -EINVAL);
104 : :
105 [ # # ]: 0 : xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
106 : :
107 : 0 : r = parse_env_file(NULL, path, field, &s);
108 [ # # ]: 0 : if (r == -ENOENT)
109 : 0 : return -ENODATA;
110 [ # # ]: 0 : if (r < 0)
111 : 0 : return r;
112 [ # # ]: 0 : if (isempty(s))
113 : 0 : return -ENODATA;
114 : :
115 : 0 : *ret = TAKE_PTR(s);
116 : :
117 : 0 : return 0;
118 : : }
119 : :
120 : 0 : static int network_link_get_strv(int ifindex, const char *key, char ***ret) {
121 : : char path[STRLEN("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
122 : 0 : _cleanup_strv_free_ char **a = NULL;
123 : 0 : _cleanup_free_ char *s = NULL;
124 : : int r;
125 : :
126 [ # # # # ]: 0 : assert_return(ifindex > 0, -EINVAL);
127 [ # # # # ]: 0 : assert_return(ret, -EINVAL);
128 : :
129 [ # # ]: 0 : xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
130 : 0 : r = parse_env_file(NULL, path, key, &s);
131 [ # # ]: 0 : if (r == -ENOENT)
132 : 0 : return -ENODATA;
133 [ # # ]: 0 : if (r < 0)
134 : 0 : return r;
135 [ # # ]: 0 : if (isempty(s)) {
136 : 0 : *ret = NULL;
137 : 0 : return 0;
138 : : }
139 : :
140 : 0 : a = strv_split(s, " ");
141 [ # # ]: 0 : if (!a)
142 : 0 : return -ENOMEM;
143 : :
144 : 0 : strv_uniq(a);
145 : 0 : r = (int) strv_length(a);
146 : :
147 : 0 : *ret = TAKE_PTR(a);
148 : :
149 : 0 : return r;
150 : : }
151 : :
152 : 0 : _public_ int sd_network_link_get_setup_state(int ifindex, char **state) {
153 : 0 : return network_link_get_string(ifindex, "ADMIN_STATE", state);
154 : : }
155 : :
156 : 0 : _public_ int sd_network_link_get_network_file(int ifindex, char **filename) {
157 : 0 : return network_link_get_string(ifindex, "NETWORK_FILE", filename);
158 : : }
159 : :
160 : 0 : _public_ int sd_network_link_get_operational_state(int ifindex, char **state) {
161 : 0 : return network_link_get_string(ifindex, "OPER_STATE", state);
162 : : }
163 : :
164 : 0 : _public_ int sd_network_link_get_carrier_state(int ifindex, char **state) {
165 : 0 : return network_link_get_string(ifindex, "CARRIER_STATE", state);
166 : : }
167 : :
168 : 0 : _public_ int sd_network_link_get_address_state(int ifindex, char **state) {
169 : 0 : return network_link_get_string(ifindex, "ADDRESS_STATE", state);
170 : : }
171 : :
172 : 0 : _public_ int sd_network_link_get_required_for_online(int ifindex) {
173 : 0 : _cleanup_free_ char *s = NULL;
174 : : int r;
175 : :
176 : 0 : r = network_link_get_string(ifindex, "REQUIRED_FOR_ONLINE", &s);
177 [ # # ]: 0 : if (r < 0) {
178 : : /* Handle -ENODATA as RequiredForOnline=yes, for compatibility */
179 [ # # ]: 0 : if (r == -ENODATA)
180 : 0 : return true;
181 : 0 : return r;
182 : : }
183 : :
184 : 0 : return parse_boolean(s);
185 : : }
186 : :
187 : 0 : _public_ int sd_network_link_get_required_operstate_for_online(int ifindex, char **state) {
188 : 0 : _cleanup_free_ char *s = NULL;
189 : : int r;
190 : :
191 [ # # # # ]: 0 : assert_return(state, -EINVAL);
192 : :
193 : 0 : r = network_link_get_string(ifindex, "REQUIRED_OPER_STATE_FOR_ONLINE", &s);
194 [ # # ]: 0 : if (r < 0) {
195 [ # # ]: 0 : if (r != -ENODATA)
196 : 0 : return r;
197 : :
198 : : /* For compatibility, assuming degraded. */
199 : 0 : s = strdup("degraded");
200 [ # # ]: 0 : if (!s)
201 : 0 : return -ENOMEM;
202 : : }
203 : :
204 : 0 : *state = TAKE_PTR(s);
205 : 0 : return 0;
206 : : }
207 : :
208 : 0 : _public_ int sd_network_link_get_llmnr(int ifindex, char **llmnr) {
209 : 0 : return network_link_get_string(ifindex, "LLMNR", llmnr);
210 : : }
211 : :
212 : 0 : _public_ int sd_network_link_get_mdns(int ifindex, char **mdns) {
213 : 0 : return network_link_get_string(ifindex, "MDNS", mdns);
214 : : }
215 : :
216 : 0 : _public_ int sd_network_link_get_dns_over_tls(int ifindex, char **dns_over_tls) {
217 : 0 : return network_link_get_string(ifindex, "DNS_OVER_TLS", dns_over_tls);
218 : : }
219 : :
220 : 0 : _public_ int sd_network_link_get_dnssec(int ifindex, char **dnssec) {
221 : 0 : return network_link_get_string(ifindex, "DNSSEC", dnssec);
222 : : }
223 : :
224 : 0 : _public_ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char ***nta) {
225 : 0 : return network_link_get_strv(ifindex, "DNSSEC_NTA", nta);
226 : : }
227 : :
228 : 0 : _public_ int sd_network_link_get_timezone(int ifindex, char **ret) {
229 : 0 : return network_link_get_string(ifindex, "TIMEZONE", ret);
230 : : }
231 : :
232 : 0 : _public_ int sd_network_link_get_dns(int ifindex, char ***ret) {
233 : 0 : return network_link_get_strv(ifindex, "DNS", ret);
234 : : }
235 : :
236 : 0 : _public_ int sd_network_link_get_ntp(int ifindex, char ***ret) {
237 : 0 : return network_link_get_strv(ifindex, "NTP", ret);
238 : : }
239 : :
240 : 0 : _public_ int sd_network_link_get_search_domains(int ifindex, char ***ret) {
241 : 0 : return network_link_get_strv(ifindex, "DOMAINS", ret);
242 : : }
243 : :
244 : 0 : _public_ int sd_network_link_get_route_domains(int ifindex, char ***ret) {
245 : 0 : return network_link_get_strv(ifindex, "ROUTE_DOMAINS", ret);
246 : : }
247 : :
248 : 0 : _public_ int sd_network_link_get_dns_default_route(int ifindex) {
249 : : char path[STRLEN("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
250 : 0 : _cleanup_free_ char *s = NULL;
251 : : int r;
252 : :
253 [ # # # # ]: 0 : assert_return(ifindex > 0, -EINVAL);
254 : :
255 [ # # ]: 0 : xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
256 : :
257 : 0 : r = parse_env_file(NULL, path, "DNS_DEFAULT_ROUTE", &s);
258 [ # # ]: 0 : if (r == -ENOENT)
259 : 0 : return -ENODATA;
260 [ # # ]: 0 : if (r < 0)
261 : 0 : return r;
262 [ # # ]: 0 : if (isempty(s))
263 : 0 : return -ENODATA;
264 : 0 : return parse_boolean(s);
265 : : }
266 : :
267 : 0 : static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) {
268 : : char path[STRLEN("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
269 : 0 : _cleanup_free_ int *ifis = NULL;
270 : 0 : _cleanup_free_ char *s = NULL;
271 : 0 : size_t allocated = 0, c = 0;
272 : : const char *x;
273 : : int r;
274 : :
275 [ # # # # ]: 0 : assert_return(ifindex > 0, -EINVAL);
276 [ # # # # ]: 0 : assert_return(ret, -EINVAL);
277 : :
278 [ # # ]: 0 : xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
279 : 0 : r = parse_env_file(NULL, path, key, &s);
280 [ # # ]: 0 : if (r == -ENOENT)
281 : 0 : return -ENODATA;
282 [ # # ]: 0 : if (r < 0)
283 : 0 : return r;
284 : :
285 : 0 : for (x = s;;) {
286 [ # # # ]: 0 : _cleanup_free_ char *word = NULL;
287 : :
288 : 0 : r = extract_first_word(&x, &word, NULL, 0);
289 [ # # ]: 0 : if (r < 0)
290 : 0 : return r;
291 [ # # ]: 0 : if (r == 0)
292 : 0 : break;
293 : :
294 : 0 : r = parse_ifindex(word, &ifindex);
295 [ # # ]: 0 : if (r < 0)
296 : 0 : return r;
297 : :
298 [ # # ]: 0 : if (!GREEDY_REALLOC(ifis, allocated, c + 2))
299 : 0 : return -ENOMEM;
300 : :
301 : 0 : ifis[c++] = ifindex;
302 : : }
303 : :
304 [ # # ]: 0 : if (ifis)
305 : 0 : ifis[c] = 0; /* Let's add a 0 ifindex to the end, to be nice */
306 : :
307 : 0 : *ret = TAKE_PTR(ifis);
308 : :
309 : 0 : return c;
310 : : }
311 : :
312 : 0 : _public_ int sd_network_link_get_carrier_bound_to(int ifindex, int **ret) {
313 : 0 : return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_TO", ret);
314 : : }
315 : :
316 : 0 : _public_ int sd_network_link_get_carrier_bound_by(int ifindex, int **ret) {
317 : 0 : return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_BY", ret);
318 : : }
319 : :
320 : 8 : static int MONITOR_TO_FD(sd_network_monitor *m) {
321 : 8 : return (int) (unsigned long) m - 1;
322 : : }
323 : :
324 : 4 : static sd_network_monitor* FD_TO_MONITOR(int fd) {
325 : 4 : return (sd_network_monitor*) (unsigned long) (fd + 1);
326 : : }
327 : :
328 : 4 : static int monitor_add_inotify_watch(int fd) {
329 : : int k;
330 : :
331 : 4 : k = inotify_add_watch(fd, "/run/systemd/netif/links/", IN_MOVED_TO|IN_DELETE);
332 [ + - ]: 4 : if (k >= 0)
333 : 4 : return 0;
334 [ # # ]: 0 : else if (errno != ENOENT)
335 : 0 : return -errno;
336 : :
337 : 0 : k = inotify_add_watch(fd, "/run/systemd/netif/", IN_CREATE|IN_ISDIR);
338 [ # # ]: 0 : if (k >= 0)
339 : 0 : return 0;
340 [ # # ]: 0 : else if (errno != ENOENT)
341 : 0 : return -errno;
342 : :
343 : 0 : k = inotify_add_watch(fd, "/run/systemd/", IN_CREATE|IN_ISDIR);
344 [ # # ]: 0 : if (k < 0)
345 : 0 : return -errno;
346 : :
347 : 0 : return 0;
348 : : }
349 : :
350 : 4 : _public_ int sd_network_monitor_new(sd_network_monitor **m, const char *category) {
351 : 4 : _cleanup_close_ int fd = -1;
352 : : int k;
353 : 4 : bool good = false;
354 : :
355 [ - + - + ]: 4 : assert_return(m, -EINVAL);
356 : :
357 : 4 : fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
358 [ - + ]: 4 : if (fd < 0)
359 : 0 : return -errno;
360 : :
361 [ - + # # ]: 4 : if (!category || streq(category, "links")) {
362 : 4 : k = monitor_add_inotify_watch(fd);
363 [ - + ]: 4 : if (k < 0)
364 : 0 : return k;
365 : :
366 : 4 : good = true;
367 : : }
368 : :
369 [ - + ]: 4 : if (!good)
370 : 0 : return -EINVAL;
371 : :
372 : 4 : *m = FD_TO_MONITOR(fd);
373 : 4 : fd = -1;
374 : :
375 : 4 : return 0;
376 : : }
377 : :
378 : 4 : _public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
379 : : int fd;
380 : :
381 [ + - ]: 4 : if (m) {
382 : 4 : fd = MONITOR_TO_FD(m);
383 : 4 : close_nointr(fd);
384 : : }
385 : :
386 : 4 : return NULL;
387 : : }
388 : :
389 : 0 : _public_ int sd_network_monitor_flush(sd_network_monitor *m) {
390 : : union inotify_event_buffer buffer;
391 : : struct inotify_event *e;
392 : : ssize_t l;
393 : : int fd, k;
394 : :
395 [ # # # # ]: 0 : assert_return(m, -EINVAL);
396 : :
397 : 0 : fd = MONITOR_TO_FD(m);
398 : :
399 : 0 : l = read(fd, &buffer, sizeof(buffer));
400 [ # # ]: 0 : if (l < 0) {
401 [ # # # # ]: 0 : if (IN_SET(errno, EAGAIN, EINTR))
402 : 0 : return 0;
403 : :
404 : 0 : return -errno;
405 : : }
406 : :
407 [ # # ]: 0 : FOREACH_INOTIFY_EVENT(e, buffer, l) {
408 [ # # ]: 0 : if (e->mask & IN_ISDIR) {
409 : 0 : k = monitor_add_inotify_watch(fd);
410 [ # # ]: 0 : if (k < 0)
411 : 0 : return k;
412 : :
413 : 0 : k = inotify_rm_watch(fd, e->wd);
414 [ # # ]: 0 : if (k < 0)
415 : 0 : return -errno;
416 : : }
417 : : }
418 : :
419 : 0 : return 0;
420 : : }
421 : :
422 : 4 : _public_ int sd_network_monitor_get_fd(sd_network_monitor *m) {
423 : :
424 [ - + - + ]: 4 : assert_return(m, -EINVAL);
425 : :
426 : 4 : return MONITOR_TO_FD(m);
427 : : }
428 : :
429 : 4 : _public_ int sd_network_monitor_get_events(sd_network_monitor *m) {
430 : :
431 [ - + - + ]: 4 : assert_return(m, -EINVAL);
432 : :
433 : : /* For now we will only return POLLIN here, since we don't
434 : : * need anything else ever for inotify. However, let's have
435 : : * this API to keep our options open should we later on need
436 : : * it. */
437 : 4 : return POLLIN;
438 : : }
439 : :
440 : 0 : _public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec) {
441 : :
442 [ # # # # ]: 0 : assert_return(m, -EINVAL);
443 [ # # # # ]: 0 : assert_return(timeout_usec, -EINVAL);
444 : :
445 : : /* For now we will only return (uint64_t) -1, since we don't
446 : : * need any timeout. However, let's have this API to keep our
447 : : * options open should we later on need it. */
448 : 0 : *timeout_usec = (uint64_t) -1;
449 : 0 : return 0;
450 : : }
|