chiark / gitweb /
core: fix return value on OOM
[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         Unit *u = userdata;
665         uint64_t sz = (uint64_t) -1;
666         int r;
667
668         assert(bus);
669         assert(reply);
670         assert(u);
671
672         if (u->cgroup_path &&
673             (u->cgroup_realized_mask & CGROUP_MEMORY)) {
674                 _cleanup_free_ char *v = NULL;
675
676                 r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
677                 if (r < 0 && r != -ENOENT)
678                         log_unit_warning_errno(u->id, r, "Couldn't read memory.usage_in_bytes attribute: %m");
679
680                 if (v) {
681                         r = safe_atou64(v, &sz);
682                         if (r < 0)
683                                 log_unit_warning_errno(u->id, r, "Failed to parse memory.usage_in_bytes attribute: %m");
684                 }
685         }
686
687         return sd_bus_message_append(reply, "t", sz);
688 }
689
690 const sd_bus_vtable bus_unit_cgroup_vtable[] = {
691         SD_BUS_VTABLE_START(0),
692         SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
693         SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
694         SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
695         SD_BUS_VTABLE_END
696 };
697
698 static int send_new_signal(sd_bus *bus, void *userdata) {
699         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
700         _cleanup_free_ char *p = NULL;
701         Unit *u = userdata;
702         int r;
703
704         assert(bus);
705         assert(u);
706
707         p = unit_dbus_path(u);
708         if (!u)
709                 return -ENOMEM;
710
711         r = sd_bus_message_new_signal(
712                         bus,
713                         &m,
714                         "/org/freedesktop/systemd1",
715                         "org.freedesktop.systemd1.Manager",
716                         "UnitNew");
717         if (r < 0)
718                 return r;
719
720         r = sd_bus_message_append(m, "so", u->id, p);
721         if (r < 0)
722                 return r;
723
724         return sd_bus_send(bus, m, NULL);
725 }
726
727 static int send_changed_signal(sd_bus *bus, void *userdata) {
728         _cleanup_free_ char *p = NULL;
729         Unit *u = userdata;
730         int r;
731
732         assert(bus);
733         assert(u);
734
735         p = unit_dbus_path(u);
736         if (!p)
737                 return -ENOMEM;
738
739         /* Send a properties changed signal. First for the specific
740          * type, then for the generic unit. The clients may rely on
741          * this order to get atomic behavior if needed. */
742
743         r = sd_bus_emit_properties_changed_strv(
744                         bus, p,
745                         UNIT_VTABLE(u)->bus_interface,
746                         NULL);
747         if (r < 0)
748                 return r;
749
750         return sd_bus_emit_properties_changed_strv(
751                         bus, p,
752                         "org.freedesktop.systemd1.Unit",
753                         NULL);
754 }
755
756 void bus_unit_send_change_signal(Unit *u) {
757         int r;
758         assert(u);
759
760         if (u->in_dbus_queue) {
761                 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
762                 u->in_dbus_queue = false;
763         }
764
765         if (!u->id)
766                 return;
767
768         r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
769         if (r < 0)
770                 log_debug_errno(r, "Failed to send unit change signal for %s: %m", u->id);
771
772         u->sent_dbus_new_signal = true;
773 }
774
775 static int send_removed_signal(sd_bus *bus, void *userdata) {
776         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
777         _cleanup_free_ char *p = NULL;
778         Unit *u = userdata;
779         int r;
780
781         assert(bus);
782         assert(u);
783
784         p = unit_dbus_path(u);
785         if (!u)
786                 return -ENOMEM;
787
788         r = sd_bus_message_new_signal(
789                         bus,
790                         &m,
791                         "/org/freedesktop/systemd1",
792                         "org.freedesktop.systemd1.Manager",
793                         "UnitRemoved");
794         if (r < 0)
795                 return r;
796
797         r = sd_bus_message_append(m, "so", u->id, p);
798         if (r < 0)
799                 return r;
800
801         return sd_bus_send(bus, m, NULL);
802 }
803
804 void bus_unit_send_removed_signal(Unit *u) {
805         int r;
806         assert(u);
807
808         if (!u->sent_dbus_new_signal)
809                 bus_unit_send_change_signal(u);
810
811         if (!u->id)
812                 return;
813
814         r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
815         if (r < 0)
816                 log_debug_errno(r, "Failed to send unit remove signal for %s: %m", u->id);
817 }
818
819 int bus_unit_queue_job(
820                 sd_bus *bus,
821                 sd_bus_message *message,
822                 Unit *u,
823                 JobType type,
824                 JobMode mode,
825                 bool reload_if_possible,
826                 sd_bus_error *error) {
827
828         _cleanup_free_ char *path = NULL;
829         Job *j;
830         int r;
831
832         assert(bus);
833         assert(message);
834         assert(u);
835         assert(type >= 0 && type < _JOB_TYPE_MAX);
836         assert(mode >= 0 && mode < _JOB_MODE_MAX);
837
838         if (reload_if_possible && unit_can_reload(u)) {
839                 if (type == JOB_RESTART)
840                         type = JOB_RELOAD_OR_START;
841                 else if (type == JOB_TRY_RESTART)
842                         type = JOB_RELOAD;
843         }
844
845         r = mac_selinux_unit_access_check(
846                         u, message,
847                         (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
848                         type == JOB_STOP ? "stop" : "reload", error);
849         if (r < 0)
850                 return r;
851
852         if (type == JOB_STOP &&
853             (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
854             unit_active_state(u) == UNIT_INACTIVE)
855                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
856
857         if ((type == JOB_START && u->refuse_manual_start) ||
858             (type == JOB_STOP && u->refuse_manual_stop) ||
859             ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
860                 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
861
862         r = manager_add_job(u->manager, type, u, mode, true, error, &j);
863         if (r < 0)
864                 return r;
865
866         if (bus == u->manager->api_bus) {
867                 if (!j->clients) {
868                         r = sd_bus_track_new(bus, &j->clients, NULL, NULL);
869                         if (r < 0)
870                                 return r;
871                 }
872
873                 r = sd_bus_track_add_sender(j->clients, message);
874                 if (r < 0)
875                         return r;
876         }
877
878         path = job_dbus_path(j);
879         if (!path)
880                 return -ENOMEM;
881
882         return sd_bus_reply_method_return(message, "o", path);
883 }
884
885 static int bus_unit_set_transient_property(
886                 Unit *u,
887                 const char *name,
888                 sd_bus_message *message,
889                 UnitSetPropertiesMode mode,
890                 sd_bus_error *error) {
891
892         int r;
893
894         assert(u);
895         assert(name);
896         assert(message);
897
898         if (streq(name, "Description")) {
899                 const char *d;
900
901                 r = sd_bus_message_read(message, "s", &d);
902                 if (r < 0)
903                         return r;
904
905                 if (mode != UNIT_CHECK) {
906                         r = unit_set_description(u, d);
907                         if (r < 0)
908                                 return r;
909
910                         unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
911                 }
912
913                 return 1;
914
915         } else if (streq(name, "DefaultDependencies")) {
916                 int b;
917
918                 r = sd_bus_message_read(message, "b", &b);
919                 if (r < 0)
920                         return r;
921
922                 if (mode != UNIT_CHECK) {
923                         u->default_dependencies = b;
924                         unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s\n", yes_no(b));
925                 }
926
927                 return 1;
928
929         } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
930                 const char *s;
931
932                 r = sd_bus_message_read(message, "s", &s);
933                 if (r < 0)
934                         return r;
935
936                 if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
937                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
938
939                 if (isempty(s)) {
940                         if (mode != UNIT_CHECK) {
941                                 unit_ref_unset(&u->slice);
942                                 unit_remove_drop_in(u, mode, name);
943                         }
944                 } else {
945                         Unit *slice;
946
947                         r = manager_load_unit(u->manager, s, NULL, error, &slice);
948                         if (r < 0)
949                                 return r;
950
951                         if (slice->type != UNIT_SLICE)
952                                 return -EINVAL;
953
954                         if (mode != UNIT_CHECK) {
955                                 unit_ref_set(&u->slice, slice);
956                                 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
957                         }
958                 }
959
960                 return 1;
961         } else if (STR_IN_SET(name,
962                               "Requires", "RequiresOverridable",
963                               "Requisite", "RequisiteOverridable",
964                               "Wants",
965                               "BindsTo",
966                               "Conflicts",
967                               "Before", "After",
968                               "OnFailure",
969                               "PropagatesReloadTo", "ReloadPropagatedFrom",
970                               "PartOf")) {
971
972                 UnitDependency d;
973                 const char *other;
974
975                 d = unit_dependency_from_string(name);
976                 if (d < 0)
977                         return -EINVAL;
978
979                 r = sd_bus_message_enter_container(message, 'a', "s");
980                 if (r < 0)
981                         return r;
982
983                 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
984                         if (!unit_name_is_valid(other, TEMPLATE_INVALID))
985                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
986
987                         if (mode != UNIT_CHECK) {
988                                 _cleanup_free_ char *label = NULL;
989
990                                 r = unit_add_dependency_by_name(u, d, other, NULL, true);
991                                 if (r < 0)
992                                         return r;
993
994                                 label = strjoin(name, "-", other, NULL);
995                                 if (!label)
996                                         return -ENOMEM;
997
998                                 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
999                         }
1000
1001                 }
1002                 if (r < 0)
1003                         return r;
1004
1005                 r = sd_bus_message_exit_container(message);
1006                 if (r < 0)
1007                         return r;
1008
1009                 return 1;
1010         }
1011
1012         return 0;
1013 }
1014
1015 int bus_unit_set_properties(
1016                 Unit *u,
1017                 sd_bus_message *message,
1018                 UnitSetPropertiesMode mode,
1019                 bool commit,
1020                 sd_bus_error *error) {
1021
1022         bool for_real = false;
1023         unsigned n = 0;
1024         int r;
1025
1026         assert(u);
1027         assert(message);
1028
1029         /* We iterate through the array twice. First run we just check
1030          * if all passed data is valid, second run actually applies
1031          * it. This is to implement transaction-like behaviour without
1032          * actually providing full transactions. */
1033
1034         r = sd_bus_message_enter_container(message, 'a', "(sv)");
1035         if (r < 0)
1036                 return r;
1037
1038         for (;;) {
1039                 const char *name;
1040
1041                 r = sd_bus_message_enter_container(message, 'r', "sv");
1042                 if (r < 0)
1043                         return r;
1044                 if (r == 0) {
1045                         if (for_real || mode == UNIT_CHECK)
1046                                 break;
1047
1048                         /* Reached EOF. Let's try again, and this time for realz... */
1049                         r = sd_bus_message_rewind(message, false);
1050                         if (r < 0)
1051                                 return r;
1052
1053                         for_real = true;
1054                         continue;
1055                 }
1056
1057                 r = sd_bus_message_read(message, "s", &name);
1058                 if (r < 0)
1059                         return r;
1060
1061                 if (!UNIT_VTABLE(u)->bus_set_property)
1062                         return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
1063
1064                 r = sd_bus_message_enter_container(message, 'v', NULL);
1065                 if (r < 0)
1066                         return r;
1067
1068                 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
1069                 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
1070                         r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
1071                 if (r < 0)
1072                         return r;
1073                 if (r == 0)
1074                         return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
1075
1076                 r = sd_bus_message_exit_container(message);
1077                 if (r < 0)
1078                         return r;
1079
1080                 r = sd_bus_message_exit_container(message);
1081                 if (r < 0)
1082                         return r;
1083
1084                 n += for_real;
1085         }
1086
1087         r = sd_bus_message_exit_container(message);
1088         if (r < 0)
1089                 return r;
1090
1091         if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
1092                 UNIT_VTABLE(u)->bus_commit_properties(u);
1093
1094         return n;
1095 }