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