1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 #pragma once
3 
4 #include <stdbool.h>
5 
6 #include "sd-event.h"
7 
8 #include "list.h"
9 #include "unit-dependency-atom.h"
10 #include "unit-name.h"
11 #include "unit.h"
12 
13 typedef struct Job Job;
14 typedef struct JobDependency JobDependency;
15 typedef enum JobType JobType;
16 typedef enum JobState JobState;
17 typedef enum JobMode JobMode;
18 typedef enum JobResult JobResult;
19 
20 /* Be careful when changing the job types! Adjust job_merging_table[] accordingly! */
21 enum JobType {
22         JOB_START,                  /* if a unit does not support being started, we'll just wait until it becomes active */
23         JOB_VERIFY_ACTIVE,
24 
25         JOB_STOP,
26 
27         JOB_RELOAD,                 /* if running, reload */
28 
29         /* Note that restarts are first treated like JOB_STOP, but
30          * then instead of finishing are patched to become
31          * JOB_START. */
32         JOB_RESTART,                /* If running, stop. Then start unconditionally. */
33 
34         _JOB_TYPE_MAX_MERGING,
35 
36         /* JOB_NOP can enter into a transaction, but as it won't pull in
37          * any dependencies and it uses the special 'nop_job' slot in Unit,
38          * it won't have to merge with anything (except possibly into another
39          * JOB_NOP, previously installed). JOB_NOP is special-cased in
40          * job_type_is_*() functions so that the transaction can be
41          * activated. */
42         JOB_NOP = _JOB_TYPE_MAX_MERGING, /* do nothing */
43 
44         _JOB_TYPE_MAX_IN_TRANSACTION,
45 
46         /* JOB_TRY_RESTART can never appear in a transaction, because
47          * it always collapses into JOB_RESTART or JOB_NOP before entering.
48          * Thus we never need to merge it with anything. */
49         JOB_TRY_RESTART = _JOB_TYPE_MAX_IN_TRANSACTION, /* if running, stop and then start */
50 
51         /* Similar to JOB_TRY_RESTART but collapses to JOB_RELOAD or JOB_NOP */
52         JOB_TRY_RELOAD,
53 
54         /* JOB_RELOAD_OR_START won't enter into a transaction and cannot result
55          * from transaction merging (there's no way for JOB_RELOAD and
56          * JOB_START to meet in one transaction). It can result from a merge
57          * during job installation, but then it will immediately collapse into
58          * one of the two simpler types. */
59         JOB_RELOAD_OR_START,        /* if running, reload, otherwise start */
60 
61         _JOB_TYPE_MAX,
62         _JOB_TYPE_INVALID = -EINVAL,
63 };
64 
65 enum JobState {
66         JOB_WAITING,
67         JOB_RUNNING,
68         _JOB_STATE_MAX,
69         _JOB_STATE_INVALID = -EINVAL,
70 };
71 
72 enum JobMode {
73         JOB_FAIL,                /* Fail if a conflicting job is already queued */
74         JOB_REPLACE,             /* Replace an existing conflicting job */
75         JOB_REPLACE_IRREVERSIBLY,/* Like JOB_REPLACE + produce irreversible jobs */
76         JOB_ISOLATE,             /* Start a unit, and stop all others */
77         JOB_FLUSH,               /* Flush out all other queued jobs when queueing this one */
78         JOB_IGNORE_DEPENDENCIES, /* Ignore both requirement and ordering dependencies */
79         JOB_IGNORE_REQUIREMENTS, /* Ignore requirement dependencies */
80         JOB_TRIGGERING,          /* Adds TRIGGERED_BY dependencies to the same transaction */
81         _JOB_MODE_MAX,
82         _JOB_MODE_INVALID = -EINVAL,
83 };
84 
85 enum JobResult {
86         JOB_DONE,                /* Job completed successfully (or skipped due to a failed ConditionXYZ=) */
87         JOB_CANCELED,            /* Job canceled by a conflicting job installation or by explicit cancel request */
88         JOB_TIMEOUT,             /* Job timeout elapsed */
89         JOB_FAILED,              /* Job failed */
90         JOB_DEPENDENCY,          /* A required dependency job did not result in JOB_DONE */
91         JOB_SKIPPED,             /* Negative result of JOB_VERIFY_ACTIVE or skip due to ExecCondition= */
92         JOB_INVALID,             /* JOB_RELOAD of inactive unit */
93         JOB_ASSERT,              /* Couldn't start a unit, because an assert didn't hold */
94         JOB_UNSUPPORTED,         /* Couldn't start a unit, because the unit type is not supported on the system */
95         JOB_COLLECTED,           /* Job was garbage collected, since nothing needed it anymore */
96         JOB_ONCE,                /* Unit was started before, and hence can't be started again */
97         _JOB_RESULT_MAX,
98         _JOB_RESULT_INVALID = -EINVAL,
99 };
100 
101 #include "unit.h"
102 
103 struct JobDependency {
104         /* Encodes that the 'subject' job needs the 'object' job in
105          * some way. This structure is used only while building a transaction. */
106         Job *subject;
107         Job *object;
108 
109         LIST_FIELDS(JobDependency, subject);
110         LIST_FIELDS(JobDependency, object);
111 
112         bool matters:1;
113         bool conflicts:1;
114 };
115 
116 struct Job {
117         Manager *manager;
118         Unit *unit;
119 
120         LIST_FIELDS(Job, transaction);
121         LIST_FIELDS(Job, dbus_queue);
122         LIST_FIELDS(Job, gc_queue);
123 
124         LIST_HEAD(JobDependency, subject_list);
125         LIST_HEAD(JobDependency, object_list);
126 
127         /* Used for graph algs as a "I have been here" marker */
128         Job* marker;
129         unsigned generation;
130 
131         uint32_t id;
132 
133         JobType type;
134         JobState state;
135 
136         sd_event_source *timer_event_source;
137         usec_t begin_usec;
138         usec_t begin_running_usec;
139 
140         /*
141          * This tracks where to send signals, and also which clients
142          * are allowed to call DBus methods on the job (other than
143          * root).
144          *
145          * There can be more than one client, because of job merging.
146          */
147         sd_bus_track *bus_track;
148         char **deserialized_clients;
149 
150         JobResult result;
151 
152         unsigned run_queue_idx;
153 
154         bool installed:1;
155         bool in_run_queue:1;
156         bool matters_to_anchor:1;
157         bool in_dbus_queue:1;
158         bool sent_dbus_new_signal:1;
159         bool ignore_order:1;
160         bool irreversible:1;
161         bool in_gc_queue:1;
162         bool ref_by_private_bus:1;
163         bool return_skip_on_cond_failure:1;
164 };
165 
166 Job* job_new(Unit *unit, JobType type);
167 Job* job_new_raw(Unit *unit);
168 void job_unlink(Job *job);
169 Job* job_free(Job *job);
170 Job* job_install(Job *j);
171 int job_install_deserialized(Job *j);
172 void job_uninstall(Job *j);
173 void job_dump(Job *j, FILE *f, const char *prefix);
174 int job_serialize(Job *j, FILE *f);
175 int job_deserialize(Job *j, FILE *f);
176 int job_coldplug(Job *j);
177 
178 JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts);
179 void job_dependency_free(JobDependency *l);
180 
181 int job_merge(Job *j, Job *other);
182 
183 JobType job_type_lookup_merge(JobType a, JobType b) _pure_;
184 
job_type_is_mergeable(JobType a,JobType b)185 _pure_ static inline bool job_type_is_mergeable(JobType a, JobType b) {
186         return job_type_lookup_merge(a, b) >= 0;
187 }
188 
job_type_is_conflicting(JobType a,JobType b)189 _pure_ static inline bool job_type_is_conflicting(JobType a, JobType b) {
190         return a != JOB_NOP && b != JOB_NOP && !job_type_is_mergeable(a, b);
191 }
192 
job_type_is_superset(JobType a,JobType b)193 _pure_ static inline bool job_type_is_superset(JobType a, JobType b) {
194         /* Checks whether operation a is a "superset" of b in its actions */
195         if (b == JOB_NOP)
196                 return true;
197         if (a == JOB_NOP)
198                 return false;
199         return a == job_type_lookup_merge(a, b);
200 }
201 
202 bool job_type_is_redundant(JobType a, UnitActiveState b) _pure_;
203 
204 /* Collapses a state-dependent job type into a simpler type by observing
205  * the state of the unit which it is going to be applied to. */
206 JobType job_type_collapse(JobType t, Unit *u);
207 
208 int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u);
209 
210 void job_add_to_run_queue(Job *j);
211 void job_add_to_dbus_queue(Job *j);
212 
213 int job_start_timer(Job *j, bool job_running);
214 
215 int job_run_and_invalidate(Job *j);
216 int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already);
217 
218 char *job_dbus_path(Job *j);
219 
220 void job_shutdown_magic(Job *j);
221 
222 int job_get_timeout(Job *j, usec_t *timeout) _pure_;
223 
224 bool job_may_gc(Job *j);
225 void job_add_to_gc_queue(Job *j);
226 
227 int job_get_before(Job *j, Job*** ret);
228 int job_get_after(Job *j, Job*** ret);
229 
230 DEFINE_TRIVIAL_CLEANUP_FUNC(Job*, job_free);
231 
232 const char* job_type_to_string(JobType t) _const_;
233 JobType job_type_from_string(const char *s) _pure_;
234 
235 const char* job_state_to_string(JobState t) _const_;
236 JobState job_state_from_string(const char *s) _pure_;
237 
238 const char* job_mode_to_string(JobMode t) _const_;
239 JobMode job_mode_from_string(const char *s) _pure_;
240 
241 const char* job_result_to_string(JobResult t) _const_;
242 JobResult job_result_from_string(const char *s) _pure_;
243 
244 const char* job_type_to_access_method(JobType t);
245 
246 int job_compare(Job *a, Job *b, UnitDependencyAtom assume_dep);
247