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