1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "alloc-util.h"
10 #include "bus-locator.h"
12 #include "discover-image.h"
14 #include "format-table.h"
15 #include "hostname-util.h"
16 #include "import-common.h"
17 #include "import-util.h"
18 #include "locale-util.h"
21 #include "main-func.h"
24 #include "parse-argument.h"
25 #include "parse-util.h"
26 #include "path-util.h"
27 #include "pretty-print.h"
28 #include "signal-util.h"
29 #include "sort-util.h"
30 #include "spawn-polkit-agent.h"
31 #include "string-table.h"
35 static PagerFlags arg_pager_flags
= 0;
36 static bool arg_legend
= true;
37 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
38 static const char *arg_host
= NULL
;
39 static ImportFlags arg_import_flags
= 0;
40 static ImportFlags arg_import_flags_mask
= 0; /* Indicates which flags have been explicitly set to on or to off */
41 static bool arg_quiet
= false;
42 static bool arg_ask_password
= true;
43 static ImportVerify arg_verify
= IMPORT_VERIFY_SIGNATURE
;
44 static const char* arg_format
= NULL
;
45 static JsonFormatFlags arg_json_format_flags
= JSON_FORMAT_OFF
;
46 static ImageClass arg_image_class
= _IMAGE_CLASS_INVALID
;
48 #define PROGRESS_PREFIX "Total: "
50 static int settle_image_class(void) {
52 if (arg_image_class
< 0) {
53 _cleanup_free_
char *j
= NULL
;
55 for (ImageClass
class = 0; class < _IMAGE_CLASS_MAX
; class++)
56 if (strextendf_with_separator(&j
, ", ", "%s (downloads to %s/)",
57 image_class_to_string(class),
58 image_root_to_string(class)) < 0)
61 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
62 "No image class specified, retry with --class= set to one of: %s.", j
);
65 /* Keep the original pristine downloaded file as a copy only when dealing with machine images,
66 * because unlike sysext/confext/portable they are typically modified during runtime. */
67 if (!FLAGS_SET(arg_import_flags_mask
, IMPORT_PULL_KEEP_DOWNLOAD
))
68 SET_FLAG(arg_import_flags
, IMPORT_PULL_KEEP_DOWNLOAD
, arg_image_class
== IMAGE_MACHINE
);
73 typedef struct Context
{
74 const char *object_path
;
78 static int match_log_message(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
79 Context
*c
= ASSERT_PTR(userdata
);
86 if (!streq_ptr(c
->object_path
, sd_bus_message_get_path(m
)))
89 r
= sd_bus_message_read(m
, "us", &priority
, &line
);
91 bus_log_parse_error(r
);
95 if (arg_quiet
&& LOG_PRI(priority
) >= LOG_INFO
)
99 clear_progress_bar(PROGRESS_PREFIX
);
101 log_full(priority
, "%s", line
);
104 draw_progress_bar(PROGRESS_PREFIX
, c
->progress
* 100);
109 static int match_progress_update(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
110 Context
*c
= ASSERT_PTR(userdata
);
115 if (!streq_ptr(c
->object_path
, sd_bus_message_get_path(m
)))
118 r
= sd_bus_message_read(m
, "d", &c
->progress
);
120 bus_log_parse_error(r
);
125 draw_progress_bar(PROGRESS_PREFIX
, c
->progress
* 100);
130 static int match_transfer_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
131 Context
*c
= ASSERT_PTR(userdata
);
132 const char *path
, *result
;
139 clear_progress_bar(PROGRESS_PREFIX
);
141 r
= sd_bus_message_read(m
, "uos", &id
, &path
, &result
);
143 bus_log_parse_error(r
);
147 if (!streq_ptr(c
->object_path
, path
))
150 sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m
)), !streq_ptr(result
, "done"));
154 static int transfer_signal_handler(sd_event_source
*s
, const struct signalfd_siginfo
*si
, void *userdata
) {
159 clear_progress_bar(PROGRESS_PREFIX
);
162 log_info("Continuing download in the background. Use \"%s cancel-transfer %" PRIu32
"\" to abort transfer.",
163 program_invocation_short_name
,
164 PTR_TO_UINT32(userdata
));
166 sd_event_exit(sd_event_source_get_event(s
), EINTR
);
170 static int transfer_image_common(sd_bus
*bus
, sd_bus_message
*m
) {
171 _cleanup_(sd_bus_slot_unrefp
) sd_bus_slot
*slot_job_removed
= NULL
, *slot_log_message
= NULL
, *slot_progress_update
= NULL
;
172 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
173 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
174 _cleanup_(sd_event_unrefp
) sd_event
* event
= NULL
;
182 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
184 r
= sd_event_default(&event
);
186 return log_error_errno(r
, "Failed to get event loop: %m");
188 r
= sd_bus_attach_event(bus
, event
, 0);
190 return log_error_errno(r
, "Failed to attach bus to event loop: %m");
192 r
= bus_match_signal_async(
197 match_transfer_removed
,
198 /* add_callback= */ NULL
,
201 return log_error_errno(r
, "Failed to request match: %m");
203 r
= sd_bus_match_signal_async(
206 "org.freedesktop.import1",
207 /* object_path= */ NULL
,
208 "org.freedesktop.import1.Transfer",
211 /* add_callback= */ NULL
,
214 return log_error_errno(r
, "Failed to request match: %m");
216 r
= sd_bus_match_signal_async(
218 &slot_progress_update
,
219 "org.freedesktop.import1",
220 /* object_path= */ NULL
,
221 "org.freedesktop.import1.Transfer",
223 match_progress_update
,
224 /* add_callback= */ NULL
,
227 return log_error_errno(r
, "Failed to request match: %m");
229 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
231 return log_error_errno(r
, "Failed to transfer image: %s", bus_error_message(&error
, r
));
233 r
= sd_bus_message_read(reply
, "uo", &id
, &c
.object_path
);
235 return bus_log_parse_error(r
);
238 clear_progress_bar(PROGRESS_PREFIX
);
239 log_info("Enqueued transfer job %u. Press C-c to continue download in background.", id
);
240 draw_progress_bar(PROGRESS_PREFIX
, c
.progress
);
243 (void) sd_event_add_signal(event
, NULL
, SIGINT
|SD_EVENT_SIGNAL_PROCMASK
, transfer_signal_handler
, UINT32_TO_PTR(id
));
244 (void) sd_event_add_signal(event
, NULL
, SIGTERM
|SD_EVENT_SIGNAL_PROCMASK
, transfer_signal_handler
, UINT32_TO_PTR(id
));
246 r
= sd_event_loop(event
);
248 return log_error_errno(r
, "Failed to run event loop: %m");
253 static int import_tar(int argc
, char *argv
[], void *userdata
) {
254 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
255 _cleanup_free_
char *ll
= NULL
, *fn
= NULL
;
256 const char *local
= NULL
, *path
= NULL
;
257 _cleanup_close_
int fd
= -EBADF
;
258 sd_bus
*bus
= ASSERT_PTR(userdata
);
261 r
= settle_image_class();
266 path
= empty_or_dash_to_null(argv
[1]);
269 local
= empty_or_dash_to_null(argv
[2]);
271 r
= path_extract_filename(path
, &fn
);
273 return log_error_errno(r
, "Cannot extract container name from filename: %m");
274 if (r
== O_DIRECTORY
)
275 return log_error_errno(SYNTHETIC_ERRNO(EISDIR
),
276 "Path '%s' refers to directory, but we need a regular file: %m", path
);
281 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
282 "Need either path or local name.");
284 r
= tar_strip_suffixes(local
, &ll
);
290 if (!image_name_is_valid(local
))
291 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
292 "Local name %s is not a suitable image name.",
296 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
298 return log_error_errno(errno
, "Failed to open %s: %m", path
);
301 if (arg_image_class
== IMAGE_MACHINE
&& (arg_image_class
& ~(IMPORT_FORCE
|IMPORT_READ_ONLY
)) == 0) {
302 r
= bus_message_new_method_call(bus
, &m
, bus_import_mgr
, "ImportTar");
304 return bus_log_create_error(r
);
306 r
= sd_bus_message_append(
309 fd
>= 0 ? fd
: STDIN_FILENO
,
311 FLAGS_SET(arg_import_flags
, IMPORT_FORCE
),
312 FLAGS_SET(arg_import_flags
, IMPORT_READ_ONLY
));
314 r
= bus_message_new_method_call(bus
, &m
, bus_import_mgr
, "ImportTarEx");
316 return bus_log_create_error(r
);
318 r
= sd_bus_message_append(
321 fd
>= 0 ? fd
: STDIN_FILENO
,
323 image_class_to_string(arg_image_class
),
324 (uint64_t) arg_import_flags
& (IMPORT_FORCE
|IMPORT_READ_ONLY
));
327 return bus_log_create_error(r
);
329 return transfer_image_common(bus
, m
);
332 static int import_raw(int argc
, char *argv
[], void *userdata
) {
333 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
334 _cleanup_free_
char *ll
= NULL
, *fn
= NULL
;
335 const char *local
= NULL
, *path
= NULL
;
336 _cleanup_close_
int fd
= -EBADF
;
337 sd_bus
*bus
= ASSERT_PTR(userdata
);
340 r
= settle_image_class();
345 path
= empty_or_dash_to_null(argv
[1]);
348 local
= empty_or_dash_to_null(argv
[2]);
350 r
= path_extract_filename(path
, &fn
);
352 return log_error_errno(r
, "Cannot extract container name from filename: %m");
353 if (r
== O_DIRECTORY
)
354 return log_error_errno(SYNTHETIC_ERRNO(EISDIR
),
355 "Path '%s' refers to directory, but we need a regular file: %m", path
);
360 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
361 "Need either path or local name.");
363 r
= raw_strip_suffixes(local
, &ll
);
369 if (!image_name_is_valid(local
))
370 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
371 "Local name %s is not a suitable image name.",
375 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
377 return log_error_errno(errno
, "Failed to open %s: %m", path
);
380 if (arg_image_class
== IMAGE_MACHINE
&& (arg_image_class
& ~(IMPORT_FORCE
|IMPORT_READ_ONLY
)) == 0) {
381 r
= bus_message_new_method_call(bus
, &m
, bus_import_mgr
, "ImportRaw");
383 return bus_log_create_error(r
);
385 r
= sd_bus_message_append(
388 fd
>= 0 ? fd
: STDIN_FILENO
,
390 FLAGS_SET(arg_import_flags
, IMPORT_FORCE
),
391 FLAGS_SET(arg_import_flags
, IMPORT_READ_ONLY
));
393 r
= bus_message_new_method_call(bus
, &m
, bus_import_mgr
, "ImportRawEx");
395 return bus_log_create_error(r
);
397 r
= sd_bus_message_append(
400 fd
>= 0 ? fd
: STDIN_FILENO
,
402 image_class_to_string(arg_image_class
),
403 (uint64_t) arg_import_flags
& (IMPORT_FORCE
|IMPORT_READ_ONLY
));
406 return bus_log_create_error(r
);
408 return transfer_image_common(bus
, m
);
411 static int import_fs(int argc
, char *argv
[], void *userdata
) {
412 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
413 const char *local
= NULL
, *path
= NULL
;
414 _cleanup_free_
char *fn
= NULL
;
415 _cleanup_close_
int fd
= -EBADF
;
416 sd_bus
*bus
= ASSERT_PTR(userdata
);
419 r
= settle_image_class();
424 path
= empty_or_dash_to_null(argv
[1]);
427 local
= empty_or_dash_to_null(argv
[2]);
429 r
= path_extract_filename(path
, &fn
);
431 return log_error_errno(r
, "Cannot extract container name from filename: %m");
436 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
437 "Need either path or local name.");
439 if (!image_name_is_valid(local
))
440 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
441 "Local name %s is not a suitable image name.",
445 fd
= open(path
, O_DIRECTORY
|O_RDONLY
|O_CLOEXEC
);
447 return log_error_errno(errno
, "Failed to open directory '%s': %m", path
);
450 if (arg_image_class
== IMAGE_MACHINE
&& (arg_image_class
& ~(IMPORT_FORCE
|IMPORT_READ_ONLY
)) == 0) {
451 r
= bus_message_new_method_call(bus
, &m
, bus_import_mgr
, "ImportFileSystem");
453 return bus_log_create_error(r
);
455 r
= sd_bus_message_append(
458 fd
>= 0 ? fd
: STDIN_FILENO
,
460 FLAGS_SET(arg_import_flags
, IMPORT_FORCE
),
461 FLAGS_SET(arg_import_flags
, IMPORT_READ_ONLY
));
463 r
= bus_message_new_method_call(bus
, &m
, bus_import_mgr
, "ImportFileSystemEx");
465 return bus_log_create_error(r
);
467 r
= sd_bus_message_append(
470 fd
>= 0 ? fd
: STDIN_FILENO
,
472 image_class_to_string(arg_image_class
),
473 (uint64_t) arg_import_flags
& (IMPORT_FORCE
|IMPORT_READ_ONLY
));
476 return bus_log_create_error(r
);
479 return transfer_image_common(bus
, m
);
482 static void determine_compression_from_filename(const char *p
) {
489 if (endswith(p
, ".xz"))
491 else if (endswith(p
, ".gz"))
493 else if (endswith(p
, ".bz2"))
494 arg_format
= "bzip2";
497 static int export_tar(int argc
, char *argv
[], void *userdata
) {
498 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
499 _cleanup_close_
int fd
= -EBADF
;
500 const char *local
= NULL
, *path
= NULL
;
501 sd_bus
*bus
= ASSERT_PTR(userdata
);
504 r
= settle_image_class();
509 if (!image_name_is_valid(local
))
510 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
511 "Image name %s is not valid.", local
);
515 path
= empty_or_dash_to_null(path
);
518 determine_compression_from_filename(path
);
520 fd
= open(path
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_CLOEXEC
|O_NOCTTY
, 0666);
522 return log_error_errno(errno
, "Failed to open %s: %m", path
);
525 if (arg_image_class
== IMAGE_MACHINE
&& arg_import_flags
== 0) {
526 r
= bus_message_new_method_call(bus
, &m
, bus_import_mgr
, "ExportTar");
528 return bus_log_create_error(r
);
530 r
= sd_bus_message_append(
534 fd
>= 0 ? fd
: STDOUT_FILENO
,
537 r
= bus_message_new_method_call(bus
, &m
, bus_import_mgr
, "ExportTarEx");
539 return bus_log_create_error(r
);
541 r
= sd_bus_message_append(
545 image_class_to_string(arg_image_class
),
546 fd
>= 0 ? fd
: STDOUT_FILENO
,
551 return bus_log_create_error(r
);
553 return transfer_image_common(bus
, m
);
556 static int export_raw(int argc
, char *argv
[], void *userdata
) {
557 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
558 _cleanup_close_
int fd
= -EBADF
;
559 const char *local
= NULL
, *path
= NULL
;
560 sd_bus
*bus
= ASSERT_PTR(userdata
);
563 r
= settle_image_class();
568 if (!image_name_is_valid(local
))
569 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
570 "Image name %s is not valid.", local
);
574 path
= empty_or_dash_to_null(path
);
577 determine_compression_from_filename(path
);
579 fd
= open(path
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_CLOEXEC
|O_NOCTTY
, 0666);
581 return log_error_errno(errno
, "Failed to open %s: %m", path
);
584 if (arg_image_class
== IMAGE_MACHINE
&& arg_import_flags
== 0) {
585 r
= bus_message_new_method_call(bus
, &m
, bus_import_mgr
, "ExportRaw");
587 return bus_log_create_error(r
);
589 r
= sd_bus_message_append(
593 fd
>= 0 ? fd
: STDOUT_FILENO
,
596 r
= bus_message_new_method_call(bus
, &m
, bus_import_mgr
, "ExportRawEx");
598 return bus_log_create_error(r
);
600 r
= sd_bus_message_append(
604 image_class_to_string(arg_image_class
),
605 fd
>= 0 ? fd
: STDOUT_FILENO
,
610 return bus_log_create_error(r
);
612 return transfer_image_common(bus
, m
);
615 static int pull_tar(int argc
, char *argv
[], void *userdata
) {
616 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
617 _cleanup_free_
char *l
= NULL
, *ll
= NULL
;
618 const char *local
, *remote
;
619 sd_bus
*bus
= ASSERT_PTR(userdata
);
622 r
= settle_image_class();
627 if (!http_url_is_valid(remote
) && !file_url_is_valid(remote
))
628 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
629 "URL '%s' is not valid.", remote
);
634 r
= import_url_last_component(remote
, &l
);
636 return log_error_errno(r
, "Failed to get final component of URL: %m");
641 local
= empty_or_dash_to_null(local
);
644 r
= tar_strip_suffixes(local
, &ll
);
650 if (!image_name_is_valid(local
))
651 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
652 "Local name %s is not a suitable image name.",
656 if (arg_image_class
== IMAGE_MACHINE
&& (arg_image_class
& ~IMPORT_FORCE
) == 0) {
657 r
= bus_message_new_method_call(bus
, &m
, bus_import_mgr
, "PullTar");
659 return bus_log_create_error(r
);
661 r
= sd_bus_message_append(
666 import_verify_to_string(arg_verify
),
667 FLAGS_SET(arg_import_flags
, IMPORT_FORCE
));
669 r
= bus_message_new_method_call(bus
, &m
, bus_import_mgr
, "PullTarEx");
671 return bus_log_create_error(r
);
673 r
= sd_bus_message_append(
678 image_class_to_string(arg_image_class
),
679 import_verify_to_string(arg_verify
),
680 (uint64_t) arg_import_flags
& (IMPORT_FORCE
|IMPORT_READ_ONLY
|IMPORT_PULL_KEEP_DOWNLOAD
));
683 return bus_log_create_error(r
);
685 return transfer_image_common(bus
, m
);
688 static int pull_raw(int argc
, char *argv
[], void *userdata
) {
689 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
690 _cleanup_free_
char *l
= NULL
, *ll
= NULL
;
691 const char *local
, *remote
;
692 sd_bus
*bus
= ASSERT_PTR(userdata
);
695 r
= settle_image_class();
700 if (!http_url_is_valid(remote
) && !file_url_is_valid(remote
))
701 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
702 "URL '%s' is not valid.", remote
);
707 r
= import_url_last_component(remote
, &l
);
709 return log_error_errno(r
, "Failed to get final component of URL: %m");
714 local
= empty_or_dash_to_null(local
);
717 r
= raw_strip_suffixes(local
, &ll
);
723 if (!image_name_is_valid(local
))
724 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
725 "Local name %s is not a suitable image name.",
729 if (arg_image_class
== IMAGE_MACHINE
&& (arg_image_class
& ~IMPORT_FORCE
) == 0) {
730 r
= bus_message_new_method_call(bus
, &m
, bus_import_mgr
, "PullRaw");
732 return bus_log_create_error(r
);
734 r
= sd_bus_message_append(
739 import_verify_to_string(arg_verify
),
740 FLAGS_SET(arg_import_flags
, IMPORT_FORCE
));
742 r
= bus_message_new_method_call(bus
, &m
, bus_import_mgr
, "PullRawEx");
744 return bus_log_create_error(r
);
746 r
= sd_bus_message_append(
751 image_class_to_string(arg_image_class
),
752 import_verify_to_string(arg_verify
),
753 (uint64_t) arg_import_flags
& (IMPORT_FORCE
|IMPORT_READ_ONLY
|IMPORT_PULL_KEEP_DOWNLOAD
));
756 return bus_log_create_error(r
);
758 return transfer_image_common(bus
, m
);
761 static int list_transfers(int argc
, char *argv
[], void *userdata
) {
762 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
763 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
764 _cleanup_(table_unrefp
) Table
*t
= NULL
;
765 sd_bus
*bus
= ASSERT_PTR(userdata
);
768 pager_open(arg_pager_flags
);
771 r
= bus_call_method(bus
, bus_import_mgr
, "ListTransfersEx", &error
, &reply
, "st", image_class_to_string(arg_image_class
), UINT64_C(0));
773 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
)) {
774 sd_bus_error_free(&error
);
776 r
= bus_call_method(bus
, bus_import_mgr
, "ListTransfers", &error
, &reply
, NULL
);
779 return log_error_errno(r
, "Could not get transfers: %s", bus_error_message(&error
, r
));
782 r
= sd_bus_message_enter_container(reply
, 'a', "(usssdo)");
785 r
= sd_bus_message_enter_container(reply
, 'a', "(ussssdo)");
788 return bus_log_parse_error(r
);
790 t
= table_new("id", "progress", "type", "class", "local", "remote");
794 (void) table_set_sort(t
, (size_t) 4, (size_t) 0);
795 table_set_ersatz_string(t
, TABLE_ERSATZ_DASH
);
798 const char *type
, *remote
, *local
, *class = "machine";
803 r
= sd_bus_message_read(reply
, "(ussssdo)", &id
, &type
, &remote
, &local
, &class, &progress
, NULL
);
805 r
= sd_bus_message_read(reply
, "(usssdo)", &id
, &type
, &remote
, &local
, &progress
, NULL
);
807 return bus_log_parse_error(r
);
811 /* Ideally we use server-side filtering. But if the server can't do it, we need to do it client side */
812 if (arg_image_class
>= 0 && image_class_from_string(class) != arg_image_class
)
818 TABLE_SET_ALIGN_PERCENT
, 100);
820 return table_log_add_error(r
);
826 TABLE_SET_ALIGN_PERCENT
, 100);
830 TABLE_PERCENT
, (int) (progress
* 100),
831 TABLE_SET_ALIGN_PERCENT
, 100);
833 return table_log_add_error(r
);
839 TABLE_STRING
, remote
,
840 TABLE_SET_URL
, remote
);
842 return table_log_add_error(r
);
845 r
= sd_bus_message_exit_container(reply
);
847 return bus_log_parse_error(r
);
849 if (!table_isempty(t
)) {
850 r
= table_print_with_pager(t
, arg_json_format_flags
, arg_pager_flags
, arg_legend
);
852 return log_error_errno(r
, "Failed to output table: %m");
856 if (!table_isempty(t
))
857 printf("\n%zu transfers listed.\n", table_get_rows(t
) - 1);
859 printf("No transfers.\n");
865 static int cancel_transfer(int argc
, char *argv
[], void *userdata
) {
866 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
867 sd_bus
*bus
= ASSERT_PTR(userdata
);
870 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
872 for (int i
= 1; i
< argc
; i
++) {
875 r
= safe_atou32(argv
[i
], &id
);
877 return log_error_errno(r
, "Failed to parse transfer id: %s", argv
[i
]);
879 r
= bus_call_method(bus
, bus_import_mgr
, "CancelTransfer", &error
, NULL
, "u", id
);
881 return log_error_errno(r
, "Could not cancel transfer: %s", bus_error_message(&error
, r
));
887 static int help(int argc
, char *argv
[], void *userdata
) {
888 _cleanup_free_
char *link
= NULL
;
891 pager_open(arg_pager_flags
);
893 r
= terminal_urlify_man("importctl", "1", &link
);
897 printf("%1$s [OPTIONS...] COMMAND ...\n\n"
898 "%5$sDownload, import or export disk images%6$s\n"
899 "\n%3$sCommands:%4$s\n"
900 " pull-tar URL [NAME] Download a TAR container image\n"
901 " pull-raw URL [NAME] Download a RAW container or VM image\n"
902 " import-tar FILE [NAME] Import a local TAR container image\n"
903 " import-raw FILE [NAME] Import a local RAW container or VM image\n"
904 " import-fs DIRECTORY [NAME] Import a local directory container image\n"
905 " export-tar NAME [FILE] Export a TAR container image locally\n"
906 " export-raw NAME [FILE] Export a RAW container or VM image locally\n"
907 " list-transfers Show list of transfers in progress\n"
908 " cancel-transfer [ID...] Cancel a transfer\n"
909 "\n%3$sOptions:%4$s\n"
910 " -h --help Show this help\n"
911 " --version Show package version\n"
912 " --no-pager Do not pipe output into a pager\n"
913 " --no-legend Do not show the headers and footers\n"
914 " --no-ask-password Do not ask for system passwords\n"
915 " -H --host=[USER@]HOST Operate on remote host\n"
916 " -M --machine=CONTAINER Operate on local container\n"
917 " --read-only Create read-only image\n"
918 " -q --quiet Suppress output\n"
919 " --json=pretty|short|off Generate JSON output\n"
920 " -j Equvilant to --json=pretty on TTY, --json=short\n"
922 " --verify=MODE Verification mode for downloaded images (no,\n"
923 " checksum, signature)\n"
924 " --format=xz|gzip|bzip2 Desired output format for export\n"
925 " --force Install image even if already exists\n"
926 " -m --class=machine Install as machine image\n"
927 " -P --class=portable Install as portable service image\n"
928 " -S --class=sysext Install as system extension image\n"
929 " -C --class=confext Install as configuration extension image\n"
930 " --keep-download=BOOL Control whether to keep pristine copy of download\n"
931 " -N Shortcut for --keep-download=no\n"
932 "\nSee the %2$s for details.\n",
933 program_invocation_short_name
,
943 static int parse_argv(int argc
, char *argv
[]) {
959 static const struct option options
[] = {
960 { "help", no_argument
, NULL
, 'h' },
961 { "version", no_argument
, NULL
, ARG_VERSION
},
962 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
963 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
964 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
965 { "host", required_argument
, NULL
, 'H' },
966 { "machine", required_argument
, NULL
, 'M' },
967 { "read-only", no_argument
, NULL
, ARG_READ_ONLY
},
968 { "json", required_argument
, NULL
, ARG_JSON
},
969 { "quiet", no_argument
, NULL
, 'q' },
970 { "verify", required_argument
, NULL
, ARG_VERIFY
},
971 { "force", no_argument
, NULL
, ARG_FORCE
},
972 { "format", required_argument
, NULL
, ARG_FORMAT
},
973 { "class", required_argument
, NULL
, ARG_CLASS
},
974 { "keep-download", required_argument
, NULL
, ARG_KEEP_DOWNLOAD
},
984 c
= getopt_long(argc
, argv
, "hH:M:jqmPSCN", options
, NULL
);
991 return help(0, NULL
, NULL
);
997 arg_pager_flags
|= PAGER_DISABLE
;
1004 case ARG_NO_ASK_PASSWORD
:
1005 arg_ask_password
= false;
1009 arg_transport
= BUS_TRANSPORT_REMOTE
;
1014 arg_transport
= BUS_TRANSPORT_MACHINE
;
1019 arg_import_flags
|= IMPORT_READ_ONLY
;
1020 arg_import_flags_mask
|= IMPORT_READ_ONLY
;
1028 if (streq(optarg
, "help")) {
1029 DUMP_STRING_TABLE(import_verify
, ImportVerify
, _IMPORT_VERIFY_MAX
);
1033 r
= import_verify_from_string(optarg
);
1035 return log_error_errno(r
, "Failed to parse --verify= setting: %s", optarg
);
1040 arg_import_flags
|= IMPORT_FORCE
;
1041 arg_import_flags_mask
|= IMPORT_FORCE
;
1045 if (!STR_IN_SET(optarg
, "uncompressed", "xz", "gzip", "bzip2"))
1046 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1047 "Unknown format: %s", optarg
);
1049 arg_format
= optarg
;
1053 r
= parse_json_argument(optarg
, &arg_json_format_flags
);
1061 arg_json_format_flags
= JSON_FORMAT_PRETTY_AUTO
|JSON_FORMAT_COLOR_AUTO
;
1066 arg_image_class
= image_class_from_string(optarg
);
1067 if (arg_image_class
< 0)
1068 return log_error_errno(arg_image_class
, "Failed to parse --class= parameter: %s", optarg
);
1072 arg_image_class
= IMAGE_MACHINE
;
1076 arg_image_class
= IMAGE_PORTABLE
;
1080 arg_image_class
= IMAGE_SYSEXT
;
1084 arg_image_class
= IMAGE_CONFEXT
;
1087 case ARG_KEEP_DOWNLOAD
:
1088 r
= parse_boolean(optarg
);
1090 return log_error_errno(r
, "Failed to parse --keep-download= value: %s", optarg
);
1092 SET_FLAG(arg_import_flags
, IMPORT_PULL_KEEP_DOWNLOAD
, r
);
1093 arg_import_flags_mask
|= IMPORT_PULL_KEEP_DOWNLOAD
;
1097 arg_import_flags_mask
&= ~IMPORT_PULL_KEEP_DOWNLOAD
;
1098 arg_import_flags_mask
|= IMPORT_PULL_KEEP_DOWNLOAD
;
1105 assert_not_reached();
1112 static int importctl_main(int argc
, char *argv
[], sd_bus
*bus
) {
1114 static const Verb verbs
[] = {
1115 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
1116 { "import-tar", 2, 3, 0, import_tar
},
1117 { "import-raw", 2, 3, 0, import_raw
},
1118 { "import-fs", 2, 3, 0, import_fs
},
1119 { "export-tar", 2, 3, 0, export_tar
},
1120 { "export-raw", 2, 3, 0, export_raw
},
1121 { "pull-tar", 2, 3, 0, pull_tar
},
1122 { "pull-raw", 2, 3, 0, pull_raw
},
1123 { "list-transfers", VERB_ANY
, 1, VERB_DEFAULT
, list_transfers
},
1124 { "cancel-transfer", 2, VERB_ANY
, 0, cancel_transfer
},
1128 return dispatch_verb(argc
, argv
, verbs
, bus
);
1131 static int run(int argc
, char *argv
[]) {
1132 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1135 setlocale(LC_ALL
, "");
1138 r
= parse_argv(argc
, argv
);
1142 r
= bus_connect_transport(arg_transport
, arg_host
, RUNTIME_SCOPE_SYSTEM
, &bus
);
1144 return bus_log_connect_error(r
, arg_transport
);
1146 (void) sd_bus_set_allow_interactive_authorization(bus
, arg_ask_password
);
1148 return importctl_main(argc
, argv
, bus
);
1151 DEFINE_MAIN_FUNCTION(run
);