chiark / gitweb /
core: do not spawn jobs or touch other units during coldplugging
[elogind.git] / src / core / target.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22
23 #include "unit.h"
24 #include "target.h"
25 #include "log.h"
26 #include "dbus-target.h"
27 #include "special.h"
28 #include "unit-name.h"
29
30 static const UnitActiveState state_translation_table[_TARGET_STATE_MAX] = {
31         [TARGET_DEAD] = UNIT_INACTIVE,
32         [TARGET_ACTIVE] = UNIT_ACTIVE
33 };
34
35 static void target_set_state(Target *t, TargetState state) {
36         TargetState old_state;
37         assert(t);
38
39         old_state = t->state;
40         t->state = state;
41
42         if (state != old_state)
43                 log_debug("%s changed %s -> %s",
44                           UNIT(t)->id,
45                           target_state_to_string(old_state),
46                           target_state_to_string(state));
47
48         unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
49 }
50
51 static int target_add_default_dependencies(Target *t) {
52
53         static const UnitDependency deps[] = {
54                 UNIT_REQUIRES,
55                 UNIT_REQUIRES_OVERRIDABLE,
56                 UNIT_REQUISITE,
57                 UNIT_REQUISITE_OVERRIDABLE,
58                 UNIT_WANTS,
59                 UNIT_BINDS_TO,
60                 UNIT_PART_OF
61         };
62
63         Iterator i;
64         Unit *other;
65         int r;
66         unsigned k;
67
68         assert(t);
69
70         /* Imply ordering for requirement dependencies on target
71          * units. Note that when the user created a contradicting
72          * ordering manually we won't add anything in here to make
73          * sure we don't create a loop. */
74
75         for (k = 0; k < ELEMENTSOF(deps); k++)
76                 SET_FOREACH(other, UNIT(t)->dependencies[deps[k]], i) {
77                         r = unit_add_default_target_dependency(other, UNIT(t));
78                         if (r < 0)
79                                 return r;
80                 }
81
82         /* Make sure targets are unloaded on shutdown */
83         return unit_add_dependency_by_name(UNIT(t), UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
84 }
85
86 static int target_load(Unit *u) {
87         Target *t = TARGET(u);
88         int r;
89
90         assert(t);
91
92         r = unit_load_fragment_and_dropin(u);
93         if (r < 0)
94                 return r;
95
96         /* This is a new unit? Then let's add in some extras */
97         if (u->load_state == UNIT_LOADED && u->default_dependencies) {
98                 r = target_add_default_dependencies(t);
99                 if (r < 0)
100                         return r;
101         }
102
103         return 0;
104 }
105
106 static int target_coldplug(Unit *u, Hashmap *deferred_work) {
107         Target *t = TARGET(u);
108
109         assert(t);
110         assert(t->state == TARGET_DEAD);
111
112         if (t->deserialized_state != t->state)
113                 target_set_state(t, t->deserialized_state);
114
115         return 0;
116 }
117
118 static void target_dump(Unit *u, FILE *f, const char *prefix) {
119         Target *t = TARGET(u);
120
121         assert(t);
122         assert(f);
123
124         fprintf(f,
125                 "%sTarget State: %s\n",
126                 prefix, target_state_to_string(t->state));
127 }
128
129 static int target_start(Unit *u) {
130         Target *t = TARGET(u);
131
132         assert(t);
133         assert(t->state == TARGET_DEAD);
134
135         target_set_state(t, TARGET_ACTIVE);
136         return 1;
137 }
138
139 static int target_stop(Unit *u) {
140         Target *t = TARGET(u);
141
142         assert(t);
143         assert(t->state == TARGET_ACTIVE);
144
145         target_set_state(t, TARGET_DEAD);
146         return 1;
147 }
148
149 static int target_serialize(Unit *u, FILE *f, FDSet *fds) {
150         Target *s = TARGET(u);
151
152         assert(s);
153         assert(f);
154         assert(fds);
155
156         unit_serialize_item(u, f, "state", target_state_to_string(s->state));
157         return 0;
158 }
159
160 static int target_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
161         Target *s = TARGET(u);
162
163         assert(u);
164         assert(key);
165         assert(value);
166         assert(fds);
167
168         if (streq(key, "state")) {
169                 TargetState state;
170
171                 state = target_state_from_string(value);
172                 if (state < 0)
173                         log_debug("Failed to parse state value %s", value);
174                 else
175                         s->deserialized_state = state;
176
177         } else
178                 log_debug("Unknown serialization key '%s'", key);
179
180         return 0;
181 }
182
183 _pure_ static UnitActiveState target_active_state(Unit *u) {
184         assert(u);
185
186         return state_translation_table[TARGET(u)->state];
187 }
188
189 _pure_ static const char *target_sub_state_to_string(Unit *u) {
190         assert(u);
191
192         return target_state_to_string(TARGET(u)->state);
193 }
194
195 static const char* const target_state_table[_TARGET_STATE_MAX] = {
196         [TARGET_DEAD] = "dead",
197         [TARGET_ACTIVE] = "active"
198 };
199
200 DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState);
201
202 const UnitVTable target_vtable = {
203         .object_size = sizeof(Target),
204
205         .sections =
206                 "Unit\0"
207                 "Target\0"
208                 "Install\0",
209
210         .load = target_load,
211         .coldplug = target_coldplug,
212
213         .dump = target_dump,
214
215         .start = target_start,
216         .stop = target_stop,
217
218         .serialize = target_serialize,
219         .deserialize_item = target_deserialize_item,
220
221         .active_state = target_active_state,
222         .sub_state_to_string = target_sub_state_to_string,
223
224         .bus_interface = "org.freedesktop.systemd1.Target",
225         .bus_vtable = bus_target_vtable,
226
227         .status_message_formats = {
228                 .finished_start_job = {
229                         [JOB_DONE]       = "Reached target %s.",
230                         [JOB_DEPENDENCY] = "Dependency failed for %s.",
231                 },
232                 .finished_stop_job = {
233                         [JOB_DONE]       = "Stopped target %s.",
234                 },
235         },
236 };