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