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