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