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