chiark / gitweb /
fba3f7cc7057d9ff8fda8fd0cf8c46dab81f045f
[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-common-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_preset(
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         int r;
183
184         assert(bus);
185         assert(reply);
186         assert(u);
187
188         r = unit_get_unit_file_preset(u);
189
190         return sd_bus_message_append(reply, "s",
191                                      r < 0 ? "":
192                                      r > 0 ? "enabled" : "disabled");
193 }
194
195 static int property_get_unit_file_state(
196                 sd_bus *bus,
197                 const char *path,
198                 const char *interface,
199                 const char *property,
200                 sd_bus_message *reply,
201                 void *userdata,
202                 sd_bus_error *error) {
203
204         Unit *u = userdata;
205
206         assert(bus);
207         assert(reply);
208         assert(u);
209
210         return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u)));
211 }
212
213 static int property_get_can_start(
214                 sd_bus *bus,
215                 const char *path,
216                 const char *interface,
217                 const char *property,
218                 sd_bus_message *reply,
219                 void *userdata,
220                 sd_bus_error *error) {
221
222         Unit *u = userdata;
223
224         assert(bus);
225         assert(reply);
226         assert(u);
227
228         return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start);
229 }
230
231 static int property_get_can_stop(
232                 sd_bus *bus,
233                 const char *path,
234                 const char *interface,
235                 const char *property,
236                 sd_bus_message *reply,
237                 void *userdata,
238                 sd_bus_error *error) {
239
240         Unit *u = userdata;
241
242         assert(bus);
243         assert(reply);
244         assert(u);
245
246         /* On the lower levels we assume that every unit we can start
247          * we can also stop */
248
249         return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_stop);
250 }
251
252 static int property_get_can_reload(
253                 sd_bus *bus,
254                 const char *path,
255                 const char *interface,
256                 const char *property,
257                 sd_bus_message *reply,
258                 void *userdata,
259                 sd_bus_error *error) {
260
261         Unit *u = userdata;
262
263         assert(bus);
264         assert(reply);
265         assert(u);
266
267         return sd_bus_message_append(reply, "b", unit_can_reload(u));
268 }
269
270 static int property_get_can_isolate(
271                 sd_bus *bus,
272                 const char *path,
273                 const char *interface,
274                 const char *property,
275                 sd_bus_message *reply,
276                 void *userdata,
277                 sd_bus_error *error) {
278
279         Unit *u = userdata;
280
281         assert(bus);
282         assert(reply);
283         assert(u);
284
285         return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start);
286 }
287
288 static int property_get_job(
289                 sd_bus *bus,
290                 const char *path,
291                 const char *interface,
292                 const char *property,
293                 sd_bus_message *reply,
294                 void *userdata,
295                 sd_bus_error *error) {
296
297         _cleanup_free_ char *p = NULL;
298         Unit *u = userdata;
299
300         assert(bus);
301         assert(reply);
302         assert(u);
303
304         if (!u->job)
305                 return sd_bus_message_append(reply, "(uo)", 0, "/");
306
307         p = job_dbus_path(u->job);
308         if (!p)
309                 return -ENOMEM;
310
311         return sd_bus_message_append(reply, "(uo)", u->job->id, p);
312 }
313
314 static int property_get_need_daemon_reload(
315                 sd_bus *bus,
316                 const char *path,
317                 const char *interface,
318                 const char *property,
319                 sd_bus_message *reply,
320                 void *userdata,
321                 sd_bus_error *error) {
322
323         Unit *u = userdata;
324
325         assert(bus);
326         assert(reply);
327         assert(u);
328
329         return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u));
330 }
331
332 static int property_get_conditions(
333                 sd_bus *bus,
334                 const char *path,
335                 const char *interface,
336                 const char *property,
337                 sd_bus_message *reply,
338                 void *userdata,
339                 sd_bus_error *error) {
340
341         const char *(*to_string)(ConditionType type) = NULL;
342         Condition **list = userdata, *c;
343         int r;
344
345         assert(bus);
346         assert(reply);
347         assert(list);
348
349         to_string = streq(property, "Asserts") ? assert_type_to_string : condition_type_to_string;
350
351         r = sd_bus_message_open_container(reply, 'a', "(sbbsi)");
352         if (r < 0)
353                 return r;
354
355         LIST_FOREACH(conditions, c, *list) {
356                 int tristate;
357
358                 tristate =
359                         c->result == CONDITION_UNTESTED ? 0 :
360                         c->result == CONDITION_SUCCEEDED ? 1 : -1;
361
362                 r = sd_bus_message_append(reply, "(sbbsi)",
363                                           to_string(c->type),
364                                           c->trigger, c->negate,
365                                           c->parameter, tristate);
366                 if (r < 0)
367                         return r;
368
369         }
370
371         return sd_bus_message_close_container(reply);
372 }
373
374 static int property_get_load_error(
375                 sd_bus *bus,
376                 const char *path,
377                 const char *interface,
378                 const char *property,
379                 sd_bus_message *reply,
380                 void *userdata,
381                 sd_bus_error *error) {
382
383         _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
384         Unit *u = userdata;
385
386         assert(bus);
387         assert(reply);
388         assert(u);
389
390         if (u->load_error != 0)
391                 sd_bus_error_set_errno(&e, u->load_error);
392
393         return sd_bus_message_append(reply, "(ss)", e.name, e.message);
394 }
395
396 int bus_unit_method_start_generic(
397                 sd_bus *bus,
398                 sd_bus_message *message,
399                 Unit *u,
400                 JobType job_type,
401                 bool reload_if_possible,
402                 sd_bus_error *error) {
403
404         const char *smode;
405         JobMode mode;
406         int r;
407
408         assert(bus);
409         assert(message);
410         assert(u);
411         assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
412
413         r = mac_selinux_unit_access_check(u, message, job_type == JOB_STOP ? "stop" : "start", error);
414         if (r < 0)
415                 return r;
416
417         r = sd_bus_message_read(message, "s", &smode);
418         if (r < 0)
419                 return r;
420
421         mode = job_mode_from_string(smode);
422         if (mode < 0)
423                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
424
425         r = bus_verify_manage_units_async(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         return bus_unit_queue_job(bus, message, u, job_type, mode, reload_if_possible, error);
432 }
433
434 static int method_start(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
435         return bus_unit_method_start_generic(bus, message, userdata, JOB_START, false, error);
436 }
437
438 static int method_stop(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
439         return bus_unit_method_start_generic(bus, message, userdata, JOB_STOP, false, error);
440 }
441
442 static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
443         return bus_unit_method_start_generic(bus, message, userdata, JOB_RELOAD, false, error);
444 }
445
446 static int method_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
447         return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, false, error);
448 }
449
450 static int method_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
451         return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, false, error);
452 }
453
454 static int method_reload_or_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
455         return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, true, error);
456 }
457
458 static int method_reload_or_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
459         return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, true, error);
460 }
461
462 int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
463         Unit *u = userdata;
464         const char *swho;
465         int32_t signo;
466         KillWho who;
467         int r;
468
469         assert(bus);
470         assert(message);
471         assert(u);
472
473         r = mac_selinux_unit_access_check(u, message, "stop", error);
474         if (r < 0)
475                 return r;
476
477         r = sd_bus_message_read(message, "si", &swho, &signo);
478         if (r < 0)
479                 return r;
480
481         if (isempty(swho))
482                 who = KILL_ALL;
483         else {
484                 who = kill_who_from_string(swho);
485                 if (who < 0)
486                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
487         }
488
489         if (signo <= 0 || signo >= _NSIG)
490                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
491
492         r = bus_verify_manage_units_async_for_kill(u->manager, message, error);
493         if (r < 0)
494                 return r;
495         if (r == 0)
496                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
497
498         r = unit_kill(u, who, signo, error);
499         if (r < 0)
500                 return r;
501
502         return sd_bus_reply_method_return(message, NULL);
503 }
504
505 int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
506         Unit *u = userdata;
507         int r;
508
509         assert(bus);
510         assert(message);
511         assert(u);
512
513         r = mac_selinux_unit_access_check(u, message, "reload", error);
514         if (r < 0)
515                 return r;
516
517         r = bus_verify_manage_units_async(u->manager, message, error);
518         if (r < 0)
519                 return r;
520         if (r == 0)
521                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
522
523         unit_reset_failed(u);
524
525         return sd_bus_reply_method_return(message, NULL);
526 }
527
528 int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
529         Unit *u = userdata;
530         int runtime, r;
531
532         assert(bus);
533         assert(message);
534         assert(u);
535
536         r = mac_selinux_unit_access_check(u, message, "start", error);
537         if (r < 0)
538                 return r;
539
540         r = sd_bus_message_read(message, "b", &runtime);
541         if (r < 0)
542                 return r;
543
544         r = bus_verify_manage_units_async(u->manager, message, error);
545         if (r < 0)
546                 return r;
547         if (r == 0)
548                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
549
550         r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
551         if (r < 0)
552                 return r;
553
554         return sd_bus_reply_method_return(message, NULL);
555 }
556
557 const sd_bus_vtable bus_unit_vtable[] = {
558         SD_BUS_VTABLE_START(0),
559
560         SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
561         SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
562         SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
563         SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
564         SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
565         SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
566         SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
567         SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
568         SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
569         SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
570         SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
571         SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
572         SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
573         SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
574         SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
575         SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST),
576         SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
577         SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST),
578         SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST),
579         SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST),
580         SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST),
581         SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
582         SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
583         SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
584         SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
585         SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
586         SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
587         SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
588         SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
589         SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
590         SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
591         SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
592         SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
593         SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
594         SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
595         SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0),
596         BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
597         BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
598         BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
599         BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
600         SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST),
601         SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
602         SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
603         SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
604         SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
605         SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
606         SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
607         SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
608         SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
609         SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
610         SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
611         SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
612         SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
613         SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
614         SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
615         SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
616         SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
617         SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
618         SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
619         BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
620         BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
621         SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), 0),
622         SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
623         SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
624         SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
625
626         SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
627         SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),
628         SD_BUS_METHOD("Reload", "s", "o", method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
629         SD_BUS_METHOD("Restart", "s", "o", method_restart, SD_BUS_VTABLE_UNPRIVILEGED),
630         SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
631         SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED),
632         SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
633         SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
634         SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
635         SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED),
636
637         SD_BUS_VTABLE_END
638 };
639
640 static int property_get_slice(
641                 sd_bus *bus,
642                 const char *path,
643                 const char *interface,
644                 const char *property,
645                 sd_bus_message *reply,
646                 void *userdata,
647                 sd_bus_error *error) {
648
649         Unit *u = userdata;
650
651         assert(bus);
652         assert(reply);
653         assert(u);
654
655         return sd_bus_message_append(reply, "s", unit_slice_name(u));
656 }
657
658 static int property_get_current_memory(
659                 sd_bus *bus,
660                 const char *path,
661                 const char *interface,
662                 const char *property,
663                 sd_bus_message *reply,
664                 void *userdata,
665                 sd_bus_error *error) {
666
667         Unit *u = userdata;
668         uint64_t sz = (uint64_t) -1;
669         int r;
670
671         assert(bus);
672         assert(reply);
673         assert(u);
674
675         if (u->cgroup_path &&
676             (u->cgroup_realized_mask & CGROUP_MEMORY)) {
677                 _cleanup_free_ char *v = NULL;
678
679                 r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
680                 if (r < 0 && r != -ENOENT)
681                         log_unit_warning_errno(u->id, r, "Couldn't read memory.usage_in_bytes attribute: %m");
682
683                 if (v) {
684                         r = safe_atou64(v, &sz);
685                         if (r < 0)
686                                 log_unit_warning_errno(u->id, r, "Failed to parse memory.usage_in_bytes attribute: %m");
687                 }
688         }
689
690         return sd_bus_message_append(reply, "t", sz);
691 }
692
693 const sd_bus_vtable bus_unit_cgroup_vtable[] = {
694         SD_BUS_VTABLE_START(0),
695         SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
696         SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
697         SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
698         SD_BUS_VTABLE_END
699 };
700
701 static int send_new_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                         "UnitNew");
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 static int send_changed_signal(sd_bus *bus, void *userdata) {
731         _cleanup_free_ char *p = NULL;
732         Unit *u = userdata;
733         int r;
734
735         assert(bus);
736         assert(u);
737
738         p = unit_dbus_path(u);
739         if (!p)
740                 return -ENOMEM;
741
742         /* Send a properties changed signal. First for the specific
743          * type, then for the generic unit. The clients may rely on
744          * this order to get atomic behavior if needed. */
745
746         r = sd_bus_emit_properties_changed_strv(
747                         bus, p,
748                         UNIT_VTABLE(u)->bus_interface,
749                         NULL);
750         if (r < 0)
751                 return r;
752
753         return sd_bus_emit_properties_changed_strv(
754                         bus, p,
755                         "org.freedesktop.systemd1.Unit",
756                         NULL);
757 }
758
759 void bus_unit_send_change_signal(Unit *u) {
760         int r;
761         assert(u);
762
763         if (u->in_dbus_queue) {
764                 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
765                 u->in_dbus_queue = false;
766         }
767
768         if (!u->id)
769                 return;
770
771         r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
772         if (r < 0)
773                 log_debug_errno(r, "Failed to send unit change signal for %s: %m", u->id);
774
775         u->sent_dbus_new_signal = true;
776 }
777
778 static int send_removed_signal(sd_bus *bus, void *userdata) {
779         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
780         _cleanup_free_ char *p = NULL;
781         Unit *u = userdata;
782         int r;
783
784         assert(bus);
785         assert(u);
786
787         p = unit_dbus_path(u);
788         if (!u)
789                 return -ENOMEM;
790
791         r = sd_bus_message_new_signal(
792                         bus,
793                         &m,
794                         "/org/freedesktop/systemd1",
795                         "org.freedesktop.systemd1.Manager",
796                         "UnitRemoved");
797         if (r < 0)
798                 return r;
799
800         r = sd_bus_message_append(m, "so", u->id, p);
801         if (r < 0)
802                 return r;
803
804         return sd_bus_send(bus, m, NULL);
805 }
806
807 void bus_unit_send_removed_signal(Unit *u) {
808         int r;
809         assert(u);
810
811         if (!u->sent_dbus_new_signal)
812                 bus_unit_send_change_signal(u);
813
814         if (!u->id)
815                 return;
816
817         r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
818         if (r < 0)
819                 log_debug_errno(r, "Failed to send unit remove signal for %s: %m", u->id);
820 }
821
822 int bus_unit_queue_job(
823                 sd_bus *bus,
824                 sd_bus_message *message,
825                 Unit *u,
826                 JobType type,
827                 JobMode mode,
828                 bool reload_if_possible,
829                 sd_bus_error *error) {
830
831         _cleanup_free_ char *path = NULL;
832         Job *j;
833         int r;
834
835         assert(bus);
836         assert(message);
837         assert(u);
838         assert(type >= 0 && type < _JOB_TYPE_MAX);
839         assert(mode >= 0 && mode < _JOB_MODE_MAX);
840
841         if (reload_if_possible && unit_can_reload(u)) {
842                 if (type == JOB_RESTART)
843                         type = JOB_RELOAD_OR_START;
844                 else if (type == JOB_TRY_RESTART)
845                         type = JOB_RELOAD;
846         }
847
848         r = mac_selinux_unit_access_check(
849                         u, message,
850                         (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
851                         type == JOB_STOP ? "stop" : "reload", error);
852         if (r < 0)
853                 return r;
854
855         if (type == JOB_STOP &&
856             (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
857             unit_active_state(u) == UNIT_INACTIVE)
858                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
859
860         if ((type == JOB_START && u->refuse_manual_start) ||
861             (type == JOB_STOP && u->refuse_manual_stop) ||
862             ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
863                 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
864
865         r = manager_add_job(u->manager, type, u, mode, true, error, &j);
866         if (r < 0)
867                 return r;
868
869         if (bus == u->manager->api_bus) {
870                 if (!j->clients) {
871                         r = sd_bus_track_new(bus, &j->clients, NULL, NULL);
872                         if (r < 0)
873                                 return r;
874                 }
875
876                 r = sd_bus_track_add_sender(j->clients, message);
877                 if (r < 0)
878                         return r;
879         }
880
881         path = job_dbus_path(j);
882         if (!path)
883                 return -ENOMEM;
884
885         return sd_bus_reply_method_return(message, "o", path);
886 }
887
888 static int bus_unit_set_transient_property(
889                 Unit *u,
890                 const char *name,
891                 sd_bus_message *message,
892                 UnitSetPropertiesMode mode,
893                 sd_bus_error *error) {
894
895         int r;
896
897         assert(u);
898         assert(name);
899         assert(message);
900
901         if (streq(name, "Description")) {
902                 const char *d;
903
904                 r = sd_bus_message_read(message, "s", &d);
905                 if (r < 0)
906                         return r;
907
908                 if (mode != UNIT_CHECK) {
909                         r = unit_set_description(u, d);
910                         if (r < 0)
911                                 return r;
912
913                         unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
914                 }
915
916                 return 1;
917
918         } else if (streq(name, "DefaultDependencies")) {
919                 int b;
920
921                 r = sd_bus_message_read(message, "b", &b);
922                 if (r < 0)
923                         return r;
924
925                 if (mode != UNIT_CHECK) {
926                         u->default_dependencies = b;
927                         unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s\n", yes_no(b));
928                 }
929
930                 return 1;
931
932         } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
933                 const char *s;
934
935                 r = sd_bus_message_read(message, "s", &s);
936                 if (r < 0)
937                         return r;
938
939                 if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
940                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
941
942                 if (isempty(s)) {
943                         if (mode != UNIT_CHECK) {
944                                 unit_ref_unset(&u->slice);
945                                 unit_remove_drop_in(u, mode, name);
946                         }
947                 } else {
948                         Unit *slice;
949
950                         r = manager_load_unit(u->manager, s, NULL, error, &slice);
951                         if (r < 0)
952                                 return r;
953
954                         if (slice->type != UNIT_SLICE)
955                                 return -EINVAL;
956
957                         if (mode != UNIT_CHECK) {
958                                 unit_ref_set(&u->slice, slice);
959                                 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
960                         }
961                 }
962
963                 return 1;
964         } else if (STR_IN_SET(name,
965                               "Requires", "RequiresOverridable",
966                               "Requisite", "RequisiteOverridable",
967                               "Wants",
968                               "BindsTo",
969                               "Conflicts",
970                               "Before", "After",
971                               "OnFailure",
972                               "PropagatesReloadTo", "ReloadPropagatedFrom",
973                               "PartOf")) {
974
975                 UnitDependency d;
976                 const char *other;
977
978                 d = unit_dependency_from_string(name);
979                 if (d < 0)
980                         return -EINVAL;
981
982                 r = sd_bus_message_enter_container(message, 'a', "s");
983                 if (r < 0)
984                         return r;
985
986                 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
987                         if (!unit_name_is_valid(other, TEMPLATE_INVALID))
988                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
989
990                         if (mode != UNIT_CHECK) {
991                                 _cleanup_free_ char *label = NULL;
992
993                                 r = unit_add_dependency_by_name(u, d, other, NULL, true);
994                                 if (r < 0)
995                                         return r;
996
997                                 label = strjoin(name, "-", other, NULL);
998                                 if (!label)
999                                         return -ENOMEM;
1000
1001                                 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
1002                         }
1003
1004                 }
1005                 if (r < 0)
1006                         return r;
1007
1008                 r = sd_bus_message_exit_container(message);
1009                 if (r < 0)
1010                         return r;
1011
1012                 return 1;
1013         }
1014
1015         return 0;
1016 }
1017
1018 int bus_unit_set_properties(
1019                 Unit *u,
1020                 sd_bus_message *message,
1021                 UnitSetPropertiesMode mode,
1022                 bool commit,
1023                 sd_bus_error *error) {
1024
1025         bool for_real = false;
1026         unsigned n = 0;
1027         int r;
1028
1029         assert(u);
1030         assert(message);
1031
1032         /* We iterate through the array twice. First run we just check
1033          * if all passed data is valid, second run actually applies
1034          * it. This is to implement transaction-like behaviour without
1035          * actually providing full transactions. */
1036
1037         r = sd_bus_message_enter_container(message, 'a', "(sv)");
1038         if (r < 0)
1039                 return r;
1040
1041         for (;;) {
1042                 const char *name;
1043
1044                 r = sd_bus_message_enter_container(message, 'r', "sv");
1045                 if (r < 0)
1046                         return r;
1047                 if (r == 0) {
1048                         if (for_real || mode == UNIT_CHECK)
1049                                 break;
1050
1051                         /* Reached EOF. Let's try again, and this time for realz... */
1052                         r = sd_bus_message_rewind(message, false);
1053                         if (r < 0)
1054                                 return r;
1055
1056                         for_real = true;
1057                         continue;
1058                 }
1059
1060                 r = sd_bus_message_read(message, "s", &name);
1061                 if (r < 0)
1062                         return r;
1063
1064                 if (!UNIT_VTABLE(u)->bus_set_property)
1065                         return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
1066
1067                 r = sd_bus_message_enter_container(message, 'v', NULL);
1068                 if (r < 0)
1069                         return r;
1070
1071                 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
1072                 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
1073                         r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
1074                 if (r < 0)
1075                         return r;
1076                 if (r == 0)
1077                         return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
1078
1079                 r = sd_bus_message_exit_container(message);
1080                 if (r < 0)
1081                         return r;
1082
1083                 r = sd_bus_message_exit_container(message);
1084                 if (r < 0)
1085                         return r;
1086
1087                 n += for_real;
1088         }
1089
1090         r = sd_bus_message_exit_container(message);
1091         if (r < 0)
1092                 return r;
1093
1094         if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
1095                 UNIT_VTABLE(u)->bus_commit_properties(u);
1096
1097         return n;
1098 }