diff options
author | Lennart Poettering <lennart@poettering.net> | 2009-11-18 00:42:52 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2009-11-18 00:42:52 +0100 |
commit | 6091827530d6dd43479d6709fb6e9f745c11e900 (patch) | |
tree | 3edf7ccdeeb60b634d63e1abcaa8132a6259a331 /manager.c |
initial commit
Diffstat (limited to 'manager.c')
-rw-r--r-- | manager.c | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/manager.c b/manager.c new file mode 100644 index 0000000000..d6bc35a289 --- /dev/null +++ b/manager.c @@ -0,0 +1,309 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#include <assert.h> +#include <errno.h> + +#include "manager.h" +#include "hashmap.h" +#include "macro.h" +#include "strv.h" + +Manager* manager_new(void) { + Manager *m; + + if (!(m = new0(Manager, 1))) + return NULL; + + if (!(m->names = hashmap_new(string_hash_func, string_compare_func))) + goto fail; + + if (!(m->jobs = hashmap_new(trivial_hash_func, trivial_compare_func))) + goto fail; + + if (!(m->jobs_to_add = hashmap_new(trivial_hash_func, trivial_compare_func))) + goto fail; + + if (!(m->jobs_to_remove = set_new(trivial_hash_func, trivial_compare_func))) + goto fail; + + return m; + +fail: + manager_free(m); + return NULL; +} + +void manager_free(Manager *m) { + Name *n; + + assert(m); + + while ((n = hashmap_first(m->names))) + name_free(n); + + hashmap_free(m->names); + hashmap_free(m->jobs); + + /* FIXME: This is incomplete */ + + hashmap_free(m->jobs_to_add); + set_free(m->jobs_to_remove); + + free(m); +} + +int manager_add_job(Manager *m, JobType type, Name *name, JobMode mode, Job **_ret) { + Job *ret, *other; + void *state; + Name *dep; + int r; + + assert(m); + assert(type < _JOB_TYPE_MAX); + assert(name); + assert(mode < _JOB_MODE_MAX); + assert(_ret); + + /* Check for conflicts, first against the jobs we shall + * create */ + if ((other = hashmap_get(m->jobs_to_add, name))) { + + if (other->type != type) + return -EEXIST; + + } else if (name->meta.job) { + + if (name->meta.job->type != type) { + + if (mode == JOB_FAIL) + return -EEXIST; + + if ((r = set_put(m->jobs_to_remove, name->meta.job)) < 0) + return r; + } + } + + if (!(ret = job_new(m, type, name))) + return -ENOMEM; + + if ((r = hashmap_put(m->jobs_to_add, name, ret)) < 0) + goto fail; + + if (type == JOB_START || type == JOB_VERIFY_STARTED || type == JOB_RESTART_FINISH) { + SET_FOREACH(dep, ret->name->meta.requires, state) + if ((r = manager_add_job(m, type, dep, mode, NULL)) < 0) + goto fail; + SET_FOREACH(dep, ret->name->meta.soft_requires, state) + if ((r = manager_add_job(m, type, dep, JOB_FAIL, NULL)) < 0) + goto fail; + SET_FOREACH(dep, ret->name->meta.wants, state) + if ((r = manager_add_job(m, type, dep, JOB_FAIL, NULL)) < 0) + goto fail; + SET_FOREACH(dep, ret->name->meta.requisite, state) + if ((r = manager_add_job(m, JOB_VERIFY_STARTED, dep, mode, NULL)) < 0) + goto fail; + SET_FOREACH(dep, ret->name->meta.soft_requisite, state) + if ((r = manager_add_job(m, JOB_VERIFY_STARTED, dep, JOB_FAIL, NULL)) < 0) + goto fail; + SET_FOREACH(dep, ret->name->meta.conflicts, state) + if ((r = manager_add_job(m, type, dep, mode, NULL)) < 0) + goto fail; + + } else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) { + + SET_FOREACH(dep, ret->name->meta.required_by, state) + if ((r = manager_add_job(m, type, dep, mode, NULL)) < 0) + goto fail; + } + + if (_ret) + *_ret = ret; + + return 0; + +fail: + job_free(ret); + + return r; +} + + +Job *manager_get_job(Manager *m, uint32_t id) { + assert(m); + + return hashmap_get(m->jobs, UINT32_TO_PTR(id)); +} + +Name *manager_get_name(Manager *m, const char *name) { + assert(m); + assert(name); + + return hashmap_get(m->names, name); +} + +static int detect_type(Name *name) { + char **n; + + assert(name); + + name->meta.type = _NAME_TYPE_INVALID; + + STRV_FOREACH(n, name->meta.names) { + NameType t; + + if ((t = name_type_from_string(*n)) == _NAME_TYPE_INVALID) + return -EINVAL; + + if (name->meta.type == _NAME_TYPE_INVALID) { + name->meta.type = t; + continue; + } + + if (name->meta.type != t) + return -EINVAL; + } + + return 0; +} + +static int fragment_load(Name *n) { + assert(n); + + /*... */ + + return 0; +} + +static int sysv_load(Service *s) { + assert(s); + + /*... */ + + return 0; +} + +static int fstab_load(Name *n) { + assert(n); + assert(n->meta.type == NAME_MOUNT || n->meta.type == NAME_AUTOMOUNT); + + /*... */ + + return 0; +} + +static int snapshot_load(Snapshot *s) { + assert(s); + + /*... */ + + return 0; +} + +static int load(Name *name) { + int r; + + assert(name); + + if (name->meta.state != NAME_STUB) + return 0; + + if ((r = detect_type(name)) < 0) + return r; + + if (name->meta.type == NAME_SERVICE) { + + /* Load a .service file */ + if ((r = fragment_load(name)) == 0) + goto finish; + + /* Load a classic init script */ + if (r == -ENOENT) + if ((r = sysv_load(SERVICE(name))) == 0) + goto finish; + + } else if (name->meta.type == NAME_MOUNT || + name->meta.type == NAME_AUTOMOUNT) { + + if ((r = fstab_load(name)) == 0) + goto finish; + + } else if (name->meta.type == NAME_SNAPSHOT) { + + if ((r = snapshot_load(SNAPSHOT(name))) == 0) + goto finish; + + } else { + if ((r = fragment_load(name)) == 0) + goto finish; + } + + name->meta.state = NAME_FAILED; + return r; + +finish: + name->meta.state = NAME_LOADED; + return 0; +} + +static int dispatch_load_queue(Manager *m) { + Meta *meta; + + assert(m); + + /* Dispatches the load queue. Takes a name from the queue and + * tries to load its data until the queue is empty */ + + while ((meta = m->load_queue)) { + load(NAME(meta)); + LIST_REMOVE(Meta, m->load_queue, meta); + } + + return 0; +} + + + +int manager_load_name(Manager *m, const char *name, Name **_ret) { + Name *ret; + NameType t; + int r; + + assert(m); + assert(name); + assert(_ret); +/* This will load the service information files, but not actually + * start any services or anything */ + + + if ((ret = manager_get_name(m, name))) + goto finish; + + if ((t = name_type_from_string(name)) == _NAME_TYPE_INVALID) + return -EINVAL; + + if (!(ret = name_new(m))) + return -ENOMEM; + + ret->meta.type = t; + + if (!(ret->meta.names = strv_new(name, NULL))) { + name_free(ret); + return -ENOMEM; + } + + if ((r = name_link(ret)) < 0) { + name_free(ret); + return r; + } + + /* At this point the new entry is created and linked. However, + * not loaded. Now load this entry and all its dependencies + * recursively */ + + dispatch_load_queue(m); + +finish: + + *_ret = ret; + return 0; +} |