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