]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-network/sd-network.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / libsystemd / sd-network / sd-network.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
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
22 #include <errno.h>
23 #include <poll.h>
24 #include <string.h>
25 #include <sys/inotify.h>
26
27 #include "sd-network.h"
28
29 #include "alloc-util.h"
30 #include "fd-util.h"
31 #include "fileio.h"
32 #include "fs-util.h"
33 #include "macro.h"
34 #include "parse-util.h"
35 #include "stdio-util.h"
36 #include "string-util.h"
37 #include "strv.h"
38 #include "util.h"
39
40 _public_ int sd_network_get_operational_state(char **state) {
41 _cleanup_free_ char *s = NULL;
42 int r;
43
44 assert_return(state, -EINVAL);
45
46 r = parse_env_file("/run/systemd/netif/state", NEWLINE, "OPER_STATE", &s, NULL);
47 if (r == -ENOENT)
48 return -ENODATA;
49 if (r < 0)
50 return r;
51 if (isempty(s))
52 return -ENODATA;
53
54 *state = s;
55 s = NULL;
56
57 return 0;
58 }
59
60 static int network_get_strv(const char *key, char ***ret) {
61 _cleanup_strv_free_ char **a = NULL;
62 _cleanup_free_ char *s = NULL;
63 int r;
64
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
98 _public_ int sd_network_get_search_domains(char ***ret) {
99 return network_get_strv("DOMAINS", ret);
100 }
101
102 _public_ int sd_network_get_route_domains(char ***ret) {
103 return network_get_strv("ROUTE_DOMAINS", ret);
104 }
105
106 static int network_link_get_string(int ifindex, const char *field, char **ret) {
107 char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
108 _cleanup_free_ char *s = NULL;
109 int r;
110
111 assert_return(ifindex > 0, -EINVAL);
112 assert_return(ret, -EINVAL);
113
114 xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
115
116 r = parse_env_file(path, NEWLINE, field, &s, NULL);
117 if (r == -ENOENT)
118 return -ENODATA;
119 if (r < 0)
120 return r;
121 if (isempty(s))
122 return -ENODATA;
123
124 *ret = s;
125 s = NULL;
126
127 return 0;
128 }
129
130 static int network_link_get_strv(int ifindex, const char *key, char ***ret) {
131 char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
132 _cleanup_strv_free_ char **a = NULL;
133 _cleanup_free_ char *s = NULL;
134 int r;
135
136 assert_return(ifindex > 0, -EINVAL);
137 assert_return(ret, -EINVAL);
138
139 xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
140 r = parse_env_file(path, NEWLINE, key, &s, NULL);
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
163 _public_ int sd_network_link_get_setup_state(int ifindex, char **state) {
164 return network_link_get_string(ifindex, "ADMIN_STATE", state);
165 }
166
167 _public_ int sd_network_link_get_network_file(int ifindex, char **filename) {
168 return network_link_get_string(ifindex, "NETWORK_FILE", filename);
169 }
170
171 _public_ int sd_network_link_get_operational_state(int ifindex, char **state) {
172 return network_link_get_string(ifindex, "OPER_STATE", state);
173 }
174
175 _public_ int sd_network_link_get_llmnr(int ifindex, char **llmnr) {
176 return network_link_get_string(ifindex, "LLMNR", llmnr);
177 }
178
179 _public_ int sd_network_link_get_mdns(int ifindex, char **mdns) {
180 return network_link_get_string(ifindex, "MDNS", mdns);
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(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 = ifis;
252 ifis = NULL;
253
254 return c;
255 }
256
257 _public_ int sd_network_link_get_carrier_bound_to(int ifindex, int **ret) {
258 return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_TO", ret);
259 }
260
261 _public_ int sd_network_link_get_carrier_bound_by(int ifindex, int **ret) {
262 return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_BY", ret);
263 }
264
265 static inline int MONITOR_TO_FD(sd_network_monitor *m) {
266 return (int) (unsigned long) m - 1;
267 }
268
269 static inline sd_network_monitor* FD_TO_MONITOR(int fd) {
270 return (sd_network_monitor*) (unsigned long) (fd + 1);
271 }
272
273 static int monitor_add_inotify_watch(int fd) {
274 int k;
275
276 k = inotify_add_watch(fd, "/run/systemd/netif/links/", IN_MOVED_TO|IN_DELETE);
277 if (k >= 0)
278 return 0;
279 else if (errno != ENOENT)
280 return -errno;
281
282 k = inotify_add_watch(fd, "/run/systemd/netif/", IN_CREATE|IN_ISDIR);
283 if (k >= 0)
284 return 0;
285 else if (errno != ENOENT)
286 return -errno;
287
288 k = inotify_add_watch(fd, "/run/systemd/", IN_CREATE|IN_ISDIR);
289 if (k < 0)
290 return -errno;
291
292 return 0;
293 }
294
295 _public_ int sd_network_monitor_new(sd_network_monitor **m, const char *category) {
296 _cleanup_close_ int fd = -1;
297 int k;
298 bool good = false;
299
300 assert_return(m, -EINVAL);
301
302 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
303 if (fd < 0)
304 return -errno;
305
306 if (!category || streq(category, "links")) {
307 k = monitor_add_inotify_watch(fd);
308 if (k < 0)
309 return k;
310
311 good = true;
312 }
313
314 if (!good)
315 return -EINVAL;
316
317 *m = FD_TO_MONITOR(fd);
318 fd = -1;
319
320 return 0;
321 }
322
323 _public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
324 int fd;
325
326 if (m) {
327 fd = MONITOR_TO_FD(m);
328 close_nointr(fd);
329 }
330
331 return NULL;
332 }
333
334 _public_ int sd_network_monitor_flush(sd_network_monitor *m) {
335 union inotify_event_buffer buffer;
336 struct inotify_event *e;
337 ssize_t l;
338 int fd, k;
339
340 assert_return(m, -EINVAL);
341
342 fd = MONITOR_TO_FD(m);
343
344 l = read(fd, &buffer, sizeof(buffer));
345 if (l < 0) {
346 if (IN_SET(errno, EAGAIN, EINTR))
347 return 0;
348
349 return -errno;
350 }
351
352 FOREACH_INOTIFY_EVENT(e, buffer, l) {
353 if (e->mask & IN_ISDIR) {
354 k = monitor_add_inotify_watch(fd);
355 if (k < 0)
356 return k;
357
358 k = inotify_rm_watch(fd, e->wd);
359 if (k < 0)
360 return -errno;
361 }
362 }
363
364 return 0;
365 }
366
367 _public_ int sd_network_monitor_get_fd(sd_network_monitor *m) {
368
369 assert_return(m, -EINVAL);
370
371 return MONITOR_TO_FD(m);
372 }
373
374 _public_ int sd_network_monitor_get_events(sd_network_monitor *m) {
375
376 assert_return(m, -EINVAL);
377
378 /* For now we will only return POLLIN here, since we don't
379 * need anything else ever for inotify. However, let's have
380 * this API to keep our options open should we later on need
381 * it. */
382 return POLLIN;
383 }
384
385 _public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec) {
386
387 assert_return(m, -EINVAL);
388 assert_return(timeout_usec, -EINVAL);
389
390 /* For now we will only return (uint64_t) -1, since we don't
391 * need any timeout. However, let's have this API to keep our
392 * options open should we later on need it. */
393 *timeout_usec = (uint64_t) -1;
394 return 0;
395 }