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