chiark / gitweb /
6e04683fdd8bb7f1f501aee4de0261fda572686c
[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, true);
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_type_is_redundant(JobType a, UnitActiveState b) {
269         switch (a) {
270
271         case JOB_START:
272                 return
273                         b == UNIT_ACTIVE ||
274                         b == UNIT_ACTIVE_RELOADING;
275
276         case JOB_STOP:
277                 return
278                         b == UNIT_INACTIVE;
279
280         case JOB_VERIFY_ACTIVE:
281                 return
282                         b == UNIT_ACTIVE ||
283                         b == UNIT_ACTIVE_RELOADING;
284
285         case JOB_RELOAD:
286                 return
287                         b == UNIT_ACTIVE_RELOADING;
288
289         case JOB_RELOAD_OR_START:
290                 return
291                         b == UNIT_ACTIVATING ||
292                         b == UNIT_ACTIVE_RELOADING;
293
294         case JOB_RESTART:
295                 return
296                         b == UNIT_ACTIVATING;
297
298         case JOB_TRY_RESTART:
299                 return
300                         b == UNIT_ACTIVATING;
301
302         default:
303                 assert_not_reached("Invalid job type");
304         }
305 }
306
307 bool job_is_runnable(Job *j) {
308         Iterator i;
309         Unit *other;
310
311         assert(j);
312         assert(j->installed);
313
314         /* Checks whether there is any job running for the units this
315          * job needs to be running after (in the case of a 'positive'
316          * job type) or before (in the case of a 'negative' job type
317          * . */
318
319         if (j->type == JOB_START ||
320             j->type == JOB_VERIFY_ACTIVE ||
321             j->type == JOB_RELOAD ||
322             j->type == JOB_RELOAD_OR_START) {
323
324                 /* Immediate result is that the job is or might be
325                  * started. In this case lets wait for the
326                  * dependencies, regardless whether they are
327                  * starting or stopping something. */
328
329                 SET_FOREACH(other, j->unit->meta.dependencies[UNIT_AFTER], i)
330                         if (other->meta.job)
331                                 return false;
332         }
333
334         /* Also, if something else is being stopped and we should
335          * change state after it, then lets wait. */
336
337         SET_FOREACH(other, j->unit->meta.dependencies[UNIT_BEFORE], i)
338                 if (other->meta.job &&
339                     (other->meta.job->type == JOB_STOP ||
340                      other->meta.job->type == JOB_RESTART ||
341                      other->meta.job->type == JOB_TRY_RESTART))
342                         return false;
343
344         /* This means that for a service a and a service b where b
345          * shall be started after a:
346          *
347          *  start a + start b → 1st step start a, 2nd step start b
348          *  start a + stop b  → 1st step stop b,  2nd step start a
349          *  stop a  + start b → 1st step stop a,  2nd step start b
350          *  stop a  + stop b  → 1st step stop b,  2nd step stop a
351          *
352          *  This has the side effect that restarts are properly
353          *  synchronized too. */
354
355         return true;
356 }
357
358 int job_run_and_invalidate(Job *j) {
359         int r;
360
361         assert(j);
362         assert(j->installed);
363
364         if (j->in_run_queue) {
365                 LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
366                 j->in_run_queue = false;
367         }
368
369         if (j->state != JOB_WAITING)
370                 return 0;
371
372         if (!job_is_runnable(j))
373                 return -EAGAIN;
374
375         j->state = JOB_RUNNING;
376         job_add_to_dbus_queue(j);
377
378         switch (j->type) {
379
380                 case JOB_START:
381                         r = unit_start(j->unit);
382                         if (r == -EBADR)
383                                 r = 0;
384                         break;
385
386                 case JOB_VERIFY_ACTIVE: {
387                         UnitActiveState t = unit_active_state(j->unit);
388                         if (UNIT_IS_ACTIVE_OR_RELOADING(t))
389                                 r = -EALREADY;
390                         else if (t == UNIT_ACTIVATING)
391                                 r = -EAGAIN;
392                         else
393                                 r = -ENOEXEC;
394                         break;
395                 }
396
397                 case JOB_STOP:
398                         r = unit_stop(j->unit);
399                         break;
400
401                 case JOB_RELOAD:
402                         r = unit_reload(j->unit);
403                         break;
404
405                 case JOB_RELOAD_OR_START:
406                         if (unit_active_state(j->unit) == UNIT_ACTIVE)
407                                 r = unit_reload(j->unit);
408                         else
409                                 r = unit_start(j->unit);
410                         break;
411
412                 case JOB_RESTART: {
413                         UnitActiveState t = unit_active_state(j->unit);
414                         if (t == UNIT_INACTIVE || t == UNIT_ACTIVATING) {
415                                 j->type = JOB_START;
416                                 r = unit_start(j->unit);
417                         } else
418                                 r = unit_stop(j->unit);
419                         break;
420                 }
421
422                 case JOB_TRY_RESTART: {
423                         UnitActiveState t = unit_active_state(j->unit);
424                         if (t == UNIT_INACTIVE || t == UNIT_DEACTIVATING)
425                                 r = -ENOEXEC;
426                         else if (t == UNIT_ACTIVATING) {
427                                 j->type = JOB_START;
428                                 r = unit_start(j->unit);
429                         } else
430                                 r = unit_stop(j->unit);
431                         break;
432                 }
433
434                 default:
435                         assert_not_reached("Unknown job type");
436         }
437
438         if (r == -EALREADY)
439                 r = job_finish_and_invalidate(j, true);
440         else if (r == -EAGAIN) {
441                 j->state = JOB_WAITING;
442                 return -EAGAIN;
443         } else if (r < 0)
444                 r = job_finish_and_invalidate(j, false);
445
446         return r;
447 }
448
449 int job_finish_and_invalidate(Job *j, bool success) {
450         Unit *u;
451         Unit *other;
452         JobType t;
453         Iterator i;
454
455         assert(j);
456         assert(j->installed);
457
458         log_debug("Job %s/%s finished, success=%s", unit_id(j->unit), job_type_to_string(j->type), yes_no(success));
459         job_add_to_dbus_queue(j);
460
461         /* Patch restart jobs so that they become normal start jobs */
462         if (success && (j->type == JOB_RESTART || j->type == JOB_TRY_RESTART)) {
463
464                 log_debug("Converting job %s/%s → %s/%s",
465                           unit_id(j->unit), job_type_to_string(j->type),
466                           unit_id(j->unit), job_type_to_string(JOB_START));
467
468                 j->state = JOB_RUNNING;
469                 j->type = JOB_START;
470
471                 job_add_to_run_queue(j);
472                 return 0;
473         }
474
475         u = j->unit;
476         t = j->type;
477         job_free(j);
478
479         /* Fail depending jobs on failure */
480         if (!success) {
481
482                 if (t == JOB_START ||
483                     t == JOB_VERIFY_ACTIVE ||
484                     t == JOB_RELOAD_OR_START) {
485
486                         SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i)
487                                 if (other->meta.job &&
488                                     (other->meta.type == JOB_START ||
489                                      other->meta.type == JOB_VERIFY_ACTIVE ||
490                                      other->meta.type == JOB_RELOAD_OR_START))
491                                         job_finish_and_invalidate(other->meta.job, false);
492
493                         SET_FOREACH(other, u->meta.dependencies[UNIT_SOFT_REQUIRED_BY], i)
494                                 if (other->meta.job &&
495                                     !other->meta.job->forced &&
496                                     (other->meta.type == JOB_START ||
497                                      other->meta.type == JOB_VERIFY_ACTIVE ||
498                                      other->meta.type == JOB_RELOAD_OR_START))
499                                         job_finish_and_invalidate(other->meta.job, false);
500
501                 } else if (t == JOB_STOP) {
502
503                         SET_FOREACH(other, u->meta.dependencies[UNIT_CONFLICTS], i)
504                                 if (other->meta.job &&
505                                     (t == JOB_START ||
506                                      t == JOB_VERIFY_ACTIVE ||
507                                      t == JOB_RELOAD_OR_START))
508                                         job_finish_and_invalidate(other->meta.job, false);
509                 }
510         }
511
512         /* Try to start the next jobs that can be started */
513         SET_FOREACH(other, u->meta.dependencies[UNIT_AFTER], i)
514                 if (other->meta.job)
515                         job_add_to_run_queue(other->meta.job);
516         SET_FOREACH(other, u->meta.dependencies[UNIT_BEFORE], i)
517                 if (other->meta.job)
518                         job_add_to_run_queue(other->meta.job);
519
520         return 0;
521 }
522
523 void job_add_to_run_queue(Job *j) {
524         assert(j);
525         assert(j->installed);
526
527         if (j->in_run_queue)
528                 return;
529
530         LIST_PREPEND(Job, run_queue, j->manager->run_queue, j);
531         j->in_run_queue = true;
532 }
533
534 void job_add_to_dbus_queue(Job *j) {
535         assert(j);
536         assert(j->installed);
537
538         if (j->in_dbus_queue)
539                 return;
540
541         LIST_PREPEND(Job, dbus_queue, j->manager->dbus_job_queue, j);
542         j->in_dbus_queue = true;
543 }
544
545 char *job_dbus_path(Job *j) {
546         char *p;
547
548         assert(j);
549
550         if (asprintf(&p, "/org/freedesktop/systemd1/job/%lu", (unsigned long) j->id) < 0)
551                 return NULL;
552
553         return p;
554 }
555
556 static const char* const job_state_table[_JOB_STATE_MAX] = {
557         [JOB_WAITING] = "waiting",
558         [JOB_RUNNING] = "running"
559 };
560
561 DEFINE_STRING_TABLE_LOOKUP(job_state, JobState);
562
563 static const char* const job_type_table[_JOB_TYPE_MAX] = {
564         [JOB_START] = "start",
565         [JOB_VERIFY_ACTIVE] = "verify-active",
566         [JOB_STOP] = "stop",
567         [JOB_RELOAD] = "reload",
568         [JOB_RELOAD_OR_START] = "reload-or-start",
569         [JOB_RESTART] = "restart",
570         [JOB_TRY_RESTART] = "try-restart",
571 };
572
573 DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
574
575 static const char* const job_mode_table[_JOB_MODE_MAX] = {
576         [JOB_FAIL] = "fail",
577         [JOB_REPLACE] = "replace"
578 };
579
580 DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);