]>
Commit | Line | Data |
---|---|---|
d6c9574f | 1 | /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
ea430986 | 2 | |
a7334b09 LP |
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 | |
5430f7f2 LP |
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 | |
a7334b09 LP |
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 | |
5430f7f2 | 16 | Lesser General Public License for more details. |
a7334b09 | 17 | |
5430f7f2 | 18 | You should have received a copy of the GNU Lesser General Public License |
a7334b09 LP |
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. |
20 | ***/ | |
21 | ||
718db961 | 22 | #include "sd-bus.h" |
ea430986 | 23 | #include "log.h" |
e2417e41 | 24 | #include "selinux-access.h" |
246aa6dd LP |
25 | #include "cgroup-util.h" |
26 | #include "strv.h" | |
27 | #include "path-util.h" | |
a5c32cff | 28 | #include "fileio.h" |
718db961 LP |
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, | |
ebcf1f97 LP |
42 | void *userdata, |
43 | sd_bus_error *error) { | |
718db961 LP |
44 | |
45 | Unit *u = userdata; | |
46 | Iterator i; | |
47 | const char *t; | |
48 | int r; | |
ea430986 | 49 | |
718db961 LP |
50 | assert(bus); |
51 | assert(reply); | |
52 | assert(u); | |
4139c1b2 | 53 | |
718db961 LP |
54 | r = sd_bus_message_open_container(reply, 'a', "s"); |
55 | if (r < 0) | |
56 | return r; | |
4139c1b2 | 57 | |
718db961 LP |
58 | SET_FOREACH(t, u->names, i) { |
59 | r = sd_bus_message_append(reply, "s", t); | |
60 | if (r < 0) | |
61 | return r; | |
62 | } | |
4139c1b2 | 63 | |
718db961 | 64 | return sd_bus_message_close_container(reply); |
4139c1b2 LP |
65 | } |
66 | ||
718db961 LP |
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, | |
ebcf1f97 LP |
73 | void *userdata, |
74 | sd_bus_error *error) { | |
718db961 LP |
75 | |
76 | Unit *u = userdata, *f; | |
8fe914ec | 77 | |
718db961 LP |
78 | assert(bus); |
79 | assert(reply); | |
8fe914ec LP |
80 | assert(u); |
81 | ||
a7f241db | 82 | f = unit_following(u); |
718db961 | 83 | return sd_bus_message_append(reply, "s", f ? f->id : ""); |
8fe914ec LP |
84 | } |
85 | ||
718db961 LP |
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, | |
ebcf1f97 LP |
92 | void *userdata, |
93 | sd_bus_error *error) { | |
4ec9a8a4 | 94 | |
718db961 | 95 | Set *s = *(Set**) userdata; |
5301be81 | 96 | Iterator j; |
718db961 LP |
97 | Unit *u; |
98 | int r; | |
5301be81 | 99 | |
718db961 LP |
100 | assert(bus); |
101 | assert(reply); | |
5301be81 | 102 | |
718db961 LP |
103 | r = sd_bus_message_open_container(reply, 'a', "s"); |
104 | if (r < 0) | |
105 | return r; | |
5301be81 | 106 | |
718db961 LP |
107 | SET_FOREACH(u, s, j) { |
108 | r = sd_bus_message_append(reply, "s", u->id); | |
109 | if (r < 0) | |
110 | return r; | |
111 | } | |
5301be81 | 112 | |
718db961 | 113 | return sd_bus_message_close_container(reply); |
5301be81 LP |
114 | } |
115 | ||
718db961 LP |
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, | |
ebcf1f97 LP |
122 | void *userdata, |
123 | sd_bus_error *error) { | |
ea430986 | 124 | |
718db961 | 125 | Unit *u = userdata; |
ea430986 | 126 | |
718db961 LP |
127 | assert(bus); |
128 | assert(reply); | |
129 | assert(u); | |
ea430986 | 130 | |
718db961 | 131 | return sd_bus_message_append(reply, "s", unit_description(u)); |
ea430986 LP |
132 | } |
133 | ||
718db961 LP |
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, | |
ebcf1f97 LP |
140 | void *userdata, |
141 | sd_bus_error *error) { | |
ea430986 | 142 | |
718db961 | 143 | Unit *u = userdata; |
ea430986 | 144 | |
718db961 LP |
145 | assert(bus); |
146 | assert(reply); | |
ea430986 LP |
147 | assert(u); |
148 | ||
718db961 | 149 | return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u))); |
ea430986 LP |
150 | } |
151 | ||
718db961 LP |
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, | |
ebcf1f97 LP |
158 | void *userdata, |
159 | sd_bus_error *error) { | |
10a94420 | 160 | |
718db961 | 161 | Unit *u = userdata; |
10a94420 | 162 | |
718db961 LP |
163 | assert(bus); |
164 | assert(reply); | |
165 | assert(u); | |
10a94420 | 166 | |
718db961 | 167 | return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u)); |
10a94420 LP |
168 | } |
169 | ||
718db961 LP |
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, | |
ebcf1f97 LP |
176 | void *userdata, |
177 | sd_bus_error *error) { | |
a4375746 | 178 | |
718db961 | 179 | Unit *u = userdata; |
a4375746 | 180 | |
718db961 LP |
181 | assert(bus); |
182 | assert(reply); | |
183 | assert(u); | |
a4375746 | 184 | |
718db961 | 185 | return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u))); |
a4375746 LP |
186 | } |
187 | ||
718db961 LP |
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, | |
ebcf1f97 LP |
194 | void *userdata, |
195 | sd_bus_error *error) { | |
38131695 | 196 | |
718db961 | 197 | Unit *u = userdata; |
b5e9dba8 | 198 | |
718db961 LP |
199 | assert(bus); |
200 | assert(reply); | |
201 | assert(u); | |
b5e9dba8 | 202 | |
718db961 | 203 | return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start); |
b5e9dba8 LP |
204 | } |
205 | ||
718db961 LP |
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, | |
ebcf1f97 LP |
212 | void *userdata, |
213 | sd_bus_error *error) { | |
718db961 LP |
214 | |
215 | Unit *u = userdata; | |
b5e9dba8 | 216 | |
718db961 LP |
217 | assert(bus); |
218 | assert(reply); | |
b5e9dba8 LP |
219 | assert(u); |
220 | ||
221 | /* On the lower levels we assume that every unit we can start | |
222 | * we can also stop */ | |
223 | ||
718db961 | 224 | return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_stop); |
38131695 LP |
225 | } |
226 | ||
718db961 LP |
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, | |
ebcf1f97 LP |
233 | void *userdata, |
234 | sd_bus_error *error) { | |
38131695 | 235 | |
718db961 | 236 | Unit *u = userdata; |
38131695 | 237 | |
718db961 LP |
238 | assert(bus); |
239 | assert(reply); | |
240 | assert(u); | |
38131695 | 241 | |
718db961 | 242 | return sd_bus_message_append(reply, "b", unit_can_reload(u)); |
38131695 LP |
243 | } |
244 | ||
718db961 LP |
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, | |
ebcf1f97 LP |
251 | void *userdata, |
252 | sd_bus_error *error) { | |
2528a7a6 | 253 | |
718db961 | 254 | Unit *u = userdata; |
2528a7a6 | 255 | |
718db961 LP |
256 | assert(bus); |
257 | assert(reply); | |
258 | assert(u); | |
2528a7a6 | 259 | |
718db961 | 260 | return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start); |
2528a7a6 LP |
261 | } |
262 | ||
718db961 LP |
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, | |
ebcf1f97 LP |
269 | void *userdata, |
270 | sd_bus_error *error) { | |
718db961 | 271 | |
f93891f3 | 272 | _cleanup_free_ char *p = NULL; |
718db961 | 273 | Unit *u = userdata; |
38131695 | 274 | |
718db961 LP |
275 | assert(bus); |
276 | assert(reply); | |
38131695 LP |
277 | assert(u); |
278 | ||
718db961 LP |
279 | if (!u->job) |
280 | return sd_bus_message_append(reply, "(uo)", 0, "/"); | |
38131695 | 281 | |
718db961 LP |
282 | p = job_dbus_path(u->job); |
283 | if (!p) | |
284 | return -ENOMEM; | |
38131695 | 285 | |
718db961 LP |
286 | return sd_bus_message_append(reply, "(uo)", u->job->id, p); |
287 | } | |
38131695 | 288 | |
718db961 LP |
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, | |
ebcf1f97 LP |
295 | void *userdata, |
296 | sd_bus_error *error) { | |
38131695 | 297 | |
718db961 | 298 | Unit *u = userdata; |
38131695 | 299 | |
718db961 LP |
300 | assert(bus); |
301 | assert(reply); | |
302 | assert(u); | |
38131695 | 303 | |
718db961 | 304 | return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u)); |
38131695 LP |
305 | } |
306 | ||
718db961 LP |
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, | |
ebcf1f97 LP |
313 | void *userdata, |
314 | sd_bus_error *error) { | |
45fb0699 | 315 | |
718db961 LP |
316 | Unit *u = userdata; |
317 | Condition *c; | |
318 | int r; | |
45fb0699 | 319 | |
718db961 LP |
320 | assert(bus); |
321 | assert(reply); | |
322 | assert(u); | |
45fb0699 | 323 | |
718db961 LP |
324 | r = sd_bus_message_open_container(reply, 'a', "(sbbsi)"); |
325 | if (r < 0) | |
326 | return r; | |
45fb0699 | 327 | |
718db961 LP |
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; | |
45fb0699 | 332 | |
718db961 | 333 | } |
52990c2e | 334 | |
718db961 | 335 | return sd_bus_message_close_container(reply); |
52990c2e ZJS |
336 | } |
337 | ||
718db961 LP |
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, | |
ebcf1f97 LP |
344 | void *userdata, |
345 | sd_bus_error *error) { | |
52990c2e | 346 | |
718db961 LP |
347 | _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL; |
348 | Unit *u = userdata; | |
52990c2e | 349 | |
718db961 LP |
350 | assert(bus); |
351 | assert(reply); | |
352 | assert(u); | |
52990c2e | 353 | |
718db961 LP |
354 | if (u->load_error != 0) |
355 | sd_bus_error_set_errno(&e, u->load_error); | |
52990c2e | 356 | |
718db961 | 357 | return sd_bus_message_append(reply, "(ss)", e.name, e.message); |
52990c2e ZJS |
358 | } |
359 | ||
ebcf1f97 | 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) { |
718db961 LP |
361 | const char *smode; |
362 | JobMode mode; | |
363 | int r; | |
9f39404c | 364 | |
718db961 LP |
365 | assert(bus); |
366 | assert(message); | |
9f39404c | 367 | assert(u); |
718db961 | 368 | assert(job_type >= 0 && job_type < _JOB_TYPE_MAX); |
9f39404c | 369 | |
718db961 LP |
370 | r = sd_bus_message_read(message, "s", &smode); |
371 | if (r < 0) | |
ebcf1f97 | 372 | return r; |
9f39404c | 373 | |
718db961 LP |
374 | mode = job_mode_from_string(smode); |
375 | if (mode < 0) | |
ebcf1f97 | 376 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode); |
9f39404c | 377 | |
ebcf1f97 | 378 | return bus_unit_queue_job(bus, message, u, job_type, mode, reload_if_possible, error); |
9f39404c LP |
379 | } |
380 | ||
ebcf1f97 LP |
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); | |
718db961 | 383 | } |
b548631a | 384 | |
ebcf1f97 LP |
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); | |
718db961 LP |
387 | } |
388 | ||
ebcf1f97 LP |
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); | |
718db961 | 391 | } |
0a524ba7 | 392 | |
ebcf1f97 LP |
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); | |
718db961 | 395 | } |
8a0867d6 | 396 | |
ebcf1f97 LP |
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); | |
718db961 | 399 | } |
cad45ba1 | 400 | |
ebcf1f97 LP |
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); | |
718db961 | 403 | } |
8a0867d6 | 404 | |
ebcf1f97 LP |
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); | |
718db961 | 407 | } |
8a0867d6 | 408 | |
ebcf1f97 | 409 | int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { |
718db961 LP |
410 | Unit *u = userdata; |
411 | const char *swho; | |
412 | int32_t signo; | |
413 | KillWho who; | |
414 | int r; | |
5632e374 | 415 | |
718db961 LP |
416 | assert(bus); |
417 | assert(message); | |
418 | assert(u); | |
cad45ba1 | 419 | |
718db961 LP |
420 | r = sd_bus_message_read(message, "si", &swho, &signo); |
421 | if (r < 0) | |
ebcf1f97 | 422 | return r; |
718db961 LP |
423 | |
424 | if (isempty(swho)) | |
425 | who = KILL_ALL; | |
426 | else { | |
427 | who = kill_who_from_string(swho); | |
428 | if (who < 0) | |
ebcf1f97 | 429 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho); |
718db961 | 430 | } |
5632e374 | 431 | |
718db961 | 432 | if (signo <= 0 || signo >= _NSIG) |
ebcf1f97 | 433 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range."); |
8e2af478 | 434 | |
ebcf1f97 LP |
435 | r = selinux_unit_access_check(u, bus, message, "stop", error); |
436 | if (r < 0) | |
437 | return r; | |
8e2af478 | 438 | |
ebcf1f97 | 439 | r = unit_kill(u, who, signo, error); |
718db961 | 440 | if (r < 0) |
ebcf1f97 | 441 | return r; |
8e2af478 | 442 | |
df2d202e | 443 | return sd_bus_reply_method_return(message, NULL); |
718db961 | 444 | } |
8e2af478 | 445 | |
ebcf1f97 | 446 | int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { |
718db961 | 447 | Unit *u = userdata; |
ebcf1f97 | 448 | int r; |
b548631a | 449 | |
718db961 LP |
450 | assert(bus); |
451 | assert(message); | |
452 | assert(u); | |
b548631a | 453 | |
ebcf1f97 LP |
454 | r = selinux_unit_access_check(u, bus, message, "reload", error); |
455 | if (r < 0) | |
456 | return r; | |
b548631a | 457 | |
718db961 | 458 | unit_reset_failed(u); |
b548631a | 459 | |
df2d202e | 460 | return sd_bus_reply_method_return(message, NULL); |
ea430986 LP |
461 | } |
462 | ||
ebcf1f97 | 463 | int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { |
718db961 LP |
464 | Unit *u = userdata; |
465 | int runtime, r; | |
ea430986 | 466 | |
718db961 | 467 | assert(bus); |
ea430986 | 468 | assert(message); |
718db961 | 469 | assert(u); |
80fbf05e | 470 | |
718db961 LP |
471 | r = sd_bus_message_read(message, "b", &runtime); |
472 | if (r < 0) | |
ebcf1f97 | 473 | return r; |
2cccbca4 | 474 | |
ebcf1f97 LP |
475 | r = selinux_unit_access_check(u, bus, message, "start", error); |
476 | if (r < 0) | |
477 | return r; | |
cad45ba1 | 478 | |
718db961 LP |
479 | r = sd_bus_message_enter_container(message, 'a', "(sv)"); |
480 | if (r < 0) | |
ebcf1f97 | 481 | return r; |
2cccbca4 | 482 | |
ebcf1f97 | 483 | r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error); |
718db961 | 484 | if (r < 0) |
ebcf1f97 | 485 | return r; |
2cccbca4 | 486 | |
718db961 LP |
487 | r = sd_bus_message_exit_container(message); |
488 | if (r < 0) | |
ebcf1f97 | 489 | return r; |
2cccbca4 | 490 | |
df2d202e | 491 | return sd_bus_reply_method_return(message, NULL); |
718db961 | 492 | } |
2cccbca4 | 493 | |
718db961 LP |
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 | }; | |
2cccbca4 | 569 | |
718db961 LP |
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, | |
ebcf1f97 LP |
576 | void *userdata, |
577 | sd_bus_error *error) { | |
2cccbca4 | 578 | |
718db961 | 579 | Unit *u = userdata; |
2cccbca4 | 580 | |
718db961 LP |
581 | assert(bus); |
582 | assert(reply); | |
583 | assert(u); | |
2cccbca4 | 584 | |
718db961 LP |
585 | return sd_bus_message_append(reply, "s", unit_slice_name(u)); |
586 | } | |
2cccbca4 | 587 | |
718db961 LP |
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 | }; | |
2cccbca4 | 594 | |
718db961 LP |
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; | |
2cccbca4 | 600 | |
718db961 LP |
601 | assert(bus); |
602 | assert(u); | |
2cccbca4 | 603 | |
718db961 LP |
604 | p = unit_dbus_path(u); |
605 | if (!u) | |
606 | return -ENOMEM; | |
2cccbca4 | 607 | |
718db961 LP |
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; | |
2cccbca4 | 616 | |
718db961 LP |
617 | r = sd_bus_message_append(m, "so", u->id, p); |
618 | if (r < 0) | |
619 | return r; | |
2cccbca4 | 620 | |
718db961 LP |
621 | return sd_bus_send_to(bus, m, destination, NULL); |
622 | } | |
2cccbca4 | 623 | |
718db961 LP |
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; | |
2cccbca4 | 628 | |
718db961 LP |
629 | assert(bus); |
630 | assert(u); | |
2cccbca4 | 631 | |
718db961 LP |
632 | p = unit_dbus_path(u); |
633 | if (!u) | |
634 | return -ENOMEM; | |
2cccbca4 | 635 | |
718db961 LP |
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. */ | |
ea430986 | 639 | |
718db961 | 640 | if (UNIT_VTABLE(u)->bus_changing_properties) { |
2cccbca4 | 641 | |
718db961 LP |
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 | } | |
80fbf05e | 649 | |
718db961 LP |
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); | |
ea430986 LP |
663 | } |
664 | ||
c1e1601e | 665 | void bus_unit_send_change_signal(Unit *u) { |
b170dd80 | 666 | int r; |
c1e1601e LP |
667 | |
668 | assert(u); | |
c1e1601e | 669 | |
ac155bb8 | 670 | if (u->in_dbus_queue) { |
71fda00f | 671 | LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u); |
ac155bb8 | 672 | u->in_dbus_queue = false; |
c0bd0cf7 | 673 | } |
c1e1601e | 674 | |
ac155bb8 | 675 | if (!u->id) |
04ade7d2 LP |
676 | return; |
677 | ||
718db961 LP |
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)); | |
c1e1601e | 681 | |
718db961 LP |
682 | u->sent_dbus_new_signal = true; |
683 | } | |
c4e2ceae | 684 | |
718db961 LP |
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; | |
c4e2ceae | 690 | |
718db961 LP |
691 | assert(bus); |
692 | assert(u); | |
c1e1601e | 693 | |
718db961 LP |
694 | p = unit_dbus_path(u); |
695 | if (!u) | |
696 | return -ENOMEM; | |
c1e1601e | 697 | |
718db961 LP |
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; | |
c1e1601e | 706 | |
718db961 LP |
707 | r = sd_bus_message_append(m, "so", u->id, p); |
708 | if (r < 0) | |
709 | return r; | |
c1e1601e | 710 | |
718db961 | 711 | return sd_bus_send_to(bus, m, destination, NULL); |
c1e1601e LP |
712 | } |
713 | ||
714 | void bus_unit_send_removed_signal(Unit *u) { | |
718db961 | 715 | int r; |
c1e1601e LP |
716 | |
717 | assert(u); | |
718 | ||
ac155bb8 | 719 | if (!u->sent_dbus_new_signal) |
7535cc78 LP |
720 | bus_unit_send_change_signal(u); |
721 | ||
ac155bb8 | 722 | if (!u->id) |
04ade7d2 LP |
723 | return; |
724 | ||
718db961 LP |
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)); | |
c1e1601e | 728 | } |
e2110e5d | 729 | |
718db961 LP |
730 | int bus_unit_queue_job( |
731 | sd_bus *bus, | |
732 | sd_bus_message *message, | |
cad45ba1 LP |
733 | Unit *u, |
734 | JobType type, | |
735 | JobMode mode, | |
ebcf1f97 LP |
736 | bool reload_if_possible, |
737 | sd_bus_error *error) { | |
cad45ba1 | 738 | |
cad45ba1 LP |
739 | _cleanup_free_ char *path = NULL; |
740 | Job *j; | |
cad45ba1 LP |
741 | int r; |
742 | ||
718db961 | 743 | assert(bus); |
cad45ba1 LP |
744 | assert(message); |
745 | assert(u); | |
746 | assert(type >= 0 && type < _JOB_TYPE_MAX); | |
747 | assert(mode >= 0 && mode < _JOB_MODE_MAX); | |
748 | ||
cad45ba1 LP |
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 | ||
ebcf1f97 LP |
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; | |
cad45ba1 | 762 | |
718db961 LP |
763 | if (type == JOB_STOP && |
764 | (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) && | |
765 | unit_active_state(u) == UNIT_INACTIVE) | |
ebcf1f97 | 766 | return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id); |
cad45ba1 LP |
767 | |
768 | if ((type == JOB_START && u->refuse_manual_start) || | |
769 | (type == JOB_STOP && u->refuse_manual_stop) || | |
718db961 | 770 | ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop))) |
ebcf1f97 | 771 | return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id); |
cad45ba1 | 772 | |
ebcf1f97 | 773 | r = manager_add_job(u->manager, type, u, mode, true, error, &j); |
cad45ba1 | 774 | if (r < 0) |
ebcf1f97 | 775 | return r; |
cad45ba1 | 776 | |
718db961 LP |
777 | r = bus_client_track(&j->subscribed, bus, sd_bus_message_get_sender(message)); |
778 | if (r < 0) | |
ebcf1f97 | 779 | return r; |
cad45ba1 LP |
780 | |
781 | path = job_dbus_path(j); | |
782 | if (!path) | |
ebcf1f97 | 783 | return r; |
cad45ba1 | 784 | |
df2d202e | 785 | return sd_bus_reply_method_return(message, "o", path); |
cad45ba1 LP |
786 | } |
787 | ||
9f2e86af LP |
788 | static int bus_unit_set_transient_property( |
789 | Unit *u, | |
790 | const char *name, | |
718db961 | 791 | sd_bus_message *message, |
9f2e86af | 792 | UnitSetPropertiesMode mode, |
718db961 | 793 | sd_bus_error *error) { |
9f2e86af LP |
794 | |
795 | int r; | |
796 | ||
797 | assert(u); | |
798 | assert(name); | |
718db961 | 799 | assert(message); |
9f2e86af LP |
800 | |
801 | if (streq(name, "Description")) { | |
718db961 | 802 | const char *d; |
9f2e86af | 803 | |
718db961 LP |
804 | r = sd_bus_message_read(message, "s", &d); |
805 | if (r < 0) | |
806 | return r; | |
8aec412f | 807 | |
718db961 LP |
808 | if (mode != UNIT_CHECK) { |
809 | r = unit_set_description(u, d); | |
8aec412f LP |
810 | if (r < 0) |
811 | return r; | |
b9316fb0 | 812 | |
718db961 | 813 | unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d); |
8aec412f | 814 | } |
9f2e86af LP |
815 | |
816 | return 1; | |
c221420b LP |
817 | |
818 | } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) { | |
819 | const char *s; | |
c221420b | 820 | |
718db961 LP |
821 | r = sd_bus_message_read(message, "s", &s); |
822 | if (r < 0) | |
823 | return r; | |
c221420b | 824 | |
718db961 LP |
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); | |
c221420b | 827 | |
8aec412f | 828 | if (isempty(s)) { |
b9ec9359 | 829 | if (mode != UNIT_CHECK) { |
8aec412f | 830 | unit_ref_unset(&u->slice); |
b9ec9359 LP |
831 | unit_remove_drop_in(u, mode, name); |
832 | } | |
8aec412f | 833 | } else { |
b9ec9359 | 834 | Unit *slice; |
b9316fb0 | 835 | |
8aec412f LP |
836 | r = manager_load_unit(u->manager, s, NULL, error, &slice); |
837 | if (r < 0) | |
838 | return r; | |
c221420b | 839 | |
8aec412f LP |
840 | if (slice->type != UNIT_SLICE) |
841 | return -EINVAL; | |
c221420b | 842 | |
b9ec9359 | 843 | if (mode != UNIT_CHECK) { |
8aec412f | 844 | unit_ref_set(&u->slice, slice); |
b9ec9359 LP |
845 | unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s); |
846 | } | |
8aec412f | 847 | } |
b9ec9359 | 848 | |
c221420b | 849 | return 1; |
7fb3ee51 LP |
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; | |
718db961 | 866 | const char *other; |
7fb3ee51 LP |
867 | |
868 | d = unit_dependency_from_string(name); | |
869 | if (d < 0) | |
870 | return -EINVAL; | |
871 | ||
718db961 LP |
872 | r = sd_bus_message_enter_container(message, 'a', "s"); |
873 | if (r < 0) | |
874 | return r; | |
7fb3ee51 | 875 | |
718db961 | 876 | while ((r = sd_bus_message_read(message, "s", &other)) > 0) { |
7fb3ee51 | 877 | if (!unit_name_is_valid(other, false)) |
718db961 | 878 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other); |
7fb3ee51 LP |
879 | |
880 | if (mode != UNIT_CHECK) { | |
b9ec9359 | 881 | _cleanup_free_ char *label = NULL; |
7fb3ee51 LP |
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 | ||
b9ec9359 | 891 | unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other); |
7fb3ee51 LP |
892 | } |
893 | ||
7fb3ee51 | 894 | } |
718db961 LP |
895 | if (r < 0) |
896 | return r; | |
7fb3ee51 LP |
897 | |
898 | return 1; | |
9f2e86af LP |
899 | } |
900 | ||
901 | return 0; | |
902 | } | |
903 | ||
c2756a68 LP |
904 | int bus_unit_set_properties( |
905 | Unit *u, | |
718db961 | 906 | sd_bus_message *message, |
c2756a68 LP |
907 | UnitSetPropertiesMode mode, |
908 | bool commit, | |
718db961 | 909 | sd_bus_error *error) { |
c2756a68 | 910 | |
8e2af478 | 911 | bool for_real = false; |
8e2af478 LP |
912 | unsigned n = 0; |
913 | int r; | |
914 | ||
915 | assert(u); | |
718db961 | 916 | assert(message); |
8e2af478 | 917 | |
c2756a68 LP |
918 | if (u->transient) |
919 | mode &= UNIT_RUNTIME; | |
920 | ||
8e2af478 LP |
921 | /* We iterate through the array twice. First run we just check |
922 | * if all passed data is valid, second run actually applies | |
923 | * it. This is to implement transaction-like behaviour without | |
924 | * actually providing full transactions. */ | |
925 | ||
718db961 LP |
926 | r = sd_bus_message_enter_container(message, 'a', "(sv)"); |
927 | if (r < 0) | |
928 | return r; | |
8e2af478 | 929 | |
8e2af478 | 930 | for (;;) { |
8e2af478 LP |
931 | const char *name; |
932 | ||
718db961 LP |
933 | r = sd_bus_message_enter_container(message, 'r', "sv"); |
934 | if (r < 0) | |
935 | return r; | |
936 | if (r == 0) { | |
a255a7f1 | 937 | if (for_real || mode == UNIT_CHECK) |
8e2af478 LP |
938 | break; |
939 | ||
940 | /* Reached EOF. Let's try again, and this time for realz... */ | |
718db961 LP |
941 | r = sd_bus_message_rewind(message, false); |
942 | if (r < 0) | |
943 | return r; | |
8e2af478 LP |
944 | for_real = true; |
945 | continue; | |
946 | } | |
947 | ||
718db961 LP |
948 | r = sd_bus_message_read(message, "s", &name); |
949 | if (r < 0) | |
950 | return r; | |
8e2af478 | 951 | |
718db961 LP |
952 | if (!UNIT_VTABLE(u)->bus_set_property) |
953 | return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties."); | |
8e2af478 | 954 | |
718db961 LP |
955 | r = sd_bus_message_enter_container(message, 'v', NULL); |
956 | if (r < 0) | |
957 | return r; | |
8e2af478 | 958 | |
718db961 | 959 | r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error); |
9f2e86af | 960 | if (r == 0 && u->transient && u->load_state == UNIT_STUB) |
718db961 LP |
961 | r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error); |
962 | if (r < 0) | |
963 | return r; | |
964 | if (r == 0) | |
965 | return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name); | |
966 | ||
967 | r = sd_bus_message_exit_container(message); | |
8e2af478 LP |
968 | if (r < 0) |
969 | return r; | |
8e2af478 | 970 | |
718db961 LP |
971 | r = sd_bus_message_exit_container(message); |
972 | if (r < 0) | |
973 | return r; | |
8e2af478 LP |
974 | |
975 | n += for_real; | |
976 | } | |
977 | ||
c2756a68 | 978 | if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties) |
8e2af478 LP |
979 | UNIT_VTABLE(u)->bus_commit_properties(u); |
980 | ||
241da328 | 981 | return n; |
8e2af478 | 982 | } |