summaryrefslogtreecommitdiff
path: root/name.c
diff options
context:
space:
mode:
Diffstat (limited to 'name.c')
-rw-r--r--name.c267
1 files changed, 267 insertions, 0 deletions
diff --git a/name.c b/name.c
new file mode 100644
index 0000000000..4b4b0b87d1
--- /dev/null
+++ b/name.c
@@ -0,0 +1,267 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#include <assert.h>
+#include <errno.h>
+
+#include "set.h"
+#include "name.h"
+#include "macro.h"
+#include "strv.h"
+
+NameType name_type_from_string(const char *n) {
+ NameType t;
+ static const char* suffixes[_NAME_TYPE_MAX] = {
+ [NAME_SERVICE] = ".service",
+ [NAME_TIMER] = ".timer",
+ [NAME_SOCKET] = ".socket",
+ [NAME_MILESTONE] = ".milestone",
+ [NAME_DEVICE] = ".device",
+ [NAME_MOUNT] = ".mount",
+ [NAME_AUTOMOUNT] = ".automount",
+ [NAME_SNAPSHOT] = ".snapshot",
+ };
+
+ assert(n);
+
+ for (t = 0; t < _NAME_TYPE_MAX; t++)
+ if (endswith(n, suffixes[t]))
+ return t;
+
+ return _NAME_TYPE_INVALID;
+}
+
+Name *name_new(Manager *m) {
+ Name *n;
+
+ assert(m);
+
+ if (!(n = new0(Name, 1)))
+ return NULL;
+
+ /* Not much initialization happening here at this time */
+ n->meta.manager = m;
+ n->meta.type = _NAME_TYPE_INVALID;
+ n->meta.state = NAME_STUB;
+
+ /* We don't link the name here, that is left for name_link() */
+
+ return n;
+}
+
+int name_link(Name *n) {
+ char **t;
+ int r;
+
+ assert(n);
+ assert(!n->meta.linked);
+
+ STRV_FOREACH(t, n->meta.names)
+ if ((r = hashmap_put(n->meta.manager->names, *t, n)) < 0)
+ goto fail;
+
+ if (n->meta.state == NAME_STUB)
+ LIST_PREPEND(Meta, n->meta.manager->load_queue, &n->meta);
+
+ n->meta.linked = true;
+
+ return 0;
+
+fail:
+ t--;
+ STRV_FOREACH_BACKWARDS(t, n->meta.names)
+ hashmap_remove(n->meta.manager->names, *t);
+
+ return r;
+}
+
+void name_free(Name *name) {
+
+ assert(name);
+
+ /* Detach from next 'bigger' objects */
+
+ if (name->meta.linked) {
+ char **t;
+
+ STRV_FOREACH(t, name->meta.names)
+ hashmap_remove(name->meta.manager->names, *t);
+
+ if (name->meta.job)
+ job_free(name->meta.job);
+ }
+
+ /* Free data and next 'smaller' objects */
+
+ if (name->meta.job)
+ job_free(name->meta.job);
+
+ /* FIXME: Other names pointing to us should probably drop their refs to us when we get destructed */
+ set_free(name->meta.requires);
+ set_free(name->meta.soft_requires);
+ set_free(name->meta.wants);
+ set_free(name->meta.requisite);
+ set_free(name->meta.soft_requires);
+ set_free(name->meta.conflicts);
+ set_free(name->meta.before);
+ set_free(name->meta.after);
+
+ switch (name->meta.type) {
+
+ case NAME_SOCKET: {
+ unsigned i;
+ Socket *s = SOCKET(name);
+
+ for (i = 0; i < s->n_fds; i++)
+ nointr_close(s->fds[i]);
+ break;
+ }
+
+ case NAME_DEVICE: {
+ Device *d = DEVICE(name);
+
+ free(d->sysfs);
+ break;
+ }
+
+ case NAME_MOUNT: {
+ Mount *m = MOUNT(name);
+
+ free(m->path);
+ break;
+ }
+
+ case NAME_AUTOMOUNT: {
+ Automount *a = AUTOMOUNT(name);
+
+ free(a->path);
+ break;
+ }
+
+ default:
+ ;
+ }
+
+ free(name->meta.description);
+ strv_free(name->meta.names);
+
+ free(name);
+}
+
+bool name_is_ready(Name *name) {
+
+ assert(name);
+
+ if (name->meta.state != NAME_LOADED)
+ return false;
+
+ assert(name->meta.type < _NAME_TYPE_MAX);
+
+ switch (name->meta.type) {
+ case NAME_SERVICE: {
+ Service *s = SERVICE(name);
+
+ return
+ s->state == SERVICE_RUNNING ||
+ s->state == SERVICE_RELOAD_PRE ||
+ s->state == SERVICE_RELOAD ||
+ s->state == SERVICE_RELOAD_POST;
+ }
+
+ case NAME_TIMER: {
+ Timer *t = TIMER(name);
+
+ return
+ t->state == TIMER_WAITING ||
+ t->state == TIMER_RUNNING;
+ }
+
+ case NAME_SOCKET: {
+ Socket *s = SOCKET(name);
+
+ return
+ s->state == SOCKET_LISTENING ||
+ s->state == SOCKET_RUNNING;
+ }
+
+ case NAME_MILESTONE:
+ return MILESTONE(name)->state == MILESTONE_ACTIVE;
+
+ case NAME_DEVICE:
+ return DEVICE(name)->state == DEVICE_AVAILABLE;
+
+ case NAME_MOUNT:
+ return MOUNT(name)->state == MOUNT_MOUNTED;
+
+ case NAME_AUTOMOUNT: {
+ Automount *a = AUTOMOUNT(name);
+
+ return
+ a->state == AUTOMOUNT_WAITING ||
+ a->state == AUTOMOUNT_RUNNING;
+ }
+
+ case NAME_SNAPSHOT:
+ return SNAPSHOT(name)->state == SNAPSHOT_ACTIVE;
+
+
+ case _NAME_TYPE_MAX:
+ case _NAME_TYPE_INVALID:
+ ;
+ }
+
+ assert_not_reached("Unknown name type.");
+ return false;
+}
+
+static int ensure_in_set(Set **s, void *data) {
+ int r;
+
+ assert(s);
+ assert(data);
+
+ if (!*s)
+ if (!(*s = set_new(trivial_hash_func, trivial_compare_func)))
+ return -ENOMEM;
+
+ if ((r = set_put(*s, data) < 0))
+ if (r != -EEXIST)
+ return r;
+
+ return 0;
+}
+
+int name_augment(Name *n) {
+ int r;
+ void* state;
+ Name *other;
+
+ assert(n);
+
+ /* Adds in the missing links to make all dependencies both-ways */
+
+ SET_FOREACH(other, n->meta.before, state)
+ if ((r = ensure_in_set(&other->meta.after, n) < 0))
+ return r;
+ SET_FOREACH(other, n->meta.after, state)
+ if ((r = ensure_in_set(&other->meta.before, n) < 0))
+ return r;
+
+ SET_FOREACH(other, n->meta.conflicts, state)
+ if ((r = ensure_in_set(&other->meta.conflicts, n) < 0))
+ return r;
+
+ SET_FOREACH(other, n->meta.requires, state)
+ if ((r = ensure_in_set(&other->meta.required_by, n) < 0))
+ return r;
+ SET_FOREACH(other, n->meta.soft_requires, state)
+ if ((r = ensure_in_set(&other->meta.required_by, n) < 0))
+ return r;
+ SET_FOREACH(other, n->meta.requisite, state)
+ if ((r = ensure_in_set(&other->meta.required_by, n) < 0))
+ return r;
+ SET_FOREACH(other, n->meta.soft_requisite, state)
+ if ((r = ensure_in_set(&other->meta.required_by, n) < 0))
+ return r;
+
+ return r;
+}