chiark / gitweb /
Standarize on one spelling of symlink error message
[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 #include <errno.h>
23 #include <signal.h>
24 #include <unistd.h>
25
26 #include "unit.h"
27 #include "target.h"
28 #include "load-fragment.h"
29 #include "log.h"
30 #include "dbus-target.h"
31 #include "special.h"
32 #include "unit-name.h"
33
34 static const UnitActiveState state_translation_table[_TARGET_STATE_MAX] = {
35         [TARGET_DEAD] = UNIT_INACTIVE,
36         [TARGET_ACTIVE] = UNIT_ACTIVE
37 };
38
39 static void target_set_state(Target *t, TargetState state) {
40         TargetState old_state;
41         assert(t);
42
43         old_state = t->state;
44         t->state = state;
45
46         if (state != old_state)
47                 log_debug("%s changed %s -> %s",
48                           UNIT(t)->id,
49                           target_state_to_string(old_state),
50                           target_state_to_string(state));
51
52         unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
53 }
54
55 static int target_add_default_dependencies(Target *t) {
56
57         static const UnitDependency deps[] = {
58                 UNIT_REQUIRES,
59                 UNIT_REQUIRES_OVERRIDABLE,
60                 UNIT_REQUISITE,
61                 UNIT_REQUISITE_OVERRIDABLE,
62                 UNIT_WANTS,
63                 UNIT_BINDS_TO,
64                 UNIT_PART_OF
65         };
66
67         Iterator i;
68         Unit *other;
69         int r;
70         unsigned k;
71
72         assert(t);
73
74         /* Imply ordering for requirement dependencies on target
75          * units. Note that when the user created a contradicting
76          * ordering manually we won't add anything in here to make
77          * sure we don't create a loop. */
78
79         for (k = 0; k < ELEMENTSOF(deps); k++)
80                 SET_FOREACH(other, UNIT(t)->dependencies[deps[k]], i) {
81                         r = unit_add_default_target_dependency(other, UNIT(t));
82                         if (r < 0)
83                                 return r;
84                 }
85
86         /* Make sure targets are unloaded on shutdown */
87         return unit_add_dependency_by_name(UNIT(t), UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
88 }
89
90 static int target_load(Unit *u) {
91         Target *t = TARGET(u);
92         int r;
93
94         assert(t);
95
96         r = unit_load_fragment_and_dropin(u);
97         if (r < 0)
98                 return r;
99
100         /* This is a new unit? Then let's add in some extras */
101         if (u->load_state == UNIT_LOADED && u->default_dependencies) {
102                 r = target_add_default_dependencies(t);
103                 if (r < 0)
104                         return r;
105         }
106
107         return 0;
108 }
109
110 static int target_coldplug(Unit *u) {
111         Target *t = TARGET(u);
112
113         assert(t);
114         assert(t->state == TARGET_DEAD);
115
116         if (t->deserialized_state != t->state)
117                 target_set_state(t, t->deserialized_state);
118
119         return 0;
120 }
121
122 static void target_dump(Unit *u, FILE *f, const char *prefix) {
123         Target *t = TARGET(u);
124
125         assert(t);
126         assert(f);
127
128         fprintf(f,
129                 "%sTarget State: %s\n",
130                 prefix, target_state_to_string(t->state));
131 }
132
133 static int target_start(Unit *u) {
134         Target *t = TARGET(u);
135
136         assert(t);
137         assert(t->state == TARGET_DEAD);
138
139         target_set_state(t, TARGET_ACTIVE);
140         return 0;
141 }
142
143 static int target_stop(Unit *u) {
144         Target *t = TARGET(u);
145
146         assert(t);
147         assert(t->state == TARGET_ACTIVE);
148
149         target_set_state(t, TARGET_DEAD);
150         return 0;
151 }
152
153 static int target_serialize(Unit *u, FILE *f, FDSet *fds) {
154         Target *s = TARGET(u);
155
156         assert(s);
157         assert(f);
158         assert(fds);
159
160         unit_serialize_item(u, f, "state", target_state_to_string(s->state));
161         return 0;
162 }
163
164 static int target_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
165         Target *s = TARGET(u);
166
167         assert(u);
168         assert(key);
169         assert(value);
170         assert(fds);
171
172         if (streq(key, "state")) {
173                 TargetState state;
174
175                 state = target_state_from_string(value);
176                 if (state < 0)
177                         log_debug("Failed to parse state value %s", value);
178                 else
179                         s->deserialized_state = state;
180
181         } else
182                 log_debug("Unknown serialization key '%s'", key);
183
184         return 0;
185 }
186
187 static UnitActiveState target_active_state(Unit *u) {
188         assert(u);
189
190         return state_translation_table[TARGET(u)->state];
191 }
192
193 static const char *target_sub_state_to_string(Unit *u) {
194         assert(u);
195
196         return target_state_to_string(TARGET(u)->state);
197 }
198
199 static const char* const target_state_table[_TARGET_STATE_MAX] = {
200         [TARGET_DEAD] = "dead",
201         [TARGET_ACTIVE] = "active"
202 };
203
204 DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState);
205
206 const UnitVTable target_vtable = {
207         .object_size = sizeof(Target),
208         .sections =
209                 "Unit\0"
210                 "Target\0"
211                 "Install\0",
212
213         .load = target_load,
214         .coldplug = target_coldplug,
215
216         .dump = target_dump,
217
218         .start = target_start,
219         .stop = target_stop,
220
221         .serialize = target_serialize,
222         .deserialize_item = target_deserialize_item,
223
224         .active_state = target_active_state,
225         .sub_state_to_string = target_sub_state_to_string,
226
227         .bus_interface = "org.freedesktop.systemd1.Target",
228         .bus_message_handler = bus_target_message_handler,
229
230         .status_message_formats = {
231                 .finished_start_job = {
232                         [JOB_DONE]       = "Reached target %s.",
233                         [JOB_DEPENDENCY] = "Dependency failed for %s.",
234                 },
235                 .finished_stop_job = {
236                         [JOB_DONE]       = "Stopped target %s.",
237                 },
238         },
239 };