1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <netinet/in.h>
4 #include <linux/if.h>
5
6 #include "alloc-util.h"
7 #include "dns-domain.h"
8 #include "fd-util.h"
9 #include "fileio.h"
10 #include "fs-util.h"
11 #include "network-internal.h"
12 #include "networkd-link.h"
13 #include "networkd-manager-bus.h"
14 #include "networkd-manager.h"
15 #include "networkd-network.h"
16 #include "networkd-state-file.h"
17 #include "ordered-set.h"
18 #include "set.h"
19 #include "strv.h"
20 #include "tmpfile-util.h"
21
ordered_set_put_dns_server(OrderedSet ** s,int ifindex,struct in_addr_full * dns)22 static int ordered_set_put_dns_server(OrderedSet **s, int ifindex, struct in_addr_full *dns) {
23 const char *p;
24 int r;
25
26 assert(s);
27 assert(dns);
28
29 if (dns->ifindex != 0 && dns->ifindex != ifindex)
30 return 0;
31
32 p = in_addr_full_to_string(dns);
33 if (!p)
34 return 0;
35
36 r = ordered_set_put_strdup(s, p);
37 if (r == -EEXIST)
38 return 0;
39
40 return r;
41 }
42
ordered_set_put_dns_servers(OrderedSet ** s,int ifindex,struct in_addr_full ** dns,unsigned n)43 static int ordered_set_put_dns_servers(OrderedSet **s, int ifindex, struct in_addr_full **dns, unsigned n) {
44 int r, c = 0;
45
46 assert(s);
47 assert(dns || n == 0);
48
49 for (unsigned i = 0; i < n; i++) {
50 r = ordered_set_put_dns_server(s, ifindex, dns[i]);
51 if (r < 0)
52 return r;
53
54 c += r;
55 }
56
57 return c;
58 }
59
ordered_set_put_in4_addr(OrderedSet ** s,const struct in_addr * address)60 static int ordered_set_put_in4_addr(OrderedSet **s, const struct in_addr *address) {
61 _cleanup_free_ char *p = NULL;
62 int r;
63
64 assert(s);
65 assert(address);
66
67 r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
68 if (r < 0)
69 return r;
70
71 r = ordered_set_ensure_allocated(s, &string_hash_ops_free);
72 if (r < 0)
73 return r;
74
75 r = ordered_set_consume(*s, TAKE_PTR(p));
76 if (r == -EEXIST)
77 return 0;
78
79 return r;
80 }
81
ordered_set_put_in4_addrv(OrderedSet ** s,const struct in_addr * addresses,size_t n,bool (* predicate)(const struct in_addr * addr))82 static int ordered_set_put_in4_addrv(
83 OrderedSet **s,
84 const struct in_addr *addresses,
85 size_t n,
86 bool (*predicate)(const struct in_addr *addr)) {
87
88 int r, c = 0;
89
90 assert(s);
91 assert(n == 0 || addresses);
92
93 for (size_t i = 0; i < n; i++) {
94 if (predicate && !predicate(&addresses[i]))
95 continue;
96 r = ordered_set_put_in4_addr(s, addresses+i);
97 if (r < 0)
98 return r;
99
100 c += r;
101 }
102
103 return c;
104 }
105
manager_save(Manager * m)106 int manager_save(Manager *m) {
107 _cleanup_ordered_set_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL;
108 const char *operstate_str, *carrier_state_str, *address_state_str, *ipv4_address_state_str, *ipv6_address_state_str, *online_state_str;
109 LinkOperationalState operstate = LINK_OPERSTATE_OFF;
110 LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
111 LinkAddressState ipv4_address_state = LINK_ADDRESS_STATE_OFF, ipv6_address_state = LINK_ADDRESS_STATE_OFF,
112 address_state = LINK_ADDRESS_STATE_OFF;
113 LinkOnlineState online_state;
114 size_t links_offline = 0, links_online = 0;
115 _cleanup_(unlink_and_freep) char *temp_path = NULL;
116 _cleanup_strv_free_ char **p = NULL;
117 _cleanup_fclose_ FILE *f = NULL;
118 Link *link;
119 int r;
120
121 assert(m);
122
123 if (isempty(m->state_file))
124 return 0; /* Do not update state file when running in test mode. */
125
126 HASHMAP_FOREACH(link, m->links_by_index) {
127 const struct in_addr *addresses;
128
129 if (link->flags & IFF_LOOPBACK)
130 continue;
131
132 operstate = MAX(operstate, link->operstate);
133 carrier_state = MAX(carrier_state, link->carrier_state);
134 address_state = MAX(address_state, link->address_state);
135 ipv4_address_state = MAX(ipv4_address_state, link->ipv4_address_state);
136 ipv6_address_state = MAX(ipv6_address_state, link->ipv6_address_state);
137
138 if (!link->network)
139 continue;
140
141 if (link->network->required_for_online) {
142 if (link->online_state == LINK_ONLINE_STATE_OFFLINE)
143 links_offline++;
144 else if (link->online_state == LINK_ONLINE_STATE_ONLINE)
145 links_online++;
146 }
147
148 /* First add the static configured entries */
149 if (link->n_dns != UINT_MAX)
150 r = ordered_set_put_dns_servers(&dns, link->ifindex, link->dns, link->n_dns);
151 else
152 r = ordered_set_put_dns_servers(&dns, link->ifindex, link->network->dns, link->network->n_dns);
153 if (r < 0)
154 return r;
155
156 r = ordered_set_put_strdupv(&ntp, link->ntp ?: link->network->ntp);
157 if (r < 0)
158 return r;
159
160 r = ordered_set_put_string_set(&search_domains, link->search_domains ?: link->network->search_domains);
161 if (r < 0)
162 return r;
163
164 r = ordered_set_put_string_set(&route_domains, link->route_domains ?: link->network->route_domains);
165 if (r < 0)
166 return r;
167
168 if (!link->dhcp_lease)
169 continue;
170
171 /* Secondly, add the entries acquired via DHCP */
172 if (link->network->dhcp_use_dns) {
173 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
174 if (r > 0) {
175 r = ordered_set_put_in4_addrv(&dns, addresses, r, in4_addr_is_non_local);
176 if (r < 0)
177 return r;
178 } else if (r < 0 && r != -ENODATA)
179 return r;
180 }
181
182 if (link->network->dhcp_use_ntp) {
183 r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
184 if (r > 0) {
185 r = ordered_set_put_in4_addrv(&ntp, addresses, r, in4_addr_is_non_local);
186 if (r < 0)
187 return r;
188 } else if (r < 0 && r != -ENODATA)
189 return r;
190 }
191
192 if (link->network->dhcp_use_sip) {
193 r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
194 if (r > 0) {
195 r = ordered_set_put_in4_addrv(&sip, addresses, r, in4_addr_is_non_local);
196 if (r < 0)
197 return r;
198 } else if (r < 0 && r != -ENODATA)
199 return r;
200 }
201
202 if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
203 OrderedSet **target_domains;
204 const char *domainname;
205 char **domains = NULL;
206
207 target_domains = (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) ? &search_domains : &route_domains;
208 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
209 if (r >= 0) {
210 r = ordered_set_put_strdup(target_domains, domainname);
211 if (r < 0)
212 return r;
213 } else if (r != -ENODATA)
214 return r;
215
216 r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains);
217 if (r >= 0) {
218 r = ordered_set_put_strdupv(target_domains, domains);
219 if (r < 0)
220 return r;
221 } else if (r != -ENODATA)
222 return r;
223 }
224 }
225
226 if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED)
227 carrier_state = LINK_CARRIER_STATE_CARRIER;
228
229 online_state = links_online > 0 ?
230 (links_offline > 0 ? LINK_ONLINE_STATE_PARTIAL : LINK_ONLINE_STATE_ONLINE) :
231 (links_offline > 0 ? LINK_ONLINE_STATE_OFFLINE : _LINK_ONLINE_STATE_INVALID);
232
233 operstate_str = link_operstate_to_string(operstate);
234 assert(operstate_str);
235
236 carrier_state_str = link_carrier_state_to_string(carrier_state);
237 assert(carrier_state_str);
238
239 address_state_str = link_address_state_to_string(address_state);
240 assert(address_state_str);
241
242 ipv4_address_state_str = link_address_state_to_string(ipv4_address_state);
243 assert(ipv4_address_state_str);
244
245 ipv6_address_state_str = link_address_state_to_string(ipv6_address_state);
246 assert(ipv6_address_state_str);
247
248 r = fopen_temporary(m->state_file, &f, &temp_path);
249 if (r < 0)
250 return r;
251
252 (void) fchmod(fileno(f), 0644);
253
254 fprintf(f,
255 "# This is private data. Do not parse.\n"
256 "OPER_STATE=%s\n"
257 "CARRIER_STATE=%s\n"
258 "ADDRESS_STATE=%s\n"
259 "IPV4_ADDRESS_STATE=%s\n"
260 "IPV6_ADDRESS_STATE=%s\n",
261 operstate_str, carrier_state_str, address_state_str, ipv4_address_state_str, ipv6_address_state_str);
262
263 online_state_str = link_online_state_to_string(online_state);
264 if (online_state_str)
265 fprintf(f, "ONLINE_STATE=%s\n", online_state_str);
266
267 ordered_set_print(f, "DNS=", dns);
268 ordered_set_print(f, "NTP=", ntp);
269 ordered_set_print(f, "SIP=", sip);
270 ordered_set_print(f, "DOMAINS=", search_domains);
271 ordered_set_print(f, "ROUTE_DOMAINS=", route_domains);
272
273 r = fflush_and_check(f);
274 if (r < 0)
275 return r;
276
277 r = conservative_rename(temp_path, m->state_file);
278 if (r < 0)
279 return r;
280
281 temp_path = mfree(temp_path);
282
283 if (m->operational_state != operstate) {
284 m->operational_state = operstate;
285 if (strv_extend(&p, "OperationalState") < 0)
286 log_oom();
287 }
288
289 if (m->carrier_state != carrier_state) {
290 m->carrier_state = carrier_state;
291 if (strv_extend(&p, "CarrierState") < 0)
292 log_oom();
293 }
294
295 if (m->address_state != address_state) {
296 m->address_state = address_state;
297 if (strv_extend(&p, "AddressState") < 0)
298 log_oom();
299 }
300
301 if (m->ipv4_address_state != ipv4_address_state) {
302 m->ipv4_address_state = ipv4_address_state;
303 if (strv_extend(&p, "IPv4AddressState") < 0)
304 log_oom();
305 }
306
307 if (m->ipv6_address_state != ipv6_address_state) {
308 m->ipv6_address_state = ipv6_address_state;
309 if (strv_extend(&p, "IPv6AddressState") < 0)
310 log_oom();
311 }
312
313 if (m->online_state != online_state) {
314 m->online_state = online_state;
315 if (strv_extend(&p, "OnlineState") < 0)
316 log_oom();
317 }
318
319 if (p) {
320 r = manager_send_changed_strv(m, p);
321 if (r < 0)
322 log_warning_errno(r, "Could not emit changed properties, ignoring: %m");
323 }
324
325 m->dirty = false;
326
327 return 0;
328 }
329
print_link_hashmap(FILE * f,const char * prefix,Hashmap * h)330 static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
331 bool space = false;
332 Link *link;
333
334 assert(f);
335 assert(prefix);
336
337 if (hashmap_isempty(h))
338 return;
339
340 fputs(prefix, f);
341 HASHMAP_FOREACH(link, h) {
342 if (space)
343 fputc(' ', f);
344
345 fprintf(f, "%i", link->ifindex);
346 space = true;
347 }
348
349 fputc('\n', f);
350 }
351
link_save_dns(Link * link,FILE * f,struct in_addr_full ** dns,unsigned n_dns,bool * space)352 static void link_save_dns(Link *link, FILE *f, struct in_addr_full **dns, unsigned n_dns, bool *space) {
353 bool _space = false;
354
355 if (!space)
356 space = &_space;
357
358 for (unsigned j = 0; j < n_dns; j++) {
359 const char *str;
360
361 if (dns[j]->ifindex != 0 && dns[j]->ifindex != link->ifindex)
362 continue;
363
364 str = in_addr_full_to_string(dns[j]);
365 if (!str)
366 continue;
367
368 if (*space)
369 fputc(' ', f);
370 fputs(str, f);
371 *space = true;
372 }
373 }
374
serialize_addresses(FILE * f,const char * lvalue,bool * space,char ** addresses,sd_dhcp_lease * lease,bool conditional,sd_dhcp_lease_server_type_t what,sd_dhcp6_lease * lease6,bool conditional6,int (* lease6_get_addr)(sd_dhcp6_lease *,const struct in6_addr **),int (* lease6_get_fqdn)(sd_dhcp6_lease *,char ***))375 static void serialize_addresses(
376 FILE *f,
377 const char *lvalue,
378 bool *space,
379 char **addresses,
380 sd_dhcp_lease *lease,
381 bool conditional,
382 sd_dhcp_lease_server_type_t what,
383 sd_dhcp6_lease *lease6,
384 bool conditional6,
385 int (*lease6_get_addr)(sd_dhcp6_lease*, const struct in6_addr**),
386 int (*lease6_get_fqdn)(sd_dhcp6_lease*, char ***)) {
387
388 bool _space = false;
389 int r;
390
391 if (!space)
392 space = &_space;
393
394 if (lvalue)
395 fprintf(f, "%s=", lvalue);
396 fputstrv(f, addresses, NULL, space);
397
398 if (lease && conditional) {
399 const struct in_addr *lease_addresses;
400
401 r = sd_dhcp_lease_get_servers(lease, what, &lease_addresses);
402 if (r > 0)
403 serialize_in_addrs(f, lease_addresses, r, space, in4_addr_is_non_local);
404 }
405
406 if (lease6 && conditional6 && lease6_get_addr) {
407 const struct in6_addr *in6_addrs;
408
409 r = lease6_get_addr(lease6, &in6_addrs);
410 if (r > 0)
411 serialize_in6_addrs(f, in6_addrs, r, space);
412 }
413
414 if (lease6 && conditional6 && lease6_get_fqdn) {
415 char **in6_hosts;
416
417 r = lease6_get_fqdn(lease6, &in6_hosts);
418 if (r > 0)
419 fputstrv(f, in6_hosts, NULL, space);
420 }
421
422 if (lvalue)
423 fputc('\n', f);
424 }
425
link_save_domains(Link * link,FILE * f,OrderedSet * static_domains,DHCPUseDomains use_domains)426 static void link_save_domains(Link *link, FILE *f, OrderedSet *static_domains, DHCPUseDomains use_domains) {
427 bool space = false;
428 const char *p;
429
430 assert(link);
431 assert(link->network);
432 assert(f);
433
434 ORDERED_SET_FOREACH(p, static_domains)
435 fputs_with_space(f, p, NULL, &space);
436
437 if (use_domains == DHCP_USE_DOMAINS_NO)
438 return;
439
440 if (link->dhcp_lease && link->network->dhcp_use_domains == use_domains) {
441 const char *domainname;
442 char **domains;
443
444 if (sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname) >= 0)
445 fputs_with_space(f, domainname, NULL, &space);
446 if (sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains) >= 0)
447 fputstrv(f, domains, NULL, &space);
448 }
449
450 if (link->dhcp6_lease && link->network->dhcp6_use_domains == use_domains) {
451 char **domains;
452
453 if (sd_dhcp6_lease_get_domains(link->dhcp6_lease, &domains) >= 0)
454 fputstrv(f, domains, NULL, &space);
455 }
456
457 if (link->network->ipv6_accept_ra_use_domains == use_domains) {
458 NDiscDNSSL *dd;
459
460 SET_FOREACH(dd, link->ndisc_dnssl)
461 fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
462 }
463 }
464
link_save(Link * link)465 int link_save(Link *link) {
466 const char *admin_state, *oper_state, *carrier_state, *address_state, *ipv4_address_state, *ipv6_address_state;
467 _cleanup_(unlink_and_freep) char *temp_path = NULL;
468 _cleanup_fclose_ FILE *f = NULL;
469 int r;
470
471 assert(link);
472 assert(link->manager);
473
474 if (isempty(link->state_file))
475 return 0; /* Do not update state files when running in test mode. */
476
477 if (link->state == LINK_STATE_LINGER)
478 return 0;
479
480 link_lldp_save(link);
481
482 admin_state = link_state_to_string(link->state);
483 assert(admin_state);
484
485 oper_state = link_operstate_to_string(link->operstate);
486 assert(oper_state);
487
488 carrier_state = link_carrier_state_to_string(link->carrier_state);
489 assert(carrier_state);
490
491 address_state = link_address_state_to_string(link->address_state);
492 assert(address_state);
493
494 ipv4_address_state = link_address_state_to_string(link->ipv4_address_state);
495 assert(ipv4_address_state);
496
497 ipv6_address_state = link_address_state_to_string(link->ipv6_address_state);
498 assert(ipv6_address_state);
499
500 r = fopen_temporary(link->state_file, &f, &temp_path);
501 if (r < 0)
502 return r;
503
504 (void) fchmod(fileno(f), 0644);
505
506 fprintf(f,
507 "# This is private data. Do not parse.\n"
508 "ADMIN_STATE=%s\n"
509 "OPER_STATE=%s\n"
510 "CARRIER_STATE=%s\n"
511 "ADDRESS_STATE=%s\n"
512 "IPV4_ADDRESS_STATE=%s\n"
513 "IPV6_ADDRESS_STATE=%s\n",
514 admin_state, oper_state, carrier_state, address_state, ipv4_address_state, ipv6_address_state);
515
516 if (link->network) {
517 const char *online_state;
518 bool space;
519
520 online_state = link_online_state_to_string(link->online_state);
521 if (online_state)
522 fprintf(f, "ONLINE_STATE=%s\n", online_state);
523
524 fprintf(f, "REQUIRED_FOR_ONLINE=%s\n",
525 yes_no(link->network->required_for_online));
526
527 LinkOperationalStateRange st = link->network->required_operstate_for_online;
528 fprintf(f, "REQUIRED_OPER_STATE_FOR_ONLINE=%s%s%s\n",
529 strempty(link_operstate_to_string(st.min)),
530 st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? ":" : "",
531 st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? strempty(link_operstate_to_string(st.max)) : "");
532
533 fprintf(f, "REQUIRED_FAMILY_FOR_ONLINE=%s\n",
534 link_required_address_family_to_string(link->network->required_family_for_online));
535
536 fprintf(f, "ACTIVATION_POLICY=%s\n",
537 activation_policy_to_string(link->network->activation_policy));
538
539 fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
540
541 /************************************************************/
542
543 /* Make sure to flush out old entries before we use the NDisc data */
544 ndisc_vacuum(link);
545
546 fputs("DNS=", f);
547 if (link->n_dns != UINT_MAX)
548 link_save_dns(link, f, link->dns, link->n_dns, NULL);
549 else {
550 space = false;
551 link_save_dns(link, f, link->network->dns, link->network->n_dns, &space);
552
553 serialize_addresses(f, NULL, &space,
554 NULL,
555 link->dhcp_lease,
556 link->network->dhcp_use_dns,
557 SD_DHCP_LEASE_DNS,
558 link->dhcp6_lease,
559 link->network->dhcp6_use_dns,
560 sd_dhcp6_lease_get_dns,
561 NULL);
562
563 if (link->network->ipv6_accept_ra_use_dns) {
564 NDiscRDNSS *dd;
565
566 SET_FOREACH(dd, link->ndisc_rdnss)
567 serialize_in6_addrs(f, &dd->address, 1, &space);
568 }
569 }
570
571 fputc('\n', f);
572
573 /************************************************************/
574
575 if (link->ntp) {
576 fputs("NTP=", f);
577 fputstrv(f, link->ntp, NULL, NULL);
578 fputc('\n', f);
579 } else
580 serialize_addresses(f, "NTP", NULL,
581 link->network->ntp,
582 link->dhcp_lease,
583 link->network->dhcp_use_ntp,
584 SD_DHCP_LEASE_NTP,
585 link->dhcp6_lease,
586 link->network->dhcp6_use_ntp,
587 sd_dhcp6_lease_get_ntp_addrs,
588 sd_dhcp6_lease_get_ntp_fqdn);
589
590 serialize_addresses(f, "SIP", NULL,
591 NULL,
592 link->dhcp_lease,
593 link->network->dhcp_use_sip,
594 SD_DHCP_LEASE_SIP,
595 NULL, false, NULL, NULL);
596
597 /************************************************************/
598
599 fputs("DOMAINS=", f);
600 if (link->search_domains)
601 link_save_domains(link, f, link->search_domains, DHCP_USE_DOMAINS_NO);
602 else
603 link_save_domains(link, f, link->network->search_domains, DHCP_USE_DOMAINS_YES);
604 fputc('\n', f);
605
606 /************************************************************/
607
608 fputs("ROUTE_DOMAINS=", f);
609 if (link->route_domains)
610 link_save_domains(link, f, link->route_domains, DHCP_USE_DOMAINS_NO);
611 else
612 link_save_domains(link, f, link->network->route_domains, DHCP_USE_DOMAINS_ROUTE);
613 fputc('\n', f);
614
615 /************************************************************/
616
617 fprintf(f, "LLMNR=%s\n",
618 resolve_support_to_string(link->llmnr >= 0 ? link->llmnr : link->network->llmnr));
619
620 /************************************************************/
621
622 fprintf(f, "MDNS=%s\n",
623 resolve_support_to_string(link->mdns >= 0 ? link->mdns : link->network->mdns));
624
625 /************************************************************/
626
627 int dns_default_route =
628 link->dns_default_route >= 0 ? link->dns_default_route :
629 link->network->dns_default_route;
630 if (dns_default_route >= 0)
631 fprintf(f, "DNS_DEFAULT_ROUTE=%s\n", yes_no(dns_default_route));
632
633 /************************************************************/
634
635 DnsOverTlsMode dns_over_tls_mode =
636 link->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID ? link->dns_over_tls_mode :
637 link->network->dns_over_tls_mode;
638 if (dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID)
639 fprintf(f, "DNS_OVER_TLS=%s\n", dns_over_tls_mode_to_string(dns_over_tls_mode));
640
641 /************************************************************/
642
643 DnssecMode dnssec_mode =
644 link->dnssec_mode != _DNSSEC_MODE_INVALID ? link->dnssec_mode :
645 link->network->dnssec_mode;
646 if (dnssec_mode != _DNSSEC_MODE_INVALID)
647 fprintf(f, "DNSSEC=%s\n", dnssec_mode_to_string(dnssec_mode));
648
649 /************************************************************/
650
651 Set *nta_anchors = link->dnssec_negative_trust_anchors;
652 if (set_isempty(nta_anchors))
653 nta_anchors = link->network->dnssec_negative_trust_anchors;
654
655 if (!set_isempty(nta_anchors)) {
656 const char *n;
657
658 fputs("DNSSEC_NTA=", f);
659 space = false;
660 SET_FOREACH(n, nta_anchors)
661 fputs_with_space(f, n, NULL, &space);
662 fputc('\n', f);
663 }
664 }
665
666 print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links);
667 print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links);
668
669 if (link->dhcp_lease) {
670 r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
671 if (r < 0)
672 return r;
673
674 fprintf(f,
675 "DHCP_LEASE=%s\n",
676 link->lease_file);
677 } else
678 (void) unlink(link->lease_file);
679
680 r = link_serialize_dhcp6_client(link, f);
681 if (r < 0)
682 return r;
683
684 r = fflush_and_check(f);
685 if (r < 0)
686 return r;
687
688 r = conservative_rename(temp_path, link->state_file);
689 if (r < 0)
690 return r;
691
692 temp_path = mfree(temp_path);
693
694 return 0;
695 }
696
link_dirty(Link * link)697 void link_dirty(Link *link) {
698 int r;
699
700 assert(link);
701 assert(link->manager);
702
703 /* The serialized state in /run is no longer up-to-date. */
704
705 /* Also mark manager dirty as link is dirty */
706 link->manager->dirty = true;
707
708 r = set_ensure_put(&link->manager->dirty_links, NULL, link);
709 if (r <= 0)
710 /* Ignore allocation errors and don't take another ref if the link was already dirty */
711 return;
712 link_ref(link);
713 }
714
link_clean(Link * link)715 void link_clean(Link *link) {
716 assert(link);
717 assert(link->manager);
718
719 /* The serialized state in /run is up-to-date */
720
721 link_unref(set_remove(link->manager->dirty_links, link));
722 }
723
link_save_and_clean(Link * link)724 int link_save_and_clean(Link *link) {
725 int r;
726
727 r = link_save(link);
728 if (r < 0)
729 return r;
730
731 link_clean(link);
732 return 0;
733 }
734