LCOV - code coverage report
Current view: top level - core - job.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 280 537 52.1 %
Date: 2015-07-29 18:47:03 Functions: 34 44 77.3 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       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 Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 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             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <errno.h>
      23             : 
      24             : #include "sd-id128.h"
      25             : #include "sd-messages.h"
      26             : #include "set.h"
      27             : #include "unit.h"
      28             : #include "macro.h"
      29             : #include "strv.h"
      30             : #include "log.h"
      31             : #include "dbus-job.h"
      32             : #include "special.h"
      33             : #include "async.h"
      34             : #include "virt.h"
      35             : #include "dbus.h"
      36             : #include "terminal-util.h"
      37             : 
      38         159 : Job* job_new_raw(Unit *unit) {
      39             :         Job *j;
      40             : 
      41             :         /* used for deserialization */
      42             : 
      43         159 :         assert(unit);
      44             : 
      45         159 :         j = new0(Job, 1);
      46         159 :         if (!j)
      47           0 :                 return NULL;
      48             : 
      49         159 :         j->manager = unit->manager;
      50         159 :         j->unit = unit;
      51         159 :         j->type = _JOB_TYPE_INVALID;
      52             : 
      53         159 :         return j;
      54             : }
      55             : 
      56         159 : Job* job_new(Unit *unit, JobType type) {
      57             :         Job *j;
      58             : 
      59         159 :         assert(type < _JOB_TYPE_MAX);
      60             : 
      61         159 :         j = job_new_raw(unit);
      62         159 :         if (!j)
      63           0 :                 return NULL;
      64             : 
      65         159 :         j->id = j->manager->current_job_id++;
      66         159 :         j->type = type;
      67             : 
      68             :         /* We don't link it here, that's what job_dependency() is for */
      69             : 
      70         159 :         return j;
      71             : }
      72             : 
      73         159 : void job_free(Job *j) {
      74         159 :         assert(j);
      75         159 :         assert(!j->installed);
      76         159 :         assert(!j->transaction_prev);
      77         159 :         assert(!j->transaction_next);
      78         159 :         assert(!j->subject_list);
      79         159 :         assert(!j->object_list);
      80             : 
      81         159 :         if (j->in_run_queue)
      82          21 :                 LIST_REMOVE(run_queue, j->manager->run_queue, j);
      83             : 
      84         159 :         if (j->in_dbus_queue)
      85           0 :                 LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j);
      86             : 
      87         159 :         sd_event_source_unref(j->timer_event_source);
      88             : 
      89         159 :         sd_bus_track_unref(j->clients);
      90         159 :         strv_free(j->deserialized_clients);
      91             : 
      92         159 :         free(j);
      93         159 : }
      94             : 
      95         105 : static void job_set_state(Job *j, JobState state) {
      96         105 :         assert(j);
      97         105 :         assert(state >= 0);
      98         105 :         assert(state < _JOB_STATE_MAX);
      99             : 
     100         105 :         if (j->state == state)
     101          21 :                 return;
     102             : 
     103          84 :         j->state = state;
     104             : 
     105          84 :         if (!j->installed)
     106           0 :                 return;
     107             : 
     108          84 :         if (j->state == JOB_RUNNING)
     109          42 :                 j->unit->manager->n_running_jobs++;
     110             :         else {
     111          42 :                 assert(j->state == JOB_WAITING);
     112          42 :                 assert(j->unit->manager->n_running_jobs > 0);
     113             : 
     114          42 :                 j->unit->manager->n_running_jobs--;
     115             : 
     116          42 :                 if (j->unit->manager->n_running_jobs <= 0)
     117          42 :                         j->unit->manager->jobs_in_progress_event_source = sd_event_source_unref(j->unit->manager->jobs_in_progress_event_source);
     118             :         }
     119             : }
     120             : 
     121          63 : void job_uninstall(Job *j) {
     122             :         Job **pj;
     123             : 
     124          63 :         assert(j->installed);
     125             : 
     126          63 :         job_set_state(j, JOB_WAITING);
     127             : 
     128          63 :         pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
     129          63 :         assert(*pj == j);
     130             : 
     131             :         /* Detach from next 'bigger' objects */
     132             : 
     133             :         /* daemon-reload should be transparent to job observers */
     134          63 :         if (j->manager->n_reloading <= 0)
     135          63 :                 bus_job_send_removed_signal(j);
     136             : 
     137          63 :         *pj = NULL;
     138             : 
     139          63 :         unit_add_to_gc_queue(j->unit);
     140             : 
     141          63 :         hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
     142          63 :         j->installed = false;
     143          63 : }
     144             : 
     145           0 : static bool job_type_allows_late_merge(JobType t) {
     146             :         /* Tells whether it is OK to merge a job of type 't' with an already
     147             :          * running job.
     148             :          * Reloads cannot be merged this way. Think of the sequence:
     149             :          * 1. Reload of a daemon is in progress; the daemon has already loaded
     150             :          *    its config file, but hasn't completed the reload operation yet.
     151             :          * 2. Edit foo's config file.
     152             :          * 3. Trigger another reload to have the daemon use the new config.
     153             :          * Should the second reload job be merged into the first one, the daemon
     154             :          * would not know about the new config.
     155             :          * JOB_RESTART jobs on the other hand can be merged, because they get
     156             :          * patched into JOB_START after stopping the unit. So if we see a
     157             :          * JOB_RESTART running, it means the unit hasn't stopped yet and at
     158             :          * this time the merge is still allowed. */
     159           0 :         return t != JOB_RELOAD;
     160             : }
     161             : 
     162          26 : static void job_merge_into_installed(Job *j, Job *other) {
     163          26 :         assert(j->installed);
     164          26 :         assert(j->unit == other->unit);
     165             : 
     166          26 :         if (j->type != JOB_NOP)
     167          26 :                 job_type_merge_and_collapse(&j->type, other->type, j->unit);
     168             :         else
     169           0 :                 assert(other->type == JOB_NOP);
     170             : 
     171          26 :         j->override = j->override || other->override;
     172          26 :         j->irreversible = j->irreversible || other->irreversible;
     173          26 :         j->ignore_order = j->ignore_order || other->ignore_order;
     174          26 : }
     175             : 
     176          89 : Job* job_install(Job *j) {
     177             :         Job **pj;
     178             :         Job *uj;
     179             : 
     180          89 :         assert(!j->installed);
     181          89 :         assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
     182          89 :         assert(j->state == JOB_WAITING);
     183             : 
     184          89 :         pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
     185          89 :         uj = *pj;
     186             : 
     187          89 :         if (uj) {
     188          28 :                 if (job_type_is_conflicting(uj->type, j->type))
     189           2 :                         job_finish_and_invalidate(uj, JOB_CANCELED, false);
     190             :                 else {
     191             :                         /* not conflicting, i.e. mergeable */
     192             : 
     193          26 :                         if (uj->state == JOB_WAITING ||
     194           0 :                             (job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) {
     195          26 :                                 job_merge_into_installed(uj, j);
     196          26 :                                 log_unit_debug(uj->unit,
     197             :                                                "Merged into installed job %s/%s as %u",
     198             :                                                uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
     199          26 :                                 return uj;
     200             :                         } else {
     201             :                                 /* already running and not safe to merge into */
     202             :                                 /* Patch uj to become a merged job and re-run it. */
     203             :                                 /* XXX It should be safer to queue j to run after uj finishes, but it is
     204             :                                  * not currently possible to have more than one installed job per unit. */
     205           0 :                                 job_merge_into_installed(uj, j);
     206           0 :                                 log_unit_debug(uj->unit,
     207             :                                                "Merged into running job, re-running: %s/%s as %u",
     208             :                                                uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
     209             : 
     210           0 :                                 job_set_state(uj, JOB_WAITING);
     211           0 :                                 return uj;
     212             :                         }
     213             :                 }
     214             :         }
     215             : 
     216             :         /* Install the job */
     217          63 :         *pj = j;
     218          63 :         j->installed = true;
     219             : 
     220          63 :         j->manager->n_installed_jobs ++;
     221          63 :         log_unit_debug(j->unit,
     222             :                        "Installed new job %s/%s as %u",
     223             :                        j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
     224          63 :         return j;
     225             : }
     226             : 
     227           0 : int job_install_deserialized(Job *j) {
     228             :         Job **pj;
     229             : 
     230           0 :         assert(!j->installed);
     231             : 
     232           0 :         if (j->type < 0 || j->type >= _JOB_TYPE_MAX_IN_TRANSACTION) {
     233           0 :                 log_debug("Invalid job type %s in deserialization.", strna(job_type_to_string(j->type)));
     234           0 :                 return -EINVAL;
     235             :         }
     236             : 
     237           0 :         pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
     238           0 :         if (*pj) {
     239           0 :                 log_unit_debug(j->unit, "Unit already has a job installed. Not installing deserialized job.");
     240           0 :                 return -EEXIST;
     241             :         }
     242             : 
     243           0 :         *pj = j;
     244           0 :         j->installed = true;
     245             : 
     246           0 :         if (j->state == JOB_RUNNING)
     247           0 :                 j->unit->manager->n_running_jobs++;
     248             : 
     249           0 :         log_unit_debug(j->unit,
     250             :                        "Reinstalled deserialized job %s/%s as %u",
     251             :                        j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
     252           0 :         return 0;
     253             : }
     254             : 
     255         266 : JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) {
     256             :         JobDependency *l;
     257             : 
     258         266 :         assert(object);
     259             : 
     260             :         /* Adds a new job link, which encodes that the 'subject' job
     261             :          * needs the 'object' job in some way. If 'subject' is NULL
     262             :          * this means the 'anchor' job (i.e. the one the user
     263             :          * explicitly asked for) is the requester. */
     264             : 
     265         266 :         if (!(l = new0(JobDependency, 1)))
     266           0 :                 return NULL;
     267             : 
     268         266 :         l->subject = subject;
     269         266 :         l->object = object;
     270         266 :         l->matters = matters;
     271         266 :         l->conflicts = conflicts;
     272             : 
     273         266 :         if (subject)
     274         266 :                 LIST_PREPEND(subject, subject->subject_list, l);
     275             : 
     276         266 :         LIST_PREPEND(object, object->object_list, l);
     277             : 
     278         266 :         return l;
     279             : }
     280             : 
     281         266 : void job_dependency_free(JobDependency *l) {
     282         266 :         assert(l);
     283             : 
     284         266 :         if (l->subject)
     285         266 :                 LIST_REMOVE(subject, l->subject->subject_list, l);
     286             : 
     287         266 :         LIST_REMOVE(object, l->object->object_list, l);
     288             : 
     289         266 :         free(l);
     290         266 : }
     291             : 
     292          72 : void job_dump(Job *j, FILE*f, const char *prefix) {
     293          72 :         assert(j);
     294          72 :         assert(f);
     295             : 
     296          72 :         if (!prefix)
     297           0 :                 prefix = "";
     298             : 
     299         216 :         fprintf(f,
     300             :                 "%s-> Job %u:\n"
     301             :                 "%s\tAction: %s -> %s\n"
     302             :                 "%s\tState: %s\n"
     303             :                 "%s\tForced: %s\n"
     304             :                 "%s\tIrreversible: %s\n",
     305             :                 prefix, j->id,
     306          72 :                 prefix, j->unit->id, job_type_to_string(j->type),
     307             :                 prefix, job_state_to_string(j->state),
     308          72 :                 prefix, yes_no(j->override),
     309          72 :                 prefix, yes_no(j->irreversible));
     310          72 : }
     311             : 
     312             : /*
     313             :  * Merging is commutative, so imagine the matrix as symmetric. We store only
     314             :  * its lower triangle to avoid duplication. We don't store the main diagonal,
     315             :  * because A merged with A is simply A.
     316             :  *
     317             :  * If the resulting type is collapsed immediately afterwards (to get rid of
     318             :  * the JOB_RELOAD_OR_START, which lies outside the lookup function's domain),
     319             :  * the following properties hold:
     320             :  *
     321             :  * Merging is associative! A merged with B, and then merged with C is the same
     322             :  * as A merged with the result of B merged with C.
     323             :  *
     324             :  * Mergeability is transitive! If A can be merged with B and B with C then
     325             :  * A also with C.
     326             :  *
     327             :  * Also, if A merged with B cannot be merged with C, then either A or B cannot
     328             :  * be merged with C either.
     329             :  */
     330             : static const JobType job_merging_table[] = {
     331             : /* What \ With       *  JOB_START         JOB_VERIFY_ACTIVE  JOB_STOP JOB_RELOAD */
     332             : /*********************************************************************************/
     333             : /*JOB_START          */
     334             : /*JOB_VERIFY_ACTIVE  */ JOB_START,
     335             : /*JOB_STOP           */ -1,                  -1,
     336             : /*JOB_RELOAD         */ JOB_RELOAD_OR_START, JOB_RELOAD,          -1,
     337             : /*JOB_RESTART        */ JOB_RESTART,         JOB_RESTART,         -1, JOB_RESTART,
     338             : };
     339             : 
     340        2049 : JobType job_type_lookup_merge(JobType a, JobType b) {
     341             :         assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX_MERGING * (_JOB_TYPE_MAX_MERGING - 1) / 2);
     342        2049 :         assert(a >= 0 && a < _JOB_TYPE_MAX_MERGING);
     343        2049 :         assert(b >= 0 && b < _JOB_TYPE_MAX_MERGING);
     344             : 
     345        2049 :         if (a == b)
     346         538 :                 return a;
     347             : 
     348        1511 :         if (a < b) {
     349         701 :                 JobType tmp = a;
     350         701 :                 a = b;
     351         701 :                 b = tmp;
     352             :         }
     353             : 
     354        1511 :         return job_merging_table[(a - 1) * a / 2 + b];
     355             : }
     356             : 
     357         377 : bool job_type_is_redundant(JobType a, UnitActiveState b) {
     358         377 :         switch (a) {
     359             : 
     360             :         case JOB_START:
     361             :                 return
     362         326 :                         b == UNIT_ACTIVE ||
     363             :                         b == UNIT_RELOADING;
     364             : 
     365             :         case JOB_STOP:
     366             :                 return
     367          51 :                         b == UNIT_INACTIVE ||
     368             :                         b == UNIT_FAILED;
     369             : 
     370             :         case JOB_VERIFY_ACTIVE:
     371             :                 return
     372           0 :                         b == UNIT_ACTIVE ||
     373             :                         b == UNIT_RELOADING;
     374             : 
     375             :         case JOB_RELOAD:
     376             :                 return
     377           0 :                         b == UNIT_RELOADING;
     378             : 
     379             :         case JOB_RESTART:
     380             :                 return
     381           0 :                         b == UNIT_ACTIVATING;
     382             : 
     383             :         case JOB_NOP:
     384           0 :                 return true;
     385             : 
     386             :         default:
     387           0 :                 assert_not_reached("Invalid job type");
     388             :         }
     389             : }
     390             : 
     391         596 : JobType job_type_collapse(JobType t, Unit *u) {
     392             :         UnitActiveState s;
     393             : 
     394         596 :         switch (t) {
     395             : 
     396             :         case JOB_TRY_RESTART:
     397           0 :                 s = unit_active_state(u);
     398           0 :                 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
     399           0 :                         return JOB_NOP;
     400             : 
     401           0 :                 return JOB_RESTART;
     402             : 
     403             :         case JOB_RELOAD_OR_START:
     404          68 :                 s = unit_active_state(u);
     405          68 :                 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
     406          34 :                         return JOB_START;
     407             : 
     408          34 :                 return JOB_RELOAD;
     409             : 
     410             :         default:
     411         528 :                 return t;
     412             :         }
     413             : }
     414             : 
     415         636 : int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) {
     416             :         JobType t;
     417             : 
     418         636 :         t = job_type_lookup_merge(*a, b);
     419         636 :         if (t < 0)
     420          56 :                 return -EEXIST;
     421             : 
     422         580 :         *a = job_type_collapse(t, u);
     423         580 :         return 0;
     424             : }
     425             : 
     426          55 : static bool job_is_runnable(Job *j) {
     427             :         Iterator i;
     428             :         Unit *other;
     429             : 
     430          55 :         assert(j);
     431          55 :         assert(j->installed);
     432             : 
     433             :         /* Checks whether there is any job running for the units this
     434             :          * job needs to be running after (in the case of a 'positive'
     435             :          * job type) or before (in the case of a 'negative' job
     436             :          * type. */
     437             : 
     438             :         /* Note that unit types have a say in what is runnable,
     439             :          * too. For example, if they return -EAGAIN from
     440             :          * unit_start() they can indicate they are not
     441             :          * runnable yet. */
     442             : 
     443             :         /* First check if there is an override */
     444          55 :         if (j->ignore_order)
     445           0 :                 return true;
     446             : 
     447          55 :         if (j->type == JOB_NOP)
     448           0 :                 return true;
     449             : 
     450          55 :         if (j->type == JOB_START ||
     451           0 :             j->type == JOB_VERIFY_ACTIVE ||
     452           0 :             j->type == JOB_RELOAD) {
     453             : 
     454             :                 /* Immediate result is that the job is or might be
     455             :                  * started. In this case let's wait for the
     456             :                  * dependencies, regardless whether they are
     457             :                  * starting or stopping something. */
     458             : 
     459         223 :                 SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i)
     460         126 :                         if (other->job)
     461          13 :                                 return false;
     462             :         }
     463             : 
     464             :         /* Also, if something else is being stopped and we should
     465             :          * change state after it, then let's wait. */
     466             : 
     467         174 :         SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
     468         120 :                 if (other->job &&
     469          60 :                     (other->job->type == JOB_STOP ||
     470          30 :                      other->job->type == JOB_RESTART))
     471           0 :                         return false;
     472             : 
     473             :         /* This means that for a service a and a service b where b
     474             :          * shall be started after a:
     475             :          *
     476             :          *  start a + start b → 1st step start a, 2nd step start b
     477             :          *  start a + stop b  → 1st step stop b,  2nd step start a
     478             :          *  stop a  + start b → 1st step stop a,  2nd step start b
     479             :          *  stop a  + stop b  → 1st step stop b,  2nd step stop a
     480             :          *
     481             :          *  This has the side effect that restarts are properly
     482             :          *  synchronized too. */
     483             : 
     484          42 :         return true;
     485             : }
     486             : 
     487           0 : static void job_change_type(Job *j, JobType newtype) {
     488           0 :         assert(j);
     489             : 
     490           0 :         log_unit_debug(j->unit,
     491             :                        "Converting job %s/%s -> %s/%s",
     492             :                        j->unit->id, job_type_to_string(j->type),
     493             :                        j->unit->id, job_type_to_string(newtype));
     494             : 
     495           0 :         j->type = newtype;
     496           0 : }
     497             : 
     498          42 : static int job_perform_on_unit(Job **j) {
     499             :         /* While we execute this operation the job might go away (for
     500             :          * example: because it finishes immediately or is replaced by a new,
     501             :          * conflicting job.) To make sure we don't access a freed job later on
     502             :          * we store the id here, so that we can verify the job is still
     503             :          * valid. */
     504          42 :         Manager *m  = (*j)->manager;
     505          42 :         Unit *u     = (*j)->unit;
     506          42 :         JobType t   = (*j)->type;
     507          42 :         uint32_t id = (*j)->id;
     508             :         int r;
     509             : 
     510          42 :         switch (t) {
     511             :                 case JOB_START:
     512          42 :                         r = unit_start(u);
     513          42 :                         break;
     514             : 
     515             :                 case JOB_RESTART:
     516           0 :                         t = JOB_STOP;
     517             :                 case JOB_STOP:
     518           0 :                         r = unit_stop(u);
     519           0 :                         break;
     520             : 
     521             :                 case JOB_RELOAD:
     522           0 :                         r = unit_reload(u);
     523           0 :                         break;
     524             : 
     525             :                 default:
     526           0 :                         assert_not_reached("Invalid job type");
     527             :         }
     528             : 
     529             :         /* Log if the job still exists and the start/stop/reload function
     530             :          * actually did something. */
     531          42 :         *j = manager_get_job(m, id);
     532          42 :         if (*j && r > 0)
     533           6 :                 unit_status_emit_starting_stopping_reloading(u, t);
     534             : 
     535          42 :         return r;
     536             : }
     537             : 
     538          55 : int job_run_and_invalidate(Job *j) {
     539             :         int r;
     540             : 
     541          55 :         assert(j);
     542          55 :         assert(j->installed);
     543          55 :         assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
     544          55 :         assert(j->in_run_queue);
     545             : 
     546          55 :         LIST_REMOVE(run_queue, j->manager->run_queue, j);
     547          55 :         j->in_run_queue = false;
     548             : 
     549          55 :         if (j->state != JOB_WAITING)
     550           0 :                 return 0;
     551             : 
     552          55 :         if (!job_is_runnable(j))
     553          13 :                 return -EAGAIN;
     554             : 
     555          42 :         job_set_state(j, JOB_RUNNING);
     556          42 :         job_add_to_dbus_queue(j);
     557             : 
     558             : 
     559          42 :         switch (j->type) {
     560             : 
     561             :                 case JOB_VERIFY_ACTIVE: {
     562           0 :                         UnitActiveState t = unit_active_state(j->unit);
     563           0 :                         if (UNIT_IS_ACTIVE_OR_RELOADING(t))
     564           0 :                                 r = -EALREADY;
     565           0 :                         else if (t == UNIT_ACTIVATING)
     566           0 :                                 r = -EAGAIN;
     567             :                         else
     568           0 :                                 r = -EBADR;
     569           0 :                         break;
     570             :                 }
     571             : 
     572             :                 case JOB_START:
     573             :                 case JOB_STOP:
     574             :                 case JOB_RESTART:
     575          42 :                         r = job_perform_on_unit(&j);
     576             : 
     577             :                         /* If the unit type does not support starting/stopping,
     578             :                          * then simply wait. */
     579          42 :                         if (r == -EBADR)
     580           0 :                                 r = 0;
     581          42 :                         break;
     582             : 
     583             :                 case JOB_RELOAD:
     584           0 :                         r = job_perform_on_unit(&j);
     585           0 :                         break;
     586             : 
     587             :                 case JOB_NOP:
     588           0 :                         r = -EALREADY;
     589           0 :                         break;
     590             : 
     591             :                 default:
     592           0 :                         assert_not_reached("Unknown job type");
     593             :         }
     594             : 
     595          42 :         if (j) {
     596           6 :                 if (r == -EALREADY)
     597           0 :                         r = job_finish_and_invalidate(j, JOB_DONE, true);
     598           6 :                 else if (r == -EBADR)
     599           0 :                         r = job_finish_and_invalidate(j, JOB_SKIPPED, true);
     600           6 :                 else if (r == -ENOEXEC)
     601           0 :                         r = job_finish_and_invalidate(j, JOB_INVALID, true);
     602           6 :                 else if (r == -EPROTO)
     603           0 :                         r = job_finish_and_invalidate(j, JOB_ASSERT, true);
     604           6 :                 else if (r == -EOPNOTSUPP)
     605           0 :                         r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true);
     606           6 :                 else if (r == -EAGAIN)
     607           0 :                         job_set_state(j, JOB_WAITING);
     608           6 :                 else if (r < 0)
     609           0 :                         r = job_finish_and_invalidate(j, JOB_FAILED, true);
     610             :         }
     611             : 
     612          42 :         return r;
     613             : }
     614             : 
     615          48 : _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) {
     616             :         const char *format;
     617             :         const UnitStatusMessageFormats *format_table;
     618             :         static const char *const generic_finished_start_job[_JOB_RESULT_MAX] = {
     619             :                 [JOB_DONE]        = "Started %s.",
     620             :                 [JOB_TIMEOUT]     = "Timed out starting %s.",
     621             :                 [JOB_FAILED]      = "Failed to start %s.",
     622             :                 [JOB_DEPENDENCY]  = "Dependency failed for %s.",
     623             :                 [JOB_ASSERT]      = "Assertion failed for %s.",
     624             :                 [JOB_UNSUPPORTED] = "Starting of %s not supported.",
     625             :         };
     626             :         static const char *const generic_finished_stop_job[_JOB_RESULT_MAX] = {
     627             :                 [JOB_DONE]        = "Stopped %s.",
     628             :                 [JOB_FAILED]      = "Stopped (with error) %s.",
     629             :                 [JOB_TIMEOUT]     = "Timed out stoppping %s.",
     630             :         };
     631             :         static const char *const generic_finished_reload_job[_JOB_RESULT_MAX] = {
     632             :                 [JOB_DONE]        = "Reloaded %s.",
     633             :                 [JOB_FAILED]      = "Reload failed for %s.",
     634             :                 [JOB_TIMEOUT]     = "Timed out reloading %s.",
     635             :         };
     636             :         /* When verify-active detects the unit is inactive, report it.
     637             :          * Most likely a DEPEND warning from a requisiting unit will
     638             :          * occur next and it's nice to see what was requisited. */
     639             :         static const char *const generic_finished_verify_active_job[_JOB_RESULT_MAX] = {
     640             :                 [JOB_SKIPPED]     = "%s is not active.",
     641             :         };
     642             : 
     643          48 :         assert(u);
     644          48 :         assert(t >= 0);
     645          48 :         assert(t < _JOB_TYPE_MAX);
     646             : 
     647          48 :         if (t == JOB_START || t == JOB_STOP || t == JOB_RESTART) {
     648          48 :                 format_table = &UNIT_VTABLE(u)->status_message_formats;
     649          48 :                 if (format_table) {
     650          48 :                         format = t == JOB_START ? format_table->finished_start_job[result] :
     651             :                                                   format_table->finished_stop_job[result];
     652          48 :                         if (format)
     653          36 :                                 return format;
     654             :                 }
     655             :         }
     656             : 
     657             :         /* Return generic strings */
     658          12 :         if (t == JOB_START)
     659          11 :                 return generic_finished_start_job[result];
     660           1 :         else if (t == JOB_STOP || t == JOB_RESTART)
     661           1 :                 return generic_finished_stop_job[result];
     662           0 :         else if (t == JOB_RELOAD)
     663           0 :                 return generic_finished_reload_job[result];
     664           0 :         else if (t == JOB_VERIFY_ACTIVE)
     665           0 :                 return generic_finished_verify_active_job[result];
     666             : 
     667           0 :         return NULL;
     668             : }
     669             : 
     670          48 : static void job_print_status_message(Unit *u, JobType t, JobResult result) {
     671             :         const char *format;
     672             :         static const char* const job_result_status_table[_JOB_RESULT_MAX] = {
     673             :                 [JOB_DONE]        = ANSI_GREEN_ON            "  OK  " ANSI_HIGHLIGHT_OFF,
     674             :                 [JOB_TIMEOUT]     = ANSI_HIGHLIGHT_RED_ON    " TIME " ANSI_HIGHLIGHT_OFF,
     675             :                 [JOB_FAILED]      = ANSI_HIGHLIGHT_RED_ON    "FAILED" ANSI_HIGHLIGHT_OFF,
     676             :                 [JOB_DEPENDENCY]  = ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF,
     677             :                 [JOB_SKIPPED]     = ANSI_HIGHLIGHT_ON        " INFO " ANSI_HIGHLIGHT_OFF,
     678             :                 [JOB_ASSERT]      = ANSI_HIGHLIGHT_YELLOW_ON "ASSERT" ANSI_HIGHLIGHT_OFF,
     679             :                 [JOB_UNSUPPORTED] = ANSI_HIGHLIGHT_YELLOW_ON "UNSUPP" ANSI_HIGHLIGHT_OFF,
     680             :         };
     681             : 
     682          48 :         assert(u);
     683          48 :         assert(t >= 0);
     684          48 :         assert(t < _JOB_TYPE_MAX);
     685             : 
     686          48 :         format = job_get_status_message_format(u, t, result);
     687          48 :         if (!format)
     688          12 :                 return;
     689             : 
     690          36 :         if (result != JOB_DONE)
     691           0 :                 manager_flip_auto_status(u->manager, true);
     692             : 
     693             :         DISABLE_WARNING_FORMAT_NONLITERAL;
     694          36 :         unit_status_printf(u, job_result_status_table[result], format);
     695             :         REENABLE_WARNING;
     696             : 
     697          36 :         if (t == JOB_START && result == JOB_FAILED) {
     698           0 :                 _cleanup_free_ char *quoted = shell_maybe_quote(u->id);
     699             : 
     700           0 :                 manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL,
     701             :                                       "See 'systemctl status %s' for details.", strna(quoted));
     702             :         }
     703             : }
     704             : 
     705          48 : static void job_log_status_message(Unit *u, JobType t, JobResult result) {
     706             :         const char *format;
     707             :         char buf[LINE_MAX];
     708             :         sd_id128_t mid;
     709             :         static const int job_result_log_level[_JOB_RESULT_MAX] = {
     710             :                 [JOB_DONE]        = LOG_INFO,
     711             :                 [JOB_CANCELED]    = LOG_INFO,
     712             :                 [JOB_TIMEOUT]     = LOG_ERR,
     713             :                 [JOB_FAILED]      = LOG_ERR,
     714             :                 [JOB_DEPENDENCY]  = LOG_WARNING,
     715             :                 [JOB_SKIPPED]     = LOG_NOTICE,
     716             :                 [JOB_INVALID]     = LOG_INFO,
     717             :                 [JOB_ASSERT]      = LOG_WARNING,
     718             :                 [JOB_UNSUPPORTED] = LOG_WARNING,
     719             :         };
     720             : 
     721          48 :         assert(u);
     722          48 :         assert(t >= 0);
     723          48 :         assert(t < _JOB_TYPE_MAX);
     724             : 
     725             :         /* Skip this if it goes to the console. since we already print
     726             :          * to the console anyway... */
     727             : 
     728          48 :         if (log_on_console())
     729          96 :                 return;
     730             : 
     731           0 :         format = job_get_status_message_format(u, t, result);
     732           0 :         if (!format)
     733           0 :                 return;
     734             : 
     735             :         DISABLE_WARNING_FORMAT_NONLITERAL;
     736           0 :         snprintf(buf, sizeof(buf), format, unit_description(u));
     737             :         REENABLE_WARNING;
     738             : 
     739           0 :         if (t == JOB_START)
     740           0 :                 mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED;
     741           0 :         else if (t == JOB_STOP || t == JOB_RESTART)
     742           0 :                 mid = SD_MESSAGE_UNIT_STOPPED;
     743           0 :         else if (t == JOB_RELOAD)
     744           0 :                 mid = SD_MESSAGE_UNIT_RELOADED;
     745             :         else {
     746           0 :                 log_struct(job_result_log_level[result],
     747             :                            LOG_UNIT_ID(u),
     748             :                            LOG_MESSAGE("%s", buf),
     749             :                            "RESULT=%s", job_result_to_string(result),
     750             :                            NULL);
     751           0 :                 return;
     752             :         }
     753             : 
     754           0 :         log_struct(job_result_log_level[result],
     755             :                    LOG_MESSAGE_ID(mid),
     756             :                    LOG_UNIT_ID(u),
     757             :                    LOG_MESSAGE("%s", buf),
     758             :                    "RESULT=%s", job_result_to_string(result),
     759             :                    NULL);
     760             : }
     761             : 
     762          48 : static void job_emit_status_message(Unit *u, JobType t, JobResult result) {
     763             : 
     764             :         /* No message if the job did not actually do anything due to failed condition. */
     765          48 :         if (t == JOB_START && result == JOB_DONE && !u->condition_result)
     766           0 :                 return;
     767             : 
     768          48 :         job_log_status_message(u, t, result);
     769             : 
     770             :         /* Reload status messages have traditionally not been printed to console. */
     771          48 :         if (t != JOB_RELOAD)
     772          48 :                 job_print_status_message(u, t, result);
     773             : }
     774             : 
     775           0 : static void job_fail_dependencies(Unit *u, UnitDependency d) {
     776             :         Unit *other;
     777             :         Iterator i;
     778             : 
     779           0 :         assert(u);
     780             : 
     781           0 :         SET_FOREACH(other, u->dependencies[d], i) {
     782           0 :                 Job *j = other->job;
     783             : 
     784           0 :                 if (!j)
     785           0 :                         continue;
     786           0 :                 if (!IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE))
     787           0 :                         continue;
     788             : 
     789           0 :                 job_finish_and_invalidate(j, JOB_DEPENDENCY, true);
     790             :         }
     791           0 : }
     792             : 
     793          48 : int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
     794             :         Unit *u;
     795             :         Unit *other;
     796             :         JobType t;
     797             :         Iterator i;
     798             : 
     799          48 :         assert(j);
     800          48 :         assert(j->installed);
     801          48 :         assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
     802             : 
     803          48 :         u = j->unit;
     804          48 :         t = j->type;
     805             : 
     806          48 :         j->result = result;
     807             : 
     808          48 :         log_unit_debug(u, "Job %s/%s finished, result=%s", u->id, job_type_to_string(t), job_result_to_string(result));
     809             : 
     810          48 :         job_emit_status_message(u, t, result);
     811             : 
     812          48 :         job_add_to_dbus_queue(j);
     813             : 
     814             :         /* Patch restart jobs so that they become normal start jobs */
     815          48 :         if (result == JOB_DONE && t == JOB_RESTART) {
     816             : 
     817           0 :                 job_change_type(j, JOB_START);
     818           0 :                 job_set_state(j, JOB_WAITING);
     819             : 
     820           0 :                 job_add_to_run_queue(j);
     821             : 
     822           0 :                 goto finish;
     823             :         }
     824             : 
     825          48 :         if (result == JOB_FAILED || result == JOB_INVALID)
     826           0 :                 j->manager->n_failed_jobs ++;
     827             : 
     828          48 :         job_uninstall(j);
     829          48 :         job_free(j);
     830             : 
     831             :         /* Fail depending jobs on failure */
     832          48 :         if (result != JOB_DONE && recursive) {
     833           0 :                 if (IN_SET(t, JOB_START, JOB_VERIFY_ACTIVE)) {
     834           0 :                         job_fail_dependencies(u, UNIT_REQUIRED_BY);
     835           0 :                         job_fail_dependencies(u, UNIT_REQUISITE_OF);
     836           0 :                         job_fail_dependencies(u, UNIT_BOUND_BY);
     837           0 :                         job_fail_dependencies(u, UNIT_REQUIRED_BY_OVERRIDABLE);
     838           0 :                         job_fail_dependencies(u, UNIT_REQUISITE_OF_OVERRIDABLE);
     839           0 :                 } else if (t == JOB_STOP)
     840           0 :                         job_fail_dependencies(u, UNIT_CONFLICTED_BY);
     841             :         }
     842             : 
     843             :         /* Trigger OnFailure dependencies that are not generated by
     844             :          * the unit itself. We don't treat JOB_CANCELED as failure in
     845             :          * this context. And JOB_FAILURE is already handled by the
     846             :          * unit itself. */
     847          48 :         if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) {
     848           0 :                 log_struct(LOG_NOTICE,
     849             :                            "JOB_TYPE=%s", job_type_to_string(t),
     850             :                            "JOB_RESULT=%s", job_result_to_string(result),
     851             :                            LOG_UNIT_ID(u),
     852             :                            LOG_UNIT_MESSAGE(u, "Job %s/%s failed with result '%s'.",
     853             :                                             u->id,
     854             :                                             job_type_to_string(t),
     855             :                                             job_result_to_string(result)),
     856             :                            NULL);
     857             : 
     858           0 :                 unit_start_on_failure(u);
     859             :         }
     860             : 
     861          48 :         unit_trigger_notify(u);
     862             : 
     863             : finish:
     864             :         /* Try to start the next jobs that can be started */
     865         192 :         SET_FOREACH(other, u->dependencies[UNIT_AFTER], i)
     866          96 :                 if (other->job)
     867          12 :                         job_add_to_run_queue(other->job);
     868         208 :         SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i)
     869         112 :                 if (other->job)
     870          34 :                         job_add_to_run_queue(other->job);
     871             : 
     872          48 :         manager_check_finished(u->manager);
     873             : 
     874          48 :         return 0;
     875             : }
     876             : 
     877           0 : static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *userdata) {
     878           0 :         Job *j = userdata;
     879             :         Unit *u;
     880             : 
     881           0 :         assert(j);
     882           0 :         assert(s == j->timer_event_source);
     883             : 
     884           0 :         log_unit_warning(j->unit, "Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
     885             : 
     886           0 :         u = j->unit;
     887           0 :         job_finish_and_invalidate(j, JOB_TIMEOUT, true);
     888             : 
     889           0 :         failure_action(u->manager, u->job_timeout_action, u->job_timeout_reboot_arg);
     890             : 
     891           0 :         return 0;
     892             : }
     893             : 
     894          89 : int job_start_timer(Job *j) {
     895             :         int r;
     896             : 
     897          89 :         if (j->timer_event_source)
     898           0 :                 return 0;
     899             : 
     900          89 :         j->begin_usec = now(CLOCK_MONOTONIC);
     901             : 
     902          89 :         if (j->unit->job_timeout <= 0)
     903          89 :                 return 0;
     904             : 
     905           0 :         r = sd_event_add_time(
     906           0 :                         j->manager->event,
     907             :                         &j->timer_event_source,
     908             :                         CLOCK_MONOTONIC,
     909           0 :                         j->begin_usec + j->unit->job_timeout, 0,
     910             :                         job_dispatch_timer, j);
     911           0 :         if (r < 0)
     912           0 :                 return r;
     913             : 
     914           0 :         (void) sd_event_source_set_description(j->timer_event_source, "job-start");
     915             : 
     916           0 :         return 0;
     917             : }
     918             : 
     919         135 : void job_add_to_run_queue(Job *j) {
     920         135 :         assert(j);
     921         135 :         assert(j->installed);
     922             : 
     923         135 :         if (j->in_run_queue)
     924          59 :                 return;
     925             : 
     926          76 :         if (!j->manager->run_queue)
     927          16 :                 sd_event_source_set_enabled(j->manager->run_queue_event_source, SD_EVENT_ONESHOT);
     928             : 
     929          76 :         LIST_PREPEND(run_queue, j->manager->run_queue, j);
     930          76 :         j->in_run_queue = true;
     931             : }
     932             : 
     933         179 : void job_add_to_dbus_queue(Job *j) {
     934         179 :         assert(j);
     935         179 :         assert(j->installed);
     936             : 
     937         179 :         if (j->in_dbus_queue)
     938         116 :                 return;
     939             : 
     940             :         /* We don't check if anybody is subscribed here, since this
     941             :          * job might just have been created and not yet assigned to a
     942             :          * connection/client. */
     943             : 
     944          63 :         LIST_PREPEND(dbus_queue, j->manager->dbus_job_queue, j);
     945          63 :         j->in_dbus_queue = true;
     946             : }
     947             : 
     948           0 : char *job_dbus_path(Job *j) {
     949             :         char *p;
     950             : 
     951           0 :         assert(j);
     952             : 
     953           0 :         if (asprintf(&p, "/org/freedesktop/systemd1/job/%"PRIu32, j->id) < 0)
     954           0 :                 return NULL;
     955             : 
     956           0 :         return p;
     957             : }
     958             : 
     959           0 : int job_serialize(Job *j, FILE *f, FDSet *fds) {
     960           0 :         fprintf(f, "job-id=%u\n", j->id);
     961           0 :         fprintf(f, "job-type=%s\n", job_type_to_string(j->type));
     962           0 :         fprintf(f, "job-state=%s\n", job_state_to_string(j->state));
     963           0 :         fprintf(f, "job-override=%s\n", yes_no(j->override));
     964           0 :         fprintf(f, "job-irreversible=%s\n", yes_no(j->irreversible));
     965           0 :         fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal));
     966           0 :         fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order));
     967             : 
     968           0 :         if (j->begin_usec > 0)
     969           0 :                 fprintf(f, "job-begin="USEC_FMT"\n", j->begin_usec);
     970             : 
     971           0 :         bus_track_serialize(j->clients, f);
     972             : 
     973             :         /* End marker */
     974           0 :         fputc('\n', f);
     975           0 :         return 0;
     976             : }
     977             : 
     978           0 : int job_deserialize(Job *j, FILE *f, FDSet *fds) {
     979           0 :         assert(j);
     980             : 
     981             :         for (;;) {
     982             :                 char line[LINE_MAX], *l, *v;
     983             :                 size_t k;
     984             : 
     985           0 :                 if (!fgets(line, sizeof(line), f)) {
     986           0 :                         if (feof(f))
     987           0 :                                 return 0;
     988           0 :                         return -errno;
     989             :                 }
     990             : 
     991           0 :                 char_array_0(line);
     992           0 :                 l = strstrip(line);
     993             : 
     994             :                 /* End marker */
     995           0 :                 if (l[0] == 0)
     996           0 :                         return 0;
     997             : 
     998           0 :                 k = strcspn(l, "=");
     999             : 
    1000           0 :                 if (l[k] == '=') {
    1001           0 :                         l[k] = 0;
    1002           0 :                         v = l+k+1;
    1003             :                 } else
    1004           0 :                         v = l+k;
    1005             : 
    1006           0 :                 if (streq(l, "job-id")) {
    1007             : 
    1008           0 :                         if (safe_atou32(v, &j->id) < 0)
    1009           0 :                                 log_debug("Failed to parse job id value %s", v);
    1010             : 
    1011           0 :                 } else if (streq(l, "job-type")) {
    1012             :                         JobType t;
    1013             : 
    1014           0 :                         t = job_type_from_string(v);
    1015           0 :                         if (t < 0)
    1016           0 :                                 log_debug("Failed to parse job type %s", v);
    1017           0 :                         else if (t >= _JOB_TYPE_MAX_IN_TRANSACTION)
    1018           0 :                                 log_debug("Cannot deserialize job of type %s", v);
    1019             :                         else
    1020           0 :                                 j->type = t;
    1021             : 
    1022           0 :                 } else if (streq(l, "job-state")) {
    1023             :                         JobState s;
    1024             : 
    1025           0 :                         s = job_state_from_string(v);
    1026           0 :                         if (s < 0)
    1027           0 :                                 log_debug("Failed to parse job state %s", v);
    1028             :                         else
    1029           0 :                                 job_set_state(j, s);
    1030             : 
    1031           0 :                 } else if (streq(l, "job-override")) {
    1032             :                         int b;
    1033             : 
    1034           0 :                         b = parse_boolean(v);
    1035           0 :                         if (b < 0)
    1036           0 :                                 log_debug("Failed to parse job override flag %s", v);
    1037             :                         else
    1038           0 :                                 j->override = j->override || b;
    1039             : 
    1040           0 :                 } else if (streq(l, "job-irreversible")) {
    1041             :                         int b;
    1042             : 
    1043           0 :                         b = parse_boolean(v);
    1044           0 :                         if (b < 0)
    1045           0 :                                 log_debug("Failed to parse job irreversible flag %s", v);
    1046             :                         else
    1047           0 :                                 j->irreversible = j->irreversible || b;
    1048             : 
    1049           0 :                 } else if (streq(l, "job-sent-dbus-new-signal")) {
    1050             :                         int b;
    1051             : 
    1052           0 :                         b = parse_boolean(v);
    1053           0 :                         if (b < 0)
    1054           0 :                                 log_debug("Failed to parse job sent_dbus_new_signal flag %s", v);
    1055             :                         else
    1056           0 :                                 j->sent_dbus_new_signal = j->sent_dbus_new_signal || b;
    1057             : 
    1058           0 :                 } else if (streq(l, "job-ignore-order")) {
    1059             :                         int b;
    1060             : 
    1061           0 :                         b = parse_boolean(v);
    1062           0 :                         if (b < 0)
    1063           0 :                                 log_debug("Failed to parse job ignore_order flag %s", v);
    1064             :                         else
    1065           0 :                                 j->ignore_order = j->ignore_order || b;
    1066             : 
    1067           0 :                 } else if (streq(l, "job-begin")) {
    1068             :                         unsigned long long ull;
    1069             : 
    1070           0 :                         if (sscanf(v, "%llu", &ull) != 1)
    1071           0 :                                 log_debug("Failed to parse job-begin value %s", v);
    1072             :                         else
    1073           0 :                                 j->begin_usec = ull;
    1074             : 
    1075           0 :                 } else if (streq(l, "subscribed")) {
    1076             : 
    1077           0 :                         if (strv_extend(&j->deserialized_clients, v) < 0)
    1078           0 :                                 return log_oom();
    1079             :                 }
    1080           0 :         }
    1081             : }
    1082             : 
    1083           0 : int job_coldplug(Job *j) {
    1084             :         int r;
    1085             : 
    1086           0 :         assert(j);
    1087             : 
    1088             :         /* After deserialization is complete and the bus connection
    1089             :          * set up again, let's start watching our subscribers again */
    1090           0 :         r = bus_track_coldplug(j->manager, &j->clients, &j->deserialized_clients);
    1091           0 :         if (r < 0)
    1092           0 :                 return r;
    1093             : 
    1094           0 :         if (j->state == JOB_WAITING)
    1095           0 :                 job_add_to_run_queue(j);
    1096             : 
    1097           0 :         if (j->begin_usec == 0 || j->unit->job_timeout == 0)
    1098           0 :                 return 0;
    1099             : 
    1100           0 :         if (j->timer_event_source)
    1101           0 :                 j->timer_event_source = sd_event_source_unref(j->timer_event_source);
    1102             : 
    1103           0 :         r = sd_event_add_time(
    1104           0 :                         j->manager->event,
    1105             :                         &j->timer_event_source,
    1106             :                         CLOCK_MONOTONIC,
    1107           0 :                         j->begin_usec + j->unit->job_timeout, 0,
    1108             :                         job_dispatch_timer, j);
    1109           0 :         if (r < 0)
    1110           0 :                 log_debug_errno(r, "Failed to restart timeout for job: %m");
    1111             : 
    1112           0 :         (void) sd_event_source_set_description(j->timer_event_source, "job-timeout");
    1113             : 
    1114           0 :         return r;
    1115             : }
    1116             : 
    1117          89 : void job_shutdown_magic(Job *j) {
    1118          89 :         assert(j);
    1119             : 
    1120             :         /* The shutdown target gets some special treatment here: we
    1121             :          * tell the kernel to begin with flushing its disk caches, to
    1122             :          * optimize shutdown time a bit. Ideally we wouldn't hardcode
    1123             :          * this magic into PID 1. However all other processes aren't
    1124             :          * options either since they'd exit much sooner than PID 1 and
    1125             :          * asynchronous sync() would cause their exit to be
    1126             :          * delayed. */
    1127             : 
    1128          89 :         if (j->type != JOB_START)
    1129           3 :                 return;
    1130             : 
    1131          86 :         if (j->unit->manager->running_as != MANAGER_SYSTEM)
    1132          86 :                 return;
    1133             : 
    1134           0 :         if (!unit_has_name(j->unit, SPECIAL_SHUTDOWN_TARGET))
    1135           0 :                 return;
    1136             : 
    1137             :         /* In case messages on console has been disabled on boot */
    1138           0 :         j->unit->manager->no_console_output = false;
    1139             : 
    1140           0 :         if (detect_container(NULL) > 0)
    1141           0 :                 return;
    1142             : 
    1143           0 :         asynchronous_sync();
    1144             : }
    1145             : 
    1146           0 : int job_get_timeout(Job *j, uint64_t *timeout) {
    1147           0 :         Unit *u = j->unit;
    1148           0 :         uint64_t x = -1, y = -1;
    1149           0 :         int r = 0, q = 0;
    1150             : 
    1151           0 :         assert(u);
    1152             : 
    1153           0 :         if (j->timer_event_source) {
    1154           0 :                 r = sd_event_source_get_time(j->timer_event_source, &x);
    1155           0 :                 if (r < 0)
    1156           0 :                         return r;
    1157           0 :                 r = 1;
    1158             :         }
    1159             : 
    1160           0 :         if (UNIT_VTABLE(u)->get_timeout) {
    1161           0 :                 q = UNIT_VTABLE(u)->get_timeout(u, &y);
    1162           0 :                 if (q < 0)
    1163           0 :                         return q;
    1164             :         }
    1165             : 
    1166           0 :         if (r == 0 && q == 0)
    1167           0 :                 return 0;
    1168             : 
    1169           0 :         *timeout = MIN(x, y);
    1170             : 
    1171           0 :         return 1;
    1172             : }
    1173             : 
    1174             : static const char* const job_state_table[_JOB_STATE_MAX] = {
    1175             :         [JOB_WAITING] = "waiting",
    1176             :         [JOB_RUNNING] = "running"
    1177             : };
    1178             : 
    1179          80 : DEFINE_STRING_TABLE_LOOKUP(job_state, JobState);
    1180             : 
    1181             : static const char* const job_type_table[_JOB_TYPE_MAX] = {
    1182             :         [JOB_START] = "start",
    1183             :         [JOB_VERIFY_ACTIVE] = "verify-active",
    1184             :         [JOB_STOP] = "stop",
    1185             :         [JOB_RELOAD] = "reload",
    1186             :         [JOB_RELOAD_OR_START] = "reload-or-start",
    1187             :         [JOB_RESTART] = "restart",
    1188             :         [JOB_TRY_RESTART] = "try-restart",
    1189             :         [JOB_NOP] = "nop",
    1190             : };
    1191             : 
    1192         934 : DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
    1193             : 
    1194             : static const char* const job_mode_table[_JOB_MODE_MAX] = {
    1195             :         [JOB_FAIL] = "fail",
    1196             :         [JOB_REPLACE] = "replace",
    1197             :         [JOB_REPLACE_IRREVERSIBLY] = "replace-irreversibly",
    1198             :         [JOB_ISOLATE] = "isolate",
    1199             :         [JOB_FLUSH] = "flush",
    1200             :         [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
    1201             :         [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements",
    1202             : };
    1203             : 
    1204         339 : DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);
    1205             : 
    1206             : static const char* const job_result_table[_JOB_RESULT_MAX] = {
    1207             :         [JOB_DONE] = "done",
    1208             :         [JOB_CANCELED] = "canceled",
    1209             :         [JOB_TIMEOUT] = "timeout",
    1210             :         [JOB_FAILED] = "failed",
    1211             :         [JOB_DEPENDENCY] = "dependency",
    1212             :         [JOB_SKIPPED] = "skipped",
    1213             :         [JOB_INVALID] = "invalid",
    1214             :         [JOB_ASSERT] = "assert",
    1215             :         [JOB_UNSUPPORTED] = "unsupported",
    1216             : };
    1217             : 
    1218          70 : DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);

Generated by: LCOV version 1.11