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