]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machinectl.c
Merge pull request #31861 from yuwata/journalctl-fix-until
[thirdparty/systemd.git] / src / machine / machinectl.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <arpa/inet.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <getopt.h>
7 #include <math.h>
8 #include <net/if.h>
9 #include <netinet/in.h>
10 #include <sys/mount.h>
11 #include <sys/socket.h>
12 #include <unistd.h>
13
14 #include "sd-bus.h"
15
16 #include "alloc-util.h"
17 #include "build.h"
18 #include "build-path.h"
19 #include "bus-common-errors.h"
20 #include "bus-error.h"
21 #include "bus-locator.h"
22 #include "bus-map-properties.h"
23 #include "bus-print-properties.h"
24 #include "bus-unit-procs.h"
25 #include "bus-unit-util.h"
26 #include "bus-wait-for-jobs.h"
27 #include "cgroup-show.h"
28 #include "cgroup-util.h"
29 #include "constants.h"
30 #include "copy.h"
31 #include "edit-util.h"
32 #include "env-util.h"
33 #include "fd-util.h"
34 #include "format-table.h"
35 #include "hostname-util.h"
36 #include "import-util.h"
37 #include "locale-util.h"
38 #include "log.h"
39 #include "logs-show.h"
40 #include "machine-dbus.h"
41 #include "macro.h"
42 #include "main-func.h"
43 #include "mkdir.h"
44 #include "nulstr-util.h"
45 #include "pager.h"
46 #include "parse-argument.h"
47 #include "parse-util.h"
48 #include "path-util.h"
49 #include "pretty-print.h"
50 #include "process-util.h"
51 #include "ptyfwd.h"
52 #include "rlimit-util.h"
53 #include "sigbus.h"
54 #include "signal-util.h"
55 #include "sort-util.h"
56 #include "spawn-ask-password-agent.h"
57 #include "spawn-polkit-agent.h"
58 #include "stdio-util.h"
59 #include "string-table.h"
60 #include "strv.h"
61 #include "terminal-util.h"
62 #include "unit-name.h"
63 #include "verbs.h"
64 #include "web-util.h"
65
66 typedef enum MachineRunner {
67 RUNNER_NSPAWN,
68 RUNNER_VMSPAWN,
69 _RUNNER_MAX,
70 _RUNNER_INVALID = -EINVAL,
71 } MachineRunner;
72
73 static const char* const machine_runner_table[_RUNNER_MAX] = {
74 [RUNNER_NSPAWN] = "nspawn",
75 [RUNNER_VMSPAWN] = "vmspawn",
76 };
77
78 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(machine_runner, MachineRunner);
79
80 static const char* const machine_runner_unit_prefix_table[_RUNNER_MAX] = {
81 [RUNNER_NSPAWN] = "systemd-nspawn",
82 [RUNNER_VMSPAWN] = "systemd-vmspawn",
83 };
84
85 static char **arg_property = NULL;
86 static bool arg_all = false;
87 static BusPrintPropertyFlags arg_print_flags = 0;
88 static bool arg_full = false;
89 static PagerFlags arg_pager_flags = 0;
90 static bool arg_legend = true;
91 static const char *arg_kill_whom = NULL;
92 static int arg_signal = SIGTERM;
93 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
94 static const char *arg_host = NULL;
95 static bool arg_read_only = false;
96 static bool arg_mkdir = false;
97 static bool arg_quiet = false;
98 static bool arg_ask_password = true;
99 static unsigned arg_lines = 10;
100 static OutputMode arg_output = OUTPUT_SHORT;
101 static bool arg_now = false;
102 static bool arg_force = false;
103 static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
104 static MachineRunner arg_runner = RUNNER_NSPAWN;
105 static const char* arg_format = NULL;
106 static const char *arg_uid = NULL;
107 static char **arg_setenv = NULL;
108 static unsigned arg_max_addresses = 1;
109
110 STATIC_DESTRUCTOR_REGISTER(arg_property, strv_freep);
111 STATIC_DESTRUCTOR_REGISTER(arg_setenv, strv_freep);
112
113 static OutputFlags get_output_flags(void) {
114 return
115 FLAGS_SET(arg_print_flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) * OUTPUT_SHOW_ALL |
116 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
117 colors_enabled() * OUTPUT_COLOR |
118 !arg_quiet * OUTPUT_WARN_CUTOFF;
119 }
120
121 static int call_get_os_release(sd_bus *bus, const char *method, const char *name, const char *query, ...) {
122 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
123 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
124 const char *k, *v, **query_res = NULL;
125 size_t count = 0, awaited_args = 0;
126 va_list ap;
127 int r;
128
129 assert(bus);
130 assert(name);
131 assert(query);
132
133 NULSTR_FOREACH(iter, query)
134 awaited_args++;
135 query_res = newa0(const char *, awaited_args);
136
137 r = bus_call_method(bus, bus_machine_mgr, method, &error, &reply, "s", name);
138 if (r < 0)
139 return log_debug_errno(r, "Failed to call '%s()': %s", method, bus_error_message(&error, r));
140
141 r = sd_bus_message_enter_container(reply, 'a', "{ss}");
142 if (r < 0)
143 return bus_log_parse_error(r);
144
145 while ((r = sd_bus_message_read(reply, "{ss}", &k, &v)) > 0) {
146 count = 0;
147 NULSTR_FOREACH(iter, query) {
148 if (streq(k, iter)) {
149 query_res[count] = v;
150 break;
151 }
152 count++;
153 }
154 }
155 if (r < 0)
156 return bus_log_parse_error(r);
157
158 r = sd_bus_message_exit_container(reply);
159 if (r < 0)
160 return bus_log_parse_error(r);
161
162 r = 0;
163 va_start(ap, query);
164 for (count = 0; count < awaited_args; count++) {
165 char **out;
166
167 out = va_arg(ap, char **);
168 assert(out);
169 if (query_res[count]) {
170 r = strdup_to(out, query_res[count]);
171 if (r < 0)
172 break;
173 }
174 }
175 va_end(ap);
176
177 return r;
178 }
179
180 static int call_get_addresses(
181 sd_bus *bus,
182 const char *name,
183 int ifi,
184 const char *prefix,
185 const char *prefix2,
186 char **ret) {
187
188 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
189 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
190 _cleanup_free_ char *addresses = NULL;
191 unsigned n = 0;
192 int r;
193
194 assert(bus);
195 assert(name);
196 assert(prefix);
197 assert(prefix2);
198
199 r = bus_call_method(bus, bus_machine_mgr, "GetMachineAddresses", NULL, &reply, "s", name);
200 if (r < 0)
201 return log_debug_errno(r, "Could not get addresses: %s", bus_error_message(&error, r));
202
203 addresses = strdup(prefix);
204 if (!addresses)
205 return log_oom();
206 prefix = "";
207
208 r = sd_bus_message_enter_container(reply, 'a', "(iay)");
209 if (r < 0)
210 return bus_log_parse_error(r);
211
212 while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
213 int family;
214 const void *a;
215 size_t sz;
216 char buf_ifi[1 + DECIMAL_STR_MAX(int)] = "";
217
218 r = sd_bus_message_read(reply, "i", &family);
219 if (r < 0)
220 return bus_log_parse_error(r);
221
222 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
223 if (r < 0)
224 return bus_log_parse_error(r);
225
226 if (family == AF_INET6 && ifi > 0)
227 xsprintf(buf_ifi, "%%%i", ifi);
228
229 if (!strextend(&addresses, prefix, IN_ADDR_TO_STRING(family, a), buf_ifi))
230 return log_oom();
231
232 r = sd_bus_message_exit_container(reply);
233 if (r < 0)
234 return bus_log_parse_error(r);
235
236 prefix = prefix2;
237
238 n++;
239 }
240 if (r < 0)
241 return bus_log_parse_error(r);
242
243 r = sd_bus_message_exit_container(reply);
244 if (r < 0)
245 return bus_log_parse_error(r);
246
247 *ret = TAKE_PTR(addresses);
248 return (int) n;
249 }
250
251 static int show_table(Table *table, const char *word) {
252 int r;
253
254 assert(table);
255 assert(word);
256
257 if (!table_isempty(table) || OUTPUT_MODE_IS_JSON(arg_output)) {
258 r = table_set_sort(table, (size_t) 0);
259 if (r < 0)
260 return table_log_sort_error(r);
261
262 table_set_header(table, arg_legend);
263
264 if (OUTPUT_MODE_IS_JSON(arg_output))
265 r = table_print_json(table, NULL, output_mode_to_json_format_flags(arg_output) | JSON_FORMAT_COLOR_AUTO);
266 else
267 r = table_print(table, NULL);
268 if (r < 0)
269 return table_log_print_error(r);
270 }
271
272 if (arg_legend) {
273 if (table_isempty(table))
274 printf("No %s.\n", word);
275 else
276 printf("\n%zu %s listed.\n", table_get_rows(table) - 1, word);
277 }
278
279 return 0;
280 }
281
282 static int list_machines(int argc, char *argv[], void *userdata) {
283 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
284 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
285 _cleanup_(table_unrefp) Table *table = NULL;
286 sd_bus *bus = ASSERT_PTR(userdata);
287 int r;
288
289 pager_open(arg_pager_flags);
290
291 r = bus_call_method(bus, bus_machine_mgr, "ListMachines", &error, &reply, NULL);
292 if (r < 0)
293 return log_error_errno(r, "Could not get machines: %s", bus_error_message(&error, r));
294
295 table = table_new("machine", "class", "service", "os", "version",
296 arg_max_addresses > 0 ? "addresses" : NULL);
297 if (!table)
298 return log_oom();
299
300 table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
301 if (!arg_full && arg_max_addresses > 0 && arg_max_addresses < UINT_MAX)
302 table_set_cell_height_max(table, arg_max_addresses);
303
304 if (arg_full)
305 table_set_width(table, 0);
306
307 r = sd_bus_message_enter_container(reply, 'a', "(ssso)");
308 if (r < 0)
309 return bus_log_parse_error(r);
310
311 for (;;) {
312 _cleanup_free_ char *os = NULL, *version_id = NULL, *addresses = NULL;
313 const char *name, *class, *service;
314
315 r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, NULL);
316 if (r < 0)
317 return bus_log_parse_error(r);
318 if (r == 0)
319 break;
320
321 if (name[0] == '.' && !arg_all)
322 continue;
323
324 (void) call_get_os_release(
325 bus,
326 "GetMachineOSRelease",
327 name,
328 "ID\0"
329 "VERSION_ID\0",
330 &os,
331 &version_id);
332
333 r = table_add_many(table,
334 TABLE_STRING, empty_to_null(name),
335 TABLE_STRING, empty_to_null(class),
336 TABLE_STRING, empty_to_null(service),
337 TABLE_STRING, empty_to_null(os),
338 TABLE_STRING, empty_to_null(version_id));
339 if (r < 0)
340 return table_log_add_error(r);
341
342 if (arg_max_addresses > 0) {
343 (void) call_get_addresses(bus, name, 0, "", "\n", &addresses);
344
345 r = table_add_many(table,
346 TABLE_STRING, empty_to_null(addresses));
347 if (r < 0)
348 return table_log_add_error(r);
349 }
350 }
351
352 r = sd_bus_message_exit_container(reply);
353 if (r < 0)
354 return bus_log_parse_error(r);
355
356 return show_table(table, "machines");
357 }
358
359 static int list_images(int argc, char *argv[], void *userdata) {
360
361 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
362 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
363 _cleanup_(table_unrefp) Table *table = NULL;
364 sd_bus *bus = ASSERT_PTR(userdata);
365 int r;
366
367 pager_open(arg_pager_flags);
368
369 r = bus_call_method(bus, bus_machine_mgr, "ListImages", &error, &reply, NULL);
370 if (r < 0)
371 return log_error_errno(r, "Could not get images: %s", bus_error_message(&error, r));
372
373 table = table_new("name", "type", "ro", "usage", "created", "modified");
374 if (!table)
375 return log_oom();
376
377 if (arg_full)
378 table_set_width(table, 0);
379
380 (void) table_set_align_percent(table, TABLE_HEADER_CELL(3), 100);
381
382 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssbttto)");
383 if (r < 0)
384 return bus_log_parse_error(r);
385
386 for (;;) {
387 uint64_t crtime, mtime, size;
388 const char *name, *type;
389 int ro_int;
390
391 r = sd_bus_message_read(reply, "(ssbttto)", &name, &type, &ro_int, &crtime, &mtime, &size, NULL);
392 if (r < 0)
393 return bus_log_parse_error(r);
394 if (r == 0)
395 break;
396
397 if (name[0] == '.' && !arg_all)
398 continue;
399
400 r = table_add_many(table,
401 TABLE_STRING, name,
402 TABLE_STRING, type,
403 TABLE_BOOLEAN, ro_int,
404 TABLE_SET_COLOR, ro_int ? ansi_highlight_red() : NULL,
405 TABLE_SIZE, size,
406 TABLE_TIMESTAMP, crtime,
407 TABLE_TIMESTAMP, mtime);
408 if (r < 0)
409 return table_log_add_error(r);
410 }
411
412 r = sd_bus_message_exit_container(reply);
413 if (r < 0)
414 return bus_log_parse_error(r);
415
416 return show_table(table, "images");
417 }
418
419 static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
420 _cleanup_free_ char *cgroup = NULL;
421 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
422 int r;
423 unsigned c;
424
425 assert(bus);
426 assert(unit);
427
428 r = show_cgroup_get_unit_path_and_warn(bus, unit, &cgroup);
429 if (r < 0)
430 return r;
431
432 if (isempty(cgroup))
433 return 0;
434
435 c = columns();
436 if (c > 18)
437 c -= 18;
438 else
439 c = 0;
440
441 r = unit_show_processes(bus, unit, cgroup, "\t\t ", c, get_output_flags(), &error);
442 if (r == -EBADR) {
443
444 if (arg_transport == BUS_TRANSPORT_REMOTE)
445 return 0;
446
447 /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
448
449 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
450 return 0;
451
452 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, &leader, leader > 0, get_output_flags());
453 } else if (r < 0)
454 return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r));
455
456 return 0;
457 }
458
459 static int print_os_release(sd_bus *bus, const char *method, const char *name, const char *prefix) {
460 _cleanup_free_ char *pretty = NULL;
461 int r;
462
463 assert(bus);
464 assert(name);
465 assert(prefix);
466
467 r = call_get_os_release(bus, method, name, "PRETTY_NAME\0", &pretty, NULL);
468 if (r < 0)
469 return r;
470
471 if (pretty)
472 printf("%s%s\n", prefix, pretty);
473
474 return 0;
475 }
476
477 static int print_uid_shift(sd_bus *bus, const char *name) {
478 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
479 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
480 uint32_t shift;
481 int r;
482
483 assert(bus);
484 assert(name);
485
486 r = bus_call_method(bus, bus_machine_mgr, "GetMachineUIDShift", &error, &reply, "s", name);
487 if (r < 0)
488 return log_debug_errno(r, "Failed to query UID/GID shift: %s", bus_error_message(&error, r));
489
490 r = sd_bus_message_read(reply, "u", &shift);
491 if (r < 0)
492 return r;
493
494 if (shift == 0) /* Don't show trivial mappings */
495 return 0;
496
497 printf(" UID Shift: %" PRIu32 "\n", shift);
498 return 0;
499 }
500
501 typedef struct MachineStatusInfo {
502 const char *name;
503 sd_id128_t id;
504 const char *class;
505 const char *service;
506 const char *unit;
507 const char *root_directory;
508 pid_t leader;
509 struct dual_timestamp timestamp;
510 int *netif;
511 size_t n_netif;
512 } MachineStatusInfo;
513
514 static void machine_status_info_clear(MachineStatusInfo *info) {
515 if (info) {
516 free(info->netif);
517 zero(*info);
518 }
519 }
520
521 static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
522 _cleanup_free_ char *addresses = NULL, *s1 = NULL, *s2 = NULL;
523 int ifi = -1;
524
525 assert(bus);
526 assert(i);
527
528 fputs(strna(i->name), stdout);
529
530 if (!sd_id128_is_null(i->id))
531 printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id));
532 else
533 putchar('\n');
534
535 s1 = strdup(strempty(FORMAT_TIMESTAMP_RELATIVE(i->timestamp.realtime)));
536 s2 = strdup(strempty(FORMAT_TIMESTAMP(i->timestamp.realtime)));
537
538 if (!isempty(s1))
539 printf("\t Since: %s; %s\n", strna(s2), s1);
540 else if (!isempty(s2))
541 printf("\t Since: %s\n", s2);
542
543 if (i->leader > 0) {
544 _cleanup_free_ char *t = NULL;
545
546 printf("\t Leader: %u", (unsigned) i->leader);
547
548 (void) pid_get_comm(i->leader, &t);
549 if (t)
550 printf(" (%s)", t);
551
552 putchar('\n');
553 }
554
555 if (i->service) {
556 printf("\t Service: %s", i->service);
557
558 if (i->class)
559 printf("; class %s", i->class);
560
561 putchar('\n');
562 } else if (i->class)
563 printf("\t Class: %s\n", i->class);
564
565 if (i->root_directory)
566 printf("\t Root: %s\n", i->root_directory);
567
568 if (i->n_netif > 0) {
569 fputs("\t Iface:", stdout);
570
571 for (size_t c = 0; c < i->n_netif; c++) {
572 char name[IF_NAMESIZE];
573
574 if (format_ifname(i->netif[c], name) >= 0) {
575 fputc(' ', stdout);
576 fputs(name, stdout);
577
578 if (ifi < 0)
579 ifi = i->netif[c];
580 else
581 ifi = 0;
582 } else
583 printf(" %i", i->netif[c]);
584 }
585
586 fputc('\n', stdout);
587 }
588
589 if (call_get_addresses(bus, i->name, ifi,
590 "\t Address: ", "\n\t ",
591 &addresses) > 0) {
592 fputs(addresses, stdout);
593 fputc('\n', stdout);
594 }
595
596 print_os_release(bus, "GetMachineOSRelease", i->name, "\t OS: ");
597
598 print_uid_shift(bus, i->name);
599
600 if (i->unit) {
601 printf("\t Unit: %s\n", i->unit);
602 show_unit_cgroup(bus, i->unit, i->leader);
603
604 if (arg_transport == BUS_TRANSPORT_LOCAL)
605
606 show_journal_by_unit(
607 stdout,
608 i->unit,
609 NULL,
610 arg_output,
611 0,
612 i->timestamp.monotonic,
613 arg_lines,
614 0,
615 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
616 SD_JOURNAL_LOCAL_ONLY,
617 true,
618 NULL);
619 }
620 }
621
622 static int map_netif(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
623 MachineStatusInfo *i = userdata;
624 size_t l;
625 const void *v;
626 int r;
627
628 assert_cc(sizeof(int32_t) == sizeof(int));
629 r = sd_bus_message_read_array(m, SD_BUS_TYPE_INT32, &v, &l);
630 if (r < 0)
631 return r;
632 if (r == 0)
633 return -EBADMSG;
634
635 i->n_netif = l / sizeof(int32_t);
636 i->netif = memdup(v, l);
637 if (!i->netif)
638 return -ENOMEM;
639
640 return 0;
641 }
642
643 static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
644
645 static const struct bus_properties_map map[] = {
646 { "Name", "s", NULL, offsetof(MachineStatusInfo, name) },
647 { "Class", "s", NULL, offsetof(MachineStatusInfo, class) },
648 { "Service", "s", NULL, offsetof(MachineStatusInfo, service) },
649 { "Unit", "s", NULL, offsetof(MachineStatusInfo, unit) },
650 { "RootDirectory", "s", NULL, offsetof(MachineStatusInfo, root_directory) },
651 { "Leader", "u", NULL, offsetof(MachineStatusInfo, leader) },
652 { "Timestamp", "t", NULL, offsetof(MachineStatusInfo, timestamp.realtime) },
653 { "TimestampMonotonic", "t", NULL, offsetof(MachineStatusInfo, timestamp.monotonic) },
654 { "Id", "ay", bus_map_id128, offsetof(MachineStatusInfo, id) },
655 { "NetworkInterfaces", "ai", map_netif, 0 },
656 {}
657 };
658
659 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
660 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
661 _cleanup_(machine_status_info_clear) MachineStatusInfo info = {};
662 int r;
663
664 assert(verb);
665 assert(bus);
666 assert(path);
667 assert(new_line);
668
669 r = bus_map_all_properties(bus,
670 "org.freedesktop.machine1",
671 path,
672 map,
673 0,
674 &error,
675 &m,
676 &info);
677 if (r < 0)
678 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
679
680 if (*new_line)
681 printf("\n");
682 *new_line = true;
683
684 print_machine_status_info(bus, &info);
685
686 return r;
687 }
688
689 static int show_machine_properties(sd_bus *bus, const char *path, bool *new_line) {
690 int r;
691
692 assert(bus);
693 assert(path);
694 assert(new_line);
695
696 if (*new_line)
697 printf("\n");
698
699 *new_line = true;
700
701 r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, NULL, arg_property, arg_print_flags, NULL);
702 if (r < 0)
703 log_error_errno(r, "Could not get properties: %m");
704
705 return r;
706 }
707
708 static int show_machine(int argc, char *argv[], void *userdata) {
709 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
710 bool properties, new_line = false;
711 sd_bus *bus = ASSERT_PTR(userdata);
712 int r = 0;
713
714 properties = !strstr(argv[0], "status");
715
716 pager_open(arg_pager_flags);
717
718 if (properties && argc <= 1) {
719
720 /* If no argument is specified, inspect the manager
721 * itself */
722 r = show_machine_properties(bus, "/org/freedesktop/machine1", &new_line);
723 if (r < 0)
724 return r;
725 }
726
727 for (int i = 1; i < argc; i++) {
728 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
729 const char *path = NULL;
730
731 r = bus_call_method(bus, bus_machine_mgr, "GetMachine", &error, &reply, "s", argv[i]);
732 if (r < 0)
733 return log_error_errno(r, "Could not get path to machine: %s", bus_error_message(&error, r));
734
735 r = sd_bus_message_read(reply, "o", &path);
736 if (r < 0)
737 return bus_log_parse_error(r);
738
739 if (properties)
740 r = show_machine_properties(bus, path, &new_line);
741 else
742 r = show_machine_info(argv[0], bus, path, &new_line);
743 }
744
745 return r;
746 }
747
748 static int print_image_hostname(sd_bus *bus, const char *name) {
749 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
750 const char *hn;
751 int r;
752
753 r = bus_call_method(bus, bus_machine_mgr, "GetImageHostname", NULL, &reply, "s", name);
754 if (r < 0)
755 return r;
756
757 r = sd_bus_message_read(reply, "s", &hn);
758 if (r < 0)
759 return r;
760
761 if (!isempty(hn))
762 printf("\tHostname: %s\n", hn);
763
764 return 0;
765 }
766
767 static int print_image_machine_id(sd_bus *bus, const char *name) {
768 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
769 sd_id128_t id;
770 int r;
771
772 r = bus_call_method(bus, bus_machine_mgr, "GetImageMachineID", NULL, &reply, "s", name);
773 if (r < 0)
774 return r;
775
776 r = bus_message_read_id128(reply, &id);
777 if (r < 0)
778 return r;
779
780 if (!sd_id128_is_null(id))
781 printf(" Machine ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(id));
782
783 return 0;
784 }
785
786 static int print_image_machine_info(sd_bus *bus, const char *name) {
787 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
788 int r;
789
790 r = bus_call_method(bus, bus_machine_mgr, "GetImageMachineInfo", NULL, &reply, "s", name);
791 if (r < 0)
792 return r;
793
794 r = sd_bus_message_enter_container(reply, 'a', "{ss}");
795 if (r < 0)
796 return r;
797
798 for (;;) {
799 const char *p, *q;
800
801 r = sd_bus_message_read(reply, "{ss}", &p, &q);
802 if (r < 0)
803 return r;
804 if (r == 0)
805 break;
806
807 if (streq(p, "DEPLOYMENT"))
808 printf(" Deployment: %s\n", q);
809 }
810
811 r = sd_bus_message_exit_container(reply);
812 if (r < 0)
813 return r;
814
815 return 0;
816 }
817
818 typedef struct ImageStatusInfo {
819 const char *name;
820 const char *path;
821 const char *type;
822 bool read_only;
823 usec_t crtime;
824 usec_t mtime;
825 uint64_t usage;
826 uint64_t limit;
827 uint64_t usage_exclusive;
828 uint64_t limit_exclusive;
829 } ImageStatusInfo;
830
831 static void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) {
832 assert(bus);
833 assert(i);
834
835 if (i->name) {
836 fputs(i->name, stdout);
837 putchar('\n');
838 }
839
840 if (i->type)
841 printf("\t Type: %s\n", i->type);
842
843 if (i->path)
844 printf("\t Path: %s\n", i->path);
845
846 (void) print_image_hostname(bus, i->name);
847 (void) print_image_machine_id(bus, i->name);
848 (void) print_image_machine_info(bus, i->name);
849
850 print_os_release(bus, "GetImageOSRelease", i->name, "\t OS: ");
851
852 printf("\t RO: %s%s%s\n",
853 i->read_only ? ansi_highlight_red() : "",
854 i->read_only ? "read-only" : "writable",
855 i->read_only ? ansi_normal() : "");
856
857 if (timestamp_is_set(i->crtime))
858 printf("\t Created: %s; %s\n",
859 FORMAT_TIMESTAMP(i->crtime), FORMAT_TIMESTAMP_RELATIVE(i->crtime));
860
861 if (timestamp_is_set(i->mtime))
862 printf("\tModified: %s; %s\n",
863 FORMAT_TIMESTAMP(i->mtime), FORMAT_TIMESTAMP_RELATIVE(i->mtime));
864
865 if (i->usage != UINT64_MAX) {
866 if (i->usage_exclusive != i->usage && i->usage_exclusive != UINT64_MAX)
867 printf("\t Usage: %s (exclusive: %s)\n",
868 FORMAT_BYTES(i->usage), FORMAT_BYTES(i->usage_exclusive));
869 else
870 printf("\t Usage: %s\n", FORMAT_BYTES(i->usage));
871 }
872
873 if (i->limit != UINT64_MAX) {
874 if (i->limit_exclusive != i->limit && i->limit_exclusive != UINT64_MAX)
875 printf("\t Limit: %s (exclusive: %s)\n",
876 FORMAT_BYTES(i->limit), FORMAT_BYTES(i->limit_exclusive));
877 else
878 printf("\t Limit: %s\n", FORMAT_BYTES(i->limit));
879 }
880 }
881
882 static int show_image_info(sd_bus *bus, const char *path, bool *new_line) {
883
884 static const struct bus_properties_map map[] = {
885 { "Name", "s", NULL, offsetof(ImageStatusInfo, name) },
886 { "Path", "s", NULL, offsetof(ImageStatusInfo, path) },
887 { "Type", "s", NULL, offsetof(ImageStatusInfo, type) },
888 { "ReadOnly", "b", NULL, offsetof(ImageStatusInfo, read_only) },
889 { "CreationTimestamp", "t", NULL, offsetof(ImageStatusInfo, crtime) },
890 { "ModificationTimestamp", "t", NULL, offsetof(ImageStatusInfo, mtime) },
891 { "Usage", "t", NULL, offsetof(ImageStatusInfo, usage) },
892 { "Limit", "t", NULL, offsetof(ImageStatusInfo, limit) },
893 { "UsageExclusive", "t", NULL, offsetof(ImageStatusInfo, usage_exclusive) },
894 { "LimitExclusive", "t", NULL, offsetof(ImageStatusInfo, limit_exclusive) },
895 {}
896 };
897
898 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
899 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
900 ImageStatusInfo info = {};
901 int r;
902
903 assert(bus);
904 assert(path);
905 assert(new_line);
906
907 r = bus_map_all_properties(bus,
908 "org.freedesktop.machine1",
909 path,
910 map,
911 BUS_MAP_BOOLEAN_AS_BOOL,
912 &error,
913 &m,
914 &info);
915 if (r < 0)
916 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
917
918 if (*new_line)
919 printf("\n");
920 *new_line = true;
921
922 print_image_status_info(bus, &info);
923
924 return r;
925 }
926
927 typedef struct PoolStatusInfo {
928 const char *path;
929 uint64_t usage;
930 uint64_t limit;
931 } PoolStatusInfo;
932
933 static void print_pool_status_info(sd_bus *bus, PoolStatusInfo *i) {
934 if (i->path)
935 printf("\t Path: %s\n", i->path);
936
937 if (i->usage != UINT64_MAX)
938 printf("\t Usage: %s\n", FORMAT_BYTES(i->usage));
939
940 if (i->limit != UINT64_MAX)
941 printf("\t Limit: %s\n", FORMAT_BYTES(i->limit));
942 }
943
944 static int show_pool_info(sd_bus *bus) {
945
946 static const struct bus_properties_map map[] = {
947 { "PoolPath", "s", NULL, offsetof(PoolStatusInfo, path) },
948 { "PoolUsage", "t", NULL, offsetof(PoolStatusInfo, usage) },
949 { "PoolLimit", "t", NULL, offsetof(PoolStatusInfo, limit) },
950 {}
951 };
952
953 PoolStatusInfo info = {
954 .usage = UINT64_MAX,
955 .limit = UINT64_MAX,
956 };
957
958 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
959 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
960 int r;
961
962 assert(bus);
963
964 r = bus_map_all_properties(bus,
965 "org.freedesktop.machine1",
966 "/org/freedesktop/machine1",
967 map,
968 0,
969 &error,
970 &m,
971 &info);
972 if (r < 0)
973 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
974
975 print_pool_status_info(bus, &info);
976
977 return 0;
978 }
979
980 static int show_image_properties(sd_bus *bus, const char *path, bool *new_line) {
981 int r;
982
983 assert(bus);
984 assert(path);
985 assert(new_line);
986
987 if (*new_line)
988 printf("\n");
989
990 *new_line = true;
991
992 r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, NULL, arg_property, arg_print_flags, NULL);
993 if (r < 0)
994 log_error_errno(r, "Could not get properties: %m");
995
996 return r;
997 }
998
999 static int show_image(int argc, char *argv[], void *userdata) {
1000 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1001 bool properties, new_line = false;
1002 sd_bus *bus = ASSERT_PTR(userdata);
1003 int r = 0;
1004
1005 properties = !strstr(argv[0], "status");
1006
1007 pager_open(arg_pager_flags);
1008
1009 if (argc <= 1) {
1010
1011 /* If no argument is specified, inspect the manager
1012 * itself */
1013
1014 if (properties)
1015 r = show_image_properties(bus, "/org/freedesktop/machine1", &new_line);
1016 else
1017 r = show_pool_info(bus);
1018 if (r < 0)
1019 return r;
1020 }
1021
1022 for (int i = 1; i < argc; i++) {
1023 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1024 const char *path = NULL;
1025
1026 r = bus_call_method(bus, bus_machine_mgr, "GetImage", &error, &reply, "s", argv[i]);
1027 if (r < 0)
1028 return log_error_errno(r, "Could not get path to image: %s", bus_error_message(&error, r));
1029
1030 r = sd_bus_message_read(reply, "o", &path);
1031 if (r < 0)
1032 return bus_log_parse_error(r);
1033
1034 if (properties)
1035 r = show_image_properties(bus, path, &new_line);
1036 else
1037 r = show_image_info(bus, path, &new_line);
1038 }
1039
1040 return r;
1041 }
1042
1043 static int kill_machine(int argc, char *argv[], void *userdata) {
1044 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1045 sd_bus *bus = ASSERT_PTR(userdata);
1046 int r;
1047
1048 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1049
1050 if (!arg_kill_whom)
1051 arg_kill_whom = "all";
1052
1053 for (int i = 1; i < argc; i++) {
1054 r = bus_call_method(
1055 bus,
1056 bus_machine_mgr,
1057 "KillMachine",
1058 &error,
1059 NULL,
1060 "ssi", argv[i], arg_kill_whom, arg_signal);
1061 if (r < 0)
1062 return log_error_errno(r, "Could not kill machine: %s", bus_error_message(&error, r));
1063 }
1064
1065 return 0;
1066 }
1067
1068 static int reboot_machine(int argc, char *argv[], void *userdata) {
1069 if (arg_runner == RUNNER_VMSPAWN)
1070 return log_error_errno(
1071 SYNTHETIC_ERRNO(EOPNOTSUPP),
1072 "%s only support supported for --runner=nspawn",
1073 streq(argv[0], "reboot") ? "Reboot" : "Restart");
1074
1075 arg_kill_whom = "leader";
1076 arg_signal = SIGINT; /* sysvinit + systemd */
1077
1078 return kill_machine(argc, argv, userdata);
1079 }
1080
1081 static int poweroff_machine(int argc, char *argv[], void *userdata) {
1082 arg_kill_whom = "leader";
1083 arg_signal = SIGRTMIN+4; /* only systemd */
1084
1085 return kill_machine(argc, argv, userdata);
1086 }
1087
1088 static int terminate_machine(int argc, char *argv[], void *userdata) {
1089 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1090 sd_bus *bus = ASSERT_PTR(userdata);
1091 int r;
1092
1093 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1094
1095 for (int i = 1; i < argc; i++) {
1096 r = bus_call_method(bus, bus_machine_mgr, "TerminateMachine", &error, NULL, "s", argv[i]);
1097 if (r < 0)
1098 return log_error_errno(r, "Could not terminate machine: %s", bus_error_message(&error, r));
1099 }
1100
1101 return 0;
1102 }
1103
1104 static const char *select_copy_method(bool copy_from, bool force) {
1105 if (force)
1106 return copy_from ? "CopyFromMachineWithFlags" : "CopyToMachineWithFlags";
1107 else
1108 return copy_from ? "CopyFromMachine" : "CopyToMachine";
1109 }
1110
1111 static int copy_files(int argc, char *argv[], void *userdata) {
1112 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1113 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1114 _cleanup_free_ char *abs_host_path = NULL;
1115 char *dest, *host_path, *container_path;
1116 sd_bus *bus = ASSERT_PTR(userdata);
1117 bool copy_from;
1118 int r;
1119
1120 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1121
1122 copy_from = streq(argv[0], "copy-from");
1123 dest = argv[3] ?: argv[2];
1124 host_path = copy_from ? dest : argv[2];
1125 container_path = copy_from ? argv[2] : dest;
1126
1127 if (!path_is_absolute(host_path)) {
1128 r = path_make_absolute_cwd(host_path, &abs_host_path);
1129 if (r < 0)
1130 return log_error_errno(r, "Failed to make path absolute: %m");
1131
1132 host_path = abs_host_path;
1133 }
1134
1135 r = bus_message_new_method_call(
1136 bus,
1137 &m,
1138 bus_machine_mgr,
1139 select_copy_method(copy_from, arg_force));
1140 if (r < 0)
1141 return bus_log_create_error(r);
1142
1143 r = sd_bus_message_append(
1144 m,
1145 "sss",
1146 argv[1],
1147 copy_from ? container_path : host_path,
1148 copy_from ? host_path : container_path);
1149 if (r < 0)
1150 return bus_log_create_error(r);
1151
1152 if (arg_force) {
1153 r = sd_bus_message_append(m, "t", (uint64_t) MACHINE_COPY_REPLACE);
1154 if (r < 0)
1155 return bus_log_create_error(r);
1156 }
1157
1158 /* This is a slow operation, hence turn off any method call timeouts */
1159 r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
1160 if (r < 0)
1161 return log_error_errno(r, "Failed to copy: %s", bus_error_message(&error, r));
1162
1163 return 0;
1164 }
1165
1166 static int bind_mount(int argc, char *argv[], void *userdata) {
1167 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1168 sd_bus *bus = ASSERT_PTR(userdata);
1169 int r;
1170
1171 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1172
1173 r = bus_call_method(
1174 bus,
1175 bus_machine_mgr,
1176 "BindMountMachine",
1177 &error,
1178 NULL,
1179 "sssbb",
1180 argv[1],
1181 argv[2],
1182 argv[3],
1183 arg_read_only,
1184 arg_mkdir);
1185 if (r < 0)
1186 return log_error_errno(r, "Failed to bind mount: %s", bus_error_message(&error, r));
1187
1188 return 0;
1189 }
1190
1191 static int on_machine_removed(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
1192 PTYForward ** forward = (PTYForward**) userdata;
1193 int r;
1194
1195 assert(m);
1196 assert(forward);
1197
1198 if (*forward) {
1199 /* If the forwarder is already initialized, tell it to
1200 * exit on the next vhangup(), so that we still flush
1201 * out what might be queued and exit then. */
1202
1203 r = pty_forward_set_ignore_vhangup(*forward, false);
1204 if (r >= 0)
1205 return 0;
1206
1207 log_error_errno(r, "Failed to set ignore_vhangup flag: %m");
1208 }
1209
1210 /* On error, or when the forwarder is not initialized yet, quit immediately */
1211 sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), EXIT_FAILURE);
1212 return 0;
1213 }
1214
1215 static int process_forward(sd_event *event, PTYForward **forward, int master, PTYForwardFlags flags, const char *name) {
1216 char last_char = 0;
1217 bool machine_died;
1218 int r;
1219
1220 assert(event);
1221 assert(master >= 0);
1222 assert(name);
1223
1224 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT) >= 0);
1225
1226 if (!arg_quiet) {
1227 if (streq(name, ".host"))
1228 log_info("Connected to the local host. Press ^] three times within 1s to exit session.");
1229 else
1230 log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", name);
1231 }
1232
1233 (void) sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
1234 (void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
1235
1236 r = pty_forward_new(event, master, flags, forward);
1237 if (r < 0)
1238 return log_error_errno(r, "Failed to create PTY forwarder: %m");
1239
1240 r = sd_event_loop(event);
1241 if (r < 0)
1242 return log_error_errno(r, "Failed to run event loop: %m");
1243
1244 pty_forward_get_last_char(*forward, &last_char);
1245
1246 machine_died =
1247 (flags & PTY_FORWARD_IGNORE_VHANGUP) &&
1248 pty_forward_get_ignore_vhangup(*forward) == 0;
1249
1250 *forward = pty_forward_free(*forward);
1251
1252 if (last_char != '\n')
1253 fputc('\n', stdout);
1254
1255 if (!arg_quiet) {
1256 if (machine_died)
1257 log_info("Machine %s terminated.", name);
1258 else if (streq(name, ".host"))
1259 log_info("Connection to the local host terminated.");
1260 else
1261 log_info("Connection to machine %s terminated.", name);
1262 }
1263
1264 return 0;
1265 }
1266
1267 static int parse_machine_uid(const char *spec, const char **machine, char **uid) {
1268 /*
1269 * Whatever is specified in the spec takes priority over global arguments.
1270 */
1271 char *_uid = NULL;
1272 const char *_machine = NULL;
1273
1274 if (spec) {
1275 const char *at;
1276
1277 at = strchr(spec, '@');
1278 if (at) {
1279 if (at == spec)
1280 /* Do the same as ssh and refuse "@host". */
1281 return -EINVAL;
1282
1283 _machine = at + 1;
1284 _uid = strndup(spec, at - spec);
1285 if (!_uid)
1286 return -ENOMEM;
1287 } else
1288 _machine = spec;
1289 };
1290
1291 if (arg_uid && !_uid) {
1292 _uid = strdup(arg_uid);
1293 if (!_uid)
1294 return -ENOMEM;
1295 }
1296
1297 *uid = _uid;
1298 *machine = isempty(_machine) ? ".host" : _machine;
1299 return 0;
1300 }
1301
1302 static int login_machine(int argc, char *argv[], void *userdata) {
1303 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1304 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1305 _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
1306 _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
1307 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
1308 int master = -1, r;
1309 sd_bus *bus = ASSERT_PTR(userdata);
1310 const char *match, *machine;
1311
1312 if (!strv_isempty(arg_setenv) || arg_uid)
1313 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1314 "--setenv= and --uid= are not supported for 'login'. Use 'shell' instead.");
1315
1316 if (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE))
1317 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
1318 "Login only supported on local machines.");
1319
1320 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1321
1322 r = sd_event_default(&event);
1323 if (r < 0)
1324 return log_error_errno(r, "Failed to get event loop: %m");
1325
1326 r = sd_bus_attach_event(bus, event, 0);
1327 if (r < 0)
1328 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1329
1330 machine = argc < 2 || isempty(argv[1]) ? ".host" : argv[1];
1331
1332 match = strjoina("type='signal',"
1333 "sender='org.freedesktop.machine1',"
1334 "path='/org/freedesktop/machine1',",
1335 "interface='org.freedesktop.machine1.Manager',"
1336 "member='MachineRemoved',"
1337 "arg0='", machine, "'");
1338
1339 r = sd_bus_add_match_async(bus, &slot, match, on_machine_removed, NULL, &forward);
1340 if (r < 0)
1341 return log_error_errno(r, "Failed to request machine removal match: %m");
1342
1343 r = bus_call_method(bus, bus_machine_mgr, "OpenMachineLogin", &error, &reply, "s", machine);
1344 if (r < 0)
1345 return log_error_errno(r, "Failed to get login PTY: %s", bus_error_message(&error, r));
1346
1347 r = sd_bus_message_read(reply, "hs", &master, NULL);
1348 if (r < 0)
1349 return bus_log_parse_error(r);
1350
1351 return process_forward(event, &forward, master, PTY_FORWARD_IGNORE_VHANGUP, machine);
1352 }
1353
1354 static int shell_machine(int argc, char *argv[], void *userdata) {
1355 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
1356 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1357 _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
1358 _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
1359 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
1360 int master = -1, r;
1361 sd_bus *bus = ASSERT_PTR(userdata);
1362 const char *match, *machine, *path;
1363 _cleanup_free_ char *uid = NULL;
1364
1365 if (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE))
1366 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
1367 "Shell only supported on local machines.");
1368
1369 /* Pass $TERM to shell session, if not explicitly specified. */
1370 if (!strv_find_prefix(arg_setenv, "TERM=")) {
1371 const char *t;
1372
1373 t = strv_find_prefix(environ, "TERM=");
1374 if (t) {
1375 if (strv_extend(&arg_setenv, t) < 0)
1376 return log_oom();
1377 }
1378 }
1379
1380 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1381
1382 r = sd_event_default(&event);
1383 if (r < 0)
1384 return log_error_errno(r, "Failed to get event loop: %m");
1385
1386 r = sd_bus_attach_event(bus, event, 0);
1387 if (r < 0)
1388 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1389
1390 r = parse_machine_uid(argc >= 2 ? argv[1] : NULL, &machine, &uid);
1391 if (r < 0)
1392 return log_error_errno(r, "Failed to parse machine specification: %m");
1393
1394 match = strjoina("type='signal',"
1395 "sender='org.freedesktop.machine1',"
1396 "path='/org/freedesktop/machine1',",
1397 "interface='org.freedesktop.machine1.Manager',"
1398 "member='MachineRemoved',"
1399 "arg0='", machine, "'");
1400
1401 r = sd_bus_add_match_async(bus, &slot, match, on_machine_removed, NULL, &forward);
1402 if (r < 0)
1403 return log_error_errno(r, "Failed to request machine removal match: %m");
1404
1405 r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "OpenMachineShell");
1406 if (r < 0)
1407 return bus_log_create_error(r);
1408
1409 path = argc < 3 || isempty(argv[2]) ? NULL : argv[2];
1410
1411 r = sd_bus_message_append(m, "sss", machine, uid, path);
1412 if (r < 0)
1413 return bus_log_create_error(r);
1414
1415 r = sd_bus_message_append_strv(m, strv_length(argv) <= 3 ? NULL : argv + 2);
1416 if (r < 0)
1417 return bus_log_create_error(r);
1418
1419 r = sd_bus_message_append_strv(m, arg_setenv);
1420 if (r < 0)
1421 return bus_log_create_error(r);
1422
1423 r = sd_bus_call(bus, m, 0, &error, &reply);
1424 if (r < 0)
1425 return log_error_errno(r, "Failed to get shell PTY: %s", bus_error_message(&error, r));
1426
1427 r = sd_bus_message_read(reply, "hs", &master, NULL);
1428 if (r < 0)
1429 return bus_log_parse_error(r);
1430
1431 return process_forward(event, &forward, master, 0, machine);
1432 }
1433
1434 static int normalize_nspawn_filename(const char *name, char **ret_file) {
1435 _cleanup_free_ char *file = NULL;
1436
1437 assert(name);
1438 assert(ret_file);
1439
1440 if (!endswith(name, ".nspawn"))
1441 file = strjoin(name, ".nspawn");
1442 else
1443 file = strdup(name);
1444 if (!file)
1445 return log_oom();
1446
1447 if (!filename_is_valid(file))
1448 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid settings file name '%s'.", file);
1449
1450 *ret_file = TAKE_PTR(file);
1451 return 0;
1452 }
1453
1454 static int get_settings_path(const char *name, char **ret_path) {
1455 assert(name);
1456 assert(ret_path);
1457
1458 FOREACH_STRING(i, "/etc/systemd/nspawn", "/run/systemd/nspawn", "/var/lib/machines") {
1459 _cleanup_free_ char *path = NULL;
1460
1461 path = path_join(i, name);
1462 if (!path)
1463 return -ENOMEM;
1464
1465 if (access(path, F_OK) >= 0) {
1466 *ret_path = TAKE_PTR(path);
1467 return 0;
1468 }
1469 }
1470
1471 return -ENOENT;
1472 }
1473
1474 static int edit_settings(int argc, char *argv[], void *userdata) {
1475 _cleanup_(edit_file_context_done) EditFileContext context = {};
1476 int r;
1477
1478 if (!on_tty())
1479 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit machine settings if not on a tty.");
1480
1481 if (arg_transport != BUS_TRANSPORT_LOCAL)
1482 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
1483 "Edit is only supported on the host machine.");
1484
1485 if (arg_runner == RUNNER_VMSPAWN)
1486 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Edit is only supported for --runner=nspawn");
1487
1488 r = mac_init();
1489 if (r < 0)
1490 return r;
1491
1492 STRV_FOREACH(name, strv_skip(argv, 1)) {
1493 _cleanup_free_ char *file = NULL, *path = NULL;
1494
1495 if (path_is_absolute(*name)) {
1496 if (!path_is_safe(*name))
1497 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1498 "Invalid settings file path '%s'.",
1499 *name);
1500
1501 r = edit_files_add(&context, *name, NULL, NULL);
1502 if (r < 0)
1503 return r;
1504 continue;
1505 }
1506
1507 r = normalize_nspawn_filename(*name, &file);
1508 if (r < 0)
1509 return r;
1510
1511 r = get_settings_path(file, &path);
1512 if (r == -ENOENT) {
1513 log_debug("No existing settings file for machine '%s' found, creating a new file.", *name);
1514
1515 path = path_join("/etc/systemd/nspawn", file);
1516 if (!path)
1517 return log_oom();
1518
1519 r = edit_files_add(&context, path, NULL, NULL);
1520 if (r < 0)
1521 return r;
1522 continue;
1523 }
1524 if (r < 0)
1525 return log_error_errno(r, "Failed to get the path of the settings file: %m");
1526
1527 if (path_startswith(path, "/var/lib/machines")) {
1528 _cleanup_free_ char *new_path = NULL;
1529
1530 new_path = path_join("/etc/systemd/nspawn", file);
1531 if (!new_path)
1532 return log_oom();
1533
1534 r = edit_files_add(&context, new_path, path, NULL);
1535 } else
1536 r = edit_files_add(&context, path, NULL, NULL);
1537 if (r < 0)
1538 return r;
1539 }
1540
1541 return do_edit_files_and_install(&context);
1542 }
1543
1544 static int cat_settings(int argc, char *argv[], void *userdata) {
1545 int r = 0;
1546
1547 if (arg_transport != BUS_TRANSPORT_LOCAL)
1548 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
1549 "Cat is only supported on the host machine.");
1550
1551 if (arg_runner == RUNNER_VMSPAWN)
1552 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Cat is only supported for --runner=nspawn");
1553
1554 pager_open(arg_pager_flags);
1555
1556 STRV_FOREACH(name, strv_skip(argv, 1)) {
1557 _cleanup_free_ char *file = NULL, *path = NULL;
1558 int q;
1559
1560 if (path_is_absolute(*name)) {
1561 if (!path_is_safe(*name))
1562 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1563 "Invalid settings file path '%s'.",
1564 *name);
1565
1566 q = cat_files(*name, /* dropins = */ NULL, /* flags = */ CAT_FORMAT_HAS_SECTIONS);
1567 if (q < 0)
1568 return r < 0 ? r : q;
1569 continue;
1570 }
1571
1572 q = normalize_nspawn_filename(*name, &file);
1573 if (q < 0)
1574 return r < 0 ? r : q;
1575
1576 q = get_settings_path(file, &path);
1577 if (q == -ENOENT) {
1578 log_error_errno(q, "No settings file found for machine '%s'.", *name);
1579 r = r < 0 ? r : q;
1580 continue;
1581 }
1582 if (q < 0) {
1583 log_error_errno(q, "Failed to get the path of the settings file: %m");
1584 return r < 0 ? r : q;
1585 }
1586
1587 q = cat_files(path, /* dropins = */ NULL, /* flags = */ CAT_FORMAT_HAS_SECTIONS);
1588 if (q < 0)
1589 return r < 0 ? r : q;
1590 }
1591
1592 return r;
1593 }
1594
1595 static int remove_image(int argc, char *argv[], void *userdata) {
1596 sd_bus *bus = ASSERT_PTR(userdata);
1597 int r;
1598
1599 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1600
1601 for (int i = 1; i < argc; i++) {
1602 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1603 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1604
1605 r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "RemoveImage");
1606 if (r < 0)
1607 return bus_log_create_error(r);
1608
1609 r = sd_bus_message_append(m, "s", argv[i]);
1610 if (r < 0)
1611 return bus_log_create_error(r);
1612
1613 /* This is a slow operation, hence turn off any method call timeouts */
1614 r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
1615 if (r < 0)
1616 return log_error_errno(r, "Could not remove image: %s", bus_error_message(&error, r));
1617 }
1618
1619 return 0;
1620 }
1621
1622 static int rename_image(int argc, char *argv[], void *userdata) {
1623 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1624 sd_bus *bus = ASSERT_PTR(userdata);
1625 int r;
1626
1627 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1628
1629 r = bus_call_method(
1630 bus,
1631 bus_machine_mgr,
1632 "RenameImage",
1633 &error,
1634 NULL,
1635 "ss", argv[1], argv[2]);
1636 if (r < 0)
1637 return log_error_errno(r, "Could not rename image: %s", bus_error_message(&error, r));
1638
1639 return 0;
1640 }
1641
1642 static int clone_image(int argc, char *argv[], void *userdata) {
1643 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1644 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1645 sd_bus *bus = ASSERT_PTR(userdata);
1646 int r;
1647
1648 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1649
1650 r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "CloneImage");
1651 if (r < 0)
1652 return bus_log_create_error(r);
1653
1654 r = sd_bus_message_append(m, "ssb", argv[1], argv[2], arg_read_only);
1655 if (r < 0)
1656 return bus_log_create_error(r);
1657
1658 /* This is a slow operation, hence turn off any method call timeouts */
1659 r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
1660 if (r < 0)
1661 return log_error_errno(r, "Could not clone image: %s", bus_error_message(&error, r));
1662
1663 return 0;
1664 }
1665
1666 static int read_only_image(int argc, char *argv[], void *userdata) {
1667 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1668 sd_bus *bus = ASSERT_PTR(userdata);
1669 int b = true, r;
1670
1671 if (argc > 2) {
1672 b = parse_boolean(argv[2]);
1673 if (b < 0)
1674 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1675 "Failed to parse boolean argument: %s",
1676 argv[2]);
1677 }
1678
1679 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1680
1681 r = bus_call_method(bus, bus_machine_mgr, "MarkImageReadOnly", &error, NULL, "sb", argv[1], b);
1682 if (r < 0)
1683 return log_error_errno(r, "Could not mark image read-only: %s", bus_error_message(&error, r));
1684
1685 return 0;
1686 }
1687
1688 static int image_exists(sd_bus *bus, const char *name) {
1689 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1690 int r;
1691
1692 assert(bus);
1693 assert(name);
1694
1695 r = bus_call_method(bus, bus_machine_mgr, "GetImage", &error, NULL, "s", name);
1696 if (r < 0) {
1697 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_IMAGE))
1698 return 0;
1699
1700 return log_error_errno(r, "Failed to check whether image %s exists: %s", name, bus_error_message(&error, r));
1701 }
1702
1703 return 1;
1704 }
1705
1706 static int make_service_name(const char *name, char **ret) {
1707 int r;
1708
1709 assert(name);
1710 assert(ret);
1711 assert(arg_runner >= 0 && arg_runner < (MachineRunner) ELEMENTSOF(machine_runner_unit_prefix_table));
1712
1713 if (!hostname_is_valid(name, 0))
1714 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1715 "Invalid machine name %s.", name);
1716
1717 r = unit_name_build(machine_runner_unit_prefix_table[arg_runner], name, ".service", ret);
1718 if (r < 0)
1719 return log_error_errno(r, "Failed to build unit name: %m");
1720
1721 return 0;
1722 }
1723
1724 static int start_machine(int argc, char *argv[], void *userdata) {
1725 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1726 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
1727 sd_bus *bus = ASSERT_PTR(userdata);
1728 int r;
1729
1730 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1731 ask_password_agent_open_if_enabled(arg_transport, arg_ask_password);
1732
1733 r = bus_wait_for_jobs_new(bus, &w);
1734 if (r < 0)
1735 return log_error_errno(r, "Could not watch jobs: %m");
1736
1737 for (int i = 1; i < argc; i++) {
1738 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1739 _cleanup_free_ char *unit = NULL;
1740 const char *object;
1741
1742 r = make_service_name(argv[i], &unit);
1743 if (r < 0)
1744 return r;
1745
1746 r = image_exists(bus, argv[i]);
1747 if (r < 0)
1748 return r;
1749 if (r == 0)
1750 return log_error_errno(SYNTHETIC_ERRNO(ENXIO),
1751 "Machine image '%s' does not exist.",
1752 argv[i]);
1753
1754 r = bus_call_method(
1755 bus,
1756 bus_systemd_mgr,
1757 "StartUnit",
1758 &error,
1759 &reply,
1760 "ss", unit, "fail");
1761 if (r < 0)
1762 return log_error_errno(r, "Failed to start unit: %s", bus_error_message(&error, r));
1763
1764 r = sd_bus_message_read(reply, "o", &object);
1765 if (r < 0)
1766 return bus_log_parse_error(r);
1767
1768 r = bus_wait_for_jobs_add(w, object);
1769 if (r < 0)
1770 return log_oom();
1771 }
1772
1773 r = bus_wait_for_jobs(w, arg_quiet, NULL);
1774 if (r < 0)
1775 return r;
1776
1777 return 0;
1778 }
1779
1780 static int enable_machine(int argc, char *argv[], void *userdata) {
1781 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
1782 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1783 const char *method;
1784 sd_bus *bus = ASSERT_PTR(userdata);
1785 int r;
1786 bool enable;
1787
1788 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1789
1790 enable = streq(argv[0], "enable");
1791 method = enable ? "EnableUnitFiles" : "DisableUnitFiles";
1792
1793 r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
1794 if (r < 0)
1795 return bus_log_create_error(r);
1796
1797 r = sd_bus_message_open_container(m, 'a', "s");
1798 if (r < 0)
1799 return bus_log_create_error(r);
1800
1801 if (enable) {
1802 r = sd_bus_message_append(m, "s", "machines.target");
1803 if (r < 0)
1804 return bus_log_create_error(r);
1805 }
1806
1807 for (int i = 1; i < argc; i++) {
1808 _cleanup_free_ char *unit = NULL;
1809
1810 r = make_service_name(argv[i], &unit);
1811 if (r < 0)
1812 return r;
1813
1814 r = image_exists(bus, argv[i]);
1815 if (r < 0)
1816 return r;
1817 if (r == 0)
1818 return log_error_errno(SYNTHETIC_ERRNO(ENXIO),
1819 "Machine image '%s' does not exist.",
1820 argv[i]);
1821
1822 r = sd_bus_message_append(m, "s", unit);
1823 if (r < 0)
1824 return bus_log_create_error(r);
1825 }
1826
1827 r = sd_bus_message_close_container(m);
1828 if (r < 0)
1829 return bus_log_create_error(r);
1830
1831 if (enable)
1832 r = sd_bus_message_append(m, "bb", false, false);
1833 else
1834 r = sd_bus_message_append(m, "b", false);
1835 if (r < 0)
1836 return bus_log_create_error(r);
1837
1838 r = sd_bus_call(bus, m, 0, &error, &reply);
1839 if (r < 0)
1840 return log_error_errno(r, "Failed to enable or disable unit: %s", bus_error_message(&error, r));
1841
1842 if (enable) {
1843 r = sd_bus_message_read(reply, "b", NULL);
1844 if (r < 0)
1845 return bus_log_parse_error(r);
1846 }
1847
1848 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
1849 if (r < 0)
1850 return r;
1851
1852 r = bus_service_manager_reload(bus);
1853 if (r < 0)
1854 return r;
1855
1856 if (arg_now) {
1857 _cleanup_strv_free_ char **new_args = NULL;
1858
1859 new_args = strv_new(enable ? "start" : "poweroff");
1860 if (!new_args)
1861 return log_oom();
1862
1863 r = strv_extend_strv(&new_args, argv + 1, /* filter_duplicates = */ false);
1864 if (r < 0)
1865 return log_oom();
1866
1867 if (enable)
1868 return start_machine(strv_length(new_args), new_args, userdata);
1869
1870 return poweroff_machine(strv_length(new_args), new_args, userdata);
1871 }
1872
1873 return 0;
1874 }
1875
1876 static int set_limit(int argc, char *argv[], void *userdata) {
1877 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1878 sd_bus *bus = userdata;
1879 uint64_t limit;
1880 int r;
1881
1882 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1883
1884 if (STR_IN_SET(argv[argc-1], "-", "none", "infinity"))
1885 limit = UINT64_MAX;
1886 else {
1887 r = parse_size(argv[argc-1], 1024, &limit);
1888 if (r < 0)
1889 return log_error_errno(r, "Failed to parse size: %s", argv[argc-1]);
1890 }
1891
1892 if (argc > 2)
1893 /* With two arguments changes the quota limit of the
1894 * specified image */
1895 r = bus_call_method(bus, bus_machine_mgr, "SetImageLimit", &error, NULL, "st", argv[1], limit);
1896 else
1897 /* With one argument changes the pool quota limit */
1898 r = bus_call_method(bus, bus_machine_mgr, "SetPoolLimit", &error, NULL, "t", limit);
1899
1900 if (r < 0)
1901 return log_error_errno(r, "Could not set limit: %s", bus_error_message(&error, r));
1902
1903 return 0;
1904 }
1905
1906 static int clean_images(int argc, char *argv[], void *userdata) {
1907 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
1908 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1909 uint64_t usage, total = 0;
1910 sd_bus *bus = userdata;
1911 const char *name;
1912 unsigned c = 0;
1913 int r;
1914
1915 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1916
1917 r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "CleanPool");
1918 if (r < 0)
1919 return bus_log_create_error(r);
1920
1921 r = sd_bus_message_append(m, "s", arg_all ? "all" : "hidden");
1922 if (r < 0)
1923 return bus_log_create_error(r);
1924
1925 /* This is a slow operation, hence permit a longer time for completion. */
1926 r = sd_bus_call(bus, m, USEC_INFINITY, &error, &reply);
1927 if (r < 0)
1928 return log_error_errno(r, "Could not clean pool: %s", bus_error_message(&error, r));
1929
1930 r = sd_bus_message_enter_container(reply, 'a', "(st)");
1931 if (r < 0)
1932 return bus_log_parse_error(r);
1933
1934 while ((r = sd_bus_message_read(reply, "(st)", &name, &usage)) > 0) {
1935 if (usage == UINT64_MAX) {
1936 log_info("Removed image '%s'", name);
1937 total = UINT64_MAX;
1938 } else {
1939 log_info("Removed image '%s'. Freed exclusive disk space: %s",
1940 name, FORMAT_BYTES(usage));
1941 if (total != UINT64_MAX)
1942 total += usage;
1943 }
1944 c++;
1945 }
1946
1947 r = sd_bus_message_exit_container(reply);
1948 if (r < 0)
1949 return bus_log_parse_error(r);
1950
1951 if (total == UINT64_MAX)
1952 log_info("Removed %u images in total.", c);
1953 else
1954 log_info("Removed %u images in total. Total freed exclusive disk space: %s.",
1955 c, FORMAT_BYTES(total));
1956
1957 return 0;
1958 }
1959
1960 static int chainload_importctl(int argc, char *argv[]) {
1961 int r;
1962
1963 log_notice("The 'machinectl %1$s' command has been replaced by 'importctl -m %1$s'. Redirecting invocation.", argv[optind]);
1964
1965 _cleanup_strv_free_ char **c =
1966 strv_new("importctl", "--class=machine");
1967 if (!c)
1968 return log_oom();
1969
1970 if (FLAGS_SET(arg_pager_flags, PAGER_DISABLE))
1971 if (strv_extend(&c, "--no-pager") < 0)
1972 return log_oom();
1973 if (!arg_legend)
1974 if (strv_extend(&c, "--no-legend") < 0)
1975 return log_oom();
1976 if (arg_read_only)
1977 if (strv_extend(&c, "--read-only") < 0)
1978 return log_oom();
1979 if (arg_force)
1980 if (strv_extend(&c, "--force") < 0)
1981 return log_oom();
1982 if (arg_quiet)
1983 if (strv_extend(&c, "--quiet") < 0)
1984 return log_oom();
1985 if (!arg_ask_password)
1986 if (strv_extend(&c, "--no-ask-password") < 0)
1987 return log_oom();
1988 if (strv_extend_many(&c, "--verify", import_verify_to_string(arg_verify)) < 0)
1989 return log_oom();
1990 if (arg_format)
1991 if (strv_extend_many(&c, "--format", arg_format) < 0)
1992 return log_oom();
1993
1994 if (strv_extend_strv(&c, argv + optind, /* filter_duplicates= */ false) < 0)
1995 return log_oom();
1996
1997 if (DEBUG_LOGGING) {
1998 _cleanup_free_ char *joined = strv_join(c, " ");
1999 log_debug("Chainloading: %s", joined);
2000 }
2001
2002 r = invoke_callout_binary(BINDIR "/importctl", c);
2003 return log_error_errno(r, "Failed to invoke 'importctl': %m");
2004 }
2005
2006 static int help(int argc, char *argv[], void *userdata) {
2007 _cleanup_free_ char *link = NULL;
2008 int r;
2009
2010 pager_open(arg_pager_flags);
2011
2012 r = terminal_urlify_man("machinectl", "1", &link);
2013 if (r < 0)
2014 return log_oom();
2015
2016 printf("%1$s [OPTIONS...] COMMAND ...\n\n"
2017 "%5$sSend control commands to or query the virtual machine and container%6$s\n"
2018 "%5$sregistration manager.%6$s\n"
2019 "\n%3$sMachine Commands:%4$s\n"
2020 " list List running VMs and containers\n"
2021 " status NAME... Show VM/container details\n"
2022 " show [NAME...] Show properties of one or more VMs/containers\n"
2023 " start NAME... Start container as a service\n"
2024 " login [NAME] Get a login prompt in a container or on the\n"
2025 " local host\n"
2026 " shell [[USER@]NAME [COMMAND...]]\n"
2027 " Invoke a shell (or other command) in a container\n"
2028 " or on the local host\n"
2029 " enable NAME... Enable automatic container start at boot\n"
2030 " disable NAME... Disable automatic container start at boot\n"
2031 " poweroff NAME... Power off one or more containers\n"
2032 " reboot NAME... Reboot one or more containers\n"
2033 " terminate NAME... Terminate one or more VMs/containers\n"
2034 " kill NAME... Send signal to processes of a VM/container\n"
2035 " copy-to NAME PATH [PATH] Copy files from the host to a container\n"
2036 " copy-from NAME PATH [PATH] Copy files from a container to the host\n"
2037 " bind NAME PATH [PATH] Bind mount a path from the host into a container\n"
2038 "\n%3$sImage Commands:%4$s\n"
2039 " list-images Show available container and VM images\n"
2040 " image-status [NAME...] Show image details\n"
2041 " show-image [NAME...] Show properties of image\n"
2042 " edit NAME|FILE... Edit settings of one or more VMs/containers\n"
2043 " cat NAME|FILE... Show settings of one or more VMs/containers\n"
2044 " clone NAME NAME Clone an image\n"
2045 " rename NAME NAME Rename an image\n"
2046 " read-only NAME [BOOL] Mark or unmark image read-only\n"
2047 " remove NAME... Remove an image\n"
2048 " set-limit [NAME] BYTES Set image or pool size limit (disk quota)\n"
2049 " clean Remove hidden (or all) images\n"
2050 "\n%3$sOptions:%4$s\n"
2051 " -h --help Show this help\n"
2052 " --version Show package version\n"
2053 " --no-pager Do not pipe output into a pager\n"
2054 " --no-legend Do not show the headers and footers\n"
2055 " --no-ask-password Do not ask for system passwords\n"
2056 " -H --host=[USER@]HOST Operate on remote host\n"
2057 " -M --machine=CONTAINER Operate on local container\n"
2058 " -p --property=NAME Show only properties by this name\n"
2059 " --value When showing properties, only print the value\n"
2060 " -P NAME Equivalent to --value --property=NAME\n"
2061 " -q --quiet Suppress output\n"
2062 " -a --all Show all properties, including empty ones\n"
2063 " -l --full Do not ellipsize output\n"
2064 " --kill-whom=WHOM Whom to send signal to\n"
2065 " -s --signal=SIGNAL Which signal to send\n"
2066 " --uid=USER Specify user ID to invoke shell as\n"
2067 " -E --setenv=VAR[=VALUE] Add an environment variable for shell\n"
2068 " --read-only Create read-only bind mount or clone\n"
2069 " --mkdir Create directory before bind mounting, if missing\n"
2070 " -n --lines=INTEGER Number of journal entries to show\n"
2071 " --max-addresses=INTEGER Number of internet addresses to show at most\n"
2072 " -o --output=STRING Change journal output mode (short, short-precise,\n"
2073 " short-iso, short-iso-precise, short-full,\n"
2074 " short-monotonic, short-unix, short-delta,\n"
2075 " json, json-pretty, json-sse, json-seq, cat,\n"
2076 " verbose, export, with-unit)\n"
2077 " --force Replace target file when copying, if necessary\n"
2078 " --now Start or power off container after enabling or\n"
2079 " disabling it\n"
2080 " --runner=RUNNER Select between nspawn and vmspawn as the runner\n"
2081 " -V Short for --runner=vmspawn\n"
2082 "\nSee the %2$s for details.\n",
2083 program_invocation_short_name,
2084 link,
2085 ansi_underline(),
2086 ansi_normal(),
2087 ansi_highlight(),
2088 ansi_normal());
2089
2090 return 0;
2091 }
2092
2093 static int parse_argv(int argc, char *argv[]) {
2094
2095 enum {
2096 ARG_VERSION = 0x100,
2097 ARG_NO_PAGER,
2098 ARG_NO_LEGEND,
2099 ARG_VALUE,
2100 ARG_KILL_WHOM,
2101 ARG_READ_ONLY,
2102 ARG_MKDIR,
2103 ARG_NO_ASK_PASSWORD,
2104 ARG_VERIFY,
2105 ARG_RUNNER,
2106 ARG_NOW,
2107 ARG_FORCE,
2108 ARG_FORMAT,
2109 ARG_UID,
2110 ARG_MAX_ADDRESSES,
2111 };
2112
2113 static const struct option options[] = {
2114 { "help", no_argument, NULL, 'h' },
2115 { "version", no_argument, NULL, ARG_VERSION },
2116 { "property", required_argument, NULL, 'p' },
2117 { "value", no_argument, NULL, ARG_VALUE },
2118 { "all", no_argument, NULL, 'a' },
2119 { "full", no_argument, NULL, 'l' },
2120 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
2121 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
2122 { "kill-whom", required_argument, NULL, ARG_KILL_WHOM },
2123 { "signal", required_argument, NULL, 's' },
2124 { "host", required_argument, NULL, 'H' },
2125 { "machine", required_argument, NULL, 'M' },
2126 { "read-only", no_argument, NULL, ARG_READ_ONLY },
2127 { "mkdir", no_argument, NULL, ARG_MKDIR },
2128 { "quiet", no_argument, NULL, 'q' },
2129 { "lines", required_argument, NULL, 'n' },
2130 { "output", required_argument, NULL, 'o' },
2131 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
2132 { "verify", required_argument, NULL, ARG_VERIFY },
2133 { "runner", required_argument, NULL, ARG_RUNNER },
2134 { "now", no_argument, NULL, ARG_NOW },
2135 { "force", no_argument, NULL, ARG_FORCE },
2136 { "format", required_argument, NULL, ARG_FORMAT },
2137 { "uid", required_argument, NULL, ARG_UID },
2138 { "setenv", required_argument, NULL, 'E' },
2139 { "max-addresses", required_argument, NULL, ARG_MAX_ADDRESSES },
2140 {}
2141 };
2142
2143 bool reorder = false;
2144 int c, r, shell = -1;
2145
2146 assert(argc >= 0);
2147 assert(argv);
2148
2149 /* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
2150 * that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
2151 optind = 0;
2152
2153 for (;;) {
2154 static const char option_string[] = "-hp:P:als:H:M:qn:o:E:V";
2155
2156 c = getopt_long(argc, argv, option_string + reorder, options, NULL);
2157 if (c < 0)
2158 break;
2159
2160 switch (c) {
2161
2162 case 1: /* getopt_long() returns 1 if "-" was the first character of the option string, and a
2163 * non-option argument was discovered. */
2164
2165 assert(!reorder);
2166
2167 /* We generally are fine with the fact that getopt_long() reorders the command line, and looks
2168 * for switches after the main verb. However, for "shell" we really don't want that, since we
2169 * want that switches specified after the machine name are passed to the program to execute,
2170 * and not processed by us. To make this possible, we'll first invoke getopt_long() with
2171 * reordering disabled (i.e. with the "-" prefix in the option string), looking for the first
2172 * non-option parameter. If it's the verb "shell" we remember its position and continue
2173 * processing options. In this case, as soon as we hit the next non-option argument we found
2174 * the machine name, and stop further processing. If the first non-option argument is any other
2175 * verb than "shell" we switch to normal reordering mode and continue processing arguments
2176 * normally. */
2177
2178 if (shell >= 0) {
2179 /* If we already found the "shell" verb on the command line, and now found the next
2180 * non-option argument, then this is the machine name and we should stop processing
2181 * further arguments. */
2182 optind--; /* don't process this argument, go one step back */
2183 goto done;
2184 }
2185 if (streq(optarg, "shell"))
2186 /* Remember the position of the "shell" verb, and continue processing normally. */
2187 shell = optind - 1;
2188 else {
2189 int saved_optind;
2190
2191 /* OK, this is some other verb. In this case, turn on reordering again, and continue
2192 * processing normally. */
2193 reorder = true;
2194
2195 /* We changed the option string. getopt_long() only looks at it again if we invoke it
2196 * at least once with a reset option index. Hence, let's reset the option index here,
2197 * then invoke getopt_long() again (ignoring what it has to say, after all we most
2198 * likely already processed it), and the bump the option index so that we read the
2199 * intended argument again. */
2200 saved_optind = optind;
2201 optind = 0;
2202 (void) getopt_long(argc, argv, option_string + reorder, options, NULL);
2203 optind = saved_optind - 1; /* go one step back, process this argument again */
2204 }
2205
2206 break;
2207
2208 case 'h':
2209 return help(0, NULL, NULL);
2210
2211 case ARG_VERSION:
2212 return version();
2213
2214 case 'p':
2215 case 'P':
2216 r = strv_extend(&arg_property, optarg);
2217 if (r < 0)
2218 return log_oom();
2219
2220 /* If the user asked for a particular property, show it to them, even if empty. */
2221 SET_FLAG(arg_print_flags, BUS_PRINT_PROPERTY_SHOW_EMPTY, true);
2222
2223 if (c == 'p')
2224 break;
2225 _fallthrough_;
2226
2227 case ARG_VALUE:
2228 SET_FLAG(arg_print_flags, BUS_PRINT_PROPERTY_ONLY_VALUE, true);
2229 break;
2230
2231 case 'a':
2232 SET_FLAG(arg_print_flags, BUS_PRINT_PROPERTY_SHOW_EMPTY, true);
2233 arg_all = true;
2234 break;
2235
2236 case 'l':
2237 arg_full = true;
2238 break;
2239
2240 case 'n':
2241 if (safe_atou(optarg, &arg_lines) < 0)
2242 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2243 "Failed to parse lines '%s'", optarg);
2244 break;
2245
2246 case 'o':
2247 if (streq(optarg, "help")) {
2248 DUMP_STRING_TABLE(output_mode, OutputMode, _OUTPUT_MODE_MAX);
2249 return 0;
2250 }
2251
2252 r = output_mode_from_string(optarg);
2253 if (r < 0)
2254 return log_error_errno(r, "Unknown output '%s'.", optarg);
2255 arg_output = r;
2256
2257 if (OUTPUT_MODE_IS_JSON(arg_output))
2258 arg_legend = false;
2259 break;
2260
2261 case ARG_NO_PAGER:
2262 arg_pager_flags |= PAGER_DISABLE;
2263 break;
2264
2265 case ARG_NO_LEGEND:
2266 arg_legend = false;
2267 break;
2268
2269 case ARG_KILL_WHOM:
2270 arg_kill_whom = optarg;
2271 break;
2272
2273 case 's':
2274 r = parse_signal_argument(optarg, &arg_signal);
2275 if (r <= 0)
2276 return r;
2277 break;
2278
2279 case ARG_NO_ASK_PASSWORD:
2280 arg_ask_password = false;
2281 break;
2282
2283 case 'H':
2284 arg_transport = BUS_TRANSPORT_REMOTE;
2285 arg_host = optarg;
2286 break;
2287
2288 case 'M':
2289 arg_transport = BUS_TRANSPORT_MACHINE;
2290 arg_host = optarg;
2291 break;
2292
2293 case ARG_READ_ONLY:
2294 arg_read_only = true;
2295 break;
2296
2297 case ARG_MKDIR:
2298 arg_mkdir = true;
2299 break;
2300
2301 case 'q':
2302 arg_quiet = true;
2303 break;
2304
2305 case ARG_VERIFY:
2306 if (streq(optarg, "help")) {
2307 DUMP_STRING_TABLE(import_verify, ImportVerify, _IMPORT_VERIFY_MAX);
2308 return 0;
2309 }
2310
2311 r = import_verify_from_string(optarg);
2312 if (r < 0)
2313 return log_error_errno(r, "Failed to parse --verify= setting: %s", optarg);
2314 arg_verify = r;
2315 break;
2316
2317 case 'V':
2318 arg_runner = RUNNER_VMSPAWN;
2319 break;
2320
2321 case ARG_RUNNER:
2322 r = machine_runner_from_string(optarg);
2323 if (r < 0)
2324 return log_error_errno(r, "Failed to parse --runner= setting: %s", optarg);
2325
2326 arg_runner = r;
2327 break;
2328
2329 case ARG_NOW:
2330 arg_now = true;
2331 break;
2332
2333 case ARG_FORCE:
2334 arg_force = true;
2335 break;
2336
2337 case ARG_FORMAT:
2338 if (!STR_IN_SET(optarg, "uncompressed", "xz", "gzip", "bzip2"))
2339 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2340 "Unknown format: %s", optarg);
2341
2342 arg_format = optarg;
2343 break;
2344
2345 case ARG_UID:
2346 arg_uid = optarg;
2347 break;
2348
2349 case 'E':
2350 r = strv_env_replace_strdup_passthrough(&arg_setenv, optarg);
2351 if (r < 0)
2352 return log_error_errno(r, "Cannot assign environment variable %s: %m", optarg);
2353 break;
2354
2355 case ARG_MAX_ADDRESSES:
2356 if (streq(optarg, "all"))
2357 arg_max_addresses = UINT_MAX;
2358 else if (safe_atou(optarg, &arg_max_addresses) < 0)
2359 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2360 "Invalid number of addresses: %s", optarg);
2361 break;
2362
2363 case '?':
2364 return -EINVAL;
2365
2366 default:
2367 assert_not_reached();
2368 }
2369 }
2370
2371 done:
2372 if (shell >= 0) {
2373 char *t;
2374
2375 /* We found the "shell" verb while processing the argument list. Since we turned off reordering of the
2376 * argument list initially let's readjust it now, and move the "shell" verb to the back. */
2377
2378 optind -= 1; /* place the option index where the "shell" verb will be placed */
2379
2380 t = argv[shell];
2381 for (int i = shell; i < optind; i++)
2382 argv[i] = argv[i+1];
2383 argv[optind] = t;
2384 }
2385
2386 return 1;
2387 }
2388
2389 static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
2390
2391 static const Verb verbs[] = {
2392 { "help", VERB_ANY, VERB_ANY, 0, help },
2393 { "list", VERB_ANY, 1, VERB_DEFAULT, list_machines },
2394 { "list-images", VERB_ANY, 1, 0, list_images },
2395 { "status", 2, VERB_ANY, 0, show_machine },
2396 { "image-status", VERB_ANY, VERB_ANY, 0, show_image },
2397 { "show", VERB_ANY, VERB_ANY, 0, show_machine },
2398 { "show-image", VERB_ANY, VERB_ANY, 0, show_image },
2399 { "terminate", 2, VERB_ANY, 0, terminate_machine },
2400 { "reboot", 2, VERB_ANY, 0, reboot_machine },
2401 { "restart", 2, VERB_ANY, 0, reboot_machine }, /* Convenience alias */
2402 { "poweroff", 2, VERB_ANY, 0, poweroff_machine },
2403 { "stop", 2, VERB_ANY, 0, poweroff_machine }, /* Convenience alias */
2404 { "kill", 2, VERB_ANY, 0, kill_machine },
2405 { "login", VERB_ANY, 2, 0, login_machine },
2406 { "shell", VERB_ANY, VERB_ANY, 0, shell_machine },
2407 { "bind", 3, 4, 0, bind_mount },
2408 { "edit", 2, VERB_ANY, 0, edit_settings },
2409 { "cat", 2, VERB_ANY, 0, cat_settings },
2410 { "copy-to", 3, 4, 0, copy_files },
2411 { "copy-from", 3, 4, 0, copy_files },
2412 { "remove", 2, VERB_ANY, 0, remove_image },
2413 { "rename", 3, 3, 0, rename_image },
2414 { "clone", 3, 3, 0, clone_image },
2415 { "read-only", 2, 3, 0, read_only_image },
2416 { "start", 2, VERB_ANY, 0, start_machine },
2417 { "enable", 2, VERB_ANY, 0, enable_machine },
2418 { "disable", 2, VERB_ANY, 0, enable_machine },
2419 { "set-limit", 2, 3, 0, set_limit },
2420 { "clean", VERB_ANY, 1, 0, clean_images },
2421 {}
2422 };
2423
2424 return dispatch_verb(argc, argv, verbs, bus);
2425 }
2426
2427 static int run(int argc, char *argv[]) {
2428 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2429 int r;
2430
2431 setlocale(LC_ALL, "");
2432 log_setup();
2433
2434 /* The journal merging logic potentially needs a lot of fds. */
2435 (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
2436 sigbus_install();
2437
2438 r = parse_argv(argc, argv);
2439 if (r <= 0)
2440 return r;
2441
2442 if (STRPTR_IN_SET(argv[optind],
2443 "import-tar", "import-raw", "import-fs",
2444 "export-tar", "export-raw",
2445 "pull-tar", "pull-raw",
2446 "list-transfers", "cancel-transfer"))
2447 return chainload_importctl(argc, argv);
2448
2449 r = bus_connect_transport(arg_transport, arg_host, RUNTIME_SCOPE_SYSTEM, &bus);
2450 if (r < 0)
2451 return bus_log_connect_error(r, arg_transport);
2452
2453 (void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
2454
2455 return machinectl_main(argc, argv, bus);
2456 }
2457
2458 DEFINE_MAIN_FUNCTION(run);