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