Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include "dbus-target.h"
4 : : #include "dbus-unit.h"
5 : : #include "log.h"
6 : : #include "serialize.h"
7 : : #include "special.h"
8 : : #include "string-util.h"
9 : : #include "target.h"
10 : : #include "unit-name.h"
11 : : #include "unit.h"
12 : :
13 : : static const UnitActiveState state_translation_table[_TARGET_STATE_MAX] = {
14 : : [TARGET_DEAD] = UNIT_INACTIVE,
15 : : [TARGET_ACTIVE] = UNIT_ACTIVE
16 : : };
17 : :
18 : 72 : static void target_set_state(Target *t, TargetState state) {
19 : : TargetState old_state;
20 [ - + ]: 72 : assert(t);
21 : :
22 [ + - ]: 72 : if (t->state != state)
23 [ + - ]: 72 : bus_unit_send_pending_change_signal(UNIT(t), false);
24 : :
25 : 72 : old_state = t->state;
26 : 72 : t->state = state;
27 : :
28 [ + - ]: 72 : if (state != old_state)
29 [ - + # # ]: 72 : log_debug("%s changed %s -> %s",
30 : : UNIT(t)->id,
31 : : target_state_to_string(old_state),
32 : : target_state_to_string(state));
33 : :
34 [ + - ]: 72 : unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], 0);
35 : 72 : }
36 : :
37 : 164 : static int target_add_default_dependencies(Target *t) {
38 : :
39 : : static const UnitDependency deps[] = {
40 : : UNIT_REQUIRES,
41 : : UNIT_REQUISITE,
42 : : UNIT_WANTS,
43 : : UNIT_BINDS_TO,
44 : : UNIT_PART_OF
45 : : };
46 : :
47 : : int r;
48 : : unsigned k;
49 : :
50 [ - + ]: 164 : assert(t);
51 : :
52 [ + - + + ]: 164 : if (!UNIT(t)->default_dependencies)
53 : 32 : return 0;
54 : :
55 : : /* Imply ordering for requirement dependencies on target units. Note that when the user created a contradicting
56 : : * ordering manually we won't add anything in here to make sure we don't create a loop. */
57 : :
58 [ + + ]: 792 : for (k = 0; k < ELEMENTSOF(deps); k++) {
59 : : Unit *other;
60 : : Iterator i;
61 : : void *v;
62 : :
63 [ + - + + ]: 1012 : HASHMAP_FOREACH_KEY(v, other, UNIT(t)->dependencies[deps[k]], i) {
64 [ + - ]: 352 : r = unit_add_default_target_dependency(other, UNIT(t));
65 [ - + ]: 352 : if (r < 0)
66 : 0 : return r;
67 : : }
68 : : }
69 : :
70 [ + - - + ]: 132 : if (unit_has_name(UNIT(t), SPECIAL_SHUTDOWN_TARGET))
71 : 0 : return 0;
72 : :
73 : : /* Make sure targets are unloaded on shutdown */
74 [ + - ]: 132 : return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
75 : : }
76 : :
77 : 440 : static int target_load(Unit *u) {
78 : 440 : Target *t = TARGET(u);
79 : : int r;
80 : :
81 [ - + ]: 440 : assert(t);
82 : :
83 : 440 : r = unit_load_fragment_and_dropin(u);
84 [ + + ]: 440 : if (r < 0)
85 : 276 : return r;
86 : :
87 : : /* This is a new unit? Then let's add in some extras */
88 [ + - ]: 164 : if (u->load_state == UNIT_LOADED) {
89 : 164 : r = target_add_default_dependencies(t);
90 [ - + ]: 164 : if (r < 0)
91 : 0 : return r;
92 : : }
93 : :
94 : 164 : return 0;
95 : : }
96 : :
97 : 0 : static int target_coldplug(Unit *u) {
98 : 0 : Target *t = TARGET(u);
99 : :
100 [ # # ]: 0 : assert(t);
101 [ # # ]: 0 : assert(t->state == TARGET_DEAD);
102 : :
103 [ # # ]: 0 : if (t->deserialized_state != t->state)
104 : 0 : target_set_state(t, t->deserialized_state);
105 : :
106 : 0 : return 0;
107 : : }
108 : :
109 : 120 : static void target_dump(Unit *u, FILE *f, const char *prefix) {
110 : 120 : Target *t = TARGET(u);
111 : :
112 [ - + ]: 120 : assert(t);
113 [ - + ]: 120 : assert(f);
114 : :
115 : 120 : fprintf(f,
116 : : "%sTarget State: %s\n",
117 : : prefix, target_state_to_string(t->state));
118 : 120 : }
119 : :
120 : 72 : static int target_start(Unit *u) {
121 : 72 : Target *t = TARGET(u);
122 : : int r;
123 : :
124 [ - + ]: 72 : assert(t);
125 [ - + ]: 72 : assert(t->state == TARGET_DEAD);
126 : :
127 : 72 : r = unit_acquire_invocation_id(u);
128 [ - + ]: 72 : if (r < 0)
129 : 0 : return r;
130 : :
131 : 72 : target_set_state(t, TARGET_ACTIVE);
132 : 72 : return 1;
133 : : }
134 : :
135 : 0 : static int target_stop(Unit *u) {
136 : 0 : Target *t = TARGET(u);
137 : :
138 [ # # ]: 0 : assert(t);
139 [ # # ]: 0 : assert(t->state == TARGET_ACTIVE);
140 : :
141 : 0 : target_set_state(t, TARGET_DEAD);
142 : 0 : return 1;
143 : : }
144 : :
145 : 0 : static int target_serialize(Unit *u, FILE *f, FDSet *fds) {
146 : 0 : Target *s = TARGET(u);
147 : :
148 [ # # ]: 0 : assert(s);
149 [ # # ]: 0 : assert(f);
150 [ # # ]: 0 : assert(fds);
151 : :
152 : 0 : (void) serialize_item(f, "state", target_state_to_string(s->state));
153 : 0 : return 0;
154 : : }
155 : :
156 : 0 : static int target_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
157 : 0 : Target *s = TARGET(u);
158 : :
159 [ # # ]: 0 : assert(u);
160 [ # # ]: 0 : assert(key);
161 [ # # ]: 0 : assert(value);
162 [ # # ]: 0 : assert(fds);
163 : :
164 [ # # ]: 0 : if (streq(key, "state")) {
165 : : TargetState state;
166 : :
167 : 0 : state = target_state_from_string(value);
168 [ # # ]: 0 : if (state < 0)
169 [ # # ]: 0 : log_debug("Failed to parse state value %s", value);
170 : : else
171 : 0 : s->deserialized_state = state;
172 : :
173 : : } else
174 [ # # ]: 0 : log_debug("Unknown serialization key '%s'", key);
175 : :
176 : 0 : return 0;
177 : : }
178 : :
179 : 3068 : _pure_ static UnitActiveState target_active_state(Unit *u) {
180 [ - + ]: 3068 : assert(u);
181 : :
182 : 3068 : return state_translation_table[TARGET(u)->state];
183 : : }
184 : :
185 : 0 : _pure_ static const char *target_sub_state_to_string(Unit *u) {
186 [ # # ]: 0 : assert(u);
187 : :
188 : 0 : return target_state_to_string(TARGET(u)->state);
189 : : }
190 : :
191 : : const UnitVTable target_vtable = {
192 : : .object_size = sizeof(Target),
193 : :
194 : : .sections =
195 : : "Unit\0"
196 : : "Target\0"
197 : : "Install\0",
198 : :
199 : : .load = target_load,
200 : : .coldplug = target_coldplug,
201 : :
202 : : .dump = target_dump,
203 : :
204 : : .start = target_start,
205 : : .stop = target_stop,
206 : :
207 : : .serialize = target_serialize,
208 : : .deserialize_item = target_deserialize_item,
209 : :
210 : : .active_state = target_active_state,
211 : : .sub_state_to_string = target_sub_state_to_string,
212 : :
213 : : .bus_vtable = bus_target_vtable,
214 : :
215 : : .status_message_formats = {
216 : : .finished_start_job = {
217 : : [JOB_DONE] = "Reached target %s.",
218 : : },
219 : : .finished_stop_job = {
220 : : [JOB_DONE] = "Stopped target %s.",
221 : : },
222 : : },
223 : : };
|