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