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