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