chiark / gitweb /
092b2065f2082f914f5971a4502354a6698c5fef
[elogind.git] / 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         static const UnitDependency deps[] = {
57                 UNIT_REQUIRES,
58                 UNIT_REQUIRES_OVERRIDABLE,
59                 UNIT_REQUISITE,
60                 UNIT_REQUISITE_OVERRIDABLE,
61                 UNIT_WANTS,
62                 UNIT_BIND_TO
63         };
64
65         Iterator i;
66         Unit *other;
67         int r;
68         unsigned k;
69
70         assert(t);
71
72         /* Imply ordering for requirement dependencies on target
73          * units. Note that when the user created a contradicting
74          * ordering manually we won't add anything in here to make
75          * sure we don't create a loop. */
76
77         for (k = 0; k < ELEMENTSOF(deps); k++)
78                 SET_FOREACH(other, UNIT(t)->dependencies[deps[k]], i)
79                         if ((r = unit_add_default_target_dependency(other, UNIT(t))) < 0)
80                                 return r;
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         if ((r = unit_load_fragment_and_dropin(u)) < 0)
93                 return r;
94
95         /* This is a new unit? Then let's add in some extras */
96         if (u->load_state == UNIT_LOADED) {
97                 if (u->default_dependencies)
98                         if ((r = target_add_default_dependencies(t)) < 0)
99                                 return r;
100         }
101
102         return 0;
103 }
104
105 static int target_coldplug(Unit *u) {
106         Target *t = TARGET(u);
107
108         assert(t);
109         assert(t->state == TARGET_DEAD);
110
111         if (t->deserialized_state != t->state)
112                 target_set_state(t, t->deserialized_state);
113
114         return 0;
115 }
116
117 static void target_dump(Unit *u, FILE *f, const char *prefix) {
118         Target *t = TARGET(u);
119
120         assert(t);
121         assert(f);
122
123         fprintf(f,
124                 "%sTarget State: %s\n",
125                 prefix, target_state_to_string(t->state));
126 }
127
128 static int target_start(Unit *u) {
129         Target *t = TARGET(u);
130
131         assert(t);
132         assert(t->state == TARGET_DEAD);
133
134         target_set_state(t, TARGET_ACTIVE);
135         return 0;
136 }
137
138 static int target_stop(Unit *u) {
139         Target *t = TARGET(u);
140
141         assert(t);
142         assert(t->state == TARGET_ACTIVE);
143
144         target_set_state(t, TARGET_DEAD);
145         return 0;
146 }
147
148 static int target_serialize(Unit *u, FILE *f, FDSet *fds) {
149         Target *s = TARGET(u);
150
151         assert(s);
152         assert(f);
153         assert(fds);
154
155         unit_serialize_item(u, f, "state", target_state_to_string(s->state));
156         return 0;
157 }
158
159 static int target_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
160         Target *s = TARGET(u);
161
162         assert(u);
163         assert(key);
164         assert(value);
165         assert(fds);
166
167         if (streq(key, "state")) {
168                 TargetState state;
169
170                 if ((state = target_state_from_string(value)) < 0)
171                         log_debug("Failed to parse state value %s", value);
172                 else
173                         s->deserialized_state = state;
174
175         } else
176                 log_debug("Unknown serialization key '%s'", key);
177
178         return 0;
179 }
180
181 static UnitActiveState target_active_state(Unit *u) {
182         assert(u);
183
184         return state_translation_table[TARGET(u)->state];
185 }
186
187 static const char *target_sub_state_to_string(Unit *u) {
188         assert(u);
189
190         return target_state_to_string(TARGET(u)->state);
191 }
192
193 static const char* const target_state_table[_TARGET_STATE_MAX] = {
194         [TARGET_DEAD] = "dead",
195         [TARGET_ACTIVE] = "active"
196 };
197
198 DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState);
199
200 const UnitVTable target_vtable = {
201         .object_size = sizeof(Target),
202         .sections =
203                 "Unit\0"
204                 "Target\0"
205                 "Install\0",
206
207         .load = target_load,
208         .coldplug = target_coldplug,
209
210         .dump = target_dump,
211
212         .start = target_start,
213         .stop = target_stop,
214
215         .serialize = target_serialize,
216         .deserialize_item = target_deserialize_item,
217
218         .active_state = target_active_state,
219         .sub_state_to_string = target_sub_state_to_string,
220
221         .bus_interface = "org.freedesktop.systemd1.Target",
222         .bus_message_handler = bus_target_message_handler,
223
224         .status_message_formats = {
225                 .finished_start_job = {
226                         [JOB_DONE]       = "Reached target %s.",
227                         [JOB_DEPENDENCY] = "Dependency failed for %s.",
228                 },
229                 .finished_stop_job = {
230                         [JOB_DONE]       = "Stopped target %s.",
231                 },
232         },
233 };