]>
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" |
906c06f6 | 23 | #include "bpf-firewall.h" |
07630cea LP |
24 | #include "bus-common-errors.h" |
25 | #include "cgroup-util.h" | |
c5a97ed1 | 26 | #include "dbus-job.h" |
8752c575 | 27 | #include "dbus-unit.h" |
07630cea | 28 | #include "dbus.h" |
291d565a | 29 | #include "fd-util.h" |
8752c575 | 30 | #include "locale-util.h" |
ea430986 | 31 | #include "log.h" |
291d565a | 32 | #include "process-util.h" |
e2417e41 | 33 | #include "selinux-access.h" |
6eb7c172 | 34 | #include "signal-util.h" |
efdb0237 | 35 | #include "special.h" |
07630cea LP |
36 | #include "string-util.h" |
37 | #include "strv.h" | |
ee104e11 | 38 | #include "user-util.h" |
718db961 LP |
39 | |
40 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState); | |
d420282b | 41 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode); |
87a47f99 | 42 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction); |
718db961 LP |
43 | |
44 | static int property_get_names( | |
45 | sd_bus *bus, | |
46 | const char *path, | |
47 | const char *interface, | |
48 | const char *property, | |
49 | sd_bus_message *reply, | |
ebcf1f97 LP |
50 | void *userdata, |
51 | sd_bus_error *error) { | |
718db961 LP |
52 | |
53 | Unit *u = userdata; | |
54 | Iterator i; | |
55 | const char *t; | |
56 | int r; | |
ea430986 | 57 | |
718db961 LP |
58 | assert(bus); |
59 | assert(reply); | |
60 | assert(u); | |
4139c1b2 | 61 | |
718db961 LP |
62 | r = sd_bus_message_open_container(reply, 'a', "s"); |
63 | if (r < 0) | |
64 | return r; | |
4139c1b2 | 65 | |
718db961 LP |
66 | SET_FOREACH(t, u->names, i) { |
67 | r = sd_bus_message_append(reply, "s", t); | |
68 | if (r < 0) | |
69 | return r; | |
70 | } | |
4139c1b2 | 71 | |
718db961 | 72 | return sd_bus_message_close_container(reply); |
4139c1b2 LP |
73 | } |
74 | ||
718db961 LP |
75 | static int property_get_following( |
76 | sd_bus *bus, | |
77 | const char *path, | |
78 | const char *interface, | |
79 | const char *property, | |
80 | sd_bus_message *reply, | |
ebcf1f97 LP |
81 | void *userdata, |
82 | sd_bus_error *error) { | |
718db961 LP |
83 | |
84 | Unit *u = userdata, *f; | |
8fe914ec | 85 | |
718db961 LP |
86 | assert(bus); |
87 | assert(reply); | |
8fe914ec LP |
88 | assert(u); |
89 | ||
a7f241db | 90 | f = unit_following(u); |
718db961 | 91 | return sd_bus_message_append(reply, "s", f ? f->id : ""); |
8fe914ec LP |
92 | } |
93 | ||
718db961 LP |
94 | static int property_get_dependencies( |
95 | sd_bus *bus, | |
96 | const char *path, | |
97 | const char *interface, | |
98 | const char *property, | |
99 | sd_bus_message *reply, | |
ebcf1f97 LP |
100 | void *userdata, |
101 | sd_bus_error *error) { | |
4ec9a8a4 | 102 | |
eef85c4a | 103 | Hashmap *h = *(Hashmap**) userdata; |
5301be81 | 104 | Iterator j; |
718db961 | 105 | Unit *u; |
eef85c4a | 106 | void *v; |
718db961 | 107 | int r; |
5301be81 | 108 | |
718db961 LP |
109 | assert(bus); |
110 | assert(reply); | |
5301be81 | 111 | |
718db961 LP |
112 | r = sd_bus_message_open_container(reply, 'a', "s"); |
113 | if (r < 0) | |
114 | return r; | |
5301be81 | 115 | |
eef85c4a | 116 | HASHMAP_FOREACH_KEY(v, u, h, j) { |
718db961 LP |
117 | r = sd_bus_message_append(reply, "s", u->id); |
118 | if (r < 0) | |
119 | return r; | |
120 | } | |
5301be81 | 121 | |
718db961 | 122 | return sd_bus_message_close_container(reply); |
5301be81 LP |
123 | } |
124 | ||
f32b43bd LP |
125 | static int property_get_obsolete_dependencies( |
126 | sd_bus *bus, | |
127 | const char *path, | |
128 | const char *interface, | |
129 | const char *property, | |
130 | sd_bus_message *reply, | |
131 | void *userdata, | |
132 | sd_bus_error *error) { | |
133 | ||
134 | assert(bus); | |
135 | assert(reply); | |
136 | ||
137 | /* For dependency types we don't support anymore always return an empty array */ | |
138 | return sd_bus_message_append(reply, "as", 0); | |
139 | } | |
140 | ||
718db961 LP |
141 | static int property_get_description( |
142 | sd_bus *bus, | |
143 | const char *path, | |
144 | const char *interface, | |
145 | const char *property, | |
146 | sd_bus_message *reply, | |
ebcf1f97 LP |
147 | void *userdata, |
148 | sd_bus_error *error) { | |
ea430986 | 149 | |
718db961 | 150 | Unit *u = userdata; |
ea430986 | 151 | |
718db961 LP |
152 | assert(bus); |
153 | assert(reply); | |
154 | assert(u); | |
ea430986 | 155 | |
718db961 | 156 | return sd_bus_message_append(reply, "s", unit_description(u)); |
ea430986 LP |
157 | } |
158 | ||
718db961 LP |
159 | static int property_get_active_state( |
160 | sd_bus *bus, | |
161 | const char *path, | |
162 | const char *interface, | |
163 | const char *property, | |
164 | sd_bus_message *reply, | |
ebcf1f97 LP |
165 | void *userdata, |
166 | sd_bus_error *error) { | |
ea430986 | 167 | |
718db961 | 168 | Unit *u = userdata; |
ea430986 | 169 | |
718db961 LP |
170 | assert(bus); |
171 | assert(reply); | |
ea430986 LP |
172 | assert(u); |
173 | ||
718db961 | 174 | return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u))); |
ea430986 LP |
175 | } |
176 | ||
718db961 LP |
177 | static int property_get_sub_state( |
178 | sd_bus *bus, | |
179 | const char *path, | |
180 | const char *interface, | |
181 | const char *property, | |
182 | sd_bus_message *reply, | |
ebcf1f97 LP |
183 | void *userdata, |
184 | sd_bus_error *error) { | |
10a94420 | 185 | |
718db961 | 186 | Unit *u = userdata; |
10a94420 | 187 | |
718db961 LP |
188 | assert(bus); |
189 | assert(reply); | |
190 | assert(u); | |
10a94420 | 191 | |
718db961 | 192 | return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u)); |
10a94420 LP |
193 | } |
194 | ||
d2dc52db LP |
195 | static int property_get_unit_file_preset( |
196 | sd_bus *bus, | |
197 | const char *path, | |
198 | const char *interface, | |
199 | const char *property, | |
200 | sd_bus_message *reply, | |
201 | void *userdata, | |
202 | sd_bus_error *error) { | |
203 | ||
204 | Unit *u = userdata; | |
205 | int r; | |
206 | ||
207 | assert(bus); | |
208 | assert(reply); | |
209 | assert(u); | |
210 | ||
211 | r = unit_get_unit_file_preset(u); | |
212 | ||
213 | return sd_bus_message_append(reply, "s", | |
214 | r < 0 ? "": | |
215 | r > 0 ? "enabled" : "disabled"); | |
216 | } | |
217 | ||
718db961 LP |
218 | static int property_get_unit_file_state( |
219 | sd_bus *bus, | |
220 | const char *path, | |
221 | const char *interface, | |
222 | const char *property, | |
223 | sd_bus_message *reply, | |
ebcf1f97 LP |
224 | void *userdata, |
225 | sd_bus_error *error) { | |
a4375746 | 226 | |
718db961 | 227 | Unit *u = userdata; |
a4375746 | 228 | |
718db961 LP |
229 | assert(bus); |
230 | assert(reply); | |
231 | assert(u); | |
a4375746 | 232 | |
76445832 | 233 | return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u))); |
a4375746 LP |
234 | } |
235 | ||
718db961 LP |
236 | static int property_get_can_start( |
237 | sd_bus *bus, | |
238 | const char *path, | |
239 | const char *interface, | |
240 | const char *property, | |
241 | sd_bus_message *reply, | |
ebcf1f97 LP |
242 | void *userdata, |
243 | sd_bus_error *error) { | |
38131695 | 244 | |
718db961 | 245 | Unit *u = userdata; |
b5e9dba8 | 246 | |
718db961 LP |
247 | assert(bus); |
248 | assert(reply); | |
249 | assert(u); | |
b5e9dba8 | 250 | |
718db961 | 251 | return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start); |
b5e9dba8 LP |
252 | } |
253 | ||
718db961 LP |
254 | static int property_get_can_stop( |
255 | sd_bus *bus, | |
256 | const char *path, | |
257 | const char *interface, | |
258 | const char *property, | |
259 | sd_bus_message *reply, | |
ebcf1f97 LP |
260 | void *userdata, |
261 | sd_bus_error *error) { | |
718db961 LP |
262 | |
263 | Unit *u = userdata; | |
b5e9dba8 | 264 | |
718db961 LP |
265 | assert(bus); |
266 | assert(reply); | |
b5e9dba8 LP |
267 | assert(u); |
268 | ||
f5869324 | 269 | return sd_bus_message_append(reply, "b", unit_can_stop(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, | |
05a98afd | 421 | bool interactive, |
88ced61b MC |
422 | sd_bus_message *call, |
423 | sd_bus_error *error) { | |
424 | ||
425 | const char *details[9] = { | |
426 | "unit", u->id, | |
427 | "verb", verb, | |
428 | }; | |
429 | ||
430 | if (polkit_message) { | |
431 | details[4] = "polkit.message"; | |
432 | details[5] = polkit_message; | |
433 | details[6] = "polkit.gettext_domain"; | |
434 | details[7] = GETTEXT_PACKAGE; | |
435 | } | |
436 | ||
05a98afd LP |
437 | return bus_verify_polkit_async( |
438 | call, | |
439 | capability, | |
440 | "org.freedesktop.systemd1.manage-units", | |
441 | details, | |
442 | interactive, | |
443 | UID_INVALID, | |
444 | &u->manager->polkit_registry, | |
445 | error); | |
88ced61b MC |
446 | } |
447 | ||
1d22e906 | 448 | int bus_unit_method_start_generic( |
1d22e906 LP |
449 | sd_bus_message *message, |
450 | Unit *u, | |
451 | JobType job_type, | |
452 | bool reload_if_possible, | |
453 | sd_bus_error *error) { | |
454 | ||
718db961 LP |
455 | const char *smode; |
456 | JobMode mode; | |
88ced61b MC |
457 | _cleanup_free_ char *verb = NULL; |
458 | static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = { | |
459 | [JOB_START] = N_("Authentication is required to start '$(unit)'."), | |
460 | [JOB_STOP] = N_("Authentication is required to stop '$(unit)'."), | |
461 | [JOB_RELOAD] = N_("Authentication is required to reload '$(unit)'."), | |
462 | [JOB_RESTART] = N_("Authentication is required to restart '$(unit)'."), | |
463 | [JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."), | |
464 | }; | |
718db961 | 465 | int r; |
9f39404c | 466 | |
718db961 | 467 | assert(message); |
9f39404c | 468 | assert(u); |
718db961 | 469 | assert(job_type >= 0 && job_type < _JOB_TYPE_MAX); |
9f39404c | 470 | |
61ea63f1 EV |
471 | r = mac_selinux_unit_access_check( |
472 | u, message, | |
94bd7323 EV |
473 | job_type_to_access_method(job_type), |
474 | error); | |
1d22e906 LP |
475 | if (r < 0) |
476 | return r; | |
477 | ||
718db961 LP |
478 | r = sd_bus_message_read(message, "s", &smode); |
479 | if (r < 0) | |
ebcf1f97 | 480 | return r; |
9f39404c | 481 | |
718db961 LP |
482 | mode = job_mode_from_string(smode); |
483 | if (mode < 0) | |
ebcf1f97 | 484 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode); |
9f39404c | 485 | |
88ced61b | 486 | if (reload_if_possible) |
605405c6 | 487 | verb = strjoin("reload-or-", job_type_to_string(job_type)); |
88ced61b MC |
488 | else |
489 | verb = strdup(job_type_to_string(job_type)); | |
490 | if (!verb) | |
491 | return -ENOMEM; | |
492 | ||
493 | r = bus_verify_manage_units_async_full( | |
494 | u, | |
495 | verb, | |
496 | CAP_SYS_ADMIN, | |
497 | job_type < _JOB_TYPE_MAX ? polkit_message_for_job[job_type] : NULL, | |
05a98afd | 498 | true, |
88ced61b MC |
499 | message, |
500 | error); | |
1d22e906 LP |
501 | if (r < 0) |
502 | return r; | |
503 | if (r == 0) | |
504 | return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ | |
505 | ||
19070062 | 506 | return bus_unit_queue_job(message, u, job_type, mode, reload_if_possible, error); |
9f39404c LP |
507 | } |
508 | ||
19070062 LP |
509 | static int method_start(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
510 | return bus_unit_method_start_generic(message, userdata, JOB_START, false, error); | |
718db961 | 511 | } |
b548631a | 512 | |
19070062 LP |
513 | static int method_stop(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
514 | return bus_unit_method_start_generic(message, userdata, JOB_STOP, false, error); | |
718db961 LP |
515 | } |
516 | ||
19070062 LP |
517 | static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
518 | return bus_unit_method_start_generic(message, userdata, JOB_RELOAD, false, error); | |
718db961 | 519 | } |
0a524ba7 | 520 | |
19070062 LP |
521 | static int method_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
522 | return bus_unit_method_start_generic(message, userdata, JOB_RESTART, false, error); | |
718db961 | 523 | } |
8a0867d6 | 524 | |
19070062 LP |
525 | static int method_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
526 | return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, false, error); | |
718db961 | 527 | } |
cad45ba1 | 528 | |
19070062 LP |
529 | static int method_reload_or_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
530 | return bus_unit_method_start_generic(message, userdata, JOB_RESTART, true, error); | |
718db961 | 531 | } |
8a0867d6 | 532 | |
19070062 LP |
533 | static int method_reload_or_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
534 | return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, true, error); | |
718db961 | 535 | } |
8a0867d6 | 536 | |
19070062 | 537 | int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
718db961 LP |
538 | Unit *u = userdata; |
539 | const char *swho; | |
540 | int32_t signo; | |
541 | KillWho who; | |
542 | int r; | |
5632e374 | 543 | |
718db961 LP |
544 | assert(message); |
545 | assert(u); | |
cad45ba1 | 546 | |
1d22e906 | 547 | r = mac_selinux_unit_access_check(u, message, "stop", error); |
283868e1 SW |
548 | if (r < 0) |
549 | return r; | |
283868e1 | 550 | |
718db961 LP |
551 | r = sd_bus_message_read(message, "si", &swho, &signo); |
552 | if (r < 0) | |
ebcf1f97 | 553 | return r; |
718db961 LP |
554 | |
555 | if (isempty(swho)) | |
556 | who = KILL_ALL; | |
557 | else { | |
558 | who = kill_who_from_string(swho); | |
559 | if (who < 0) | |
ebcf1f97 | 560 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho); |
718db961 | 561 | } |
5632e374 | 562 | |
6eb7c172 | 563 | if (!SIGNAL_VALID(signo)) |
ebcf1f97 | 564 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range."); |
8e2af478 | 565 | |
88ced61b MC |
566 | r = bus_verify_manage_units_async_full( |
567 | u, | |
568 | "kill", | |
569 | CAP_KILL, | |
570 | N_("Authentication is required to kill '$(unit)'."), | |
05a98afd | 571 | true, |
88ced61b MC |
572 | message, |
573 | error); | |
ebcf1f97 LP |
574 | if (r < 0) |
575 | return r; | |
1d22e906 LP |
576 | if (r == 0) |
577 | return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ | |
8e2af478 | 578 | |
ebcf1f97 | 579 | r = unit_kill(u, who, signo, error); |
718db961 | 580 | if (r < 0) |
ebcf1f97 | 581 | return r; |
8e2af478 | 582 | |
df2d202e | 583 | return sd_bus_reply_method_return(message, NULL); |
718db961 | 584 | } |
8e2af478 | 585 | |
19070062 | 586 | int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
718db961 | 587 | Unit *u = userdata; |
ebcf1f97 | 588 | int r; |
b548631a | 589 | |
718db961 LP |
590 | assert(message); |
591 | assert(u); | |
b548631a | 592 | |
1d22e906 | 593 | r = mac_selinux_unit_access_check(u, message, "reload", error); |
283868e1 SW |
594 | if (r < 0) |
595 | return r; | |
283868e1 | 596 | |
88ced61b MC |
597 | r = bus_verify_manage_units_async_full( |
598 | u, | |
599 | "reset-failed", | |
600 | CAP_SYS_ADMIN, | |
601 | N_("Authentication is required to reset the \"failed\" state of '$(unit)'."), | |
05a98afd | 602 | true, |
88ced61b MC |
603 | message, |
604 | error); | |
ebcf1f97 LP |
605 | if (r < 0) |
606 | return r; | |
1d22e906 LP |
607 | if (r == 0) |
608 | return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ | |
b548631a | 609 | |
718db961 | 610 | unit_reset_failed(u); |
b548631a | 611 | |
df2d202e | 612 | return sd_bus_reply_method_return(message, NULL); |
ea430986 LP |
613 | } |
614 | ||
19070062 | 615 | int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
718db961 LP |
616 | Unit *u = userdata; |
617 | int runtime, r; | |
ea430986 | 618 | |
ea430986 | 619 | assert(message); |
718db961 | 620 | assert(u); |
80fbf05e | 621 | |
1d22e906 | 622 | r = mac_selinux_unit_access_check(u, message, "start", error); |
283868e1 SW |
623 | if (r < 0) |
624 | return r; | |
283868e1 | 625 | |
718db961 LP |
626 | r = sd_bus_message_read(message, "b", &runtime); |
627 | if (r < 0) | |
ebcf1f97 | 628 | return r; |
2cccbca4 | 629 | |
88ced61b MC |
630 | r = bus_verify_manage_units_async_full( |
631 | u, | |
632 | "set-property", | |
633 | CAP_SYS_ADMIN, | |
634 | N_("Authentication is required to set properties on '$(unit)'."), | |
05a98afd | 635 | true, |
88ced61b MC |
636 | message, |
637 | error); | |
ebcf1f97 LP |
638 | if (r < 0) |
639 | return r; | |
1d22e906 LP |
640 | if (r == 0) |
641 | return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ | |
cad45ba1 | 642 | |
ebcf1f97 | 643 | r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error); |
718db961 | 644 | if (r < 0) |
ebcf1f97 | 645 | return r; |
2cccbca4 | 646 | |
df2d202e | 647 | return sd_bus_reply_method_return(message, NULL); |
718db961 | 648 | } |
2cccbca4 | 649 | |
05a98afd LP |
650 | int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
651 | Unit *u = userdata; | |
652 | int r; | |
653 | ||
654 | assert(message); | |
655 | assert(u); | |
656 | ||
657 | r = mac_selinux_unit_access_check(u, message, "start", error); | |
658 | if (r < 0) | |
659 | return r; | |
660 | ||
661 | r = bus_verify_manage_units_async_full( | |
662 | u, | |
663 | "ref", | |
664 | CAP_SYS_ADMIN, | |
665 | NULL, | |
666 | false, | |
667 | message, | |
668 | error); | |
669 | if (r < 0) | |
670 | return r; | |
671 | if (r == 0) | |
672 | return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ | |
673 | ||
674 | r = bus_unit_track_add_sender(u, message); | |
675 | if (r < 0) | |
676 | return r; | |
677 | ||
678 | return sd_bus_reply_method_return(message, NULL); | |
679 | } | |
680 | ||
681 | int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |
682 | Unit *u = userdata; | |
683 | int r; | |
684 | ||
685 | assert(message); | |
686 | assert(u); | |
687 | ||
688 | r = bus_unit_track_remove_sender(u, message); | |
689 | if (r == -EUNATCH) | |
690 | return sd_bus_error_setf(error, BUS_ERROR_NOT_REFERENCED, "Unit has not been referenced yet."); | |
691 | if (r < 0) | |
692 | return r; | |
693 | ||
694 | return sd_bus_reply_method_return(message, NULL); | |
695 | } | |
696 | ||
718db961 LP |
697 | const sd_bus_vtable bus_unit_vtable[] = { |
698 | SD_BUS_VTABLE_START(0), | |
699 | ||
556089dc LP |
700 | SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST), |
701 | SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
718db961 | 702 | SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0), |
556089dc | 703 | SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST), |
556089dc | 704 | SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST), |
556089dc LP |
705 | SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST), |
706 | SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST), | |
707 | SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST), | |
708 | SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), | |
be7d9ff7 | 709 | SD_BUS_PROPERTY("RequisiteOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF]), SD_BUS_VTABLE_PROPERTY_CONST), |
556089dc LP |
710 | SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), |
711 | SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST), | |
712 | SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST), | |
713 | SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST), | |
714 | SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), | |
715 | SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST), | |
716 | SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST), | |
717 | SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST), | |
718 | SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST), | |
719 | SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), | |
720 | SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST), | |
721 | SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST), | |
722 | SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST), | |
723 | SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST), | |
724 | SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST), | |
725 | SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
726 | SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST), | |
718db961 LP |
727 | SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
728 | SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
556089dc LP |
729 | SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST), |
730 | SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST), | |
731 | SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST), | |
718db961 | 732 | SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0), |
d2dc52db | 733 | SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0), |
a483fb59 | 734 | BUS_PROPERTY_DUAL_TIMESTAMP("StateChangeTimestamp", offsetof(Unit, state_change_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
718db961 LP |
735 | BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
736 | BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
737 | BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
738 | BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
556089dc LP |
739 | SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST), |
740 | SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
741 | SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
742 | SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
718db961 | 743 | SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
556089dc LP |
744 | SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST), |
745 | SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST), | |
746 | SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST), | |
747 | SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST), | |
748 | SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST), | |
749 | SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST), | |
750 | SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST), | |
556089dc LP |
751 | SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST), |
752 | SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST), | |
a2df3ea4 | 753 | SD_BUS_PROPERTY("JobRunningTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_running_timeout), SD_BUS_VTABLE_PROPERTY_CONST), |
87a47f99 | 754 | SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_emergency_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST), |
f189ab18 | 755 | SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST), |
718db961 | 756 | SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
59fccdc5 | 757 | SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
718db961 | 758 | BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
59fccdc5 LP |
759 | BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
760 | SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), 0), | |
761 | SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0), | |
556089dc LP |
762 | SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST), |
763 | SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST), | |
f5869324 | 764 | SD_BUS_PROPERTY("Perpetual", "b", bus_property_get_bool, offsetof(Unit, perpetual), SD_BUS_VTABLE_PROPERTY_CONST), |
f0367da7 | 765 | SD_BUS_PROPERTY("StartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), |
6bf0f408 | 766 | SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), |
87a47f99 | 767 | SD_BUS_PROPERTY("StartLimitAction", "s", property_get_emergency_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST), |
6bf0f408 | 768 | SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST), |
4b58153d | 769 | SD_BUS_PROPERTY("InvocationID", "ay", bus_property_get_id128, offsetof(Unit, invocation_id), 0), |
718db961 | 770 | |
1d22e906 LP |
771 | SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED), |
772 | SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED), | |
773 | SD_BUS_METHOD("Reload", "s", "o", method_reload, SD_BUS_VTABLE_UNPRIVILEGED), | |
774 | SD_BUS_METHOD("Restart", "s", "o", method_restart, SD_BUS_VTABLE_UNPRIVILEGED), | |
775 | SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED), | |
776 | SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED), | |
777 | SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED), | |
778 | SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED), | |
779 | SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED), | |
780 | SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED), | |
05a98afd LP |
781 | SD_BUS_METHOD("Ref", NULL, NULL, bus_unit_method_ref, SD_BUS_VTABLE_UNPRIVILEGED), |
782 | SD_BUS_METHOD("Unref", NULL, NULL, bus_unit_method_unref, SD_BUS_VTABLE_UNPRIVILEGED), | |
718db961 | 783 | |
51d73fd9 LP |
784 | /* Obsolete properties or obsolete alias names */ |
785 | SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), | |
786 | SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), | |
787 | SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), | |
788 | SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), | |
789 | 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 |
790 | SD_BUS_VTABLE_END |
791 | }; | |
2cccbca4 | 792 | |
718db961 LP |
793 | static int property_get_slice( |
794 | sd_bus *bus, | |
795 | const char *path, | |
796 | const char *interface, | |
797 | const char *property, | |
798 | sd_bus_message *reply, | |
ebcf1f97 LP |
799 | void *userdata, |
800 | sd_bus_error *error) { | |
2cccbca4 | 801 | |
718db961 | 802 | Unit *u = userdata; |
2cccbca4 | 803 | |
718db961 LP |
804 | assert(bus); |
805 | assert(reply); | |
806 | assert(u); | |
2cccbca4 | 807 | |
718db961 LP |
808 | return sd_bus_message_append(reply, "s", unit_slice_name(u)); |
809 | } | |
2cccbca4 | 810 | |
934277fe LP |
811 | static int property_get_current_memory( |
812 | sd_bus *bus, | |
813 | const char *path, | |
814 | const char *interface, | |
815 | const char *property, | |
816 | sd_bus_message *reply, | |
817 | void *userdata, | |
818 | sd_bus_error *error) { | |
819 | ||
934277fe | 820 | uint64_t sz = (uint64_t) -1; |
5ad096b3 | 821 | Unit *u = userdata; |
934277fe LP |
822 | int r; |
823 | ||
824 | assert(bus); | |
825 | assert(reply); | |
826 | assert(u); | |
827 | ||
5ad096b3 LP |
828 | r = unit_get_memory_current(u, &sz); |
829 | if (r < 0 && r != -ENODATA) | |
f2341e0a | 830 | log_unit_warning_errno(u, r, "Failed to get memory.usage_in_bytes attribute: %m"); |
934277fe | 831 | |
5ad096b3 LP |
832 | return sd_bus_message_append(reply, "t", sz); |
833 | } | |
934277fe | 834 | |
03a7b521 LP |
835 | static int property_get_current_tasks( |
836 | sd_bus *bus, | |
837 | const char *path, | |
838 | const char *interface, | |
839 | const char *property, | |
840 | sd_bus_message *reply, | |
841 | void *userdata, | |
842 | sd_bus_error *error) { | |
843 | ||
844 | uint64_t cn = (uint64_t) -1; | |
845 | Unit *u = userdata; | |
846 | int r; | |
847 | ||
848 | assert(bus); | |
849 | assert(reply); | |
850 | assert(u); | |
851 | ||
852 | r = unit_get_tasks_current(u, &cn); | |
853 | if (r < 0 && r != -ENODATA) | |
854 | log_unit_warning_errno(u, r, "Failed to get pids.current attribute: %m"); | |
855 | ||
856 | return sd_bus_message_append(reply, "t", cn); | |
857 | } | |
858 | ||
5ad096b3 LP |
859 | static int property_get_cpu_usage( |
860 | sd_bus *bus, | |
861 | const char *path, | |
862 | const char *interface, | |
863 | const char *property, | |
864 | sd_bus_message *reply, | |
865 | void *userdata, | |
866 | sd_bus_error *error) { | |
934277fe | 867 | |
5ad096b3 LP |
868 | nsec_t ns = (nsec_t) -1; |
869 | Unit *u = userdata; | |
870 | int r; | |
871 | ||
872 | assert(bus); | |
873 | assert(reply); | |
874 | assert(u); | |
875 | ||
876 | r = unit_get_cpu_usage(u, &ns); | |
877 | if (r < 0 && r != -ENODATA) | |
f2341e0a | 878 | log_unit_warning_errno(u, r, "Failed to get cpuacct.usage attribute: %m"); |
5ad096b3 LP |
879 | |
880 | return sd_bus_message_append(reply, "t", ns); | |
934277fe LP |
881 | } |
882 | ||
98bac605 LP |
883 | static int property_get_cgroup( |
884 | sd_bus *bus, | |
885 | const char *path, | |
886 | const char *interface, | |
887 | const char *property, | |
888 | sd_bus_message *reply, | |
889 | void *userdata, | |
890 | sd_bus_error *error) { | |
891 | ||
892 | Unit *u = userdata; | |
893 | const char *t; | |
894 | ||
895 | assert(bus); | |
896 | assert(reply); | |
897 | assert(u); | |
898 | ||
899 | /* Three cases: a) u->cgroup_path is NULL, in which case the | |
900 | * unit has no control group, which we report as the empty | |
901 | * string. b) u->cgroup_path is the empty string, which | |
902 | * indicates the root cgroup, which we report as "/". c) all | |
903 | * other cases we report as-is. */ | |
904 | ||
905 | if (u->cgroup_path) | |
906 | t = isempty(u->cgroup_path) ? "/" : u->cgroup_path; | |
907 | else | |
908 | t = ""; | |
909 | ||
910 | return sd_bus_message_append(reply, "s", t); | |
911 | } | |
912 | ||
291d565a LP |
913 | static int append_process(sd_bus_message *reply, const char *p, pid_t pid, Set *pids) { |
914 | _cleanup_free_ char *buf = NULL, *cmdline = NULL; | |
915 | int r; | |
916 | ||
917 | assert(reply); | |
918 | assert(pid > 0); | |
919 | ||
920 | r = set_put(pids, PID_TO_PTR(pid)); | |
4c701096 | 921 | if (IN_SET(r, 0, -EEXIST)) |
291d565a LP |
922 | return 0; |
923 | if (r < 0) | |
924 | return r; | |
925 | ||
926 | if (!p) { | |
927 | r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &buf); | |
928 | if (r == -ESRCH) | |
929 | return 0; | |
930 | if (r < 0) | |
931 | return r; | |
932 | ||
933 | p = buf; | |
934 | } | |
935 | ||
936 | (void) get_process_cmdline(pid, 0, true, &cmdline); | |
937 | ||
938 | return sd_bus_message_append(reply, | |
939 | "(sus)", | |
940 | p, | |
941 | (uint32_t) pid, | |
942 | cmdline); | |
943 | } | |
944 | ||
945 | static int append_cgroup(sd_bus_message *reply, const char *p, Set *pids) { | |
946 | _cleanup_closedir_ DIR *d = NULL; | |
947 | _cleanup_fclose_ FILE *f = NULL; | |
948 | int r; | |
949 | ||
950 | assert(reply); | |
951 | assert(p); | |
952 | ||
953 | r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, p, &f); | |
954 | if (r == ENOENT) | |
955 | return 0; | |
956 | if (r < 0) | |
957 | return r; | |
958 | ||
959 | for (;;) { | |
960 | pid_t pid; | |
961 | ||
962 | r = cg_read_pid(f, &pid); | |
963 | if (r < 0) | |
964 | return r; | |
965 | if (r == 0) | |
966 | break; | |
967 | ||
968 | if (is_kernel_thread(pid) > 0) | |
969 | continue; | |
970 | ||
971 | r = append_process(reply, p, pid, pids); | |
972 | if (r < 0) | |
973 | return r; | |
974 | } | |
975 | ||
976 | r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, p, &d); | |
977 | if (r == -ENOENT) | |
978 | return 0; | |
979 | if (r < 0) | |
980 | return r; | |
981 | ||
982 | for (;;) { | |
983 | _cleanup_free_ char *g = NULL, *j = NULL; | |
984 | ||
985 | r = cg_read_subgroup(d, &g); | |
986 | if (r < 0) | |
987 | return r; | |
988 | if (r == 0) | |
989 | break; | |
990 | ||
605405c6 | 991 | j = strjoin(p, "/", g); |
291d565a LP |
992 | if (!j) |
993 | return -ENOMEM; | |
994 | ||
995 | r = append_cgroup(reply, j, pids); | |
996 | if (r < 0) | |
997 | return r; | |
998 | } | |
999 | ||
1000 | return 0; | |
1001 | } | |
1002 | ||
1003 | int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |
1004 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; | |
1005 | _cleanup_(set_freep) Set *pids = NULL; | |
291d565a LP |
1006 | Unit *u = userdata; |
1007 | pid_t pid; | |
1008 | int r; | |
1009 | ||
1010 | assert(message); | |
1011 | ||
807fa5d9 LP |
1012 | r = mac_selinux_unit_access_check(u, message, "status", error); |
1013 | if (r < 0) | |
1014 | return r; | |
1015 | ||
291d565a LP |
1016 | pids = set_new(NULL); |
1017 | if (!pids) | |
1018 | return -ENOMEM; | |
1019 | ||
1020 | r = sd_bus_message_new_method_return(message, &reply); | |
1021 | if (r < 0) | |
1022 | return r; | |
1023 | ||
1024 | r = sd_bus_message_open_container(reply, 'a', "(sus)"); | |
1025 | if (r < 0) | |
1026 | return r; | |
1027 | ||
1028 | if (u->cgroup_path) { | |
1029 | r = append_cgroup(reply, u->cgroup_path, pids); | |
1030 | if (r < 0) | |
1031 | return r; | |
1032 | } | |
1033 | ||
1034 | /* The main and control pids might live outside of the cgroup, hence fetch them separately */ | |
1035 | pid = unit_main_pid(u); | |
1036 | if (pid > 0) { | |
1037 | r = append_process(reply, NULL, pid, pids); | |
1038 | if (r < 0) | |
1039 | return r; | |
1040 | } | |
1041 | ||
1042 | pid = unit_control_pid(u); | |
1043 | if (pid > 0) { | |
1044 | r = append_process(reply, NULL, pid, pids); | |
1045 | if (r < 0) | |
1046 | return r; | |
1047 | } | |
1048 | ||
1049 | r = sd_bus_message_close_container(reply); | |
1050 | if (r < 0) | |
1051 | return r; | |
1052 | ||
1053 | return sd_bus_send(NULL, reply, NULL); | |
1054 | } | |
1055 | ||
906c06f6 DM |
1056 | static int property_get_ip_counter( |
1057 | sd_bus *bus, | |
1058 | const char *path, | |
1059 | const char *interface, | |
1060 | const char *property, | |
1061 | sd_bus_message *reply, | |
1062 | void *userdata, | |
1063 | sd_bus_error *error) { | |
1064 | ||
1065 | CGroupIPAccountingMetric metric; | |
1066 | uint64_t value = (uint64_t) -1; | |
1067 | Unit *u = userdata; | |
1068 | ||
1069 | assert(bus); | |
1070 | assert(reply); | |
1071 | assert(property); | |
1072 | assert(u); | |
1073 | ||
1074 | if (streq(property, "IPIngressBytes")) | |
1075 | metric = CGROUP_IP_INGRESS_BYTES; | |
1076 | else if (streq(property, "IPIngressPackets")) | |
1077 | metric = CGROUP_IP_INGRESS_PACKETS; | |
1078 | else if (streq(property, "IPEgressBytes")) | |
1079 | metric = CGROUP_IP_EGRESS_BYTES; | |
1080 | else { | |
1081 | assert(streq(property, "IPEgressPackets")); | |
1082 | metric = CGROUP_IP_EGRESS_PACKETS; | |
1083 | } | |
1084 | ||
1085 | (void) unit_get_ip_accounting(u, metric, &value); | |
1086 | return sd_bus_message_append(reply, "t", value); | |
1087 | } | |
1088 | ||
718db961 LP |
1089 | const sd_bus_vtable bus_unit_cgroup_vtable[] = { |
1090 | SD_BUS_VTABLE_START(0), | |
1091 | SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0), | |
98bac605 | 1092 | SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup, 0, 0), |
934277fe | 1093 | SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0), |
5ad096b3 | 1094 | SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0), |
03a7b521 | 1095 | SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0), |
906c06f6 DM |
1096 | SD_BUS_PROPERTY("IPIngressBytes", "t", property_get_ip_counter, 0, 0), |
1097 | SD_BUS_PROPERTY("IPIngressPackets", "t", property_get_ip_counter, 0, 0), | |
1098 | SD_BUS_PROPERTY("IPEgressBytes", "t", property_get_ip_counter, 0, 0), | |
1099 | SD_BUS_PROPERTY("IPEgressPackets", "t", property_get_ip_counter, 0, 0), | |
291d565a | 1100 | SD_BUS_METHOD("GetProcesses", NULL, "a(sus)", bus_unit_method_get_processes, SD_BUS_VTABLE_UNPRIVILEGED), |
718db961 LP |
1101 | SD_BUS_VTABLE_END |
1102 | }; | |
2cccbca4 | 1103 | |
8f8f05a9 | 1104 | static int send_new_signal(sd_bus *bus, void *userdata) { |
4afd3348 | 1105 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; |
718db961 LP |
1106 | _cleanup_free_ char *p = NULL; |
1107 | Unit *u = userdata; | |
1108 | int r; | |
2cccbca4 | 1109 | |
718db961 LP |
1110 | assert(bus); |
1111 | assert(u); | |
2cccbca4 | 1112 | |
718db961 | 1113 | p = unit_dbus_path(u); |
e861098b | 1114 | if (!p) |
718db961 | 1115 | return -ENOMEM; |
2cccbca4 | 1116 | |
718db961 LP |
1117 | r = sd_bus_message_new_signal( |
1118 | bus, | |
151b9b96 | 1119 | &m, |
718db961 LP |
1120 | "/org/freedesktop/systemd1", |
1121 | "org.freedesktop.systemd1.Manager", | |
151b9b96 | 1122 | "UnitNew"); |
718db961 LP |
1123 | if (r < 0) |
1124 | return r; | |
2cccbca4 | 1125 | |
718db961 LP |
1126 | r = sd_bus_message_append(m, "so", u->id, p); |
1127 | if (r < 0) | |
1128 | return r; | |
2cccbca4 | 1129 | |
8f8f05a9 | 1130 | return sd_bus_send(bus, m, NULL); |
718db961 | 1131 | } |
2cccbca4 | 1132 | |
8f8f05a9 | 1133 | static int send_changed_signal(sd_bus *bus, void *userdata) { |
718db961 LP |
1134 | _cleanup_free_ char *p = NULL; |
1135 | Unit *u = userdata; | |
1136 | int r; | |
2cccbca4 | 1137 | |
718db961 LP |
1138 | assert(bus); |
1139 | assert(u); | |
2cccbca4 | 1140 | |
718db961 | 1141 | p = unit_dbus_path(u); |
9ceefc81 | 1142 | if (!p) |
718db961 | 1143 | return -ENOMEM; |
2cccbca4 | 1144 | |
718db961 LP |
1145 | /* Send a properties changed signal. First for the specific |
1146 | * type, then for the generic unit. The clients may rely on | |
1147 | * this order to get atomic behavior if needed. */ | |
ea430986 | 1148 | |
aec8de63 LP |
1149 | r = sd_bus_emit_properties_changed_strv( |
1150 | bus, p, | |
21b735e7 | 1151 | unit_dbus_interface_from_type(u->type), |
aec8de63 | 1152 | NULL); |
fe7f06f1 | 1153 | if (r < 0) |
aec8de63 | 1154 | return r; |
80fbf05e | 1155 | |
fe7f06f1 | 1156 | return sd_bus_emit_properties_changed_strv( |
718db961 LP |
1157 | bus, p, |
1158 | "org.freedesktop.systemd1.Unit", | |
718db961 | 1159 | NULL); |
ea430986 LP |
1160 | } |
1161 | ||
c1e1601e | 1162 | void bus_unit_send_change_signal(Unit *u) { |
b170dd80 | 1163 | int r; |
c1e1601e | 1164 | assert(u); |
c1e1601e | 1165 | |
ac155bb8 | 1166 | if (u->in_dbus_queue) { |
71fda00f | 1167 | LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u); |
ac155bb8 | 1168 | u->in_dbus_queue = false; |
c0bd0cf7 | 1169 | } |
c1e1601e | 1170 | |
ac155bb8 | 1171 | if (!u->id) |
04ade7d2 LP |
1172 | return; |
1173 | ||
ae572acd | 1174 | r = bus_foreach_bus(u->manager, u->bus_track, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u); |
718db961 | 1175 | if (r < 0) |
f2341e0a | 1176 | log_unit_debug_errno(u, r, "Failed to send unit change signal for %s: %m", u->id); |
c1e1601e | 1177 | |
718db961 LP |
1178 | u->sent_dbus_new_signal = true; |
1179 | } | |
c4e2ceae | 1180 | |
8f8f05a9 | 1181 | static int send_removed_signal(sd_bus *bus, void *userdata) { |
4afd3348 | 1182 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; |
718db961 LP |
1183 | _cleanup_free_ char *p = NULL; |
1184 | Unit *u = userdata; | |
1185 | int r; | |
c4e2ceae | 1186 | |
718db961 LP |
1187 | assert(bus); |
1188 | assert(u); | |
c1e1601e | 1189 | |
718db961 | 1190 | p = unit_dbus_path(u); |
e861098b | 1191 | if (!p) |
718db961 | 1192 | return -ENOMEM; |
c1e1601e | 1193 | |
718db961 LP |
1194 | r = sd_bus_message_new_signal( |
1195 | bus, | |
151b9b96 | 1196 | &m, |
718db961 LP |
1197 | "/org/freedesktop/systemd1", |
1198 | "org.freedesktop.systemd1.Manager", | |
151b9b96 | 1199 | "UnitRemoved"); |
718db961 LP |
1200 | if (r < 0) |
1201 | return r; | |
c1e1601e | 1202 | |
718db961 LP |
1203 | r = sd_bus_message_append(m, "so", u->id, p); |
1204 | if (r < 0) | |
1205 | return r; | |
c1e1601e | 1206 | |
8f8f05a9 | 1207 | return sd_bus_send(bus, m, NULL); |
c1e1601e LP |
1208 | } |
1209 | ||
1210 | void bus_unit_send_removed_signal(Unit *u) { | |
718db961 | 1211 | int r; |
c1e1601e LP |
1212 | assert(u); |
1213 | ||
0dd99f86 | 1214 | if (!u->sent_dbus_new_signal || u->in_dbus_queue) |
7535cc78 LP |
1215 | bus_unit_send_change_signal(u); |
1216 | ||
ac155bb8 | 1217 | if (!u->id) |
04ade7d2 LP |
1218 | return; |
1219 | ||
ae572acd | 1220 | r = bus_foreach_bus(u->manager, u->bus_track, send_removed_signal, u); |
718db961 | 1221 | if (r < 0) |
f2341e0a | 1222 | log_unit_debug_errno(u, r, "Failed to send unit remove signal for %s: %m", u->id); |
c1e1601e | 1223 | } |
e2110e5d | 1224 | |
718db961 | 1225 | int bus_unit_queue_job( |
718db961 | 1226 | sd_bus_message *message, |
cad45ba1 LP |
1227 | Unit *u, |
1228 | JobType type, | |
1229 | JobMode mode, | |
ebcf1f97 LP |
1230 | bool reload_if_possible, |
1231 | sd_bus_error *error) { | |
cad45ba1 | 1232 | |
cad45ba1 LP |
1233 | _cleanup_free_ char *path = NULL; |
1234 | Job *j; | |
cad45ba1 LP |
1235 | int r; |
1236 | ||
cad45ba1 LP |
1237 | assert(message); |
1238 | assert(u); | |
1239 | assert(type >= 0 && type < _JOB_TYPE_MAX); | |
1240 | assert(mode >= 0 && mode < _JOB_MODE_MAX); | |
1241 | ||
f596e00f EV |
1242 | r = mac_selinux_unit_access_check( |
1243 | u, message, | |
1244 | job_type_to_access_method(type), | |
1245 | error); | |
1246 | if (r < 0) | |
1247 | return r; | |
1248 | ||
cad45ba1 LP |
1249 | if (reload_if_possible && unit_can_reload(u)) { |
1250 | if (type == JOB_RESTART) | |
1251 | type = JOB_RELOAD_OR_START; | |
1252 | else if (type == JOB_TRY_RESTART) | |
3282591d | 1253 | type = JOB_TRY_RELOAD; |
cad45ba1 LP |
1254 | } |
1255 | ||
718db961 | 1256 | if (type == JOB_STOP && |
3742095b | 1257 | (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_ERROR)) && |
718db961 | 1258 | unit_active_state(u) == UNIT_INACTIVE) |
ebcf1f97 | 1259 | return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id); |
cad45ba1 LP |
1260 | |
1261 | if ((type == JOB_START && u->refuse_manual_start) || | |
1262 | (type == JOB_STOP && u->refuse_manual_stop) || | |
3742095b | 1263 | (IN_SET(type, JOB_RESTART, JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) || |
efb30ba1 | 1264 | (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start)) |
7e974e85 | 1265 | return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id); |
cad45ba1 | 1266 | |
4bd29fe5 | 1267 | r = manager_add_job(u->manager, type, u, mode, error, &j); |
cad45ba1 | 1268 | if (r < 0) |
ebcf1f97 | 1269 | return r; |
cad45ba1 | 1270 | |
c5a97ed1 LP |
1271 | r = bus_job_track_sender(j, message); |
1272 | if (r < 0) | |
1273 | return r; | |
cad45ba1 LP |
1274 | |
1275 | path = job_dbus_path(j); | |
1276 | if (!path) | |
6ce270b1 | 1277 | return -ENOMEM; |
cad45ba1 | 1278 | |
df2d202e | 1279 | return sd_bus_reply_method_return(message, "o", path); |
cad45ba1 LP |
1280 | } |
1281 | ||
9f2e86af LP |
1282 | static int bus_unit_set_transient_property( |
1283 | Unit *u, | |
1284 | const char *name, | |
718db961 | 1285 | sd_bus_message *message, |
9f2e86af | 1286 | UnitSetPropertiesMode mode, |
718db961 | 1287 | sd_bus_error *error) { |
9f2e86af LP |
1288 | |
1289 | int r; | |
1290 | ||
1291 | assert(u); | |
1292 | assert(name); | |
718db961 | 1293 | assert(message); |
9f2e86af LP |
1294 | |
1295 | if (streq(name, "Description")) { | |
718db961 | 1296 | const char *d; |
9f2e86af | 1297 | |
718db961 LP |
1298 | r = sd_bus_message_read(message, "s", &d); |
1299 | if (r < 0) | |
1300 | return r; | |
8aec412f | 1301 | |
718db961 LP |
1302 | if (mode != UNIT_CHECK) { |
1303 | r = unit_set_description(u, d); | |
8aec412f LP |
1304 | if (r < 0) |
1305 | return r; | |
b9316fb0 | 1306 | |
b27b4b51 | 1307 | unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s", d); |
8aec412f | 1308 | } |
9f2e86af LP |
1309 | |
1310 | return 1; | |
261420ba LP |
1311 | |
1312 | } else if (streq(name, "DefaultDependencies")) { | |
1313 | int b; | |
1314 | ||
1315 | r = sd_bus_message_read(message, "b", &b); | |
1316 | if (r < 0) | |
1317 | return r; | |
1318 | ||
1319 | if (mode != UNIT_CHECK) { | |
1320 | u->default_dependencies = b; | |
b27b4b51 | 1321 | unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s", yes_no(b)); |
261420ba LP |
1322 | } |
1323 | ||
1324 | return 1; | |
c221420b | 1325 | |
d79200e2 LP |
1326 | } else if (streq(name, "Slice")) { |
1327 | Unit *slice; | |
c221420b | 1328 | const char *s; |
c221420b | 1329 | |
d79200e2 LP |
1330 | if (!UNIT_HAS_CGROUP_CONTEXT(u)) |
1331 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "The slice property is only available for units with control groups."); | |
1332 | if (u->type == UNIT_SLICE) | |
1333 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Slice may not be set for slice units."); | |
efdb0237 LP |
1334 | if (unit_has_name(u, SPECIAL_INIT_SCOPE)) |
1335 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set slice for init.scope"); | |
d79200e2 | 1336 | |
718db961 LP |
1337 | r = sd_bus_message_read(message, "s", &s); |
1338 | if (r < 0) | |
1339 | return r; | |
c221420b | 1340 | |
d79200e2 LP |
1341 | if (!unit_name_is_valid(s, UNIT_NAME_PLAIN)) |
1342 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name '%s'", s); | |
1343 | ||
aea529e5 LP |
1344 | /* Note that we do not dispatch the load queue here yet, as we don't want our own transient unit to be |
1345 | * loaded while we are still setting it up. Or in other words, we use manager_load_unit_prepare() | |
1346 | * instead of manager_load_unit() on purpose, here. */ | |
1347 | r = manager_load_unit_prepare(u->manager, s, NULL, error, &slice); | |
d79200e2 LP |
1348 | if (r < 0) |
1349 | return r; | |
c221420b | 1350 | |
d79200e2 LP |
1351 | if (slice->type != UNIT_SLICE) |
1352 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit name '%s' is not a slice", s); | |
b9316fb0 | 1353 | |
d79200e2 LP |
1354 | if (mode != UNIT_CHECK) { |
1355 | r = unit_set_slice(u, slice); | |
8aec412f LP |
1356 | if (r < 0) |
1357 | return r; | |
c221420b | 1358 | |
b27b4b51 | 1359 | unit_write_drop_in_private_format(u, mode, name, "Slice=%s", s); |
8aec412f | 1360 | } |
b9ec9359 | 1361 | |
c221420b | 1362 | return 1; |
d79200e2 | 1363 | |
311f6cf3 WC |
1364 | } else if (STR_IN_SET(name, |
1365 | "Requires", "RequiresOverridable", | |
1366 | "Requisite", "RequisiteOverridable", | |
1367 | "Wants", | |
1368 | "BindsTo", | |
1369 | "Conflicts", | |
1370 | "Before", "After", | |
1371 | "OnFailure", | |
1372 | "PropagatesReloadTo", "ReloadPropagatedFrom", | |
1373 | "PartOf")) { | |
7fb3ee51 LP |
1374 | |
1375 | UnitDependency d; | |
718db961 | 1376 | const char *other; |
7fb3ee51 | 1377 | |
f32b43bd LP |
1378 | if (streq(name, "RequiresOverridable")) |
1379 | d = UNIT_REQUIRES; /* redirect for obsolete unit dependency type */ | |
1380 | else if (streq(name, "RequisiteOverridable")) | |
1381 | d = UNIT_REQUISITE; /* same here */ | |
1382 | else { | |
1383 | d = unit_dependency_from_string(name); | |
1384 | if (d < 0) | |
1385 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit dependency: %s", name); | |
1386 | } | |
7fb3ee51 | 1387 | |
718db961 LP |
1388 | r = sd_bus_message_enter_container(message, 'a', "s"); |
1389 | if (r < 0) | |
1390 | return r; | |
7fb3ee51 | 1391 | |
718db961 | 1392 | while ((r = sd_bus_message_read(message, "s", &other)) > 0) { |
7410616c | 1393 | if (!unit_name_is_valid(other, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) |
718db961 | 1394 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other); |
7fb3ee51 LP |
1395 | |
1396 | if (mode != UNIT_CHECK) { | |
b9ec9359 | 1397 | _cleanup_free_ char *label = NULL; |
7fb3ee51 | 1398 | |
eef85c4a | 1399 | r = unit_add_dependency_by_name(u, d, other, NULL, true, UNIT_DEPENDENCY_FILE); |
7fb3ee51 LP |
1400 | if (r < 0) |
1401 | return r; | |
1402 | ||
605405c6 | 1403 | label = strjoin(name, "-", other); |
7fb3ee51 LP |
1404 | if (!label) |
1405 | return -ENOMEM; | |
1406 | ||
b27b4b51 | 1407 | unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s", name, other); |
7fb3ee51 LP |
1408 | } |
1409 | ||
7fb3ee51 | 1410 | } |
718db961 LP |
1411 | if (r < 0) |
1412 | return r; | |
7fb3ee51 | 1413 | |
6ce270b1 LP |
1414 | r = sd_bus_message_exit_container(message); |
1415 | if (r < 0) | |
1416 | return r; | |
1417 | ||
7fb3ee51 | 1418 | return 1; |
05a98afd LP |
1419 | |
1420 | } else if (streq(name, "AddRef")) { | |
1421 | ||
1422 | int b; | |
1423 | ||
1424 | /* Why is this called "AddRef" rather than just "Ref", or "Reference"? There's already a "Ref()" method | |
1425 | * on the Unit interface, and it's probably not a good idea to expose a property and a method on the | |
1426 | * same interface (well, strictly speaking AddRef isn't exposed as full property, we just read it for | |
1427 | * transient units, but still). And "References" and "ReferencedBy" is already used as unit reference | |
1428 | * dependency type, hence let's not confuse things with that. | |
1429 | * | |
1430 | * Note that we don't acually add the reference to the bus track. We do that only after the setup of | |
1431 | * the transient unit is complete, so that setting this property multiple times in the same transient | |
1432 | * unit creation call doesn't count as individual references. */ | |
1433 | ||
1434 | r = sd_bus_message_read(message, "b", &b); | |
1435 | if (r < 0) | |
1436 | return r; | |
1437 | ||
1438 | if (mode != UNIT_CHECK) | |
1439 | u->bus_track_add = b; | |
1440 | ||
1441 | return 1; | |
9f2e86af LP |
1442 | } |
1443 | ||
1444 | return 0; | |
1445 | } | |
1446 | ||
c2756a68 LP |
1447 | int bus_unit_set_properties( |
1448 | Unit *u, | |
718db961 | 1449 | sd_bus_message *message, |
c2756a68 LP |
1450 | UnitSetPropertiesMode mode, |
1451 | bool commit, | |
718db961 | 1452 | sd_bus_error *error) { |
c2756a68 | 1453 | |
8e2af478 | 1454 | bool for_real = false; |
8e2af478 LP |
1455 | unsigned n = 0; |
1456 | int r; | |
1457 | ||
1458 | assert(u); | |
718db961 | 1459 | assert(message); |
8e2af478 LP |
1460 | |
1461 | /* We iterate through the array twice. First run we just check | |
1462 | * if all passed data is valid, second run actually applies | |
1463 | * it. This is to implement transaction-like behaviour without | |
1464 | * actually providing full transactions. */ | |
1465 | ||
718db961 LP |
1466 | r = sd_bus_message_enter_container(message, 'a', "(sv)"); |
1467 | if (r < 0) | |
1468 | return r; | |
8e2af478 | 1469 | |
8e2af478 | 1470 | for (;;) { |
8e2af478 LP |
1471 | const char *name; |
1472 | ||
718db961 LP |
1473 | r = sd_bus_message_enter_container(message, 'r', "sv"); |
1474 | if (r < 0) | |
1475 | return r; | |
1476 | if (r == 0) { | |
a255a7f1 | 1477 | if (for_real || mode == UNIT_CHECK) |
8e2af478 LP |
1478 | break; |
1479 | ||
1480 | /* Reached EOF. Let's try again, and this time for realz... */ | |
718db961 LP |
1481 | r = sd_bus_message_rewind(message, false); |
1482 | if (r < 0) | |
1483 | return r; | |
6ce270b1 | 1484 | |
8e2af478 LP |
1485 | for_real = true; |
1486 | continue; | |
1487 | } | |
1488 | ||
718db961 LP |
1489 | r = sd_bus_message_read(message, "s", &name); |
1490 | if (r < 0) | |
1491 | return r; | |
8e2af478 | 1492 | |
718db961 LP |
1493 | if (!UNIT_VTABLE(u)->bus_set_property) |
1494 | return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties."); | |
8e2af478 | 1495 | |
718db961 LP |
1496 | r = sd_bus_message_enter_container(message, 'v', NULL); |
1497 | if (r < 0) | |
1498 | return r; | |
8e2af478 | 1499 | |
718db961 | 1500 | r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error); |
9f2e86af | 1501 | if (r == 0 && u->transient && u->load_state == UNIT_STUB) |
718db961 LP |
1502 | r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error); |
1503 | if (r < 0) | |
1504 | return r; | |
1505 | if (r == 0) | |
1506 | return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name); | |
1507 | ||
1508 | r = sd_bus_message_exit_container(message); | |
8e2af478 LP |
1509 | if (r < 0) |
1510 | return r; | |
8e2af478 | 1511 | |
718db961 LP |
1512 | r = sd_bus_message_exit_container(message); |
1513 | if (r < 0) | |
1514 | return r; | |
8e2af478 LP |
1515 | |
1516 | n += for_real; | |
1517 | } | |
1518 | ||
6ce270b1 LP |
1519 | r = sd_bus_message_exit_container(message); |
1520 | if (r < 0) | |
1521 | return r; | |
1522 | ||
c2756a68 | 1523 | if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties) |
8e2af478 LP |
1524 | UNIT_VTABLE(u)->bus_commit_properties(u); |
1525 | ||
241da328 | 1526 | return n; |
8e2af478 | 1527 | } |
000a996d FB |
1528 | |
1529 | int bus_unit_check_load_state(Unit *u, sd_bus_error *error) { | |
6eb7c172 | 1530 | assert(u); |
000a996d FB |
1531 | |
1532 | if (u->load_state == UNIT_LOADED) | |
1533 | return 0; | |
1534 | ||
1535 | /* Give a better description of the unit error when | |
1536 | * possible. Note that in the case of UNIT_MASKED, load_error | |
1537 | * is not set. */ | |
1538 | if (u->load_state == UNIT_MASKED) | |
b21d2f81 | 1539 | return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit %s is masked.", u->id); |
000a996d FB |
1540 | |
1541 | if (u->load_state == UNIT_NOT_FOUND) | |
b21d2f81 | 1542 | return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not found.", u->id); |
000a996d | 1543 | |
b21d2f81 | 1544 | return sd_bus_error_set_errnof(error, u->load_error, "Unit %s is not loaded properly: %m.", u->id); |
000a996d | 1545 | } |
05a98afd | 1546 | |
c5a97ed1 | 1547 | static int bus_unit_track_handler(sd_bus_track *t, void *userdata) { |
05a98afd LP |
1548 | Unit *u = userdata; |
1549 | ||
1550 | assert(t); | |
1551 | assert(u); | |
1552 | ||
1553 | u->bus_track = sd_bus_track_unref(u->bus_track); /* make sure we aren't called again */ | |
1554 | ||
1555 | unit_add_to_gc_queue(u); | |
1556 | return 0; | |
1557 | } | |
1558 | ||
c5a97ed1 | 1559 | static int bus_unit_allocate_bus_track(Unit *u) { |
05a98afd LP |
1560 | int r; |
1561 | ||
1562 | assert(u); | |
1563 | ||
1564 | if (u->bus_track) | |
1565 | return 0; | |
1566 | ||
c5a97ed1 | 1567 | r = sd_bus_track_new(u->manager->api_bus, &u->bus_track, bus_unit_track_handler, u); |
05a98afd LP |
1568 | if (r < 0) |
1569 | return r; | |
1570 | ||
1571 | r = sd_bus_track_set_recursive(u->bus_track, true); | |
1572 | if (r < 0) { | |
1573 | u->bus_track = sd_bus_track_unref(u->bus_track); | |
1574 | return r; | |
1575 | } | |
1576 | ||
1577 | return 0; | |
1578 | } | |
1579 | ||
1580 | int bus_unit_track_add_name(Unit *u, const char *name) { | |
1581 | int r; | |
1582 | ||
1583 | assert(u); | |
1584 | ||
c5a97ed1 | 1585 | r = bus_unit_allocate_bus_track(u); |
05a98afd LP |
1586 | if (r < 0) |
1587 | return r; | |
1588 | ||
1589 | return sd_bus_track_add_name(u->bus_track, name); | |
1590 | } | |
1591 | ||
1592 | int bus_unit_track_add_sender(Unit *u, sd_bus_message *m) { | |
1593 | int r; | |
1594 | ||
1595 | assert(u); | |
1596 | ||
c5a97ed1 | 1597 | r = bus_unit_allocate_bus_track(u); |
05a98afd LP |
1598 | if (r < 0) |
1599 | return r; | |
1600 | ||
1601 | return sd_bus_track_add_sender(u->bus_track, m); | |
1602 | } | |
1603 | ||
1604 | int bus_unit_track_remove_sender(Unit *u, sd_bus_message *m) { | |
1605 | assert(u); | |
1606 | ||
1607 | /* If we haven't allocated the bus track object yet, then there's definitely no reference taken yet, return an | |
1608 | * error */ | |
1609 | if (!u->bus_track) | |
1610 | return -EUNATCH; | |
1611 | ||
1612 | return sd_bus_track_remove_sender(u->bus_track, m); | |
1613 | } |