]> git.ipfire.org Git - people/ms/systemd.git/blame - name.c
recursively kill jobs from transaction list
[people/ms/systemd.git] / name.c
CommitLineData
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
13NameType 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
41bool 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
61Name *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! */
85int 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 109int 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
139static 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 158void 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
228bool 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
294static 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
311static 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
326int 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! */
365static 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
406int 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
418const char* name_id(Name *n) {
419 assert(n);
420
421 return set_first(n->meta.names);
422}
423
ceed3570 424void 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
535static 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
564static 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
573static 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
582static int snapshot_load(Snapshot *s) {
583 assert(s);
584
585 /* Load snapshots from disk */
586
587 return 0;
588}
589
590static int name_load_dropin(Name *n) {
591 assert(n);
592
593 /* Load dependencies from drop-in directories */
594
595 return 0;
596}
597
598int 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
639finish:
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}