LCOV - code coverage report
Current view: top level - core - job.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 369 783 47.1 %
Date: 2019-08-23 13:36:53 Functions: 42 57 73.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 286 811 35.3 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <errno.h>
       4                 :            : 
       5                 :            : #include "sd-id128.h"
       6                 :            : #include "sd-messages.h"
       7                 :            : 
       8                 :            : #include "alloc-util.h"
       9                 :            : #include "async.h"
      10                 :            : #include "cgroup.h"
      11                 :            : #include "dbus-job.h"
      12                 :            : #include "dbus.h"
      13                 :            : #include "escape.h"
      14                 :            : #include "fileio.h"
      15                 :            : #include "job.h"
      16                 :            : #include "log.h"
      17                 :            : #include "macro.h"
      18                 :            : #include "parse-util.h"
      19                 :            : #include "serialize.h"
      20                 :            : #include "set.h"
      21                 :            : #include "sort-util.h"
      22                 :            : #include "special.h"
      23                 :            : #include "stdio-util.h"
      24                 :            : #include "string-table.h"
      25                 :            : #include "string-util.h"
      26                 :            : #include "strv.h"
      27                 :            : #include "terminal-util.h"
      28                 :            : #include "unit.h"
      29                 :            : #include "virt.h"
      30                 :            : 
      31                 :        728 : Job* job_new_raw(Unit *unit) {
      32                 :            :         Job *j;
      33                 :            : 
      34                 :            :         /* used for deserialization */
      35                 :            : 
      36         [ -  + ]:        728 :         assert(unit);
      37                 :            : 
      38                 :        728 :         j = new(Job, 1);
      39         [ -  + ]:        728 :         if (!j)
      40                 :          0 :                 return NULL;
      41                 :            : 
      42                 :        728 :         *j = (Job) {
      43                 :        728 :                 .manager = unit->manager,
      44                 :            :                 .unit = unit,
      45                 :            :                 .type = _JOB_TYPE_INVALID,
      46                 :            :         };
      47                 :            : 
      48                 :        728 :         return j;
      49                 :            : }
      50                 :            : 
      51                 :        728 : Job* job_new(Unit *unit, JobType type) {
      52                 :            :         Job *j;
      53                 :            : 
      54         [ -  + ]:        728 :         assert(type < _JOB_TYPE_MAX);
      55                 :            : 
      56                 :        728 :         j = job_new_raw(unit);
      57         [ -  + ]:        728 :         if (!j)
      58                 :          0 :                 return NULL;
      59                 :            : 
      60                 :        728 :         j->id = j->manager->current_job_id++;
      61                 :        728 :         j->type = type;
      62                 :            : 
      63                 :            :         /* We don't link it here, that's what job_dependency() is for */
      64                 :            : 
      65                 :        728 :         return j;
      66                 :            : }
      67                 :            : 
      68                 :        728 : void job_unlink(Job *j) {
      69         [ -  + ]:        728 :         assert(j);
      70         [ -  + ]:        728 :         assert(!j->installed);
      71         [ -  + ]:        728 :         assert(!j->transaction_prev);
      72         [ -  + ]:        728 :         assert(!j->transaction_next);
      73         [ -  + ]:        728 :         assert(!j->subject_list);
      74         [ -  + ]:        728 :         assert(!j->object_list);
      75                 :            : 
      76         [ +  + ]:        728 :         if (j->in_run_queue) {
      77                 :        104 :                 prioq_remove(j->manager->run_queue, j, &j->run_queue_idx);
      78                 :        104 :                 j->in_run_queue = false;
      79                 :            :         }
      80                 :            : 
      81         [ -  + ]:        728 :         if (j->in_dbus_queue) {
      82   [ #  #  #  #  :          0 :                 LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j);
             #  #  #  # ]
      83                 :          0 :                 j->in_dbus_queue = false;
      84                 :            :         }
      85                 :            : 
      86         [ -  + ]:        728 :         if (j->in_gc_queue) {
      87   [ #  #  #  #  :          0 :                 LIST_REMOVE(gc_queue, j->manager->gc_job_queue, j);
             #  #  #  # ]
      88                 :          0 :                 j->in_gc_queue = false;
      89                 :            :         }
      90                 :            : 
      91                 :        728 :         j->timer_event_source = sd_event_source_unref(j->timer_event_source);
      92                 :        728 : }
      93                 :            : 
      94                 :        728 : Job* job_free(Job *j) {
      95         [ -  + ]:        728 :         assert(j);
      96         [ -  + ]:        728 :         assert(!j->installed);
      97         [ -  + ]:        728 :         assert(!j->transaction_prev);
      98         [ -  + ]:        728 :         assert(!j->transaction_next);
      99         [ -  + ]:        728 :         assert(!j->subject_list);
     100         [ -  + ]:        728 :         assert(!j->object_list);
     101                 :            : 
     102                 :        728 :         job_unlink(j);
     103                 :            : 
     104                 :        728 :         sd_bus_track_unref(j->bus_track);
     105                 :        728 :         strv_free(j->deserialized_clients);
     106                 :            : 
     107                 :        728 :         return mfree(j);
     108                 :            : }
     109                 :            : 
     110                 :        296 : static void job_set_state(Job *j, JobState state) {
     111         [ -  + ]:        296 :         assert(j);
     112         [ -  + ]:        296 :         assert(state >= 0);
     113         [ -  + ]:        296 :         assert(state < _JOB_STATE_MAX);
     114                 :            : 
     115         [ +  + ]:        296 :         if (j->state == state)
     116                 :        104 :                 return;
     117                 :            : 
     118                 :        192 :         j->state = state;
     119                 :            : 
     120         [ -  + ]:        192 :         if (!j->installed)
     121                 :          0 :                 return;
     122                 :            : 
     123         [ +  + ]:        192 :         if (j->state == JOB_RUNNING)
     124                 :         96 :                 j->unit->manager->n_running_jobs++;
     125                 :            :         else {
     126         [ -  + ]:         96 :                 assert(j->state == JOB_WAITING);
     127         [ -  + ]:         96 :                 assert(j->unit->manager->n_running_jobs > 0);
     128                 :            : 
     129                 :         96 :                 j->unit->manager->n_running_jobs--;
     130                 :            : 
     131         [ +  - ]:         96 :                 if (j->unit->manager->n_running_jobs <= 0)
     132                 :         96 :                         j->unit->manager->jobs_in_progress_event_source = sd_event_source_unref(j->unit->manager->jobs_in_progress_event_source);
     133                 :            :         }
     134                 :            : }
     135                 :            : 
     136                 :        200 : void job_uninstall(Job *j) {
     137                 :            :         Job **pj;
     138                 :            : 
     139         [ -  + ]:        200 :         assert(j->installed);
     140                 :            : 
     141                 :        200 :         job_set_state(j, JOB_WAITING);
     142                 :            : 
     143         [ -  + ]:        200 :         pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
     144         [ -  + ]:        200 :         assert(*pj == j);
     145                 :            : 
     146                 :            :         /* Detach from next 'bigger' objects */
     147                 :            : 
     148                 :            :         /* daemon-reload should be transparent to job observers */
     149         [ +  - ]:        200 :         if (!MANAGER_IS_RELOADING(j->manager))
     150                 :        200 :                 bus_job_send_removed_signal(j);
     151                 :            : 
     152                 :        200 :         *pj = NULL;
     153                 :            : 
     154                 :        200 :         unit_add_to_gc_queue(j->unit);
     155                 :            : 
     156                 :        200 :         unit_add_to_dbus_queue(j->unit); /* The Job property of the unit has changed now */
     157                 :            : 
     158                 :        200 :         hashmap_remove_value(j->manager->jobs, UINT32_TO_PTR(j->id), j);
     159                 :        200 :         j->installed = false;
     160                 :        200 : }
     161                 :            : 
     162                 :          0 : static bool job_type_allows_late_merge(JobType t) {
     163                 :            :         /* Tells whether it is OK to merge a job of type 't' with an already
     164                 :            :          * running job.
     165                 :            :          * Reloads cannot be merged this way. Think of the sequence:
     166                 :            :          * 1. Reload of a daemon is in progress; the daemon has already loaded
     167                 :            :          *    its config file, but hasn't completed the reload operation yet.
     168                 :            :          * 2. Edit foo's config file.
     169                 :            :          * 3. Trigger another reload to have the daemon use the new config.
     170                 :            :          * Should the second reload job be merged into the first one, the daemon
     171                 :            :          * would not know about the new config.
     172                 :            :          * JOB_RESTART jobs on the other hand can be merged, because they get
     173                 :            :          * patched into JOB_START after stopping the unit. So if we see a
     174                 :            :          * JOB_RESTART running, it means the unit hasn't stopped yet and at
     175                 :            :          * this time the merge is still allowed. */
     176                 :          0 :         return t != JOB_RELOAD;
     177                 :            : }
     178                 :            : 
     179                 :         72 : static void job_merge_into_installed(Job *j, Job *other) {
     180         [ -  + ]:         72 :         assert(j->installed);
     181         [ -  + ]:         72 :         assert(j->unit == other->unit);
     182                 :            : 
     183         [ +  - ]:         72 :         if (j->type != JOB_NOP)
     184         [ -  + ]:         72 :                 assert_se(job_type_merge_and_collapse(&j->type, other->type, j->unit) == 0);
     185                 :            :         else
     186         [ #  # ]:          0 :                 assert(other->type == JOB_NOP);
     187                 :            : 
     188   [ +  -  -  + ]:         72 :         j->irreversible = j->irreversible || other->irreversible;
     189   [ +  -  -  + ]:         72 :         j->ignore_order = j->ignore_order || other->ignore_order;
     190                 :         72 : }
     191                 :            : 
     192                 :        272 : Job* job_install(Job *j) {
     193                 :            :         Job **pj;
     194                 :            :         Job *uj;
     195                 :            : 
     196         [ -  + ]:        272 :         assert(!j->installed);
     197         [ -  + ]:        272 :         assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
     198         [ -  + ]:        272 :         assert(j->state == JOB_WAITING);
     199                 :            : 
     200         [ -  + ]:        272 :         pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
     201                 :        272 :         uj = *pj;
     202                 :            : 
     203         [ +  + ]:        272 :         if (uj) {
     204         [ +  + ]:         80 :                 if (job_type_is_conflicting(uj->type, j->type))
     205                 :          8 :                         job_finish_and_invalidate(uj, JOB_CANCELED, false, false);
     206                 :            :                 else {
     207                 :            :                         /* not conflicting, i.e. mergeable */
     208                 :            : 
     209   [ -  +  #  # ]:         72 :                         if (uj->state == JOB_WAITING ||
     210         [ #  # ]:          0 :                             (job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) {
     211                 :         72 :                                 job_merge_into_installed(uj, j);
     212         [ +  - ]:         72 :                                 log_unit_debug(uj->unit,
     213                 :            :                                                "Merged %s/%s into installed job %s/%s as %"PRIu32,
     214                 :            :                                                j->unit->id, job_type_to_string(j->type), uj->unit->id,
     215                 :            :                                                job_type_to_string(uj->type), uj->id);
     216                 :         72 :                                 return uj;
     217                 :            :                         } else {
     218                 :            :                                 /* already running and not safe to merge into */
     219                 :            :                                 /* Patch uj to become a merged job and re-run it. */
     220                 :            :                                 /* XXX It should be safer to queue j to run after uj finishes, but it is
     221                 :            :                                  * not currently possible to have more than one installed job per unit. */
     222                 :          0 :                                 job_merge_into_installed(uj, j);
     223         [ #  # ]:          0 :                                 log_unit_debug(uj->unit,
     224                 :            :                                                "Merged into running job, re-running: %s/%s as %"PRIu32,
     225                 :            :                                                uj->unit->id, job_type_to_string(uj->type), uj->id);
     226                 :            : 
     227                 :          0 :                                 job_set_state(uj, JOB_WAITING);
     228                 :          0 :                                 return uj;
     229                 :            :                         }
     230                 :            :                 }
     231                 :            :         }
     232                 :            : 
     233                 :            :         /* Install the job */
     234                 :        200 :         *pj = j;
     235                 :        200 :         j->installed = true;
     236                 :            : 
     237                 :        200 :         j->manager->n_installed_jobs++;
     238         [ +  - ]:        200 :         log_unit_debug(j->unit,
     239                 :            :                        "Installed new job %s/%s as %u",
     240                 :            :                        j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
     241                 :            : 
     242                 :        200 :         job_add_to_gc_queue(j);
     243                 :            : 
     244                 :        200 :         job_add_to_dbus_queue(j); /* announce this job to clients */
     245                 :        200 :         unit_add_to_dbus_queue(j->unit); /* The Job property of the unit has changed now */
     246                 :            : 
     247                 :        200 :         return j;
     248                 :            : }
     249                 :            : 
     250                 :          0 : int job_install_deserialized(Job *j) {
     251                 :            :         Job **pj;
     252                 :            :         int r;
     253                 :            : 
     254         [ #  # ]:          0 :         assert(!j->installed);
     255                 :            : 
     256   [ #  #  #  # ]:          0 :         if (j->type < 0 || j->type >= _JOB_TYPE_MAX_IN_TRANSACTION)
     257         [ #  # ]:          0 :                 return log_unit_debug_errno(j->unit, SYNTHETIC_ERRNO(EINVAL),
     258                 :            :                                        "Invalid job type %s in deserialization.",
     259                 :            :                                        strna(job_type_to_string(j->type)));
     260                 :            : 
     261         [ #  # ]:          0 :         pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
     262         [ #  # ]:          0 :         if (*pj)
     263         [ #  # ]:          0 :                 return log_unit_debug_errno(j->unit, SYNTHETIC_ERRNO(EEXIST),
     264                 :            :                                             "Unit already has a job installed. Not installing deserialized job.");
     265                 :            : 
     266                 :          0 :         r = hashmap_put(j->manager->jobs, UINT32_TO_PTR(j->id), j);
     267         [ #  # ]:          0 :         if (r == -EEXIST)
     268         [ #  # ]:          0 :                 return log_unit_debug_errno(j->unit, r, "Job ID %" PRIu32 " already used, cannot deserialize job.", j->id);
     269         [ #  # ]:          0 :         if (r < 0)
     270         [ #  # ]:          0 :                 return log_unit_debug_errno(j->unit, r, "Failed to insert job into jobs hash table: %m");
     271                 :            : 
     272                 :          0 :         *pj = j;
     273                 :          0 :         j->installed = true;
     274                 :            : 
     275         [ #  # ]:          0 :         if (j->state == JOB_RUNNING)
     276                 :          0 :                 j->unit->manager->n_running_jobs++;
     277                 :            : 
     278         [ #  # ]:          0 :         log_unit_debug(j->unit,
     279                 :            :                        "Reinstalled deserialized job %s/%s as %u",
     280                 :            :                        j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
     281                 :          0 :         return 0;
     282                 :            : }
     283                 :            : 
     284                 :       1172 : JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) {
     285                 :            :         JobDependency *l;
     286                 :            : 
     287         [ -  + ]:       1172 :         assert(object);
     288                 :            : 
     289                 :            :         /* Adds a new job link, which encodes that the 'subject' job
     290                 :            :          * needs the 'object' job in some way. If 'subject' is NULL
     291                 :            :          * this means the 'anchor' job (i.e. the one the user
     292                 :            :          * explicitly asked for) is the requester. */
     293                 :            : 
     294                 :       1172 :         l = new0(JobDependency, 1);
     295         [ -  + ]:       1172 :         if (!l)
     296                 :          0 :                 return NULL;
     297                 :            : 
     298                 :       1172 :         l->subject = subject;
     299                 :       1172 :         l->object = object;
     300                 :       1172 :         l->matters = matters;
     301                 :       1172 :         l->conflicts = conflicts;
     302                 :            : 
     303         [ +  - ]:       1172 :         if (subject)
     304   [ -  +  +  + ]:       1172 :                 LIST_PREPEND(subject, subject->subject_list, l);
     305                 :            : 
     306   [ -  +  +  + ]:       1172 :         LIST_PREPEND(object, object->object_list, l);
     307                 :            : 
     308                 :       1172 :         return l;
     309                 :            : }
     310                 :            : 
     311                 :       1172 : void job_dependency_free(JobDependency *l) {
     312         [ -  + ]:       1172 :         assert(l);
     313                 :            : 
     314         [ +  - ]:       1172 :         if (l->subject)
     315   [ -  +  +  +  :       1172 :                 LIST_REMOVE(subject, l->subject->subject_list, l);
             +  +  -  + ]
     316                 :            : 
     317   [ -  +  +  +  :       1172 :         LIST_REMOVE(object, l->object->object_list, l);
             +  +  -  + ]
     318                 :            : 
     319                 :       1172 :         free(l);
     320                 :       1172 : }
     321                 :            : 
     322                 :        252 : void job_dump(Job *j, FILE *f, const char *prefix) {
     323         [ -  + ]:        252 :         assert(j);
     324         [ -  + ]:        252 :         assert(f);
     325                 :            : 
     326                 :        252 :         prefix = strempty(prefix);
     327                 :            : 
     328                 :        252 :         fprintf(f,
     329                 :            :                 "%s-> Job %u:\n"
     330                 :            :                 "%s\tAction: %s -> %s\n"
     331                 :            :                 "%s\tState: %s\n"
     332                 :            :                 "%s\tIrreversible: %s\n"
     333                 :            :                 "%s\tMay GC: %s\n",
     334                 :            :                 prefix, j->id,
     335                 :        252 :                 prefix, j->unit->id, job_type_to_string(j->type),
     336                 :            :                 prefix, job_state_to_string(j->state),
     337                 :        252 :                 prefix, yes_no(j->irreversible),
     338                 :        252 :                 prefix, yes_no(job_may_gc(j)));
     339                 :        252 : }
     340                 :            : 
     341                 :            : /*
     342                 :            :  * Merging is commutative, so imagine the matrix as symmetric. We store only
     343                 :            :  * its lower triangle to avoid duplication. We don't store the main diagonal,
     344                 :            :  * because A merged with A is simply A.
     345                 :            :  *
     346                 :            :  * If the resulting type is collapsed immediately afterwards (to get rid of
     347                 :            :  * the JOB_RELOAD_OR_START, which lies outside the lookup function's domain),
     348                 :            :  * the following properties hold:
     349                 :            :  *
     350                 :            :  * Merging is associative! A merged with B, and then merged with C is the same
     351                 :            :  * as A merged with the result of B merged with C.
     352                 :            :  *
     353                 :            :  * Mergeability is transitive! If A can be merged with B and B with C then
     354                 :            :  * A also with C.
     355                 :            :  *
     356                 :            :  * Also, if A merged with B cannot be merged with C, then either A or B cannot
     357                 :            :  * be merged with C either.
     358                 :            :  */
     359                 :            : static const JobType job_merging_table[] = {
     360                 :            : /* What \ With       *  JOB_START         JOB_VERIFY_ACTIVE  JOB_STOP JOB_RELOAD */
     361                 :            : /*********************************************************************************/
     362                 :            : /*JOB_START          */
     363                 :            : /*JOB_VERIFY_ACTIVE  */ JOB_START,
     364                 :            : /*JOB_STOP           */ -1,                  -1,
     365                 :            : /*JOB_RELOAD         */ JOB_RELOAD_OR_START, JOB_RELOAD,          -1,
     366                 :            : /*JOB_RESTART        */ JOB_RESTART,         JOB_RESTART,         -1, JOB_RESTART,
     367                 :            : };
     368                 :            : 
     369                 :       8073 : JobType job_type_lookup_merge(JobType a, JobType b) {
     370                 :            :         assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX_MERGING * (_JOB_TYPE_MAX_MERGING - 1) / 2);
     371   [ +  -  -  + ]:       8073 :         assert(a >= 0 && a < _JOB_TYPE_MAX_MERGING);
     372   [ +  -  -  + ]:       8073 :         assert(b >= 0 && b < _JOB_TYPE_MAX_MERGING);
     373                 :            : 
     374         [ +  + ]:       8073 :         if (a == b)
     375                 :       2021 :                 return a;
     376                 :            : 
     377         [ +  + ]:       6052 :         if (a < b) {
     378                 :       2804 :                 JobType tmp = a;
     379                 :       2804 :                 a = b;
     380                 :       2804 :                 b = tmp;
     381                 :            :         }
     382                 :            : 
     383                 :       6052 :         return job_merging_table[(a - 1) * a / 2 + b];
     384                 :            : }
     385                 :            : 
     386                 :       1796 : bool job_type_is_redundant(JobType a, UnitActiveState b) {
     387   [ +  +  -  -  :       1796 :         switch (a) {
                -  -  - ]
     388                 :            : 
     389                 :       1514 :         case JOB_START:
     390         [ +  + ]:       1514 :                 return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING);
     391                 :            : 
     392                 :        282 :         case JOB_STOP:
     393         [ +  + ]:        282 :                 return IN_SET(b, UNIT_INACTIVE, UNIT_FAILED);
     394                 :            : 
     395                 :          0 :         case JOB_VERIFY_ACTIVE:
     396         [ #  # ]:          0 :                 return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING);
     397                 :            : 
     398                 :          0 :         case JOB_RELOAD:
     399                 :            :                 return
     400                 :          0 :                         b == UNIT_RELOADING;
     401                 :            : 
     402                 :          0 :         case JOB_RESTART:
     403                 :            :                 return
     404                 :          0 :                         b == UNIT_ACTIVATING;
     405                 :            : 
     406                 :          0 :         case JOB_NOP:
     407                 :          0 :                 return true;
     408                 :            : 
     409                 :          0 :         default:
     410                 :          0 :                 assert_not_reached("Invalid job type");
     411                 :            :         }
     412                 :            : }
     413                 :            : 
     414                 :       2368 : JobType job_type_collapse(JobType t, Unit *u) {
     415                 :            :         UnitActiveState s;
     416                 :            : 
     417   [ -  -  +  + ]:       2368 :         switch (t) {
     418                 :            : 
     419                 :          0 :         case JOB_TRY_RESTART:
     420                 :          0 :                 s = unit_active_state(u);
     421         [ #  # ]:          0 :                 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
     422                 :          0 :                         return JOB_NOP;
     423                 :            : 
     424                 :          0 :                 return JOB_RESTART;
     425                 :            : 
     426                 :          0 :         case JOB_TRY_RELOAD:
     427                 :          0 :                 s = unit_active_state(u);
     428         [ #  # ]:          0 :                 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
     429                 :          0 :                         return JOB_NOP;
     430                 :            : 
     431                 :          0 :                 return JOB_RELOAD;
     432                 :            : 
     433                 :        272 :         case JOB_RELOAD_OR_START:
     434                 :        272 :                 s = unit_active_state(u);
     435         [ +  + ]:        272 :                 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
     436                 :        136 :                         return JOB_START;
     437                 :            : 
     438                 :        136 :                 return JOB_RELOAD;
     439                 :            : 
     440                 :       2096 :         default:
     441                 :       2096 :                 return t;
     442                 :            :         }
     443                 :            : }
     444                 :            : 
     445                 :       2512 : int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) {
     446                 :            :         JobType t;
     447                 :            : 
     448                 :       2512 :         t = job_type_lookup_merge(*a, b);
     449         [ +  + ]:       2512 :         if (t < 0)
     450                 :        224 :                 return -EEXIST;
     451                 :            : 
     452                 :       2288 :         *a = job_type_collapse(t, u);
     453                 :       2288 :         return 0;
     454                 :            : }
     455                 :            : 
     456                 :        144 : static bool job_is_runnable(Job *j) {
     457                 :            :         Iterator i;
     458                 :            :         Unit *other;
     459                 :            :         void *v;
     460                 :            : 
     461         [ -  + ]:        144 :         assert(j);
     462         [ -  + ]:        144 :         assert(j->installed);
     463                 :            : 
     464                 :            :         /* Checks whether there is any job running for the units this
     465                 :            :          * job needs to be running after (in the case of a 'positive'
     466                 :            :          * job type) or before (in the case of a 'negative' job
     467                 :            :          * type. */
     468                 :            : 
     469                 :            :         /* Note that unit types have a say in what is runnable,
     470                 :            :          * too. For example, if they return -EAGAIN from
     471                 :            :          * unit_start() they can indicate they are not
     472                 :            :          * runnable yet. */
     473                 :            : 
     474                 :            :         /* First check if there is an override */
     475         [ -  + ]:        144 :         if (j->ignore_order)
     476                 :          0 :                 return true;
     477                 :            : 
     478         [ -  + ]:        144 :         if (j->type == JOB_NOP)
     479                 :          0 :                 return true;
     480                 :            : 
     481         [ +  + ]:        573 :         HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i)
     482   [ +  +  +  - ]:        477 :                 if (other->job && job_compare(j, other->job, UNIT_AFTER) > 0)
     483                 :         48 :                         return false;
     484                 :            : 
     485         [ +  + ]:        264 :         HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i)
     486   [ +  +  -  + ]:        168 :                 if (other->job && job_compare(j, other->job, UNIT_BEFORE) > 0)
     487                 :          0 :                         return false;
     488                 :            : 
     489                 :         96 :         return true;
     490                 :            : }
     491                 :            : 
     492                 :          0 : static void job_change_type(Job *j, JobType newtype) {
     493         [ #  # ]:          0 :         assert(j);
     494                 :            : 
     495         [ #  # ]:          0 :         log_unit_debug(j->unit,
     496                 :            :                        "Converting job %s/%s -> %s/%s",
     497                 :            :                        j->unit->id, job_type_to_string(j->type),
     498                 :            :                        j->unit->id, job_type_to_string(newtype));
     499                 :            : 
     500                 :          0 :         j->type = newtype;
     501                 :          0 : }
     502                 :            : 
     503                 :         24 : _pure_ static const char* job_get_begin_status_message_format(Unit *u, JobType t) {
     504                 :            :         const char *format;
     505                 :            : 
     506         [ -  + ]:         24 :         assert(u);
     507                 :            : 
     508         [ -  + ]:         24 :         if (t == JOB_RELOAD)
     509                 :          0 :                 return "Reloading %s.";
     510                 :            : 
     511   [ +  -  -  + ]:         24 :         assert(IN_SET(t, JOB_START, JOB_STOP));
     512                 :            : 
     513                 :         24 :         format = UNIT_VTABLE(u)->status_message_formats.starting_stopping[t == JOB_STOP];
     514         [ +  - ]:         24 :         if (format)
     515                 :         24 :                 return format;
     516                 :            : 
     517                 :            :         /* Return generic strings */
     518         [ #  # ]:          0 :         if (t == JOB_START)
     519                 :          0 :                 return "Starting %s.";
     520                 :            :         else {
     521         [ #  # ]:          0 :                 assert(t == JOB_STOP);
     522                 :          0 :                 return "Stopping %s.";
     523                 :            :         }
     524                 :            : }
     525                 :            : 
     526                 :         24 : static void job_print_begin_status_message(Unit *u, JobType t) {
     527                 :            :         const char *format;
     528                 :            : 
     529         [ -  + ]:         24 :         assert(u);
     530                 :            : 
     531                 :            :         /* Reload status messages have traditionally not been printed to console. */
     532   [ +  -  -  + ]:         24 :         if (!IN_SET(t, JOB_START, JOB_STOP))
     533                 :          0 :                 return;
     534                 :            : 
     535                 :         24 :         format = job_get_begin_status_message_format(u, t);
     536                 :            : 
     537                 :            :         DISABLE_WARNING_FORMAT_NONLITERAL;
     538                 :         24 :         unit_status_printf(u, "", format);
     539                 :            :         REENABLE_WARNING;
     540                 :            : }
     541                 :            : 
     542                 :         24 : static void job_log_begin_status_message(Unit *u, uint32_t job_id, JobType t) {
     543                 :            :         const char *format, *mid;
     544                 :            :         char buf[LINE_MAX];
     545                 :            : 
     546         [ -  + ]:         24 :         assert(u);
     547         [ -  + ]:         24 :         assert(t >= 0);
     548         [ -  + ]:         24 :         assert(t < _JOB_TYPE_MAX);
     549                 :            : 
     550   [ +  -  -  + ]:         24 :         if (!IN_SET(t, JOB_START, JOB_STOP, JOB_RELOAD))
     551                 :         24 :                 return;
     552                 :            : 
     553         [ +  - ]:         24 :         if (log_on_console()) /* Skip this if it would only go on the console anyway */
     554                 :         24 :                 return;
     555                 :            : 
     556                 :            :         /* We log status messages for all units and all operations. */
     557                 :            : 
     558                 :          0 :         format = job_get_begin_status_message_format(u, t);
     559                 :            : 
     560                 :            :         DISABLE_WARNING_FORMAT_NONLITERAL;
     561                 :          0 :         (void) snprintf(buf, sizeof buf, format, unit_status_string(u));
     562                 :            :         REENABLE_WARNING;
     563                 :            : 
     564         [ #  # ]:          0 :         mid = t == JOB_START ? "MESSAGE_ID=" SD_MESSAGE_UNIT_STARTING_STR :
     565         [ #  # ]:          0 :               t == JOB_STOP  ? "MESSAGE_ID=" SD_MESSAGE_UNIT_STOPPING_STR :
     566                 :            :                                "MESSAGE_ID=" SD_MESSAGE_UNIT_RELOADING_STR;
     567                 :            : 
     568                 :            :         /* Note that we deliberately use LOG_MESSAGE() instead of
     569                 :            :          * LOG_UNIT_MESSAGE() here, since this is supposed to mimic
     570                 :            :          * closely what is written to screen using the status output,
     571                 :            :          * which is supposed the highest level, friendliest output
     572                 :            :          * possible, which means we should avoid the low-level unit
     573                 :            :          * name. */
     574                 :          0 :         log_struct(LOG_INFO,
     575                 :            :                    LOG_MESSAGE("%s", buf),
     576                 :            :                    "JOB_ID=%" PRIu32, job_id,
     577                 :            :                    "JOB_TYPE=%s", job_type_to_string(t),
     578                 :            :                    LOG_UNIT_ID(u),
     579                 :            :                    LOG_UNIT_INVOCATION_ID(u),
     580                 :            :                    mid);
     581                 :            : }
     582                 :            : 
     583                 :         24 : static void job_emit_begin_status_message(Unit *u, uint32_t job_id, JobType t) {
     584         [ -  + ]:         24 :         assert(u);
     585         [ -  + ]:         24 :         assert(t >= 0);
     586         [ -  + ]:         24 :         assert(t < _JOB_TYPE_MAX);
     587                 :            : 
     588                 :         24 :         job_log_begin_status_message(u, job_id, t);
     589                 :         24 :         job_print_begin_status_message(u, t);
     590                 :         24 : }
     591                 :            : 
     592                 :         96 : static int job_perform_on_unit(Job **j) {
     593                 :            :         uint32_t id;
     594                 :            :         Manager *m;
     595                 :            :         JobType t;
     596                 :            :         Unit *u;
     597                 :            :         int r;
     598                 :            : 
     599                 :            :         /* While we execute this operation the job might go away (for
     600                 :            :          * example: because it finishes immediately or is replaced by
     601                 :            :          * a new, conflicting job.) To make sure we don't access a
     602                 :            :          * freed job later on we store the id here, so that we can
     603                 :            :          * verify the job is still valid. */
     604                 :            : 
     605         [ -  + ]:         96 :         assert(j);
     606         [ -  + ]:         96 :         assert(*j);
     607                 :            : 
     608                 :         96 :         m = (*j)->manager;
     609                 :         96 :         u = (*j)->unit;
     610                 :         96 :         t = (*j)->type;
     611                 :         96 :         id = (*j)->id;
     612                 :            : 
     613   [ +  -  -  -  :         96 :         switch (t) {
                      - ]
     614                 :         96 :                 case JOB_START:
     615                 :         96 :                         r = unit_start(u);
     616                 :         96 :                         break;
     617                 :            : 
     618                 :          0 :                 case JOB_RESTART:
     619                 :          0 :                         t = JOB_STOP;
     620                 :            :                         _fallthrough_;
     621                 :          0 :                 case JOB_STOP:
     622                 :          0 :                         r = unit_stop(u);
     623                 :          0 :                         break;
     624                 :            : 
     625                 :          0 :                 case JOB_RELOAD:
     626                 :          0 :                         r = unit_reload(u);
     627                 :          0 :                         break;
     628                 :            : 
     629                 :          0 :                 default:
     630                 :          0 :                         assert_not_reached("Invalid job type");
     631                 :            :         }
     632                 :            : 
     633                 :            :         /* Log if the job still exists and the start/stop/reload function actually did something. Note that this means
     634                 :            :          * for units for which there's no 'activating' phase (i.e. because we transition directly from 'inactive' to
     635                 :            :          * 'active') we'll possibly skip the "Starting..." message. */
     636                 :         96 :         *j = manager_get_job(m, id);
     637   [ +  +  +  - ]:         96 :         if (*j && r > 0)
     638                 :         24 :                 job_emit_begin_status_message(u, id, t);
     639                 :            : 
     640                 :         96 :         return r;
     641                 :            : }
     642                 :            : 
     643                 :        144 : int job_run_and_invalidate(Job *j) {
     644                 :            :         int r;
     645                 :            : 
     646         [ -  + ]:        144 :         assert(j);
     647         [ -  + ]:        144 :         assert(j->installed);
     648         [ -  + ]:        144 :         assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
     649         [ -  + ]:        144 :         assert(j->in_run_queue);
     650                 :            : 
     651                 :        144 :         prioq_remove(j->manager->run_queue, j, &j->run_queue_idx);
     652                 :        144 :         j->in_run_queue = false;
     653                 :            : 
     654         [ -  + ]:        144 :         if (j->state != JOB_WAITING)
     655                 :          0 :                 return 0;
     656                 :            : 
     657         [ +  + ]:        144 :         if (!job_is_runnable(j))
     658                 :         48 :                 return -EAGAIN;
     659                 :            : 
     660                 :         96 :         job_start_timer(j, true);
     661                 :         96 :         job_set_state(j, JOB_RUNNING);
     662                 :         96 :         job_add_to_dbus_queue(j);
     663                 :            : 
     664   [ -  +  -  -  :         96 :         switch (j->type) {
                      - ]
     665                 :            : 
     666                 :          0 :                 case JOB_VERIFY_ACTIVE: {
     667                 :            :                         UnitActiveState t;
     668                 :            : 
     669                 :          0 :                         t = unit_active_state(j->unit);
     670         [ #  # ]:          0 :                         if (UNIT_IS_ACTIVE_OR_RELOADING(t))
     671                 :          0 :                                 r = -EALREADY;
     672         [ #  # ]:          0 :                         else if (t == UNIT_ACTIVATING)
     673                 :          0 :                                 r = -EAGAIN;
     674                 :            :                         else
     675                 :          0 :                                 r = -EBADR;
     676                 :          0 :                         break;
     677                 :            :                 }
     678                 :            : 
     679                 :         96 :                 case JOB_START:
     680                 :            :                 case JOB_STOP:
     681                 :            :                 case JOB_RESTART:
     682                 :         96 :                         r = job_perform_on_unit(&j);
     683                 :            : 
     684                 :            :                         /* If the unit type does not support starting/stopping, then simply wait. */
     685         [ -  + ]:         96 :                         if (r == -EBADR)
     686                 :          0 :                                 r = 0;
     687                 :         96 :                         break;
     688                 :            : 
     689                 :          0 :                 case JOB_RELOAD:
     690                 :          0 :                         r = job_perform_on_unit(&j);
     691                 :          0 :                         break;
     692                 :            : 
     693                 :          0 :                 case JOB_NOP:
     694                 :          0 :                         r = -EALREADY;
     695                 :          0 :                         break;
     696                 :            : 
     697                 :          0 :                 default:
     698                 :          0 :                         assert_not_reached("Unknown job type");
     699                 :            :         }
     700                 :            : 
     701         [ +  + ]:         96 :         if (j) {
     702         [ -  + ]:         24 :                 if (r == -EAGAIN)
     703                 :          0 :                         job_set_state(j, JOB_WAITING); /* Hmm, not ready after all, let's return to JOB_WAITING state */
     704         [ -  + ]:         24 :                 else if (r == -EALREADY) /* already being executed */
     705                 :          0 :                         r = job_finish_and_invalidate(j, JOB_DONE, true, true);
     706         [ -  + ]:         24 :                 else if (r == -ECOMM)    /* condition failed, but all is good */
     707                 :          0 :                         r = job_finish_and_invalidate(j, JOB_DONE, true, false);
     708         [ -  + ]:         24 :                 else if (r == -EBADR)
     709                 :          0 :                         r = job_finish_and_invalidate(j, JOB_SKIPPED, true, false);
     710         [ -  + ]:         24 :                 else if (r == -ENOEXEC)
     711                 :          0 :                         r = job_finish_and_invalidate(j, JOB_INVALID, true, false);
     712         [ -  + ]:         24 :                 else if (r == -EPROTO)
     713                 :          0 :                         r = job_finish_and_invalidate(j, JOB_ASSERT, true, false);
     714         [ -  + ]:         24 :                 else if (r == -EOPNOTSUPP)
     715                 :          0 :                         r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true, false);
     716         [ -  + ]:         24 :                 else if (r == -ENOLINK)
     717                 :          0 :                         r = job_finish_and_invalidate(j, JOB_DEPENDENCY, true, false);
     718         [ -  + ]:         24 :                 else if (r == -ESTALE)
     719                 :          0 :                         r = job_finish_and_invalidate(j, JOB_ONCE, true, false);
     720         [ -  + ]:         24 :                 else if (r < 0)
     721                 :          0 :                         r = job_finish_and_invalidate(j, JOB_FAILED, true, false);
     722                 :            :         }
     723                 :            : 
     724                 :         96 :         return r;
     725                 :            : }
     726                 :            : 
     727                 :        176 : _pure_ static const char *job_get_done_status_message_format(Unit *u, JobType t, JobResult result) {
     728                 :            : 
     729                 :            :         static const char *const generic_finished_start_job[_JOB_RESULT_MAX] = {
     730                 :            :                 [JOB_DONE]        = "Started %s.",
     731                 :            :                 [JOB_TIMEOUT]     = "Timed out starting %s.",
     732                 :            :                 [JOB_FAILED]      = "Failed to start %s.",
     733                 :            :                 [JOB_DEPENDENCY]  = "Dependency failed for %s.",
     734                 :            :                 [JOB_ASSERT]      = "Assertion failed for %s.",
     735                 :            :                 [JOB_UNSUPPORTED] = "Starting of %s not supported.",
     736                 :            :                 [JOB_COLLECTED]   = "Unnecessary job for %s was removed.",
     737                 :            :                 [JOB_ONCE]        = "Unit %s has been started before and cannot be started again."
     738                 :            :         };
     739                 :            :         static const char *const generic_finished_stop_job[_JOB_RESULT_MAX] = {
     740                 :            :                 [JOB_DONE]        = "Stopped %s.",
     741                 :            :                 [JOB_FAILED]      = "Stopped (with error) %s.",
     742                 :            :                 [JOB_TIMEOUT]     = "Timed out stopping %s.",
     743                 :            :         };
     744                 :            :         static const char *const generic_finished_reload_job[_JOB_RESULT_MAX] = {
     745                 :            :                 [JOB_DONE]        = "Reloaded %s.",
     746                 :            :                 [JOB_FAILED]      = "Reload failed for %s.",
     747                 :            :                 [JOB_TIMEOUT]     = "Timed out reloading %s.",
     748                 :            :         };
     749                 :            :         /* When verify-active detects the unit is inactive, report it.
     750                 :            :          * Most likely a DEPEND warning from a requisiting unit will
     751                 :            :          * occur next and it's nice to see what was requisited. */
     752                 :            :         static const char *const generic_finished_verify_active_job[_JOB_RESULT_MAX] = {
     753                 :            :                 [JOB_SKIPPED]     = "%s is not active.",
     754                 :            :         };
     755                 :            : 
     756                 :            :         const char *format;
     757                 :            : 
     758         [ -  + ]:        176 :         assert(u);
     759         [ -  + ]:        176 :         assert(t >= 0);
     760         [ -  + ]:        176 :         assert(t < _JOB_TYPE_MAX);
     761                 :            : 
     762   [ +  -  +  - ]:        176 :         if (IN_SET(t, JOB_START, JOB_STOP, JOB_RESTART)) {
     763                 :        176 :                 format = t == JOB_START ?
     764         [ +  + ]:        196 :                         UNIT_VTABLE(u)->status_message_formats.finished_start_job[result] :
     765                 :         20 :                         UNIT_VTABLE(u)->status_message_formats.finished_stop_job[result];
     766         [ +  + ]:        176 :                 if (format)
     767                 :         72 :                         return format;
     768                 :            :         }
     769                 :            : 
     770                 :            :         /* Return generic strings */
     771         [ +  + ]:        104 :         if (t == JOB_START)
     772                 :         84 :                 return generic_finished_start_job[result];
     773   [ +  -  +  - ]:         20 :         else if (IN_SET(t, JOB_STOP, JOB_RESTART))
     774                 :         20 :                 return generic_finished_stop_job[result];
     775         [ #  # ]:          0 :         else if (t == JOB_RELOAD)
     776                 :          0 :                 return generic_finished_reload_job[result];
     777         [ #  # ]:          0 :         else if (t == JOB_VERIFY_ACTIVE)
     778                 :          0 :                 return generic_finished_verify_active_job[result];
     779                 :            : 
     780                 :          0 :         return NULL;
     781                 :            : }
     782                 :            : 
     783                 :            : static const struct {
     784                 :            :         const char *color, *word;
     785                 :            : } job_print_done_status_messages[_JOB_RESULT_MAX] = {
     786                 :            :         [JOB_DONE]        = { ANSI_OK_COLOR,         "  OK  " },
     787                 :            :         [JOB_TIMEOUT]     = { ANSI_HIGHLIGHT_RED,    " TIME " },
     788                 :            :         [JOB_FAILED]      = { ANSI_HIGHLIGHT_RED,    "FAILED" },
     789                 :            :         [JOB_DEPENDENCY]  = { ANSI_HIGHLIGHT_YELLOW, "DEPEND" },
     790                 :            :         [JOB_SKIPPED]     = { ANSI_HIGHLIGHT,        " INFO " },
     791                 :            :         [JOB_ASSERT]      = { ANSI_HIGHLIGHT_YELLOW, "ASSERT" },
     792                 :            :         [JOB_UNSUPPORTED] = { ANSI_HIGHLIGHT_YELLOW, "UNSUPP" },
     793                 :            :         /* JOB_COLLECTED */
     794                 :            :         [JOB_ONCE]        = { ANSI_HIGHLIGHT_RED,    " ONCE " },
     795                 :            : };
     796                 :            : 
     797                 :        176 : static void job_print_done_status_message(Unit *u, JobType t, JobResult result) {
     798                 :            :         const char *format;
     799                 :            :         const char *status;
     800                 :            : 
     801         [ -  + ]:        176 :         assert(u);
     802         [ -  + ]:        176 :         assert(t >= 0);
     803         [ -  + ]:        176 :         assert(t < _JOB_TYPE_MAX);
     804                 :            : 
     805                 :            :         /* Reload status messages have traditionally not been printed to console. */
     806         [ -  + ]:        176 :         if (t == JOB_RELOAD)
     807                 :          0 :                 return;
     808                 :            : 
     809                 :            :         /* No message if the job did not actually do anything due to failed condition. */
     810   [ +  +  +  +  :        176 :         if (t == JOB_START && result == JOB_DONE && !u->condition_result)
                   -  + ]
     811                 :          0 :                 return;
     812                 :            : 
     813         [ +  + ]:        176 :         if (!job_print_done_status_messages[result].word)
     814                 :        104 :                 return;
     815                 :            : 
     816                 :         72 :         format = job_get_done_status_message_format(u, t, result);
     817         [ -  + ]:         72 :         if (!format)
     818                 :          0 :                 return;
     819                 :            : 
     820         [ -  + ]:         72 :         if (log_get_show_color())
     821   [ #  #  #  #  :          0 :                 status = strjoina(job_print_done_status_messages[result].color,
          #  #  #  #  #  
                #  #  # ]
     822                 :            :                                   job_print_done_status_messages[result].word,
     823                 :            :                                   ANSI_NORMAL);
     824                 :            :         else
     825                 :         72 :                 status = job_print_done_status_messages[result].word;
     826                 :            : 
     827         [ -  + ]:         72 :         if (result != JOB_DONE)
     828                 :          0 :                 manager_flip_auto_status(u->manager, true);
     829                 :            : 
     830                 :            :         DISABLE_WARNING_FORMAT_NONLITERAL;
     831                 :         72 :         unit_status_printf(u, status, format);
     832                 :            :         REENABLE_WARNING;
     833                 :            : 
     834   [ +  -  -  + ]:         72 :         if (t == JOB_START && result == JOB_FAILED) {
     835                 :          0 :                 _cleanup_free_ char *quoted;
     836                 :            : 
     837                 :          0 :                 quoted = shell_maybe_quote(u->id, ESCAPE_BACKSLASH);
     838                 :          0 :                 manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL, "See 'systemctl status %s' for details.", strna(quoted));
     839                 :            :         }
     840                 :            : }
     841                 :            : 
     842                 :        176 : static void job_log_done_status_message(Unit *u, uint32_t job_id, JobType t, JobResult result) {
     843                 :            :         const char *format, *mid;
     844                 :            :         char buf[LINE_MAX];
     845                 :            :         static const int job_result_log_level[_JOB_RESULT_MAX] = {
     846                 :            :                 [JOB_DONE]        = LOG_INFO,
     847                 :            :                 [JOB_CANCELED]    = LOG_INFO,
     848                 :            :                 [JOB_TIMEOUT]     = LOG_ERR,
     849                 :            :                 [JOB_FAILED]      = LOG_ERR,
     850                 :            :                 [JOB_DEPENDENCY]  = LOG_WARNING,
     851                 :            :                 [JOB_SKIPPED]     = LOG_NOTICE,
     852                 :            :                 [JOB_INVALID]     = LOG_INFO,
     853                 :            :                 [JOB_ASSERT]      = LOG_WARNING,
     854                 :            :                 [JOB_UNSUPPORTED] = LOG_WARNING,
     855                 :            :                 [JOB_COLLECTED]   = LOG_INFO,
     856                 :            :                 [JOB_ONCE]        = LOG_ERR,
     857                 :            :         };
     858                 :            : 
     859         [ -  + ]:        176 :         assert(u);
     860         [ -  + ]:        176 :         assert(t >= 0);
     861         [ -  + ]:        176 :         assert(t < _JOB_TYPE_MAX);
     862                 :            : 
     863                 :            :         /* Skip printing if output goes to the console, and job_print_status_message()
     864                 :            :            will actually print something to the console. */
     865   [ +  -  +  + ]:        176 :         if (log_on_console() && job_print_done_status_messages[result].word)
     866                 :        176 :                 return;
     867                 :            : 
     868                 :            :         /* Show condition check message if the job did not actually do anything due to failed condition. */
     869   [ +  +  -  +  :        104 :         if ((t == JOB_START && result == JOB_DONE && !u->condition_result) ||
             #  #  +  + ]
     870         [ -  + ]:         84 :             (t == JOB_START && result == JOB_SKIPPED)) {
     871                 :          0 :                 log_struct(LOG_INFO,
     872                 :            :                            "MESSAGE=Condition check resulted in %s being skipped.", unit_status_string(u),
     873                 :            :                            "JOB_ID=%" PRIu32, job_id,
     874                 :            :                            "JOB_TYPE=%s", job_type_to_string(t),
     875                 :            :                            "JOB_RESULT=%s", job_result_to_string(result),
     876                 :            :                            LOG_UNIT_ID(u),
     877                 :            :                            LOG_UNIT_INVOCATION_ID(u),
     878                 :            :                            "MESSAGE_ID=" SD_MESSAGE_UNIT_STARTED_STR);
     879                 :            : 
     880                 :          0 :                 return;
     881                 :            :         }
     882                 :            : 
     883                 :        104 :         format = job_get_done_status_message_format(u, t, result);
     884         [ +  - ]:        104 :         if (!format)
     885                 :        104 :                 return;
     886                 :            : 
     887                 :            :         /* The description might be longer than the buffer, but that's OK,
     888                 :            :          * we'll just truncate it here. Note that we use snprintf() rather than
     889                 :            :          * xsprintf() on purpose here: we are fine with truncation and don't
     890                 :            :          * consider that an error. */
     891                 :            :         DISABLE_WARNING_FORMAT_NONLITERAL;
     892                 :          0 :         (void) snprintf(buf, sizeof(buf), format, unit_status_string(u));
     893                 :            :         REENABLE_WARNING;
     894                 :            : 
     895   [ #  #  #  # ]:          0 :         switch (t) {
     896                 :            : 
     897                 :          0 :         case JOB_START:
     898         [ #  # ]:          0 :                 if (result == JOB_DONE)
     899                 :          0 :                         mid = "MESSAGE_ID=" SD_MESSAGE_UNIT_STARTED_STR;
     900                 :            :                 else
     901                 :          0 :                         mid = "MESSAGE_ID=" SD_MESSAGE_UNIT_FAILED_STR;
     902                 :          0 :                 break;
     903                 :            : 
     904                 :          0 :         case JOB_RELOAD:
     905                 :          0 :                 mid = "MESSAGE_ID=" SD_MESSAGE_UNIT_RELOADED_STR;
     906                 :          0 :                 break;
     907                 :            : 
     908                 :          0 :         case JOB_STOP:
     909                 :            :         case JOB_RESTART:
     910                 :          0 :                 mid = "MESSAGE_ID=" SD_MESSAGE_UNIT_STOPPED_STR;
     911                 :          0 :                 break;
     912                 :            : 
     913                 :          0 :         default:
     914                 :          0 :                 log_struct(job_result_log_level[result],
     915                 :            :                            LOG_MESSAGE("%s", buf),
     916                 :            :                            "JOB_ID=%" PRIu32, job_id,
     917                 :            :                            "JOB_TYPE=%s", job_type_to_string(t),
     918                 :            :                            "JOB_RESULT=%s", job_result_to_string(result),
     919                 :            :                            LOG_UNIT_ID(u),
     920                 :            :                            LOG_UNIT_INVOCATION_ID(u));
     921                 :          0 :                 return;
     922                 :            :         }
     923                 :            : 
     924                 :          0 :         log_struct(job_result_log_level[result],
     925                 :            :                    LOG_MESSAGE("%s", buf),
     926                 :            :                    "JOB_ID=%" PRIu32, job_id,
     927                 :            :                    "JOB_TYPE=%s", job_type_to_string(t),
     928                 :            :                    "JOB_RESULT=%s", job_result_to_string(result),
     929                 :            :                    LOG_UNIT_ID(u),
     930                 :            :                    LOG_UNIT_INVOCATION_ID(u),
     931                 :            :                    mid);
     932                 :            : }
     933                 :            : 
     934                 :        176 : static void job_emit_done_status_message(Unit *u, uint32_t job_id, JobType t, JobResult result) {
     935         [ -  + ]:        176 :         assert(u);
     936                 :            : 
     937                 :        176 :         job_log_done_status_message(u, job_id, t, result);
     938                 :        176 :         job_print_done_status_message(u, t, result);
     939                 :        176 : }
     940                 :            : 
     941                 :          0 : static void job_fail_dependencies(Unit *u, UnitDependency d) {
     942                 :            :         Unit *other;
     943                 :            :         Iterator i;
     944                 :            :         void *v;
     945                 :            : 
     946         [ #  # ]:          0 :         assert(u);
     947                 :            : 
     948         [ #  # ]:          0 :         HASHMAP_FOREACH_KEY(v, other, u->dependencies[d], i) {
     949                 :          0 :                 Job *j = other->job;
     950                 :            : 
     951         [ #  # ]:          0 :                 if (!j)
     952                 :          0 :                         continue;
     953   [ #  #  #  # ]:          0 :                 if (!IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE))
     954                 :          0 :                         continue;
     955                 :            : 
     956                 :          0 :                 job_finish_and_invalidate(j, JOB_DEPENDENCY, true, false);
     957                 :            :         }
     958                 :          0 : }
     959                 :            : 
     960                 :        176 : int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already) {
     961                 :            :         Unit *u;
     962                 :            :         Unit *other;
     963                 :            :         JobType t;
     964                 :            :         Iterator i;
     965                 :            :         void *v;
     966                 :            : 
     967         [ -  + ]:        176 :         assert(j);
     968         [ -  + ]:        176 :         assert(j->installed);
     969         [ -  + ]:        176 :         assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
     970                 :            : 
     971                 :        176 :         u = j->unit;
     972                 :        176 :         t = j->type;
     973                 :            : 
     974                 :        176 :         j->result = result;
     975                 :            : 
     976         [ +  - ]:        176 :         log_unit_debug(u, "Job %" PRIu32 " %s/%s finished, result=%s", j->id, u->id, job_type_to_string(t), job_result_to_string(result));
     977                 :            : 
     978                 :            :         /* If this job did nothing to respective unit we don't log the status message */
     979         [ +  - ]:        176 :         if (!already)
     980                 :        176 :                 job_emit_done_status_message(u, j->id, t, result);
     981                 :            : 
     982                 :            :         /* Patch restart jobs so that they become normal start jobs */
     983   [ +  +  -  + ]:        176 :         if (result == JOB_DONE && t == JOB_RESTART) {
     984                 :            : 
     985                 :          0 :                 job_change_type(j, JOB_START);
     986                 :          0 :                 job_set_state(j, JOB_WAITING);
     987                 :            : 
     988                 :          0 :                 job_add_to_dbus_queue(j);
     989                 :          0 :                 job_add_to_run_queue(j);
     990                 :          0 :                 job_add_to_gc_queue(j);
     991                 :            : 
     992                 :          0 :                 goto finish;
     993                 :            :         }
     994                 :            : 
     995   [ -  +  -  + ]:        176 :         if (IN_SET(result, JOB_FAILED, JOB_INVALID))
     996                 :          0 :                 j->manager->n_failed_jobs++;
     997                 :            : 
     998                 :        176 :         job_uninstall(j);
     999                 :        176 :         job_free(j);
    1000                 :            : 
    1001                 :            :         /* Fail depending jobs on failure */
    1002   [ +  +  -  + ]:        176 :         if (result != JOB_DONE && recursive) {
    1003   [ #  #  #  # ]:          0 :                 if (IN_SET(t, JOB_START, JOB_VERIFY_ACTIVE)) {
    1004                 :          0 :                         job_fail_dependencies(u, UNIT_REQUIRED_BY);
    1005                 :          0 :                         job_fail_dependencies(u, UNIT_REQUISITE_OF);
    1006                 :          0 :                         job_fail_dependencies(u, UNIT_BOUND_BY);
    1007         [ #  # ]:          0 :                 } else if (t == JOB_STOP)
    1008                 :          0 :                         job_fail_dependencies(u, UNIT_CONFLICTED_BY);
    1009                 :            :         }
    1010                 :            : 
    1011                 :            :         /* A special check to make sure we take down anything RequisiteOf if we
    1012                 :            :          * aren't active. This is when the verify-active job merges with a
    1013                 :            :          * satisfying job type, and then loses it's invalidation effect, as the
    1014                 :            :          * result there is JOB_DONE for the start job we merged into, while we
    1015                 :            :          * should be failing the depending job if the said unit isn't infact
    1016                 :            :          * active. Oneshots are an example of this, where going directly from
    1017                 :            :          * activating to inactive is success.
    1018                 :            :          *
    1019                 :            :          * This happens when you use ConditionXYZ= in a unit too, since in that
    1020                 :            :          * case the job completes with the JOB_DONE result, but the unit never
    1021                 :            :          * really becomes active. Note that such a case still involves merging:
    1022                 :            :          *
    1023                 :            :          * A start job waits for something else, and a verify-active comes in
    1024                 :            :          * and merges in the installed job. Then, later, when it becomes
    1025                 :            :          * runnable, it finishes with JOB_DONE result as execution on conditions
    1026                 :            :          * not being met is skipped, breaking our dependency semantics.
    1027                 :            :          *
    1028                 :            :          * Also, depending on if start job waits or not, the merging may or may
    1029                 :            :          * not happen (the verify-active job may trigger after it finishes), so
    1030                 :            :          * you get undeterministic results without this check.
    1031                 :            :          */
    1032   [ +  +  +  -  :        176 :         if (result == JOB_DONE && recursive && !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) {
                   -  + ]
    1033   [ #  #  #  # ]:          0 :                 if (IN_SET(t, JOB_START, JOB_RELOAD))
    1034                 :          0 :                         job_fail_dependencies(u, UNIT_REQUISITE_OF);
    1035                 :            :         }
    1036                 :            :         /* Trigger OnFailure dependencies that are not generated by
    1037                 :            :          * the unit itself. We don't treat JOB_CANCELED as failure in
    1038                 :            :          * this context. And JOB_FAILURE is already handled by the
    1039                 :            :          * unit itself. */
    1040   [ -  +  -  + ]:        176 :         if (IN_SET(result, JOB_TIMEOUT, JOB_DEPENDENCY)) {
    1041                 :          0 :                 log_struct(LOG_NOTICE,
    1042                 :            :                            "JOB_TYPE=%s", job_type_to_string(t),
    1043                 :            :                            "JOB_RESULT=%s", job_result_to_string(result),
    1044                 :            :                            LOG_UNIT_ID(u),
    1045                 :            :                            LOG_UNIT_MESSAGE(u, "Job %s/%s failed with result '%s'.",
    1046                 :            :                                             u->id,
    1047                 :            :                                             job_type_to_string(t),
    1048                 :            :                                             job_result_to_string(result)));
    1049                 :            : 
    1050                 :          0 :                 unit_start_on_failure(u);
    1051                 :            :         }
    1052                 :            : 
    1053                 :        176 :         unit_trigger_notify(u);
    1054                 :            : 
    1055                 :        176 : finish:
    1056                 :            :         /* Try to start the next jobs that can be started */
    1057         [ +  + ]:        704 :         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_AFTER], i)
    1058         [ +  + ]:        528 :                 if (other->job) {
    1059                 :         56 :                         job_add_to_run_queue(other->job);
    1060                 :         56 :                         job_add_to_gc_queue(other->job);
    1061                 :            :                 }
    1062         [ +  + ]:        552 :         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BEFORE], i)
    1063         [ +  + ]:        376 :                 if (other->job) {
    1064                 :        116 :                         job_add_to_run_queue(other->job);
    1065                 :        116 :                         job_add_to_gc_queue(other->job);
    1066                 :            :                 }
    1067                 :            : 
    1068                 :        176 :         manager_check_finished(u->manager);
    1069                 :            : 
    1070                 :        176 :         return 0;
    1071                 :            : }
    1072                 :            : 
    1073                 :          0 : static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *userdata) {
    1074                 :          0 :         Job *j = userdata;
    1075                 :            :         Unit *u;
    1076                 :            : 
    1077         [ #  # ]:          0 :         assert(j);
    1078         [ #  # ]:          0 :         assert(s == j->timer_event_source);
    1079                 :            : 
    1080         [ #  # ]:          0 :         log_unit_warning(j->unit, "Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
    1081                 :            : 
    1082                 :          0 :         u = j->unit;
    1083                 :          0 :         job_finish_and_invalidate(j, JOB_TIMEOUT, true, false);
    1084                 :            : 
    1085                 :          0 :         emergency_action(u->manager, u->job_timeout_action,
    1086                 :            :                          EMERGENCY_ACTION_IS_WATCHDOG|EMERGENCY_ACTION_WARN,
    1087                 :          0 :                          u->job_timeout_reboot_arg, -1, "job timed out");
    1088                 :            : 
    1089                 :          0 :         return 0;
    1090                 :            : }
    1091                 :            : 
    1092                 :        368 : int job_start_timer(Job *j, bool job_running) {
    1093                 :            :         int r;
    1094                 :            :         usec_t timeout_time, old_timeout_time;
    1095                 :            : 
    1096         [ +  + ]:        368 :         if (job_running) {
    1097                 :         96 :                 j->begin_running_usec = now(CLOCK_MONOTONIC);
    1098                 :            : 
    1099         [ +  - ]:         96 :                 if (j->unit->job_running_timeout == USEC_INFINITY)
    1100                 :         96 :                         return 0;
    1101                 :            : 
    1102                 :          0 :                 timeout_time = usec_add(j->begin_running_usec, j->unit->job_running_timeout);
    1103                 :            : 
    1104         [ #  # ]:          0 :                 if (j->timer_event_source) {
    1105                 :            :                         /* Update only if JobRunningTimeoutSec= results in earlier timeout */
    1106                 :          0 :                         r = sd_event_source_get_time(j->timer_event_source, &old_timeout_time);
    1107         [ #  # ]:          0 :                         if (r < 0)
    1108                 :          0 :                                 return r;
    1109                 :            : 
    1110         [ #  # ]:          0 :                         if (old_timeout_time <= timeout_time)
    1111                 :          0 :                                 return 0;
    1112                 :            : 
    1113                 :          0 :                         return sd_event_source_set_time(j->timer_event_source, timeout_time);
    1114                 :            :                 }
    1115                 :            :         } else {
    1116         [ -  + ]:        272 :                 if (j->timer_event_source)
    1117                 :          0 :                         return 0;
    1118                 :            : 
    1119                 :        272 :                 j->begin_usec = now(CLOCK_MONOTONIC);
    1120                 :            : 
    1121         [ +  - ]:        272 :                 if (j->unit->job_timeout == USEC_INFINITY)
    1122                 :        272 :                         return 0;
    1123                 :            : 
    1124                 :          0 :                 timeout_time = usec_add(j->begin_usec, j->unit->job_timeout);
    1125                 :            :         }
    1126                 :            : 
    1127                 :          0 :         r = sd_event_add_time(
    1128                 :          0 :                         j->manager->event,
    1129                 :            :                         &j->timer_event_source,
    1130                 :            :                         CLOCK_MONOTONIC,
    1131                 :            :                         timeout_time, 0,
    1132                 :            :                         job_dispatch_timer, j);
    1133         [ #  # ]:          0 :         if (r < 0)
    1134                 :          0 :                 return r;
    1135                 :            : 
    1136                 :          0 :         (void) sd_event_source_set_description(j->timer_event_source, "job-start");
    1137                 :            : 
    1138                 :          0 :         return 0;
    1139                 :            : }
    1140                 :            : 
    1141                 :        444 : void job_add_to_run_queue(Job *j) {
    1142                 :            :         int r;
    1143                 :            : 
    1144         [ -  + ]:        444 :         assert(j);
    1145         [ -  + ]:        444 :         assert(j->installed);
    1146                 :            : 
    1147         [ +  + ]:        444 :         if (j->in_run_queue)
    1148                 :        196 :                 return;
    1149                 :            : 
    1150         [ +  + ]:        248 :         if (prioq_isempty(j->manager->run_queue)) {
    1151                 :         36 :                 r = sd_event_source_set_enabled(j->manager->run_queue_event_source, SD_EVENT_ONESHOT);
    1152         [ -  + ]:         36 :                 if (r < 0)
    1153         [ #  # ]:          0 :                         log_warning_errno(r, "Failed to enable job run queue event source, ignoring: %m");
    1154                 :            :         }
    1155                 :            : 
    1156                 :        248 :         r = prioq_put(j->manager->run_queue, j, &j->run_queue_idx);
    1157         [ -  + ]:        248 :         if (r < 0)
    1158         [ #  # ]:          0 :                 log_warning_errno(r, "Failed put job in run queue, ignoring: %m");
    1159                 :            :         else
    1160                 :        248 :                 j->in_run_queue = true;
    1161                 :            : }
    1162                 :            : 
    1163                 :        568 : void job_add_to_dbus_queue(Job *j) {
    1164         [ -  + ]:        568 :         assert(j);
    1165         [ -  + ]:        568 :         assert(j->installed);
    1166                 :            : 
    1167         [ +  + ]:        568 :         if (j->in_dbus_queue)
    1168                 :        368 :                 return;
    1169                 :            : 
    1170                 :            :         /* We don't check if anybody is subscribed here, since this
    1171                 :            :          * job might just have been created and not yet assigned to a
    1172                 :            :          * connection/client. */
    1173                 :            : 
    1174   [ -  +  +  + ]:        200 :         LIST_PREPEND(dbus_queue, j->manager->dbus_job_queue, j);
    1175                 :        200 :         j->in_dbus_queue = true;
    1176                 :            : }
    1177                 :            : 
    1178                 :          0 : char *job_dbus_path(Job *j) {
    1179                 :            :         char *p;
    1180                 :            : 
    1181         [ #  # ]:          0 :         assert(j);
    1182                 :            : 
    1183         [ #  # ]:          0 :         if (asprintf(&p, "/org/freedesktop/systemd1/job/%"PRIu32, j->id) < 0)
    1184                 :          0 :                 return NULL;
    1185                 :            : 
    1186                 :          0 :         return p;
    1187                 :            : }
    1188                 :            : 
    1189                 :          0 : int job_serialize(Job *j, FILE *f) {
    1190         [ #  # ]:          0 :         assert(j);
    1191         [ #  # ]:          0 :         assert(f);
    1192                 :            : 
    1193                 :          0 :         (void) serialize_item_format(f, "job-id", "%u", j->id);
    1194                 :          0 :         (void) serialize_item(f, "job-type", job_type_to_string(j->type));
    1195                 :          0 :         (void) serialize_item(f, "job-state", job_state_to_string(j->state));
    1196                 :          0 :         (void) serialize_bool(f, "job-irreversible", j->irreversible);
    1197                 :          0 :         (void) serialize_bool(f, "job-sent-dbus-new-signal", j->sent_dbus_new_signal);
    1198                 :          0 :         (void) serialize_bool(f, "job-ignore-order", j->ignore_order);
    1199                 :            : 
    1200         [ #  # ]:          0 :         if (j->begin_usec > 0)
    1201                 :          0 :                 (void) serialize_usec(f, "job-begin", j->begin_usec);
    1202         [ #  # ]:          0 :         if (j->begin_running_usec > 0)
    1203                 :          0 :                 (void) serialize_usec(f, "job-begin-running", j->begin_running_usec);
    1204                 :            : 
    1205                 :          0 :         bus_track_serialize(j->bus_track, f, "subscribed");
    1206                 :            : 
    1207                 :            :         /* End marker */
    1208                 :          0 :         fputc('\n', f);
    1209                 :          0 :         return 0;
    1210                 :            : }
    1211                 :            : 
    1212                 :          0 : int job_deserialize(Job *j, FILE *f) {
    1213                 :            :         int r;
    1214                 :            : 
    1215         [ #  # ]:          0 :         assert(j);
    1216         [ #  # ]:          0 :         assert(f);
    1217                 :            : 
    1218                 :          0 :         for (;;) {
    1219         [ #  # ]:          0 :                 _cleanup_free_ char *line = NULL;
    1220                 :            :                 char *l, *v;
    1221                 :            :                 size_t k;
    1222                 :            : 
    1223                 :          0 :                 r = read_line(f, LONG_LINE_MAX, &line);
    1224         [ #  # ]:          0 :                 if (r < 0)
    1225         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to read serialization line: %m");
    1226         [ #  # ]:          0 :                 if (r == 0)
    1227                 :          0 :                         return 0;
    1228                 :            : 
    1229                 :          0 :                 l = strstrip(line);
    1230                 :            : 
    1231                 :            :                 /* End marker */
    1232         [ #  # ]:          0 :                 if (isempty(l))
    1233                 :          0 :                         return 0;
    1234                 :            : 
    1235                 :          0 :                 k = strcspn(l, "=");
    1236                 :            : 
    1237         [ #  # ]:          0 :                 if (l[k] == '=') {
    1238                 :          0 :                         l[k] = 0;
    1239                 :          0 :                         v = l+k+1;
    1240                 :            :                 } else
    1241                 :          0 :                         v = l+k;
    1242                 :            : 
    1243         [ #  # ]:          0 :                 if (streq(l, "job-id")) {
    1244                 :            : 
    1245         [ #  # ]:          0 :                         if (safe_atou32(v, &j->id) < 0)
    1246         [ #  # ]:          0 :                                 log_debug("Failed to parse job id value: %s", v);
    1247                 :            : 
    1248         [ #  # ]:          0 :                 } else if (streq(l, "job-type")) {
    1249                 :            :                         JobType t;
    1250                 :            : 
    1251                 :          0 :                         t = job_type_from_string(v);
    1252         [ #  # ]:          0 :                         if (t < 0)
    1253         [ #  # ]:          0 :                                 log_debug("Failed to parse job type: %s", v);
    1254         [ #  # ]:          0 :                         else if (t >= _JOB_TYPE_MAX_IN_TRANSACTION)
    1255         [ #  # ]:          0 :                                 log_debug("Cannot deserialize job of type: %s", v);
    1256                 :            :                         else
    1257                 :          0 :                                 j->type = t;
    1258                 :            : 
    1259         [ #  # ]:          0 :                 } else if (streq(l, "job-state")) {
    1260                 :            :                         JobState s;
    1261                 :            : 
    1262                 :          0 :                         s = job_state_from_string(v);
    1263         [ #  # ]:          0 :                         if (s < 0)
    1264         [ #  # ]:          0 :                                 log_debug("Failed to parse job state: %s", v);
    1265                 :            :                         else
    1266                 :          0 :                                 job_set_state(j, s);
    1267                 :            : 
    1268         [ #  # ]:          0 :                 } else if (streq(l, "job-irreversible")) {
    1269                 :            :                         int b;
    1270                 :            : 
    1271                 :          0 :                         b = parse_boolean(v);
    1272         [ #  # ]:          0 :                         if (b < 0)
    1273         [ #  # ]:          0 :                                 log_debug("Failed to parse job irreversible flag: %s", v);
    1274                 :            :                         else
    1275   [ #  #  #  # ]:          0 :                                 j->irreversible = j->irreversible || b;
    1276                 :            : 
    1277         [ #  # ]:          0 :                 } else if (streq(l, "job-sent-dbus-new-signal")) {
    1278                 :            :                         int b;
    1279                 :            : 
    1280                 :          0 :                         b = parse_boolean(v);
    1281         [ #  # ]:          0 :                         if (b < 0)
    1282         [ #  # ]:          0 :                                 log_debug("Failed to parse job sent_dbus_new_signal flag: %s", v);
    1283                 :            :                         else
    1284   [ #  #  #  # ]:          0 :                                 j->sent_dbus_new_signal = j->sent_dbus_new_signal || b;
    1285                 :            : 
    1286         [ #  # ]:          0 :                 } else if (streq(l, "job-ignore-order")) {
    1287                 :            :                         int b;
    1288                 :            : 
    1289                 :          0 :                         b = parse_boolean(v);
    1290         [ #  # ]:          0 :                         if (b < 0)
    1291         [ #  # ]:          0 :                                 log_debug("Failed to parse job ignore_order flag: %s", v);
    1292                 :            :                         else
    1293   [ #  #  #  # ]:          0 :                                 j->ignore_order = j->ignore_order || b;
    1294                 :            : 
    1295         [ #  # ]:          0 :                 } else if (streq(l, "job-begin"))
    1296                 :          0 :                         (void) deserialize_usec(v, &j->begin_usec);
    1297                 :            : 
    1298         [ #  # ]:          0 :                 else if (streq(l, "job-begin-running"))
    1299                 :          0 :                         (void) deserialize_usec(v, &j->begin_running_usec);
    1300                 :            : 
    1301         [ #  # ]:          0 :                 else if (streq(l, "subscribed")) {
    1302         [ #  # ]:          0 :                         if (strv_extend(&j->deserialized_clients, v) < 0)
    1303                 :          0 :                                 return log_oom();
    1304                 :            :                 } else
    1305         [ #  # ]:          0 :                         log_debug("Unknown job serialization key: %s", l);
    1306                 :            :         }
    1307                 :            : }
    1308                 :            : 
    1309                 :          0 : int job_coldplug(Job *j) {
    1310                 :            :         int r;
    1311                 :          0 :         usec_t timeout_time = USEC_INFINITY;
    1312                 :            : 
    1313         [ #  # ]:          0 :         assert(j);
    1314                 :            : 
    1315                 :            :         /* After deserialization is complete and the bus connection
    1316                 :            :          * set up again, let's start watching our subscribers again */
    1317                 :          0 :         (void) bus_job_coldplug_bus_track(j);
    1318                 :            : 
    1319         [ #  # ]:          0 :         if (j->state == JOB_WAITING)
    1320                 :          0 :                 job_add_to_run_queue(j);
    1321                 :            : 
    1322                 :            :         /* Maybe due to new dependencies we don't actually need this job anymore? */
    1323                 :          0 :         job_add_to_gc_queue(j);
    1324                 :            : 
    1325                 :            :         /* Create timer only when job began or began running and the respective timeout is finite.
    1326                 :            :          * Follow logic of job_start_timer() if both timeouts are finite */
    1327         [ #  # ]:          0 :         if (j->begin_usec == 0)
    1328                 :          0 :                 return 0;
    1329                 :            : 
    1330         [ #  # ]:          0 :         if (j->unit->job_timeout != USEC_INFINITY)
    1331                 :          0 :                 timeout_time = usec_add(j->begin_usec, j->unit->job_timeout);
    1332                 :            : 
    1333         [ #  # ]:          0 :         if (timestamp_is_set(j->begin_running_usec))
    1334                 :          0 :                 timeout_time = MIN(timeout_time, usec_add(j->begin_running_usec, j->unit->job_running_timeout));
    1335                 :            : 
    1336         [ #  # ]:          0 :         if (timeout_time == USEC_INFINITY)
    1337                 :          0 :                 return 0;
    1338                 :            : 
    1339                 :          0 :         j->timer_event_source = sd_event_source_unref(j->timer_event_source);
    1340                 :            : 
    1341                 :          0 :         r = sd_event_add_time(
    1342                 :          0 :                         j->manager->event,
    1343                 :            :                         &j->timer_event_source,
    1344                 :            :                         CLOCK_MONOTONIC,
    1345                 :            :                         timeout_time, 0,
    1346                 :            :                         job_dispatch_timer, j);
    1347         [ #  # ]:          0 :         if (r < 0)
    1348         [ #  # ]:          0 :                 log_debug_errno(r, "Failed to restart timeout for job: %m");
    1349                 :            : 
    1350                 :          0 :         (void) sd_event_source_set_description(j->timer_event_source, "job-timeout");
    1351                 :            : 
    1352                 :          0 :         return r;
    1353                 :            : }
    1354                 :            : 
    1355                 :        272 : void job_shutdown_magic(Job *j) {
    1356         [ -  + ]:        272 :         assert(j);
    1357                 :            : 
    1358                 :            :         /* The shutdown target gets some special treatment here: we
    1359                 :            :          * tell the kernel to begin with flushing its disk caches, to
    1360                 :            :          * optimize shutdown time a bit. Ideally we wouldn't hardcode
    1361                 :            :          * this magic into PID 1. However all other processes aren't
    1362                 :            :          * options either since they'd exit much sooner than PID 1 and
    1363                 :            :          * asynchronous sync() would cause their exit to be
    1364                 :            :          * delayed. */
    1365                 :            : 
    1366         [ +  + ]:        272 :         if (j->type != JOB_START)
    1367                 :         20 :                 return;
    1368                 :            : 
    1369         [ +  - ]:        252 :         if (!MANAGER_IS_SYSTEM(j->unit->manager))
    1370                 :        252 :                 return;
    1371                 :            : 
    1372         [ #  # ]:          0 :         if (!unit_has_name(j->unit, SPECIAL_SHUTDOWN_TARGET))
    1373                 :          0 :                 return;
    1374                 :            : 
    1375                 :            :         /* In case messages on console has been disabled on boot */
    1376                 :          0 :         j->unit->manager->no_console_output = false;
    1377                 :            : 
    1378         [ #  # ]:          0 :         if (detect_container() > 0)
    1379                 :          0 :                 return;
    1380                 :            : 
    1381                 :          0 :         (void) asynchronous_sync(NULL);
    1382                 :            : }
    1383                 :            : 
    1384                 :          0 : int job_get_timeout(Job *j, usec_t *timeout) {
    1385                 :          0 :         usec_t x = USEC_INFINITY, y = USEC_INFINITY;
    1386                 :          0 :         Unit *u = j->unit;
    1387                 :            :         int r;
    1388                 :            : 
    1389         [ #  # ]:          0 :         assert(u);
    1390                 :            : 
    1391         [ #  # ]:          0 :         if (j->timer_event_source) {
    1392                 :          0 :                 r = sd_event_source_get_time(j->timer_event_source, &x);
    1393         [ #  # ]:          0 :                 if (r < 0)
    1394                 :          0 :                         return r;
    1395                 :            :         }
    1396                 :            : 
    1397         [ #  # ]:          0 :         if (UNIT_VTABLE(u)->get_timeout) {
    1398                 :          0 :                 r = UNIT_VTABLE(u)->get_timeout(u, &y);
    1399         [ #  # ]:          0 :                 if (r < 0)
    1400                 :          0 :                         return r;
    1401                 :            :         }
    1402                 :            : 
    1403   [ #  #  #  # ]:          0 :         if (x == USEC_INFINITY && y == USEC_INFINITY)
    1404                 :          0 :                 return 0;
    1405                 :            : 
    1406                 :          0 :         *timeout = MIN(x, y);
    1407                 :          0 :         return 1;
    1408                 :            : }
    1409                 :            : 
    1410                 :        624 : bool job_may_gc(Job *j) {
    1411                 :            :         Unit *other;
    1412                 :            :         Iterator i;
    1413                 :            :         void *v;
    1414                 :            : 
    1415         [ -  + ]:        624 :         assert(j);
    1416                 :            : 
    1417                 :            :         /* Checks whether this job should be GC'ed away. We only do this for jobs of units that have no effect on their
    1418                 :            :          * own and just track external state. For now the only unit type that qualifies for this are .device units.
    1419                 :            :          * Returns true if the job can be collected. */
    1420                 :            : 
    1421         [ +  - ]:        624 :         if (!UNIT_VTABLE(j->unit)->gc_jobs)
    1422                 :        624 :                 return false;
    1423                 :            : 
    1424         [ #  # ]:          0 :         if (sd_bus_track_count(j->bus_track) > 0)
    1425                 :          0 :                 return false;
    1426                 :            : 
    1427                 :            :         /* FIXME: So this is a bit ugly: for now we don't properly track references made via private bus connections
    1428                 :            :          * (because it's nasty, as sd_bus_track doesn't apply to it). We simply remember that the job was once
    1429                 :            :          * referenced by one, and reset this whenever we notice that no private bus connections are around. This means
    1430                 :            :          * the GC is a bit too conservative when it comes to jobs created by private bus connections. */
    1431         [ #  # ]:          0 :         if (j->ref_by_private_bus) {
    1432         [ #  # ]:          0 :                 if (set_isempty(j->unit->manager->private_buses))
    1433                 :          0 :                         j->ref_by_private_bus = false;
    1434                 :            :                 else
    1435                 :          0 :                         return false;
    1436                 :            :         }
    1437                 :            : 
    1438         [ #  # ]:          0 :         if (j->type == JOB_NOP)
    1439                 :          0 :                 return false;
    1440                 :            : 
    1441                 :            :         /* The logic is inverse to job_is_runnable, we cannot GC as long as we block any job. */
    1442         [ #  # ]:          0 :         HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i)
    1443   [ #  #  #  # ]:          0 :                 if (other->job && job_compare(j, other->job, UNIT_BEFORE) < 0)
    1444                 :          0 :                         return false;
    1445                 :            : 
    1446         [ #  # ]:          0 :         HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i)
    1447   [ #  #  #  # ]:          0 :                 if (other->job && job_compare(j, other->job, UNIT_AFTER) < 0)
    1448                 :          0 :                         return false;
    1449                 :            : 
    1450                 :          0 :         return true;
    1451                 :            : }
    1452                 :            : 
    1453                 :        372 : void job_add_to_gc_queue(Job *j) {
    1454         [ -  + ]:        372 :         assert(j);
    1455                 :            : 
    1456         [ -  + ]:        372 :         if (j->in_gc_queue)
    1457                 :          0 :                 return;
    1458                 :            : 
    1459         [ +  - ]:        372 :         if (!job_may_gc(j))
    1460                 :        372 :                 return;
    1461                 :            : 
    1462   [ #  #  #  # ]:          0 :         LIST_PREPEND(gc_queue, j->unit->manager->gc_job_queue, j);
    1463                 :          0 :         j->in_gc_queue = true;
    1464                 :            : }
    1465                 :            : 
    1466                 :          0 : static int job_compare_id(Job * const *a, Job * const *b) {
    1467         [ #  # ]:          0 :         return CMP((*a)->id, (*b)->id);
    1468                 :            : }
    1469                 :            : 
    1470                 :          0 : static size_t sort_job_list(Job **list, size_t n) {
    1471                 :          0 :         Job *previous = NULL;
    1472                 :            :         size_t a, b;
    1473                 :            : 
    1474                 :            :         /* Order by numeric IDs */
    1475                 :          0 :         typesafe_qsort(list, n, job_compare_id);
    1476                 :            : 
    1477                 :            :         /* Filter out duplicates */
    1478         [ #  # ]:          0 :         for (a = 0, b = 0; a < n; a++) {
    1479                 :            : 
    1480         [ #  # ]:          0 :                 if (previous == list[a])
    1481                 :          0 :                         continue;
    1482                 :            : 
    1483                 :          0 :                 previous = list[b++] = list[a];
    1484                 :            :         }
    1485                 :            : 
    1486                 :          0 :         return b;
    1487                 :            : }
    1488                 :            : 
    1489                 :          0 : int job_get_before(Job *j, Job*** ret) {
    1490                 :          0 :         _cleanup_free_ Job** list = NULL;
    1491                 :          0 :         size_t n = 0, n_allocated = 0;
    1492                 :          0 :         Unit *other = NULL;
    1493                 :            :         Iterator i;
    1494                 :            :         void *v;
    1495                 :            : 
    1496                 :            :         /* Returns a list of all pending jobs that need to finish before this job may be started. */
    1497                 :            : 
    1498         [ #  # ]:          0 :         assert(j);
    1499         [ #  # ]:          0 :         assert(ret);
    1500                 :            : 
    1501         [ #  # ]:          0 :         if (j->ignore_order) {
    1502                 :          0 :                 *ret = NULL;
    1503                 :          0 :                 return 0;
    1504                 :            :         }
    1505                 :            : 
    1506         [ #  # ]:          0 :         HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i) {
    1507         [ #  # ]:          0 :                 if (!other->job)
    1508                 :          0 :                         continue;
    1509         [ #  # ]:          0 :                 if (job_compare(j, other->job, UNIT_AFTER) <= 0)
    1510                 :          0 :                         continue;
    1511                 :            : 
    1512         [ #  # ]:          0 :                 if (!GREEDY_REALLOC(list, n_allocated, n+1))
    1513                 :          0 :                         return -ENOMEM;
    1514                 :          0 :                 list[n++] = other->job;
    1515                 :            :         }
    1516                 :            : 
    1517         [ #  # ]:          0 :         HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i) {
    1518         [ #  # ]:          0 :                 if (!other->job)
    1519                 :          0 :                         continue;
    1520         [ #  # ]:          0 :                 if (job_compare(j, other->job, UNIT_BEFORE) <= 0)
    1521                 :          0 :                         continue;
    1522                 :            : 
    1523         [ #  # ]:          0 :                 if (!GREEDY_REALLOC(list, n_allocated, n+1))
    1524                 :          0 :                         return -ENOMEM;
    1525                 :          0 :                 list[n++] = other->job;
    1526                 :            :         }
    1527                 :            : 
    1528                 :          0 :         n = sort_job_list(list, n);
    1529                 :            : 
    1530                 :          0 :         *ret = TAKE_PTR(list);
    1531                 :            : 
    1532                 :          0 :         return (int) n;
    1533                 :            : }
    1534                 :            : 
    1535                 :          0 : int job_get_after(Job *j, Job*** ret) {
    1536                 :          0 :         _cleanup_free_ Job** list = NULL;
    1537                 :          0 :         size_t n = 0, n_allocated = 0;
    1538                 :          0 :         Unit *other = NULL;
    1539                 :            :         void *v;
    1540                 :            :         Iterator i;
    1541                 :            : 
    1542         [ #  # ]:          0 :         assert(j);
    1543         [ #  # ]:          0 :         assert(ret);
    1544                 :            : 
    1545                 :            :         /* Returns a list of all pending jobs that are waiting for this job to finish. */
    1546                 :            : 
    1547         [ #  # ]:          0 :         HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i) {
    1548         [ #  # ]:          0 :                 if (!other->job)
    1549                 :          0 :                         continue;
    1550                 :            : 
    1551         [ #  # ]:          0 :                 if (other->job->ignore_order)
    1552                 :          0 :                         continue;
    1553                 :            : 
    1554         [ #  # ]:          0 :                 if (job_compare(j, other->job, UNIT_BEFORE) >= 0)
    1555                 :          0 :                         continue;
    1556                 :            : 
    1557         [ #  # ]:          0 :                 if (!GREEDY_REALLOC(list, n_allocated, n+1))
    1558                 :          0 :                         return -ENOMEM;
    1559                 :          0 :                 list[n++] = other->job;
    1560                 :            :         }
    1561                 :            : 
    1562         [ #  # ]:          0 :         HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i) {
    1563         [ #  # ]:          0 :                 if (!other->job)
    1564                 :          0 :                         continue;
    1565                 :            : 
    1566         [ #  # ]:          0 :                 if (other->job->ignore_order)
    1567                 :          0 :                         continue;
    1568                 :            : 
    1569         [ #  # ]:          0 :                 if (job_compare(j, other->job, UNIT_AFTER) >= 0)
    1570                 :          0 :                         continue;
    1571                 :            : 
    1572         [ #  # ]:          0 :                 if (!GREEDY_REALLOC(list, n_allocated, n+1))
    1573                 :          0 :                         return -ENOMEM;
    1574                 :          0 :                 list[n++] = other->job;
    1575                 :            :         }
    1576                 :            : 
    1577                 :          0 :         n = sort_job_list(list, n);
    1578                 :            : 
    1579                 :          0 :         *ret = TAKE_PTR(list);
    1580                 :            : 
    1581                 :          0 :         return (int) n;
    1582                 :            : }
    1583                 :            : 
    1584                 :            : static const char* const job_state_table[_JOB_STATE_MAX] = {
    1585                 :            :         [JOB_WAITING] = "waiting",
    1586                 :            :         [JOB_RUNNING] = "running",
    1587                 :            : };
    1588                 :            : 
    1589   [ +  +  +  + ]:        284 : DEFINE_STRING_TABLE_LOOKUP(job_state, JobState);
    1590                 :            : 
    1591                 :            : static const char* const job_type_table[_JOB_TYPE_MAX] = {
    1592                 :            :         [JOB_START] = "start",
    1593                 :            :         [JOB_VERIFY_ACTIVE] = "verify-active",
    1594                 :            :         [JOB_STOP] = "stop",
    1595                 :            :         [JOB_RELOAD] = "reload",
    1596                 :            :         [JOB_RELOAD_OR_START] = "reload-or-start",
    1597                 :            :         [JOB_RESTART] = "restart",
    1598                 :            :         [JOB_TRY_RESTART] = "try-restart",
    1599                 :            :         [JOB_TRY_RELOAD] = "try-reload",
    1600                 :            :         [JOB_NOP] = "nop",
    1601                 :            : };
    1602                 :            : 
    1603   [ +  +  +  + ]:       7120 : DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
    1604                 :            : 
    1605                 :            : static const char* const job_mode_table[_JOB_MODE_MAX] = {
    1606                 :            :         [JOB_FAIL] = "fail",
    1607                 :            :         [JOB_REPLACE] = "replace",
    1608                 :            :         [JOB_REPLACE_IRREVERSIBLY] = "replace-irreversibly",
    1609                 :            :         [JOB_ISOLATE] = "isolate",
    1610                 :            :         [JOB_FLUSH] = "flush",
    1611                 :            :         [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
    1612                 :            :         [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements",
    1613                 :            : };
    1614                 :            : 
    1615   [ +  +  +  + ]:       4208 : DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);
    1616                 :            : 
    1617                 :            : static const char* const job_result_table[_JOB_RESULT_MAX] = {
    1618                 :            :         [JOB_DONE] = "done",
    1619                 :            :         [JOB_CANCELED] = "canceled",
    1620                 :            :         [JOB_TIMEOUT] = "timeout",
    1621                 :            :         [JOB_FAILED] = "failed",
    1622                 :            :         [JOB_DEPENDENCY] = "dependency",
    1623                 :            :         [JOB_SKIPPED] = "skipped",
    1624                 :            :         [JOB_INVALID] = "invalid",
    1625                 :            :         [JOB_ASSERT] = "assert",
    1626                 :            :         [JOB_UNSUPPORTED] = "unsupported",
    1627                 :            :         [JOB_COLLECTED] = "collected",
    1628                 :            :         [JOB_ONCE] = "once",
    1629                 :            : };
    1630                 :            : 
    1631   [ +  +  +  + ]:        280 : DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);
    1632                 :            : 
    1633                 :          0 : const char* job_type_to_access_method(JobType t) {
    1634         [ #  # ]:          0 :         assert(t >= 0);
    1635         [ #  # ]:          0 :         assert(t < _JOB_TYPE_MAX);
    1636                 :            : 
    1637   [ #  #  #  # ]:          0 :         if (IN_SET(t, JOB_START, JOB_RESTART, JOB_TRY_RESTART))
    1638                 :          0 :                 return "start";
    1639         [ #  # ]:          0 :         else if (t == JOB_STOP)
    1640                 :          0 :                 return "stop";
    1641                 :            :         else
    1642                 :          0 :                 return "reload";
    1643                 :            : }
    1644                 :            : 
    1645                 :            : /*
    1646                 :            :  * assume_dep   assumed dependency between units (a is before/after b)
    1647                 :            :  *
    1648                 :            :  * Returns
    1649                 :            :  *    0         jobs are independent,
    1650                 :            :  *   >0         a should run after b,
    1651                 :            :  *   <0         a should run before b,
    1652                 :            :  *
    1653                 :            :  * The logic means that for a service a and a service b where b.After=a:
    1654                 :            :  *
    1655                 :            :  *  start a + start b → 1st step start a, 2nd step start b
    1656                 :            :  *  start a + stop b  → 1st step stop b,  2nd step start a
    1657                 :            :  *  stop a  + start b → 1st step stop a,  2nd step start b
    1658                 :            :  *  stop a  + stop b  → 1st step stop b,  2nd step stop a
    1659                 :            :  *
    1660                 :            :  *  This has the side effect that restarts are properly
    1661                 :            :  *  synchronized too.
    1662                 :            :  */
    1663                 :       1006 : int job_compare(Job *a, Job *b, UnitDependency assume_dep) {
    1664         [ -  + ]:       1006 :         assert(a->type < _JOB_TYPE_MAX_IN_TRANSACTION);
    1665         [ -  + ]:       1006 :         assert(b->type < _JOB_TYPE_MAX_IN_TRANSACTION);
    1666   [ +  -  -  + ]:       1006 :         assert(IN_SET(assume_dep, UNIT_AFTER, UNIT_BEFORE));
    1667                 :            : 
    1668                 :            :         /* Trivial cases first */
    1669   [ +  -  -  + ]:       1006 :         if (a->type == JOB_NOP || b->type == JOB_NOP)
    1670                 :          0 :                 return 0;
    1671                 :            : 
    1672   [ +  -  -  + ]:       1006 :         if (a->ignore_order || b->ignore_order)
    1673                 :          0 :                 return 0;
    1674                 :            : 
    1675         [ +  + ]:       1006 :         if (assume_dep == UNIT_AFTER)
    1676                 :        307 :                 return -job_compare(b, a, UNIT_BEFORE);
    1677                 :            : 
    1678                 :            :         /* Let's make it simple, JOB_STOP goes always first (in case both ua and ub stop,
    1679                 :            :          * then ub's stop goes first anyway).
    1680                 :            :          * JOB_RESTART is JOB_STOP in disguise (before it is patched to JOB_START). */
    1681   [ +  +  +  + ]:        699 :         if (IN_SET(b->type, JOB_STOP, JOB_RESTART))
    1682                 :         92 :                 return 1;
    1683                 :            :         else
    1684                 :        607 :                 return -1;
    1685                 :            : }

Generated by: LCOV version 1.14