]>
Commit | Line | Data |
---|---|---|
a7334b09 LP |
1 | /*** |
2 | This file is part of systemd. | |
3 | ||
4 | Copyright 2010 Lennart Poettering | |
5 | ||
6 | systemd is free software; you can redistribute it and/or modify it | |
5430f7f2 LP |
7 | under the terms of the GNU Lesser General Public License as published by |
8 | the Free Software Foundation; either version 2.1 of the License, or | |
a7334b09 LP |
9 | (at your option) any later version. |
10 | ||
11 | systemd is distributed in the hope that it will be useful, but | |
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
5430f7f2 | 14 | Lesser General Public License for more details. |
a7334b09 | 15 | |
5430f7f2 | 16 | You should have received a copy of the GNU Lesser General Public License |
a7334b09 LP |
17 | along with systemd; If not, see <http://www.gnu.org/licenses/>. |
18 | ***/ | |
19 | ||
718db961 | 20 | #include "sd-bus.h" |
07630cea | 21 | |
b5efdb8a | 22 | #include "alloc-util.h" |
07630cea LP |
23 | #include "bus-common-errors.h" |
24 | #include "cgroup-util.h" | |
8752c575 | 25 | #include "dbus-unit.h" |
07630cea | 26 | #include "dbus.h" |
291d565a | 27 | #include "fd-util.h" |
8752c575 | 28 | #include "locale-util.h" |
ea430986 | 29 | #include "log.h" |
291d565a | 30 | #include "process-util.h" |
e2417e41 | 31 | #include "selinux-access.h" |
6eb7c172 | 32 | #include "signal-util.h" |
efdb0237 | 33 | #include "special.h" |
07630cea LP |
34 | #include "string-util.h" |
35 | #include "strv.h" | |
ee104e11 | 36 | #include "user-util.h" |
718db961 LP |
37 | |
38 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState); | |
d420282b | 39 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode); |
f189ab18 | 40 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action, failure_action, FailureAction); |
718db961 LP |
41 | |
42 | static int property_get_names( | |
43 | sd_bus *bus, | |
44 | const char *path, | |
45 | const char *interface, | |
46 | const char *property, | |
47 | sd_bus_message *reply, | |
ebcf1f97 LP |
48 | void *userdata, |
49 | sd_bus_error *error) { | |
718db961 LP |
50 | |
51 | Unit *u = userdata; | |
52 | Iterator i; | |
53 | const char *t; | |
54 | int r; | |
ea430986 | 55 | |
718db961 LP |
56 | assert(bus); |
57 | assert(reply); | |
58 | assert(u); | |
4139c1b2 | 59 | |
718db961 LP |
60 | r = sd_bus_message_open_container(reply, 'a', "s"); |
61 | if (r < 0) | |
62 | return r; | |
4139c1b2 | 63 | |
718db961 LP |
64 | SET_FOREACH(t, u->names, i) { |
65 | r = sd_bus_message_append(reply, "s", t); | |
66 | if (r < 0) | |
67 | return r; | |
68 | } | |
4139c1b2 | 69 | |
718db961 | 70 | return sd_bus_message_close_container(reply); |
4139c1b2 LP |
71 | } |
72 | ||
718db961 LP |
73 | static int property_get_following( |
74 | sd_bus *bus, | |
75 | const char *path, | |
76 | const char *interface, | |
77 | const char *property, | |
78 | sd_bus_message *reply, | |
ebcf1f97 LP |
79 | void *userdata, |
80 | sd_bus_error *error) { | |
718db961 LP |
81 | |
82 | Unit *u = userdata, *f; | |
8fe914ec | 83 | |
718db961 LP |
84 | assert(bus); |
85 | assert(reply); | |
8fe914ec LP |
86 | assert(u); |
87 | ||
a7f241db | 88 | f = unit_following(u); |
718db961 | 89 | return sd_bus_message_append(reply, "s", f ? f->id : ""); |
8fe914ec LP |
90 | } |
91 | ||
718db961 LP |
92 | static int property_get_dependencies( |
93 | sd_bus *bus, | |
94 | const char *path, | |
95 | const char *interface, | |
96 | const char *property, | |
97 | sd_bus_message *reply, | |
ebcf1f97 LP |
98 | void *userdata, |
99 | sd_bus_error *error) { | |
4ec9a8a4 | 100 | |
718db961 | 101 | Set *s = *(Set**) userdata; |
5301be81 | 102 | Iterator j; |
718db961 LP |
103 | Unit *u; |
104 | int r; | |
5301be81 | 105 | |
718db961 LP |
106 | assert(bus); |
107 | assert(reply); | |
5301be81 | 108 | |
718db961 LP |
109 | r = sd_bus_message_open_container(reply, 'a', "s"); |
110 | if (r < 0) | |
111 | return r; | |
5301be81 | 112 | |
718db961 LP |
113 | SET_FOREACH(u, s, j) { |
114 | r = sd_bus_message_append(reply, "s", u->id); | |
115 | if (r < 0) | |
116 | return r; | |
117 | } | |
5301be81 | 118 | |
718db961 | 119 | return sd_bus_message_close_container(reply); |
5301be81 LP |
120 | } |
121 | ||
f32b43bd LP |
122 | static int property_get_obsolete_dependencies( |
123 | sd_bus *bus, | |
124 | const char *path, | |
125 | const char *interface, | |
126 | const char *property, | |
127 | sd_bus_message *reply, | |
128 | void *userdata, | |
129 | sd_bus_error *error) { | |
130 | ||
131 | assert(bus); | |
132 | assert(reply); | |
133 | ||
134 | /* For dependency types we don't support anymore always return an empty array */ | |
135 | return sd_bus_message_append(reply, "as", 0); | |
136 | } | |
137 | ||
718db961 LP |
138 | static int property_get_description( |
139 | sd_bus *bus, | |
140 | const char *path, | |
141 | const char *interface, | |
142 | const char *property, | |
143 | sd_bus_message *reply, | |
ebcf1f97 LP |
144 | void *userdata, |
145 | sd_bus_error *error) { | |
ea430986 | 146 | |
718db961 | 147 | Unit *u = userdata; |
ea430986 | 148 | |
718db961 LP |
149 | assert(bus); |
150 | assert(reply); | |
151 | assert(u); | |
ea430986 | 152 | |
718db961 | 153 | return sd_bus_message_append(reply, "s", unit_description(u)); |
ea430986 LP |
154 | } |
155 | ||
718db961 LP |
156 | static int property_get_active_state( |
157 | sd_bus *bus, | |
158 | const char *path, | |
159 | const char *interface, | |
160 | const char *property, | |
161 | sd_bus_message *reply, | |
ebcf1f97 LP |
162 | void *userdata, |
163 | sd_bus_error *error) { | |
ea430986 | 164 | |
718db961 | 165 | Unit *u = userdata; |
ea430986 | 166 | |
718db961 LP |
167 | assert(bus); |
168 | assert(reply); | |
ea430986 LP |
169 | assert(u); |
170 | ||
718db961 | 171 | return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u))); |
ea430986 LP |
172 | } |
173 | ||
718db961 LP |
174 | static int property_get_sub_state( |
175 | sd_bus *bus, | |
176 | const char *path, | |
177 | const char *interface, | |
178 | const char *property, | |
179 | sd_bus_message *reply, | |
ebcf1f97 LP |
180 | void *userdata, |
181 | sd_bus_error *error) { | |
10a94420 | 182 | |
718db961 | 183 | Unit *u = userdata; |
10a94420 | 184 | |
718db961 LP |
185 | assert(bus); |
186 | assert(reply); | |
187 | assert(u); | |
10a94420 | 188 | |
718db961 | 189 | return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u)); |
10a94420 LP |
190 | } |
191 | ||
d2dc52db LP |
192 | static int property_get_unit_file_preset( |
193 | sd_bus *bus, | |
194 | const char *path, | |
195 | const char *interface, | |
196 | const char *property, | |
197 | sd_bus_message *reply, | |
198 | void *userdata, | |
199 | sd_bus_error *error) { | |
200 | ||
201 | Unit *u = userdata; | |
202 | int r; | |
203 | ||
204 | assert(bus); | |
205 | assert(reply); | |
206 | assert(u); | |
207 | ||
208 | r = unit_get_unit_file_preset(u); | |
209 | ||
210 | return sd_bus_message_append(reply, "s", | |
211 | r < 0 ? "": | |
212 | r > 0 ? "enabled" : "disabled"); | |
213 | } | |
214 | ||
718db961 LP |
215 | static int property_get_unit_file_state( |
216 | sd_bus *bus, | |
217 | const char *path, | |
218 | const char *interface, | |
219 | const char *property, | |
220 | sd_bus_message *reply, | |
ebcf1f97 LP |
221 | void *userdata, |
222 | sd_bus_error *error) { | |
a4375746 | 223 | |
718db961 | 224 | Unit *u = userdata; |
a4375746 | 225 | |
718db961 LP |
226 | assert(bus); |
227 | assert(reply); | |
228 | assert(u); | |
a4375746 | 229 | |
76445832 | 230 | return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u))); |
a4375746 LP |
231 | } |
232 | ||
718db961 LP |
233 | static int property_get_can_start( |
234 | sd_bus *bus, | |
235 | const char *path, | |
236 | const char *interface, | |
237 | const char *property, | |
238 | sd_bus_message *reply, | |
ebcf1f97 LP |
239 | void *userdata, |
240 | sd_bus_error *error) { | |
38131695 | 241 | |
718db961 | 242 | Unit *u = userdata; |
b5e9dba8 | 243 | |
718db961 LP |
244 | assert(bus); |
245 | assert(reply); | |
246 | assert(u); | |
b5e9dba8 | 247 | |
718db961 | 248 | return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start); |
b5e9dba8 LP |
249 | } |
250 | ||
718db961 LP |
251 | static int property_get_can_stop( |
252 | sd_bus *bus, | |
253 | const char *path, | |
254 | const char *interface, | |
255 | const char *property, | |
256 | sd_bus_message *reply, | |
ebcf1f97 LP |
257 | void *userdata, |
258 | sd_bus_error *error) { | |
718db961 LP |
259 | |
260 | Unit *u = userdata; | |
b5e9dba8 | 261 | |
718db961 LP |
262 | assert(bus); |
263 | assert(reply); | |
b5e9dba8 LP |
264 | assert(u); |
265 | ||
266 | /* On the lower levels we assume that every unit we can start | |
267 | * we can also stop */ | |
268 | ||
718db961 | 269 | return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_stop); |
38131695 LP |
270 | } |
271 | ||
718db961 LP |
272 | static int property_get_can_reload( |
273 | sd_bus *bus, | |
274 | const char *path, | |
275 | const char *interface, | |
276 | const char *property, | |
277 | sd_bus_message *reply, | |
ebcf1f97 LP |
278 | void *userdata, |
279 | sd_bus_error *error) { | |
38131695 | 280 | |
718db961 | 281 | Unit *u = userdata; |
38131695 | 282 | |
718db961 LP |
283 | assert(bus); |
284 | assert(reply); | |
285 | assert(u); | |
38131695 | 286 | |
718db961 | 287 | return sd_bus_message_append(reply, "b", unit_can_reload(u)); |
38131695 LP |
288 | } |
289 | ||
718db961 LP |
290 | static int property_get_can_isolate( |
291 | sd_bus *bus, | |
292 | const char *path, | |
293 | const char *interface, | |
294 | const char *property, | |
295 | sd_bus_message *reply, | |
ebcf1f97 LP |
296 | void *userdata, |
297 | sd_bus_error *error) { | |
2528a7a6 | 298 | |
718db961 | 299 | Unit *u = userdata; |
2528a7a6 | 300 | |
718db961 LP |
301 | assert(bus); |
302 | assert(reply); | |
303 | assert(u); | |
2528a7a6 | 304 | |
718db961 | 305 | return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start); |
2528a7a6 LP |
306 | } |
307 | ||
718db961 LP |
308 | static int property_get_job( |
309 | sd_bus *bus, | |
310 | const char *path, | |
311 | const char *interface, | |
312 | const char *property, | |
313 | sd_bus_message *reply, | |
ebcf1f97 LP |
314 | void *userdata, |
315 | sd_bus_error *error) { | |
718db961 | 316 | |
f93891f3 | 317 | _cleanup_free_ char *p = NULL; |
718db961 | 318 | Unit *u = userdata; |
38131695 | 319 | |
718db961 LP |
320 | assert(bus); |
321 | assert(reply); | |
38131695 LP |
322 | assert(u); |
323 | ||
718db961 LP |
324 | if (!u->job) |
325 | return sd_bus_message_append(reply, "(uo)", 0, "/"); | |
38131695 | 326 | |
718db961 LP |
327 | p = job_dbus_path(u->job); |
328 | if (!p) | |
329 | return -ENOMEM; | |
38131695 | 330 | |
718db961 LP |
331 | return sd_bus_message_append(reply, "(uo)", u->job->id, p); |
332 | } | |
38131695 | 333 | |
718db961 LP |
334 | static int property_get_need_daemon_reload( |
335 | sd_bus *bus, | |
336 | const char *path, | |
337 | const char *interface, | |
338 | const char *property, | |
339 | sd_bus_message *reply, | |
ebcf1f97 LP |
340 | void *userdata, |
341 | sd_bus_error *error) { | |
38131695 | 342 | |
718db961 | 343 | Unit *u = userdata; |
38131695 | 344 | |
718db961 LP |
345 | assert(bus); |
346 | assert(reply); | |
347 | assert(u); | |
38131695 | 348 | |
718db961 | 349 | return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u)); |
38131695 LP |
350 | } |
351 | ||
718db961 LP |
352 | static int property_get_conditions( |
353 | sd_bus *bus, | |
354 | const char *path, | |
355 | const char *interface, | |
356 | const char *property, | |
357 | sd_bus_message *reply, | |
ebcf1f97 LP |
358 | void *userdata, |
359 | sd_bus_error *error) { | |
45fb0699 | 360 | |
59fccdc5 LP |
361 | const char *(*to_string)(ConditionType type) = NULL; |
362 | Condition **list = userdata, *c; | |
718db961 | 363 | int r; |
45fb0699 | 364 | |
718db961 LP |
365 | assert(bus); |
366 | assert(reply); | |
59fccdc5 LP |
367 | assert(list); |
368 | ||
369 | to_string = streq(property, "Asserts") ? assert_type_to_string : condition_type_to_string; | |
45fb0699 | 370 | |
718db961 LP |
371 | r = sd_bus_message_open_container(reply, 'a', "(sbbsi)"); |
372 | if (r < 0) | |
373 | return r; | |
45fb0699 | 374 | |
59fccdc5 | 375 | LIST_FOREACH(conditions, c, *list) { |
cc50ef13 LP |
376 | int tristate; |
377 | ||
378 | tristate = | |
379 | c->result == CONDITION_UNTESTED ? 0 : | |
380 | c->result == CONDITION_SUCCEEDED ? 1 : -1; | |
381 | ||
2c7e050f | 382 | r = sd_bus_message_append(reply, "(sbbsi)", |
59fccdc5 | 383 | to_string(c->type), |
2c7e050f | 384 | c->trigger, c->negate, |
cc50ef13 | 385 | c->parameter, tristate); |
718db961 LP |
386 | if (r < 0) |
387 | return r; | |
45fb0699 | 388 | |
718db961 | 389 | } |
52990c2e | 390 | |
718db961 | 391 | return sd_bus_message_close_container(reply); |
52990c2e ZJS |
392 | } |
393 | ||
718db961 LP |
394 | static int property_get_load_error( |
395 | sd_bus *bus, | |
396 | const char *path, | |
397 | const char *interface, | |
398 | const char *property, | |
399 | sd_bus_message *reply, | |
ebcf1f97 LP |
400 | void *userdata, |
401 | sd_bus_error *error) { | |
52990c2e | 402 | |
4afd3348 | 403 | _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL; |
718db961 | 404 | Unit *u = userdata; |
52990c2e | 405 | |
718db961 LP |
406 | assert(bus); |
407 | assert(reply); | |
408 | assert(u); | |
52990c2e | 409 | |
718db961 LP |
410 | if (u->load_error != 0) |
411 | sd_bus_error_set_errno(&e, u->load_error); | |
52990c2e | 412 | |
718db961 | 413 | return sd_bus_message_append(reply, "(ss)", e.name, e.message); |
52990c2e ZJS |
414 | } |
415 | ||
88ced61b MC |
416 | static int bus_verify_manage_units_async_full( |
417 | Unit *u, | |
418 | const char *verb, | |
419 | int capability, | |
420 | const char *polkit_message, | |
421 | sd_bus_message *call, | |
422 | sd_bus_error *error) { | |
423 | ||
424 | const char *details[9] = { | |
425 | "unit", u->id, | |
426 | "verb", verb, | |
427 | }; | |
428 | ||
429 | if (polkit_message) { | |
430 | details[4] = "polkit.message"; | |
431 | details[5] = polkit_message; | |
432 | details[6] = "polkit.gettext_domain"; | |
433 | details[7] = GETTEXT_PACKAGE; | |
434 | } | |
435 | ||
436 | return bus_verify_polkit_async(call, capability, "org.freedesktop.systemd1.manage-units", details, false, UID_INVALID, &u->manager->polkit_registry, error); | |
437 | } | |
438 | ||
1d22e906 | 439 | int bus_unit_method_start_generic( |
1d22e906 LP |
440 | sd_bus_message *message, |
441 | Unit *u, | |
442 | JobType job_type, | |
443 | bool reload_if_possible, | |
444 | sd_bus_error *error) { | |
445 | ||
718db961 LP |
446 | const char *smode; |
447 | JobMode mode; | |
88ced61b MC |
448 | _cleanup_free_ char *verb = NULL; |
449 | static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = { | |
450 | [JOB_START] = N_("Authentication is required to start '$(unit)'."), | |
451 | [JOB_STOP] = N_("Authentication is required to stop '$(unit)'."), | |
452 | [JOB_RELOAD] = N_("Authentication is required to reload '$(unit)'."), | |
453 | [JOB_RESTART] = N_("Authentication is required to restart '$(unit)'."), | |
454 | [JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."), | |
455 | }; | |
718db961 | 456 | int r; |
9f39404c | 457 | |
718db961 | 458 | assert(message); |
9f39404c | 459 | assert(u); |
718db961 | 460 | assert(job_type >= 0 && job_type < _JOB_TYPE_MAX); |
9f39404c | 461 | |
61ea63f1 EV |
462 | r = mac_selinux_unit_access_check( |
463 | u, message, | |
94bd7323 EV |
464 | job_type_to_access_method(job_type), |
465 | error); | |
1d22e906 LP |
466 | if (r < 0) |
467 | return r; | |
468 | ||
718db961 LP |
469 | r = sd_bus_message_read(message, "s", &smode); |
470 | if (r < 0) | |
ebcf1f97 | 471 | return r; |
9f39404c | 472 | |
718db961 LP |
473 | mode = job_mode_from_string(smode); |
474 | if (mode < 0) | |
ebcf1f97 | 475 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode); |
9f39404c | 476 | |
88ced61b MC |
477 | if (reload_if_possible) |
478 | verb = strjoin("reload-or-", job_type_to_string(job_type), NULL); | |
479 | else | |
480 | verb = strdup(job_type_to_string(job_type)); | |
481 | if (!verb) | |
482 | return -ENOMEM; | |
483 | ||
484 | r = bus_verify_manage_units_async_full( | |
485 | u, | |
486 | verb, | |
487 | CAP_SYS_ADMIN, | |
488 | job_type < _JOB_TYPE_MAX ? polkit_message_for_job[job_type] : NULL, | |
489 | message, | |
490 | error); | |
1d22e906 LP |
491 | if (r < 0) |
492 | return r; | |
493 | if (r == 0) | |
494 | return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ | |
495 | ||
19070062 | 496 | return bus_unit_queue_job(message, u, job_type, mode, reload_if_possible, error); |
9f39404c LP |
497 | } |
498 | ||
19070062 LP |
499 | static int method_start(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
500 | return bus_unit_method_start_generic(message, userdata, JOB_START, false, error); | |
718db961 | 501 | } |
b548631a | 502 | |
19070062 LP |
503 | static int method_stop(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
504 | return bus_unit_method_start_generic(message, userdata, JOB_STOP, false, error); | |
718db961 LP |
505 | } |
506 | ||
19070062 LP |
507 | static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
508 | return bus_unit_method_start_generic(message, userdata, JOB_RELOAD, false, error); | |
718db961 | 509 | } |
0a524ba7 | 510 | |
19070062 LP |
511 | static int method_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
512 | return bus_unit_method_start_generic(message, userdata, JOB_RESTART, false, error); | |
718db961 | 513 | } |
8a0867d6 | 514 | |
19070062 LP |
515 | static int method_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
516 | return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, false, error); | |
718db961 | 517 | } |
cad45ba1 | 518 | |
19070062 LP |
519 | static int method_reload_or_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
520 | return bus_unit_method_start_generic(message, userdata, JOB_RESTART, true, error); | |
718db961 | 521 | } |
8a0867d6 | 522 | |
19070062 LP |
523 | static int method_reload_or_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
524 | return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, true, error); | |
718db961 | 525 | } |
8a0867d6 | 526 | |
19070062 | 527 | int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
718db961 LP |
528 | Unit *u = userdata; |
529 | const char *swho; | |
530 | int32_t signo; | |
531 | KillWho who; | |
532 | int r; | |
5632e374 | 533 | |
718db961 LP |
534 | assert(message); |
535 | assert(u); | |
cad45ba1 | 536 | |
1d22e906 | 537 | r = mac_selinux_unit_access_check(u, message, "stop", error); |
283868e1 SW |
538 | if (r < 0) |
539 | return r; | |
283868e1 | 540 | |
718db961 LP |
541 | r = sd_bus_message_read(message, "si", &swho, &signo); |
542 | if (r < 0) | |
ebcf1f97 | 543 | return r; |
718db961 LP |
544 | |
545 | if (isempty(swho)) | |
546 | who = KILL_ALL; | |
547 | else { | |
548 | who = kill_who_from_string(swho); | |
549 | if (who < 0) | |
ebcf1f97 | 550 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho); |
718db961 | 551 | } |
5632e374 | 552 | |
6eb7c172 | 553 | if (!SIGNAL_VALID(signo)) |
ebcf1f97 | 554 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range."); |
8e2af478 | 555 | |
88ced61b MC |
556 | r = bus_verify_manage_units_async_full( |
557 | u, | |
558 | "kill", | |
559 | CAP_KILL, | |
560 | N_("Authentication is required to kill '$(unit)'."), | |
561 | message, | |
562 | error); | |
ebcf1f97 LP |
563 | if (r < 0) |
564 | return r; | |
1d22e906 LP |
565 | if (r == 0) |
566 | return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ | |
8e2af478 | 567 | |
ebcf1f97 | 568 | r = unit_kill(u, who, signo, error); |
718db961 | 569 | if (r < 0) |
ebcf1f97 | 570 | return r; |
8e2af478 | 571 | |
df2d202e | 572 | return sd_bus_reply_method_return(message, NULL); |
718db961 | 573 | } |
8e2af478 | 574 | |
19070062 | 575 | int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
718db961 | 576 | Unit *u = userdata; |
ebcf1f97 | 577 | int r; |
b548631a | 578 | |
718db961 LP |
579 | assert(message); |
580 | assert(u); | |
b548631a | 581 | |
1d22e906 | 582 | r = mac_selinux_unit_access_check(u, message, "reload", error); |
283868e1 SW |
583 | if (r < 0) |
584 | return r; | |
283868e1 | 585 | |
88ced61b MC |
586 | r = bus_verify_manage_units_async_full( |
587 | u, | |
588 | "reset-failed", | |
589 | CAP_SYS_ADMIN, | |
590 | N_("Authentication is required to reset the \"failed\" state of '$(unit)'."), | |
591 | message, | |
592 | error); | |
ebcf1f97 LP |
593 | if (r < 0) |
594 | return r; | |
1d22e906 LP |
595 | if (r == 0) |
596 | return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ | |
b548631a | 597 | |
718db961 | 598 | unit_reset_failed(u); |
b548631a | 599 | |
df2d202e | 600 | return sd_bus_reply_method_return(message, NULL); |
ea430986 LP |
601 | } |
602 | ||
19070062 | 603 | int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
718db961 LP |
604 | Unit *u = userdata; |
605 | int runtime, r; | |
ea430986 | 606 | |
ea430986 | 607 | assert(message); |
718db961 | 608 | assert(u); |
80fbf05e | 609 | |
1d22e906 | 610 | r = mac_selinux_unit_access_check(u, message, "start", error); |
283868e1 SW |
611 | if (r < 0) |
612 | return r; | |
283868e1 | 613 | |
718db961 LP |
614 | r = sd_bus_message_read(message, "b", &runtime); |
615 | if (r < 0) | |
ebcf1f97 | 616 | return r; |
2cccbca4 | 617 | |
88ced61b MC |
618 | r = bus_verify_manage_units_async_full( |
619 | u, | |
620 | "set-property", | |
621 | CAP_SYS_ADMIN, | |
622 | N_("Authentication is required to set properties on '$(unit)'."), | |
623 | message, | |
624 | error); | |
ebcf1f97 LP |
625 | if (r < 0) |
626 | return r; | |
1d22e906 LP |
627 | if (r == 0) |
628 | return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ | |
cad45ba1 | 629 | |
ebcf1f97 | 630 | r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error); |
718db961 | 631 | if (r < 0) |
ebcf1f97 | 632 | return r; |
2cccbca4 | 633 | |
df2d202e | 634 | return sd_bus_reply_method_return(message, NULL); |
718db961 | 635 | } |
2cccbca4 | 636 | |
718db961 LP |
637 | const sd_bus_vtable bus_unit_vtable[] = { |
638 | SD_BUS_VTABLE_START(0), | |
639 | ||
556089dc LP |
640 | SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST), |
641 | SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
718db961 | 642 | SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0), |
556089dc | 643 | SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST), |
556089dc | 644 | SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST), |
556089dc LP |
645 | SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST), |
646 | SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST), | |
647 | SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST), | |
648 | SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), | |
be7d9ff7 | 649 | SD_BUS_PROPERTY("RequisiteOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF]), SD_BUS_VTABLE_PROPERTY_CONST), |
556089dc LP |
650 | SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), |
651 | SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST), | |
652 | SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST), | |
653 | SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST), | |
654 | SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), | |
655 | SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST), | |
656 | SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST), | |
657 | SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST), | |
658 | SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST), | |
659 | SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), | |
660 | SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST), | |
661 | SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST), | |
662 | SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST), | |
663 | SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST), | |
664 | SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST), | |
665 | SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
666 | SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST), | |
718db961 LP |
667 | SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
668 | SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
556089dc LP |
669 | SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST), |
670 | SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST), | |
671 | SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST), | |
718db961 | 672 | SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0), |
d2dc52db | 673 | SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0), |
a483fb59 | 674 | BUS_PROPERTY_DUAL_TIMESTAMP("StateChangeTimestamp", offsetof(Unit, state_change_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
718db961 LP |
675 | BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
676 | BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
677 | BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
678 | BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
556089dc LP |
679 | SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST), |
680 | SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
681 | SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
682 | SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
718db961 | 683 | SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
556089dc LP |
684 | SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST), |
685 | SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST), | |
686 | SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST), | |
687 | SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST), | |
688 | SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST), | |
689 | SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST), | |
690 | SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST), | |
556089dc LP |
691 | SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST), |
692 | SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST), | |
f189ab18 LP |
693 | SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST), |
694 | SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST), | |
718db961 | 695 | SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
59fccdc5 | 696 | SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
718db961 | 697 | BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
59fccdc5 LP |
698 | BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
699 | SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), 0), | |
700 | SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0), | |
556089dc LP |
701 | SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST), |
702 | SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST), | |
f0367da7 | 703 | SD_BUS_PROPERTY("StartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), |
6bf0f408 LP |
704 | SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), |
705 | SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST), | |
706 | SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST), | |
718db961 | 707 | |
1d22e906 LP |
708 | SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED), |
709 | SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED), | |
710 | SD_BUS_METHOD("Reload", "s", "o", method_reload, SD_BUS_VTABLE_UNPRIVILEGED), | |
711 | SD_BUS_METHOD("Restart", "s", "o", method_restart, SD_BUS_VTABLE_UNPRIVILEGED), | |
712 | SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED), | |
713 | SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED), | |
714 | SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED), | |
715 | SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED), | |
716 | SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED), | |
717 | SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED), | |
718db961 | 718 | |
51d73fd9 LP |
719 | /* Obsolete properties or obsolete alias names */ |
720 | SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), | |
721 | SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), | |
722 | SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), | |
723 | SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), | |
724 | SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), | |
718db961 LP |
725 | SD_BUS_VTABLE_END |
726 | }; | |
2cccbca4 | 727 | |
718db961 LP |
728 | static int property_get_slice( |
729 | sd_bus *bus, | |
730 | const char *path, | |
731 | const char *interface, | |
732 | const char *property, | |
733 | sd_bus_message *reply, | |
ebcf1f97 LP |
734 | void *userdata, |
735 | sd_bus_error *error) { | |
2cccbca4 | 736 | |
718db961 | 737 | Unit *u = userdata; |
2cccbca4 | 738 | |
718db961 LP |
739 | assert(bus); |
740 | assert(reply); | |
741 | assert(u); | |
2cccbca4 | 742 | |
718db961 LP |
743 | return sd_bus_message_append(reply, "s", unit_slice_name(u)); |
744 | } | |
2cccbca4 | 745 | |
934277fe LP |
746 | static int property_get_current_memory( |
747 | sd_bus *bus, | |
748 | const char *path, | |
749 | const char *interface, | |
750 | const char *property, | |
751 | sd_bus_message *reply, | |
752 | void *userdata, | |
753 | sd_bus_error *error) { | |
754 | ||
934277fe | 755 | uint64_t sz = (uint64_t) -1; |
5ad096b3 | 756 | Unit *u = userdata; |
934277fe LP |
757 | int r; |
758 | ||
759 | assert(bus); | |
760 | assert(reply); | |
761 | assert(u); | |
762 | ||
5ad096b3 LP |
763 | r = unit_get_memory_current(u, &sz); |
764 | if (r < 0 && r != -ENODATA) | |
f2341e0a | 765 | log_unit_warning_errno(u, r, "Failed to get memory.usage_in_bytes attribute: %m"); |
934277fe | 766 | |
5ad096b3 LP |
767 | return sd_bus_message_append(reply, "t", sz); |
768 | } | |
934277fe | 769 | |
03a7b521 LP |
770 | static int property_get_current_tasks( |
771 | sd_bus *bus, | |
772 | const char *path, | |
773 | const char *interface, | |
774 | const char *property, | |
775 | sd_bus_message *reply, | |
776 | void *userdata, | |
777 | sd_bus_error *error) { | |
778 | ||
779 | uint64_t cn = (uint64_t) -1; | |
780 | Unit *u = userdata; | |
781 | int r; | |
782 | ||
783 | assert(bus); | |
784 | assert(reply); | |
785 | assert(u); | |
786 | ||
787 | r = unit_get_tasks_current(u, &cn); | |
788 | if (r < 0 && r != -ENODATA) | |
789 | log_unit_warning_errno(u, r, "Failed to get pids.current attribute: %m"); | |
790 | ||
791 | return sd_bus_message_append(reply, "t", cn); | |
792 | } | |
793 | ||
5ad096b3 LP |
794 | static int property_get_cpu_usage( |
795 | sd_bus *bus, | |
796 | const char *path, | |
797 | const char *interface, | |
798 | const char *property, | |
799 | sd_bus_message *reply, | |
800 | void *userdata, | |
801 | sd_bus_error *error) { | |
934277fe | 802 | |
5ad096b3 LP |
803 | nsec_t ns = (nsec_t) -1; |
804 | Unit *u = userdata; | |
805 | int r; | |
806 | ||
807 | assert(bus); | |
808 | assert(reply); | |
809 | assert(u); | |
810 | ||
811 | r = unit_get_cpu_usage(u, &ns); | |
812 | if (r < 0 && r != -ENODATA) | |
f2341e0a | 813 | log_unit_warning_errno(u, r, "Failed to get cpuacct.usage attribute: %m"); |
5ad096b3 LP |
814 | |
815 | return sd_bus_message_append(reply, "t", ns); | |
934277fe LP |
816 | } |
817 | ||
98bac605 LP |
818 | static int property_get_cgroup( |
819 | sd_bus *bus, | |
820 | const char *path, | |
821 | const char *interface, | |
822 | const char *property, | |
823 | sd_bus_message *reply, | |
824 | void *userdata, | |
825 | sd_bus_error *error) { | |
826 | ||
827 | Unit *u = userdata; | |
828 | const char *t; | |
829 | ||
830 | assert(bus); | |
831 | assert(reply); | |
832 | assert(u); | |
833 | ||
834 | /* Three cases: a) u->cgroup_path is NULL, in which case the | |
835 | * unit has no control group, which we report as the empty | |
836 | * string. b) u->cgroup_path is the empty string, which | |
837 | * indicates the root cgroup, which we report as "/". c) all | |
838 | * other cases we report as-is. */ | |
839 | ||
840 | if (u->cgroup_path) | |
841 | t = isempty(u->cgroup_path) ? "/" : u->cgroup_path; | |
842 | else | |
843 | t = ""; | |
844 | ||
845 | return sd_bus_message_append(reply, "s", t); | |
846 | } | |
847 | ||
291d565a LP |
848 | static int append_process(sd_bus_message *reply, const char *p, pid_t pid, Set *pids) { |
849 | _cleanup_free_ char *buf = NULL, *cmdline = NULL; | |
850 | int r; | |
851 | ||
852 | assert(reply); | |
853 | assert(pid > 0); | |
854 | ||
855 | r = set_put(pids, PID_TO_PTR(pid)); | |
856 | if (r == -EEXIST || r == 0) | |
857 | return 0; | |
858 | if (r < 0) | |
859 | return r; | |
860 | ||
861 | if (!p) { | |
862 | r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &buf); | |
863 | if (r == -ESRCH) | |
864 | return 0; | |
865 | if (r < 0) | |
866 | return r; | |
867 | ||
868 | p = buf; | |
869 | } | |
870 | ||
871 | (void) get_process_cmdline(pid, 0, true, &cmdline); | |
872 | ||
873 | return sd_bus_message_append(reply, | |
874 | "(sus)", | |
875 | p, | |
876 | (uint32_t) pid, | |
877 | cmdline); | |
878 | } | |
879 | ||
880 | static int append_cgroup(sd_bus_message *reply, const char *p, Set *pids) { | |
881 | _cleanup_closedir_ DIR *d = NULL; | |
882 | _cleanup_fclose_ FILE *f = NULL; | |
883 | int r; | |
884 | ||
885 | assert(reply); | |
886 | assert(p); | |
887 | ||
888 | r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, p, &f); | |
889 | if (r == ENOENT) | |
890 | return 0; | |
891 | if (r < 0) | |
892 | return r; | |
893 | ||
894 | for (;;) { | |
895 | pid_t pid; | |
896 | ||
897 | r = cg_read_pid(f, &pid); | |
898 | if (r < 0) | |
899 | return r; | |
900 | if (r == 0) | |
901 | break; | |
902 | ||
903 | if (is_kernel_thread(pid) > 0) | |
904 | continue; | |
905 | ||
906 | r = append_process(reply, p, pid, pids); | |
907 | if (r < 0) | |
908 | return r; | |
909 | } | |
910 | ||
911 | r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, p, &d); | |
912 | if (r == -ENOENT) | |
913 | return 0; | |
914 | if (r < 0) | |
915 | return r; | |
916 | ||
917 | for (;;) { | |
918 | _cleanup_free_ char *g = NULL, *j = NULL; | |
919 | ||
920 | r = cg_read_subgroup(d, &g); | |
921 | if (r < 0) | |
922 | return r; | |
923 | if (r == 0) | |
924 | break; | |
925 | ||
926 | j = strjoin(p, "/", g, NULL); | |
927 | if (!j) | |
928 | return -ENOMEM; | |
929 | ||
930 | r = append_cgroup(reply, j, pids); | |
931 | if (r < 0) | |
932 | return r; | |
933 | } | |
934 | ||
935 | return 0; | |
936 | } | |
937 | ||
938 | int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |
939 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; | |
940 | _cleanup_(set_freep) Set *pids = NULL; | |
291d565a LP |
941 | Unit *u = userdata; |
942 | pid_t pid; | |
943 | int r; | |
944 | ||
945 | assert(message); | |
946 | ||
947 | pids = set_new(NULL); | |
948 | if (!pids) | |
949 | return -ENOMEM; | |
950 | ||
951 | r = sd_bus_message_new_method_return(message, &reply); | |
952 | if (r < 0) | |
953 | return r; | |
954 | ||
955 | r = sd_bus_message_open_container(reply, 'a', "(sus)"); | |
956 | if (r < 0) | |
957 | return r; | |
958 | ||
959 | if (u->cgroup_path) { | |
960 | r = append_cgroup(reply, u->cgroup_path, pids); | |
961 | if (r < 0) | |
962 | return r; | |
963 | } | |
964 | ||
965 | /* The main and control pids might live outside of the cgroup, hence fetch them separately */ | |
966 | pid = unit_main_pid(u); | |
967 | if (pid > 0) { | |
968 | r = append_process(reply, NULL, pid, pids); | |
969 | if (r < 0) | |
970 | return r; | |
971 | } | |
972 | ||
973 | pid = unit_control_pid(u); | |
974 | if (pid > 0) { | |
975 | r = append_process(reply, NULL, pid, pids); | |
976 | if (r < 0) | |
977 | return r; | |
978 | } | |
979 | ||
980 | r = sd_bus_message_close_container(reply); | |
981 | if (r < 0) | |
982 | return r; | |
983 | ||
984 | return sd_bus_send(NULL, reply, NULL); | |
985 | } | |
986 | ||
718db961 LP |
987 | const sd_bus_vtable bus_unit_cgroup_vtable[] = { |
988 | SD_BUS_VTABLE_START(0), | |
989 | SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0), | |
98bac605 | 990 | SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup, 0, 0), |
934277fe | 991 | SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0), |
5ad096b3 | 992 | SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0), |
03a7b521 | 993 | SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0), |
291d565a | 994 | SD_BUS_METHOD("GetProcesses", NULL, "a(sus)", bus_unit_method_get_processes, SD_BUS_VTABLE_UNPRIVILEGED), |
718db961 LP |
995 | SD_BUS_VTABLE_END |
996 | }; | |
2cccbca4 | 997 | |
8f8f05a9 | 998 | static int send_new_signal(sd_bus *bus, void *userdata) { |
4afd3348 | 999 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; |
718db961 LP |
1000 | _cleanup_free_ char *p = NULL; |
1001 | Unit *u = userdata; | |
1002 | int r; | |
2cccbca4 | 1003 | |
718db961 LP |
1004 | assert(bus); |
1005 | assert(u); | |
2cccbca4 | 1006 | |
718db961 | 1007 | p = unit_dbus_path(u); |
e861098b | 1008 | if (!p) |
718db961 | 1009 | return -ENOMEM; |
2cccbca4 | 1010 | |
718db961 LP |
1011 | r = sd_bus_message_new_signal( |
1012 | bus, | |
151b9b96 | 1013 | &m, |
718db961 LP |
1014 | "/org/freedesktop/systemd1", |
1015 | "org.freedesktop.systemd1.Manager", | |
151b9b96 | 1016 | "UnitNew"); |
718db961 LP |
1017 | if (r < 0) |
1018 | return r; | |
2cccbca4 | 1019 | |
718db961 LP |
1020 | r = sd_bus_message_append(m, "so", u->id, p); |
1021 | if (r < 0) | |
1022 | return r; | |
2cccbca4 | 1023 | |
8f8f05a9 | 1024 | return sd_bus_send(bus, m, NULL); |
718db961 | 1025 | } |
2cccbca4 | 1026 | |
8f8f05a9 | 1027 | static int send_changed_signal(sd_bus *bus, void *userdata) { |
718db961 LP |
1028 | _cleanup_free_ char *p = NULL; |
1029 | Unit *u = userdata; | |
1030 | int r; | |
2cccbca4 | 1031 | |
718db961 LP |
1032 | assert(bus); |
1033 | assert(u); | |
2cccbca4 | 1034 | |
718db961 | 1035 | p = unit_dbus_path(u); |
9ceefc81 | 1036 | if (!p) |
718db961 | 1037 | return -ENOMEM; |
2cccbca4 | 1038 | |
718db961 LP |
1039 | /* Send a properties changed signal. First for the specific |
1040 | * type, then for the generic unit. The clients may rely on | |
1041 | * this order to get atomic behavior if needed. */ | |
ea430986 | 1042 | |
aec8de63 LP |
1043 | r = sd_bus_emit_properties_changed_strv( |
1044 | bus, p, | |
21b735e7 | 1045 | unit_dbus_interface_from_type(u->type), |
aec8de63 | 1046 | NULL); |
fe7f06f1 | 1047 | if (r < 0) |
aec8de63 | 1048 | return r; |
80fbf05e | 1049 | |
fe7f06f1 | 1050 | return sd_bus_emit_properties_changed_strv( |
718db961 LP |
1051 | bus, p, |
1052 | "org.freedesktop.systemd1.Unit", | |
718db961 | 1053 | NULL); |
ea430986 LP |
1054 | } |
1055 | ||
c1e1601e | 1056 | void bus_unit_send_change_signal(Unit *u) { |
b170dd80 | 1057 | int r; |
c1e1601e | 1058 | assert(u); |
c1e1601e | 1059 | |
ac155bb8 | 1060 | if (u->in_dbus_queue) { |
71fda00f | 1061 | LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u); |
ac155bb8 | 1062 | u->in_dbus_queue = false; |
c0bd0cf7 | 1063 | } |
c1e1601e | 1064 | |
ac155bb8 | 1065 | if (!u->id) |
04ade7d2 LP |
1066 | return; |
1067 | ||
8f8f05a9 | 1068 | r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u); |
718db961 | 1069 | if (r < 0) |
f2341e0a | 1070 | log_unit_debug_errno(u, r, "Failed to send unit change signal for %s: %m", u->id); |
c1e1601e | 1071 | |
718db961 LP |
1072 | u->sent_dbus_new_signal = true; |
1073 | } | |
c4e2ceae | 1074 | |
8f8f05a9 | 1075 | static int send_removed_signal(sd_bus *bus, void *userdata) { |
4afd3348 | 1076 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; |
718db961 LP |
1077 | _cleanup_free_ char *p = NULL; |
1078 | Unit *u = userdata; | |
1079 | int r; | |
c4e2ceae | 1080 | |
718db961 LP |
1081 | assert(bus); |
1082 | assert(u); | |
c1e1601e | 1083 | |
718db961 | 1084 | p = unit_dbus_path(u); |
e861098b | 1085 | if (!p) |
718db961 | 1086 | return -ENOMEM; |
c1e1601e | 1087 | |
718db961 LP |
1088 | r = sd_bus_message_new_signal( |
1089 | bus, | |
151b9b96 | 1090 | &m, |
718db961 LP |
1091 | "/org/freedesktop/systemd1", |
1092 | "org.freedesktop.systemd1.Manager", | |
151b9b96 | 1093 | "UnitRemoved"); |
718db961 LP |
1094 | if (r < 0) |
1095 | return r; | |
c1e1601e | 1096 | |
718db961 LP |
1097 | r = sd_bus_message_append(m, "so", u->id, p); |
1098 | if (r < 0) | |
1099 | return r; | |
c1e1601e | 1100 | |
8f8f05a9 | 1101 | return sd_bus_send(bus, m, NULL); |
c1e1601e LP |
1102 | } |
1103 | ||
1104 | void bus_unit_send_removed_signal(Unit *u) { | |
718db961 | 1105 | int r; |
c1e1601e LP |
1106 | assert(u); |
1107 | ||
ac155bb8 | 1108 | if (!u->sent_dbus_new_signal) |
7535cc78 LP |
1109 | bus_unit_send_change_signal(u); |
1110 | ||
ac155bb8 | 1111 | if (!u->id) |
04ade7d2 LP |
1112 | return; |
1113 | ||
8f8f05a9 | 1114 | r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u); |
718db961 | 1115 | if (r < 0) |
f2341e0a | 1116 | log_unit_debug_errno(u, r, "Failed to send unit remove signal for %s: %m", u->id); |
c1e1601e | 1117 | } |
e2110e5d | 1118 | |
718db961 | 1119 | int bus_unit_queue_job( |
718db961 | 1120 | sd_bus_message *message, |
cad45ba1 LP |
1121 | Unit *u, |
1122 | JobType type, | |
1123 | JobMode mode, | |
ebcf1f97 LP |
1124 | bool reload_if_possible, |
1125 | sd_bus_error *error) { | |
cad45ba1 | 1126 | |
cad45ba1 LP |
1127 | _cleanup_free_ char *path = NULL; |
1128 | Job *j; | |
cad45ba1 LP |
1129 | int r; |
1130 | ||
cad45ba1 LP |
1131 | assert(message); |
1132 | assert(u); | |
1133 | assert(type >= 0 && type < _JOB_TYPE_MAX); | |
1134 | assert(mode >= 0 && mode < _JOB_MODE_MAX); | |
1135 | ||
f596e00f EV |
1136 | r = mac_selinux_unit_access_check( |
1137 | u, message, | |
1138 | job_type_to_access_method(type), | |
1139 | error); | |
1140 | if (r < 0) | |
1141 | return r; | |
1142 | ||
cad45ba1 LP |
1143 | if (reload_if_possible && unit_can_reload(u)) { |
1144 | if (type == JOB_RESTART) | |
1145 | type = JOB_RELOAD_OR_START; | |
1146 | else if (type == JOB_TRY_RESTART) | |
3282591d | 1147 | type = JOB_TRY_RELOAD; |
cad45ba1 LP |
1148 | } |
1149 | ||
718db961 LP |
1150 | if (type == JOB_STOP && |
1151 | (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) && | |
1152 | unit_active_state(u) == UNIT_INACTIVE) | |
ebcf1f97 | 1153 | return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id); |
cad45ba1 LP |
1154 | |
1155 | if ((type == JOB_START && u->refuse_manual_start) || | |
1156 | (type == JOB_STOP && u->refuse_manual_stop) || | |
efb30ba1 EV |
1157 | ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) || |
1158 | (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start)) | |
ebcf1f97 | 1159 | return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id); |
cad45ba1 | 1160 | |
4bd29fe5 | 1161 | r = manager_add_job(u->manager, type, u, mode, error, &j); |
cad45ba1 | 1162 | if (r < 0) |
ebcf1f97 | 1163 | return r; |
cad45ba1 | 1164 | |
19070062 | 1165 | if (sd_bus_message_get_bus(message) == u->manager->api_bus) { |
b39a2770 | 1166 | if (!j->clients) { |
19070062 | 1167 | r = sd_bus_track_new(sd_bus_message_get_bus(message), &j->clients, NULL, NULL); |
8f8f05a9 LP |
1168 | if (r < 0) |
1169 | return r; | |
1170 | } | |
1171 | ||
b39a2770 | 1172 | r = sd_bus_track_add_sender(j->clients, message); |
8f8f05a9 LP |
1173 | if (r < 0) |
1174 | return r; | |
1175 | } | |
cad45ba1 LP |
1176 | |
1177 | path = job_dbus_path(j); | |
1178 | if (!path) | |
6ce270b1 | 1179 | return -ENOMEM; |
cad45ba1 | 1180 | |
df2d202e | 1181 | return sd_bus_reply_method_return(message, "o", path); |
cad45ba1 LP |
1182 | } |
1183 | ||
9f2e86af LP |
1184 | static int bus_unit_set_transient_property( |
1185 | Unit *u, | |
1186 | const char *name, | |
718db961 | 1187 | sd_bus_message *message, |
9f2e86af | 1188 | UnitSetPropertiesMode mode, |
718db961 | 1189 | sd_bus_error *error) { |
9f2e86af LP |
1190 | |
1191 | int r; | |
1192 | ||
1193 | assert(u); | |
1194 | assert(name); | |
718db961 | 1195 | assert(message); |
9f2e86af LP |
1196 | |
1197 | if (streq(name, "Description")) { | |
718db961 | 1198 | const char *d; |
9f2e86af | 1199 | |
718db961 LP |
1200 | r = sd_bus_message_read(message, "s", &d); |
1201 | if (r < 0) | |
1202 | return r; | |
8aec412f | 1203 | |
718db961 LP |
1204 | if (mode != UNIT_CHECK) { |
1205 | r = unit_set_description(u, d); | |
8aec412f LP |
1206 | if (r < 0) |
1207 | return r; | |
b9316fb0 | 1208 | |
b27b4b51 | 1209 | unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s", d); |
8aec412f | 1210 | } |
9f2e86af LP |
1211 | |
1212 | return 1; | |
261420ba LP |
1213 | |
1214 | } else if (streq(name, "DefaultDependencies")) { | |
1215 | int b; | |
1216 | ||
1217 | r = sd_bus_message_read(message, "b", &b); | |
1218 | if (r < 0) | |
1219 | return r; | |
1220 | ||
1221 | if (mode != UNIT_CHECK) { | |
1222 | u->default_dependencies = b; | |
b27b4b51 | 1223 | unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s", yes_no(b)); |
261420ba LP |
1224 | } |
1225 | ||
1226 | return 1; | |
c221420b | 1227 | |
d79200e2 LP |
1228 | } else if (streq(name, "Slice")) { |
1229 | Unit *slice; | |
c221420b | 1230 | const char *s; |
c221420b | 1231 | |
d79200e2 LP |
1232 | if (!UNIT_HAS_CGROUP_CONTEXT(u)) |
1233 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "The slice property is only available for units with control groups."); | |
1234 | if (u->type == UNIT_SLICE) | |
1235 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Slice may not be set for slice units."); | |
efdb0237 LP |
1236 | if (unit_has_name(u, SPECIAL_INIT_SCOPE)) |
1237 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set slice for init.scope"); | |
d79200e2 | 1238 | |
718db961 LP |
1239 | r = sd_bus_message_read(message, "s", &s); |
1240 | if (r < 0) | |
1241 | return r; | |
c221420b | 1242 | |
d79200e2 LP |
1243 | if (!unit_name_is_valid(s, UNIT_NAME_PLAIN)) |
1244 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name '%s'", s); | |
1245 | ||
aea529e5 LP |
1246 | /* Note that we do not dispatch the load queue here yet, as we don't want our own transient unit to be |
1247 | * loaded while we are still setting it up. Or in other words, we use manager_load_unit_prepare() | |
1248 | * instead of manager_load_unit() on purpose, here. */ | |
1249 | r = manager_load_unit_prepare(u->manager, s, NULL, error, &slice); | |
d79200e2 LP |
1250 | if (r < 0) |
1251 | return r; | |
c221420b | 1252 | |
d79200e2 LP |
1253 | if (slice->type != UNIT_SLICE) |
1254 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit name '%s' is not a slice", s); | |
b9316fb0 | 1255 | |
d79200e2 LP |
1256 | if (mode != UNIT_CHECK) { |
1257 | r = unit_set_slice(u, slice); | |
8aec412f LP |
1258 | if (r < 0) |
1259 | return r; | |
c221420b | 1260 | |
b27b4b51 | 1261 | unit_write_drop_in_private_format(u, mode, name, "Slice=%s", s); |
8aec412f | 1262 | } |
b9ec9359 | 1263 | |
c221420b | 1264 | return 1; |
d79200e2 | 1265 | |
311f6cf3 WC |
1266 | } else if (STR_IN_SET(name, |
1267 | "Requires", "RequiresOverridable", | |
1268 | "Requisite", "RequisiteOverridable", | |
1269 | "Wants", | |
1270 | "BindsTo", | |
1271 | "Conflicts", | |
1272 | "Before", "After", | |
1273 | "OnFailure", | |
1274 | "PropagatesReloadTo", "ReloadPropagatedFrom", | |
1275 | "PartOf")) { | |
7fb3ee51 LP |
1276 | |
1277 | UnitDependency d; | |
718db961 | 1278 | const char *other; |
7fb3ee51 | 1279 | |
f32b43bd LP |
1280 | if (streq(name, "RequiresOverridable")) |
1281 | d = UNIT_REQUIRES; /* redirect for obsolete unit dependency type */ | |
1282 | else if (streq(name, "RequisiteOverridable")) | |
1283 | d = UNIT_REQUISITE; /* same here */ | |
1284 | else { | |
1285 | d = unit_dependency_from_string(name); | |
1286 | if (d < 0) | |
1287 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit dependency: %s", name); | |
1288 | } | |
7fb3ee51 | 1289 | |
718db961 LP |
1290 | r = sd_bus_message_enter_container(message, 'a', "s"); |
1291 | if (r < 0) | |
1292 | return r; | |
7fb3ee51 | 1293 | |
718db961 | 1294 | while ((r = sd_bus_message_read(message, "s", &other)) > 0) { |
7410616c | 1295 | if (!unit_name_is_valid(other, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) |
718db961 | 1296 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other); |
7fb3ee51 LP |
1297 | |
1298 | if (mode != UNIT_CHECK) { | |
b9ec9359 | 1299 | _cleanup_free_ char *label = NULL; |
7fb3ee51 LP |
1300 | |
1301 | r = unit_add_dependency_by_name(u, d, other, NULL, true); | |
1302 | if (r < 0) | |
1303 | return r; | |
1304 | ||
1305 | label = strjoin(name, "-", other, NULL); | |
1306 | if (!label) | |
1307 | return -ENOMEM; | |
1308 | ||
b27b4b51 | 1309 | unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s", name, other); |
7fb3ee51 LP |
1310 | } |
1311 | ||
7fb3ee51 | 1312 | } |
718db961 LP |
1313 | if (r < 0) |
1314 | return r; | |
7fb3ee51 | 1315 | |
6ce270b1 LP |
1316 | r = sd_bus_message_exit_container(message); |
1317 | if (r < 0) | |
1318 | return r; | |
1319 | ||
7fb3ee51 | 1320 | return 1; |
9f2e86af LP |
1321 | } |
1322 | ||
1323 | return 0; | |
1324 | } | |
1325 | ||
c2756a68 LP |
1326 | int bus_unit_set_properties( |
1327 | Unit *u, | |
718db961 | 1328 | sd_bus_message *message, |
c2756a68 LP |
1329 | UnitSetPropertiesMode mode, |
1330 | bool commit, | |
718db961 | 1331 | sd_bus_error *error) { |
c2756a68 | 1332 | |
8e2af478 | 1333 | bool for_real = false; |
8e2af478 LP |
1334 | unsigned n = 0; |
1335 | int r; | |
1336 | ||
1337 | assert(u); | |
718db961 | 1338 | assert(message); |
8e2af478 LP |
1339 | |
1340 | /* We iterate through the array twice. First run we just check | |
1341 | * if all passed data is valid, second run actually applies | |
1342 | * it. This is to implement transaction-like behaviour without | |
1343 | * actually providing full transactions. */ | |
1344 | ||
718db961 LP |
1345 | r = sd_bus_message_enter_container(message, 'a', "(sv)"); |
1346 | if (r < 0) | |
1347 | return r; | |
8e2af478 | 1348 | |
8e2af478 | 1349 | for (;;) { |
8e2af478 LP |
1350 | const char *name; |
1351 | ||
718db961 LP |
1352 | r = sd_bus_message_enter_container(message, 'r', "sv"); |
1353 | if (r < 0) | |
1354 | return r; | |
1355 | if (r == 0) { | |
a255a7f1 | 1356 | if (for_real || mode == UNIT_CHECK) |
8e2af478 LP |
1357 | break; |
1358 | ||
1359 | /* Reached EOF. Let's try again, and this time for realz... */ | |
718db961 LP |
1360 | r = sd_bus_message_rewind(message, false); |
1361 | if (r < 0) | |
1362 | return r; | |
6ce270b1 | 1363 | |
8e2af478 LP |
1364 | for_real = true; |
1365 | continue; | |
1366 | } | |
1367 | ||
718db961 LP |
1368 | r = sd_bus_message_read(message, "s", &name); |
1369 | if (r < 0) | |
1370 | return r; | |
8e2af478 | 1371 | |
718db961 LP |
1372 | if (!UNIT_VTABLE(u)->bus_set_property) |
1373 | return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties."); | |
8e2af478 | 1374 | |
718db961 LP |
1375 | r = sd_bus_message_enter_container(message, 'v', NULL); |
1376 | if (r < 0) | |
1377 | return r; | |
8e2af478 | 1378 | |
718db961 | 1379 | r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error); |
9f2e86af | 1380 | if (r == 0 && u->transient && u->load_state == UNIT_STUB) |
718db961 LP |
1381 | r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error); |
1382 | if (r < 0) | |
1383 | return r; | |
1384 | if (r == 0) | |
1385 | return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name); | |
1386 | ||
1387 | r = sd_bus_message_exit_container(message); | |
8e2af478 LP |
1388 | if (r < 0) |
1389 | return r; | |
8e2af478 | 1390 | |
718db961 LP |
1391 | r = sd_bus_message_exit_container(message); |
1392 | if (r < 0) | |
1393 | return r; | |
8e2af478 LP |
1394 | |
1395 | n += for_real; | |
1396 | } | |
1397 | ||
6ce270b1 LP |
1398 | r = sd_bus_message_exit_container(message); |
1399 | if (r < 0) | |
1400 | return r; | |
1401 | ||
c2756a68 | 1402 | if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties) |
8e2af478 LP |
1403 | UNIT_VTABLE(u)->bus_commit_properties(u); |
1404 | ||
241da328 | 1405 | return n; |
8e2af478 | 1406 | } |
000a996d FB |
1407 | |
1408 | int bus_unit_check_load_state(Unit *u, sd_bus_error *error) { | |
6eb7c172 | 1409 | assert(u); |
000a996d FB |
1410 | |
1411 | if (u->load_state == UNIT_LOADED) | |
1412 | return 0; | |
1413 | ||
1414 | /* Give a better description of the unit error when | |
1415 | * possible. Note that in the case of UNIT_MASKED, load_error | |
1416 | * is not set. */ | |
1417 | if (u->load_state == UNIT_MASKED) | |
b21d2f81 | 1418 | return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit %s is masked.", u->id); |
000a996d FB |
1419 | |
1420 | if (u->load_state == UNIT_NOT_FOUND) | |
b21d2f81 | 1421 | return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not found.", u->id); |
000a996d | 1422 | |
b21d2f81 | 1423 | return sd_bus_error_set_errnof(error, u->load_error, "Unit %s is not loaded properly: %m.", u->id); |
000a996d | 1424 | } |