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