chiark / gitweb /
util: add split_spaces() call
[elogind.git] / manager.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 #include <assert.h>
4 #include <errno.h>
5
6 #include "manager.h"
7 #include "hashmap.h"
8 #include "macro.h"
9 #include "strv.h"
10
11 Manager* manager_new(void) {
12         Manager *m;
13
14         if (!(m = new0(Manager, 1)))
15                 return NULL;
16
17         if (!(m->names = hashmap_new(string_hash_func, string_compare_func)))
18                 goto fail;
19
20         if (!(m->jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
21                 goto fail;
22
23         if (!(m->jobs_to_add = hashmap_new(trivial_hash_func, trivial_compare_func)))
24                 goto fail;
25
26         if (!(m->jobs_to_remove = set_new(trivial_hash_func, trivial_compare_func)))
27                 goto fail;
28
29         return m;
30
31 fail:
32         manager_free(m);
33         return NULL;
34 }
35
36 void manager_free(Manager *m) {
37         Name *n;
38
39         assert(m);
40
41         while ((n = hashmap_first(m->names)))
42                 name_free(n);
43
44         hashmap_free(m->names);
45         hashmap_free(m->jobs);
46
47         /* FIXME: This is incomplete */
48
49         hashmap_free(m->jobs_to_add);
50         set_free(m->jobs_to_remove);
51
52         free(m);
53 }
54
55 int manager_add_job(Manager *m, JobType type, Name *name, JobMode mode, Job **_ret) {
56         Job *ret, *other;
57         void *state;
58         Name *dep;
59         int r;
60
61         assert(m);
62         assert(type < _JOB_TYPE_MAX);
63         assert(name);
64         assert(mode < _JOB_MODE_MAX);
65         assert(_ret);
66
67         /* Check for conflicts, first against the jobs we shall
68          * create */
69         if ((other = hashmap_get(m->jobs_to_add, name))) {
70
71                 if (other->type != type)
72                         return -EEXIST;
73
74         } else if (name->meta.job) {
75
76                 if (name->meta.job->type != type) {
77
78                         if (mode == JOB_FAIL)
79                                 return -EEXIST;
80
81                         if ((r = set_put(m->jobs_to_remove, name->meta.job)) < 0)
82                                 return r;
83                 }
84         }
85
86         if (!(ret = job_new(m, type, name)))
87                 return -ENOMEM;
88
89         if ((r = hashmap_put(m->jobs_to_add, name, ret)) < 0)
90                 goto fail;
91
92         if (type == JOB_START || type == JOB_VERIFY_STARTED || type == JOB_RESTART_FINISH) {
93                 SET_FOREACH(dep, ret->name->meta.requires, state)
94                         if ((r = manager_add_job(m, type, dep, mode, NULL)) < 0)
95                                 goto fail;
96                 SET_FOREACH(dep, ret->name->meta.soft_requires, state)
97                         if ((r = manager_add_job(m, type, dep, JOB_FAIL, NULL)) < 0)
98                                 goto fail;
99                 SET_FOREACH(dep, ret->name->meta.wants, state)
100                         if ((r = manager_add_job(m, type, dep, JOB_FAIL, NULL)) < 0)
101                                 goto fail;
102                 SET_FOREACH(dep, ret->name->meta.requisite, state)
103                         if ((r = manager_add_job(m, JOB_VERIFY_STARTED, dep, mode, NULL)) < 0)
104                                 goto fail;
105                 SET_FOREACH(dep, ret->name->meta.soft_requisite, state)
106                         if ((r = manager_add_job(m, JOB_VERIFY_STARTED, dep, JOB_FAIL, NULL)) < 0)
107                                 goto fail;
108                 SET_FOREACH(dep, ret->name->meta.conflicts, state)
109                         if ((r = manager_add_job(m, type, dep, mode, NULL)) < 0)
110                                 goto fail;
111
112         } else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) {
113
114                 SET_FOREACH(dep, ret->name->meta.required_by, state)
115                         if ((r = manager_add_job(m, type, dep, mode, NULL)) < 0)
116                                 goto fail;
117         }
118
119         if (_ret)
120                 *_ret = ret;
121
122         return 0;
123
124 fail:
125         job_free(ret);
126
127         return r;
128 }
129
130
131 Job *manager_get_job(Manager *m, uint32_t id) {
132         assert(m);
133
134         return hashmap_get(m->jobs, UINT32_TO_PTR(id));
135 }
136
137 Name *manager_get_name(Manager *m, const char *name) {
138         assert(m);
139         assert(name);
140
141         return hashmap_get(m->names, name);
142 }
143
144 static int detect_type(Name *name) {
145         char **n;
146
147         assert(name);
148
149         name->meta.type = _NAME_TYPE_INVALID;
150
151         STRV_FOREACH(n, name->meta.names) {
152                 NameType t;
153
154                 if ((t = name_type_from_string(*n)) == _NAME_TYPE_INVALID)
155                         return -EINVAL;
156
157                 if (name->meta.type == _NAME_TYPE_INVALID) {
158                         name->meta.type = t;
159                         continue;
160                 }
161
162                 if (name->meta.type != t)
163                         return -EINVAL;
164         }
165
166         return 0;
167 }
168
169 static int fragment_load(Name *n) {
170         assert(n);
171
172         /*... */
173
174         return 0;
175 }
176
177 static int sysv_load(Service *s) {
178         assert(s);
179
180         /*... */
181
182         return 0;
183 }
184
185 static int fstab_load(Name *n) {
186         assert(n);
187         assert(n->meta.type == NAME_MOUNT || n->meta.type == NAME_AUTOMOUNT);
188
189         /*... */
190
191         return 0;
192 }
193
194 static int snapshot_load(Snapshot *s) {
195         assert(s);
196
197         /*... */
198
199         return 0;
200 }
201
202 static int load(Name *name) {
203         int r;
204
205         assert(name);
206
207         if (name->meta.state != NAME_STUB)
208                 return 0;
209
210         if ((r = detect_type(name)) < 0)
211                 return r;
212
213         if (name->meta.type == NAME_SERVICE) {
214
215                 /* Load a .service file */
216                 if ((r = fragment_load(name)) == 0)
217                         goto finish;
218
219                 /* Load a classic init script */
220                 if (r == -ENOENT)
221                         if ((r = sysv_load(SERVICE(name))) == 0)
222                                 goto finish;
223
224         } else if (name->meta.type == NAME_MOUNT ||
225                    name->meta.type == NAME_AUTOMOUNT) {
226
227                 if ((r = fstab_load(name)) == 0)
228                         goto finish;
229
230         } else if (name->meta.type == NAME_SNAPSHOT) {
231
232                 if ((r = snapshot_load(SNAPSHOT(name))) == 0)
233                         goto finish;
234
235         } else {
236                 if ((r = fragment_load(name)) == 0)
237                         goto finish;
238         }
239
240         name->meta.state = NAME_FAILED;
241         return r;
242
243 finish:
244         name->meta.state = NAME_LOADED;
245         return 0;
246 }
247
248 static int dispatch_load_queue(Manager *m) {
249         Meta *meta;
250
251         assert(m);
252
253         /* Dispatches the load queue. Takes a name from the queue and
254          * tries to load its data until the queue is empty */
255
256         while ((meta = m->load_queue)) {
257                 load(NAME(meta));
258                 LIST_REMOVE(Meta, m->load_queue, meta);
259         }
260
261         return 0;
262 }
263
264
265
266 int manager_load_name(Manager *m, const char *name, Name **_ret) {
267         Name *ret;
268         NameType t;
269         int r;
270
271         assert(m);
272         assert(name);
273         assert(_ret);
274 /* This will load the service information files, but not actually
275  * start any services or anything */
276
277
278         if ((ret = manager_get_name(m, name)))
279                 goto finish;
280
281         if ((t = name_type_from_string(name)) == _NAME_TYPE_INVALID)
282                 return -EINVAL;
283
284         if (!(ret = name_new(m)))
285                 return -ENOMEM;
286
287         ret->meta.type = t;
288
289         if (!(ret->meta.names = strv_new(name, NULL))) {
290                 name_free(ret);
291                 return -ENOMEM;
292         }
293
294         if ((r = name_link(ret)) < 0) {
295                 name_free(ret);
296                 return r;
297         }
298
299         /* At this point the new entry is created and linked. However,
300          * not loaded. Now load this entry and all its dependencies
301          * recursively */
302
303         dispatch_load_queue(m);
304
305 finish:
306
307         *_ret = ret;
308         return 0;
309 }