chiark / gitweb /
bus-policy: append items rather than prepending them
[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 = bus_verify_manage_unit_async_for_kill(u->manager, message, error);
425         if (r < 0)
426                 return r;
427         if (r == 0)
428                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
429
430         r = sd_bus_message_read(message, "si", &swho, &signo);
431         if (r < 0)
432                 return r;
433
434         if (isempty(swho))
435                 who = KILL_ALL;
436         else {
437                 who = kill_who_from_string(swho);
438                 if (who < 0)
439                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
440         }
441
442         if (signo <= 0 || signo >= _NSIG)
443                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
444
445         r = selinux_unit_access_check(u, message, "stop", error);
446         if (r < 0)
447                 return r;
448
449         r = unit_kill(u, who, signo, error);
450         if (r < 0)
451                 return r;
452
453         return sd_bus_reply_method_return(message, NULL);
454 }
455
456 int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
457         Unit *u = userdata;
458         int r;
459
460         assert(bus);
461         assert(message);
462         assert(u);
463
464         r = bus_verify_manage_unit_async(u->manager, message, error);
465         if (r < 0)
466                 return r;
467         if (r == 0)
468                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
469
470         r = selinux_unit_access_check(u, message, "reload", error);
471         if (r < 0)
472                 return r;
473
474         unit_reset_failed(u);
475
476         return sd_bus_reply_method_return(message, NULL);
477 }
478
479 int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
480         Unit *u = userdata;
481         int runtime, r;
482
483         assert(bus);
484         assert(message);
485         assert(u);
486
487         r = bus_verify_manage_unit_async(u->manager, message, error);
488         if (r < 0)
489                 return r;
490         if (r == 0)
491                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
492
493         r = sd_bus_message_read(message, "b", &runtime);
494         if (r < 0)
495                 return r;
496
497         r = selinux_unit_access_check(u, message, "start", error);
498         if (r < 0)
499                 return r;
500
501         r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
502         if (r < 0)
503                 return r;
504
505         return sd_bus_reply_method_return(message, NULL);
506 }
507
508 const sd_bus_vtable bus_unit_vtable[] = {
509         SD_BUS_VTABLE_START(0),
510
511         SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
512         SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
513         SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
514         SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
515         SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
516         SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
517         SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
518         SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
519         SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
520         SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
521         SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
522         SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
523         SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
524         SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
525         SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
526         SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST),
527         SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
528         SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST),
529         SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST),
530         SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST),
531         SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST),
532         SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
533         SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
534         SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
535         SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
536         SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
537         SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
538         SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
539         SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
540         SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
541         SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
542         SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
543         SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
544         SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
545         SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
546         BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
547         BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
548         BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
549         BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
550         SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST),
551         SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
552         SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
553         SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
554         SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
555         SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
556         SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
557         SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
558         SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
559         SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
560         SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
561         SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
562         SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
563         SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
564         SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
565         SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
566         BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
567         SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, 0, 0),
568         SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
569         SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
570
571         SD_BUS_METHOD("Start", "s", "o", method_start, 0),
572         SD_BUS_METHOD("Stop", "s", "o", method_stop, 0),
573         SD_BUS_METHOD("Reload", "s", "o", method_reload, 0),
574         SD_BUS_METHOD("Restart", "s", "o", method_restart, 0),
575         SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, 0),
576         SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, 0),
577         SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, 0),
578         SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, 0),
579         SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, 0),
580         SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, 0),
581
582         SD_BUS_VTABLE_END
583 };
584
585 static int property_get_slice(
586                 sd_bus *bus,
587                 const char *path,
588                 const char *interface,
589                 const char *property,
590                 sd_bus_message *reply,
591                 void *userdata,
592                 sd_bus_error *error) {
593
594         Unit *u = userdata;
595
596         assert(bus);
597         assert(reply);
598         assert(u);
599
600         return sd_bus_message_append(reply, "s", unit_slice_name(u));
601 }
602
603 const sd_bus_vtable bus_unit_cgroup_vtable[] = {
604         SD_BUS_VTABLE_START(0),
605         SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
606         SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
607         SD_BUS_VTABLE_END
608 };
609
610 static int send_new_signal(sd_bus *bus, void *userdata) {
611         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
612         _cleanup_free_ char *p = NULL;
613         Unit *u = userdata;
614         int r;
615
616         assert(bus);
617         assert(u);
618
619         p = unit_dbus_path(u);
620         if (!u)
621                 return -ENOMEM;
622
623         r = sd_bus_message_new_signal(
624                         bus,
625                         &m,
626                         "/org/freedesktop/systemd1",
627                         "org.freedesktop.systemd1.Manager",
628                         "UnitNew");
629         if (r < 0)
630                 return r;
631
632         r = sd_bus_message_append(m, "so", u->id, p);
633         if (r < 0)
634                 return r;
635
636         return sd_bus_send(bus, m, NULL);
637 }
638
639 static int send_changed_signal(sd_bus *bus, void *userdata) {
640         _cleanup_free_ char *p = NULL;
641         Unit *u = userdata;
642         int r;
643
644         assert(bus);
645         assert(u);
646
647         p = unit_dbus_path(u);
648         if (!p)
649                 return -ENOMEM;
650
651         /* Send a properties changed signal. First for the specific
652          * type, then for the generic unit. The clients may rely on
653          * this order to get atomic behavior if needed. */
654
655         r = sd_bus_emit_properties_changed_strv(
656                         bus, p,
657                         UNIT_VTABLE(u)->bus_interface,
658                         NULL);
659         if (r < 0)
660                 return r;
661
662         return sd_bus_emit_properties_changed_strv(
663                         bus, p,
664                         "org.freedesktop.systemd1.Unit",
665                         NULL);
666 }
667
668 void bus_unit_send_change_signal(Unit *u) {
669         int r;
670         assert(u);
671
672         if (u->in_dbus_queue) {
673                 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
674                 u->in_dbus_queue = false;
675         }
676
677         if (!u->id)
678                 return;
679
680         r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
681         if (r < 0)
682                 log_debug("Failed to send unit change signal for %s: %s", u->id, strerror(-r));
683
684         u->sent_dbus_new_signal = true;
685 }
686
687 static int send_removed_signal(sd_bus *bus, void *userdata) {
688         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
689         _cleanup_free_ char *p = NULL;
690         Unit *u = userdata;
691         int r;
692
693         assert(bus);
694         assert(u);
695
696         p = unit_dbus_path(u);
697         if (!u)
698                 return -ENOMEM;
699
700         r = sd_bus_message_new_signal(
701                         bus,
702                         &m,
703                         "/org/freedesktop/systemd1",
704                         "org.freedesktop.systemd1.Manager",
705                         "UnitRemoved");
706         if (r < 0)
707                 return r;
708
709         r = sd_bus_message_append(m, "so", u->id, p);
710         if (r < 0)
711                 return r;
712
713         return sd_bus_send(bus, m, NULL);
714 }
715
716 void bus_unit_send_removed_signal(Unit *u) {
717         int r;
718         assert(u);
719
720         if (!u->sent_dbus_new_signal)
721                 bus_unit_send_change_signal(u);
722
723         if (!u->id)
724                 return;
725
726         r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
727         if (r < 0)
728                 log_debug("Failed to send unit remove signal for %s: %s", u->id, strerror(-r));
729 }
730
731 int bus_unit_queue_job(
732                 sd_bus *bus,
733                 sd_bus_message *message,
734                 Unit *u,
735                 JobType type,
736                 JobMode mode,
737                 bool reload_if_possible,
738                 sd_bus_error *error) {
739
740         _cleanup_free_ char *path = NULL;
741         Job *j;
742         int r;
743
744         assert(bus);
745         assert(message);
746         assert(u);
747         assert(type >= 0 && type < _JOB_TYPE_MAX);
748         assert(mode >= 0 && mode < _JOB_MODE_MAX);
749
750         if (reload_if_possible && unit_can_reload(u)) {
751                 if (type == JOB_RESTART)
752                         type = JOB_RELOAD_OR_START;
753                 else if (type == JOB_TRY_RESTART)
754                         type = JOB_RELOAD;
755         }
756
757         r = selinux_unit_access_check(
758                         u, message,
759                         (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
760                         type == JOB_STOP ? "stop" : "reload", error);
761         if (r < 0)
762                 return r;
763
764         if (type == JOB_STOP &&
765             (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
766             unit_active_state(u) == UNIT_INACTIVE)
767                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
768
769         if ((type == JOB_START && u->refuse_manual_start) ||
770             (type == JOB_STOP && u->refuse_manual_stop) ||
771             ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
772                 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
773
774         r = manager_add_job(u->manager, type, u, mode, true, error, &j);
775         if (r < 0)
776                 return r;
777
778         if (bus == u->manager->api_bus) {
779                 if (!j->clients) {
780                         r = sd_bus_track_new(bus, &j->clients, NULL, NULL);
781                         if (r < 0)
782                                 return r;
783                 }
784
785                 r = sd_bus_track_add_sender(j->clients, message);
786                 if (r < 0)
787                         return r;
788         }
789
790         path = job_dbus_path(j);
791         if (!path)
792                 return -ENOMEM;
793
794         return sd_bus_reply_method_return(message, "o", path);
795 }
796
797 static int bus_unit_set_transient_property(
798                 Unit *u,
799                 const char *name,
800                 sd_bus_message *message,
801                 UnitSetPropertiesMode mode,
802                 sd_bus_error *error) {
803
804         int r;
805
806         assert(u);
807         assert(name);
808         assert(message);
809
810         if (streq(name, "Description")) {
811                 const char *d;
812
813                 r = sd_bus_message_read(message, "s", &d);
814                 if (r < 0)
815                         return r;
816
817                 if (mode != UNIT_CHECK) {
818                         r = unit_set_description(u, d);
819                         if (r < 0)
820                                 return r;
821
822                         unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
823                 }
824
825                 return 1;
826
827         } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
828                 const char *s;
829
830                 r = sd_bus_message_read(message, "s", &s);
831                 if (r < 0)
832                         return r;
833
834                 if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
835                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
836
837                 if (isempty(s)) {
838                         if (mode != UNIT_CHECK) {
839                                 unit_ref_unset(&u->slice);
840                                 unit_remove_drop_in(u, mode, name);
841                         }
842                 } else {
843                         Unit *slice;
844
845                         r = manager_load_unit(u->manager, s, NULL, error, &slice);
846                         if (r < 0)
847                                 return r;
848
849                         if (slice->type != UNIT_SLICE)
850                                 return -EINVAL;
851
852                         if (mode != UNIT_CHECK) {
853                                 unit_ref_set(&u->slice, slice);
854                                 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
855                         }
856                 }
857
858                 return 1;
859
860         } else if (streq(name, "Requires") ||
861                    streq(name, "RequiresOverridable") ||
862                    streq(name, "Requisite") ||
863                    streq(name, "RequisiteOverridable") ||
864                    streq(name, "Wants") ||
865                    streq(name, "BindsTo") ||
866                    streq(name, "Conflicts") ||
867                    streq(name, "Before") ||
868                    streq(name, "After") ||
869                    streq(name, "OnFailure") ||
870                    streq(name, "PropagatesReloadTo") ||
871                    streq(name, "ReloadPropagatedFrom") ||
872                    streq(name, "PartOf")) {
873
874                 UnitDependency d;
875                 const char *other;
876
877                 d = unit_dependency_from_string(name);
878                 if (d < 0)
879                         return -EINVAL;
880
881                 r = sd_bus_message_enter_container(message, 'a', "s");
882                 if (r < 0)
883                         return r;
884
885                 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
886                         if (!unit_name_is_valid(other, TEMPLATE_INVALID))
887                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
888
889                         if (mode != UNIT_CHECK) {
890                                 _cleanup_free_ char *label = NULL;
891
892                                 r = unit_add_dependency_by_name(u, d, other, NULL, true);
893                                 if (r < 0)
894                                         return r;
895
896                                 label = strjoin(name, "-", other, NULL);
897                                 if (!label)
898                                         return -ENOMEM;
899
900                                 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
901                         }
902
903                 }
904                 if (r < 0)
905                         return r;
906
907                 r = sd_bus_message_exit_container(message);
908                 if (r < 0)
909                         return r;
910
911                 return 1;
912         }
913
914         return 0;
915 }
916
917 int bus_unit_set_properties(
918                 Unit *u,
919                 sd_bus_message *message,
920                 UnitSetPropertiesMode mode,
921                 bool commit,
922                 sd_bus_error *error) {
923
924         bool for_real = false;
925         unsigned n = 0;
926         int r;
927
928         assert(u);
929         assert(message);
930
931         /* We iterate through the array twice. First run we just check
932          * if all passed data is valid, second run actually applies
933          * it. This is to implement transaction-like behaviour without
934          * actually providing full transactions. */
935
936         r = sd_bus_message_enter_container(message, 'a', "(sv)");
937         if (r < 0)
938                 return r;
939
940         for (;;) {
941                 const char *name;
942
943                 r = sd_bus_message_enter_container(message, 'r', "sv");
944                 if (r < 0)
945                         return r;
946                 if (r == 0) {
947                         if (for_real || mode == UNIT_CHECK)
948                                 break;
949
950                         /* Reached EOF. Let's try again, and this time for realz... */
951                         r = sd_bus_message_rewind(message, false);
952                         if (r < 0)
953                                 return r;
954
955                         for_real = true;
956                         continue;
957                 }
958
959                 r = sd_bus_message_read(message, "s", &name);
960                 if (r < 0)
961                         return r;
962
963                 if (!UNIT_VTABLE(u)->bus_set_property)
964                         return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
965
966                 r = sd_bus_message_enter_container(message, 'v', NULL);
967                 if (r < 0)
968                         return r;
969
970                 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
971                 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
972                         r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
973                 if (r < 0)
974                         return r;
975                 if (r == 0)
976                         return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
977
978                 r = sd_bus_message_exit_container(message);
979                 if (r < 0)
980                         return r;
981
982                 r = sd_bus_message_exit_container(message);
983                 if (r < 0)
984                         return r;
985
986                 n += for_real;
987         }
988
989         r = sd_bus_message_exit_container(message);
990         if (r < 0)
991                 return r;
992
993         if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
994                 UNIT_VTABLE(u)->bus_commit_properties(u);
995
996         return n;
997 }