chiark / gitweb /
systemctl: add add-wants and add-requires verbs
[elogind.git] / src / core / dbus-scope.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 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 "unit.h"
23 #include "scope.h"
24 #include "dbus-unit.h"
25 #include "dbus-cgroup.h"
26 #include "dbus-kill.h"
27 #include "dbus-scope.h"
28 #include "dbus.h"
29 #include "bus-util.h"
30 #include "bus-internal.h"
31 #include "bus-errors.h"
32
33 static int bus_scope_abandon(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
34         Scope *s = userdata;
35         int r;
36
37         assert(bus);
38         assert(message);
39         assert(s);
40
41         r = bus_verify_manage_unit_async(UNIT(s)->manager, message, error);
42         if (r < 0)
43                 return r;
44         if (r == 0)
45                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
46
47         r = scope_abandon(s);
48         if (sd_bus_error_is_set(error))
49                 return r;
50
51         if (r == -ESTALE)
52                 return sd_bus_error_setf(error, BUS_ERROR_SCOPE_NOT_RUNNING, "Scope %s is not running, cannot abandon.", UNIT(s)->id);
53
54         return sd_bus_reply_method_return(message, NULL);
55 }
56
57 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, scope_result, ScopeResult);
58
59 const sd_bus_vtable bus_scope_vtable[] = {
60         SD_BUS_VTABLE_START(0),
61         SD_BUS_PROPERTY("Controller", "s", NULL, offsetof(Scope, controller), SD_BUS_VTABLE_PROPERTY_CONST),
62         SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Scope, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
63         SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Scope, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
64         SD_BUS_SIGNAL("RequestStop", NULL, 0),
65         SD_BUS_METHOD("Abandon", NULL, NULL, bus_scope_abandon, 0),
66         SD_BUS_VTABLE_END
67 };
68
69 static int bus_scope_set_transient_property(
70                 Scope *s,
71                 const char *name,
72                 sd_bus_message *message,
73                 UnitSetPropertiesMode mode,
74                 sd_bus_error *error) {
75
76         int r;
77
78         assert(s);
79         assert(name);
80         assert(message);
81
82         if (streq(name, "PIDs")) {
83                 unsigned n = 0;
84                 uint32_t pid;
85
86                 r = sd_bus_message_enter_container(message, 'a', "u");
87                 if (r < 0)
88                         return r;
89
90                 while ((r = sd_bus_message_read(message, "u", &pid)) > 0) {
91
92                         if (pid <= 1)
93                                 return -EINVAL;
94
95                         if (mode != UNIT_CHECK) {
96                                 r = unit_watch_pid(UNIT(s), pid);
97                                 if (r < 0 && r != -EEXIST)
98                                         return r;
99                         }
100
101                         n++;
102                 }
103                 if (r < 0)
104                         return r;
105
106                 r = sd_bus_message_exit_container(message);
107                 if (r < 0)
108                         return r;
109
110                 if (n <= 0)
111                         return -EINVAL;
112
113                 return 1;
114
115         } else if (streq(name, "Controller")) {
116                 const char *controller;
117                 char *c;
118
119                 r = sd_bus_message_read(message, "s", &controller);
120                 if (r < 0)
121                         return r;
122
123                 if (!isempty(controller) && !service_name_is_valid(controller))
124                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Controller '%s' is not a valid bus name.", controller);
125
126                 if (mode != UNIT_CHECK) {
127                         if (isempty(controller))
128                                 c = NULL;
129                         else {
130                                 c = strdup(controller);
131                                 if (!c)
132                                         return -ENOMEM;
133                         }
134
135                         free(s->controller);
136                         s->controller = c;
137                 }
138
139                 return 1;
140
141         } else if (streq(name, "TimeoutStopUSec")) {
142
143                 if (mode != UNIT_CHECK) {
144                         r = sd_bus_message_read(message, "t", &s->timeout_stop_usec);
145                         if (r < 0)
146                                 return r;
147
148                         unit_write_drop_in_format(UNIT(s), mode, name, "[Scope]\nTimeoutStopSec="USEC_FMT"us\n", s->timeout_stop_usec);
149                 } else {
150                         r = sd_bus_message_skip(message, "t");
151                         if (r < 0)
152                                 return r;
153                 }
154
155                 return 1;
156         }
157
158         return 0;
159 }
160
161 int bus_scope_set_property(
162                 Unit *u,
163                 const char *name,
164                 sd_bus_message *message,
165                 UnitSetPropertiesMode mode,
166                 sd_bus_error *error) {
167
168         Scope *s = SCOPE(u);
169         int r;
170
171         assert(s);
172         assert(name);
173         assert(message);
174
175         r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
176         if (r != 0)
177                 return r;
178
179         if (u->load_state == UNIT_STUB) {
180                 /* While we are created we still accept PIDs */
181
182                 r = bus_scope_set_transient_property(s, name, message, mode, error);
183                 if (r != 0)
184                         return r;
185
186                 r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, mode, error);
187                 if (r != 0)
188                         return r;
189         }
190
191         return 0;
192 }
193
194 int bus_scope_commit_properties(Unit *u) {
195         assert(u);
196
197         unit_update_cgroup_members_masks(u);
198         unit_realize_cgroup(u);
199
200         return 0;
201 }
202
203 int bus_scope_send_request_stop(Scope *s) {
204         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
205         _cleanup_free_ char *p = NULL;
206         int r;
207
208         assert(s);
209
210         if (!s->controller)
211                 return 0;
212
213         p = unit_dbus_path(UNIT(s));
214         if (!p)
215                 return -ENOMEM;
216
217         r = sd_bus_message_new_signal(
218                         UNIT(s)->manager->api_bus,
219                         &m,
220                         p,
221                         "org.freedesktop.systemd1.Scope",
222                         "RequestStop");
223         if (r < 0)
224                 return r;
225
226         return sd_bus_send_to(UNIT(s)->manager->api_bus, m, /* s->controller */ NULL, NULL);
227 }