]>
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 2013 Lennart Poettering | |
7 | ||
8 | systemd is free software; you can redistribute it and/or modify it | |
9 | under the terms of the GNU Lesser General Public License as published by | |
10 | the Free Software Foundation; either version 2.1 of the License, or | |
11 | (at your option) any later version. | |
12 | ||
13 | systemd is distributed in the hope that it will be useful, but | |
14 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | Lesser General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU Lesser General Public License | |
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
20 | ***/ | |
21 | ||
3f6fd1ba | 22 | #include <arpa/inet.h> |
1ee306e1 | 23 | #include <errno.h> |
3f6fd1ba | 24 | #include <fcntl.h> |
1ee306e1 | 25 | #include <getopt.h> |
1ee306e1 | 26 | #include <locale.h> |
f48e75cb | 27 | #include <net/if.h> |
3f6fd1ba LP |
28 | #include <netinet/in.h> |
29 | #include <string.h> | |
785890ac | 30 | #include <sys/mount.h> |
3f6fd1ba LP |
31 | #include <sys/socket.h> |
32 | #include <unistd.h> | |
eef46c37 | 33 | |
a1da8583 | 34 | #include "sd-bus.h" |
3f6fd1ba | 35 | |
b5efdb8a | 36 | #include "alloc-util.h" |
a1da8583 | 37 | #include "bus-error.h" |
3f6fd1ba | 38 | #include "bus-util.h" |
1ee306e1 | 39 | #include "cgroup-show.h" |
9d127096 | 40 | #include "cgroup-util.h" |
f2cbe59e | 41 | #include "copy.h" |
3f6fd1ba | 42 | #include "env-util.h" |
3ffd4af2 | 43 | #include "fd-util.h" |
3f6fd1ba | 44 | #include "hostname-util.h" |
3d7415f4 | 45 | #include "import-util.h" |
3f6fd1ba LP |
46 | #include "log.h" |
47 | #include "logs-show.h" | |
48 | #include "macro.h" | |
49 | #include "mkdir.h" | |
50 | #include "pager.h" | |
6bedfcbb | 51 | #include "parse-util.h" |
3f6fd1ba | 52 | #include "path-util.h" |
0b452006 | 53 | #include "process-util.h" |
3f6fd1ba | 54 | #include "ptyfwd.h" |
24882e06 | 55 | #include "signal-util.h" |
3f6fd1ba LP |
56 | #include "spawn-polkit-agent.h" |
57 | #include "strv.h" | |
58 | #include "terminal-util.h" | |
59 | #include "unit-name.h" | |
60 | #include "util.h" | |
61 | #include "verbs.h" | |
49cf4170 | 62 | #include "web-util.h" |
1ee306e1 LP |
63 | |
64 | static char **arg_property = NULL; | |
65 | static bool arg_all = false; | |
66 | static bool arg_full = false; | |
67 | static bool arg_no_pager = false; | |
e56056e9 | 68 | static bool arg_legend = true; |
1ee306e1 LP |
69 | static const char *arg_kill_who = NULL; |
70 | static int arg_signal = SIGTERM; | |
d21ed1ea | 71 | static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; |
1ee306e1 | 72 | static char *arg_host = NULL; |
785890ac LP |
73 | static bool arg_read_only = false; |
74 | static bool arg_mkdir = false; | |
d8f52ed2 | 75 | static bool arg_quiet = false; |
acf97e21 | 76 | static bool arg_ask_password = true; |
8b0cc9a3 LP |
77 | static unsigned arg_lines = 10; |
78 | static OutputMode arg_output = OUTPUT_SHORT; | |
3d7415f4 | 79 | static bool arg_force = false; |
6e18cc9f | 80 | static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE; |
587fec42 | 81 | static const char* arg_format = NULL; |
c454426c LP |
82 | static const char *arg_uid = NULL; |
83 | static char **arg_setenv = NULL; | |
1ee306e1 LP |
84 | |
85 | static void pager_open_if_enabled(void) { | |
86 | ||
1ee306e1 LP |
87 | if (arg_no_pager) |
88 | return; | |
89 | ||
90 | pager_open(false); | |
91 | } | |
92 | ||
acf97e21 LP |
93 | static void polkit_agent_open_if_enabled(void) { |
94 | ||
95 | /* Open the polkit agent as a child process if necessary */ | |
96 | ||
97 | if (!arg_ask_password) | |
98 | return; | |
99 | ||
100 | if (arg_transport != BUS_TRANSPORT_LOCAL) | |
101 | return; | |
102 | ||
103 | polkit_agent_open(); | |
104 | } | |
105 | ||
8b0cc9a3 LP |
106 | static OutputFlags get_output_flags(void) { |
107 | return | |
108 | arg_all * OUTPUT_SHOW_ALL | | |
109 | arg_full * OUTPUT_FULL_WIDTH | | |
110 | (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH | | |
111 | on_tty() * OUTPUT_COLOR | | |
112 | !arg_quiet * OUTPUT_WARN_CUTOFF; | |
113 | } | |
114 | ||
0b63e278 LP |
115 | typedef struct MachineInfo { |
116 | const char *name; | |
117 | const char *class; | |
118 | const char *service; | |
119 | } MachineInfo; | |
120 | ||
121 | static int compare_machine_info(const void *a, const void *b) { | |
122 | const MachineInfo *x = a, *y = b; | |
123 | ||
124 | return strcmp(x->name, y->name); | |
125 | } | |
126 | ||
56159e0d LP |
127 | static int list_machines(int argc, char *argv[], void *userdata) { |
128 | ||
0b63e278 | 129 | size_t max_name = strlen("MACHINE"), max_class = strlen("CLASS"), max_service = strlen("SERVICE"); |
4afd3348 LP |
130 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
131 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; | |
0b63e278 | 132 | _cleanup_free_ MachineInfo *machines = NULL; |
a1da8583 | 133 | const char *name, *class, *service, *object; |
0b63e278 | 134 | size_t n_machines = 0, n_allocated = 0, j; |
56159e0d | 135 | sd_bus *bus = userdata; |
1ee306e1 LP |
136 | int r; |
137 | ||
56159e0d LP |
138 | assert(bus); |
139 | ||
1ee306e1 LP |
140 | pager_open_if_enabled(); |
141 | ||
a1da8583 TG |
142 | r = sd_bus_call_method( |
143 | bus, | |
144 | "org.freedesktop.machine1", | |
145 | "/org/freedesktop/machine1", | |
146 | "org.freedesktop.machine1.Manager", | |
147 | "ListMachines", | |
148 | &error, | |
149 | &reply, | |
3d7415f4 | 150 | NULL); |
a1da8583 TG |
151 | if (r < 0) { |
152 | log_error("Could not get machines: %s", bus_error_message(&error, -r)); | |
1ee306e1 | 153 | return r; |
1ee306e1 LP |
154 | } |
155 | ||
3d7415f4 | 156 | r = sd_bus_message_enter_container(reply, 'a', "(ssso)"); |
a1da8583 | 157 | if (r < 0) |
5b30bef8 | 158 | return bus_log_parse_error(r); |
1ee306e1 | 159 | |
a1da8583 | 160 | while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) { |
0b63e278 LP |
161 | size_t l; |
162 | ||
fee6d013 LP |
163 | if (name[0] == '.' && !arg_all) |
164 | continue; | |
165 | ||
0b63e278 LP |
166 | if (!GREEDY_REALLOC(machines, n_allocated, n_machines + 1)) |
167 | return log_oom(); | |
1ee306e1 | 168 | |
0b63e278 LP |
169 | machines[n_machines].name = name; |
170 | machines[n_machines].class = class; | |
171 | machines[n_machines].service = service; | |
172 | ||
173 | l = strlen(name); | |
174 | if (l > max_name) | |
175 | max_name = l; | |
176 | ||
177 | l = strlen(class); | |
178 | if (l > max_class) | |
179 | max_class = l; | |
180 | ||
181 | l = strlen(service); | |
182 | if (l > max_service) | |
183 | max_service = l; | |
184 | ||
185 | n_machines ++; | |
1ee306e1 | 186 | } |
a1da8583 | 187 | if (r < 0) |
5b30bef8 | 188 | return bus_log_parse_error(r); |
a1da8583 TG |
189 | |
190 | r = sd_bus_message_exit_container(reply); | |
191 | if (r < 0) | |
5b30bef8 | 192 | return bus_log_parse_error(r); |
1ee306e1 | 193 | |
0b63e278 LP |
194 | qsort_safe(machines, n_machines, sizeof(MachineInfo), compare_machine_info); |
195 | ||
196 | if (arg_legend) | |
197 | printf("%-*s %-*s %-*s\n", | |
198 | (int) max_name, "MACHINE", | |
199 | (int) max_class, "CLASS", | |
200 | (int) max_service, "SERVICE"); | |
201 | ||
202 | for (j = 0; j < n_machines; j++) | |
203 | printf("%-*s %-*s %-*s\n", | |
204 | (int) max_name, machines[j].name, | |
205 | (int) max_class, machines[j].class, | |
206 | (int) max_service, machines[j].service); | |
207 | ||
e56056e9 | 208 | if (arg_legend) |
0b63e278 | 209 | printf("\n%zu machines listed.\n", n_machines); |
1ee306e1 LP |
210 | |
211 | return 0; | |
212 | } | |
213 | ||
cd61c3bf LP |
214 | typedef struct ImageInfo { |
215 | const char *name; | |
216 | const char *type; | |
217 | bool read_only; | |
10f9c755 LP |
218 | usec_t crtime; |
219 | usec_t mtime; | |
b6b18498 | 220 | uint64_t size; |
cd61c3bf LP |
221 | } ImageInfo; |
222 | ||
223 | static int compare_image_info(const void *a, const void *b) { | |
224 | const ImageInfo *x = a, *y = b; | |
225 | ||
226 | return strcmp(x->name, y->name); | |
227 | } | |
228 | ||
56159e0d | 229 | static int list_images(int argc, char *argv[], void *userdata) { |
cd61c3bf | 230 | |
4afd3348 | 231 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
c19de711 | 232 | size_t max_name = strlen("NAME"), max_type = strlen("TYPE"), max_size = strlen("USAGE"), max_crtime = strlen("CREATED"), max_mtime = strlen("MODIFIED"); |
4afd3348 | 233 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; |
cd61c3bf LP |
234 | _cleanup_free_ ImageInfo *images = NULL; |
235 | size_t n_images = 0, n_allocated = 0, j; | |
236 | const char *name, *type, *object; | |
56159e0d | 237 | sd_bus *bus = userdata; |
b6b18498 | 238 | uint64_t crtime, mtime, size; |
10f9c755 | 239 | int read_only, r; |
cd61c3bf | 240 | |
56159e0d LP |
241 | assert(bus); |
242 | ||
cd61c3bf LP |
243 | pager_open_if_enabled(); |
244 | ||
245 | r = sd_bus_call_method( | |
246 | bus, | |
247 | "org.freedesktop.machine1", | |
248 | "/org/freedesktop/machine1", | |
249 | "org.freedesktop.machine1.Manager", | |
250 | "ListImages", | |
251 | &error, | |
252 | &reply, | |
253 | ""); | |
254 | if (r < 0) { | |
255 | log_error("Could not get images: %s", bus_error_message(&error, -r)); | |
256 | return r; | |
257 | } | |
258 | ||
b6b18498 | 259 | r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssbttto)"); |
cd61c3bf LP |
260 | if (r < 0) |
261 | return bus_log_parse_error(r); | |
262 | ||
b6b18498 LP |
263 | while ((r = sd_bus_message_read(reply, "(ssbttto)", &name, &type, &read_only, &crtime, &mtime, &size, &object)) > 0) { |
264 | char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_BYTES_MAX)]; | |
10f9c755 | 265 | size_t l; |
cd61c3bf LP |
266 | |
267 | if (name[0] == '.' && !arg_all) | |
268 | continue; | |
269 | ||
270 | if (!GREEDY_REALLOC(images, n_allocated, n_images + 1)) | |
271 | return log_oom(); | |
272 | ||
273 | images[n_images].name = name; | |
274 | images[n_images].type = type; | |
275 | images[n_images].read_only = read_only; | |
10f9c755 LP |
276 | images[n_images].crtime = crtime; |
277 | images[n_images].mtime = mtime; | |
b6b18498 | 278 | images[n_images].size = size; |
10f9c755 LP |
279 | |
280 | l = strlen(name); | |
281 | if (l > max_name) | |
282 | max_name = l; | |
cd61c3bf | 283 | |
10f9c755 LP |
284 | l = strlen(type); |
285 | if (l > max_type) | |
286 | max_type = l; | |
cd61c3bf | 287 | |
10f9c755 | 288 | if (crtime != 0) { |
b6b18498 | 289 | l = strlen(strna(format_timestamp(buf, sizeof(buf), crtime))); |
10f9c755 LP |
290 | if (l > max_crtime) |
291 | max_crtime = l; | |
292 | } | |
293 | ||
294 | if (mtime != 0) { | |
b6b18498 | 295 | l = strlen(strna(format_timestamp(buf, sizeof(buf), mtime))); |
10f9c755 LP |
296 | if (l > max_mtime) |
297 | max_mtime = l; | |
298 | } | |
cd61c3bf | 299 | |
b6b18498 LP |
300 | if (size != (uint64_t) -1) { |
301 | l = strlen(strna(format_bytes(buf, sizeof(buf), size))); | |
302 | if (l > max_size) | |
303 | max_size = l; | |
304 | } | |
305 | ||
cd61c3bf LP |
306 | n_images++; |
307 | } | |
308 | if (r < 0) | |
309 | return bus_log_parse_error(r); | |
310 | ||
311 | r = sd_bus_message_exit_container(reply); | |
312 | if (r < 0) | |
313 | return bus_log_parse_error(r); | |
314 | ||
315 | qsort_safe(images, n_images, sizeof(ImageInfo), compare_image_info); | |
316 | ||
317 | if (arg_legend) | |
b6b18498 | 318 | printf("%-*s %-*s %-3s %-*s %-*s %-*s\n", |
10f9c755 LP |
319 | (int) max_name, "NAME", |
320 | (int) max_type, "TYPE", | |
321 | "RO", | |
c19de711 | 322 | (int) max_size, "USAGE", |
10f9c755 LP |
323 | (int) max_crtime, "CREATED", |
324 | (int) max_mtime, "MODIFIED"); | |
cd61c3bf LP |
325 | |
326 | for (j = 0; j < n_images; j++) { | |
b6b18498 | 327 | char crtime_buf[FORMAT_TIMESTAMP_MAX], mtime_buf[FORMAT_TIMESTAMP_MAX], size_buf[FORMAT_BYTES_MAX]; |
10f9c755 | 328 | |
b6b18498 | 329 | printf("%-*s %-*s %s%-3s%s %-*s %-*s %-*s\n", |
cd61c3bf LP |
330 | (int) max_name, images[j].name, |
331 | (int) max_type, images[j].type, | |
1fc464f6 | 332 | images[j].read_only ? ansi_highlight_red() : "", yes_no(images[j].read_only), images[j].read_only ? ansi_normal() : "", |
b6b18498 LP |
333 | (int) max_size, strna(format_bytes(size_buf, sizeof(size_buf), images[j].size)), |
334 | (int) max_crtime, strna(format_timestamp(crtime_buf, sizeof(crtime_buf), images[j].crtime)), | |
335 | (int) max_mtime, strna(format_timestamp(mtime_buf, sizeof(mtime_buf), images[j].mtime))); | |
cd61c3bf LP |
336 | } |
337 | ||
cd61c3bf LP |
338 | if (arg_legend) |
339 | printf("\n%zu images listed.\n", n_images); | |
340 | ||
341 | return 0; | |
342 | } | |
343 | ||
89f7c846 | 344 | static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) { |
4afd3348 LP |
345 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; |
346 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; | |
aa1936ea | 347 | _cleanup_free_ char *path = NULL; |
aa1936ea | 348 | const char *cgroup; |
8b0cc9a3 | 349 | int r; |
aa1936ea LP |
350 | unsigned c; |
351 | ||
352 | assert(bus); | |
353 | assert(unit); | |
354 | ||
d21ed1ea | 355 | if (arg_transport == BUS_TRANSPORT_REMOTE) |
aa1936ea LP |
356 | return 0; |
357 | ||
358 | path = unit_dbus_path_from_name(unit); | |
359 | if (!path) | |
360 | return log_oom(); | |
361 | ||
a7893c6b | 362 | r = sd_bus_get_property( |
aa1936ea LP |
363 | bus, |
364 | "org.freedesktop.systemd1", | |
365 | path, | |
21b735e7 | 366 | unit_dbus_interface_from_name(unit), |
a7893c6b | 367 | "ControlGroup", |
aa1936ea | 368 | &error, |
a1da8583 | 369 | &reply, |
a7893c6b | 370 | "s"); |
aa1936ea | 371 | if (r < 0) { |
a1da8583 | 372 | log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r)); |
aa1936ea LP |
373 | return r; |
374 | } | |
375 | ||
a7893c6b | 376 | r = sd_bus_message_read(reply, "s", &cgroup); |
5b30bef8 LP |
377 | if (r < 0) |
378 | return bus_log_parse_error(r); | |
aa1936ea | 379 | |
6f883237 | 380 | if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0) |
9d127096 LP |
381 | return 0; |
382 | ||
aa1936ea LP |
383 | c = columns(); |
384 | if (c > 18) | |
385 | c -= 18; | |
386 | else | |
387 | c = 0; | |
388 | ||
8b0cc9a3 | 389 | show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags()); |
aa1936ea LP |
390 | return 0; |
391 | } | |
392 | ||
f48e75cb | 393 | static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2) { |
4afd3348 | 394 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; |
878cd7e9 LP |
395 | int r; |
396 | ||
397 | assert(bus); | |
398 | assert(name); | |
399 | assert(prefix); | |
400 | assert(prefix2); | |
401 | ||
402 | r = sd_bus_call_method(bus, | |
403 | "org.freedesktop.machine1", | |
404 | "/org/freedesktop/machine1", | |
405 | "org.freedesktop.machine1.Manager", | |
406 | "GetMachineAddresses", | |
407 | NULL, | |
408 | &reply, | |
409 | "s", name); | |
410 | if (r < 0) | |
411 | return r; | |
412 | ||
0dd25fb9 | 413 | r = sd_bus_message_enter_container(reply, 'a', "(iay)"); |
878cd7e9 LP |
414 | if (r < 0) |
415 | return bus_log_parse_error(r); | |
416 | ||
0dd25fb9 LP |
417 | while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) { |
418 | int family; | |
878cd7e9 LP |
419 | const void *a; |
420 | size_t sz; | |
421 | char buffer[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)]; | |
422 | ||
0dd25fb9 | 423 | r = sd_bus_message_read(reply, "i", &family); |
878cd7e9 LP |
424 | if (r < 0) |
425 | return bus_log_parse_error(r); | |
426 | ||
427 | r = sd_bus_message_read_array(reply, 'y', &a, &sz); | |
428 | if (r < 0) | |
429 | return bus_log_parse_error(r); | |
430 | ||
f48e75cb LP |
431 | fputs(prefix, stdout); |
432 | fputs(inet_ntop(family, a, buffer, sizeof(buffer)), stdout); | |
433 | if (family == AF_INET6 && ifi > 0) | |
434 | printf("%%%i", ifi); | |
435 | fputc('\n', stdout); | |
878cd7e9 LP |
436 | |
437 | r = sd_bus_message_exit_container(reply); | |
438 | if (r < 0) | |
439 | return bus_log_parse_error(r); | |
440 | ||
441 | if (prefix != prefix2) | |
442 | prefix = prefix2; | |
443 | } | |
444 | if (r < 0) | |
445 | return bus_log_parse_error(r); | |
446 | ||
447 | r = sd_bus_message_exit_container(reply); | |
448 | if (r < 0) | |
449 | return bus_log_parse_error(r); | |
450 | ||
451 | return 0; | |
452 | } | |
453 | ||
717603e3 | 454 | static int print_os_release(sd_bus *bus, const char *name, const char *prefix) { |
4afd3348 | 455 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; |
717603e3 LP |
456 | const char *k, *v, *pretty = NULL; |
457 | int r; | |
458 | ||
459 | assert(bus); | |
460 | assert(name); | |
461 | assert(prefix); | |
462 | ||
463 | r = sd_bus_call_method(bus, | |
464 | "org.freedesktop.machine1", | |
465 | "/org/freedesktop/machine1", | |
466 | "org.freedesktop.machine1.Manager", | |
467 | "GetMachineOSRelease", | |
468 | NULL, | |
469 | &reply, | |
470 | "s", name); | |
471 | if (r < 0) | |
472 | return r; | |
473 | ||
474 | r = sd_bus_message_enter_container(reply, 'a', "{ss}"); | |
475 | if (r < 0) | |
476 | return bus_log_parse_error(r); | |
477 | ||
478 | while ((r = sd_bus_message_read(reply, "{ss}", &k, &v)) > 0) { | |
479 | if (streq(k, "PRETTY_NAME")) | |
480 | pretty = v; | |
481 | ||
482 | } | |
483 | if (r < 0) | |
484 | return bus_log_parse_error(r); | |
485 | ||
486 | r = sd_bus_message_exit_container(reply); | |
487 | if (r < 0) | |
488 | return bus_log_parse_error(r); | |
489 | ||
490 | if (pretty) | |
491 | printf("%s%s\n", prefix, pretty); | |
492 | ||
493 | return 0; | |
494 | } | |
495 | ||
1ee306e1 | 496 | typedef struct MachineStatusInfo { |
9f6eb1cd | 497 | char *name; |
1ee306e1 | 498 | sd_id128_t id; |
9f6eb1cd KS |
499 | char *class; |
500 | char *service; | |
89f7c846 | 501 | char *unit; |
9f6eb1cd | 502 | char *root_directory; |
1ee306e1 | 503 | pid_t leader; |
8b0cc9a3 | 504 | struct dual_timestamp timestamp; |
f48e75cb LP |
505 | int *netif; |
506 | unsigned n_netif; | |
1ee306e1 LP |
507 | } MachineStatusInfo; |
508 | ||
e7e55dbd DH |
509 | static void machine_status_info_clear(MachineStatusInfo *info) { |
510 | if (info) { | |
511 | free(info->name); | |
512 | free(info->class); | |
513 | free(info->service); | |
514 | free(info->unit); | |
515 | free(info->root_directory); | |
516 | free(info->netif); | |
517 | zero(*info); | |
518 | } | |
519 | } | |
520 | ||
a1da8583 | 521 | static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) { |
1ee306e1 LP |
522 | char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1; |
523 | char since2[FORMAT_TIMESTAMP_MAX], *s2; | |
f48e75cb LP |
524 | int ifi = -1; |
525 | ||
56159e0d | 526 | assert(bus); |
1ee306e1 LP |
527 | assert(i); |
528 | ||
529 | fputs(strna(i->name), stdout); | |
530 | ||
531 | if (!sd_id128_equal(i->id, SD_ID128_NULL)) | |
532 | printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id)); | |
533 | else | |
534 | putchar('\n'); | |
535 | ||
8b0cc9a3 LP |
536 | s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp.realtime); |
537 | s2 = format_timestamp(since2, sizeof(since2), i->timestamp.realtime); | |
1ee306e1 LP |
538 | |
539 | if (s1) | |
540 | printf("\t Since: %s; %s\n", s2, s1); | |
541 | else if (s2) | |
542 | printf("\t Since: %s\n", s2); | |
543 | ||
544 | if (i->leader > 0) { | |
545 | _cleanup_free_ char *t = NULL; | |
546 | ||
547 | printf("\t Leader: %u", (unsigned) i->leader); | |
548 | ||
549 | get_process_comm(i->leader, &t); | |
550 | if (t) | |
551 | printf(" (%s)", t); | |
552 | ||
553 | putchar('\n'); | |
554 | } | |
555 | ||
556 | if (i->service) { | |
557 | printf("\t Service: %s", i->service); | |
558 | ||
559 | if (i->class) | |
560 | printf("; class %s", i->class); | |
561 | ||
562 | putchar('\n'); | |
563 | } else if (i->class) | |
564 | printf("\t Class: %s\n", i->class); | |
565 | ||
1ee306e1 LP |
566 | if (i->root_directory) |
567 | printf("\t Root: %s\n", i->root_directory); | |
568 | ||
f48e75cb LP |
569 | if (i->n_netif > 0) { |
570 | unsigned c; | |
571 | ||
572 | fputs("\t Iface:", stdout); | |
573 | ||
574 | for (c = 0; c < i->n_netif; c++) { | |
575 | char name[IF_NAMESIZE+1] = ""; | |
576 | ||
577 | if (if_indextoname(i->netif[c], name)) { | |
578 | fputc(' ', stdout); | |
579 | fputs(name, stdout); | |
580 | ||
581 | if (ifi < 0) | |
582 | ifi = i->netif[c]; | |
583 | else | |
584 | ifi = 0; | |
585 | } else | |
586 | printf(" %i", i->netif[c]); | |
587 | } | |
588 | ||
589 | fputc('\n', stdout); | |
590 | } | |
591 | ||
592 | print_addresses(bus, i->name, ifi, | |
878cd7e9 LP |
593 | "\t Address: ", |
594 | "\t "); | |
595 | ||
717603e3 LP |
596 | print_os_release(bus, i->name, "\t OS: "); |
597 | ||
89f7c846 LP |
598 | if (i->unit) { |
599 | printf("\t Unit: %s\n", i->unit); | |
600 | show_unit_cgroup(bus, i->unit, i->leader); | |
8b0cc9a3 | 601 | |
ece174c5 | 602 | if (arg_transport == BUS_TRANSPORT_LOCAL) |
8b0cc9a3 LP |
603 | |
604 | show_journal_by_unit( | |
605 | stdout, | |
606 | i->unit, | |
607 | arg_output, | |
608 | 0, | |
609 | i->timestamp.monotonic, | |
610 | arg_lines, | |
611 | 0, | |
612 | get_output_flags() | OUTPUT_BEGIN_NEWLINE, | |
613 | SD_JOURNAL_LOCAL_ONLY, | |
614 | true, | |
615 | NULL); | |
1ee306e1 LP |
616 | } |
617 | } | |
618 | ||
f48e75cb LP |
619 | static int map_netif(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { |
620 | MachineStatusInfo *i = userdata; | |
621 | size_t l; | |
622 | const void *v; | |
623 | int r; | |
624 | ||
625 | assert_cc(sizeof(int32_t) == sizeof(int)); | |
626 | r = sd_bus_message_read_array(m, SD_BUS_TYPE_INT32, &v, &l); | |
627 | if (r < 0) | |
628 | return r; | |
e7e9b6bb ZJS |
629 | if (r == 0) |
630 | return -EBADMSG; | |
f48e75cb LP |
631 | |
632 | i->n_netif = l / sizeof(int32_t); | |
633 | i->netif = memdup(v, l); | |
634 | if (!i->netif) | |
635 | return -ENOMEM; | |
636 | ||
637 | return 0; | |
638 | } | |
639 | ||
fefdc04b | 640 | static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) { |
a6c61602 | 641 | |
9f6eb1cd | 642 | static const struct bus_properties_map map[] = { |
8b0cc9a3 LP |
643 | { "Name", "s", NULL, offsetof(MachineStatusInfo, name) }, |
644 | { "Class", "s", NULL, offsetof(MachineStatusInfo, class) }, | |
645 | { "Service", "s", NULL, offsetof(MachineStatusInfo, service) }, | |
646 | { "Unit", "s", NULL, offsetof(MachineStatusInfo, unit) }, | |
647 | { "RootDirectory", "s", NULL, offsetof(MachineStatusInfo, root_directory) }, | |
648 | { "Leader", "u", NULL, offsetof(MachineStatusInfo, leader) }, | |
649 | { "Timestamp", "t", NULL, offsetof(MachineStatusInfo, timestamp.realtime) }, | |
650 | { "TimestampMonotonic", "t", NULL, offsetof(MachineStatusInfo, timestamp.monotonic) }, | |
651 | { "Id", "ay", bus_map_id128, offsetof(MachineStatusInfo, id) }, | |
652 | { "NetworkInterfaces", "ai", map_netif, 0 }, | |
9f6eb1cd KS |
653 | {} |
654 | }; | |
a6c61602 | 655 | |
e7e55dbd | 656 | _cleanup_(machine_status_info_clear) MachineStatusInfo info = {}; |
a1da8583 TG |
657 | int r; |
658 | ||
56159e0d LP |
659 | assert(verb); |
660 | assert(bus); | |
1ee306e1 LP |
661 | assert(path); |
662 | assert(new_line); | |
663 | ||
9f6eb1cd KS |
664 | r = bus_map_all_properties(bus, |
665 | "org.freedesktop.machine1", | |
666 | path, | |
667 | map, | |
668 | &info); | |
f647962d MS |
669 | if (r < 0) |
670 | return log_error_errno(r, "Could not get properties: %m"); | |
1ee306e1 | 671 | |
1ee306e1 LP |
672 | if (*new_line) |
673 | printf("\n"); | |
1ee306e1 LP |
674 | *new_line = true; |
675 | ||
9f6eb1cd | 676 | print_machine_status_info(bus, &info); |
1ee306e1 | 677 | |
9f6eb1cd KS |
678 | return r; |
679 | } | |
1ee306e1 | 680 | |
fefdc04b | 681 | static int show_machine_properties(sd_bus *bus, const char *path, bool *new_line) { |
9f6eb1cd | 682 | int r; |
1ee306e1 | 683 | |
56159e0d LP |
684 | assert(bus); |
685 | assert(path); | |
686 | assert(new_line); | |
687 | ||
9f6eb1cd KS |
688 | if (*new_line) |
689 | printf("\n"); | |
1ee306e1 | 690 | |
9f6eb1cd | 691 | *new_line = true; |
a1da8583 | 692 | |
27e72d6b | 693 | r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all); |
a1da8583 | 694 | if (r < 0) |
da927ba9 | 695 | log_error_errno(r, "Could not get properties: %m"); |
1ee306e1 | 696 | |
a7893c6b | 697 | return r; |
1ee306e1 LP |
698 | } |
699 | ||
fefdc04b | 700 | static int show_machine(int argc, char *argv[], void *userdata) { |
56159e0d | 701 | |
4afd3348 LP |
702 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
703 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; | |
9f6eb1cd | 704 | bool properties, new_line = false; |
56159e0d LP |
705 | sd_bus *bus = userdata; |
706 | int r = 0, i; | |
1ee306e1 LP |
707 | |
708 | assert(bus); | |
1ee306e1 | 709 | |
56159e0d | 710 | properties = !strstr(argv[0], "status"); |
1ee306e1 LP |
711 | |
712 | pager_open_if_enabled(); | |
713 | ||
56159e0d | 714 | if (properties && argc <= 1) { |
a1da8583 | 715 | |
9f6eb1cd | 716 | /* If no argument is specified, inspect the manager |
1ee306e1 | 717 | * itself */ |
fefdc04b | 718 | r = show_machine_properties(bus, "/org/freedesktop/machine1", &new_line); |
8c841f21 | 719 | if (r < 0) |
9f6eb1cd | 720 | return r; |
1ee306e1 LP |
721 | } |
722 | ||
56159e0d | 723 | for (i = 1; i < argc; i++) { |
1ee306e1 LP |
724 | const char *path = NULL; |
725 | ||
a1da8583 TG |
726 | r = sd_bus_call_method( |
727 | bus, | |
728 | "org.freedesktop.machine1", | |
729 | "/org/freedesktop/machine1", | |
730 | "org.freedesktop.machine1.Manager", | |
731 | "GetMachine", | |
732 | &error, | |
733 | &reply, | |
56159e0d | 734 | "s", argv[i]); |
a1da8583 TG |
735 | if (r < 0) { |
736 | log_error("Could not get path to machine: %s", bus_error_message(&error, -r)); | |
737 | return r; | |
738 | } | |
739 | ||
740 | r = sd_bus_message_read(reply, "o", &path); | |
5b30bef8 LP |
741 | if (r < 0) |
742 | return bus_log_parse_error(r); | |
1ee306e1 | 743 | |
9f6eb1cd | 744 | if (properties) |
fefdc04b | 745 | r = show_machine_properties(bus, path, &new_line); |
9f6eb1cd | 746 | else |
fefdc04b LP |
747 | r = show_machine_info(argv[0], bus, path, &new_line); |
748 | } | |
749 | ||
750 | return r; | |
751 | } | |
752 | ||
753 | typedef struct ImageStatusInfo { | |
754 | char *name; | |
755 | char *path; | |
756 | char *type; | |
757 | int read_only; | |
758 | usec_t crtime; | |
759 | usec_t mtime; | |
c19de711 | 760 | uint64_t usage; |
b6b18498 | 761 | uint64_t limit; |
c19de711 | 762 | uint64_t usage_exclusive; |
b6b18498 | 763 | uint64_t limit_exclusive; |
fefdc04b LP |
764 | } ImageStatusInfo; |
765 | ||
e7e55dbd DH |
766 | static void image_status_info_clear(ImageStatusInfo *info) { |
767 | if (info) { | |
768 | free(info->name); | |
769 | free(info->path); | |
770 | free(info->type); | |
771 | zero(*info); | |
772 | } | |
773 | } | |
774 | ||
fefdc04b LP |
775 | static void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) { |
776 | char ts_relative[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1; | |
777 | char ts_absolute[FORMAT_TIMESTAMP_MAX], *s2; | |
b6b18498 LP |
778 | char bs[FORMAT_BYTES_MAX], *s3; |
779 | char bs_exclusive[FORMAT_BYTES_MAX], *s4; | |
fefdc04b LP |
780 | |
781 | assert(bus); | |
782 | assert(i); | |
783 | ||
784 | if (i->name) { | |
785 | fputs(i->name, stdout); | |
786 | putchar('\n'); | |
787 | } | |
788 | ||
9a14fb62 | 789 | if (i->type) |
fefdc04b LP |
790 | printf("\t Type: %s\n", i->type); |
791 | ||
792 | if (i->path) | |
793 | printf("\t Path: %s\n", i->path); | |
794 | ||
795 | printf("\t RO: %s%s%s\n", | |
796 | i->read_only ? ansi_highlight_red() : "", | |
797 | i->read_only ? "read-only" : "writable", | |
1fc464f6 | 798 | i->read_only ? ansi_normal() : ""); |
fefdc04b LP |
799 | |
800 | s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->crtime); | |
801 | s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->crtime); | |
b6b18498 | 802 | if (s1 && s2) |
fefdc04b LP |
803 | printf("\t Created: %s; %s\n", s2, s1); |
804 | else if (s2) | |
805 | printf("\t Created: %s\n", s2); | |
806 | ||
807 | s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->mtime); | |
808 | s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->mtime); | |
b6b18498 | 809 | if (s1 && s2) |
fefdc04b LP |
810 | printf("\tModified: %s; %s\n", s2, s1); |
811 | else if (s2) | |
812 | printf("\tModified: %s\n", s2); | |
b6b18498 | 813 | |
c19de711 LP |
814 | s3 = format_bytes(bs, sizeof(bs), i->usage); |
815 | s4 = i->usage_exclusive != i->usage ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->usage_exclusive) : NULL; | |
b6b18498 | 816 | if (s3 && s4) |
c19de711 | 817 | printf("\t Usage: %s (exclusive: %s)\n", s3, s4); |
b6b18498 | 818 | else if (s3) |
c19de711 | 819 | printf("\t Usage: %s\n", s3); |
b6b18498 LP |
820 | |
821 | s3 = format_bytes(bs, sizeof(bs), i->limit); | |
822 | s4 = i->limit_exclusive != i->limit ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->limit_exclusive) : NULL; | |
823 | if (s3 && s4) | |
824 | printf("\t Limit: %s (exclusive: %s)\n", s3, s4); | |
825 | else if (s3) | |
826 | printf("\t Limit: %s\n", s3); | |
fefdc04b LP |
827 | } |
828 | ||
160e3793 | 829 | static int show_image_info(sd_bus *bus, const char *path, bool *new_line) { |
fefdc04b LP |
830 | |
831 | static const struct bus_properties_map map[] = { | |
b6b18498 LP |
832 | { "Name", "s", NULL, offsetof(ImageStatusInfo, name) }, |
833 | { "Path", "s", NULL, offsetof(ImageStatusInfo, path) }, | |
834 | { "Type", "s", NULL, offsetof(ImageStatusInfo, type) }, | |
835 | { "ReadOnly", "b", NULL, offsetof(ImageStatusInfo, read_only) }, | |
836 | { "CreationTimestamp", "t", NULL, offsetof(ImageStatusInfo, crtime) }, | |
837 | { "ModificationTimestamp", "t", NULL, offsetof(ImageStatusInfo, mtime) }, | |
c19de711 | 838 | { "Usage", "t", NULL, offsetof(ImageStatusInfo, usage) }, |
b6b18498 | 839 | { "Limit", "t", NULL, offsetof(ImageStatusInfo, limit) }, |
c19de711 | 840 | { "UsageExclusive", "t", NULL, offsetof(ImageStatusInfo, usage_exclusive) }, |
b6b18498 | 841 | { "LimitExclusive", "t", NULL, offsetof(ImageStatusInfo, limit_exclusive) }, |
fefdc04b LP |
842 | {} |
843 | }; | |
844 | ||
e7e55dbd | 845 | _cleanup_(image_status_info_clear) ImageStatusInfo info = {}; |
fefdc04b LP |
846 | int r; |
847 | ||
fefdc04b LP |
848 | assert(bus); |
849 | assert(path); | |
850 | assert(new_line); | |
851 | ||
852 | r = bus_map_all_properties(bus, | |
853 | "org.freedesktop.machine1", | |
854 | path, | |
855 | map, | |
856 | &info); | |
857 | if (r < 0) | |
858 | return log_error_errno(r, "Could not get properties: %m"); | |
859 | ||
860 | if (*new_line) | |
861 | printf("\n"); | |
862 | *new_line = true; | |
863 | ||
864 | print_image_status_info(bus, &info); | |
865 | ||
fefdc04b LP |
866 | return r; |
867 | } | |
868 | ||
160e3793 LP |
869 | typedef struct PoolStatusInfo { |
870 | char *path; | |
871 | uint64_t usage; | |
872 | uint64_t limit; | |
873 | } PoolStatusInfo; | |
874 | ||
e7e55dbd DH |
875 | static void pool_status_info_clear(PoolStatusInfo *info) { |
876 | if (info) { | |
877 | free(info->path); | |
878 | zero(*info); | |
879 | info->usage = -1; | |
880 | info->limit = -1; | |
881 | } | |
882 | } | |
883 | ||
160e3793 LP |
884 | static void print_pool_status_info(sd_bus *bus, PoolStatusInfo *i) { |
885 | char bs[FORMAT_BYTES_MAX], *s; | |
886 | ||
887 | if (i->path) | |
888 | printf("\t Path: %s\n", i->path); | |
889 | ||
890 | s = format_bytes(bs, sizeof(bs), i->usage); | |
891 | if (s) | |
892 | printf("\t Usage: %s\n", s); | |
893 | ||
894 | s = format_bytes(bs, sizeof(bs), i->limit); | |
895 | if (s) | |
896 | printf("\t Limit: %s\n", s); | |
897 | } | |
898 | ||
899 | static int show_pool_info(sd_bus *bus) { | |
900 | ||
901 | static const struct bus_properties_map map[] = { | |
902 | { "PoolPath", "s", NULL, offsetof(PoolStatusInfo, path) }, | |
903 | { "PoolUsage", "t", NULL, offsetof(PoolStatusInfo, usage) }, | |
904 | { "PoolLimit", "t", NULL, offsetof(PoolStatusInfo, limit) }, | |
905 | {} | |
906 | }; | |
907 | ||
e7e55dbd | 908 | _cleanup_(pool_status_info_clear) PoolStatusInfo info = { |
160e3793 LP |
909 | .usage = (uint64_t) -1, |
910 | .limit = (uint64_t) -1, | |
911 | }; | |
912 | int r; | |
913 | ||
914 | assert(bus); | |
915 | ||
916 | r = bus_map_all_properties(bus, | |
917 | "org.freedesktop.machine1", | |
918 | "/org/freedesktop/machine1", | |
919 | map, | |
920 | &info); | |
921 | if (r < 0) | |
922 | return log_error_errno(r, "Could not get properties: %m"); | |
923 | ||
924 | print_pool_status_info(bus, &info); | |
925 | ||
160e3793 LP |
926 | return 0; |
927 | } | |
928 | ||
929 | ||
fefdc04b LP |
930 | static int show_image_properties(sd_bus *bus, const char *path, bool *new_line) { |
931 | int r; | |
932 | ||
933 | assert(bus); | |
934 | assert(path); | |
935 | assert(new_line); | |
936 | ||
937 | if (*new_line) | |
938 | printf("\n"); | |
939 | ||
940 | *new_line = true; | |
941 | ||
942 | r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all); | |
943 | if (r < 0) | |
944 | log_error_errno(r, "Could not get properties: %m"); | |
945 | ||
946 | return r; | |
947 | } | |
948 | ||
949 | static int show_image(int argc, char *argv[], void *userdata) { | |
950 | ||
4afd3348 LP |
951 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
952 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; | |
fefdc04b LP |
953 | bool properties, new_line = false; |
954 | sd_bus *bus = userdata; | |
955 | int r = 0, i; | |
956 | ||
957 | assert(bus); | |
958 | ||
959 | properties = !strstr(argv[0], "status"); | |
960 | ||
961 | pager_open_if_enabled(); | |
962 | ||
160e3793 | 963 | if (argc <= 1) { |
fefdc04b LP |
964 | |
965 | /* If no argument is specified, inspect the manager | |
966 | * itself */ | |
160e3793 LP |
967 | |
968 | if (properties) | |
969 | r = show_image_properties(bus, "/org/freedesktop/machine1", &new_line); | |
970 | else | |
971 | r = show_pool_info(bus); | |
fefdc04b LP |
972 | if (r < 0) |
973 | return r; | |
974 | } | |
975 | ||
976 | for (i = 1; i < argc; i++) { | |
977 | const char *path = NULL; | |
978 | ||
979 | r = sd_bus_call_method( | |
90adaa25 LP |
980 | bus, |
981 | "org.freedesktop.machine1", | |
982 | "/org/freedesktop/machine1", | |
983 | "org.freedesktop.machine1.Manager", | |
984 | "GetImage", | |
985 | &error, | |
986 | &reply, | |
987 | "s", argv[i]); | |
fefdc04b LP |
988 | if (r < 0) { |
989 | log_error("Could not get path to image: %s", bus_error_message(&error, -r)); | |
990 | return r; | |
991 | } | |
992 | ||
993 | r = sd_bus_message_read(reply, "o", &path); | |
994 | if (r < 0) | |
995 | return bus_log_parse_error(r); | |
996 | ||
997 | if (properties) | |
998 | r = show_image_properties(bus, path, &new_line); | |
999 | else | |
160e3793 | 1000 | r = show_image_info(bus, path, &new_line); |
1ee306e1 LP |
1001 | } |
1002 | ||
9f6eb1cd | 1003 | return r; |
1ee306e1 LP |
1004 | } |
1005 | ||
56159e0d | 1006 | static int kill_machine(int argc, char *argv[], void *userdata) { |
4afd3348 | 1007 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
56159e0d | 1008 | sd_bus *bus = userdata; |
90adaa25 | 1009 | int r, i; |
1ee306e1 | 1010 | |
56159e0d | 1011 | assert(bus); |
1ee306e1 | 1012 | |
acf97e21 LP |
1013 | polkit_agent_open_if_enabled(); |
1014 | ||
1ee306e1 LP |
1015 | if (!arg_kill_who) |
1016 | arg_kill_who = "all"; | |
1017 | ||
56159e0d | 1018 | for (i = 1; i < argc; i++) { |
a1da8583 | 1019 | r = sd_bus_call_method( |
56159e0d LP |
1020 | bus, |
1021 | "org.freedesktop.machine1", | |
1022 | "/org/freedesktop/machine1", | |
1023 | "org.freedesktop.machine1.Manager", | |
1024 | "KillMachine", | |
1025 | &error, | |
1026 | NULL, | |
1027 | "ssi", argv[i], arg_kill_who, arg_signal); | |
a1da8583 TG |
1028 | if (r < 0) { |
1029 | log_error("Could not kill machine: %s", bus_error_message(&error, -r)); | |
1ee306e1 | 1030 | return r; |
a1da8583 | 1031 | } |
1ee306e1 LP |
1032 | } |
1033 | ||
1034 | return 0; | |
1035 | } | |
1036 | ||
56159e0d | 1037 | static int reboot_machine(int argc, char *argv[], void *userdata) { |
1dba654b LP |
1038 | arg_kill_who = "leader"; |
1039 | arg_signal = SIGINT; /* sysvinit + systemd */ | |
1ee306e1 | 1040 | |
56159e0d | 1041 | return kill_machine(argc, argv, userdata); |
1dba654b | 1042 | } |
1ee306e1 | 1043 | |
56159e0d | 1044 | static int poweroff_machine(int argc, char *argv[], void *userdata) { |
1dba654b LP |
1045 | arg_kill_who = "leader"; |
1046 | arg_signal = SIGRTMIN+4; /* only systemd */ | |
1ee306e1 | 1047 | |
56159e0d | 1048 | return kill_machine(argc, argv, userdata); |
1ee306e1 LP |
1049 | } |
1050 | ||
56159e0d | 1051 | static int terminate_machine(int argc, char *argv[], void *userdata) { |
4afd3348 | 1052 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
56159e0d | 1053 | sd_bus *bus = userdata; |
2723b3b5 | 1054 | int r, i; |
923d8fd3 | 1055 | |
56159e0d | 1056 | assert(bus); |
923d8fd3 | 1057 | |
acf97e21 LP |
1058 | polkit_agent_open_if_enabled(); |
1059 | ||
56159e0d | 1060 | for (i = 1; i < argc; i++) { |
923d8fd3 LP |
1061 | r = sd_bus_call_method( |
1062 | bus, | |
1063 | "org.freedesktop.machine1", | |
1064 | "/org/freedesktop/machine1", | |
1065 | "org.freedesktop.machine1.Manager", | |
1dba654b | 1066 | "TerminateMachine", |
923d8fd3 | 1067 | &error, |
1dba654b | 1068 | NULL, |
56159e0d | 1069 | "s", argv[i]); |
923d8fd3 | 1070 | if (r < 0) { |
1dba654b | 1071 | log_error("Could not terminate machine: %s", bus_error_message(&error, -r)); |
923d8fd3 LP |
1072 | return r; |
1073 | } | |
923d8fd3 LP |
1074 | } |
1075 | ||
1076 | return 0; | |
1077 | } | |
1078 | ||
0370612e | 1079 | static int copy_files(int argc, char *argv[], void *userdata) { |
4afd3348 | 1080 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
1fe6fa16 RM |
1081 | _cleanup_free_ char *abs_host_path = NULL; |
1082 | char *dest, *host_path, *container_path; | |
0370612e LP |
1083 | sd_bus *bus = userdata; |
1084 | bool copy_from; | |
785890ac LP |
1085 | int r; |
1086 | ||
1087 | assert(bus); | |
0370612e | 1088 | |
2723b3b5 LP |
1089 | polkit_agent_open_if_enabled(); |
1090 | ||
0370612e | 1091 | copy_from = streq(argv[0], "copy-from"); |
1fe6fa16 RM |
1092 | dest = argv[3] ?: argv[2]; |
1093 | host_path = copy_from ? dest : argv[2]; | |
1094 | container_path = copy_from ? argv[2] : dest; | |
1095 | ||
1096 | if (!path_is_absolute(host_path)) { | |
0f474365 LP |
1097 | r = path_make_absolute_cwd(host_path, &abs_host_path); |
1098 | if (r < 0) | |
1099 | return log_error_errno(r, "Failed to make path absolute: %m"); | |
1100 | ||
1fe6fa16 RM |
1101 | host_path = abs_host_path; |
1102 | } | |
785890ac LP |
1103 | |
1104 | r = sd_bus_call_method( | |
1105 | bus, | |
1106 | "org.freedesktop.machine1", | |
1107 | "/org/freedesktop/machine1", | |
1108 | "org.freedesktop.machine1.Manager", | |
0370612e | 1109 | copy_from ? "CopyFromMachine" : "CopyToMachine", |
785890ac | 1110 | &error, |
0370612e LP |
1111 | NULL, |
1112 | "sss", | |
1113 | argv[1], | |
1fe6fa16 RM |
1114 | copy_from ? container_path : host_path, |
1115 | copy_from ? host_path : container_path); | |
0f474365 LP |
1116 | if (r < 0) |
1117 | return log_error_errno(r, "Failed to copy: %s", bus_error_message(&error, r)); | |
f2cbe59e LP |
1118 | |
1119 | return 0; | |
1120 | } | |
1121 | ||
56159e0d | 1122 | static int bind_mount(int argc, char *argv[], void *userdata) { |
4afd3348 | 1123 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
56159e0d | 1124 | sd_bus *bus = userdata; |
785890ac LP |
1125 | int r; |
1126 | ||
56159e0d LP |
1127 | assert(bus); |
1128 | ||
2723b3b5 LP |
1129 | polkit_agent_open_if_enabled(); |
1130 | ||
90adaa25 LP |
1131 | r = sd_bus_call_method( |
1132 | bus, | |
1133 | "org.freedesktop.machine1", | |
1134 | "/org/freedesktop/machine1", | |
1135 | "org.freedesktop.machine1.Manager", | |
1136 | "BindMountMachine", | |
1137 | &error, | |
1138 | NULL, | |
1139 | "sssbb", | |
1140 | argv[1], | |
1141 | argv[2], | |
1142 | argv[3], | |
1143 | arg_read_only, | |
1144 | arg_mkdir); | |
785890ac | 1145 | if (r < 0) { |
90adaa25 LP |
1146 | log_error("Failed to bind mount: %s", bus_error_message(&error, -r)); |
1147 | return r; | |
785890ac LP |
1148 | } |
1149 | ||
90adaa25 | 1150 | return 0; |
785890ac LP |
1151 | } |
1152 | ||
19070062 | 1153 | static int on_machine_removed(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { |
0ec5543c LP |
1154 | PTYForward ** forward = (PTYForward**) userdata; |
1155 | int r; | |
1156 | ||
0ec5543c LP |
1157 | assert(m); |
1158 | assert(forward); | |
1159 | ||
1160 | if (*forward) { | |
1161 | /* If the forwarder is already initialized, tell it to | |
da054c37 LP |
1162 | * exit on the next vhangup(), so that we still flush |
1163 | * out what might be queued and exit then. */ | |
0ec5543c | 1164 | |
da054c37 | 1165 | r = pty_forward_set_ignore_vhangup(*forward, false); |
0ec5543c LP |
1166 | if (r >= 0) |
1167 | return 0; | |
1168 | ||
da054c37 | 1169 | log_error_errno(r, "Failed to set ignore_vhangup flag: %m"); |
0ec5543c LP |
1170 | } |
1171 | ||
1172 | /* On error, or when the forwarder is not initialized yet, quit immediately */ | |
19070062 | 1173 | sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), EXIT_FAILURE); |
0ec5543c LP |
1174 | return 0; |
1175 | } | |
1176 | ||
ae3dde80 | 1177 | static int process_forward(sd_event *event, PTYForward **forward, int master, PTYForwardFlags flags, const char *name) { |
c454426c LP |
1178 | char last_char = 0; |
1179 | bool machine_died; | |
1180 | int ret = 0, r; | |
1181 | ||
1182 | assert(event); | |
1183 | assert(master >= 0); | |
1184 | assert(name); | |
1185 | ||
1186 | assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT, -1) >= 0); | |
1187 | ||
91913f58 LP |
1188 | if (streq(name, ".host")) |
1189 | log_info("Connected to the local host. Press ^] three times within 1s to exit session."); | |
1190 | else | |
1191 | log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", name); | |
c454426c LP |
1192 | |
1193 | sd_event_add_signal(event, NULL, SIGINT, NULL, NULL); | |
1194 | sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL); | |
1195 | ||
ae3dde80 | 1196 | r = pty_forward_new(event, master, flags, forward); |
c454426c LP |
1197 | if (r < 0) |
1198 | return log_error_errno(r, "Failed to create PTY forwarder: %m"); | |
1199 | ||
1200 | r = sd_event_loop(event); | |
1201 | if (r < 0) | |
1202 | return log_error_errno(r, "Failed to run event loop: %m"); | |
1203 | ||
1204 | pty_forward_get_last_char(*forward, &last_char); | |
1205 | ||
1206 | machine_died = | |
ae3dde80 | 1207 | (flags & PTY_FORWARD_IGNORE_VHANGUP) && |
c454426c LP |
1208 | pty_forward_get_ignore_vhangup(*forward) == 0; |
1209 | ||
1210 | *forward = pty_forward_free(*forward); | |
1211 | ||
1212 | if (last_char != '\n') | |
1213 | fputc('\n', stdout); | |
1214 | ||
1215 | if (machine_died) | |
1216 | log_info("Machine %s terminated.", name); | |
91913f58 LP |
1217 | else if (streq(name, ".host")) |
1218 | log_info("Connection to the local host terminated."); | |
c454426c LP |
1219 | else |
1220 | log_info("Connection to machine %s terminated.", name); | |
1221 | ||
1222 | sd_event_get_exit_code(event, &ret); | |
1223 | return ret; | |
1224 | } | |
1225 | ||
56159e0d | 1226 | static int login_machine(int argc, char *argv[], void *userdata) { |
4afd3348 LP |
1227 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; |
1228 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; | |
023fb90b | 1229 | _cleanup_(pty_forward_freep) PTYForward *forward = NULL; |
4afd3348 LP |
1230 | _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL; |
1231 | _cleanup_(sd_event_unrefp) sd_event *event = NULL; | |
c454426c | 1232 | int master = -1, r; |
56159e0d | 1233 | sd_bus *bus = userdata; |
91913f58 | 1234 | const char *pty, *match, *machine; |
04d39279 LP |
1235 | |
1236 | assert(bus); | |
04d39279 | 1237 | |
c454426c LP |
1238 | if (!strv_isempty(arg_setenv) || arg_uid) { |
1239 | log_error("--setenv= and --uid= are not supported for 'login'. Use 'shell' instead."); | |
1240 | return -EINVAL; | |
1241 | } | |
1242 | ||
bf441e3d | 1243 | if (arg_transport != BUS_TRANSPORT_LOCAL && |
de33fc62 | 1244 | arg_transport != BUS_TRANSPORT_MACHINE) { |
923d8fd3 | 1245 | log_error("Login only supported on local machines."); |
15411c0c | 1246 | return -EOPNOTSUPP; |
04d39279 LP |
1247 | } |
1248 | ||
acf97e21 LP |
1249 | polkit_agent_open_if_enabled(); |
1250 | ||
023fb90b | 1251 | r = sd_event_default(&event); |
f647962d MS |
1252 | if (r < 0) |
1253 | return log_error_errno(r, "Failed to get event loop: %m"); | |
023fb90b LP |
1254 | |
1255 | r = sd_bus_attach_event(bus, event, 0); | |
f647962d MS |
1256 | if (r < 0) |
1257 | return log_error_errno(r, "Failed to attach bus to event loop: %m"); | |
023fb90b | 1258 | |
91913f58 LP |
1259 | machine = argc < 2 || isempty(argv[1]) ? ".host" : argv[1]; |
1260 | ||
63c372cb | 1261 | match = strjoina("type='signal'," |
c454426c LP |
1262 | "sender='org.freedesktop.machine1'," |
1263 | "path='/org/freedesktop/machine1',", | |
1264 | "interface='org.freedesktop.machine1.Manager'," | |
1265 | "member='MachineRemoved'," | |
91913f58 | 1266 | "arg0='", machine, "'"); |
0ec5543c LP |
1267 | |
1268 | r = sd_bus_add_match(bus, &slot, match, on_machine_removed, &forward); | |
1269 | if (r < 0) | |
1270 | return log_error_errno(r, "Failed to add machine removal match: %m"); | |
1271 | ||
2723b3b5 LP |
1272 | r = sd_bus_call_method( |
1273 | bus, | |
1274 | "org.freedesktop.machine1", | |
1275 | "/org/freedesktop/machine1", | |
1276 | "org.freedesktop.machine1.Manager", | |
1277 | "OpenMachineLogin", | |
1278 | &error, | |
1279 | &reply, | |
91913f58 | 1280 | "s", machine); |
40205d70 | 1281 | if (r < 0) { |
c454426c | 1282 | log_error("Failed to get login PTY: %s", bus_error_message(&error, -r)); |
785890ac | 1283 | return r; |
40205d70 | 1284 | } |
04d39279 | 1285 | |
40205d70 LP |
1286 | r = sd_bus_message_read(reply, "hs", &master, &pty); |
1287 | if (r < 0) | |
ee451d76 | 1288 | return bus_log_parse_error(r); |
04d39279 | 1289 | |
ae3dde80 | 1290 | return process_forward(event, &forward, master, PTY_FORWARD_IGNORE_VHANGUP, machine); |
c454426c | 1291 | } |
04d39279 | 1292 | |
c454426c | 1293 | static int shell_machine(int argc, char *argv[], void *userdata) { |
4afd3348 LP |
1294 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; |
1295 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; | |
c454426c | 1296 | _cleanup_(pty_forward_freep) PTYForward *forward = NULL; |
4afd3348 LP |
1297 | _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL; |
1298 | _cleanup_(sd_event_unrefp) sd_event *event = NULL; | |
c454426c LP |
1299 | int master = -1, r; |
1300 | sd_bus *bus = userdata; | |
ef3100e9 | 1301 | const char *pty, *match, *machine, *path, *uid = NULL; |
04d39279 | 1302 | |
c454426c LP |
1303 | assert(bus); |
1304 | ||
1305 | if (arg_transport != BUS_TRANSPORT_LOCAL && | |
1306 | arg_transport != BUS_TRANSPORT_MACHINE) { | |
1307 | log_error("Shell only supported on local machines."); | |
1308 | return -EOPNOTSUPP; | |
1309 | } | |
1310 | ||
89fec318 LP |
1311 | /* Pass $TERM to shell session, if not explicitly specified. */ |
1312 | if (!strv_find_prefix(arg_setenv, "TERM=")) { | |
1313 | const char *t; | |
1314 | ||
1315 | t = strv_find_prefix(environ, "TERM="); | |
1316 | if (t) { | |
1317 | if (strv_extend(&arg_setenv, t) < 0) | |
1318 | return log_oom(); | |
1319 | } | |
1320 | } | |
1321 | ||
c454426c | 1322 | polkit_agent_open_if_enabled(); |
023fb90b | 1323 | |
c454426c | 1324 | r = sd_event_default(&event); |
f647962d | 1325 | if (r < 0) |
c454426c | 1326 | return log_error_errno(r, "Failed to get event loop: %m"); |
023fb90b | 1327 | |
c454426c | 1328 | r = sd_bus_attach_event(bus, event, 0); |
f647962d | 1329 | if (r < 0) |
c454426c | 1330 | return log_error_errno(r, "Failed to attach bus to event loop: %m"); |
04d39279 | 1331 | |
ef3100e9 LP |
1332 | machine = argc < 2 || isempty(argv[1]) ? NULL : argv[1]; |
1333 | ||
1334 | if (arg_uid) | |
1335 | uid = arg_uid; | |
1336 | else if (machine) { | |
1337 | const char *at; | |
1338 | ||
1339 | at = strchr(machine, '@'); | |
1340 | if (at) { | |
1341 | uid = strndupa(machine, at - machine); | |
1342 | machine = at + 1; | |
1343 | } | |
1344 | } | |
1345 | ||
1346 | if (isempty(machine)) | |
1347 | machine = ".host"; | |
91913f58 | 1348 | |
c454426c LP |
1349 | match = strjoina("type='signal'," |
1350 | "sender='org.freedesktop.machine1'," | |
1351 | "path='/org/freedesktop/machine1',", | |
1352 | "interface='org.freedesktop.machine1.Manager'," | |
1353 | "member='MachineRemoved'," | |
91913f58 | 1354 | "arg0='", machine, "'"); |
c7b7d449 | 1355 | |
c454426c LP |
1356 | r = sd_bus_add_match(bus, &slot, match, on_machine_removed, &forward); |
1357 | if (r < 0) | |
1358 | return log_error_errno(r, "Failed to add machine removal match: %m"); | |
023fb90b | 1359 | |
c454426c LP |
1360 | r = sd_bus_message_new_method_call( |
1361 | bus, | |
1362 | &m, | |
1363 | "org.freedesktop.machine1", | |
1364 | "/org/freedesktop/machine1", | |
1365 | "org.freedesktop.machine1.Manager", | |
1366 | "OpenMachineShell"); | |
1367 | if (r < 0) | |
1368 | return bus_log_create_error(r); | |
04d39279 | 1369 | |
91913f58 LP |
1370 | path = argc < 3 || isempty(argv[2]) ? NULL : argv[2]; |
1371 | ||
ef3100e9 | 1372 | r = sd_bus_message_append(m, "sss", machine, uid, path); |
c454426c LP |
1373 | if (r < 0) |
1374 | return bus_log_create_error(r); | |
04d39279 | 1375 | |
91913f58 | 1376 | r = sd_bus_message_append_strv(m, strv_length(argv) <= 3 ? NULL : argv + 2); |
c454426c LP |
1377 | if (r < 0) |
1378 | return bus_log_create_error(r); | |
1379 | ||
1380 | r = sd_bus_message_append_strv(m, arg_setenv); | |
1381 | if (r < 0) | |
1382 | return bus_log_create_error(r); | |
1383 | ||
1384 | r = sd_bus_call(bus, m, 0, &error, &reply); | |
1385 | if (r < 0) { | |
1386 | log_error("Failed to get shell PTY: %s", bus_error_message(&error, -r)); | |
1387 | return r; | |
1388 | } | |
1389 | ||
1390 | r = sd_bus_message_read(reply, "hs", &master, &pty); | |
1391 | if (r < 0) | |
1392 | return bus_log_parse_error(r); | |
1393 | ||
40e1f4ea | 1394 | return process_forward(event, &forward, master, 0, machine); |
04d39279 LP |
1395 | } |
1396 | ||
08682124 | 1397 | static int remove_image(int argc, char *argv[], void *userdata) { |
4afd3348 | 1398 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
08682124 | 1399 | sd_bus *bus = userdata; |
ebd93cb6 | 1400 | int r, i; |
08682124 LP |
1401 | |
1402 | assert(bus); | |
1403 | ||
acf97e21 LP |
1404 | polkit_agent_open_if_enabled(); |
1405 | ||
08682124 | 1406 | for (i = 1; i < argc; i++) { |
08682124 LP |
1407 | r = sd_bus_call_method( |
1408 | bus, | |
1409 | "org.freedesktop.machine1", | |
1410 | "/org/freedesktop/machine1", | |
1411 | "org.freedesktop.machine1.Manager", | |
1412 | "RemoveImage", | |
1413 | &error, | |
1414 | NULL, | |
1415 | "s", argv[i]); | |
1416 | if (r < 0) { | |
1417 | log_error("Could not remove image: %s", bus_error_message(&error, -r)); | |
1418 | return r; | |
1419 | } | |
1420 | } | |
1421 | ||
1422 | return 0; | |
1423 | } | |
1424 | ||
ebd93cb6 | 1425 | static int rename_image(int argc, char *argv[], void *userdata) { |
4afd3348 | 1426 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
ebd93cb6 LP |
1427 | sd_bus *bus = userdata; |
1428 | int r; | |
1429 | ||
acf97e21 LP |
1430 | polkit_agent_open_if_enabled(); |
1431 | ||
ebd93cb6 LP |
1432 | r = sd_bus_call_method( |
1433 | bus, | |
1434 | "org.freedesktop.machine1", | |
1435 | "/org/freedesktop/machine1", | |
1436 | "org.freedesktop.machine1.Manager", | |
1437 | "RenameImage", | |
1438 | &error, | |
1439 | NULL, | |
1440 | "ss", argv[1], argv[2]); | |
1441 | if (r < 0) { | |
1442 | log_error("Could not rename image: %s", bus_error_message(&error, -r)); | |
1443 | return r; | |
1444 | } | |
1445 | ||
1446 | return 0; | |
1447 | } | |
1448 | ||
1449 | static int clone_image(int argc, char *argv[], void *userdata) { | |
4afd3348 | 1450 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
ebd93cb6 LP |
1451 | sd_bus *bus = userdata; |
1452 | int r; | |
1453 | ||
acf97e21 LP |
1454 | polkit_agent_open_if_enabled(); |
1455 | ||
ebd93cb6 LP |
1456 | r = sd_bus_call_method( |
1457 | bus, | |
1458 | "org.freedesktop.machine1", | |
1459 | "/org/freedesktop/machine1", | |
1460 | "org.freedesktop.machine1.Manager", | |
1461 | "CloneImage", | |
1462 | &error, | |
1463 | NULL, | |
1464 | "ssb", argv[1], argv[2], arg_read_only); | |
1465 | if (r < 0) { | |
1466 | log_error("Could not clone image: %s", bus_error_message(&error, -r)); | |
1467 | return r; | |
1468 | } | |
1469 | ||
1470 | return 0; | |
1471 | } | |
1472 | ||
1473 | static int read_only_image(int argc, char *argv[], void *userdata) { | |
4afd3348 | 1474 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
ebd93cb6 LP |
1475 | sd_bus *bus = userdata; |
1476 | int b = true, r; | |
1477 | ||
1478 | if (argc > 2) { | |
1479 | b = parse_boolean(argv[2]); | |
1480 | if (b < 0) { | |
1481 | log_error("Failed to parse boolean argument: %s", argv[2]); | |
1482 | return -EINVAL; | |
1483 | } | |
1484 | } | |
1485 | ||
acf97e21 LP |
1486 | polkit_agent_open_if_enabled(); |
1487 | ||
ebd93cb6 LP |
1488 | r = sd_bus_call_method( |
1489 | bus, | |
1490 | "org.freedesktop.machine1", | |
1491 | "/org/freedesktop/machine1", | |
1492 | "org.freedesktop.machine1.Manager", | |
1493 | "MarkImageReadOnly", | |
1494 | &error, | |
1495 | NULL, | |
1496 | "sb", argv[1], b); | |
1497 | if (r < 0) { | |
1498 | log_error("Could not mark image read-only: %s", bus_error_message(&error, -r)); | |
1499 | return r; | |
1500 | } | |
1501 | ||
1502 | return 0; | |
1503 | } | |
1504 | ||
7410616c LP |
1505 | static int make_service_name(const char *name, char **ret) { |
1506 | _cleanup_free_ char *e = NULL; | |
1507 | int r; | |
1508 | ||
1509 | assert(name); | |
1510 | assert(ret); | |
1511 | ||
1512 | if (!machine_name_is_valid(name)) { | |
1513 | log_error("Invalid machine name %s.", name); | |
1514 | return -EINVAL; | |
1515 | } | |
1516 | ||
1517 | e = unit_name_escape(name); | |
1518 | if (!e) | |
1519 | return log_oom(); | |
1520 | ||
1521 | r = unit_name_build("systemd-nspawn", e, ".service", ret); | |
1522 | if (r < 0) | |
1523 | return log_error_errno(r, "Failed to build unit name: %m"); | |
1524 | ||
1525 | return 0; | |
1526 | } | |
1527 | ||
ebd011d9 | 1528 | static int start_machine(int argc, char *argv[], void *userdata) { |
4afd3348 | 1529 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
ebd011d9 LP |
1530 | _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; |
1531 | sd_bus *bus = userdata; | |
1532 | int r, i; | |
1533 | ||
1534 | assert(bus); | |
1535 | ||
acf97e21 LP |
1536 | polkit_agent_open_if_enabled(); |
1537 | ||
ebd011d9 LP |
1538 | r = bus_wait_for_jobs_new(bus, &w); |
1539 | if (r < 0) | |
1540 | return log_oom(); | |
1541 | ||
1542 | for (i = 1; i < argc; i++) { | |
4afd3348 | 1543 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; |
7410616c | 1544 | _cleanup_free_ char *unit = NULL; |
ebd011d9 LP |
1545 | const char *object; |
1546 | ||
7410616c LP |
1547 | r = make_service_name(argv[i], &unit); |
1548 | if (r < 0) | |
1549 | return r; | |
ebd011d9 | 1550 | |
2723b3b5 | 1551 | r = sd_bus_call_method( |
ebd011d9 | 1552 | bus, |
ebd011d9 LP |
1553 | "org.freedesktop.systemd1", |
1554 | "/org/freedesktop/systemd1", | |
1555 | "org.freedesktop.systemd1.Manager", | |
2723b3b5 LP |
1556 | "StartUnit", |
1557 | &error, | |
1558 | &reply, | |
1559 | "ss", unit, "fail"); | |
ebd011d9 LP |
1560 | if (r < 0) { |
1561 | log_error("Failed to start unit: %s", bus_error_message(&error, -r)); | |
1562 | return r; | |
1563 | } | |
1564 | ||
1565 | r = sd_bus_message_read(reply, "o", &object); | |
1566 | if (r < 0) | |
1567 | return bus_log_parse_error(r); | |
1568 | ||
1569 | r = bus_wait_for_jobs_add(w, object); | |
1570 | if (r < 0) | |
1571 | return log_oom(); | |
1572 | } | |
1573 | ||
d8f52ed2 | 1574 | r = bus_wait_for_jobs(w, arg_quiet); |
ebd011d9 LP |
1575 | if (r < 0) |
1576 | return r; | |
1577 | ||
1578 | return 0; | |
1579 | } | |
1580 | ||
d8f52ed2 | 1581 | static int enable_machine(int argc, char *argv[], void *userdata) { |
4afd3348 LP |
1582 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; |
1583 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; | |
d8f52ed2 LP |
1584 | int carries_install_info = 0; |
1585 | const char *method = NULL; | |
1586 | sd_bus *bus = userdata; | |
1587 | int r, i; | |
1588 | ||
1589 | assert(bus); | |
1590 | ||
acf97e21 LP |
1591 | polkit_agent_open_if_enabled(); |
1592 | ||
d8f52ed2 LP |
1593 | method = streq(argv[0], "enable") ? "EnableUnitFiles" : "DisableUnitFiles"; |
1594 | ||
1595 | r = sd_bus_message_new_method_call( | |
1596 | bus, | |
1597 | &m, | |
1598 | "org.freedesktop.systemd1", | |
1599 | "/org/freedesktop/systemd1", | |
1600 | "org.freedesktop.systemd1.Manager", | |
1601 | method); | |
1602 | if (r < 0) | |
1603 | return bus_log_create_error(r); | |
1604 | ||
d8f52ed2 LP |
1605 | r = sd_bus_message_open_container(m, 'a', "s"); |
1606 | if (r < 0) | |
1607 | return bus_log_create_error(r); | |
1608 | ||
1609 | for (i = 1; i < argc; i++) { | |
90615ad7 | 1610 | _cleanup_free_ char *unit = NULL; |
d8f52ed2 | 1611 | |
7410616c LP |
1612 | r = make_service_name(argv[i], &unit); |
1613 | if (r < 0) | |
1614 | return r; | |
d8f52ed2 LP |
1615 | |
1616 | r = sd_bus_message_append(m, "s", unit); | |
1617 | if (r < 0) | |
1618 | return bus_log_create_error(r); | |
1619 | } | |
1620 | ||
1621 | r = sd_bus_message_close_container(m); | |
1622 | if (r < 0) | |
1623 | return bus_log_create_error(r); | |
1624 | ||
1625 | if (streq(argv[0], "enable")) | |
1626 | r = sd_bus_message_append(m, "bb", false, false); | |
1627 | else | |
1628 | r = sd_bus_message_append(m, "b", false); | |
1629 | if (r < 0) | |
1630 | return bus_log_create_error(r); | |
1631 | ||
1632 | r = sd_bus_call(bus, m, 0, &error, &reply); | |
1633 | if (r < 0) { | |
1634 | log_error("Failed to enable or disable unit: %s", bus_error_message(&error, -r)); | |
1635 | return r; | |
1636 | } | |
1637 | ||
1638 | if (streq(argv[0], "enable")) { | |
1639 | r = sd_bus_message_read(reply, "b", carries_install_info); | |
1640 | if (r < 0) | |
1641 | return bus_log_parse_error(r); | |
1642 | } | |
1643 | ||
57ab2eab | 1644 | r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); |
d8f52ed2 LP |
1645 | if (r < 0) |
1646 | return r; | |
1647 | ||
2723b3b5 | 1648 | r = sd_bus_call_method( |
d8f52ed2 | 1649 | bus, |
d8f52ed2 LP |
1650 | "org.freedesktop.systemd1", |
1651 | "/org/freedesktop/systemd1", | |
1652 | "org.freedesktop.systemd1.Manager", | |
2723b3b5 LP |
1653 | "Reload", |
1654 | &error, | |
1655 | NULL, | |
1656 | NULL); | |
d8f52ed2 LP |
1657 | if (r < 0) { |
1658 | log_error("Failed to reload daemon: %s", bus_error_message(&error, -r)); | |
1659 | return r; | |
1660 | } | |
1661 | ||
1662 | return 0; | |
1663 | } | |
1664 | ||
19070062 | 1665 | static int match_log_message(sd_bus_message *m, void *userdata, sd_bus_error *error) { |
6adf7b5e | 1666 | const char **our_path = userdata, *line; |
3d7415f4 LP |
1667 | unsigned priority; |
1668 | int r; | |
1669 | ||
3d7415f4 | 1670 | assert(m); |
6adf7b5e | 1671 | assert(our_path); |
3d7415f4 LP |
1672 | |
1673 | r = sd_bus_message_read(m, "us", &priority, &line); | |
1674 | if (r < 0) { | |
1675 | bus_log_parse_error(r); | |
1676 | return 0; | |
1677 | } | |
1678 | ||
6adf7b5e | 1679 | if (!streq_ptr(*our_path, sd_bus_message_get_path(m))) |
3d7415f4 LP |
1680 | return 0; |
1681 | ||
1682 | if (arg_quiet && LOG_PRI(priority) >= LOG_INFO) | |
1683 | return 0; | |
1684 | ||
1685 | log_full(priority, "%s", line); | |
1686 | return 0; | |
1687 | } | |
1688 | ||
19070062 | 1689 | static int match_transfer_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) { |
6adf7b5e | 1690 | const char **our_path = userdata, *path, *result; |
3d7415f4 LP |
1691 | uint32_t id; |
1692 | int r; | |
1693 | ||
3d7415f4 | 1694 | assert(m); |
6adf7b5e | 1695 | assert(our_path); |
3d7415f4 LP |
1696 | |
1697 | r = sd_bus_message_read(m, "uos", &id, &path, &result); | |
1698 | if (r < 0) { | |
1699 | bus_log_parse_error(r); | |
1700 | return 0; | |
1701 | } | |
1702 | ||
6adf7b5e | 1703 | if (!streq_ptr(*our_path, path)) |
3d7415f4 LP |
1704 | return 0; |
1705 | ||
19070062 | 1706 | sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), !streq_ptr(result, "done")); |
6adf7b5e LP |
1707 | return 0; |
1708 | } | |
1709 | ||
1710 | static int transfer_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { | |
1711 | assert(s); | |
1712 | assert(si); | |
1713 | ||
1714 | if (!arg_quiet) | |
cc98b302 | 1715 | log_info("Continuing download in the background. Use \"machinectl cancel-transfer %" PRIu32 "\" to abort transfer.", PTR_TO_UINT32(userdata)); |
6adf7b5e LP |
1716 | |
1717 | sd_event_exit(sd_event_source_get_event(s), EINTR); | |
3d7415f4 LP |
1718 | return 0; |
1719 | } | |
1720 | ||
587fec42 | 1721 | static int transfer_image_common(sd_bus *bus, sd_bus_message *m) { |
4afd3348 LP |
1722 | _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot_job_removed = NULL, *slot_log_message = NULL; |
1723 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; | |
1724 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; | |
1725 | _cleanup_(sd_event_unrefp) sd_event* event = NULL; | |
6adf7b5e | 1726 | const char *path = NULL; |
3d7415f4 LP |
1727 | uint32_t id; |
1728 | int r; | |
1729 | ||
1730 | assert(bus); | |
1731 | assert(m); | |
1732 | ||
1733 | polkit_agent_open_if_enabled(); | |
1734 | ||
6adf7b5e LP |
1735 | r = sd_event_default(&event); |
1736 | if (r < 0) | |
1737 | return log_error_errno(r, "Failed to get event loop: %m"); | |
1738 | ||
1739 | r = sd_bus_attach_event(bus, event, 0); | |
1740 | if (r < 0) | |
1741 | return log_error_errno(r, "Failed to attach bus to event loop: %m"); | |
1742 | ||
3d7415f4 LP |
1743 | r = sd_bus_add_match( |
1744 | bus, | |
1745 | &slot_job_removed, | |
1746 | "type='signal'," | |
1747 | "sender='org.freedesktop.import1'," | |
1748 | "interface='org.freedesktop.import1.Manager'," | |
1749 | "member='TransferRemoved'," | |
1750 | "path='/org/freedesktop/import1'", | |
6adf7b5e | 1751 | match_transfer_removed, &path); |
3d7415f4 LP |
1752 | if (r < 0) |
1753 | return log_error_errno(r, "Failed to install match: %m"); | |
1754 | ||
1755 | r = sd_bus_add_match( | |
1756 | bus, | |
1757 | &slot_log_message, | |
1758 | "type='signal'," | |
1759 | "sender='org.freedesktop.import1'," | |
1760 | "interface='org.freedesktop.import1.Transfer'," | |
1761 | "member='LogMessage'", | |
6adf7b5e | 1762 | match_log_message, &path); |
3d7415f4 LP |
1763 | if (r < 0) |
1764 | return log_error_errno(r, "Failed to install match: %m"); | |
1765 | ||
1766 | r = sd_bus_call(bus, m, 0, &error, &reply); | |
1767 | if (r < 0) { | |
587fec42 | 1768 | log_error("Failed transfer image: %s", bus_error_message(&error, -r)); |
3d7415f4 LP |
1769 | return r; |
1770 | } | |
1771 | ||
6adf7b5e | 1772 | r = sd_bus_message_read(reply, "uo", &id, &path); |
3d7415f4 LP |
1773 | if (r < 0) |
1774 | return bus_log_parse_error(r); | |
1775 | ||
72c0a2c2 | 1776 | assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0); |
3d7415f4 | 1777 | |
6adf7b5e LP |
1778 | if (!arg_quiet) |
1779 | log_info("Enqueued transfer job %u. Press C-c to continue download in background.", id); | |
3d7415f4 | 1780 | |
6adf7b5e LP |
1781 | sd_event_add_signal(event, NULL, SIGINT, transfer_signal_handler, UINT32_TO_PTR(id)); |
1782 | sd_event_add_signal(event, NULL, SIGTERM, transfer_signal_handler, UINT32_TO_PTR(id)); | |
1783 | ||
1784 | r = sd_event_loop(event); | |
1785 | if (r < 0) | |
1786 | return log_error_errno(r, "Failed to run event loop: %m"); | |
3d7415f4 | 1787 | |
6adf7b5e | 1788 | return -r; |
3d7415f4 LP |
1789 | } |
1790 | ||
b6e676ce | 1791 | static int import_tar(int argc, char *argv[], void *userdata) { |
4afd3348 | 1792 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; |
b6e676ce LP |
1793 | _cleanup_free_ char *ll = NULL; |
1794 | _cleanup_close_ int fd = -1; | |
1795 | const char *local = NULL, *path = NULL; | |
1796 | sd_bus *bus = userdata; | |
1797 | int r; | |
1798 | ||
1799 | assert(bus); | |
1800 | ||
1801 | if (argc >= 2) | |
1802 | path = argv[1]; | |
1803 | if (isempty(path) || streq(path, "-")) | |
1804 | path = NULL; | |
1805 | ||
1806 | if (argc >= 3) | |
1807 | local = argv[2]; | |
1808 | else if (path) | |
1809 | local = basename(path); | |
1810 | if (isempty(local) || streq(local, "-")) | |
1811 | local = NULL; | |
1812 | ||
1813 | if (!local) { | |
1814 | log_error("Need either path or local name."); | |
1815 | return -EINVAL; | |
1816 | } | |
1817 | ||
1818 | r = tar_strip_suffixes(local, &ll); | |
1819 | if (r < 0) | |
1820 | return log_oom(); | |
1821 | ||
1822 | local = ll; | |
1823 | ||
1824 | if (!machine_name_is_valid(local)) { | |
1825 | log_error("Local name %s is not a suitable machine name.", local); | |
1826 | return -EINVAL; | |
1827 | } | |
1828 | ||
1829 | if (path) { | |
1830 | fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY); | |
1831 | if (fd < 0) | |
1832 | return log_error_errno(errno, "Failed to open %s: %m", path); | |
1833 | } | |
1834 | ||
1835 | r = sd_bus_message_new_method_call( | |
1836 | bus, | |
1837 | &m, | |
1838 | "org.freedesktop.import1", | |
1839 | "/org/freedesktop/import1", | |
1840 | "org.freedesktop.import1.Manager", | |
1841 | "ImportTar"); | |
1842 | if (r < 0) | |
1843 | return bus_log_create_error(r); | |
1844 | ||
1845 | r = sd_bus_message_append( | |
1846 | m, | |
1847 | "hsbb", | |
1848 | fd >= 0 ? fd : STDIN_FILENO, | |
1849 | local, | |
1850 | arg_force, | |
1851 | arg_read_only); | |
1852 | if (r < 0) | |
1853 | return bus_log_create_error(r); | |
1854 | ||
587fec42 | 1855 | return transfer_image_common(bus, m); |
b6e676ce LP |
1856 | } |
1857 | ||
1858 | static int import_raw(int argc, char *argv[], void *userdata) { | |
4afd3348 | 1859 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; |
b6e676ce LP |
1860 | _cleanup_free_ char *ll = NULL; |
1861 | _cleanup_close_ int fd = -1; | |
1862 | const char *local = NULL, *path = NULL; | |
1863 | sd_bus *bus = userdata; | |
1864 | int r; | |
1865 | ||
1866 | assert(bus); | |
1867 | ||
1868 | if (argc >= 2) | |
1869 | path = argv[1]; | |
1870 | if (isempty(path) || streq(path, "-")) | |
1871 | path = NULL; | |
1872 | ||
1873 | if (argc >= 3) | |
1874 | local = argv[2]; | |
1875 | else if (path) | |
1876 | local = basename(path); | |
1877 | if (isempty(local) || streq(local, "-")) | |
1878 | local = NULL; | |
1879 | ||
1880 | if (!local) { | |
1881 | log_error("Need either path or local name."); | |
1882 | return -EINVAL; | |
1883 | } | |
1884 | ||
1885 | r = raw_strip_suffixes(local, &ll); | |
1886 | if (r < 0) | |
1887 | return log_oom(); | |
1888 | ||
1889 | local = ll; | |
1890 | ||
1891 | if (!machine_name_is_valid(local)) { | |
1892 | log_error("Local name %s is not a suitable machine name.", local); | |
1893 | return -EINVAL; | |
1894 | } | |
1895 | ||
1896 | if (path) { | |
1897 | fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY); | |
1898 | if (fd < 0) | |
1899 | return log_error_errno(errno, "Failed to open %s: %m", path); | |
1900 | } | |
1901 | ||
1902 | r = sd_bus_message_new_method_call( | |
1903 | bus, | |
1904 | &m, | |
1905 | "org.freedesktop.import1", | |
1906 | "/org/freedesktop/import1", | |
1907 | "org.freedesktop.import1.Manager", | |
1908 | "ImportRaw"); | |
1909 | if (r < 0) | |
1910 | return bus_log_create_error(r); | |
1911 | ||
1912 | r = sd_bus_message_append( | |
1913 | m, | |
1914 | "hsbb", | |
1915 | fd >= 0 ? fd : STDIN_FILENO, | |
1916 | local, | |
1917 | arg_force, | |
1918 | arg_read_only); | |
1919 | if (r < 0) | |
1920 | return bus_log_create_error(r); | |
1921 | ||
587fec42 LP |
1922 | return transfer_image_common(bus, m); |
1923 | } | |
1924 | ||
1925 | static void determine_compression_from_filename(const char *p) { | |
1926 | if (arg_format) | |
1927 | return; | |
1928 | ||
1929 | if (!p) | |
1930 | return; | |
1931 | ||
1932 | if (endswith(p, ".xz")) | |
1933 | arg_format = "xz"; | |
1934 | else if (endswith(p, ".gz")) | |
1935 | arg_format = "gzip"; | |
1936 | else if (endswith(p, ".bz2")) | |
1937 | arg_format = "bzip2"; | |
1938 | } | |
1939 | ||
1940 | static int export_tar(int argc, char *argv[], void *userdata) { | |
4afd3348 | 1941 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; |
587fec42 LP |
1942 | _cleanup_close_ int fd = -1; |
1943 | const char *local = NULL, *path = NULL; | |
1944 | sd_bus *bus = userdata; | |
1945 | int r; | |
1946 | ||
1947 | assert(bus); | |
1948 | ||
1949 | local = argv[1]; | |
1950 | if (!machine_name_is_valid(local)) { | |
1951 | log_error("Machine name %s is not valid.", local); | |
1952 | return -EINVAL; | |
1953 | } | |
1954 | ||
1955 | if (argc >= 3) | |
1956 | path = argv[2]; | |
1957 | if (isempty(path) || streq(path, "-")) | |
1958 | path = NULL; | |
1959 | ||
1960 | if (path) { | |
1961 | determine_compression_from_filename(path); | |
1962 | ||
1963 | fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666); | |
1964 | if (fd < 0) | |
1965 | return log_error_errno(errno, "Failed to open %s: %m", path); | |
1966 | } | |
1967 | ||
1968 | r = sd_bus_message_new_method_call( | |
1969 | bus, | |
1970 | &m, | |
1971 | "org.freedesktop.import1", | |
1972 | "/org/freedesktop/import1", | |
1973 | "org.freedesktop.import1.Manager", | |
1974 | "ExportTar"); | |
1975 | if (r < 0) | |
1976 | return bus_log_create_error(r); | |
1977 | ||
1978 | r = sd_bus_message_append( | |
1979 | m, | |
1980 | "shs", | |
1981 | local, | |
1982 | fd >= 0 ? fd : STDOUT_FILENO, | |
1983 | arg_format); | |
1984 | if (r < 0) | |
1985 | return bus_log_create_error(r); | |
1986 | ||
1987 | return transfer_image_common(bus, m); | |
1988 | } | |
1989 | ||
1990 | static int export_raw(int argc, char *argv[], void *userdata) { | |
4afd3348 | 1991 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; |
587fec42 LP |
1992 | _cleanup_close_ int fd = -1; |
1993 | const char *local = NULL, *path = NULL; | |
1994 | sd_bus *bus = userdata; | |
1995 | int r; | |
1996 | ||
1997 | assert(bus); | |
1998 | ||
1999 | local = argv[1]; | |
2000 | if (!machine_name_is_valid(local)) { | |
2001 | log_error("Machine name %s is not valid.", local); | |
2002 | return -EINVAL; | |
2003 | } | |
2004 | ||
2005 | if (argc >= 3) | |
2006 | path = argv[2]; | |
2007 | if (isempty(path) || streq(path, "-")) | |
2008 | path = NULL; | |
2009 | ||
2010 | if (path) { | |
2011 | determine_compression_from_filename(path); | |
2012 | ||
2013 | fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666); | |
2014 | if (fd < 0) | |
2015 | return log_error_errno(errno, "Failed to open %s: %m", path); | |
2016 | } | |
2017 | ||
2018 | r = sd_bus_message_new_method_call( | |
2019 | bus, | |
2020 | &m, | |
2021 | "org.freedesktop.import1", | |
2022 | "/org/freedesktop/import1", | |
2023 | "org.freedesktop.import1.Manager", | |
2024 | "ExportRaw"); | |
2025 | if (r < 0) | |
2026 | return bus_log_create_error(r); | |
2027 | ||
2028 | r = sd_bus_message_append( | |
2029 | m, | |
2030 | "shs", | |
2031 | local, | |
2032 | fd >= 0 ? fd : STDOUT_FILENO, | |
2033 | arg_format); | |
2034 | if (r < 0) | |
2035 | return bus_log_create_error(r); | |
2036 | ||
2037 | return transfer_image_common(bus, m); | |
b6e676ce LP |
2038 | } |
2039 | ||
3d7415f4 | 2040 | static int pull_tar(int argc, char *argv[], void *userdata) { |
4afd3348 | 2041 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; |
3d7415f4 LP |
2042 | _cleanup_free_ char *l = NULL, *ll = NULL; |
2043 | const char *local, *remote; | |
2044 | sd_bus *bus = userdata; | |
2045 | int r; | |
2046 | ||
2047 | assert(bus); | |
2048 | ||
2049 | remote = argv[1]; | |
2050 | if (!http_url_is_valid(remote)) { | |
2051 | log_error("URL '%s' is not valid.", remote); | |
2052 | return -EINVAL; | |
2053 | } | |
2054 | ||
2055 | if (argc >= 3) | |
2056 | local = argv[2]; | |
2057 | else { | |
2058 | r = import_url_last_component(remote, &l); | |
2059 | if (r < 0) | |
2060 | return log_error_errno(r, "Failed to get final component of URL: %m"); | |
2061 | ||
2062 | local = l; | |
2063 | } | |
2064 | ||
2065 | if (isempty(local) || streq(local, "-")) | |
2066 | local = NULL; | |
2067 | ||
2068 | if (local) { | |
2069 | r = tar_strip_suffixes(local, &ll); | |
2070 | if (r < 0) | |
b6e676ce | 2071 | return log_oom(); |
3d7415f4 LP |
2072 | |
2073 | local = ll; | |
2074 | ||
2075 | if (!machine_name_is_valid(local)) { | |
2076 | log_error("Local name %s is not a suitable machine name.", local); | |
2077 | return -EINVAL; | |
2078 | } | |
2079 | } | |
2080 | ||
2081 | r = sd_bus_message_new_method_call( | |
2082 | bus, | |
2083 | &m, | |
2084 | "org.freedesktop.import1", | |
2085 | "/org/freedesktop/import1", | |
2086 | "org.freedesktop.import1.Manager", | |
2087 | "PullTar"); | |
2088 | if (r < 0) | |
2089 | return bus_log_create_error(r); | |
2090 | ||
2091 | r = sd_bus_message_append( | |
2092 | m, | |
2093 | "sssb", | |
2094 | remote, | |
2095 | local, | |
6e18cc9f | 2096 | import_verify_to_string(arg_verify), |
3d7415f4 LP |
2097 | arg_force); |
2098 | if (r < 0) | |
2099 | return bus_log_create_error(r); | |
2100 | ||
587fec42 | 2101 | return transfer_image_common(bus, m); |
3d7415f4 LP |
2102 | } |
2103 | ||
2104 | static int pull_raw(int argc, char *argv[], void *userdata) { | |
4afd3348 | 2105 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; |
3d7415f4 LP |
2106 | _cleanup_free_ char *l = NULL, *ll = NULL; |
2107 | const char *local, *remote; | |
2108 | sd_bus *bus = userdata; | |
2109 | int r; | |
2110 | ||
2111 | assert(bus); | |
2112 | ||
2113 | remote = argv[1]; | |
2114 | if (!http_url_is_valid(remote)) { | |
2115 | log_error("URL '%s' is not valid.", remote); | |
2116 | return -EINVAL; | |
2117 | } | |
2118 | ||
2119 | if (argc >= 3) | |
2120 | local = argv[2]; | |
2121 | else { | |
2122 | r = import_url_last_component(remote, &l); | |
2123 | if (r < 0) | |
2124 | return log_error_errno(r, "Failed to get final component of URL: %m"); | |
2125 | ||
2126 | local = l; | |
2127 | } | |
2128 | ||
2129 | if (isempty(local) || streq(local, "-")) | |
2130 | local = NULL; | |
2131 | ||
2132 | if (local) { | |
2133 | r = raw_strip_suffixes(local, &ll); | |
2134 | if (r < 0) | |
b6e676ce | 2135 | return log_oom(); |
3d7415f4 LP |
2136 | |
2137 | local = ll; | |
2138 | ||
2139 | if (!machine_name_is_valid(local)) { | |
2140 | log_error("Local name %s is not a suitable machine name.", local); | |
2141 | return -EINVAL; | |
2142 | } | |
2143 | } | |
2144 | ||
2145 | r = sd_bus_message_new_method_call( | |
2146 | bus, | |
2147 | &m, | |
2148 | "org.freedesktop.import1", | |
2149 | "/org/freedesktop/import1", | |
2150 | "org.freedesktop.import1.Manager", | |
2151 | "PullRaw"); | |
2152 | if (r < 0) | |
2153 | return bus_log_create_error(r); | |
2154 | ||
2155 | r = sd_bus_message_append( | |
2156 | m, | |
2157 | "sssb", | |
2158 | remote, | |
2159 | local, | |
6e18cc9f | 2160 | import_verify_to_string(arg_verify), |
3d7415f4 LP |
2161 | arg_force); |
2162 | if (r < 0) | |
2163 | return bus_log_create_error(r); | |
2164 | ||
587fec42 | 2165 | return transfer_image_common(bus, m); |
3d7415f4 LP |
2166 | } |
2167 | ||
3d7415f4 LP |
2168 | typedef struct TransferInfo { |
2169 | uint32_t id; | |
2170 | const char *type; | |
2171 | const char *remote; | |
2172 | const char *local; | |
7079cfef | 2173 | double progress; |
3d7415f4 LP |
2174 | } TransferInfo; |
2175 | ||
2176 | static int compare_transfer_info(const void *a, const void *b) { | |
2177 | const TransferInfo *x = a, *y = b; | |
2178 | ||
2179 | return strcmp(x->local, y->local); | |
2180 | } | |
2181 | ||
2182 | static int list_transfers(int argc, char *argv[], void *userdata) { | |
2183 | size_t max_type = strlen("TYPE"), max_local = strlen("LOCAL"), max_remote = strlen("REMOTE"); | |
4afd3348 LP |
2184 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; |
2185 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; | |
3d7415f4 LP |
2186 | _cleanup_free_ TransferInfo *transfers = NULL; |
2187 | size_t n_transfers = 0, n_allocated = 0, j; | |
2188 | const char *type, *remote, *local, *object; | |
2189 | sd_bus *bus = userdata; | |
2190 | uint32_t id, max_id = 0; | |
7079cfef | 2191 | double progress; |
3d7415f4 LP |
2192 | int r; |
2193 | ||
2194 | pager_open_if_enabled(); | |
2195 | ||
2196 | r = sd_bus_call_method( | |
2197 | bus, | |
2198 | "org.freedesktop.import1", | |
2199 | "/org/freedesktop/import1", | |
2200 | "org.freedesktop.import1.Manager", | |
2201 | "ListTransfers", | |
2202 | &error, | |
2203 | &reply, | |
2204 | NULL); | |
2205 | if (r < 0) { | |
2206 | log_error("Could not get transfers: %s", bus_error_message(&error, -r)); | |
2207 | return r; | |
2208 | } | |
2209 | ||
7079cfef | 2210 | r = sd_bus_message_enter_container(reply, 'a', "(usssdo)"); |
3d7415f4 LP |
2211 | if (r < 0) |
2212 | return bus_log_parse_error(r); | |
2213 | ||
7079cfef | 2214 | while ((r = sd_bus_message_read(reply, "(usssdo)", &id, &type, &remote, &local, &progress, &object)) > 0) { |
3d7415f4 LP |
2215 | size_t l; |
2216 | ||
2217 | if (!GREEDY_REALLOC(transfers, n_allocated, n_transfers + 1)) | |
2218 | return log_oom(); | |
2219 | ||
2220 | transfers[n_transfers].id = id; | |
2221 | transfers[n_transfers].type = type; | |
2222 | transfers[n_transfers].remote = remote; | |
2223 | transfers[n_transfers].local = local; | |
7079cfef | 2224 | transfers[n_transfers].progress = progress; |
3d7415f4 LP |
2225 | |
2226 | l = strlen(type); | |
2227 | if (l > max_type) | |
2228 | max_type = l; | |
2229 | ||
2230 | l = strlen(remote); | |
2231 | if (l > max_remote) | |
2232 | max_remote = l; | |
2233 | ||
2234 | l = strlen(local); | |
2235 | if (l > max_local) | |
2236 | max_local = l; | |
2237 | ||
2238 | if (id > max_id) | |
2239 | max_id = id; | |
2240 | ||
2241 | n_transfers ++; | |
2242 | } | |
2243 | if (r < 0) | |
2244 | return bus_log_parse_error(r); | |
2245 | ||
2246 | r = sd_bus_message_exit_container(reply); | |
2247 | if (r < 0) | |
2248 | return bus_log_parse_error(r); | |
2249 | ||
2250 | qsort_safe(transfers, n_transfers, sizeof(TransferInfo), compare_transfer_info); | |
2251 | ||
2252 | if (arg_legend) | |
7079cfef | 2253 | printf("%-*s %-*s %-*s %-*s %-*s\n", |
3d7415f4 | 2254 | (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), "ID", |
7079cfef | 2255 | (int) 7, "PERCENT", |
3d7415f4 LP |
2256 | (int) max_type, "TYPE", |
2257 | (int) max_local, "LOCAL", | |
2258 | (int) max_remote, "REMOTE"); | |
2259 | ||
2260 | for (j = 0; j < n_transfers; j++) | |
7079cfef | 2261 | printf("%*" PRIu32 " %*u%% %-*s %-*s %-*s\n", |
3d7415f4 | 2262 | (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id, |
7079cfef | 2263 | (int) 6, (unsigned) (transfers[j].progress * 100), |
3d7415f4 LP |
2264 | (int) max_type, transfers[j].type, |
2265 | (int) max_local, transfers[j].local, | |
2266 | (int) max_remote, transfers[j].remote); | |
2267 | ||
2268 | if (arg_legend) | |
2269 | printf("\n%zu transfers listed.\n", n_transfers); | |
2270 | ||
2271 | return 0; | |
2272 | } | |
2273 | ||
2274 | static int cancel_transfer(int argc, char *argv[], void *userdata) { | |
4afd3348 | 2275 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
3d7415f4 LP |
2276 | sd_bus *bus = userdata; |
2277 | int r, i; | |
2278 | ||
2279 | assert(bus); | |
2280 | ||
2281 | polkit_agent_open_if_enabled(); | |
2282 | ||
2283 | for (i = 1; i < argc; i++) { | |
2284 | uint32_t id; | |
2285 | ||
2286 | r = safe_atou32(argv[i], &id); | |
2287 | if (r < 0) | |
2288 | return log_error_errno(r, "Failed to parse transfer id: %s", argv[i]); | |
2289 | ||
2290 | r = sd_bus_call_method( | |
2291 | bus, | |
2292 | "org.freedesktop.import1", | |
2293 | "/org/freedesktop/import1", | |
2294 | "org.freedesktop.import1.Manager", | |
2295 | "CancelTransfer", | |
2296 | &error, | |
2297 | NULL, | |
2298 | "u", id); | |
2299 | if (r < 0) { | |
2300 | log_error("Could not cancel transfer: %s", bus_error_message(&error, -r)); | |
2301 | return r; | |
2302 | } | |
2303 | } | |
2304 | ||
2305 | return 0; | |
2306 | } | |
2307 | ||
d6ce17c7 | 2308 | static int set_limit(int argc, char *argv[], void *userdata) { |
4afd3348 | 2309 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
d6ce17c7 LP |
2310 | sd_bus *bus = userdata; |
2311 | uint64_t limit; | |
2312 | int r; | |
2313 | ||
7705a405 | 2314 | if (STR_IN_SET(argv[argc-1], "-", "none", "infinity")) |
d6ce17c7 LP |
2315 | limit = (uint64_t) -1; |
2316 | else { | |
59f448cf | 2317 | r = parse_size(argv[argc-1], 1024, &limit); |
d6ce17c7 LP |
2318 | if (r < 0) |
2319 | return log_error("Failed to parse size: %s", argv[argc-1]); | |
d6ce17c7 LP |
2320 | } |
2321 | ||
2322 | if (argc > 2) | |
2323 | /* With two arguments changes the quota limit of the | |
2324 | * specified image */ | |
2325 | r = sd_bus_call_method( | |
2326 | bus, | |
2327 | "org.freedesktop.machine1", | |
2328 | "/org/freedesktop/machine1", | |
2329 | "org.freedesktop.machine1.Manager", | |
2330 | "SetImageLimit", | |
2331 | &error, | |
2332 | NULL, | |
2333 | "st", argv[1], limit); | |
2334 | else | |
2335 | /* With one argument changes the pool quota limit */ | |
2336 | r = sd_bus_call_method( | |
2337 | bus, | |
2338 | "org.freedesktop.machine1", | |
2339 | "/org/freedesktop/machine1", | |
2340 | "org.freedesktop.machine1.Manager", | |
2341 | "SetPoolLimit", | |
2342 | &error, | |
2343 | NULL, | |
2344 | "t", limit); | |
2345 | ||
2346 | if (r < 0) { | |
2347 | log_error("Could not set limit: %s", bus_error_message(&error, -r)); | |
2348 | return r; | |
2349 | } | |
2350 | ||
2351 | return 0; | |
2352 | } | |
2353 | ||
56159e0d LP |
2354 | static int help(int argc, char *argv[], void *userdata) { |
2355 | ||
1ee306e1 | 2356 | printf("%s [OPTIONS...] {COMMAND} ...\n\n" |
f2cbe59e LP |
2357 | "Send control commands to or query the virtual machine and container\n" |
2358 | "registration manager.\n\n" | |
2359 | " -h --help Show this help\n" | |
2360 | " --version Show package version\n" | |
2361 | " --no-pager Do not pipe output into a pager\n" | |
2362 | " --no-legend Do not show the headers and footers\n" | |
acf97e21 | 2363 | " --no-ask-password Do not ask for system passwords\n" |
f2cbe59e LP |
2364 | " -H --host=[USER@]HOST Operate on remote host\n" |
2365 | " -M --machine=CONTAINER Operate on local container\n" | |
2366 | " -p --property=NAME Show only properties by this name\n" | |
d8f52ed2 | 2367 | " -q --quiet Suppress output\n" |
f2cbe59e LP |
2368 | " -a --all Show all properties, including empty ones\n" |
2369 | " -l --full Do not ellipsize output\n" | |
2370 | " --kill-who=WHO Who to send signal to\n" | |
2371 | " -s --signal=SIGNAL Which signal to send\n" | |
c454426c LP |
2372 | " --uid=USER Specify user ID to invoke shell as\n" |
2373 | " --setenv=VAR=VALUE Add an environment variable for shell\n" | |
f2cbe59e | 2374 | " --read-only Create read-only bind mount\n" |
8b0cc9a3 LP |
2375 | " --mkdir Create directory before bind mounting, if missing\n" |
2376 | " -n --lines=INTEGER Number of journal entries to show\n" | |
2377 | " -o --output=STRING Change journal output mode (short,\n" | |
2378 | " short-monotonic, verbose, export, json,\n" | |
3d7415f4 | 2379 | " json-pretty, json-sse, cat)\n" |
7f444afa LP |
2380 | " --verify=MODE Verification mode for downloaded images (no,\n" |
2381 | " checksum, signature)\n" | |
b43d75c3 | 2382 | " --force Download image even if already exists\n\n" |
cd61c3bf | 2383 | "Machine Commands:\n" |
f2cbe59e | 2384 | " list List running VMs and containers\n" |
fefdc04b | 2385 | " status NAME... Show VM/container details\n" |
91913f58 | 2386 | " show [NAME...] Show properties of one or more VMs/containers\n" |
ebd011d9 | 2387 | " start NAME... Start container as a service\n" |
91913f58 LP |
2388 | " login [NAME] Get a login prompt in a container or on the\n" |
2389 | " local host\n" | |
ef3100e9 LP |
2390 | " shell [[USER@]NAME [COMMAND...]]\n" |
2391 | " Invoke a shell (or other command) in a container\n" | |
2392 | " or on the local host\n" | |
d8f52ed2 LP |
2393 | " enable NAME... Enable automatic container start at boot\n" |
2394 | " disable NAME... Disable automatic container start at boot\n" | |
f2cbe59e LP |
2395 | " poweroff NAME... Power off one or more containers\n" |
2396 | " reboot NAME... Reboot one or more containers\n" | |
f2cbe59e | 2397 | " terminate NAME... Terminate one or more VMs/containers\n" |
ebd93cb6 | 2398 | " kill NAME... Send signal to processes of a VM/container\n" |
f2cbe59e | 2399 | " copy-to NAME PATH [PATH] Copy files from the host to a container\n" |
ebd93cb6 LP |
2400 | " copy-from NAME PATH [PATH] Copy files from a container to the host\n" |
2401 | " bind NAME PATH [PATH] Bind mount a path from the host into a container\n\n" | |
fefdc04b | 2402 | "Image Commands:\n" |
56b921c3 | 2403 | " list-images Show available container and VM images\n" |
91913f58 LP |
2404 | " image-status [NAME...] Show image details\n" |
2405 | " show-image [NAME...] Show properties of image\n" | |
ebd93cb6 LP |
2406 | " clone NAME NAME Clone an image\n" |
2407 | " rename NAME NAME Rename an image\n" | |
2408 | " read-only NAME [BOOL] Mark or unmark image read-only\n" | |
d6ce17c7 | 2409 | " remove NAME... Remove an image\n" |
e721d697 | 2410 | " set-limit [NAME] BYTES Set image or pool size limit (disk quota)\n\n" |
b5b38b41 LP |
2411 | "Image Transfer Commands:\n" |
2412 | " pull-tar URL [NAME] Download a TAR container image\n" | |
2413 | " pull-raw URL [NAME] Download a RAW container or VM image\n" | |
587fec42 LP |
2414 | " import-tar FILE [NAME] Import a local TAR container image\n" |
2415 | " import-raw FILE [NAME] Import a local RAW container or VM image\n" | |
6e9efa59 LP |
2416 | " export-tar NAME [FILE] Export a TAR container image locally\n" |
2417 | " export-raw NAME [FILE] Export a RAW container or VM image locally\n" | |
b5b38b41 | 2418 | " list-transfers Show list of downloads in progress\n" |
3d7415f4 | 2419 | " cancel-transfer Cancel a download\n" |
f7621db0 | 2420 | , program_invocation_short_name); |
56159e0d LP |
2421 | |
2422 | return 0; | |
1ee306e1 LP |
2423 | } |
2424 | ||
2425 | static int parse_argv(int argc, char *argv[]) { | |
2426 | ||
2427 | enum { | |
2428 | ARG_VERSION = 0x100, | |
2429 | ARG_NO_PAGER, | |
e56056e9 | 2430 | ARG_NO_LEGEND, |
1ee306e1 | 2431 | ARG_KILL_WHO, |
785890ac LP |
2432 | ARG_READ_ONLY, |
2433 | ARG_MKDIR, | |
acf97e21 | 2434 | ARG_NO_ASK_PASSWORD, |
3d7415f4 LP |
2435 | ARG_VERIFY, |
2436 | ARG_FORCE, | |
587fec42 | 2437 | ARG_FORMAT, |
c454426c LP |
2438 | ARG_UID, |
2439 | ARG_SETENV, | |
1ee306e1 LP |
2440 | }; |
2441 | ||
2442 | static const struct option options[] = { | |
2443 | { "help", no_argument, NULL, 'h' }, | |
2444 | { "version", no_argument, NULL, ARG_VERSION }, | |
2445 | { "property", required_argument, NULL, 'p' }, | |
2446 | { "all", no_argument, NULL, 'a' }, | |
2447 | { "full", no_argument, NULL, 'l' }, | |
2448 | { "no-pager", no_argument, NULL, ARG_NO_PAGER }, | |
e56056e9 | 2449 | { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, |
1ee306e1 LP |
2450 | { "kill-who", required_argument, NULL, ARG_KILL_WHO }, |
2451 | { "signal", required_argument, NULL, 's' }, | |
2452 | { "host", required_argument, NULL, 'H' }, | |
a7893c6b | 2453 | { "machine", required_argument, NULL, 'M' }, |
785890ac LP |
2454 | { "read-only", no_argument, NULL, ARG_READ_ONLY }, |
2455 | { "mkdir", no_argument, NULL, ARG_MKDIR }, | |
d8f52ed2 | 2456 | { "quiet", no_argument, NULL, 'q' }, |
8b0cc9a3 LP |
2457 | { "lines", required_argument, NULL, 'n' }, |
2458 | { "output", required_argument, NULL, 'o' }, | |
acf97e21 | 2459 | { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, |
3d7415f4 LP |
2460 | { "verify", required_argument, NULL, ARG_VERIFY }, |
2461 | { "force", no_argument, NULL, ARG_FORCE }, | |
587fec42 | 2462 | { "format", required_argument, NULL, ARG_FORMAT }, |
c454426c LP |
2463 | { "uid", required_argument, NULL, ARG_UID }, |
2464 | { "setenv", required_argument, NULL, ARG_SETENV }, | |
eb9da376 | 2465 | {} |
1ee306e1 LP |
2466 | }; |
2467 | ||
a7893c6b | 2468 | int c, r; |
1ee306e1 LP |
2469 | |
2470 | assert(argc >= 0); | |
2471 | assert(argv); | |
2472 | ||
8b0cc9a3 | 2473 | while ((c = getopt_long(argc, argv, "hp:als:H:M:qn:o:", options, NULL)) >= 0) |
1ee306e1 LP |
2474 | |
2475 | switch (c) { | |
2476 | ||
2477 | case 'h': | |
56159e0d | 2478 | return help(0, NULL, NULL); |
1ee306e1 LP |
2479 | |
2480 | case ARG_VERSION: | |
3f6fd1ba | 2481 | return version(); |
1ee306e1 | 2482 | |
a7893c6b LP |
2483 | case 'p': |
2484 | r = strv_extend(&arg_property, optarg); | |
2485 | if (r < 0) | |
2486 | return log_oom(); | |
1ee306e1 LP |
2487 | |
2488 | /* If the user asked for a particular | |
2489 | * property, show it to him, even if it is | |
2490 | * empty. */ | |
2491 | arg_all = true; | |
2492 | break; | |
1ee306e1 LP |
2493 | |
2494 | case 'a': | |
2495 | arg_all = true; | |
2496 | break; | |
2497 | ||
2498 | case 'l': | |
2499 | arg_full = true; | |
2500 | break; | |
2501 | ||
8b0cc9a3 LP |
2502 | case 'n': |
2503 | if (safe_atou(optarg, &arg_lines) < 0) { | |
2504 | log_error("Failed to parse lines '%s'", optarg); | |
2505 | return -EINVAL; | |
2506 | } | |
2507 | break; | |
2508 | ||
2509 | case 'o': | |
2510 | arg_output = output_mode_from_string(optarg); | |
2511 | if (arg_output < 0) { | |
2512 | log_error("Unknown output '%s'.", optarg); | |
2513 | return -EINVAL; | |
2514 | } | |
2515 | break; | |
2516 | ||
1ee306e1 LP |
2517 | case ARG_NO_PAGER: |
2518 | arg_no_pager = true; | |
2519 | break; | |
2520 | ||
e56056e9 TA |
2521 | case ARG_NO_LEGEND: |
2522 | arg_legend = false; | |
2523 | break; | |
2524 | ||
1ee306e1 LP |
2525 | case ARG_KILL_WHO: |
2526 | arg_kill_who = optarg; | |
2527 | break; | |
2528 | ||
2529 | case 's': | |
2530 | arg_signal = signal_from_string_try_harder(optarg); | |
2531 | if (arg_signal < 0) { | |
2532 | log_error("Failed to parse signal string %s.", optarg); | |
2533 | return -EINVAL; | |
2534 | } | |
2535 | break; | |
2536 | ||
acf97e21 LP |
2537 | case ARG_NO_ASK_PASSWORD: |
2538 | arg_ask_password = false; | |
2539 | break; | |
2540 | ||
1ee306e1 | 2541 | case 'H': |
d21ed1ea | 2542 | arg_transport = BUS_TRANSPORT_REMOTE; |
a7893c6b LP |
2543 | arg_host = optarg; |
2544 | break; | |
2545 | ||
2546 | case 'M': | |
de33fc62 | 2547 | arg_transport = BUS_TRANSPORT_MACHINE; |
a7893c6b | 2548 | arg_host = optarg; |
1ee306e1 LP |
2549 | break; |
2550 | ||
785890ac LP |
2551 | case ARG_READ_ONLY: |
2552 | arg_read_only = true; | |
2553 | break; | |
2554 | ||
2555 | case ARG_MKDIR: | |
2556 | arg_mkdir = true; | |
2557 | break; | |
2558 | ||
d8f52ed2 LP |
2559 | case 'q': |
2560 | arg_quiet = true; | |
2561 | break; | |
2562 | ||
3d7415f4 | 2563 | case ARG_VERIFY: |
6e18cc9f LP |
2564 | arg_verify = import_verify_from_string(optarg); |
2565 | if (arg_verify < 0) { | |
2566 | log_error("Failed to parse --verify= setting: %s", optarg); | |
2567 | return -EINVAL; | |
2568 | } | |
3d7415f4 LP |
2569 | break; |
2570 | ||
2571 | case ARG_FORCE: | |
2572 | arg_force = true; | |
2573 | break; | |
2574 | ||
587fec42 LP |
2575 | case ARG_FORMAT: |
2576 | if (!STR_IN_SET(optarg, "uncompressed", "xz", "gzip", "bzip2")) { | |
2577 | log_error("Unknown format: %s", optarg); | |
2578 | return -EINVAL; | |
2579 | } | |
2580 | ||
2581 | arg_format = optarg; | |
2582 | break; | |
2583 | ||
c454426c LP |
2584 | case ARG_UID: |
2585 | arg_uid = optarg; | |
2586 | break; | |
2587 | ||
2588 | case ARG_SETENV: | |
2589 | if (!env_assignment_is_valid(optarg)) { | |
2590 | log_error("Environment assignment invalid: %s", optarg); | |
2591 | return -EINVAL; | |
2592 | } | |
2593 | ||
2594 | r = strv_extend(&arg_setenv, optarg); | |
2595 | if (r < 0) | |
2596 | return log_oom(); | |
2597 | break; | |
2598 | ||
1ee306e1 LP |
2599 | case '?': |
2600 | return -EINVAL; | |
2601 | ||
2602 | default: | |
eb9da376 | 2603 | assert_not_reached("Unhandled option"); |
1ee306e1 | 2604 | } |
1ee306e1 LP |
2605 | |
2606 | return 1; | |
2607 | } | |
2608 | ||
56159e0d LP |
2609 | static int machinectl_main(int argc, char *argv[], sd_bus *bus) { |
2610 | ||
2611 | static const Verb verbs[] = { | |
3d7415f4 LP |
2612 | { "help", VERB_ANY, VERB_ANY, 0, help }, |
2613 | { "list", VERB_ANY, 1, VERB_DEFAULT, list_machines }, | |
2614 | { "list-images", VERB_ANY, 1, 0, list_images }, | |
2615 | { "status", 2, VERB_ANY, 0, show_machine }, | |
160e3793 | 2616 | { "image-status", VERB_ANY, VERB_ANY, 0, show_image }, |
3d7415f4 LP |
2617 | { "show", VERB_ANY, VERB_ANY, 0, show_machine }, |
2618 | { "show-image", VERB_ANY, VERB_ANY, 0, show_image }, | |
2619 | { "terminate", 2, VERB_ANY, 0, terminate_machine }, | |
2620 | { "reboot", 2, VERB_ANY, 0, reboot_machine }, | |
2621 | { "poweroff", 2, VERB_ANY, 0, poweroff_machine }, | |
2622 | { "kill", 2, VERB_ANY, 0, kill_machine }, | |
91913f58 LP |
2623 | { "login", VERB_ANY, 2, 0, login_machine }, |
2624 | { "shell", VERB_ANY, VERB_ANY, 0, shell_machine }, | |
3d7415f4 LP |
2625 | { "bind", 3, 4, 0, bind_mount }, |
2626 | { "copy-to", 3, 4, 0, copy_files }, | |
2627 | { "copy-from", 3, 4, 0, copy_files }, | |
2628 | { "remove", 2, VERB_ANY, 0, remove_image }, | |
2629 | { "rename", 3, 3, 0, rename_image }, | |
2630 | { "clone", 3, 3, 0, clone_image }, | |
2631 | { "read-only", 2, 3, 0, read_only_image }, | |
2632 | { "start", 2, VERB_ANY, 0, start_machine }, | |
2633 | { "enable", 2, VERB_ANY, 0, enable_machine }, | |
2634 | { "disable", 2, VERB_ANY, 0, enable_machine }, | |
b6e676ce LP |
2635 | { "import-tar", 2, 3, 0, import_tar }, |
2636 | { "import-raw", 2, 3, 0, import_raw }, | |
587fec42 LP |
2637 | { "export-tar", 2, 3, 0, export_tar }, |
2638 | { "export-raw", 2, 3, 0, export_raw }, | |
3d7415f4 LP |
2639 | { "pull-tar", 2, 3, 0, pull_tar }, |
2640 | { "pull-raw", 2, 3, 0, pull_raw }, | |
3d7415f4 LP |
2641 | { "list-transfers", VERB_ANY, 1, 0, list_transfers }, |
2642 | { "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer }, | |
d6ce17c7 | 2643 | { "set-limit", 2, 3, 0, set_limit }, |
56159e0d | 2644 | {} |
1ee306e1 LP |
2645 | }; |
2646 | ||
56159e0d | 2647 | return dispatch_verb(argc, argv, verbs, bus); |
1ee306e1 LP |
2648 | } |
2649 | ||
2650 | int main(int argc, char*argv[]) { | |
4afd3348 | 2651 | _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; |
84f6181c | 2652 | int r; |
1ee306e1 LP |
2653 | |
2654 | setlocale(LC_ALL, ""); | |
2655 | log_parse_environment(); | |
2656 | log_open(); | |
2657 | ||
2658 | r = parse_argv(argc, argv); | |
84f6181c | 2659 | if (r <= 0) |
1ee306e1 | 2660 | goto finish; |
1ee306e1 | 2661 | |
266f3e26 | 2662 | r = bus_connect_transport(arg_transport, arg_host, false, &bus); |
a1da8583 | 2663 | if (r < 0) { |
da927ba9 | 2664 | log_error_errno(r, "Failed to create bus connection: %m"); |
a1da8583 TG |
2665 | goto finish; |
2666 | } | |
1ee306e1 | 2667 | |
2723b3b5 LP |
2668 | sd_bus_set_allow_interactive_authorization(bus, arg_ask_password); |
2669 | ||
56159e0d | 2670 | r = machinectl_main(argc, argv, bus); |
1ee306e1 LP |
2671 | |
2672 | finish: | |
1ee306e1 | 2673 | pager_close(); |
acf97e21 | 2674 | polkit_agent_close(); |
1ee306e1 | 2675 | |
84f6181c | 2676 | strv_free(arg_property); |
c454426c | 2677 | strv_free(arg_setenv); |
84f6181c LP |
2678 | |
2679 | return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; | |
1ee306e1 | 2680 | } |