1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
11 #include "load-fragment.h"
13 Manager* manager_new(void) {
16 if (!(m = new0(Manager, 1)))
19 if (!(m->names = hashmap_new(string_hash_func, string_compare_func)))
22 if (!(m->jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
25 if (!(m->jobs_to_add = hashmap_new(trivial_hash_func, trivial_compare_func)))
28 if (!(m->jobs_to_remove = set_new(trivial_hash_func, trivial_compare_func)))
38 void manager_free(Manager *m) {
43 while ((n = hashmap_first(m->names)))
46 hashmap_free(m->names);
47 hashmap_free(m->jobs);
49 /* FIXME: This is incomplete */
51 hashmap_free(m->jobs_to_add);
52 set_free(m->jobs_to_remove);
57 static void transaction_abort(Manager *m) {
61 assert(m->n_dependency_depth == 0);
63 while ((j = hashmap_steal_first(m->jobs_to_add)))
66 set_clear(m->jobs_to_remove);
69 static int transaction_activate(Manager *m) {
75 assert(m->n_dependency_depth == 0);
77 /* This applies the changes recorded in jobs_to_add and
78 * jobs_to_remove to the actual list of jobs */
80 HASHMAP_FOREACH(j, m->jobs_to_add, state) {
83 if ((r = hashmap_put(j->manager->jobs, UINT32_TO_PTR(j->id), j)) < 0)
87 /* all entries are now registered, now make sure the names
90 while ((j = hashmap_steal_first(m->jobs_to_add))) {
91 j->name->meta.job = j;
95 while ((j = set_steal_first(m->jobs_to_remove)))
102 HASHMAP_FOREACH(j, m->jobs_to_add, state)
103 hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
105 transaction_abort(m);
109 int manager_add_job(Manager *m, JobType type, Name *name, JobMode mode, Job **_ret) {
116 assert(type < _JOB_TYPE_MAX);
118 assert(mode < _JOB_MODE_MAX);
120 /* Check for conflicts, first against the jobs we shall
122 if ((other = hashmap_get(m->jobs_to_add, name))) {
124 if (other->type != type)
127 } else if (name->meta.job) {
129 if (name->meta.job->type != type) {
131 if (mode == JOB_FAIL)
134 if ((r = set_put(m->jobs_to_remove, name->meta.job)) < 0)
139 if (!(ret = job_new(m, type, name)))
142 m->n_dependency_depth ++;
144 if ((r = hashmap_put(m->jobs_to_add, name, ret)) < 0)
147 if (type == JOB_START || type == JOB_VERIFY_STARTED || type == JOB_RESTART_FINISH) {
148 SET_FOREACH(dep, ret->name->meta.dependencies[NAME_REQUIRES], state)
149 if ((r = manager_add_job(m, type, dep, mode, NULL)) < 0)
151 SET_FOREACH(dep, ret->name->meta.dependencies[NAME_SOFT_REQUIRES], state)
152 if ((r = manager_add_job(m, type, dep, JOB_FAIL, NULL)) < 0)
154 SET_FOREACH(dep, ret->name->meta.dependencies[NAME_WANTS], state)
155 if ((r = manager_add_job(m, type, dep, JOB_FAIL, NULL)) < 0)
157 SET_FOREACH(dep, ret->name->meta.dependencies[NAME_REQUISITE], state)
158 if ((r = manager_add_job(m, JOB_VERIFY_STARTED, dep, mode, NULL)) < 0)
160 SET_FOREACH(dep, ret->name->meta.dependencies[NAME_SOFT_REQUISITE], state)
161 if ((r = manager_add_job(m, JOB_VERIFY_STARTED, dep, JOB_FAIL, NULL)) < 0)
163 SET_FOREACH(dep, ret->name->meta.dependencies[NAME_CONFLICTS], state)
164 if ((r = manager_add_job(m, type, dep, mode, NULL)) < 0)
167 } else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) {
169 SET_FOREACH(dep, ret->name->meta.dependencies[NAME_REQUIRED_BY], state)
170 if ((r = manager_add_job(m, type, dep, mode, NULL)) < 0)
174 if (--m->n_dependency_depth <= 0)
175 if ((r = transaction_activate(m)) < 0) {
176 transaction_abort(m);
189 if (--m->n_dependency_depth <= 0)
190 transaction_abort(m);
196 Job *manager_get_job(Manager *m, uint32_t id) {
199 return hashmap_get(m->jobs, UINT32_TO_PTR(id));
202 Name *manager_get_name(Manager *m, const char *name) {
206 return hashmap_get(m->names, name);
209 static int verify_type(Name *name) {
215 /* Checks that all aliases of this name have the same and valid type */
217 SET_FOREACH(n, name->meta.names, state) {
220 if ((t = name_type_from_string(n)) == _NAME_TYPE_INVALID)
223 if (name->meta.type == _NAME_TYPE_INVALID) {
228 if (name->meta.type != t)
232 if (name->meta.type == _NAME_TYPE_INVALID)
238 static int service_load_sysv(Service *s) {
241 /* Load service data from SysV init scripts, preferably with
247 static int name_load_fstab(Name *n) {
249 assert(n->meta.type == NAME_MOUNT || n->meta.type == NAME_AUTOMOUNT);
251 /* Load mount data from /etc/fstab */
256 static int snapshot_load(Snapshot *s) {
259 /* Load snapshots from disk */
264 static int name_load_dropin(Name *n) {
267 /* Load dependencies from drop-in directories */
272 static int load(Name *name) {
277 if (name->meta.state != NAME_STUB)
280 if ((r = verify_type(name)) < 0)
283 if (name->meta.type == NAME_SERVICE) {
285 /* Load a .service file */
286 if ((r = name_load_fragment(name)) == 0)
289 /* Load a classic init script */
291 if ((r = service_load_sysv(SERVICE(name))) == 0)
294 } else if (name->meta.type == NAME_MOUNT ||
295 name->meta.type == NAME_AUTOMOUNT) {
297 if ((r = name_load_fstab(name)) == 0)
300 } else if (name->meta.type == NAME_SNAPSHOT) {
302 if ((r = snapshot_load(SNAPSHOT(name))) == 0)
306 if ((r = name_load_fragment(name)) == 0)
310 name->meta.state = NAME_FAILED;
314 if ((r = name_load_dropin(name)) < 0)
317 if ((r = name_link_names(name)) < 0)
320 name->meta.state = NAME_LOADED;
324 static int dispatch_load_queue(Manager *m) {
329 /* Make sure we are not run recursively */
330 if (m->dispatching_load_queue)
333 m->dispatching_load_queue = true;
335 /* Dispatches the load queue. Takes a name from the queue and
336 * tries to load its data until the queue is empty */
338 while ((meta = m->load_queue)) {
340 LIST_REMOVE(Meta, m->load_queue, meta);
343 m->dispatching_load_queue = false;
348 int manager_load_name(Manager *m, const char *name, Name **_ret) {
358 if (!name_is_valid(name))
361 /* This will load the service information files, but not actually
362 * start any services or anything */
364 if ((ret = manager_get_name(m, name)))
367 if ((t = name_type_from_string(name)) == _NAME_TYPE_INVALID)
370 if (!(ret = name_new(m)))
375 if (!(n = strdup(name))) {
380 if (set_put(ret->meta.names, n) < 0) {
386 if ((r = name_link(ret)) < 0) {
391 /* At this point the new entry is created and linked. However,
392 * not loaded. Now load this entry and all its dependencies
395 dispatch_load_queue(m);
403 void manager_dump_jobs(Manager *s, FILE *f) {
410 HASHMAP_FOREACH(j, s->jobs, state)
414 void manager_dump_names(Manager *s, FILE *f) {
422 HASHMAP_FOREACH_KEY(n, t, s->names, state)