]> git.ipfire.org Git - people/ms/systemd.git/blame - name.c
first attempt at proper service/socket logic
[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>
9152c765 6#include <sys/epoll.h>
034c6ed7
LP
7#include <sys/timerfd.h>
8#include <sys/poll.h>
60918275
LP
9
10#include "set.h"
11#include "name.h"
12#include "macro.h"
13#include "strv.h"
7fad411c 14#include "load-fragment.h"
5cb5a6ff
LP
15#include "load-dropin.h"
16
9152c765 17const NameVTable * const name_vtable[_NAME_TYPE_MAX] = {
5cb5a6ff
LP
18 [NAME_SERVICE] = &service_vtable,
19 [NAME_TIMER] = &timer_vtable,
20 [NAME_SOCKET] = &socket_vtable,
21 [NAME_MILESTONE] = &milestone_vtable,
22 [NAME_DEVICE] = &device_vtable,
23 [NAME_MOUNT] = &mount_vtable,
24 [NAME_AUTOMOUNT] = &automount_vtable,
25 [NAME_SNAPSHOT] = &snapshot_vtable
26};
27
60918275
LP
28NameType name_type_from_string(const char *n) {
29 NameType t;
60918275
LP
30
31 assert(n);
32
33 for (t = 0; t < _NAME_TYPE_MAX; t++)
5cb5a6ff 34 if (endswith(n, name_vtable[t]->suffix))
60918275
LP
35 return t;
36
37 return _NAME_TYPE_INVALID;
38}
39
07232470
LP
40#define VALID_CHARS \
41 "0123456789" \
42 "abcdefghijklmnopqrstuvwxyz" \
43 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
44 "-_"
45
46bool name_is_valid(const char *n) {
47 NameType t;
48 const char *e, *i;
49
50 assert(n);
51
5cb5a6ff
LP
52 if (strlen(n) >= NAME_MAX)
53 return false;
54
07232470
LP
55 t = name_type_from_string(n);
56 if (t < 0 || t >= _NAME_TYPE_MAX)
57 return false;
58
59 if (!(e = strrchr(n, '.')))
60 return false;
61
62 for (i = n; i < e; i++)
63 if (!strchr(VALID_CHARS, *i))
64 return false;
65
66 return true;
67}
68
60918275
LP
69Name *name_new(Manager *m) {
70 Name *n;
71
72 assert(m);
73
74 if (!(n = new0(Name, 1)))
75 return NULL;
76
87d1515d
LP
77 if (!(n->meta.names = set_new(string_hash_func, string_compare_func))) {
78 free(n);
79 return NULL;
80 }
81
60918275
LP
82 n->meta.manager = m;
83 n->meta.type = _NAME_TYPE_INVALID;
60918275
LP
84
85 /* We don't link the name here, that is left for name_link() */
86
87 return n;
88}
89
034c6ed7
LP
90int name_add_name(Name *n, const char *text) {
91 NameType t;
92 char *s;
93 int r;
94
95 assert(n);
96 assert(text);
97
98 if ((t = name_type_from_string(text)) == _NAME_TYPE_INVALID)
99 return -EINVAL;
100
101 if (n->meta.type != _NAME_TYPE_INVALID && t != n->meta.type)
102 return -EINVAL;
103
104 if (!(s = strdup(text)))
105 return -ENOMEM;
106
107 if ((r = set_put(n->meta.names, s)) < 0) {
108 free(s);
109 return r;
110 }
111
112 n->meta.type = t;
113
114 if (!n->meta.id)
115 n->meta.id = s;
116
117 return 0;
118}
119
e5b5ae50
LP
120/* FIXME: Does not rollback on failure! */
121int name_link_names(Name *n, bool replace) {
11dd41ce 122 char *t;
034c6ed7 123 Iterator i;
11dd41ce
LP
124 int r;
125
126 assert(n);
127
128 if (!n->meta.linked)
129 return 0;
130
e5b5ae50 131 /* Link all names that aren't linked yet. */
11dd41ce 132
034c6ed7 133 SET_FOREACH(t, n->meta.names, i)
e5b5ae50
LP
134 if (replace) {
135 if ((r = hashmap_replace(n->meta.manager->names, t, n)) < 0)
136 return r;
137 } else {
138 if ((r = hashmap_put(n->meta.manager->names, t, n)) < 0)
139 return r;
11dd41ce
LP
140 }
141
142 return 0;
143}
144
60918275 145int name_link(Name *n) {
60918275
LP
146 int r;
147
148 assert(n);
87d1515d 149 assert(!set_isempty(n->meta.names));
60918275
LP
150 assert(!n->meta.linked);
151
7fad411c
LP
152 if ((r = name_sanitize(n)) < 0)
153 return r;
154
11dd41ce 155 n->meta.linked = true;
60918275 156
7fad411c 157 if ((r = name_link_names(n, false)) < 0) {
11dd41ce 158 char *t;
034c6ed7 159 Iterator i;
60918275 160
11dd41ce 161 /* Rollback the registered names */
034c6ed7 162 SET_FOREACH(t, n->meta.names, i)
e5b5ae50 163 hashmap_remove_value(n->meta.manager->names, t, n);
60918275 164
11dd41ce
LP
165 n->meta.linked = false;
166 return r;
167 }
60918275 168
034c6ed7
LP
169 if (n->meta.load_state == NAME_STUB) {
170 LIST_PREPEND(Meta, load_queue, n->meta.manager->load_queue, &n->meta);
171 n->meta.in_load_queue = true;
172 }
60918275 173
11dd41ce 174 return 0;
60918275
LP
175}
176
87d1515d 177static void bidi_set_free(Name *name, Set *s) {
034c6ed7 178 Iterator i;
87d1515d
LP
179 Name *other;
180
181 assert(name);
87d1515d
LP
182
183 /* Frees the set and makes sure we are dropped from the
184 * inverse pointers */
185
034c6ed7 186 SET_FOREACH(other, s, i) {
87d1515d
LP
187 NameDependency d;
188
189 for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
190 set_remove(other->meta.dependencies[d], name);
191 }
192
193 set_free(s);
194}
195
60918275 196void name_free(Name *name) {
87d1515d
LP
197 NameDependency d;
198 char *t;
60918275
LP
199
200 assert(name);
201
202 /* Detach from next 'bigger' objects */
60918275 203 if (name->meta.linked) {
11dd41ce 204 char *t;
034c6ed7 205 Iterator i;
60918275 206
034c6ed7 207 SET_FOREACH(t, name->meta.names, i)
e5b5ae50 208 hashmap_remove_value(name->meta.manager->names, t, name);
60918275 209
034c6ed7
LP
210 if (name->meta.in_load_queue)
211 LIST_REMOVE(Meta, load_queue, name->meta.manager->load_queue, &name->meta);
60918275
LP
212 }
213
214 /* Free data and next 'smaller' objects */
60918275
LP
215 if (name->meta.job)
216 job_free(name->meta.job);
217
87d1515d
LP
218 for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
219 bidi_set_free(name, name->meta.dependencies[d]);
60918275 220
034c6ed7
LP
221 if (NAME_VTABLE(name)->done)
222 NAME_VTABLE(name)->done(name);
60918275
LP
223
224 free(name->meta.description);
87d1515d
LP
225
226 while ((t = set_steal_first(name->meta.names)))
227 free(t);
228 set_free(name->meta.names);
60918275
LP
229
230 free(name);
231}
232
5cb5a6ff 233NameActiveState name_active_state(Name *name) {
60918275
LP
234 assert(name);
235
5cb5a6ff
LP
236 if (name->meta.load_state != NAME_LOADED)
237 return NAME_INACTIVE;
60918275 238
5cb5a6ff 239 return NAME_VTABLE(name)->active_state(name);
60918275
LP
240}
241
242static int ensure_in_set(Set **s, void *data) {
243 int r;
244
245 assert(s);
246 assert(data);
247
034c6ed7
LP
248 if ((r = set_ensure_allocated(s, trivial_hash_func, trivial_compare_func)) < 0)
249 return r;
60918275 250
7fad411c 251 if ((r = set_put(*s, data)) < 0)
034c6ed7 252 return r;
60918275
LP
253
254 return 0;
255}
256
87d1515d
LP
257static int ensure_merge(Set **s, Set *other) {
258
259 if (!other)
260 return 0;
261
262 if (*s)
263 return set_merge(*s, other);
264
265 if (!(*s = set_copy(other)))
266 return -ENOMEM;
267
268 return 0;
269}
270
e5b5ae50 271/* FIXME: Does not rollback on failure! */
87d1515d
LP
272int name_merge(Name *name, Name *other) {
273 int r;
274 NameDependency d;
275
276 assert(name);
277 assert(other);
87d1515d
LP
278 assert(name->meta.manager == other->meta.manager);
279
e5b5ae50
LP
280 /* This merges 'other' into 'name'. FIXME: This does not
281 * rollback on failure. */
282
87d1515d
LP
283 if (name->meta.type != other->meta.type)
284 return -EINVAL;
285
5cb5a6ff 286 if (other->meta.load_state != NAME_STUB)
87d1515d
LP
287 return -EINVAL;
288
289 /* Merge names */
290 if ((r = ensure_merge(&name->meta.names, other->meta.names)) < 0)
291 return r;
292
293 /* Merge dependencies */
294 for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
295 if ((r = ensure_merge(&name->meta.dependencies[d], other->meta.dependencies[d])) < 0)
296 return r;
297
e5b5ae50
LP
298 /* Hookup new deps and names */
299 if (name->meta.linked) {
7fad411c 300 if ((r = name_sanitize(name)) < 0)
11dd41ce
LP
301 return r;
302
e5b5ae50
LP
303 if ((r = name_link_names(name, true)) < 0)
304 return r;
305 }
306
87d1515d
LP
307 return 0;
308}
a66d02c3 309
7fad411c
LP
310/* FIXME: Does not rollback on failure! */
311static int augment(Name *n) {
312 int r;
034c6ed7 313 Iterator i;
7fad411c
LP
314 Name *other;
315
316 assert(n);
317
318 /* Adds in the missing links to make all dependencies
319 * bidirectional. */
320
034c6ed7 321 SET_FOREACH(other, n->meta.dependencies[NAME_BEFORE], i)
7fad411c
LP
322 if ((r = ensure_in_set(&other->meta.dependencies[NAME_AFTER], n)) < 0)
323 return r;
034c6ed7 324 SET_FOREACH(other, n->meta.dependencies[NAME_AFTER], i)
7fad411c
LP
325 if ((r = ensure_in_set(&other->meta.dependencies[NAME_BEFORE], n)) < 0)
326 return r;
327
034c6ed7 328 SET_FOREACH(other, n->meta.dependencies[NAME_CONFLICTS], i)
7fad411c
LP
329 if ((r = ensure_in_set(&other->meta.dependencies[NAME_CONFLICTS], n)) < 0)
330 return r;
331
034c6ed7 332 SET_FOREACH(other, n->meta.dependencies[NAME_REQUIRES], i)
7fad411c
LP
333 if ((r = ensure_in_set(&other->meta.dependencies[NAME_REQUIRED_BY], n)) < 0)
334 return r;
034c6ed7 335 SET_FOREACH(other, n->meta.dependencies[NAME_REQUISITE], i)
7fad411c
LP
336 if ((r = ensure_in_set(&other->meta.dependencies[NAME_REQUIRED_BY], n)) < 0)
337 return r;
338
034c6ed7 339 SET_FOREACH(other, n->meta.dependencies[NAME_SOFT_REQUIRES], i)
5cb5a6ff 340 if ((r = ensure_in_set(&other->meta.dependencies[NAME_SOFT_REQUIRED_BY], n)) < 0)
7fad411c 341 return r;
5cb5a6ff 342
034c6ed7 343 SET_FOREACH(other, n->meta.dependencies[NAME_WANTS], i)
7fad411c
LP
344 if ((r = ensure_in_set(&other->meta.dependencies[NAME_WANTED_BY], n)) < 0)
345 return r;
346
347 return 0;
348}
349
350int name_sanitize(Name *n) {
351 NameDependency d;
352
353 assert(n);
354
355 /* Remove loops */
356 for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
357 set_remove(n->meta.dependencies[d], n);
358
359 return augment(n);
360}
361
a66d02c3
LP
362const char* name_id(Name *n) {
363 assert(n);
364
034c6ed7
LP
365 if (n->meta.id)
366 return n->meta.id;
367
a66d02c3
LP
368 return set_first(n->meta.names);
369}
370
5cb5a6ff
LP
371const char *name_description(Name *n) {
372 assert(n);
373
374 if (n->meta.description)
375 return n->meta.description;
376
377 return name_id(n);
378}
379
ceed3570 380void name_dump(Name *n, FILE *f, const char *prefix) {
a66d02c3 381
5cb5a6ff 382 static const char* const load_state_table[_NAME_LOAD_STATE_MAX] = {
42f4e3c4
LP
383 [NAME_STUB] = "stub",
384 [NAME_LOADED] = "loaded",
385 [NAME_FAILED] = "failed"
386 };
387
5cb5a6ff
LP
388 static const char* const active_state_table[_NAME_ACTIVE_STATE_MAX] = {
389 [NAME_ACTIVE] = "active",
390 [NAME_INACTIVE] = "inactive",
391 [NAME_ACTIVATING] = "activating",
392 [NAME_DEACTIVATING] = "deactivating"
a66d02c3
LP
393 };
394
7fad411c
LP
395 static const char* const dependency_table[_NAME_DEPENDENCY_MAX] = {
396 [NAME_REQUIRES] = "Requires",
397 [NAME_SOFT_REQUIRES] = "SoftRequires",
398 [NAME_WANTS] = "Wants",
399 [NAME_REQUISITE] = "Requisite",
400 [NAME_SOFT_REQUISITE] = "SoftRequisite",
401 [NAME_REQUIRED_BY] = "RequiredBy",
5cb5a6ff 402 [NAME_SOFT_REQUIRED_BY] = "SoftRequiredBy",
542563ba 403 [NAME_WANTED_BY] = "WantedBy",
7fad411c
LP
404 [NAME_CONFLICTS] = "Conflicts",
405 [NAME_BEFORE] = "Before",
406 [NAME_AFTER] = "After",
407 };
408
11dd41ce 409 char *t;
7fad411c 410 NameDependency d;
034c6ed7 411 Iterator i;
11dd41ce 412
a66d02c3
LP
413 assert(n);
414
ceed3570
LP
415 if (!prefix)
416 prefix = "";
417
11dd41ce 418 fprintf(f,
ceed3570
LP
419 "%sName %s:\n"
420 "%s\tDescription: %s\n"
5cb5a6ff
LP
421 "%s\tName Load State: %s\n"
422 "%s\tName Active State: %s\n",
ceed3570 423 prefix, name_id(n),
5cb5a6ff
LP
424 prefix, name_description(n),
425 prefix, load_state_table[n->meta.load_state],
426 prefix, active_state_table[name_active_state(n)]);
ceed3570 427
034c6ed7 428 SET_FOREACH(t, n->meta.names, i)
5cb5a6ff 429 fprintf(f, "%s\tName: %s\n", prefix, t);
11dd41ce 430
7fad411c 431 for (d = 0; d < _NAME_DEPENDENCY_MAX; d++) {
7fad411c
LP
432 Name *other;
433
434 if (set_isempty(n->meta.dependencies[d]))
435 continue;
436
034c6ed7 437 SET_FOREACH(other, n->meta.dependencies[d], i)
5cb5a6ff 438 fprintf(f, "%s\t%s: %s\n", prefix, dependency_table[d], name_id(other));
7fad411c
LP
439 }
440
5cb5a6ff
LP
441 if (NAME_VTABLE(n)->dump)
442 NAME_VTABLE(n)->dump(n, f, prefix);
42f4e3c4 443
a66d02c3 444 if (n->meta.job) {
ceed3570
LP
445 char *p;
446
447 if (asprintf(&p, "%s\t", prefix) >= 0)
448 prefix = p;
449 else
450 p = NULL;
451
452 job_dump(n->meta.job, f, prefix);
453 free(p);
a66d02c3
LP
454 }
455}
7fad411c
LP
456
457static int verify_type(Name *name) {
458 char *n;
034c6ed7 459 Iterator i;
7fad411c
LP
460
461 assert(name);
462
463 /* Checks that all aliases of this name have the same and valid type */
464
034c6ed7 465 SET_FOREACH(n, name->meta.names, i) {
7fad411c
LP
466 NameType t;
467
468 if ((t = name_type_from_string(n)) == _NAME_TYPE_INVALID)
469 return -EINVAL;
470
471 if (name->meta.type == _NAME_TYPE_INVALID) {
472 name->meta.type = t;
473 continue;
474 }
475
476 if (name->meta.type != t)
477 return -EINVAL;
478 }
479
480 if (name->meta.type == _NAME_TYPE_INVALID)
481 return -EINVAL;
482
483 return 0;
484}
485
5cb5a6ff
LP
486/* Common implementation for multiple backends */
487int name_load_fragment_and_dropin(Name *n) {
488 int r;
7fad411c 489
5cb5a6ff 490 assert(n);
7fad411c 491
5cb5a6ff
LP
492 /* Load a .socket file */
493 if ((r = name_load_fragment(n)) < 0)
494 return r;
495
496 /* Load drop-in directory data */
497 if ((r = name_load_dropin(n)) < 0)
498 return r;
499
500 return 0;
7fad411c
LP
501}
502
5cb5a6ff
LP
503int name_load(Name *name) {
504 int r;
505
506 assert(name);
507
034c6ed7
LP
508 if (name->meta.in_load_queue) {
509 LIST_REMOVE(Meta, load_queue, name->meta.manager->load_queue, &name->meta);
510 name->meta.in_load_queue = false;
511 }
512
5cb5a6ff
LP
513 if (name->meta.load_state != NAME_STUB)
514 return 0;
7fad411c 515
5cb5a6ff
LP
516 if ((r = verify_type(name)) < 0)
517 return r;
518
034c6ed7
LP
519 if (NAME_VTABLE(name)->init)
520 if ((r = NAME_VTABLE(name)->init(name)) < 0)
5cb5a6ff 521 goto fail;
7fad411c 522
5cb5a6ff
LP
523 if ((r = name_sanitize(name)) < 0)
524 goto fail;
525
526 if ((r = name_link_names(name, false)) < 0)
527 goto fail;
528
529 name->meta.load_state = NAME_LOADED;
7fad411c 530 return 0;
5cb5a6ff
LP
531
532fail:
533 name->meta.load_state = NAME_FAILED;
534 return r;
7fad411c
LP
535}
536
5cb5a6ff
LP
537/* Errors:
538 * -EBADR: This name type does not support starting.
539 * -EALREADY: Name is already started.
540 * -EAGAIN: An operation is already in progress. Retry later.
541 */
542int name_start(Name *n) {
543 NameActiveState state;
544
545 assert(n);
7fad411c 546
5cb5a6ff
LP
547 if (!NAME_VTABLE(n)->start)
548 return -EBADR;
7fad411c 549
5cb5a6ff
LP
550 state = name_active_state(n);
551 if (NAME_IS_ACTIVE_OR_RELOADING(state))
552 return -EALREADY;
553
034c6ed7
LP
554 /* We don't suppress calls to ->start() here when we are
555 * already starting, to allow this request to be used as a
556 * "hurry up" call, for example when the name is in some "auto
557 * restart" state where it waits for a holdoff timer to elapse
558 * before it will start again. */
5cb5a6ff
LP
559
560 return NAME_VTABLE(n)->start(n);
7fad411c
LP
561}
562
5cb5a6ff
LP
563bool name_type_can_start(NameType t) {
564 assert(t >= 0 && t < _NAME_TYPE_MAX);
565
566 return !!name_vtable[t]->start;
567}
568
569/* Errors:
570 * -EBADR: This name type does not support stopping.
571 * -EALREADY: Name is already stopped.
572 * -EAGAIN: An operation is already in progress. Retry later.
573 */
574int name_stop(Name *n) {
575 NameActiveState state;
576
7fad411c
LP
577 assert(n);
578
5cb5a6ff
LP
579 if (!NAME_VTABLE(n)->stop)
580 return -EBADR;
7fad411c 581
5cb5a6ff
LP
582 state = name_active_state(n);
583 if (state == NAME_INACTIVE)
584 return -EALREADY;
585
586 if (state == NAME_DEACTIVATING)
587 return 0;
588
589 return NAME_VTABLE(n)->stop(n);
7fad411c
LP
590}
591
5cb5a6ff
LP
592/* Errors:
593 * -EBADR: This name type does not support reloading.
594 * -ENOEXEC: Name is not started.
595 * -EAGAIN: An operation is already in progress. Retry later.
596 */
597int name_reload(Name *n) {
598 NameActiveState state;
7fad411c 599
5cb5a6ff
LP
600 assert(n);
601
034c6ed7 602 if (!name_can_reload(n))
5cb5a6ff
LP
603 return -EBADR;
604
605 state = name_active_state(n);
606 if (name_active_state(n) == NAME_ACTIVE_RELOADING)
607 return -EALREADY;
608
609 if (name_active_state(n) != NAME_ACTIVE)
610 return -ENOEXEC;
611
612 return NAME_VTABLE(n)->reload(n);
613}
7fad411c 614
5cb5a6ff
LP
615bool name_type_can_reload(NameType t) {
616 assert(t >= 0 && t < _NAME_TYPE_MAX);
034c6ed7 617
5cb5a6ff
LP
618 return !!name_vtable[t]->reload;
619}
620
034c6ed7
LP
621bool name_can_reload(Name *n) {
622 assert(n);
623
624 if (!name_type_can_reload(n->meta.type))
625 return false;
626
627 if (!NAME_VTABLE(n)->can_reload)
628 return true;
629
630 return NAME_VTABLE(n)->can_reload(n);
631}
632
5cb5a6ff 633static void retroactively_start_dependencies(Name *n) {
034c6ed7 634 Iterator i;
5cb5a6ff
LP
635 Name *other;
636
637 assert(n);
638 assert(NAME_IS_ACTIVE_OR_ACTIVATING(name_active_state(n)));
639
034c6ed7 640 SET_FOREACH(other, n->meta.dependencies[NAME_REQUIRES], i)
5cb5a6ff
LP
641 if (!NAME_IS_ACTIVE_OR_ACTIVATING(name_active_state(other)))
642 manager_add_job(n->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL);
643
034c6ed7 644 SET_FOREACH(other, n->meta.dependencies[NAME_SOFT_REQUIRES], i)
5cb5a6ff
LP
645 if (!NAME_IS_ACTIVE_OR_ACTIVATING(name_active_state(other)))
646 manager_add_job(n->meta.manager, JOB_START, other, JOB_FAIL, false, NULL);
647
034c6ed7 648 SET_FOREACH(other, n->meta.dependencies[NAME_REQUISITE], i)
5cb5a6ff
LP
649 if (!NAME_IS_ACTIVE_OR_ACTIVATING(name_active_state(other)))
650 manager_add_job(n->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL);
651
034c6ed7 652 SET_FOREACH(other, n->meta.dependencies[NAME_WANTS], i)
5cb5a6ff
LP
653 if (!NAME_IS_ACTIVE_OR_ACTIVATING(name_active_state(other)))
654 manager_add_job(n->meta.manager, JOB_START, other, JOB_FAIL, false, NULL);
655
034c6ed7 656 SET_FOREACH(other, n->meta.dependencies[NAME_CONFLICTS], i)
5cb5a6ff
LP
657 if (!NAME_IS_ACTIVE_OR_ACTIVATING(name_active_state(other)))
658 manager_add_job(n->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL);
659}
660
661static void retroactively_stop_dependencies(Name *n) {
034c6ed7 662 Iterator i;
5cb5a6ff
LP
663 Name *other;
664
665 assert(n);
666 assert(NAME_IS_INACTIVE_OR_DEACTIVATING(name_active_state(n)));
667
034c6ed7 668 SET_FOREACH(other, n->meta.dependencies[NAME_REQUIRED_BY], i)
5cb5a6ff
LP
669 if (!NAME_IS_INACTIVE_OR_DEACTIVATING(name_active_state(other)))
670 manager_add_job(n->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL);
671}
672
83c60c9f 673void name_notify(Name *n, NameActiveState os, NameActiveState ns) {
5cb5a6ff
LP
674 assert(n);
675 assert(os < _NAME_ACTIVE_STATE_MAX);
676 assert(ns < _NAME_ACTIVE_STATE_MAX);
677 assert(!(os == NAME_ACTIVE && ns == NAME_ACTIVATING));
678 assert(!(os == NAME_INACTIVE && ns == NAME_DEACTIVATING));
679
680 if (os == ns)
83c60c9f 681 return;
7fad411c 682
034c6ed7
LP
683 if (!NAME_IS_ACTIVE_OR_RELOADING(os) && NAME_IS_ACTIVE_OR_RELOADING(ns))
684 n->meta.active_enter_timestamp = now(CLOCK_REALTIME);
685 else if (NAME_IS_ACTIVE_OR_RELOADING(os) && !NAME_IS_ACTIVE_OR_RELOADING(ns))
686 n->meta.active_exit_timestamp = now(CLOCK_REALTIME);
687
5cb5a6ff 688 if (n->meta.job) {
7fad411c 689
5cb5a6ff 690 if (n->meta.job->state == JOB_WAITING)
7fad411c 691
5cb5a6ff
LP
692 /* So we reached a different state for this
693 * job. Let's see if we can run it now if it
694 * failed previously due to EAGAIN. */
034c6ed7 695 job_schedule_run(n->meta.job);
7fad411c 696
5cb5a6ff
LP
697 else {
698 assert(n->meta.job->state == JOB_RUNNING);
7fad411c 699
5cb5a6ff
LP
700 /* Let's check of this state change
701 * constitutes a finished job, or maybe
702 * cotradicts a running job and hence needs to
703 * invalidate jobs. */
7fad411c 704
5cb5a6ff 705 switch (n->meta.job->type) {
7fad411c 706
5cb5a6ff
LP
707 case JOB_START:
708 case JOB_VERIFY_ACTIVE:
7fad411c 709
83c60c9f
LP
710 if (NAME_IS_ACTIVE_OR_RELOADING(ns)) {
711 job_finish_and_invalidate(n->meta.job, true);
712 return;
713 } else if (ns == NAME_ACTIVATING)
714 return;
5cb5a6ff
LP
715 else
716 job_finish_and_invalidate(n->meta.job, false);
7fad411c 717
5cb5a6ff 718 break;
7fad411c 719
5cb5a6ff
LP
720 case JOB_RELOAD:
721 case JOB_RELOAD_OR_START:
7fad411c 722
83c60c9f
LP
723 if (ns == NAME_ACTIVE) {
724 job_finish_and_invalidate(n->meta.job, true);
725 return;
726 } else if (ns == NAME_ACTIVATING || ns == NAME_ACTIVE_RELOADING)
727 return;
5cb5a6ff
LP
728 else
729 job_finish_and_invalidate(n->meta.job, false);
7fad411c 730
5cb5a6ff 731 break;
7fad411c 732
5cb5a6ff
LP
733 case JOB_STOP:
734 case JOB_RESTART:
735 case JOB_TRY_RESTART:
736
83c60c9f
LP
737 if (ns == NAME_INACTIVE) {
738 job_finish_and_invalidate(n->meta.job, true);
739 return;
740 } else if (ns == NAME_DEACTIVATING)
741 return;
5cb5a6ff
LP
742 else
743 job_finish_and_invalidate(n->meta.job, false);
744
745 break;
746
747 default:
748 assert_not_reached("Job type unknown");
749 }
750 }
751 }
752
753 /* If this state change happened without being requested by a
754 * job, then let's retroactively start or stop dependencies */
755
756 if (NAME_IS_INACTIVE_OR_DEACTIVATING(os) && NAME_IS_ACTIVE_OR_ACTIVATING(ns))
757 retroactively_start_dependencies(n);
758 else if (NAME_IS_ACTIVE_OR_ACTIVATING(os) && NAME_IS_INACTIVE_OR_DEACTIVATING(ns))
759 retroactively_stop_dependencies(n);
7fad411c 760}
9152c765
LP
761
762int name_watch_fd(Name *n, int fd, uint32_t events) {
763 struct epoll_event ev;
764
765 assert(n);
766 assert(fd >= 0);
767
768 zero(ev);
769 ev.data.fd = fd;
770 ev.data.ptr = n;
034c6ed7 771 ev.data.u32 = MANAGER_FD;
9152c765
LP
772 ev.events = events;
773
034c6ed7
LP
774 if (epoll_ctl(n->meta.manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) >= 0)
775 return 0;
9152c765 776
034c6ed7
LP
777 if (errno == EEXIST)
778 if (epoll_ctl(n->meta.manager->epoll_fd, EPOLL_CTL_MOD, fd, &ev) >= 0)
779 return 0;
780
781 return -errno;
9152c765
LP
782}
783
784void name_unwatch_fd(Name *n, int fd) {
785 assert(n);
786 assert(fd >= 0);
787
788 assert_se(epoll_ctl(n->meta.manager->epoll_fd, EPOLL_CTL_DEL, fd, NULL) >= 0 || errno == ENOENT);
789}
790
791int name_watch_pid(Name *n, pid_t pid) {
792 assert(n);
793 assert(pid >= 1);
794
795 return hashmap_put(n->meta.manager->watch_pids, UINT32_TO_PTR(pid), n);
796}
797
798void name_unwatch_pid(Name *n, pid_t pid) {
799 assert(n);
800 assert(pid >= 1);
801
802 hashmap_remove(n->meta.manager->watch_pids, UINT32_TO_PTR(pid));
803}
034c6ed7
LP
804
805int name_watch_timer(Name *n, usec_t delay, int *id) {
806 struct epoll_event ev;
807 int fd;
808 struct itimerspec its;
809 int flags;
810 bool ours;
811
812 assert(n);
813 assert(id);
814
815 /* This will try to reuse the old timer if there is one */
816
817 if (*id >= 0) {
818 ours = false;
819 fd = *id;
820
821 } else {
822 ours = true;
823
824 if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
825 return -errno;
826 }
827
828 zero(its);
829
830 if (delay <= 0) {
831 /* Set absolute time in the past, but not 0, since we
832 * don't want to disarm the timer */
833 its.it_value.tv_sec = 0;
834 its.it_value.tv_nsec = 1;
835
836 flags = TFD_TIMER_ABSTIME;
837 } else {
838 timespec_store(&its.it_value, delay);
839 flags = 0;
840 }
841
842 /* This will also flush the elapse counter */
843 if (timerfd_settime(fd, flags, &its, NULL) < 0)
844 goto fail;
845
846 zero(ev);
847 ev.data.fd = fd;
848 ev.data.ptr = n;
849 ev.data.u32 = MANAGER_TIMER;
850 ev.events = POLLIN;
851
852 if (epoll_ctl(n->meta.manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
853 goto fail;
854
855 *id = fd;
856 return 0;
857
858fail:
859 if (ours)
860 assert_se(close_nointr(fd) == 0);
861
862 return -errno;
863}
864
865void name_unwatch_timer(Name *n, int *id) {
866 assert(n);
867 assert(id);
868
869 if (*id >= 0) {
870 assert_se(epoll_ctl(n->meta.manager->epoll_fd, EPOLL_CTL_DEL, *id, NULL) >= 0);
871 assert_se(close_nointr(*id) == 0);
872
873 *id = -1;
874 }
875}
876
877char *name_change_suffix(const char *t, const char *suffix) {
878 char *e, *n;
879 size_t a, b;
880
881 assert(t);
882 assert(name_is_valid(t));
883 assert(suffix);
884
885 assert_se(e = strrchr(t, '.'));
886 a = e - t;
887 b = strlen(suffix);
888
889 if (!(n = new(char, a + b + 1)))
890 return NULL;
891
892 memcpy(n, t, a);
893 memcpy(n+a, t, b+1);
894
895 return n;
896}
897
898bool name_job_is_applicable(Name *n, JobType j) {
899 assert(n);
900 assert(j >= 0 && j < _JOB_TYPE_MAX);
901
902 switch (j) {
903 case JOB_VERIFY_ACTIVE:
904 case JOB_START:
905 return true;
906
907 case JOB_STOP:
908 case JOB_RESTART:
909 case JOB_TRY_RESTART:
910 return name_can_start(n);
911
912 case JOB_RELOAD:
913 return name_can_reload(n);
914
915 case JOB_RELOAD_OR_START:
916 return name_can_reload(n) && name_can_start(n);
917
918 default:
919 assert_not_reached("Invalid job type");
920 }
921}