X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=name.c;h=80ce5d5b36a6a2bff20d35b3e9d124506f95ea02;hb=a66d02c3290008d50b2b52f84cfbf46a546ba831;hp=4b4b0b87d179720a4efd9f36b0f9206779833b06;hpb=6091827530d6dd43479d6709fb6e9f745c11e900;p=elogind.git diff --git a/name.c b/name.c index 4b4b0b87d..80ce5d5b3 100644 --- a/name.c +++ b/name.c @@ -2,6 +2,7 @@ #include #include +#include #include "set.h" #include "name.h" @@ -30,6 +31,32 @@ NameType name_type_from_string(const char *n) { return _NAME_TYPE_INVALID; } +#define VALID_CHARS \ + "0123456789" \ + "abcdefghijklmnopqrstuvwxyz" \ + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ + "-_" + +bool name_is_valid(const char *n) { + NameType t; + const char *e, *i; + + assert(n); + + t = name_type_from_string(n); + if (t < 0 || t >= _NAME_TYPE_MAX) + return false; + + if (!(e = strrchr(n, '.'))) + return false; + + for (i = n; i < e; i++) + if (!strchr(VALID_CHARS, *i)) + return false; + + return true; +} + Name *name_new(Manager *m) { Name *n; @@ -38,6 +65,11 @@ Name *name_new(Manager *m) { if (!(n = new0(Name, 1))) return NULL; + if (!(n->meta.names = set_new(string_hash_func, string_compare_func))) { + free(n); + return NULL; + } + /* Not much initialization happening here at this time */ n->meta.manager = m; n->meta.type = _NAME_TYPE_INVALID; @@ -51,12 +83,14 @@ Name *name_new(Manager *m) { int name_link(Name *n) { char **t; int r; + void *state; assert(n); + assert(!set_isempty(n->meta.names)); assert(!n->meta.linked); - STRV_FOREACH(t, n->meta.names) - if ((r = hashmap_put(n->meta.manager->names, *t, n)) < 0) + SET_FOREACH(t, n->meta.names, state) + if ((r = hashmap_put(n->meta.manager->names, t, n)) < 0) goto fail; if (n->meta.state == NAME_STUB) @@ -67,43 +101,55 @@ int name_link(Name *n) { return 0; fail: - t--; - STRV_FOREACH_BACKWARDS(t, n->meta.names) - hashmap_remove(n->meta.manager->names, *t); + SET_FOREACH(t, n->meta.names, state) + assert_se(hashmap_remove(n->meta.manager->names, t) == n); return r; } +static void bidi_set_free(Name *name, Set *s) { + void *state; + Name *other; + + assert(name); + + /* Frees the set and makes sure we are dropped from the + * inverse pointers */ + + SET_FOREACH(other, s, state) { + NameDependency d; + + for (d = 0; d < _NAME_DEPENDENCY_MAX; d++) + set_remove(other->meta.dependencies[d], name); + } + + set_free(s); +} + void name_free(Name *name) { + NameDependency d; + char *t; assert(name); /* Detach from next 'bigger' objects */ - if (name->meta.linked) { char **t; + void *state; - STRV_FOREACH(t, name->meta.names) - hashmap_remove(name->meta.manager->names, *t); + SET_FOREACH(t, name->meta.names, state) + assert_se(hashmap_remove(name->meta.manager->names, t) == name); - if (name->meta.job) - job_free(name->meta.job); + if (name->meta.state == NAME_STUB) + LIST_REMOVE(Meta, name->meta.manager->load_queue, &name->meta); } /* 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); + for (d = 0; d < _NAME_DEPENDENCY_MAX; d++) + bidi_set_free(name, name->meta.dependencies[d]); switch (name->meta.type) { @@ -142,7 +188,10 @@ void name_free(Name *name) { } free(name->meta.description); - strv_free(name->meta.names); + + while ((t = set_steal_first(name->meta.names))) + free(t); + set_free(name->meta.names); free(name); } @@ -237,31 +286,104 @@ int name_augment(Name *n) { assert(n); - /* Adds in the missing links to make all dependencies both-ways */ + /* Adds in the missing links to make all dependencies bidirectional */ - SET_FOREACH(other, n->meta.before, state) - if ((r = ensure_in_set(&other->meta.after, n) < 0)) + SET_FOREACH(other, n->meta.dependencies[NAME_BEFORE], state) + if ((r = ensure_in_set(&other->meta.dependencies[NAME_AFTER], n) < 0)) return r; - SET_FOREACH(other, n->meta.after, state) - if ((r = ensure_in_set(&other->meta.before, n) < 0)) + SET_FOREACH(other, n->meta.dependencies[NAME_AFTER], state) + if ((r = ensure_in_set(&other->meta.dependencies[NAME_BEFORE], n) < 0)) return r; - SET_FOREACH(other, n->meta.conflicts, state) - if ((r = ensure_in_set(&other->meta.conflicts, n) < 0)) + SET_FOREACH(other, n->meta.dependencies[NAME_CONFLICTS], state) + if ((r = ensure_in_set(&other->meta.dependencies[NAME_CONFLICTS], n) < 0)) return r; - SET_FOREACH(other, n->meta.requires, state) - if ((r = ensure_in_set(&other->meta.required_by, n) < 0)) + SET_FOREACH(other, n->meta.dependencies[NAME_REQUIRES], state) + if ((r = ensure_in_set(&other->meta.dependencies[NAME_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)) + SET_FOREACH(other, n->meta.dependencies[NAME_REQUISITE], state) + if ((r = ensure_in_set(&other->meta.dependencies[NAME_REQUIRED_BY], n) < 0)) return r; - SET_FOREACH(other, n->meta.requisite, state) - if ((r = ensure_in_set(&other->meta.required_by, n) < 0)) + + SET_FOREACH(other, n->meta.dependencies[NAME_WANTS], state) + if ((r = ensure_in_set(&other->meta.dependencies[NAME_WANTED_BY], n) < 0)) + return r; + SET_FOREACH(other, n->meta.dependencies[NAME_SOFT_REQUIRES], state) + if ((r = ensure_in_set(&other->meta.dependencies[NAME_WANTED_BY], n) < 0)) return r; - SET_FOREACH(other, n->meta.soft_requisite, state) - if ((r = ensure_in_set(&other->meta.required_by, n) < 0)) + SET_FOREACH(other, n->meta.dependencies[NAME_SOFT_REQUISITE], state) + if ((r = ensure_in_set(&other->meta.dependencies[NAME_WANTED_BY], n) < 0)) return r; return r; } + +static int ensure_merge(Set **s, Set *other) { + + if (!other) + return 0; + + if (*s) + return set_merge(*s, other); + + if (!(*s = set_copy(other))) + return -ENOMEM; + + return 0; +} + +int name_merge(Name *name, Name *other) { + int r; + NameDependency d; + + assert(name); + assert(other); + + assert(name->meta.manager == other->meta.manager); + + if (name->meta.type != other->meta.type) + return -EINVAL; + + if (other->meta.state != NAME_STUB) + return -EINVAL; + + /* Merge names */ + if ((r = ensure_merge(&name->meta.names, other->meta.names)) < 0) + return r; + + /* Merge dependencies */ + for (d = 0; d < _NAME_DEPENDENCY_MAX; d++) + if ((r = ensure_merge(&name->meta.dependencies[d], other->meta.dependencies[d])) < 0) + return r; + + return 0; +} + +const char* name_id(Name *n) { + assert(n); + + return set_first(n->meta.names); +} + +void name_dump(Name *n, FILE *f) { + + static const char* const state_table[_NAME_STATE_MAX] = { + [NAME_STUB] = "STUB", + [NAME_LOADED] = "LOADED", + [NAME_FAILED] = "FAILED" + }; + + assert(n); + + fprintf(stderr, + "Name %s (%s), state %s\n", + name_id(n), + n->meta.description ? n->meta.description : name_id(n), + state_table[n->meta.state]); + + if (n->meta.job) { + fprintf(f, "\t▶ "); + job_dump(n->meta.job, f); + } +}