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