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