chiark / gitweb /
sd-bus: add support for policy upload on activator connections
[elogind.git] / src / core / dbus-unit.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 "sd-bus.h"
23 #include "log.h"
24 #include "selinux-access.h"
25 #include "cgroup-util.h"
26 #include "strv.h"
27 #include "path-util.h"
28 #include "fileio.h"
29 #include "bus-errors.h"
30 #include "dbus.h"
31 #include "dbus-manager.h"
32 #include "dbus-unit.h"
33
34 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
35 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
36
37 static int property_get_names(
38                 sd_bus *bus,
39                 const char *path,
40                 const char *interface,
41                 const char *property,
42                 sd_bus_message *reply,
43                 void *userdata,
44                 sd_bus_error *error) {
45
46         Unit *u = userdata;
47         Iterator i;
48         const char *t;
49         int r;
50
51         assert(bus);
52         assert(reply);
53         assert(u);
54
55         r = sd_bus_message_open_container(reply, 'a', "s");
56         if (r < 0)
57                 return r;
58
59         SET_FOREACH(t, u->names, i) {
60                 r = sd_bus_message_append(reply, "s", t);
61                 if (r < 0)
62                         return r;
63         }
64
65         return sd_bus_message_close_container(reply);
66 }
67
68 static int property_get_following(
69                 sd_bus *bus,
70                 const char *path,
71                 const char *interface,
72                 const char *property,
73                 sd_bus_message *reply,
74                 void *userdata,
75                 sd_bus_error *error) {
76
77         Unit *u = userdata, *f;
78
79         assert(bus);
80         assert(reply);
81         assert(u);
82
83         f = unit_following(u);
84         return sd_bus_message_append(reply, "s", f ? f->id : "");
85 }
86
87 static int property_get_dependencies(
88                 sd_bus *bus,
89                 const char *path,
90                 const char *interface,
91                 const char *property,
92                 sd_bus_message *reply,
93                 void *userdata,
94                 sd_bus_error *error) {
95
96         Set *s = *(Set**) userdata;
97         Iterator j;
98         Unit *u;
99         int r;
100
101         assert(bus);
102         assert(reply);
103
104         r = sd_bus_message_open_container(reply, 'a', "s");
105         if (r < 0)
106                 return r;
107
108         SET_FOREACH(u, s, j) {
109                 r = sd_bus_message_append(reply, "s", u->id);
110                 if (r < 0)
111                         return r;
112         }
113
114         return sd_bus_message_close_container(reply);
115 }
116
117 static int property_get_description(
118                 sd_bus *bus,
119                 const char *path,
120                 const char *interface,
121                 const char *property,
122                 sd_bus_message *reply,
123                 void *userdata,
124                 sd_bus_error *error) {
125
126         Unit *u = userdata;
127
128         assert(bus);
129         assert(reply);
130         assert(u);
131
132         return sd_bus_message_append(reply, "s", unit_description(u));
133 }
134
135 static int property_get_active_state(
136                 sd_bus *bus,
137                 const char *path,
138                 const char *interface,
139                 const char *property,
140                 sd_bus_message *reply,
141                 void *userdata,
142                 sd_bus_error *error) {
143
144         Unit *u = userdata;
145
146         assert(bus);
147         assert(reply);
148         assert(u);
149
150         return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u)));
151 }
152
153 static int property_get_sub_state(
154                 sd_bus *bus,
155                 const char *path,
156                 const char *interface,
157                 const char *property,
158                 sd_bus_message *reply,
159                 void *userdata,
160                 sd_bus_error *error) {
161
162         Unit *u = userdata;
163
164         assert(bus);
165         assert(reply);
166         assert(u);
167
168         return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u));
169 }
170
171 static int property_get_unit_file_state(
172                 sd_bus *bus,
173                 const char *path,
174                 const char *interface,
175                 const char *property,
176                 sd_bus_message *reply,
177                 void *userdata,
178                 sd_bus_error *error) {
179
180         Unit *u = userdata;
181
182         assert(bus);
183         assert(reply);
184         assert(u);
185
186         return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u)));
187 }
188
189 static int property_get_can_start(
190                 sd_bus *bus,
191                 const char *path,
192                 const char *interface,
193                 const char *property,
194                 sd_bus_message *reply,
195                 void *userdata,
196                 sd_bus_error *error) {
197
198         Unit *u = userdata;
199
200         assert(bus);
201         assert(reply);
202         assert(u);
203
204         return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start);
205 }
206
207 static int property_get_can_stop(
208                 sd_bus *bus,
209                 const char *path,
210                 const char *interface,
211                 const char *property,
212                 sd_bus_message *reply,
213                 void *userdata,
214                 sd_bus_error *error) {
215
216         Unit *u = userdata;
217
218         assert(bus);
219         assert(reply);
220         assert(u);
221
222         /* On the lower levels we assume that every unit we can start
223          * we can also stop */
224
225         return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_stop);
226 }
227
228 static int property_get_can_reload(
229                 sd_bus *bus,
230                 const char *path,
231                 const char *interface,
232                 const char *property,
233                 sd_bus_message *reply,
234                 void *userdata,
235                 sd_bus_error *error) {
236
237         Unit *u = userdata;
238
239         assert(bus);
240         assert(reply);
241         assert(u);
242
243         return sd_bus_message_append(reply, "b", unit_can_reload(u));
244 }
245
246 static int property_get_can_isolate(
247                 sd_bus *bus,
248                 const char *path,
249                 const char *interface,
250                 const char *property,
251                 sd_bus_message *reply,
252                 void *userdata,
253                 sd_bus_error *error) {
254
255         Unit *u = userdata;
256
257         assert(bus);
258         assert(reply);
259         assert(u);
260
261         return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start);
262 }
263
264 static int property_get_job(
265                 sd_bus *bus,
266                 const char *path,
267                 const char *interface,
268                 const char *property,
269                 sd_bus_message *reply,
270                 void *userdata,
271                 sd_bus_error *error) {
272
273         _cleanup_free_ char *p = NULL;
274         Unit *u = userdata;
275
276         assert(bus);
277         assert(reply);
278         assert(u);
279
280         if (!u->job)
281                 return sd_bus_message_append(reply, "(uo)", 0, "/");
282
283         p = job_dbus_path(u->job);
284         if (!p)
285                 return -ENOMEM;
286
287         return sd_bus_message_append(reply, "(uo)", u->job->id, p);
288 }
289
290 static int property_get_need_daemon_reload(
291                 sd_bus *bus,
292                 const char *path,
293                 const char *interface,
294                 const char *property,
295                 sd_bus_message *reply,
296                 void *userdata,
297                 sd_bus_error *error) {
298
299         Unit *u = userdata;
300
301         assert(bus);
302         assert(reply);
303         assert(u);
304
305         return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u));
306 }
307
308 static int property_get_conditions(
309                 sd_bus *bus,
310                 const char *path,
311                 const char *interface,
312                 const char *property,
313                 sd_bus_message *reply,
314                 void *userdata,
315                 sd_bus_error *error) {
316
317         Unit *u = userdata;
318         Condition *c;
319         int r;
320
321         assert(bus);
322         assert(reply);
323         assert(u);
324
325         r = sd_bus_message_open_container(reply, 'a', "(sbbsi)");
326         if (r < 0)
327                 return r;
328
329         LIST_FOREACH(conditions, c, u->conditions) {
330                 r = sd_bus_message_append(reply, "(sbbsi)",
331                                           condition_type_to_string(c->type),
332                                           c->trigger, c->negate,
333                                           c->parameter, c->state);
334                 if (r < 0)
335                         return r;
336
337         }
338
339         return sd_bus_message_close_container(reply);
340 }
341
342 static int property_get_load_error(
343                 sd_bus *bus,
344                 const char *path,
345                 const char *interface,
346                 const char *property,
347                 sd_bus_message *reply,
348                 void *userdata,
349                 sd_bus_error *error) {
350
351         _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
352         Unit *u = userdata;
353
354         assert(bus);
355         assert(reply);
356         assert(u);
357
358         if (u->load_error != 0)
359                 sd_bus_error_set_errno(&e, u->load_error);
360
361         return sd_bus_message_append(reply, "(ss)", e.name, e.message);
362 }
363
364 int bus_unit_method_start_generic(sd_bus *bus, sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error) {
365         const char *smode;
366         JobMode mode;
367         int r;
368
369         assert(bus);
370         assert(message);
371         assert(u);
372         assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
373
374         r = sd_bus_message_read(message, "s", &smode);
375         if (r < 0)
376                 return r;
377
378         mode = job_mode_from_string(smode);
379         if (mode < 0)
380                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
381
382         return bus_unit_queue_job(bus, message, u, job_type, mode, reload_if_possible, error);
383 }
384
385 static int method_start(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
386         return bus_unit_method_start_generic(bus, message, userdata, JOB_START, false, error);
387 }
388
389 static int method_stop(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
390         return bus_unit_method_start_generic(bus, message, userdata, JOB_STOP, false, error);
391 }
392
393 static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
394         return bus_unit_method_start_generic(bus, message, userdata, JOB_RELOAD, false, error);
395 }
396
397 static int method_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
398         return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, false, error);
399 }
400
401 static int method_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
402         return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, false, error);
403 }
404
405 static int method_reload_or_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
406         return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, true, error);
407 }
408
409 static int method_reload_or_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
410         return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, true, error);
411 }
412
413 int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
414         Unit *u = userdata;
415         const char *swho;
416         int32_t signo;
417         KillWho who;
418         int r;
419
420         assert(bus);
421         assert(message);
422         assert(u);
423
424         r = sd_bus_message_read(message, "si", &swho, &signo);
425         if (r < 0)
426                 return r;
427
428         if (isempty(swho))
429                 who = KILL_ALL;
430         else {
431                 who = kill_who_from_string(swho);
432                 if (who < 0)
433                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
434         }
435
436         if (signo <= 0 || signo >= _NSIG)
437                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
438
439         r = selinux_unit_access_check(u, bus, message, "stop", error);
440         if (r < 0)
441                 return r;
442
443         r = unit_kill(u, who, signo, error);
444         if (r < 0)
445                 return r;
446
447         return sd_bus_reply_method_return(message, NULL);
448 }
449
450 int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
451         Unit *u = userdata;
452         int r;
453
454         assert(bus);
455         assert(message);
456         assert(u);
457
458         r = selinux_unit_access_check(u, bus, message, "reload", error);
459         if (r < 0)
460                 return r;
461
462         unit_reset_failed(u);
463
464         return sd_bus_reply_method_return(message, NULL);
465 }
466
467 int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
468         Unit *u = userdata;
469         int runtime, r;
470
471         assert(bus);
472         assert(message);
473         assert(u);
474
475         r = sd_bus_message_read(message, "b", &runtime);
476         if (r < 0)
477                 return r;
478
479         r = selinux_unit_access_check(u, bus, message, "start", error);
480         if (r < 0)
481                 return r;
482
483         r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
484         if (r < 0)
485                 return r;
486
487         return sd_bus_reply_method_return(message, NULL);
488 }
489
490 const sd_bus_vtable bus_unit_vtable[] = {
491         SD_BUS_VTABLE_START(0),
492
493         SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
494         SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
495         SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
496         SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
497         SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
498         SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
499         SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
500         SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
501         SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
502         SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
503         SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
504         SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
505         SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
506         SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
507         SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
508         SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST),
509         SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
510         SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST),
511         SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST),
512         SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST),
513         SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST),
514         SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
515         SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
516         SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
517         SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
518         SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
519         SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
520         SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
521         SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
522         SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
523         SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
524         SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
525         SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
526         SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
527         SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
528         BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
529         BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
530         BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
531         BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
532         SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST),
533         SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
534         SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
535         SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
536         SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
537         SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
538         SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
539         SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
540         SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
541         SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
542         SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
543         SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
544         SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
545         SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
546         SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
547         SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
548         BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
549         SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, 0, 0),
550         SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
551         SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
552
553         SD_BUS_METHOD("Start", "s", "o", method_start, 0),
554         SD_BUS_METHOD("Stop", "s", "o", method_stop, 0),
555         SD_BUS_METHOD("Reload", "s", "o", method_reload, 0),
556         SD_BUS_METHOD("Restart", "s", "o", method_restart, 0),
557         SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, 0),
558         SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, 0),
559         SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, 0),
560         SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, 0),
561         SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, 0),
562         SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, 0),
563
564         SD_BUS_VTABLE_END
565 };
566
567 static int property_get_slice(
568                 sd_bus *bus,
569                 const char *path,
570                 const char *interface,
571                 const char *property,
572                 sd_bus_message *reply,
573                 void *userdata,
574                 sd_bus_error *error) {
575
576         Unit *u = userdata;
577
578         assert(bus);
579         assert(reply);
580         assert(u);
581
582         return sd_bus_message_append(reply, "s", unit_slice_name(u));
583 }
584
585 const sd_bus_vtable bus_unit_cgroup_vtable[] = {
586         SD_BUS_VTABLE_START(0),
587         SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
588         SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
589         SD_BUS_VTABLE_END
590 };
591
592 static int send_new_signal(sd_bus *bus, void *userdata) {
593         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
594         _cleanup_free_ char *p = NULL;
595         Unit *u = userdata;
596         int r;
597
598         assert(bus);
599         assert(u);
600
601         p = unit_dbus_path(u);
602         if (!u)
603                 return -ENOMEM;
604
605         r = sd_bus_message_new_signal(
606                         bus,
607                         &m,
608                         "/org/freedesktop/systemd1",
609                         "org.freedesktop.systemd1.Manager",
610                         "UnitNew");
611         if (r < 0)
612                 return r;
613
614         r = sd_bus_message_append(m, "so", u->id, p);
615         if (r < 0)
616                 return r;
617
618         return sd_bus_send(bus, m, NULL);
619 }
620
621 static int send_changed_signal(sd_bus *bus, void *userdata) {
622         _cleanup_free_ char *p = NULL;
623         Unit *u = userdata;
624         int r;
625
626         assert(bus);
627         assert(u);
628
629         p = unit_dbus_path(u);
630         if (!p)
631                 return -ENOMEM;
632
633         /* Send a properties changed signal. First for the specific
634          * type, then for the generic unit. The clients may rely on
635          * this order to get atomic behavior if needed. */
636
637         r = sd_bus_emit_properties_changed_strv(
638                         bus, p,
639                         UNIT_VTABLE(u)->bus_interface,
640                         NULL);
641         if (r < 0) {
642                 log_warning("Failed to send out specific PropertiesChanged signal for %s: %s", u->id, strerror(-r));
643                 return r;
644         }
645
646         r = sd_bus_emit_properties_changed_strv(
647                         bus, p,
648                         "org.freedesktop.systemd1.Unit",
649                         NULL);
650         if (r < 0) {
651                 log_warning("Failed to send out generic PropertiesChanged signal for %s: %s", u->id, strerror(-r));
652                 return r;
653         }
654
655         return 0;
656 }
657
658 void bus_unit_send_change_signal(Unit *u) {
659         int r;
660         assert(u);
661
662         if (u->in_dbus_queue) {
663                 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
664                 u->in_dbus_queue = false;
665         }
666
667         if (!u->id)
668                 return;
669
670         r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
671         if (r < 0)
672                 log_debug("Failed to send unit change signal for %s: %s", u->id, strerror(-r));
673
674         u->sent_dbus_new_signal = true;
675 }
676
677 static int send_removed_signal(sd_bus *bus, void *userdata) {
678         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
679         _cleanup_free_ char *p = NULL;
680         Unit *u = userdata;
681         int r;
682
683         assert(bus);
684         assert(u);
685
686         p = unit_dbus_path(u);
687         if (!u)
688                 return -ENOMEM;
689
690         r = sd_bus_message_new_signal(
691                         bus,
692                         &m,
693                         "/org/freedesktop/systemd1",
694                         "org.freedesktop.systemd1.Manager",
695                         "UnitRemoved");
696         if (r < 0)
697                 return r;
698
699         r = sd_bus_message_append(m, "so", u->id, p);
700         if (r < 0)
701                 return r;
702
703         return sd_bus_send(bus, m, NULL);
704 }
705
706 void bus_unit_send_removed_signal(Unit *u) {
707         int r;
708         assert(u);
709
710         if (!u->sent_dbus_new_signal)
711                 bus_unit_send_change_signal(u);
712
713         if (!u->id)
714                 return;
715
716         r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
717         if (r < 0)
718                 log_debug("Failed to send unit remove signal for %s: %s", u->id, strerror(-r));
719 }
720
721 int bus_unit_queue_job(
722                 sd_bus *bus,
723                 sd_bus_message *message,
724                 Unit *u,
725                 JobType type,
726                 JobMode mode,
727                 bool reload_if_possible,
728                 sd_bus_error *error) {
729
730         _cleanup_free_ char *path = NULL;
731         Job *j;
732         int r;
733
734         assert(bus);
735         assert(message);
736         assert(u);
737         assert(type >= 0 && type < _JOB_TYPE_MAX);
738         assert(mode >= 0 && mode < _JOB_MODE_MAX);
739
740         if (reload_if_possible && unit_can_reload(u)) {
741                 if (type == JOB_RESTART)
742                         type = JOB_RELOAD_OR_START;
743                 else if (type == JOB_TRY_RESTART)
744                         type = JOB_RELOAD;
745         }
746
747         r = selinux_unit_access_check(
748                         u, bus, message,
749                         (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
750                         type == JOB_STOP ? "stop" : "reload", error);
751         if (r < 0)
752                 return r;
753
754         if (type == JOB_STOP &&
755             (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
756             unit_active_state(u) == UNIT_INACTIVE)
757                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
758
759         if ((type == JOB_START && u->refuse_manual_start) ||
760             (type == JOB_STOP && u->refuse_manual_stop) ||
761             ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
762                 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
763
764         r = manager_add_job(u->manager, type, u, mode, true, error, &j);
765         if (r < 0)
766                 return r;
767
768         if (bus == u->manager->api_bus) {
769                 if (!j->subscribed) {
770                         r = sd_bus_track_new(bus, &j->subscribed, NULL, NULL);
771                         if (r < 0)
772                                 return r;
773                 }
774
775                 r = sd_bus_track_add_sender(j->subscribed, message);
776                 if (r < 0)
777                         return r;
778         }
779
780         path = job_dbus_path(j);
781         if (!path)
782                 return -ENOMEM;
783
784         return sd_bus_reply_method_return(message, "o", path);
785 }
786
787 static int bus_unit_set_transient_property(
788                 Unit *u,
789                 const char *name,
790                 sd_bus_message *message,
791                 UnitSetPropertiesMode mode,
792                 sd_bus_error *error) {
793
794         int r;
795
796         assert(u);
797         assert(name);
798         assert(message);
799
800         if (streq(name, "Description")) {
801                 const char *d;
802
803                 r = sd_bus_message_read(message, "s", &d);
804                 if (r < 0)
805                         return r;
806
807                 if (mode != UNIT_CHECK) {
808                         r = unit_set_description(u, d);
809                         if (r < 0)
810                                 return r;
811
812                         unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
813                 }
814
815                 return 1;
816
817         } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
818                 const char *s;
819
820                 r = sd_bus_message_read(message, "s", &s);
821                 if (r < 0)
822                         return r;
823
824                 if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
825                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
826
827                 if (isempty(s)) {
828                         if (mode != UNIT_CHECK) {
829                                 unit_ref_unset(&u->slice);
830                                 unit_remove_drop_in(u, mode, name);
831                         }
832                 } else {
833                         Unit *slice;
834
835                         r = manager_load_unit(u->manager, s, NULL, error, &slice);
836                         if (r < 0)
837                                 return r;
838
839                         if (slice->type != UNIT_SLICE)
840                                 return -EINVAL;
841
842                         if (mode != UNIT_CHECK) {
843                                 unit_ref_set(&u->slice, slice);
844                                 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
845                         }
846                 }
847
848                 return 1;
849
850         } else if (streq(name, "Requires") ||
851                    streq(name, "RequiresOverridable") ||
852                    streq(name, "Requisite") ||
853                    streq(name, "RequisiteOverridable") ||
854                    streq(name, "Wants") ||
855                    streq(name, "BindsTo") ||
856                    streq(name, "Conflicts") ||
857                    streq(name, "Before") ||
858                    streq(name, "After") ||
859                    streq(name, "OnFailure") ||
860                    streq(name, "PropagatesReloadTo") ||
861                    streq(name, "ReloadPropagatedFrom") ||
862                    streq(name, "PartOf")) {
863
864                 UnitDependency d;
865                 const char *other;
866
867                 d = unit_dependency_from_string(name);
868                 if (d < 0)
869                         return -EINVAL;
870
871                 r = sd_bus_message_enter_container(message, 'a', "s");
872                 if (r < 0)
873                         return r;
874
875                 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
876                         if (!unit_name_is_valid(other, TEMPLATE_INVALID))
877                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
878
879                         if (mode != UNIT_CHECK) {
880                                 _cleanup_free_ char *label = NULL;
881
882                                 r = unit_add_dependency_by_name(u, d, other, NULL, true);
883                                 if (r < 0)
884                                         return r;
885
886                                 label = strjoin(name, "-", other, NULL);
887                                 if (!label)
888                                         return -ENOMEM;
889
890                                 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
891                         }
892
893                 }
894                 if (r < 0)
895                         return r;
896
897                 r = sd_bus_message_exit_container(message);
898                 if (r < 0)
899                         return r;
900
901                 return 1;
902         }
903
904         return 0;
905 }
906
907 int bus_unit_set_properties(
908                 Unit *u,
909                 sd_bus_message *message,
910                 UnitSetPropertiesMode mode,
911                 bool commit,
912                 sd_bus_error *error) {
913
914         bool for_real = false;
915         unsigned n = 0;
916         int r;
917
918         assert(u);
919         assert(message);
920
921         /* We iterate through the array twice. First run we just check
922          * if all passed data is valid, second run actually applies
923          * it. This is to implement transaction-like behaviour without
924          * actually providing full transactions. */
925
926         r = sd_bus_message_enter_container(message, 'a', "(sv)");
927         if (r < 0)
928                 return r;
929
930         for (;;) {
931                 const char *name;
932
933                 r = sd_bus_message_enter_container(message, 'r', "sv");
934                 if (r < 0)
935                         return r;
936                 if (r == 0) {
937                         if (for_real || mode == UNIT_CHECK)
938                                 break;
939
940                         /* Reached EOF. Let's try again, and this time for realz... */
941                         r = sd_bus_message_rewind(message, false);
942                         if (r < 0)
943                                 return r;
944
945                         for_real = true;
946                         continue;
947                 }
948
949                 r = sd_bus_message_read(message, "s", &name);
950                 if (r < 0)
951                         return r;
952
953                 if (!UNIT_VTABLE(u)->bus_set_property)
954                         return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
955
956                 r = sd_bus_message_enter_container(message, 'v', NULL);
957                 if (r < 0)
958                         return r;
959
960                 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
961                 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
962                         r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
963                 if (r < 0)
964                         return r;
965                 if (r == 0)
966                         return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
967
968                 r = sd_bus_message_exit_container(message);
969                 if (r < 0)
970                         return r;
971
972                 r = sd_bus_message_exit_container(message);
973                 if (r < 0)
974                         return r;
975
976                 n += for_real;
977         }
978
979         r = sd_bus_message_exit_container(message);
980         if (r < 0)
981                 return r;
982
983         if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
984                 UNIT_VTABLE(u)->bus_commit_properties(u);
985
986         return n;
987 }