]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-network/sd-network.c
Merge pull request #7608 from poettering/more-news-v236
[thirdparty/systemd.git] / src / libsystemd / sd-network / sd-network.c
CommitLineData
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
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
fe8db0c5 22#include <errno.h>
0a6f50c0 23#include <poll.h>
07630cea
LP
24#include <string.h>
25#include <sys/inotify.h>
fe8db0c5 26
07630cea
LP
27#include "sd-network.h"
28
b5efdb8a 29#include "alloc-util.h"
77601719 30#include "fd-util.h"
07630cea 31#include "fileio.h"
77601719 32#include "fs-util.h"
fe8db0c5 33#include "macro.h"
77601719 34#include "parse-util.h"
5f02f341 35#include "stdio-util.h"
07630cea 36#include "string-util.h"
fe8db0c5 37#include "strv.h"
07630cea 38#include "util.h"
fe8db0c5 39
03cc0fd1
LP
40_public_ int sd_network_get_operational_state(char **state) {
41 _cleanup_free_ char *s = NULL;
deb2e523
TG
42 int r;
43
fe8db0c5
TG
44 assert_return(state, -EINVAL);
45
03cc0fd1 46 r = parse_env_file("/run/systemd/netif/state", NEWLINE, "OPER_STATE", &s, NULL);
cb6fa44c
TG
47 if (r == -ENOENT)
48 return -ENODATA;
03cc0fd1 49 if (r < 0)
fe8db0c5 50 return r;
03cc0fd1
LP
51 if (isempty(s))
52 return -ENODATA;
deb2e523
TG
53
54 *state = s;
55 s = NULL;
56
57 return 0;
58}
59
03cc0fd1
LP
60static int network_get_strv(const char *key, char ***ret) {
61 _cleanup_strv_free_ char **a = NULL;
bbf7c048
TG
62 _cleanup_free_ char *s = NULL;
63 int r;
64
03cc0fd1
LP
65 assert_return(ret, -EINVAL);
66
67 r = parse_env_file("/run/systemd/netif/state", NEWLINE, key, &s, NULL);
68 if (r == -ENOENT)
69 return -ENODATA;
70 if (r < 0)
71 return r;
72 if (isempty(s)) {
73 *ret = NULL;
74 return 0;
75 }
76
77 a = strv_split(s, " ");
78 if (!a)
79 return -ENOMEM;
80
81 strv_uniq(a);
82 r = strv_length(a);
83
84 *ret = a;
85 a = NULL;
86
87 return r;
88}
89
90_public_ int sd_network_get_dns(char ***ret) {
91 return network_get_strv("DNS", ret);
92}
93
94_public_ int sd_network_get_ntp(char ***ret) {
95 return network_get_strv("NTP", ret);
96}
97
3df9bec5 98_public_ int sd_network_get_search_domains(char ***ret) {
8612e936
LP
99 return network_get_strv("DOMAINS", ret);
100}
101
3df9bec5
LP
102_public_ int sd_network_get_route_domains(char ***ret) {
103 return network_get_strv("ROUTE_DOMAINS", ret);
104}
105
38e5900f 106static int network_link_get_string(int ifindex, const char *field, char **ret) {
fbd0b64f 107 char path[STRLEN("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
5f02f341 108 _cleanup_free_ char *s = NULL;
03cc0fd1
LP
109 int r;
110
111 assert_return(ifindex > 0, -EINVAL);
38e5900f 112 assert_return(ret, -EINVAL);
bbf7c048 113
5f02f341 114 xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
03cc0fd1 115
5f02f341 116 r = parse_env_file(path, NEWLINE, field, &s, NULL);
bbf7c048
TG
117 if (r == -ENOENT)
118 return -ENODATA;
03cc0fd1 119 if (r < 0)
bbf7c048 120 return r;
03cc0fd1
LP
121 if (isempty(s))
122 return -ENODATA;
bbf7c048 123
38e5900f 124 *ret = s;
bbf7c048
TG
125 s = NULL;
126
127 return 0;
128}
129
8a516214 130static int network_link_get_strv(int ifindex, const char *key, char ***ret) {
fbd0b64f 131 char path[STRLEN("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
8a516214 132 _cleanup_strv_free_ char **a = NULL;
5f02f341 133 _cleanup_free_ char *s = NULL;
8a516214
LP
134 int r;
135
136 assert_return(ifindex > 0, -EINVAL);
137 assert_return(ret, -EINVAL);
138
5f02f341
LP
139 xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
140 r = parse_env_file(path, NEWLINE, key, &s, NULL);
8a516214
LP
141 if (r == -ENOENT)
142 return -ENODATA;
143 if (r < 0)
144 return r;
145 if (isempty(s)) {
146 *ret = NULL;
147 return 0;
148 }
149
150 a = strv_split(s, " ");
151 if (!a)
152 return -ENOMEM;
153
154 strv_uniq(a);
155 r = strv_length(a);
156
157 *ret = a;
158 a = NULL;
159
160 return r;
161}
162
38e5900f
LP
163_public_ int sd_network_link_get_setup_state(int ifindex, char **state) {
164 return network_link_get_string(ifindex, "ADMIN_STATE", state);
165}
adc5b2e2 166
38e5900f
LP
167_public_ int sd_network_link_get_network_file(int ifindex, char **filename) {
168 return network_link_get_string(ifindex, "NETWORK_FILE", filename);
adc5b2e2
TG
169}
170
d6731e4c 171_public_ int sd_network_link_get_operational_state(int ifindex, char **state) {
38e5900f 172 return network_link_get_string(ifindex, "OPER_STATE", state);
fe8db0c5
TG
173}
174
c1a38904
MTL
175_public_ int sd_network_link_get_required_for_online(int ifindex) {
176 _cleanup_free_ char *s = NULL;
177 int r;
178
179 r = network_link_get_string(ifindex, "REQUIRED_FOR_ONLINE", &s);
180 if (r < 0) {
181 /* Handle -ENODATA as RequiredForOnline=yes, for compatibility */
182 if (r == -ENODATA)
183 return true;
184 return r;
185 }
186
187 return parse_boolean(s);
188}
189
d6731e4c 190_public_ int sd_network_link_get_llmnr(int ifindex, char **llmnr) {
38e5900f 191 return network_link_get_string(ifindex, "LLMNR", llmnr);
bd8f6538
TG
192}
193
aaa297d4
LP
194_public_ int sd_network_link_get_mdns(int ifindex, char **mdns) {
195 return network_link_get_string(ifindex, "MDNS", mdns);
196}
197
ad6c0475
LP
198_public_ int sd_network_link_get_dnssec(int ifindex, char **dnssec) {
199 return network_link_get_string(ifindex, "DNSSEC", dnssec);
200}
201
8a516214
LP
202_public_ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char ***nta) {
203 return network_link_get_strv(ifindex, "DNSSEC_NTA", nta);
204}
205
34437b4f 206_public_ int sd_network_link_get_timezone(int ifindex, char **ret) {
38e5900f 207 return network_link_get_string(ifindex, "TIMEZONE", ret);
8eb9058d 208}
49699bac 209
d6731e4c 210_public_ int sd_network_link_get_dns(int ifindex, char ***ret) {
8a516214 211 return network_link_get_strv(ifindex, "DNS", ret);
bcb7a07e
TG
212}
213
d6731e4c 214_public_ int sd_network_link_get_ntp(int ifindex, char ***ret) {
8a516214 215 return network_link_get_strv(ifindex, "NTP", ret);
bcb7a07e
TG
216}
217
3df9bec5 218_public_ int sd_network_link_get_search_domains(int ifindex, char ***ret) {
8a516214 219 return network_link_get_strv(ifindex, "DOMAINS", ret);
9b4d1882
TG
220}
221
3df9bec5
LP
222_public_ int sd_network_link_get_route_domains(int ifindex, char ***ret) {
223 return network_link_get_strv(ifindex, "ROUTE_DOMAINS", ret);
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
LP
237 xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
238 r = parse_env_file(path, NEWLINE, key, &s, NULL);
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
LP
265
266 *ret = ifis;
267 ifis = NULL;
268
269 return c;
270}
271
272_public_ int sd_network_link_get_carrier_bound_to(int ifindex, int **ret) {
273 return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_TO", ret);
0d4ad91d
AR
274}
275
b295beea
LP
276_public_ int sd_network_link_get_carrier_bound_by(int ifindex, int **ret) {
277 return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_BY", ret);
0d4ad91d
AR
278}
279
fe8db0c5
TG
280static inline int MONITOR_TO_FD(sd_network_monitor *m) {
281 return (int) (unsigned long) m - 1;
282}
283
284static inline sd_network_monitor* FD_TO_MONITOR(int fd) {
285 return (sd_network_monitor*) (unsigned long) (fd + 1);
286}
287
870395a4
TG
288static int monitor_add_inotify_watch(int fd) {
289 int k;
290
291 k = inotify_add_watch(fd, "/run/systemd/netif/links/", IN_MOVED_TO|IN_DELETE);
292 if (k >= 0)
293 return 0;
294 else if (errno != ENOENT)
295 return -errno;
296
297 k = inotify_add_watch(fd, "/run/systemd/netif/", IN_CREATE|IN_ISDIR);
298 if (k >= 0)
299 return 0;
300 else if (errno != ENOENT)
301 return -errno;
302
303 k = inotify_add_watch(fd, "/run/systemd/", IN_CREATE|IN_ISDIR);
304 if (k < 0)
305 return -errno;
306
307 return 0;
308}
309
0014a4ad 310_public_ int sd_network_monitor_new(sd_network_monitor **m, const char *category) {
870395a4
TG
311 _cleanup_close_ int fd = -1;
312 int k;
fe8db0c5
TG
313 bool good = false;
314
315 assert_return(m, -EINVAL);
316
317 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
318 if (fd < 0)
319 return -errno;
320
7e141e49 321 if (!category || streq(category, "links")) {
870395a4
TG
322 k = monitor_add_inotify_watch(fd);
323 if (k < 0)
324 return k;
fe8db0c5
TG
325
326 good = true;
327 }
328
3de1c8ce 329 if (!good)
fe8db0c5 330 return -EINVAL;
fe8db0c5
TG
331
332 *m = FD_TO_MONITOR(fd);
870395a4
TG
333 fd = -1;
334
fe8db0c5
TG
335 return 0;
336}
337
338_public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
339 int fd;
340
0b347626
TG
341 if (m) {
342 fd = MONITOR_TO_FD(m);
343 close_nointr(fd);
344 }
fe8db0c5
TG
345
346 return NULL;
347}
348
349_public_ int sd_network_monitor_flush(sd_network_monitor *m) {
870395a4
TG
350 union inotify_event_buffer buffer;
351 struct inotify_event *e;
352 ssize_t l;
353 int fd, k;
fe8db0c5
TG
354
355 assert_return(m, -EINVAL);
356
870395a4
TG
357 fd = MONITOR_TO_FD(m);
358
359 l = read(fd, &buffer, sizeof(buffer));
360 if (l < 0) {
945c2931 361 if (IN_SET(errno, EAGAIN, EINTR))
870395a4
TG
362 return 0;
363
364 return -errno;
365 }
366
367 FOREACH_INOTIFY_EVENT(e, buffer, l) {
368 if (e->mask & IN_ISDIR) {
369 k = monitor_add_inotify_watch(fd);
370 if (k < 0)
371 return k;
372
373 k = inotify_rm_watch(fd, e->wd);
374 if (k < 0)
375 return -errno;
376 }
377 }
378
379 return 0;
fe8db0c5
TG
380}
381
382_public_ int sd_network_monitor_get_fd(sd_network_monitor *m) {
383
384 assert_return(m, -EINVAL);
385
386 return MONITOR_TO_FD(m);
387}
388
389_public_ int sd_network_monitor_get_events(sd_network_monitor *m) {
390
391 assert_return(m, -EINVAL);
392
393 /* For now we will only return POLLIN here, since we don't
394 * need anything else ever for inotify. However, let's have
395 * this API to keep our options open should we later on need
396 * it. */
397 return POLLIN;
398}
399
400_public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec) {
401
402 assert_return(m, -EINVAL);
403 assert_return(timeout_usec, -EINVAL);
404
405 /* For now we will only return (uint64_t) -1, since we don't
406 * need any timeout. However, let's have this API to keep our
407 * options open should we later on need it. */
408 *timeout_usec = (uint64_t) -1;
409 return 0;
410}