]>
Commit | Line | Data |
---|---|---|
60918275 LP |
1 | /*-*- Mode: C; c-basic-offset: 8 -*-*/ |
2 | ||
3 | #include <assert.h> | |
4 | #include <errno.h> | |
07232470 | 5 | #include <string.h> |
60918275 LP |
6 | |
7 | #include "set.h" | |
8 | #include "name.h" | |
9 | #include "macro.h" | |
10 | #include "strv.h" | |
7fad411c | 11 | #include "load-fragment.h" |
60918275 LP |
12 | |
13 | NameType name_type_from_string(const char *n) { | |
14 | NameType t; | |
15 | static const char* suffixes[_NAME_TYPE_MAX] = { | |
16 | [NAME_SERVICE] = ".service", | |
17 | [NAME_TIMER] = ".timer", | |
18 | [NAME_SOCKET] = ".socket", | |
19 | [NAME_MILESTONE] = ".milestone", | |
20 | [NAME_DEVICE] = ".device", | |
21 | [NAME_MOUNT] = ".mount", | |
22 | [NAME_AUTOMOUNT] = ".automount", | |
23 | [NAME_SNAPSHOT] = ".snapshot", | |
24 | }; | |
25 | ||
26 | assert(n); | |
27 | ||
28 | for (t = 0; t < _NAME_TYPE_MAX; t++) | |
29 | if (endswith(n, suffixes[t])) | |
30 | return t; | |
31 | ||
32 | return _NAME_TYPE_INVALID; | |
33 | } | |
34 | ||
07232470 LP |
35 | #define VALID_CHARS \ |
36 | "0123456789" \ | |
37 | "abcdefghijklmnopqrstuvwxyz" \ | |
38 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ | |
39 | "-_" | |
40 | ||
41 | bool name_is_valid(const char *n) { | |
42 | NameType t; | |
43 | const char *e, *i; | |
44 | ||
45 | assert(n); | |
46 | ||
47 | t = name_type_from_string(n); | |
48 | if (t < 0 || t >= _NAME_TYPE_MAX) | |
49 | return false; | |
50 | ||
51 | if (!(e = strrchr(n, '.'))) | |
52 | return false; | |
53 | ||
54 | for (i = n; i < e; i++) | |
55 | if (!strchr(VALID_CHARS, *i)) | |
56 | return false; | |
57 | ||
58 | return true; | |
59 | } | |
60 | ||
60918275 LP |
61 | Name *name_new(Manager *m) { |
62 | Name *n; | |
63 | ||
64 | assert(m); | |
65 | ||
66 | if (!(n = new0(Name, 1))) | |
67 | return NULL; | |
68 | ||
87d1515d LP |
69 | if (!(n->meta.names = set_new(string_hash_func, string_compare_func))) { |
70 | free(n); | |
71 | return NULL; | |
72 | } | |
73 | ||
60918275 LP |
74 | /* Not much initialization happening here at this time */ |
75 | n->meta.manager = m; | |
76 | n->meta.type = _NAME_TYPE_INVALID; | |
77 | n->meta.state = NAME_STUB; | |
78 | ||
79 | /* We don't link the name here, that is left for name_link() */ | |
80 | ||
81 | return n; | |
82 | } | |
83 | ||
e5b5ae50 LP |
84 | /* FIXME: Does not rollback on failure! */ |
85 | int name_link_names(Name *n, bool replace) { | |
11dd41ce LP |
86 | char *t; |
87 | void *state; | |
88 | int r; | |
89 | ||
90 | assert(n); | |
91 | ||
92 | if (!n->meta.linked) | |
93 | return 0; | |
94 | ||
e5b5ae50 | 95 | /* Link all names that aren't linked yet. */ |
11dd41ce LP |
96 | |
97 | SET_FOREACH(t, n->meta.names, state) | |
e5b5ae50 LP |
98 | if (replace) { |
99 | if ((r = hashmap_replace(n->meta.manager->names, t, n)) < 0) | |
100 | return r; | |
101 | } else { | |
102 | if ((r = hashmap_put(n->meta.manager->names, t, n)) < 0) | |
103 | return r; | |
11dd41ce LP |
104 | } |
105 | ||
106 | return 0; | |
107 | } | |
108 | ||
60918275 | 109 | int name_link(Name *n) { |
60918275 LP |
110 | int r; |
111 | ||
112 | assert(n); | |
87d1515d | 113 | assert(!set_isempty(n->meta.names)); |
60918275 LP |
114 | assert(!n->meta.linked); |
115 | ||
7fad411c LP |
116 | if ((r = name_sanitize(n)) < 0) |
117 | return r; | |
118 | ||
11dd41ce | 119 | n->meta.linked = true; |
60918275 | 120 | |
7fad411c | 121 | if ((r = name_link_names(n, false)) < 0) { |
11dd41ce LP |
122 | char *t; |
123 | void *state; | |
60918275 | 124 | |
11dd41ce LP |
125 | /* Rollback the registered names */ |
126 | SET_FOREACH(t, n->meta.names, state) | |
e5b5ae50 | 127 | hashmap_remove_value(n->meta.manager->names, t, n); |
60918275 | 128 | |
11dd41ce LP |
129 | n->meta.linked = false; |
130 | return r; | |
131 | } | |
60918275 | 132 | |
11dd41ce LP |
133 | if (n->meta.state == NAME_STUB) |
134 | LIST_PREPEND(Meta, n->meta.manager->load_queue, &n->meta); | |
60918275 | 135 | |
11dd41ce | 136 | return 0; |
60918275 LP |
137 | } |
138 | ||
87d1515d LP |
139 | static void bidi_set_free(Name *name, Set *s) { |
140 | void *state; | |
141 | Name *other; | |
142 | ||
143 | assert(name); | |
87d1515d LP |
144 | |
145 | /* Frees the set and makes sure we are dropped from the | |
146 | * inverse pointers */ | |
147 | ||
148 | SET_FOREACH(other, s, state) { | |
149 | NameDependency d; | |
150 | ||
151 | for (d = 0; d < _NAME_DEPENDENCY_MAX; d++) | |
152 | set_remove(other->meta.dependencies[d], name); | |
153 | } | |
154 | ||
155 | set_free(s); | |
156 | } | |
157 | ||
60918275 | 158 | void name_free(Name *name) { |
87d1515d LP |
159 | NameDependency d; |
160 | char *t; | |
60918275 LP |
161 | |
162 | assert(name); | |
163 | ||
164 | /* Detach from next 'bigger' objects */ | |
60918275 | 165 | if (name->meta.linked) { |
11dd41ce | 166 | char *t; |
87d1515d | 167 | void *state; |
60918275 | 168 | |
87d1515d | 169 | SET_FOREACH(t, name->meta.names, state) |
e5b5ae50 | 170 | hashmap_remove_value(name->meta.manager->names, t, name); |
60918275 | 171 | |
87d1515d LP |
172 | if (name->meta.state == NAME_STUB) |
173 | LIST_REMOVE(Meta, name->meta.manager->load_queue, &name->meta); | |
60918275 LP |
174 | } |
175 | ||
176 | /* Free data and next 'smaller' objects */ | |
60918275 LP |
177 | if (name->meta.job) |
178 | job_free(name->meta.job); | |
179 | ||
87d1515d LP |
180 | for (d = 0; d < _NAME_DEPENDENCY_MAX; d++) |
181 | bidi_set_free(name, name->meta.dependencies[d]); | |
60918275 LP |
182 | |
183 | switch (name->meta.type) { | |
184 | ||
185 | case NAME_SOCKET: { | |
186 | unsigned i; | |
187 | Socket *s = SOCKET(name); | |
188 | ||
189 | for (i = 0; i < s->n_fds; i++) | |
42f4e3c4 | 190 | close_nointr(s->fds[i]); |
60918275 LP |
191 | break; |
192 | } | |
193 | ||
194 | case NAME_DEVICE: { | |
195 | Device *d = DEVICE(name); | |
196 | ||
197 | free(d->sysfs); | |
198 | break; | |
199 | } | |
200 | ||
201 | case NAME_MOUNT: { | |
202 | Mount *m = MOUNT(name); | |
203 | ||
204 | free(m->path); | |
205 | break; | |
206 | } | |
207 | ||
208 | case NAME_AUTOMOUNT: { | |
209 | Automount *a = AUTOMOUNT(name); | |
210 | ||
211 | free(a->path); | |
212 | break; | |
213 | } | |
214 | ||
215 | default: | |
216 | ; | |
217 | } | |
218 | ||
219 | free(name->meta.description); | |
87d1515d LP |
220 | |
221 | while ((t = set_steal_first(name->meta.names))) | |
222 | free(t); | |
223 | set_free(name->meta.names); | |
60918275 LP |
224 | |
225 | free(name); | |
226 | } | |
227 | ||
228 | bool name_is_ready(Name *name) { | |
229 | ||
230 | assert(name); | |
231 | ||
232 | if (name->meta.state != NAME_LOADED) | |
233 | return false; | |
234 | ||
235 | assert(name->meta.type < _NAME_TYPE_MAX); | |
236 | ||
237 | switch (name->meta.type) { | |
238 | case NAME_SERVICE: { | |
239 | Service *s = SERVICE(name); | |
240 | ||
241 | return | |
242 | s->state == SERVICE_RUNNING || | |
243 | s->state == SERVICE_RELOAD_PRE || | |
244 | s->state == SERVICE_RELOAD || | |
245 | s->state == SERVICE_RELOAD_POST; | |
246 | } | |
247 | ||
248 | case NAME_TIMER: { | |
249 | Timer *t = TIMER(name); | |
250 | ||
251 | return | |
252 | t->state == TIMER_WAITING || | |
253 | t->state == TIMER_RUNNING; | |
254 | } | |
255 | ||
256 | case NAME_SOCKET: { | |
257 | Socket *s = SOCKET(name); | |
258 | ||
259 | return | |
260 | s->state == SOCKET_LISTENING || | |
261 | s->state == SOCKET_RUNNING; | |
262 | } | |
263 | ||
264 | case NAME_MILESTONE: | |
265 | return MILESTONE(name)->state == MILESTONE_ACTIVE; | |
266 | ||
267 | case NAME_DEVICE: | |
268 | return DEVICE(name)->state == DEVICE_AVAILABLE; | |
269 | ||
270 | case NAME_MOUNT: | |
271 | return MOUNT(name)->state == MOUNT_MOUNTED; | |
272 | ||
273 | case NAME_AUTOMOUNT: { | |
274 | Automount *a = AUTOMOUNT(name); | |
275 | ||
276 | return | |
277 | a->state == AUTOMOUNT_WAITING || | |
278 | a->state == AUTOMOUNT_RUNNING; | |
279 | } | |
280 | ||
281 | case NAME_SNAPSHOT: | |
282 | return SNAPSHOT(name)->state == SNAPSHOT_ACTIVE; | |
283 | ||
284 | ||
285 | case _NAME_TYPE_MAX: | |
286 | case _NAME_TYPE_INVALID: | |
287 | ; | |
288 | } | |
289 | ||
290 | assert_not_reached("Unknown name type."); | |
291 | return false; | |
292 | } | |
293 | ||
294 | static int ensure_in_set(Set **s, void *data) { | |
295 | int r; | |
296 | ||
297 | assert(s); | |
298 | assert(data); | |
299 | ||
300 | if (!*s) | |
301 | if (!(*s = set_new(trivial_hash_func, trivial_compare_func))) | |
302 | return -ENOMEM; | |
303 | ||
7fad411c | 304 | if ((r = set_put(*s, data)) < 0) |
60918275 LP |
305 | if (r != -EEXIST) |
306 | return r; | |
307 | ||
308 | return 0; | |
309 | } | |
310 | ||
87d1515d LP |
311 | static int ensure_merge(Set **s, Set *other) { |
312 | ||
313 | if (!other) | |
314 | return 0; | |
315 | ||
316 | if (*s) | |
317 | return set_merge(*s, other); | |
318 | ||
319 | if (!(*s = set_copy(other))) | |
320 | return -ENOMEM; | |
321 | ||
322 | return 0; | |
323 | } | |
324 | ||
e5b5ae50 | 325 | /* FIXME: Does not rollback on failure! */ |
87d1515d LP |
326 | int name_merge(Name *name, Name *other) { |
327 | int r; | |
328 | NameDependency d; | |
329 | ||
330 | assert(name); | |
331 | assert(other); | |
87d1515d LP |
332 | assert(name->meta.manager == other->meta.manager); |
333 | ||
e5b5ae50 LP |
334 | /* This merges 'other' into 'name'. FIXME: This does not |
335 | * rollback on failure. */ | |
336 | ||
87d1515d LP |
337 | if (name->meta.type != other->meta.type) |
338 | return -EINVAL; | |
339 | ||
340 | if (other->meta.state != NAME_STUB) | |
341 | return -EINVAL; | |
342 | ||
343 | /* Merge names */ | |
344 | if ((r = ensure_merge(&name->meta.names, other->meta.names)) < 0) | |
345 | return r; | |
346 | ||
347 | /* Merge dependencies */ | |
348 | for (d = 0; d < _NAME_DEPENDENCY_MAX; d++) | |
349 | if ((r = ensure_merge(&name->meta.dependencies[d], other->meta.dependencies[d])) < 0) | |
350 | return r; | |
351 | ||
e5b5ae50 LP |
352 | /* Hookup new deps and names */ |
353 | if (name->meta.linked) { | |
7fad411c | 354 | if ((r = name_sanitize(name)) < 0) |
11dd41ce LP |
355 | return r; |
356 | ||
e5b5ae50 LP |
357 | if ((r = name_link_names(name, true)) < 0) |
358 | return r; | |
359 | } | |
360 | ||
87d1515d LP |
361 | return 0; |
362 | } | |
a66d02c3 | 363 | |
7fad411c LP |
364 | /* FIXME: Does not rollback on failure! */ |
365 | static int augment(Name *n) { | |
366 | int r; | |
367 | void* state; | |
368 | Name *other; | |
369 | ||
370 | assert(n); | |
371 | ||
372 | /* Adds in the missing links to make all dependencies | |
373 | * bidirectional. */ | |
374 | ||
375 | SET_FOREACH(other, n->meta.dependencies[NAME_BEFORE], state) | |
376 | if ((r = ensure_in_set(&other->meta.dependencies[NAME_AFTER], n)) < 0) | |
377 | return r; | |
378 | SET_FOREACH(other, n->meta.dependencies[NAME_AFTER], state) | |
379 | if ((r = ensure_in_set(&other->meta.dependencies[NAME_BEFORE], n)) < 0) | |
380 | return r; | |
381 | ||
382 | SET_FOREACH(other, n->meta.dependencies[NAME_CONFLICTS], state) | |
383 | if ((r = ensure_in_set(&other->meta.dependencies[NAME_CONFLICTS], n)) < 0) | |
384 | return r; | |
385 | ||
386 | SET_FOREACH(other, n->meta.dependencies[NAME_REQUIRES], state) | |
387 | if ((r = ensure_in_set(&other->meta.dependencies[NAME_REQUIRED_BY], n)) < 0) | |
388 | return r; | |
389 | SET_FOREACH(other, n->meta.dependencies[NAME_REQUISITE], state) | |
390 | if ((r = ensure_in_set(&other->meta.dependencies[NAME_REQUIRED_BY], n)) < 0) | |
391 | return r; | |
392 | ||
393 | SET_FOREACH(other, n->meta.dependencies[NAME_WANTS], state) | |
394 | if ((r = ensure_in_set(&other->meta.dependencies[NAME_WANTED_BY], n)) < 0) | |
395 | return r; | |
396 | SET_FOREACH(other, n->meta.dependencies[NAME_SOFT_REQUIRES], state) | |
397 | if ((r = ensure_in_set(&other->meta.dependencies[NAME_WANTED_BY], n)) < 0) | |
398 | return r; | |
399 | SET_FOREACH(other, n->meta.dependencies[NAME_SOFT_REQUISITE], state) | |
400 | if ((r = ensure_in_set(&other->meta.dependencies[NAME_WANTED_BY], n)) < 0) | |
401 | return r; | |
402 | ||
403 | return 0; | |
404 | } | |
405 | ||
406 | int name_sanitize(Name *n) { | |
407 | NameDependency d; | |
408 | ||
409 | assert(n); | |
410 | ||
411 | /* Remove loops */ | |
412 | for (d = 0; d < _NAME_DEPENDENCY_MAX; d++) | |
413 | set_remove(n->meta.dependencies[d], n); | |
414 | ||
415 | return augment(n); | |
416 | } | |
417 | ||
a66d02c3 LP |
418 | const char* name_id(Name *n) { |
419 | assert(n); | |
420 | ||
421 | return set_first(n->meta.names); | |
422 | } | |
423 | ||
ceed3570 | 424 | void name_dump(Name *n, FILE *f, const char *prefix) { |
a66d02c3 LP |
425 | |
426 | static const char* const state_table[_NAME_STATE_MAX] = { | |
42f4e3c4 LP |
427 | [NAME_STUB] = "stub", |
428 | [NAME_LOADED] = "loaded", | |
429 | [NAME_FAILED] = "failed" | |
430 | }; | |
431 | ||
432 | static const char* const socket_state_table[_SOCKET_STATE_MAX] = { | |
433 | [SOCKET_DEAD] = "dead", | |
434 | [SOCKET_BEFORE] = "before", | |
435 | [SOCKET_START_PRE] = "start-pre", | |
436 | [SOCKET_START] = "start", | |
437 | [SOCKET_START_POST] = "start-post", | |
438 | [SOCKET_LISTENING] = "listening", | |
439 | [SOCKET_RUNNING] = "running", | |
440 | [SOCKET_STOP_PRE] = "stop-pre", | |
441 | [SOCKET_STOP] = "stop", | |
442 | [SOCKET_STOP_POST] = "stop-post", | |
443 | [SOCKET_MAINTAINANCE] = "maintainance" | |
a66d02c3 LP |
444 | }; |
445 | ||
7fad411c LP |
446 | static const char* const dependency_table[_NAME_DEPENDENCY_MAX] = { |
447 | [NAME_REQUIRES] = "Requires", | |
448 | [NAME_SOFT_REQUIRES] = "SoftRequires", | |
449 | [NAME_WANTS] = "Wants", | |
450 | [NAME_REQUISITE] = "Requisite", | |
451 | [NAME_SOFT_REQUISITE] = "SoftRequisite", | |
452 | [NAME_REQUIRED_BY] = "RequiredBy", | |
453 | [NAME_WANTED_BY] = "WantedBy", | |
454 | [NAME_CONFLICTS] = "Conflicts", | |
455 | [NAME_BEFORE] = "Before", | |
456 | [NAME_AFTER] = "After", | |
457 | }; | |
458 | ||
11dd41ce LP |
459 | void *state; |
460 | char *t; | |
7fad411c | 461 | NameDependency d; |
11dd41ce | 462 | |
a66d02c3 LP |
463 | assert(n); |
464 | ||
ceed3570 LP |
465 | if (!prefix) |
466 | prefix = ""; | |
467 | ||
11dd41ce | 468 | fprintf(f, |
ceed3570 LP |
469 | "%sName %s:\n" |
470 | "%s\tDescription: %s\n" | |
471 | "%s\tName State: %s\n", | |
472 | prefix, name_id(n), | |
473 | prefix, n->meta.description ? n->meta.description : name_id(n), | |
474 | prefix, state_table[n->meta.state]); | |
475 | ||
476 | fprintf(f, "%s\tNames: ", prefix); | |
11dd41ce LP |
477 | SET_FOREACH(t, n->meta.names, state) |
478 | fprintf(f, "%s ", t); | |
479 | fprintf(f, "\n"); | |
480 | ||
7fad411c LP |
481 | for (d = 0; d < _NAME_DEPENDENCY_MAX; d++) { |
482 | void *state; | |
483 | Name *other; | |
484 | ||
485 | if (set_isempty(n->meta.dependencies[d])) | |
486 | continue; | |
487 | ||
488 | fprintf(f, "%s\t%s: ", prefix, dependency_table[d]); | |
489 | ||
490 | SET_FOREACH(other, n->meta.dependencies[d], state) | |
491 | fprintf(f, "%s ", name_id(other)); | |
492 | ||
493 | fprintf(f, "\n"); | |
494 | } | |
495 | ||
496 | ||
42f4e3c4 LP |
497 | switch (n->meta.type) { |
498 | case NAME_SOCKET: { | |
499 | int r; | |
500 | char *s = NULL; | |
501 | const char *t; | |
502 | ||
503 | if ((r = address_print(&n->socket.address, &s)) < 0) | |
504 | t = strerror(-r); | |
505 | else | |
506 | t = s; | |
507 | ||
e5b5ae50 | 508 | fprintf(f, |
ceed3570 LP |
509 | "%s\tAddress: %s\n" |
510 | "%s\tSocket State: %s\n", | |
511 | prefix, t, | |
512 | prefix, socket_state_table[n->socket.state]); | |
e5b5ae50 | 513 | |
42f4e3c4 LP |
514 | free(s); |
515 | break; | |
516 | } | |
517 | ||
518 | default: | |
519 | ; | |
520 | } | |
521 | ||
a66d02c3 | 522 | if (n->meta.job) { |
ceed3570 LP |
523 | char *p; |
524 | ||
525 | if (asprintf(&p, "%s\t", prefix) >= 0) | |
526 | prefix = p; | |
527 | else | |
528 | p = NULL; | |
529 | ||
530 | job_dump(n->meta.job, f, prefix); | |
531 | free(p); | |
a66d02c3 LP |
532 | } |
533 | } | |
7fad411c LP |
534 | |
535 | static int verify_type(Name *name) { | |
536 | char *n; | |
537 | void *state; | |
538 | ||
539 | assert(name); | |
540 | ||
541 | /* Checks that all aliases of this name have the same and valid type */ | |
542 | ||
543 | SET_FOREACH(n, name->meta.names, state) { | |
544 | NameType t; | |
545 | ||
546 | if ((t = name_type_from_string(n)) == _NAME_TYPE_INVALID) | |
547 | return -EINVAL; | |
548 | ||
549 | if (name->meta.type == _NAME_TYPE_INVALID) { | |
550 | name->meta.type = t; | |
551 | continue; | |
552 | } | |
553 | ||
554 | if (name->meta.type != t) | |
555 | return -EINVAL; | |
556 | } | |
557 | ||
558 | if (name->meta.type == _NAME_TYPE_INVALID) | |
559 | return -EINVAL; | |
560 | ||
561 | return 0; | |
562 | } | |
563 | ||
564 | static int service_load_sysv(Service *s) { | |
565 | assert(s); | |
566 | ||
567 | /* Load service data from SysV init scripts, preferably with | |
568 | * LSB headers ... */ | |
569 | ||
570 | return -ENOENT; | |
571 | } | |
572 | ||
573 | static int name_load_fstab(Name *n) { | |
574 | assert(n); | |
575 | assert(n->meta.type == NAME_MOUNT || n->meta.type == NAME_AUTOMOUNT); | |
576 | ||
577 | /* Load mount data from /etc/fstab */ | |
578 | ||
579 | return 0; | |
580 | } | |
581 | ||
582 | static int snapshot_load(Snapshot *s) { | |
583 | assert(s); | |
584 | ||
585 | /* Load snapshots from disk */ | |
586 | ||
587 | return 0; | |
588 | } | |
589 | ||
590 | static int name_load_dropin(Name *n) { | |
591 | assert(n); | |
592 | ||
593 | /* Load dependencies from drop-in directories */ | |
594 | ||
595 | return 0; | |
596 | } | |
597 | ||
598 | int name_load(Name *name) { | |
599 | int r; | |
600 | ||
601 | assert(name); | |
602 | ||
603 | if (name->meta.state != NAME_STUB) | |
604 | return 0; | |
605 | ||
606 | if ((r = verify_type(name)) < 0) | |
607 | return r; | |
608 | ||
609 | if (name->meta.type == NAME_SERVICE) { | |
610 | ||
611 | /* Load a .service file */ | |
612 | if ((r = name_load_fragment(name)) == 0) | |
613 | goto finish; | |
614 | ||
615 | /* Load a classic init script */ | |
616 | if (r == -ENOENT) | |
617 | if ((r = service_load_sysv(SERVICE(name))) == 0) | |
618 | goto finish; | |
619 | ||
620 | } else if (name->meta.type == NAME_MOUNT || | |
621 | name->meta.type == NAME_AUTOMOUNT) { | |
622 | ||
623 | if ((r = name_load_fstab(name)) == 0) | |
624 | goto finish; | |
625 | ||
626 | } else if (name->meta.type == NAME_SNAPSHOT) { | |
627 | ||
628 | if ((r = snapshot_load(SNAPSHOT(name))) == 0) | |
629 | goto finish; | |
630 | ||
631 | } else { | |
632 | if ((r = name_load_fragment(name)) == 0) | |
633 | goto finish; | |
634 | } | |
635 | ||
636 | name->meta.state = NAME_FAILED; | |
637 | return r; | |
638 | ||
639 | finish: | |
640 | if ((r = name_load_dropin(name)) < 0) | |
641 | return r; | |
642 | ||
643 | if ((r = name_sanitize(name)) < 0) | |
644 | return r; | |
645 | ||
646 | if ((r = name_link_names(name, false)) < 0) | |
647 | return r; | |
648 | ||
649 | name->meta.state = NAME_LOADED; | |
650 | return 0; | |
651 | } |