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 18 : static void target_set_state(Target *t, TargetState state) {
19 : TargetState old_state;
20 18 : assert(t);
21 :
22 18 : if (t->state != state)
23 18 : bus_unit_send_pending_change_signal(UNIT(t), false);
24 :
25 18 : old_state = t->state;
26 18 : t->state = state;
27 :
28 18 : if (state != old_state)
29 18 : 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 18 : unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], 0);
35 18 : }
36 :
37 41 : 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 41 : assert(t);
51 :
52 41 : if (!UNIT(t)->default_dependencies)
53 8 : 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 198 : for (k = 0; k < ELEMENTSOF(deps); k++) {
59 : Unit *other;
60 : Iterator i;
61 : void *v;
62 :
63 253 : HASHMAP_FOREACH_KEY(v, other, UNIT(t)->dependencies[deps[k]], i) {
64 88 : r = unit_add_default_target_dependency(other, UNIT(t));
65 88 : if (r < 0)
66 0 : return r;
67 : }
68 : }
69 :
70 33 : if (unit_has_name(UNIT(t), SPECIAL_SHUTDOWN_TARGET))
71 0 : return 0;
72 :
73 : /* Make sure targets are unloaded on shutdown */
74 33 : return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
75 : }
76 :
77 110 : static int target_load(Unit *u) {
78 110 : Target *t = TARGET(u);
79 : int r;
80 :
81 110 : assert(t);
82 :
83 110 : r = unit_load_fragment_and_dropin(u);
84 110 : if (r < 0)
85 69 : return r;
86 :
87 : /* This is a new unit? Then let's add in some extras */
88 41 : if (u->load_state == UNIT_LOADED) {
89 41 : r = target_add_default_dependencies(t);
90 41 : if (r < 0)
91 0 : return r;
92 : }
93 :
94 41 : 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 30 : static void target_dump(Unit *u, FILE *f, const char *prefix) {
110 30 : Target *t = TARGET(u);
111 :
112 30 : assert(t);
113 30 : assert(f);
114 :
115 30 : fprintf(f,
116 : "%sTarget State: %s\n",
117 : prefix, target_state_to_string(t->state));
118 30 : }
119 :
120 18 : static int target_start(Unit *u) {
121 18 : Target *t = TARGET(u);
122 : int r;
123 :
124 18 : assert(t);
125 18 : assert(t->state == TARGET_DEAD);
126 :
127 18 : r = unit_acquire_invocation_id(u);
128 18 : if (r < 0)
129 0 : return r;
130 :
131 18 : target_set_state(t, TARGET_ACTIVE);
132 18 : 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 707 : _pure_ static UnitActiveState target_active_state(Unit *u) {
180 707 : assert(u);
181 :
182 707 : 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 : };
|