]>
Commit | Line | Data |
---|---|---|
1ee306e1 LP |
1 | /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
2 | ||
3 | /*** | |
4 | This file is part of systemd. | |
5 | ||
6 | Copyright 2011 Lennart Poettering | |
7 | ||
8 | systemd is free software; you can redistribute it and/or modify it | |
9 | under the terms of the GNU Lesser General Public License as published by | |
10 | the Free Software Foundation; either version 2.1 of the License, or | |
11 | (at your option) any later version. | |
12 | ||
13 | systemd is distributed in the hope that it will be useful, but | |
14 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | Lesser General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU Lesser General Public License | |
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
20 | ***/ | |
21 | ||
22 | #include <errno.h> | |
23 | #include <string.h> | |
24 | #include <unistd.h> | |
25 | #include <pwd.h> | |
adacb957 | 26 | #include <sys/capability.h> |
1ee306e1 | 27 | |
c3350683 LP |
28 | #include "sd-id128.h" |
29 | #include "sd-messages.h" | |
1ee306e1 | 30 | |
1ee306e1 LP |
31 | #include "strv.h" |
32 | #include "mkdir.h" | |
33 | #include "path-util.h" | |
34 | #include "special.h" | |
1ee306e1 LP |
35 | #include "fileio-label.h" |
36 | #include "label.h" | |
37 | #include "utf8.h" | |
38 | #include "unit-name.h" | |
c3350683 | 39 | #include "bus-util.h" |
718db961 | 40 | #include "bus-errors.h" |
c3350683 | 41 | #include "time-util.h" |
23c80348 | 42 | #include "cgroup-util.h" |
c3350683 | 43 | #include "machined.h" |
1ee306e1 LP |
44 | |
45 | static bool valid_machine_name(const char *p) { | |
46 | size_t l; | |
47 | ||
48 | if (!filename_is_safe(p)) | |
49 | return false; | |
50 | ||
51 | if (!ascii_is_valid(p)) | |
52 | return false; | |
53 | ||
54 | l = strlen(p); | |
55 | ||
56 | if (l < 1 || l> 64) | |
57 | return false; | |
58 | ||
59 | return true; | |
60 | } | |
61 | ||
ebcf1f97 | 62 | static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { |
c3350683 LP |
63 | _cleanup_free_ char *p = NULL; |
64 | Manager *m = userdata; | |
65 | Machine *machine; | |
66 | const char *name; | |
67 | int r; | |
68 | ||
69 | assert(bus); | |
70 | assert(message); | |
71 | assert(m); | |
72 | ||
73 | r = sd_bus_message_read(message, "s", &name); | |
74 | if (r < 0) | |
ebcf1f97 | 75 | return r; |
c3350683 LP |
76 | |
77 | machine = hashmap_get(m->machines, name); | |
78 | if (!machine) | |
ebcf1f97 | 79 | return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name); |
c3350683 LP |
80 | |
81 | p = machine_bus_path(machine); | |
82 | if (!p) | |
ebcf1f97 | 83 | return -ENOMEM; |
c3350683 | 84 | |
df2d202e | 85 | return sd_bus_reply_method_return(message, "o", p); |
c3350683 LP |
86 | } |
87 | ||
ebcf1f97 | 88 | static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { |
c3350683 LP |
89 | _cleanup_free_ char *p = NULL; |
90 | Manager *m = userdata; | |
91 | Machine *machine = NULL; | |
4e724d9c | 92 | pid_t pid; |
c3350683 LP |
93 | int r; |
94 | ||
95 | assert(bus); | |
96 | assert(message); | |
97 | assert(m); | |
98 | ||
4e724d9c LP |
99 | assert_cc(sizeof(pid_t) == sizeof(uint32_t)); |
100 | ||
c3350683 LP |
101 | r = sd_bus_message_read(message, "u", &pid); |
102 | if (r < 0) | |
ebcf1f97 | 103 | return r; |
c3350683 | 104 | |
4e724d9c | 105 | if (pid == 0) { |
5b12334d LP |
106 | _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; |
107 | ||
108 | r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); | |
109 | if (r < 0) | |
110 | return r; | |
111 | ||
112 | r = sd_bus_creds_get_pid(creds, &pid); | |
4e724d9c | 113 | if (r < 0) |
ebcf1f97 | 114 | return r; |
4e724d9c LP |
115 | } |
116 | ||
c3350683 LP |
117 | r = manager_get_machine_by_pid(m, pid, &machine); |
118 | if (r < 0) | |
ebcf1f97 | 119 | return r; |
c3350683 | 120 | if (!machine) |
ebcf1f97 | 121 | return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID %lu does not belong to any known machine", (unsigned long) pid); |
c3350683 LP |
122 | |
123 | p = machine_bus_path(machine); | |
124 | if (!p) | |
ebcf1f97 | 125 | return -ENOMEM; |
c3350683 | 126 | |
df2d202e | 127 | return sd_bus_reply_method_return(message, "o", p); |
c3350683 LP |
128 | } |
129 | ||
ebcf1f97 | 130 | static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { |
c3350683 LP |
131 | _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; |
132 | Manager *m = userdata; | |
133 | Machine *machine; | |
134 | Iterator i; | |
135 | int r; | |
136 | ||
137 | assert(bus); | |
138 | assert(message); | |
139 | assert(m); | |
140 | ||
df2d202e | 141 | r = sd_bus_message_new_method_return(message, &reply); |
c3350683 | 142 | if (r < 0) |
ebcf1f97 | 143 | return sd_bus_error_set_errno(error, r); |
c3350683 LP |
144 | |
145 | r = sd_bus_message_open_container(reply, 'a', "(ssso)"); | |
146 | if (r < 0) | |
ebcf1f97 | 147 | return sd_bus_error_set_errno(error, r); |
c3350683 LP |
148 | |
149 | HASHMAP_FOREACH(machine, m->machines, i) { | |
150 | _cleanup_free_ char *p = NULL; | |
151 | ||
152 | p = machine_bus_path(machine); | |
153 | if (!p) | |
ebcf1f97 | 154 | return -ENOMEM; |
c3350683 LP |
155 | |
156 | r = sd_bus_message_append(reply, "(ssso)", | |
157 | machine->name, | |
158 | strempty(machine_class_to_string(machine->class)), | |
159 | machine->service, | |
160 | p); | |
161 | if (r < 0) | |
ebcf1f97 | 162 | return sd_bus_error_set_errno(error, r); |
c3350683 | 163 | } |
1ee306e1 | 164 | |
c3350683 LP |
165 | r = sd_bus_message_close_container(reply); |
166 | if (r < 0) | |
ebcf1f97 | 167 | return sd_bus_error_set_errno(error, r); |
c3350683 LP |
168 | |
169 | return sd_bus_send(bus, reply, NULL); | |
170 | } | |
171 | ||
89f7c846 | 172 | static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, Machine **_m, sd_bus_error *error) { |
8aec412f | 173 | const char *name, *service, *class, *root_directory; |
1ee306e1 LP |
174 | MachineClass c; |
175 | uint32_t leader; | |
176 | sd_id128_t id; | |
c3350683 | 177 | const void *v; |
1ee306e1 | 178 | Machine *m; |
c3350683 LP |
179 | size_t n; |
180 | int r; | |
1ee306e1 | 181 | |
c3350683 | 182 | assert(manager); |
89f7c846 LP |
183 | assert(message); |
184 | assert(_m); | |
1ee306e1 | 185 | |
c3350683 LP |
186 | r = sd_bus_message_read(message, "s", &name); |
187 | if (r < 0) | |
ebcf1f97 | 188 | return r; |
c3350683 | 189 | if (!valid_machine_name(name)) |
ebcf1f97 | 190 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name"); |
1ee306e1 | 191 | |
c3350683 LP |
192 | r = sd_bus_message_read_array(message, 'y', &v, &n); |
193 | if (r < 0) | |
ebcf1f97 | 194 | return r; |
1ee306e1 LP |
195 | if (n == 0) |
196 | id = SD_ID128_NULL; | |
197 | else if (n == 16) | |
198 | memcpy(&id, v, n); | |
199 | else | |
ebcf1f97 | 200 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter"); |
1ee306e1 | 201 | |
c3350683 LP |
202 | r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory); |
203 | if (r < 0) | |
ebcf1f97 | 204 | return r; |
1ee306e1 LP |
205 | |
206 | if (isempty(class)) | |
207 | c = _MACHINE_CLASS_INVALID; | |
208 | else { | |
209 | c = machine_class_from_string(class); | |
210 | if (c < 0) | |
ebcf1f97 | 211 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter"); |
1ee306e1 LP |
212 | } |
213 | ||
c3350683 | 214 | if (leader == 1) |
ebcf1f97 | 215 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID"); |
1ee306e1 | 216 | |
c3350683 | 217 | if (!isempty(root_directory) && !path_is_absolute(root_directory)) |
ebcf1f97 | 218 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path"); |
1ee306e1 | 219 | |
c3350683 | 220 | if (leader == 0) { |
5b12334d LP |
221 | _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; |
222 | ||
223 | r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); | |
224 | if (r < 0) | |
225 | return r; | |
226 | ||
c3350683 | 227 | assert_cc(sizeof(uint32_t) == sizeof(pid_t)); |
554604b3 | 228 | |
5b12334d | 229 | r = sd_bus_creds_get_pid(creds, (pid_t*) &leader); |
c3350683 | 230 | if (r < 0) |
ebcf1f97 | 231 | return r; |
c3350683 | 232 | } |
554604b3 | 233 | |
1ee306e1 | 234 | if (hashmap_get(manager->machines, name)) |
ebcf1f97 | 235 | return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name); |
1ee306e1 LP |
236 | |
237 | r = manager_add_machine(manager, name, &m); | |
238 | if (r < 0) | |
ebcf1f97 | 239 | return r; |
1ee306e1 LP |
240 | |
241 | m->leader = leader; | |
242 | m->class = c; | |
243 | m->id = id; | |
244 | ||
245 | if (!isempty(service)) { | |
246 | m->service = strdup(service); | |
247 | if (!m->service) { | |
ebcf1f97 | 248 | r = -ENOMEM; |
1ee306e1 LP |
249 | goto fail; |
250 | } | |
251 | } | |
252 | ||
253 | if (!isempty(root_directory)) { | |
254 | m->root_directory = strdup(root_directory); | |
255 | if (!m->root_directory) { | |
ebcf1f97 | 256 | r = -ENOMEM; |
1ee306e1 LP |
257 | goto fail; |
258 | } | |
259 | } | |
260 | ||
89f7c846 LP |
261 | *_m = m; |
262 | ||
263 | return 1; | |
264 | ||
265 | fail: | |
266 | machine_add_to_gc_queue(m); | |
267 | return r; | |
268 | } | |
269 | ||
270 | static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { | |
271 | Manager *manager = userdata; | |
272 | Machine *m = NULL; | |
273 | int r; | |
274 | ||
275 | r = method_create_or_register_machine(manager, message, &m, error); | |
276 | if (r < 0) | |
277 | return r; | |
278 | ||
279 | r = sd_bus_message_enter_container(message, 'a', "(sv)"); | |
280 | if (r < 0) | |
281 | goto fail; | |
282 | ||
ebcf1f97 LP |
283 | r = machine_start(m, message, error); |
284 | if (r < 0) | |
1ee306e1 LP |
285 | goto fail; |
286 | ||
c3350683 | 287 | m->create_message = sd_bus_message_ref(message); |
c3350683 | 288 | return 1; |
1ee306e1 LP |
289 | |
290 | fail: | |
a3e7f417 | 291 | machine_add_to_gc_queue(m); |
89f7c846 LP |
292 | return r; |
293 | } | |
1ee306e1 | 294 | |
89f7c846 LP |
295 | static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { |
296 | Manager *manager = userdata; | |
297 | _cleanup_free_ char *p = NULL; | |
298 | Machine *m = NULL; | |
299 | int r; | |
300 | ||
301 | r = method_create_or_register_machine(manager, message, &m, error); | |
302 | if (r < 0) | |
303 | return r; | |
304 | ||
305 | r = cg_pid_get_unit(m->leader, &m->unit); | |
306 | if (r < 0) { | |
307 | r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r)); | |
308 | goto fail; | |
309 | } | |
310 | ||
311 | r = machine_start(m, NULL, error); | |
312 | if (r < 0) | |
313 | goto fail; | |
314 | ||
315 | p = machine_bus_path(m); | |
316 | if (!p) { | |
317 | r = -ENOMEM; | |
318 | goto fail; | |
319 | } | |
320 | ||
321 | return sd_bus_reply_method_return(message, "o", p); | |
322 | ||
323 | fail: | |
324 | machine_add_to_gc_queue(m); | |
1ee306e1 LP |
325 | return r; |
326 | } | |
327 | ||
ebcf1f97 | 328 | static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { |
1ee306e1 | 329 | Manager *m = userdata; |
c3350683 LP |
330 | Machine *machine; |
331 | const char *name; | |
1ee306e1 LP |
332 | int r; |
333 | ||
c3350683 | 334 | assert(bus); |
1ee306e1 LP |
335 | assert(message); |
336 | assert(m); | |
337 | ||
c3350683 LP |
338 | r = sd_bus_message_read(message, "s", &name); |
339 | if (r < 0) | |
ebcf1f97 | 340 | return sd_bus_error_set_errno(error, r); |
1ee306e1 | 341 | |
c3350683 LP |
342 | machine = hashmap_get(m->machines, name); |
343 | if (!machine) | |
ebcf1f97 | 344 | return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name); |
1ee306e1 | 345 | |
c3350683 LP |
346 | r = machine_stop(machine); |
347 | if (r < 0) | |
ebcf1f97 | 348 | return sd_bus_error_set_errno(error, r); |
1ee306e1 | 349 | |
df2d202e | 350 | return sd_bus_reply_method_return(message, NULL); |
c3350683 | 351 | } |
1ee306e1 | 352 | |
ebcf1f97 | 353 | static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { |
c3350683 LP |
354 | Manager *m = userdata; |
355 | Machine *machine; | |
356 | const char *name; | |
357 | const char *swho; | |
358 | int32_t signo; | |
359 | KillWho who; | |
360 | int r; | |
1ee306e1 | 361 | |
c3350683 LP |
362 | assert(bus); |
363 | assert(message); | |
364 | assert(m); | |
1ee306e1 | 365 | |
c3350683 LP |
366 | r = sd_bus_message_read(message, "ssi", &name, &swho, &signo); |
367 | if (r < 0) | |
ebcf1f97 | 368 | return sd_bus_error_set_errno(error, r); |
1ee306e1 | 369 | |
c3350683 LP |
370 | if (isempty(swho)) |
371 | who = KILL_ALL; | |
372 | else { | |
373 | who = kill_who_from_string(swho); | |
374 | if (who < 0) | |
ebcf1f97 | 375 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho); |
c3350683 | 376 | } |
1ee306e1 | 377 | |
c3350683 | 378 | if (signo <= 0 || signo >= _NSIG) |
ebcf1f97 | 379 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo); |
1ee306e1 | 380 | |
c3350683 LP |
381 | machine = hashmap_get(m->machines, name); |
382 | if (!machine) | |
ebcf1f97 | 383 | return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name); |
1ee306e1 | 384 | |
c3350683 LP |
385 | r = machine_kill(machine, who, signo); |
386 | if (r < 0) | |
ebcf1f97 | 387 | return sd_bus_error_set_errno(error, r); |
1ee306e1 | 388 | |
df2d202e | 389 | return sd_bus_reply_method_return(message, NULL); |
c3350683 | 390 | } |
1ee306e1 | 391 | |
c3350683 LP |
392 | const sd_bus_vtable manager_vtable[] = { |
393 | SD_BUS_VTABLE_START(0), | |
adacb957 LP |
394 | SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED), |
395 | SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED), | |
396 | SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED), | |
c3350683 | 397 | SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0), |
89f7c846 | 398 | SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0), |
adacb957 LP |
399 | SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), |
400 | SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), | |
c3350683 LP |
401 | SD_BUS_SIGNAL("MachineNew", "so", 0), |
402 | SD_BUS_SIGNAL("MachineRemoved", "so", 0), | |
403 | SD_BUS_VTABLE_END | |
404 | }; | |
1ee306e1 | 405 | |
ebcf1f97 | 406 | int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { |
c3350683 | 407 | const char *path, *result, *unit; |
1ee306e1 | 408 | Manager *m = userdata; |
c3350683 LP |
409 | Machine *machine; |
410 | uint32_t id; | |
411 | int r; | |
1ee306e1 | 412 | |
c3350683 | 413 | assert(bus); |
1ee306e1 | 414 | assert(message); |
c3350683 | 415 | assert(m); |
1ee306e1 | 416 | |
c3350683 LP |
417 | r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result); |
418 | if (r < 0) { | |
ebcf1f97 LP |
419 | bus_log_parse_error(r); |
420 | return r; | |
c3350683 | 421 | } |
6797c324 | 422 | |
c3350683 LP |
423 | machine = hashmap_get(m->machine_units, unit); |
424 | if (!machine) | |
425 | return 0; | |
6797c324 | 426 | |
c3350683 LP |
427 | if (streq_ptr(path, machine->scope_job)) { |
428 | free(machine->scope_job); | |
429 | machine->scope_job = NULL; | |
6797c324 | 430 | |
c3350683 LP |
431 | if (machine->started) { |
432 | if (streq(result, "done")) | |
433 | machine_send_create_reply(machine, NULL); | |
434 | else { | |
ebcf1f97 | 435 | _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL; |
6797c324 | 436 | |
ebcf1f97 | 437 | sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result); |
6797c324 | 438 | |
ebcf1f97 | 439 | machine_send_create_reply(machine, &e); |
c3350683 LP |
440 | } |
441 | } else | |
442 | machine_save(machine); | |
1ee306e1 LP |
443 | } |
444 | ||
c3350683 LP |
445 | machine_add_to_gc_queue(machine); |
446 | return 0; | |
1ee306e1 LP |
447 | } |
448 | ||
ebcf1f97 | 449 | int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { |
c3350683 LP |
450 | _cleanup_free_ char *unit = NULL; |
451 | Manager *m = userdata; | |
452 | Machine *machine; | |
453 | const char *path; | |
ebcf1f97 | 454 | int r; |
554604b3 | 455 | |
c3350683 LP |
456 | assert(bus); |
457 | assert(message); | |
458 | assert(m); | |
554604b3 | 459 | |
c3350683 LP |
460 | path = sd_bus_message_get_path(message); |
461 | if (!path) | |
554604b3 | 462 | return 0; |
554604b3 | 463 | |
ebcf1f97 LP |
464 | r = unit_name_from_dbus_path(path, &unit); |
465 | if (r < 0) | |
466 | return r; | |
554604b3 | 467 | |
c3350683 LP |
468 | machine = hashmap_get(m->machine_units, unit); |
469 | if (machine) | |
470 | machine_add_to_gc_queue(machine); | |
554604b3 | 471 | |
c3350683 LP |
472 | return 0; |
473 | } | |
554604b3 | 474 | |
ebcf1f97 | 475 | int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { |
c3350683 LP |
476 | const char *path, *unit; |
477 | Manager *m = userdata; | |
478 | Machine *machine; | |
479 | int r; | |
554604b3 | 480 | |
c3350683 LP |
481 | assert(bus); |
482 | assert(message); | |
483 | assert(m); | |
554604b3 | 484 | |
c3350683 LP |
485 | r = sd_bus_message_read(message, "so", &unit, &path); |
486 | if (r < 0) { | |
ebcf1f97 LP |
487 | bus_log_parse_error(r); |
488 | return r; | |
554604b3 LP |
489 | } |
490 | ||
c3350683 LP |
491 | machine = hashmap_get(m->machine_units, unit); |
492 | if (machine) | |
493 | machine_add_to_gc_queue(machine); | |
554604b3 | 494 | |
c3350683 LP |
495 | return 0; |
496 | } | |
554604b3 | 497 | |
ebcf1f97 | 498 | int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { |
c3350683 | 499 | Manager *m = userdata; |
a658cafa LP |
500 | Machine *machine; |
501 | Iterator i; | |
c3350683 | 502 | int b, r; |
554604b3 | 503 | |
c3350683 | 504 | assert(bus); |
554604b3 | 505 | |
c3350683 LP |
506 | r = sd_bus_message_read(message, "b", &b); |
507 | if (r < 0) { | |
ebcf1f97 LP |
508 | bus_log_parse_error(r); |
509 | return r; | |
554604b3 | 510 | } |
a658cafa LP |
511 | if (b) |
512 | return 0; | |
554604b3 | 513 | |
a658cafa LP |
514 | /* systemd finished reloading, let's recheck all our machines */ |
515 | log_debug("System manager has been reloaded, rechecking machines..."); | |
554604b3 | 516 | |
a658cafa LP |
517 | HASHMAP_FOREACH(machine, m->machines, i) |
518 | machine_add_to_gc_queue(machine); | |
554604b3 LP |
519 | |
520 | return 0; | |
521 | } | |
522 | ||
1ee306e1 LP |
523 | int manager_start_scope( |
524 | Manager *manager, | |
525 | const char *scope, | |
526 | pid_t pid, | |
527 | const char *slice, | |
528 | const char *description, | |
c3350683 LP |
529 | sd_bus_message *more_properties, |
530 | sd_bus_error *error, | |
1ee306e1 LP |
531 | char **job) { |
532 | ||
c3350683 | 533 | _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; |
554604b3 | 534 | int r; |
1ee306e1 LP |
535 | |
536 | assert(manager); | |
537 | assert(scope); | |
538 | assert(pid > 1); | |
539 | ||
c3350683 LP |
540 | r = sd_bus_message_new_method_call( |
541 | manager->bus, | |
151b9b96 | 542 | &m, |
1ee306e1 LP |
543 | "org.freedesktop.systemd1", |
544 | "/org/freedesktop/systemd1", | |
545 | "org.freedesktop.systemd1.Manager", | |
151b9b96 | 546 | "StartTransientUnit"); |
c3350683 LP |
547 | if (r < 0) |
548 | return r; | |
1ee306e1 | 549 | |
a658cafa | 550 | r = sd_bus_message_append(m, "ss", strempty(scope), "fail"); |
c3350683 LP |
551 | if (r < 0) |
552 | return r; | |
1ee306e1 | 553 | |
c3350683 LP |
554 | r = sd_bus_message_open_container(m, 'a', "(sv)"); |
555 | if (r < 0) | |
556 | return r; | |
1ee306e1 LP |
557 | |
558 | if (!isempty(slice)) { | |
c3350683 LP |
559 | r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice); |
560 | if (r < 0) | |
561 | return r; | |
1ee306e1 LP |
562 | } |
563 | ||
564 | if (!isempty(description)) { | |
c3350683 LP |
565 | r = sd_bus_message_append(m, "(sv)", "Description", "s", description); |
566 | if (r < 0) | |
567 | return r; | |
1ee306e1 LP |
568 | } |
569 | ||
c3350683 LP |
570 | r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid); |
571 | if (r < 0) | |
572 | return r; | |
554604b3 LP |
573 | |
574 | if (more_properties) { | |
c3350683 | 575 | r = sd_bus_message_copy(m, more_properties, true); |
554604b3 LP |
576 | if (r < 0) |
577 | return r; | |
578 | } | |
579 | ||
c3350683 LP |
580 | r = sd_bus_message_close_container(m); |
581 | if (r < 0) | |
582 | return r; | |
1ee306e1 | 583 | |
86b8d289 LP |
584 | r = sd_bus_message_append(m, "a(sa(sv))", 0); |
585 | if (r < 0) | |
586 | return r; | |
587 | ||
c49b30a2 | 588 | r = sd_bus_call(manager->bus, m, 0, error, &reply); |
c3350683 LP |
589 | if (r < 0) |
590 | return r; | |
1ee306e1 LP |
591 | |
592 | if (job) { | |
593 | const char *j; | |
594 | char *copy; | |
595 | ||
c3350683 LP |
596 | r = sd_bus_message_read(reply, "o", &j); |
597 | if (r < 0) | |
598 | return r; | |
1ee306e1 LP |
599 | |
600 | copy = strdup(j); | |
601 | if (!copy) | |
602 | return -ENOMEM; | |
603 | ||
604 | *job = copy; | |
605 | } | |
606 | ||
c3350683 | 607 | return 1; |
1ee306e1 LP |
608 | } |
609 | ||
c3350683 LP |
610 | int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) { |
611 | _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; | |
1ee306e1 LP |
612 | int r; |
613 | ||
614 | assert(manager); | |
615 | assert(unit); | |
616 | ||
c3350683 | 617 | r = sd_bus_call_method( |
1ee306e1 LP |
618 | manager->bus, |
619 | "org.freedesktop.systemd1", | |
620 | "/org/freedesktop/systemd1", | |
621 | "org.freedesktop.systemd1.Manager", | |
622 | "StopUnit", | |
1ee306e1 | 623 | error, |
c3350683 LP |
624 | &reply, |
625 | "ss", unit, "fail"); | |
1ee306e1 | 626 | if (r < 0) { |
c3350683 LP |
627 | if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) || |
628 | sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) { | |
6797c324 LP |
629 | |
630 | if (job) | |
631 | *job = NULL; | |
632 | ||
c3350683 | 633 | sd_bus_error_free(error); |
6797c324 LP |
634 | return 0; |
635 | } | |
636 | ||
1ee306e1 LP |
637 | return r; |
638 | } | |
639 | ||
640 | if (job) { | |
641 | const char *j; | |
642 | char *copy; | |
643 | ||
c3350683 LP |
644 | r = sd_bus_message_read(reply, "o", &j); |
645 | if (r < 0) | |
646 | return r; | |
1ee306e1 LP |
647 | |
648 | copy = strdup(j); | |
649 | if (!copy) | |
650 | return -ENOMEM; | |
651 | ||
652 | *job = copy; | |
653 | } | |
654 | ||
6797c324 | 655 | return 1; |
1ee306e1 LP |
656 | } |
657 | ||
de58a50e | 658 | int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) { |
1ee306e1 LP |
659 | assert(manager); |
660 | assert(unit); | |
661 | ||
a658cafa | 662 | return sd_bus_call_method( |
1ee306e1 LP |
663 | manager->bus, |
664 | "org.freedesktop.systemd1", | |
665 | "/org/freedesktop/systemd1", | |
666 | "org.freedesktop.systemd1.Manager", | |
667 | "KillUnit", | |
1ee306e1 | 668 | error, |
a658cafa | 669 | NULL, |
de58a50e | 670 | "ssi", unit, "all", signo); |
1ee306e1 LP |
671 | } |
672 | ||
673 | int manager_unit_is_active(Manager *manager, const char *unit) { | |
c3350683 LP |
674 | _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; |
675 | _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; | |
1ee306e1 | 676 | _cleanup_free_ char *path = NULL; |
1ee306e1 | 677 | const char *state; |
1ee306e1 LP |
678 | int r; |
679 | ||
680 | assert(manager); | |
681 | assert(unit); | |
682 | ||
1ee306e1 LP |
683 | path = unit_dbus_path_from_name(unit); |
684 | if (!path) | |
685 | return -ENOMEM; | |
686 | ||
c3350683 | 687 | r = sd_bus_get_property( |
1ee306e1 LP |
688 | manager->bus, |
689 | "org.freedesktop.systemd1", | |
690 | path, | |
c3350683 LP |
691 | "org.freedesktop.systemd1.Unit", |
692 | "ActiveState", | |
1ee306e1 | 693 | &error, |
c3350683 LP |
694 | &reply, |
695 | "s"); | |
1ee306e1 | 696 | if (r < 0) { |
c3350683 LP |
697 | if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) || |
698 | sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED)) | |
6797c324 | 699 | return true; |
6797c324 | 700 | |
c3350683 LP |
701 | if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) || |
702 | sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED)) | |
6797c324 | 703 | return false; |
6797c324 | 704 | |
1ee306e1 LP |
705 | return r; |
706 | } | |
707 | ||
c3350683 LP |
708 | r = sd_bus_message_read(reply, "s", &state); |
709 | if (r < 0) | |
1ee306e1 | 710 | return -EINVAL; |
1ee306e1 LP |
711 | |
712 | return !streq(state, "inactive") && !streq(state, "failed"); | |
713 | } | |
bd16acf3 | 714 | |
c3350683 LP |
715 | int manager_job_is_active(Manager *manager, const char *path) { |
716 | _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; | |
717 | _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; | |
718 | int r; | |
bd16acf3 | 719 | |
c3350683 LP |
720 | assert(manager); |
721 | assert(path); | |
bd16acf3 | 722 | |
c3350683 LP |
723 | r = sd_bus_get_property( |
724 | manager->bus, | |
725 | "org.freedesktop.systemd1", | |
726 | path, | |
727 | "org.freedesktop.systemd1.Job", | |
728 | "State", | |
729 | &error, | |
730 | &reply, | |
731 | "s"); | |
732 | if (r < 0) { | |
733 | if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) || | |
734 | sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED)) | |
735 | return true; | |
bd16acf3 | 736 | |
c3350683 LP |
737 | if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT)) |
738 | return false; | |
bd16acf3 | 739 | |
bd16acf3 | 740 | return r; |
c3350683 | 741 | } |
bd16acf3 | 742 | |
c3350683 LP |
743 | /* We don't actually care about the state really. The fact |
744 | * that we could read the job state is enough for us */ | |
bd16acf3 | 745 | |
c3350683 | 746 | return true; |
bd16acf3 | 747 | } |
ab49725f KS |
748 | |
749 | int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) { | |
750 | _cleanup_free_ char *unit = NULL; | |
751 | Machine *mm; | |
752 | int r; | |
753 | ||
754 | assert(m); | |
755 | assert(pid >= 1); | |
756 | assert(machine); | |
757 | ||
758 | r = cg_pid_get_unit(pid, &unit); | |
759 | if (r < 0) | |
760 | mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid)); | |
761 | else | |
762 | mm = hashmap_get(m->machine_units, unit); | |
763 | ||
764 | if (!mm) | |
765 | return 0; | |
766 | ||
767 | *machine = mm; | |
768 | return 1; | |
769 | } | |
770 | ||
771 | int manager_add_machine(Manager *m, const char *name, Machine **_machine) { | |
772 | Machine *machine; | |
773 | ||
774 | assert(m); | |
775 | assert(name); | |
776 | ||
777 | machine = hashmap_get(m->machines, name); | |
778 | if (!machine) { | |
779 | machine = machine_new(m, name); | |
780 | if (!machine) | |
781 | return -ENOMEM; | |
782 | } | |
783 | ||
784 | if (_machine) | |
785 | *_machine = machine; | |
786 | ||
787 | return 0; | |
788 | } |