chiark / gitweb /
unit: rename load_path to fragment_path to make clear what kind of configuration...
[elogind.git] / job.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <assert.h>
23 #include <errno.h>
24
25 #include "set.h"
26 #include "unit.h"
27 #include "macro.h"
28 #include "strv.h"
29 #include "load-fragment.h"
30 #include "load-dropin.h"
31 #include "log.h"
32
33 Job* job_new(Manager *m, JobType type, Unit *unit) {
34         Job *j;
35
36         assert(m);
37         assert(type < _JOB_TYPE_MAX);
38         assert(unit);
39
40         if (!(j = new0(Job, 1)))
41                 return NULL;
42
43         j->manager = m;
44         j->id = m->current_job_id++;
45         j->type = type;
46         j->unit = unit;
47
48         /* We don't link it here, that's what job_dependency() is for */
49
50         return j;
51 }
52
53 void job_free(Job *j) {
54         assert(j);
55
56         /* Detach from next 'bigger' objects */
57         if (j->installed) {
58                 bus_job_send_removed_signal(j);
59
60                 if (j->unit->meta.job == j)
61                         j->unit->meta.job = NULL;
62
63                 hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
64                 j->installed = false;
65         }
66
67         /* Detach from next 'smaller' objects */
68         manager_transaction_unlink_job(j->manager, j);
69
70         if (j->in_run_queue)
71                 LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
72
73         if (j->in_dbus_queue)
74                 LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
75
76         free(j);
77 }
78
79 JobDependency* job_dependency_new(Job *subject, Job *object, bool matters) {
80         JobDependency *l;
81
82         assert(object);
83
84         /* Adds a new job link, which encodes that the 'subject' job
85          * needs the 'object' job in some way. If 'subject' is NULL
86          * this means the 'anchor' job (i.e. the one the user
87          * explcitily asked for) is the requester. */
88
89         if (!(l = new0(JobDependency, 1)))
90                 return NULL;
91
92         l->subject = subject;
93         l->object = object;
94         l->matters = matters;
95
96         if (subject)
97                 LIST_PREPEND(JobDependency, subject, subject->subject_list, l);
98         else
99                 LIST_PREPEND(JobDependency, subject, object->manager->transaction_anchor, l);
100
101         LIST_PREPEND(JobDependency, object, object->object_list, l);
102
103         return l;
104 }
105
106 void job_dependency_free(JobDependency *l) {
107         assert(l);
108
109         if (l->subject)
110                 LIST_REMOVE(JobDependency, subject, l->subject->subject_list, l);
111         else
112                 LIST_REMOVE(JobDependency, subject, l->object->manager->transaction_anchor, l);
113
114         LIST_REMOVE(JobDependency, object, l->object->object_list, l);
115
116         free(l);
117 }
118
119 void job_dependency_delete(Job *subject, Job *object, bool *matters) {
120         JobDependency *l;
121
122         assert(object);
123
124         LIST_FOREACH(object, l, object->object_list) {
125                 assert(l->object == object);
126
127                 if (l->subject == subject)
128                         break;
129         }
130
131         if (!l) {
132                 if (matters)
133                         *matters = false;
134                 return;
135         }
136
137         if (matters)
138                 *matters = l->matters;
139
140         job_dependency_free(l);
141 }
142
143 void job_dump(Job *j, FILE*f, const char *prefix) {
144
145
146         assert(j);
147         assert(f);
148
149         fprintf(f,
150                 "%sā†’ Job %u:\n"
151                 "%s\tAction: %s ā†’ %s\n"
152                 "%s\tState: %s\n"
153                 "%s\tForced: %s\n",
154                 prefix, j->id,
155                 prefix, unit_id(j->unit), job_type_to_string(j->type),
156                 prefix, job_state_to_string(j->state),
157                 prefix, yes_no(j->forced));
158 }
159
160 bool job_is_anchor(Job *j) {
161         JobDependency *l;
162
163         assert(j);
164
165         LIST_FOREACH(object, l, j->object_list)
166                 if (!l->subject)
167                         return true;
168
169         return false;
170 }
171
172 static bool types_match(JobType a, JobType b, JobType c, JobType d) {
173         return
174                 (a == c && b == d) ||
175                 (a == d && b == c);
176 }
177
178 int job_type_merge(JobType *a, JobType b) {
179         if (*a == b)
180                 return 0;
181
182         /* Merging is associative! a merged with b merged with c is
183          * the same as a merged with c merged with b. */
184
185         /* Mergeability is transitive! if a can be merged with b and b
186          * with c then a also with c */
187
188         /* Also, if a merged with b cannot be merged with c, then
189          * either a or b cannot be merged with c either */
190
191         if (types_match(*a, b, JOB_START, JOB_VERIFY_ACTIVE))
192                 *a = JOB_START;
193         else if (types_match(*a, b, JOB_START, JOB_RELOAD) ||
194                  types_match(*a, b, JOB_START, JOB_RELOAD_OR_START) ||
195                  types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RELOAD_OR_START) ||
196                  types_match(*a, b, JOB_RELOAD, JOB_RELOAD_OR_START))
197                 *a = JOB_RELOAD_OR_START;
198         else if (types_match(*a, b, JOB_START, JOB_RESTART) ||
199                  types_match(*a, b, JOB_START, JOB_TRY_RESTART) ||
200                  types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RESTART) ||
201                  types_match(*a, b, JOB_RELOAD, JOB_RESTART) ||
202                  types_match(*a, b, JOB_RELOAD_OR_START, JOB_RESTART) ||
203                  types_match(*a, b, JOB_RELOAD_OR_START, JOB_TRY_RESTART) ||
204                  types_match(*a, b, JOB_RESTART, JOB_TRY_RESTART))
205                 *a = JOB_RESTART;
206         else if (types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RELOAD))
207                 *a = JOB_RELOAD;
208         else if (types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_TRY_RESTART) ||
209                  types_match(*a, b, JOB_RELOAD, JOB_TRY_RESTART))
210                 *a = JOB_TRY_RESTART;
211         else
212                 return -EEXIST;
213
214         return 0;
215 }
216
217 bool job_type_is_mergeable(JobType a, JobType b) {
218         return job_type_merge(&a, b) >= 0;
219 }
220
221 bool job_type_is_superset(JobType a, JobType b) {
222
223         /* Checks whether operation a is a "superset" of b in its
224          * actions */
225
226         if (a == b)
227                 return true;
228
229         switch (a) {
230                 case JOB_START:
231                         return b == JOB_VERIFY_ACTIVE;
232
233                 case JOB_RELOAD:
234                         return
235                                 b == JOB_VERIFY_ACTIVE;
236
237                 case JOB_RELOAD_OR_START:
238                         return
239                                 b == JOB_RELOAD ||
240                                 b == JOB_START ||
241                                 b == JOB_VERIFY_ACTIVE;
242
243                 case JOB_RESTART:
244                         return
245                                 b == JOB_START ||
246                                 b == JOB_VERIFY_ACTIVE ||
247                                 b == JOB_RELOAD ||
248                                 b == JOB_RELOAD_OR_START ||
249                                 b == JOB_TRY_RESTART;
250
251                 case JOB_TRY_RESTART:
252                         return
253                                 b == JOB_VERIFY_ACTIVE ||
254                                 b == JOB_RELOAD;
255                 default:
256                         return false;
257
258         }
259 }
260
261 bool job_type_is_conflicting(JobType a, JobType b) {
262         assert(a >= 0 && a < _JOB_TYPE_MAX);
263         assert(b >= 0 && b < _JOB_TYPE_MAX);
264
265         return (a == JOB_STOP) != (b == JOB_STOP);
266 }
267
268 bool job_is_runnable(Job *j) {
269         Iterator i;
270         Unit *other;
271
272         assert(j);
273         assert(j->installed);
274
275         /* Checks whether there is any job running for the units this
276          * job needs to be running after (in the case of a 'positive'
277          * job type) or before (in the case of a 'negative' job type
278          * . */
279
280         if (j->type == JOB_START ||
281             j->type == JOB_VERIFY_ACTIVE ||
282             j->type == JOB_RELOAD ||
283             j->type == JOB_RELOAD_OR_START) {
284
285                 /* Immediate result is that the job is or might be
286                  * started. In this case lets wait for the
287                  * dependencies, regardless whether they are
288                  * starting or stopping something. */
289
290                 SET_FOREACH(other, j->unit->meta.dependencies[UNIT_AFTER], i)
291                         if (other->meta.job)
292                                 return false;
293         }
294
295         /* Also, if something else is being stopped and we should
296          * change state after it, then lets wait. */
297
298         SET_FOREACH(other, j->unit->meta.dependencies[UNIT_BEFORE], i)
299                 if (other->meta.job &&
300                     (other->meta.job->type == JOB_STOP ||
301                      other->meta.job->type == JOB_RESTART ||
302                      other->meta.job->type == JOB_TRY_RESTART))
303                         return false;
304
305         /* This means that for a service a and a service b where b
306          * shall be started after a:
307          *
308          *  start a + start b ā†’ 1st step start a, 2nd step start b
309          *  start a + stop b  ā†’ 1st step stop b,  2nd step start a
310          *  stop a  + start b ā†’ 1st step stop a,  2nd step start b
311          *  stop a  + stop b  ā†’ 1st step stop b,  2nd step stop a
312          *
313          *  This has the side effect that restarts are properly
314          *  synchronized too. */
315
316         return true;
317 }
318
319 int job_run_and_invalidate(Job *j) {
320         int r;
321
322         assert(j);
323         assert(j->installed);
324
325         if (j->in_run_queue) {
326                 LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
327                 j->in_run_queue = false;
328         }
329
330         if (j->state != JOB_WAITING)
331                 return 0;
332
333         if (!job_is_runnable(j))
334                 return -EAGAIN;
335
336         j->state = JOB_RUNNING;
337         job_add_to_dbus_queue(j);
338
339         switch (j->type) {
340
341                 case JOB_START:
342                         r = unit_start(j->unit);
343                         if (r == -EBADR)
344                                 r = 0;
345                         break;
346
347                 case JOB_VERIFY_ACTIVE: {
348                         UnitActiveState t = unit_active_state(j->unit);
349                         if (UNIT_IS_ACTIVE_OR_RELOADING(t))
350                                 r = -EALREADY;
351                         else if (t == UNIT_ACTIVATING)
352                                 r = -EAGAIN;
353                         else
354                                 r = -ENOEXEC;
355                         break;
356                 }
357
358                 case JOB_STOP:
359                         r = unit_stop(j->unit);
360                         break;
361
362                 case JOB_RELOAD:
363                         r = unit_reload(j->unit);
364                         break;
365
366                 case JOB_RELOAD_OR_START:
367                         if (unit_active_state(j->unit) == UNIT_ACTIVE)
368                                 r = unit_reload(j->unit);
369                         else
370                                 r = unit_start(j->unit);
371                         break;
372
373                 case JOB_RESTART: {
374                         UnitActiveState t = unit_active_state(j->unit);
375                         if (t == UNIT_INACTIVE || t == UNIT_ACTIVATING) {
376                                 j->type = JOB_START;
377                                 r = unit_start(j->unit);
378                         } else
379                                 r = unit_stop(j->unit);
380                         break;
381                 }
382
383                 case JOB_TRY_RESTART: {
384                         UnitActiveState t = unit_active_state(j->unit);
385                         if (t == UNIT_INACTIVE || t == UNIT_DEACTIVATING)
386                                 r = -ENOEXEC;
387                         else if (t == UNIT_ACTIVATING) {
388                                 j->type = JOB_START;
389                                 r = unit_start(j->unit);
390                         } else
391                                 r = unit_stop(j->unit);
392                         break;
393                 }
394
395                 default:
396                         assert_not_reached("Unknown job type");
397         }
398
399         if (r == -EALREADY)
400                 r = job_finish_and_invalidate(j, true);
401         else if (r == -EAGAIN) {
402                 j->state = JOB_WAITING;
403                 return -EAGAIN;
404         } else if (r < 0)
405                 r = job_finish_and_invalidate(j, false);
406
407         return r;
408 }
409
410 int job_finish_and_invalidate(Job *j, bool success) {
411         Unit *u;
412         Unit *other;
413         UnitType t;
414         Iterator i;
415
416         assert(j);
417         assert(j->installed);
418
419         log_debug("Job %s/%s finished, success=%s", unit_id(j->unit), job_type_to_string(j->type), yes_no(success));
420         job_add_to_dbus_queue(j);
421
422         /* Patch restart jobs so that they become normal start jobs */
423         if (success && (j->type == JOB_RESTART || j->type == JOB_TRY_RESTART)) {
424
425                 log_debug("Converting job %s/%s ā†’ %s/%s",
426                           unit_id(j->unit), job_type_to_string(j->type),
427                           unit_id(j->unit), job_type_to_string(JOB_START));
428
429                 j->state = JOB_RUNNING;
430                 j->type = JOB_START;
431
432                 job_add_to_run_queue(j);
433                 return 0;
434         }
435
436         u = j->unit;
437         t = j->type;
438         job_free(j);
439
440         /* Fail depending jobs on failure */
441         if (!success) {
442
443                 if (t == JOB_START ||
444                     t == JOB_VERIFY_ACTIVE ||
445                     t == JOB_RELOAD_OR_START) {
446
447                         SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i)
448                                 if (other->meta.job &&
449                                     (other->meta.type == JOB_START ||
450                                      other->meta.type == JOB_VERIFY_ACTIVE ||
451                                      other->meta.type == JOB_RELOAD_OR_START))
452                                         job_finish_and_invalidate(other->meta.job, false);
453
454                         SET_FOREACH(other, u->meta.dependencies[UNIT_SOFT_REQUIRED_BY], i)
455                                 if (other->meta.job &&
456                                     !other->meta.job->forced &&
457                                     (other->meta.type == JOB_START ||
458                                      other->meta.type == JOB_VERIFY_ACTIVE ||
459                                      other->meta.type == JOB_RELOAD_OR_START))
460                                         job_finish_and_invalidate(other->meta.job, false);
461
462                 } else if (t == JOB_STOP) {
463
464                         SET_FOREACH(other, u->meta.dependencies[UNIT_CONFLICTS], i)
465                                 if (other->meta.job &&
466                                     (t == JOB_START ||
467                                      t == JOB_VERIFY_ACTIVE ||
468                                      t == JOB_RELOAD_OR_START))
469                                         job_finish_and_invalidate(other->meta.job, false);
470                 }
471         }
472
473         /* Try to start the next jobs that can be started */
474         SET_FOREACH(other, u->meta.dependencies[UNIT_AFTER], i)
475                 if (other->meta.job)
476                         job_add_to_run_queue(other->meta.job);
477         SET_FOREACH(other, u->meta.dependencies[UNIT_BEFORE], i)
478                 if (other->meta.job)
479                         job_add_to_run_queue(other->meta.job);
480
481         return 0;
482 }
483
484 void job_add_to_run_queue(Job *j) {
485         assert(j);
486         assert(j->installed);
487
488         if (j->in_run_queue)
489                 return;
490
491         LIST_PREPEND(Job, run_queue, j->manager->run_queue, j);
492         j->in_run_queue = true;
493 }
494
495 void job_add_to_dbus_queue(Job *j) {
496         assert(j);
497         assert(j->installed);
498
499         if (j->in_dbus_queue)
500                 return;
501
502         LIST_PREPEND(Job, dbus_queue, j->manager->dbus_job_queue, j);
503         j->in_dbus_queue = true;
504 }
505
506 char *job_dbus_path(Job *j) {
507         char *p;
508
509         assert(j);
510
511         if (asprintf(&p, "/org/freedesktop/systemd1/job/%lu", (unsigned long) j->id) < 0)
512                 return NULL;
513
514         return p;
515 }
516
517 static const char* const job_state_table[_JOB_STATE_MAX] = {
518         [JOB_WAITING] = "waiting",
519         [JOB_RUNNING] = "running"
520 };
521
522 DEFINE_STRING_TABLE_LOOKUP(job_state, JobState);
523
524 static const char* const job_type_table[_JOB_TYPE_MAX] = {
525         [JOB_START] = "start",
526         [JOB_VERIFY_ACTIVE] = "verify-active",
527         [JOB_STOP] = "stop",
528         [JOB_RELOAD] = "reload",
529         [JOB_RELOAD_OR_START] = "reload-or-start",
530         [JOB_RESTART] = "restart",
531         [JOB_TRY_RESTART] = "try-restart",
532 };
533
534 DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
535
536 static const char* const job_mode_table[_JOB_MODE_MAX] = {
537         [JOB_FAIL] = "fail",
538         [JOB_REPLACE] = "replace"
539 };
540
541 DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);