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