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