]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-state-file.c
network: introduce link_get_use_ntp()
[thirdparty/systemd.git] / src / network / networkd-state-file.c
CommitLineData
3b5a4fc6
YW
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <netinet/in.h>
7b9da386 4#include <linux/if.h>
3b5a4fc6
YW
5
6#include "alloc-util.h"
7#include "dns-domain.h"
a2640646 8#include "escape.h"
3b5a4fc6
YW
9#include "fd-util.h"
10#include "fileio.h"
11#include "fs-util.h"
12#include "network-internal.h"
6341ea54 13#include "networkd-dhcp-common.h"
3b5a4fc6
YW
14#include "networkd-link.h"
15#include "networkd-manager-bus.h"
16#include "networkd-manager.h"
17#include "networkd-network.h"
d12fb2bc 18#include "networkd-ntp.h"
3b5a4fc6
YW
19#include "networkd-state-file.h"
20#include "ordered-set.h"
21#include "set.h"
22#include "strv.h"
23#include "tmpfile-util.h"
24
86a66e9b 25static int ordered_set_put_dns_servers(OrderedSet **s, int ifindex, struct in_addr_full **dns, unsigned n) {
3b5a4fc6
YW
26 int r;
27
28 assert(s);
86a66e9b 29 assert(dns || n == 0);
3b5a4fc6 30
86a66e9b
YW
31 FOREACH_ARRAY(a, dns, n) {
32 const char *p;
3b5a4fc6 33
86a66e9b
YW
34 if ((*a)->ifindex != 0 && (*a)->ifindex != ifindex)
35 return 0;
3b5a4fc6 36
86a66e9b
YW
37 p = in_addr_full_to_string(*a);
38 if (!p)
39 return 0;
40
41 r = ordered_set_put_strdup(s, p);
42 if (r < 0)
43 return r;
44 }
3b5a4fc6 45
86a66e9b 46 return 0;
3b5a4fc6
YW
47}
48
86a66e9b
YW
49static int ordered_set_put_in4_addrv(
50 OrderedSet **s,
51 const struct in_addr *addresses,
52 size_t n,
53 bool (*predicate)(const struct in_addr *addr)) {
54
55 int r;
3b5a4fc6
YW
56
57 assert(s);
86a66e9b 58 assert(n == 0 || addresses);
3b5a4fc6 59
86a66e9b
YW
60 FOREACH_ARRAY(a, addresses, n) {
61 if (predicate && !predicate(a))
62 continue;
63
64 r = ordered_set_put_strdup(s, IN4_ADDR_TO_STRING(a));
3b5a4fc6
YW
65 if (r < 0)
66 return r;
86a66e9b
YW
67 }
68
69 return 0;
70}
71
72static int ordered_set_put_in6_addrv(
73 OrderedSet **s,
74 const struct in6_addr *addresses,
75 size_t n) {
76
77 int r;
78
79 assert(s);
80 assert(n == 0 || addresses);
3b5a4fc6 81
86a66e9b
YW
82 FOREACH_ARRAY(a, addresses, n) {
83 r = ordered_set_put_strdup(s, IN6_ADDR_TO_STRING(a));
84 if (r < 0)
85 return r;
3b5a4fc6
YW
86 }
87
86a66e9b 88 return 0;
3b5a4fc6
YW
89}
90
86a66e9b 91static int link_put_dns(Link *link, OrderedSet **s) {
3b5a4fc6
YW
92 int r;
93
86a66e9b
YW
94 assert(link);
95 assert(link->network);
3b5a4fc6 96 assert(s);
3b5a4fc6 97
86a66e9b
YW
98 if (link->n_dns != UINT_MAX)
99 return ordered_set_put_dns_servers(s, link->ifindex, link->dns, link->n_dns);
100
101 r = ordered_set_put_dns_servers(s, link->ifindex, link->network->dns, link->network->n_dns);
3b5a4fc6
YW
102 if (r < 0)
103 return r;
104
9646ffe2 105 if (link->dhcp_lease && link_get_use_dns(link, NETWORK_CONFIG_SOURCE_DHCP4)) {
86a66e9b
YW
106 const struct in_addr *addresses;
107
108 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
109 if (r >= 0) {
110 r = ordered_set_put_in4_addrv(s, addresses, r, in4_addr_is_non_local);
111 if (r < 0)
112 return r;
113 }
114 }
115
9646ffe2 116 if (link->dhcp6_lease && link_get_use_dns(link, NETWORK_CONFIG_SOURCE_DHCP6)) {
86a66e9b
YW
117 const struct in6_addr *addresses;
118
119 r = sd_dhcp6_lease_get_dns(link->dhcp6_lease, &addresses);
120 if (r >= 0) {
121 r = ordered_set_put_in6_addrv(s, addresses, r);
122 if (r < 0)
123 return r;
124 }
125 }
126
9646ffe2 127 if (link_get_use_dns(link, NETWORK_CONFIG_SOURCE_NDISC)) {
86a66e9b
YW
128 NDiscRDNSS *a;
129
130 SET_FOREACH(a, link->ndisc_rdnss) {
64761f38 131 r = ordered_set_put_in6_addrv(s, &a->address, 1);
86a66e9b
YW
132 if (r < 0)
133 return r;
134 }
135 }
136
137 return 0;
138}
139
140static int link_put_ntp(Link *link, OrderedSet **s) {
141 int r;
142
143 assert(link);
144 assert(link->network);
145 assert(s);
146
147 if (link->ntp)
148 return ordered_set_put_strdupv(s, link->ntp);
149
150 r = ordered_set_put_strdupv(s, link->network->ntp);
cf453507
YW
151 if (r < 0)
152 return r;
153
d12fb2bc 154 if (link->dhcp_lease && link_get_use_ntp(link, NETWORK_CONFIG_SOURCE_DHCP4)) {
86a66e9b
YW
155 const struct in_addr *addresses;
156
157 r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
158 if (r >= 0) {
159 r = ordered_set_put_in4_addrv(s, addresses, r, in4_addr_is_non_local);
160 if (r < 0)
161 return r;
162 }
163 }
164
d12fb2bc 165 if (link->dhcp6_lease && link_get_use_ntp(link, NETWORK_CONFIG_SOURCE_DHCP6)) {
86a66e9b
YW
166 const struct in6_addr *addresses;
167 char **fqdn;
3b5a4fc6 168
86a66e9b
YW
169 r = sd_dhcp6_lease_get_ntp_addrs(link->dhcp6_lease, &addresses);
170 if (r >= 0) {
171 r = ordered_set_put_in6_addrv(s, addresses, r);
172 if (r < 0)
173 return r;
174 }
175
176 r = sd_dhcp6_lease_get_ntp_fqdn(link->dhcp6_lease, &fqdn);
177 if (r >= 0) {
178 r = ordered_set_put_strdupv(s, fqdn);
179 if (r < 0)
180 return r;
181 }
182 }
183
184 return 0;
3b5a4fc6
YW
185}
186
86a66e9b
YW
187static int link_put_sip(Link *link, OrderedSet **s) {
188 int r;
189
190 assert(link);
191 assert(link->network);
192 assert(s);
193
e188243d 194 if (link->dhcp_lease && link->network->dhcp_use_sip) {
86a66e9b
YW
195 const struct in_addr *addresses;
196
197 r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
198 if (r >= 0) {
199 r = ordered_set_put_in4_addrv(s, addresses, r, in4_addr_is_non_local);
200 if (r < 0)
201 return r;
202 }
203 }
204
205 return 0;
206}
44e1f7e3 207
86a66e9b
YW
208static int link_put_domains(Link *link, bool is_route, OrderedSet **s) {
209 OrderedSet *link_domains, *network_domains;
78f5c649 210 UseDomains use_domains;
86a66e9b 211 int r;
3b5a4fc6 212
86a66e9b
YW
213 assert(link);
214 assert(link->network);
3b5a4fc6 215 assert(s);
3b5a4fc6 216
86a66e9b
YW
217 link_domains = is_route ? link->route_domains : link->search_domains;
218 network_domains = is_route ? link->network->route_domains : link->network->search_domains;
78f5c649 219 use_domains = is_route ? USE_DOMAINS_ROUTE : USE_DOMAINS_YES;
86a66e9b
YW
220
221 if (link_domains)
222 return ordered_set_put_string_set(s, link_domains);
223
224 r = ordered_set_put_string_set(s, network_domains);
225 if (r < 0)
226 return r;
227
7a169cb4 228 if (link->dhcp_lease && link_get_use_domains(link, NETWORK_CONFIG_SOURCE_DHCP4) == use_domains) {
86a66e9b
YW
229 const char *domainname;
230 char **domains;
231
232 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
233 if (r >= 0) {
234 r = ordered_set_put_strdup(s, domainname);
235 if (r < 0)
236 return r;
237 }
3b5a4fc6 238
86a66e9b
YW
239 r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains);
240 if (r >= 0) {
241 r = ordered_set_put_strdupv(s, domains);
242 if (r < 0)
243 return r;
244 }
245 }
246
7a169cb4 247 if (link->dhcp6_lease && link_get_use_domains(link, NETWORK_CONFIG_SOURCE_DHCP6) == use_domains) {
86a66e9b
YW
248 char **domains;
249
250 r = sd_dhcp6_lease_get_domains(link->dhcp6_lease, &domains);
251 if (r >= 0) {
252 r = ordered_set_put_strdupv(s, domains);
253 if (r < 0)
254 return r;
255 }
256 }
257
7a169cb4 258 if (link_get_use_domains(link, NETWORK_CONFIG_SOURCE_NDISC) == use_domains) {
86a66e9b
YW
259 NDiscDNSSL *a;
260
261 SET_FOREACH(a, link->ndisc_dnssl) {
262 r = ordered_set_put_strdup(s, NDISC_DNSSL_DOMAIN(a));
263 if (r < 0)
264 return r;
265 }
3b5a4fc6
YW
266 }
267
86a66e9b 268 return 0;
3b5a4fc6
YW
269}
270
271int manager_save(Manager *m) {
cf453507 272 _cleanup_ordered_set_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL;
bcdcc596 273 const char *operstate_str, *carrier_state_str, *address_state_str, *ipv4_address_state_str, *ipv6_address_state_str, *online_state_str;
3b5a4fc6
YW
274 LinkOperationalState operstate = LINK_OPERSTATE_OFF;
275 LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
8430841b
L
276 LinkAddressState ipv4_address_state = LINK_ADDRESS_STATE_OFF, ipv6_address_state = LINK_ADDRESS_STATE_OFF,
277 address_state = LINK_ADDRESS_STATE_OFF;
bcdcc596
AÅ 
278 LinkOnlineState online_state;
279 size_t links_offline = 0, links_online = 0;
d23a66f2 280 _cleanup_(unlink_and_freep) char *temp_path = NULL;
3b5a4fc6
YW
281 _cleanup_strv_free_ char **p = NULL;
282 _cleanup_fclose_ FILE *f = NULL;
283 Link *link;
284 int r;
285
286 assert(m);
4c78dc17
YW
287
288 if (isempty(m->state_file))
289 return 0; /* Do not update state file when running in test mode. */
3b5a4fc6 290
6eab614d 291 HASHMAP_FOREACH(link, m->links_by_index) {
3b5a4fc6
YW
292 if (link->flags & IFF_LOOPBACK)
293 continue;
294
90afec18
YW
295 operstate = MAX(operstate, link->operstate);
296 carrier_state = MAX(carrier_state, link->carrier_state);
297 address_state = MAX(address_state, link->address_state);
298 ipv4_address_state = MAX(ipv4_address_state, link->ipv4_address_state);
299 ipv6_address_state = MAX(ipv6_address_state, link->ipv6_address_state);
8430841b 300
3b5a4fc6
YW
301 if (!link->network)
302 continue;
303
bcdcc596
AÅ 
304 if (link->network->required_for_online) {
305 if (link->online_state == LINK_ONLINE_STATE_OFFLINE)
306 links_offline++;
307 else if (link->online_state == LINK_ONLINE_STATE_ONLINE)
308 links_online++;
309 }
310
86a66e9b 311 r = link_put_dns(link, &dns);
3b5a4fc6
YW
312 if (r < 0)
313 return r;
314
86a66e9b 315 r = link_put_ntp(link, &ntp);
3b5a4fc6
YW
316 if (r < 0)
317 return r;
318
86a66e9b 319 r = link_put_sip(link, &sip);
3b5a4fc6
YW
320 if (r < 0)
321 return r;
322
86a66e9b 323 r = link_put_domains(link, /* is_route = */ false, &search_domains);
3b5a4fc6
YW
324 if (r < 0)
325 return r;
326
86a66e9b
YW
327 r = link_put_domains(link, /* is_route = */ true, &route_domains);
328 if (r < 0)
329 return r;
3b5a4fc6
YW
330 }
331
332 if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED)
333 carrier_state = LINK_CARRIER_STATE_CARRIER;
334
bcdcc596
AÅ 
335 online_state = links_online > 0 ?
336 (links_offline > 0 ? LINK_ONLINE_STATE_PARTIAL : LINK_ONLINE_STATE_ONLINE) :
337 (links_offline > 0 ? LINK_ONLINE_STATE_OFFLINE : _LINK_ONLINE_STATE_INVALID);
338
3b5a4fc6
YW
339 operstate_str = link_operstate_to_string(operstate);
340 assert(operstate_str);
341
342 carrier_state_str = link_carrier_state_to_string(carrier_state);
343 assert(carrier_state_str);
344
345 address_state_str = link_address_state_to_string(address_state);
346 assert(address_state_str);
347
8430841b
L
348 ipv4_address_state_str = link_address_state_to_string(ipv4_address_state);
349 assert(ipv4_address_state_str);
350
351 ipv6_address_state_str = link_address_state_to_string(ipv6_address_state);
352 assert(ipv6_address_state_str);
353
3b5a4fc6
YW
354 r = fopen_temporary(m->state_file, &f, &temp_path);
355 if (r < 0)
356 return r;
357
358 (void) fchmod(fileno(f), 0644);
359
360 fprintf(f,
361 "# This is private data. Do not parse.\n"
362 "OPER_STATE=%s\n"
363 "CARRIER_STATE=%s\n"
8430841b
L
364 "ADDRESS_STATE=%s\n"
365 "IPV4_ADDRESS_STATE=%s\n"
366 "IPV6_ADDRESS_STATE=%s\n",
367 operstate_str, carrier_state_str, address_state_str, ipv4_address_state_str, ipv6_address_state_str);
3b5a4fc6 368
bcdcc596
AÅ 
369 online_state_str = link_online_state_to_string(online_state);
370 if (online_state_str)
371 fprintf(f, "ONLINE_STATE=%s\n", online_state_str);
372
3b5a4fc6
YW
373 ordered_set_print(f, "DNS=", dns);
374 ordered_set_print(f, "NTP=", ntp);
375 ordered_set_print(f, "SIP=", sip);
376 ordered_set_print(f, "DOMAINS=", search_domains);
377 ordered_set_print(f, "ROUTE_DOMAINS=", route_domains);
378
379 r = fflush_and_check(f);
380 if (r < 0)
d23a66f2 381 return r;
3b5a4fc6
YW
382
383 r = conservative_rename(temp_path, m->state_file);
384 if (r < 0)
d23a66f2
YW
385 return r;
386
387 temp_path = mfree(temp_path);
3b5a4fc6
YW
388
389 if (m->operational_state != operstate) {
390 m->operational_state = operstate;
391 if (strv_extend(&p, "OperationalState") < 0)
392 log_oom();
393 }
394
395 if (m->carrier_state != carrier_state) {
396 m->carrier_state = carrier_state;
397 if (strv_extend(&p, "CarrierState") < 0)
398 log_oom();
399 }
400
401 if (m->address_state != address_state) {
402 m->address_state = address_state;
403 if (strv_extend(&p, "AddressState") < 0)
404 log_oom();
405 }
406
8430841b
L
407 if (m->ipv4_address_state != ipv4_address_state) {
408 m->ipv4_address_state = ipv4_address_state;
409 if (strv_extend(&p, "IPv4AddressState") < 0)
410 log_oom();
411 }
412
413 if (m->ipv6_address_state != ipv6_address_state) {
414 m->ipv6_address_state = ipv6_address_state;
415 if (strv_extend(&p, "IPv6AddressState") < 0)
416 log_oom();
417 }
418
bcdcc596
AÅ 
419 if (m->online_state != online_state) {
420 m->online_state = online_state;
421 if (strv_extend(&p, "OnlineState") < 0)
422 log_oom();
423 }
424
3b5a4fc6
YW
425 if (p) {
426 r = manager_send_changed_strv(m, p);
427 if (r < 0)
d23a66f2 428 log_warning_errno(r, "Could not emit changed properties, ignoring: %m");
3b5a4fc6
YW
429 }
430
431 m->dirty = false;
432
433 return 0;
3b5a4fc6
YW
434}
435
436static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
437 bool space = false;
438 Link *link;
439
440 assert(f);
441 assert(prefix);
442
443 if (hashmap_isempty(h))
444 return;
445
446 fputs(prefix, f);
447 HASHMAP_FOREACH(link, h) {
448 if (space)
449 fputc(' ', f);
450
451 fprintf(f, "%i", link->ifindex);
452 space = true;
453 }
454
455 fputc('\n', f);
456}
457
458static void link_save_dns(Link *link, FILE *f, struct in_addr_full **dns, unsigned n_dns, bool *space) {
56437e33
YW
459 bool _space = false;
460
461 if (!space)
462 space = &_space;
463
3b5a4fc6
YW
464 for (unsigned j = 0; j < n_dns; j++) {
465 const char *str;
466
467 if (dns[j]->ifindex != 0 && dns[j]->ifindex != link->ifindex)
468 continue;
469
470 str = in_addr_full_to_string(dns[j]);
471 if (!str)
472 continue;
473
474 if (*space)
475 fputc(' ', f);
476 fputs(str, f);
477 *space = true;
478 }
479}
480
481static void serialize_addresses(
482 FILE *f,
483 const char *lvalue,
484 bool *space,
485 char **addresses,
486 sd_dhcp_lease *lease,
487 bool conditional,
488 sd_dhcp_lease_server_type_t what,
489 sd_dhcp6_lease *lease6,
490 bool conditional6,
491 int (*lease6_get_addr)(sd_dhcp6_lease*, const struct in6_addr**),
492 int (*lease6_get_fqdn)(sd_dhcp6_lease*, char ***)) {
3b5a4fc6
YW
493
494 bool _space = false;
44e1f7e3
YW
495 int r;
496
3b5a4fc6
YW
497 if (!space)
498 space = &_space;
499
500 if (lvalue)
501 fprintf(f, "%s=", lvalue);
502 fputstrv(f, addresses, NULL, space);
503
504 if (lease && conditional) {
505 const struct in_addr *lease_addresses;
506
507 r = sd_dhcp_lease_get_servers(lease, what, &lease_addresses);
508 if (r > 0)
509 serialize_in_addrs(f, lease_addresses, r, space, in4_addr_is_non_local);
510 }
511
512 if (lease6 && conditional6 && lease6_get_addr) {
513 const struct in6_addr *in6_addrs;
514
515 r = lease6_get_addr(lease6, &in6_addrs);
516 if (r > 0)
517 serialize_in6_addrs(f, in6_addrs, r, space);
518 }
519
520 if (lease6 && conditional6 && lease6_get_fqdn) {
521 char **in6_hosts;
522
523 r = lease6_get_fqdn(lease6, &in6_hosts);
524 if (r > 0)
525 fputstrv(f, in6_hosts, NULL, space);
526 }
527
528 if (lvalue)
529 fputc('\n', f);
530}
531
78f5c649 532static void link_save_domains(Link *link, FILE *f, OrderedSet *static_domains, UseDomains use_domains) {
56437e33
YW
533 bool space = false;
534 const char *p;
535
536 assert(link);
537 assert(link->network);
538 assert(f);
539
540 ORDERED_SET_FOREACH(p, static_domains)
215286a4 541 fputs_with_separator(f, p, NULL, &space);
56437e33 542
78f5c649 543 if (use_domains == USE_DOMAINS_NO)
56437e33
YW
544 return;
545
7a169cb4 546 if (link->dhcp_lease && link_get_use_domains(link, NETWORK_CONFIG_SOURCE_DHCP4) == use_domains) {
56437e33
YW
547 const char *domainname;
548 char **domains;
549
550 if (sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname) >= 0)
215286a4 551 fputs_with_separator(f, domainname, NULL, &space);
56437e33
YW
552 if (sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains) >= 0)
553 fputstrv(f, domains, NULL, &space);
554 }
555
7a169cb4 556 if (link->dhcp6_lease && link_get_use_domains(link, NETWORK_CONFIG_SOURCE_DHCP6) == use_domains) {
56437e33
YW
557 char **domains;
558
559 if (sd_dhcp6_lease_get_domains(link->dhcp6_lease, &domains) >= 0)
560 fputstrv(f, domains, NULL, &space);
561 }
562
7a169cb4 563 if (link_get_use_domains(link, NETWORK_CONFIG_SOURCE_NDISC) == use_domains) {
56437e33
YW
564 NDiscDNSSL *dd;
565
566 SET_FOREACH(dd, link->ndisc_dnssl)
215286a4 567 fputs_with_separator(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
56437e33
YW
568 }
569}
570
a70c27b8 571static int link_save(Link *link) {
edb88a72 572 const char *admin_state, *oper_state, *carrier_state, *address_state, *ipv4_address_state, *ipv6_address_state,
6341ea54 573 *captive_portal;
d23a66f2 574 _cleanup_(unlink_and_freep) char *temp_path = NULL;
3b5a4fc6
YW
575 _cleanup_fclose_ FILE *f = NULL;
576 int r;
577
578 assert(link);
3b5a4fc6
YW
579 assert(link->manager);
580
4c78dc17
YW
581 if (isempty(link->state_file))
582 return 0; /* Do not update state files when running in test mode. */
583
d23a66f2 584 if (link->state == LINK_STATE_LINGER)
3b5a4fc6 585 return 0;
3b5a4fc6 586
3b5a4fc6
YW
587 admin_state = link_state_to_string(link->state);
588 assert(admin_state);
589
590 oper_state = link_operstate_to_string(link->operstate);
591 assert(oper_state);
592
593 carrier_state = link_carrier_state_to_string(link->carrier_state);
594 assert(carrier_state);
595
596 address_state = link_address_state_to_string(link->address_state);
597 assert(address_state);
598
8430841b
L
599 ipv4_address_state = link_address_state_to_string(link->ipv4_address_state);
600 assert(ipv4_address_state);
601
602 ipv6_address_state = link_address_state_to_string(link->ipv6_address_state);
603 assert(ipv6_address_state);
604
3b5a4fc6
YW
605 r = fopen_temporary(link->state_file, &f, &temp_path);
606 if (r < 0)
d23a66f2 607 return r;
3b5a4fc6
YW
608
609 (void) fchmod(fileno(f), 0644);
610
611 fprintf(f,
612 "# This is private data. Do not parse.\n"
613 "ADMIN_STATE=%s\n"
614 "OPER_STATE=%s\n"
615 "CARRIER_STATE=%s\n"
8430841b
L
616 "ADDRESS_STATE=%s\n"
617 "IPV4_ADDRESS_STATE=%s\n"
618 "IPV6_ADDRESS_STATE=%s\n",
619 admin_state, oper_state, carrier_state, address_state, ipv4_address_state, ipv6_address_state);
3b5a4fc6
YW
620
621 if (link->network) {
56437e33 622 const char *online_state;
a2640646 623 bool space = false;
3b5a4fc6 624
bcdcc596
AÅ 
625 online_state = link_online_state_to_string(link->online_state);
626 if (online_state)
627 fprintf(f, "ONLINE_STATE=%s\n", online_state);
628
3b5a4fc6
YW
629 fprintf(f, "REQUIRED_FOR_ONLINE=%s\n",
630 yes_no(link->network->required_for_online));
631
2278d9f6
YW
632 LinkOperationalStateRange st;
633 link_required_operstate_for_online(link, &st);
634
635 fprintf(f, "REQUIRED_OPER_STATE_FOR_ONLINE=%s:%s\n",
636 link_operstate_to_string(st.min), link_operstate_to_string(st.max));
3b5a4fc6 637
8430841b 638 fprintf(f, "REQUIRED_FAMILY_FOR_ONLINE=%s\n",
a853cc99 639 link_required_address_family_to_string(link_required_family_for_online(link)));
8430841b 640
3b5a4fc6
YW
641 fprintf(f, "ACTIVATION_POLICY=%s\n",
642 activation_policy_to_string(link->network->activation_policy));
643
644 fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
645
a2640646
DDM
646 fputs("NETWORK_FILE_DROPINS=\"", f);
647 STRV_FOREACH(d, link->network->dropins) {
648 _cleanup_free_ char *escaped = NULL;
649
650 escaped = xescape(*d, ":");
651 if (!escaped)
652 return -ENOMEM;
653
215286a4 654 fputs_with_separator(f, escaped, ":", &space);
a2640646
DDM
655 }
656 fputs("\"\n", f);
657
3b5a4fc6
YW
658 /************************************************************/
659
56437e33
YW
660 fputs("DNS=", f);
661 if (link->n_dns != UINT_MAX)
662 link_save_dns(link, f, link->dns, link->n_dns, NULL);
663 else {
664 space = false;
665 link_save_dns(link, f, link->network->dns, link->network->n_dns, &space);
3b5a4fc6 666
56437e33
YW
667 serialize_addresses(f, NULL, &space,
668 NULL,
669 link->dhcp_lease,
9646ffe2 670 link_get_use_dns(link, NETWORK_CONFIG_SOURCE_DHCP4),
56437e33
YW
671 SD_DHCP_LEASE_DNS,
672 link->dhcp6_lease,
9646ffe2 673 link_get_use_dns(link, NETWORK_CONFIG_SOURCE_DHCP6),
56437e33
YW
674 sd_dhcp6_lease_get_dns,
675 NULL);
676
9646ffe2 677 if (link_get_use_dns(link, NETWORK_CONFIG_SOURCE_NDISC)) {
56437e33
YW
678 NDiscRDNSS *dd;
679
680 SET_FOREACH(dd, link->ndisc_rdnss)
681 serialize_in6_addrs(f, &dd->address, 1, &space);
682 }
3b5a4fc6
YW
683 }
684
685 fputc('\n', f);
686
687 /************************************************************/
688
56437e33
YW
689 if (link->ntp) {
690 fputs("NTP=", f);
691 fputstrv(f, link->ntp, NULL, NULL);
692 fputc('\n', f);
693 } else
694 serialize_addresses(f, "NTP", NULL,
695 link->network->ntp,
696 link->dhcp_lease,
d12fb2bc 697 link_get_use_ntp(link, NETWORK_CONFIG_SOURCE_DHCP4),
56437e33
YW
698 SD_DHCP_LEASE_NTP,
699 link->dhcp6_lease,
d12fb2bc 700 link_get_use_ntp(link, NETWORK_CONFIG_SOURCE_DHCP6),
56437e33
YW
701 sd_dhcp6_lease_get_ntp_addrs,
702 sd_dhcp6_lease_get_ntp_fqdn);
3b5a4fc6
YW
703
704 serialize_addresses(f, "SIP", NULL,
705 NULL,
706 link->dhcp_lease,
707 link->network->dhcp_use_sip,
708 SD_DHCP_LEASE_SIP,
709 NULL, false, NULL, NULL);
710
711 /************************************************************/
712
6341ea54
YW
713 r = link_get_captive_portal(link, &captive_portal);
714 if (r < 0)
715 return r;
a75feb55 716
6341ea54
YW
717 if (captive_portal)
718 fprintf(f, "CAPTIVE_PORTAL=%s\n", captive_portal);
edb88a72
RP
719
720 /************************************************************/
721
3b5a4fc6 722 fputs("DOMAINS=", f);
56437e33 723 if (link->search_domains)
78f5c649 724 link_save_domains(link, f, link->search_domains, USE_DOMAINS_NO);
56437e33 725 else
78f5c649 726 link_save_domains(link, f, link->network->search_domains, USE_DOMAINS_YES);
3b5a4fc6
YW
727 fputc('\n', f);
728
729 /************************************************************/
730
731 fputs("ROUTE_DOMAINS=", f);
56437e33 732 if (link->route_domains)
78f5c649 733 link_save_domains(link, f, link->route_domains, USE_DOMAINS_NO);
56437e33 734 else
78f5c649 735 link_save_domains(link, f, link->network->route_domains, USE_DOMAINS_ROUTE);
3b5a4fc6
YW
736 fputc('\n', f);
737
738 /************************************************************/
739
740 fprintf(f, "LLMNR=%s\n",
741 resolve_support_to_string(link->llmnr >= 0 ? link->llmnr : link->network->llmnr));
742
743 /************************************************************/
744
745 fprintf(f, "MDNS=%s\n",
746 resolve_support_to_string(link->mdns >= 0 ? link->mdns : link->network->mdns));
747
748 /************************************************************/
749
750 int dns_default_route =
751 link->dns_default_route >= 0 ? link->dns_default_route :
752 link->network->dns_default_route;
753 if (dns_default_route >= 0)
754 fprintf(f, "DNS_DEFAULT_ROUTE=%s\n", yes_no(dns_default_route));
755
756 /************************************************************/
757
758 DnsOverTlsMode dns_over_tls_mode =
759 link->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID ? link->dns_over_tls_mode :
760 link->network->dns_over_tls_mode;
761 if (dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID)
762 fprintf(f, "DNS_OVER_TLS=%s\n", dns_over_tls_mode_to_string(dns_over_tls_mode));
763
764 /************************************************************/
765
766 DnssecMode dnssec_mode =
767 link->dnssec_mode != _DNSSEC_MODE_INVALID ? link->dnssec_mode :
768 link->network->dnssec_mode;
769 if (dnssec_mode != _DNSSEC_MODE_INVALID)
770 fprintf(f, "DNSSEC=%s\n", dnssec_mode_to_string(dnssec_mode));
771
772 /************************************************************/
773
774 Set *nta_anchors = link->dnssec_negative_trust_anchors;
775 if (set_isempty(nta_anchors))
776 nta_anchors = link->network->dnssec_negative_trust_anchors;
777
778 if (!set_isempty(nta_anchors)) {
779 const char *n;
780
781 fputs("DNSSEC_NTA=", f);
782 space = false;
783 SET_FOREACH(n, nta_anchors)
215286a4 784 fputs_with_separator(f, n, NULL, &space);
3b5a4fc6
YW
785 fputc('\n', f);
786 }
787 }
788
789 print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links);
790 print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links);
791
792 if (link->dhcp_lease) {
793 r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
794 if (r < 0)
d23a66f2 795 return r;
3b5a4fc6
YW
796
797 fprintf(f,
798 "DHCP_LEASE=%s\n",
799 link->lease_file);
800 } else
801 (void) unlink(link->lease_file);
802
803 r = link_serialize_dhcp6_client(link, f);
804 if (r < 0)
d23a66f2 805 return r;
3b5a4fc6
YW
806
807 r = fflush_and_check(f);
808 if (r < 0)
d23a66f2 809 return r;
3b5a4fc6
YW
810
811 r = conservative_rename(temp_path, link->state_file);
812 if (r < 0)
d23a66f2 813 return r;
3b5a4fc6 814
d23a66f2 815 temp_path = mfree(temp_path);
3b5a4fc6 816
d23a66f2 817 return 0;
3b5a4fc6
YW
818}
819
820void link_dirty(Link *link) {
821 int r;
822
823 assert(link);
824 assert(link->manager);
825
826 /* The serialized state in /run is no longer up-to-date. */
827
828 /* Also mark manager dirty as link is dirty */
829 link->manager->dirty = true;
830
831 r = set_ensure_put(&link->manager->dirty_links, NULL, link);
832 if (r <= 0)
833 /* Ignore allocation errors and don't take another ref if the link was already dirty */
834 return;
835 link_ref(link);
836}
837
838void link_clean(Link *link) {
839 assert(link);
840 assert(link->manager);
841
842 /* The serialized state in /run is up-to-date */
843
844 link_unref(set_remove(link->manager->dirty_links, link));
845}
846
bd7d9028
YW
847int link_save_and_clean_full(Link *link, bool also_save_manager) {
848 int r, k = 0;
849
850 assert(link);
851 assert(link->manager);
852
853 if (also_save_manager)
854 k = manager_save(link->manager);
3b5a4fc6
YW
855
856 r = link_save(link);
857 if (r < 0)
858 return r;
859
860 link_clean(link);
bd7d9028 861 return k;
3b5a4fc6 862}
2e1113b7
YW
863
864int manager_clean_all(Manager *manager) {
865 int r, ret = 0;
866
867 assert(manager);
868
869 if (manager->dirty) {
870 r = manager_save(manager);
871 if (r < 0)
872 log_warning_errno(r, "Failed to update state file %s, ignoring: %m", manager->state_file);
873 RET_GATHER(ret, r);
874 }
875
876 Link *link;
877 SET_FOREACH(link, manager->dirty_links) {
878 r = link_save_and_clean(link);
879 if (r < 0)
880 log_link_warning_errno(link, r, "Failed to update link state file %s, ignoring: %m", link->state_file);
881 RET_GATHER(ret, r);
882 }
883
884 return ret;
885}