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