1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "alloc-util.h"
9 #include "bus-common-errors.h"
10 #include "bus-get-properties.h"
11 #include "bus-log-control-api.h"
12 #include "bus-polkit.h"
17 #include "hostname-util.h"
18 #include "import-util.h"
19 #include "machine-pool.h"
20 #include "main-func.h"
21 #include "missing_capability.h"
22 #include "mkdir-label.h"
23 #include "parse-util.h"
24 #include "path-util.h"
25 #include "percent-util.h"
26 #include "process-util.h"
27 #include "service-util.h"
28 #include "signal-util.h"
29 #include "socket-util.h"
30 #include "stat-util.h"
31 #include "string-table.h"
33 #include "syslog-util.h"
34 #include "user-util.h"
38 typedef struct Transfer Transfer
;
39 typedef struct Manager Manager
;
41 typedef enum TransferType
{
50 _TRANSFER_TYPE_INVALID
= -EINVAL
,
73 char log_message
[LINE_MAX
];
74 size_t log_message_size
;
76 sd_event_source
*pid_event_source
;
77 sd_event_source
*log_event_source
;
80 unsigned progress_percent
;
90 uint32_t current_transfer_id
;
93 Hashmap
*polkit_registry
;
97 sd_event_source
*notify_event_source
;
100 #define TRANSFERS_MAX 64
102 static const char* const transfer_type_table
[_TRANSFER_TYPE_MAX
] = {
103 [TRANSFER_IMPORT_TAR
] = "import-tar",
104 [TRANSFER_IMPORT_RAW
] = "import-raw",
105 [TRANSFER_IMPORT_FS
] = "import-fs",
106 [TRANSFER_EXPORT_TAR
] = "export-tar",
107 [TRANSFER_EXPORT_RAW
] = "export-raw",
108 [TRANSFER_PULL_TAR
] = "pull-tar",
109 [TRANSFER_PULL_RAW
] = "pull-raw",
112 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(transfer_type
, TransferType
);
114 static Transfer
*transfer_unref(Transfer
*t
) {
119 hashmap_remove(t
->manager
->transfers
, UINT32_TO_PTR(t
->id
));
121 sd_event_source_unref(t
->pid_event_source
);
122 sd_event_source_unref(t
->log_event_source
);
127 free(t
->object_path
);
130 sigkill_wait(t
->pid
);
132 safe_close(t
->log_fd
);
133 safe_close(t
->stdin_fd
);
134 safe_close(t
->stdout_fd
);
139 DEFINE_TRIVIAL_CLEANUP_FUNC(Transfer
*, transfer_unref
);
141 static int transfer_new(Manager
*m
, Transfer
**ret
) {
142 _cleanup_(transfer_unrefp
) Transfer
*t
= NULL
;
149 if (hashmap_size(m
->transfers
) >= TRANSFERS_MAX
)
152 t
= new(Transfer
, 1);
157 .type
= _TRANSFER_TYPE_INVALID
,
161 .verify
= _IMPORT_VERIFY_INVALID
,
162 .progress_percent
= UINT_MAX
,
165 id
= m
->current_transfer_id
+ 1;
167 if (asprintf(&t
->object_path
, "/org/freedesktop/import1/transfer/_%" PRIu32
, id
) < 0)
170 r
= hashmap_ensure_put(&m
->transfers
, &trivial_hash_ops
, UINT32_TO_PTR(id
), t
);
174 m
->current_transfer_id
= id
;
184 static double transfer_percent_as_double(Transfer
*t
) {
187 if (t
->progress_percent
== UINT_MAX
)
190 return (double) t
->progress_percent
/ 100.0;
193 static void transfer_send_log_line(Transfer
*t
, const char *line
) {
194 int r
, priority
= LOG_INFO
;
199 syslog_parse_priority(&line
, &priority
, true);
201 log_full(priority
, "(transfer%" PRIu32
") %s", t
->id
, line
);
203 r
= sd_bus_emit_signal(
206 "org.freedesktop.import1.Transfer",
212 log_warning_errno(r
, "Cannot emit log message signal, ignoring: %m");
215 static void transfer_send_logs(Transfer
*t
, bool flush
) {
218 /* Try to send out all log messages, if we can. But if we
219 * can't we remove the messages from the buffer, but don't
222 while (t
->log_message_size
> 0) {
223 _cleanup_free_
char *n
= NULL
;
226 if (t
->log_message_size
>= sizeof(t
->log_message
))
227 e
= t
->log_message
+ sizeof(t
->log_message
);
231 a
= memchr(t
->log_message
, 0, t
->log_message_size
);
232 b
= memchr(t
->log_message
, '\n', t
->log_message_size
);
246 e
= t
->log_message
+ t
->log_message_size
;
249 n
= strndup(t
->log_message
, e
- t
->log_message
);
251 /* Skip over NUL and newlines */
252 while (e
< t
->log_message
+ t
->log_message_size
&& IN_SET(*e
, 0, '\n'))
255 memmove(t
->log_message
, e
, t
->log_message
+ sizeof(t
->log_message
) - e
);
256 t
->log_message_size
-= e
- t
->log_message
;
266 transfer_send_log_line(t
, n
);
270 static int transfer_finalize(Transfer
*t
, bool success
) {
275 transfer_send_logs(t
, true);
277 r
= sd_bus_emit_signal(
279 "/org/freedesktop/import1",
280 "org.freedesktop.import1.Manager",
286 t
->n_canceled
> 0 ? "canceled" : "failed");
289 log_error_errno(r
, "Cannot emit message: %m");
295 static int transfer_cancel(Transfer
*t
) {
300 r
= kill_and_sigcont(t
->pid
, t
->n_canceled
< 3 ? SIGTERM
: SIGKILL
);
308 static int transfer_on_pid(sd_event_source
*s
, const siginfo_t
*si
, void *userdata
) {
309 Transfer
*t
= ASSERT_PTR(userdata
);
310 bool success
= false;
314 if (si
->si_code
== CLD_EXITED
) {
315 if (si
->si_status
!= 0)
316 log_error("Transfer process failed with exit code %i.", si
->si_status
);
318 log_debug("Transfer process succeeded.");
322 } else if (IN_SET(si
->si_code
, CLD_KILLED
, CLD_DUMPED
))
323 log_error("Transfer process terminated by signal %s.", signal_to_string(si
->si_status
));
325 log_error("Transfer process failed due to unknown reason.");
329 return transfer_finalize(t
, success
);
332 static int transfer_on_log(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
333 Transfer
*t
= ASSERT_PTR(userdata
);
338 l
= read(fd
, t
->log_message
+ t
->log_message_size
, sizeof(t
->log_message
) - t
->log_message_size
);
340 log_error_errno(errno
, "Failed to read log message: %m");
342 /* EOF/read error. We just close the pipe here, and
343 * close the watch, waiting for the SIGCHLD to arrive,
344 * before we do anything else. */
345 t
->log_event_source
= sd_event_source_unref(t
->log_event_source
);
349 t
->log_message_size
+= l
;
351 transfer_send_logs(t
, false);
356 static int transfer_start(Transfer
*t
) {
357 _cleanup_close_pair_
int pipefd
[2] = { -1, -1 };
363 if (pipe2(pipefd
, O_CLOEXEC
) < 0)
366 r
= safe_fork("(sd-transfer)", FORK_RESET_SIGNALS
|FORK_DEATHSIG
, &t
->pid
);
370 const char *cmd
[] = {
371 NULL
, /* systemd-import, systemd-import-fs, systemd-export or systemd-pull */
373 NULL
, /* --verify= */
374 NULL
, /* verify argument */
375 NULL
, /* maybe --force */
376 NULL
, /* maybe --read-only */
377 NULL
, /* if so: the actual URL */
378 NULL
, /* maybe --format= */
379 NULL
, /* if so: the actual format */
388 pipefd
[0] = safe_close(pipefd
[0]);
390 r
= rearrange_stdio(TAKE_FD(t
->stdin_fd
),
391 t
->stdout_fd
< 0 ? pipefd
[1] : TAKE_FD(t
->stdout_fd
),
395 log_error_errno(r
, "Failed to set stdin/stdout/stderr: %m");
399 if (setenv("SYSTEMD_LOG_TARGET", "console-prefixed", 1) < 0 ||
400 setenv("NOTIFY_SOCKET", "/run/systemd/import/notify", 1) < 0) {
401 log_error_errno(errno
, "setenv() failed: %m");
405 r
= setenv_systemd_exec_pid(true);
407 log_warning_errno(r
, "Failed to update $SYSTEMD_EXEC_PID, ignoring: %m");
411 case TRANSFER_IMPORT_TAR
:
412 case TRANSFER_IMPORT_RAW
:
413 cmd
[k
++] = SYSTEMD_IMPORT_PATH
;
416 case TRANSFER_IMPORT_FS
:
417 cmd
[k
++] = SYSTEMD_IMPORT_FS_PATH
;
420 case TRANSFER_EXPORT_TAR
:
421 case TRANSFER_EXPORT_RAW
:
422 cmd
[k
++] = SYSTEMD_EXPORT_PATH
;
425 case TRANSFER_PULL_TAR
:
426 case TRANSFER_PULL_RAW
:
427 cmd
[k
++] = SYSTEMD_PULL_PATH
;
431 assert_not_reached();
436 case TRANSFER_IMPORT_TAR
:
437 case TRANSFER_EXPORT_TAR
:
438 case TRANSFER_PULL_TAR
:
442 case TRANSFER_IMPORT_RAW
:
443 case TRANSFER_EXPORT_RAW
:
444 case TRANSFER_PULL_RAW
:
448 case TRANSFER_IMPORT_FS
:
456 if (t
->verify
!= _IMPORT_VERIFY_INVALID
) {
457 cmd
[k
++] = "--verify";
458 cmd
[k
++] = import_verify_to_string(t
->verify
);
462 cmd
[k
++] = "--force";
464 cmd
[k
++] = "--read-only";
467 cmd
[k
++] = "--format";
468 cmd
[k
++] = t
->format
;
471 if (!IN_SET(t
->type
, TRANSFER_EXPORT_TAR
, TRANSFER_EXPORT_RAW
)) {
473 cmd
[k
++] = t
->remote
;
482 execv(cmd
[0], (char * const *) cmd
);
483 log_error_errno(errno
, "Failed to execute %s tool: %m", cmd
[0]);
487 pipefd
[1] = safe_close(pipefd
[1]);
488 t
->log_fd
= TAKE_FD(pipefd
[0]);
490 t
->stdin_fd
= safe_close(t
->stdin_fd
);
492 r
= sd_event_add_child(t
->manager
->event
, &t
->pid_event_source
,
493 t
->pid
, WEXITED
, transfer_on_pid
, t
);
497 r
= sd_event_add_io(t
->manager
->event
, &t
->log_event_source
,
498 t
->log_fd
, EPOLLIN
, transfer_on_log
, t
);
502 /* Make sure always process logging before SIGCHLD */
503 r
= sd_event_source_set_priority(t
->log_event_source
, SD_EVENT_PRIORITY_NORMAL
-5);
507 r
= sd_bus_emit_signal(
509 "/org/freedesktop/import1",
510 "org.freedesktop.import1.Manager",
521 static Manager
*manager_unref(Manager
*m
) {
527 sd_event_source_unref(m
->notify_event_source
);
528 safe_close(m
->notify_fd
);
530 while ((t
= hashmap_first(m
->transfers
)))
533 hashmap_free(m
->transfers
);
535 bus_verify_polkit_async_registry_free(m
->polkit_registry
);
537 m
->bus
= sd_bus_flush_close_unref(m
->bus
);
538 sd_event_unref(m
->event
);
543 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager
*, manager_unref
);
545 static int manager_on_notify(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
547 char buf
[NOTIFY_BUFFER_MAX
+1];
548 struct iovec iovec
= {
550 .iov_len
= sizeof(buf
)-1,
552 CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred
)) +
553 CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX
)) control
;
554 struct msghdr msghdr
= {
557 .msg_control
= &control
,
558 .msg_controllen
= sizeof(control
),
561 Manager
*m
= userdata
;
567 n
= recvmsg_safe(fd
, &msghdr
, MSG_DONTWAIT
|MSG_CMSG_CLOEXEC
);
569 if (ERRNO_IS_TRANSIENT(n
))
574 cmsg_close_all(&msghdr
);
576 if (msghdr
.msg_flags
& MSG_TRUNC
) {
577 log_warning("Got overly long notification datagram, ignoring.");
581 ucred
= CMSG_FIND_DATA(&msghdr
, SOL_SOCKET
, SCM_CREDENTIALS
, struct ucred
);
582 if (!ucred
|| ucred
->pid
<= 0) {
583 log_warning("Got notification datagram lacking credential information, ignoring.");
587 HASHMAP_FOREACH(t
, m
->transfers
)
588 if (ucred
->pid
== t
->pid
)
592 log_warning("Got notification datagram from unexpected peer, ignoring.");
598 p
= startswith(buf
, "X_IMPORT_PROGRESS=");
600 p
= strstr(buf
, "\nX_IMPORT_PROGRESS=");
607 e
= strchrnul(p
, '\n');
610 r
= parse_percent(p
);
612 log_warning("Got invalid percent value, ignoring.");
616 t
->progress_percent
= (unsigned) r
;
618 log_debug("Got percentage from client: %u%%", t
->progress_percent
);
622 static int manager_new(Manager
**ret
) {
623 _cleanup_(manager_unrefp
) Manager
*m
= NULL
;
624 static const union sockaddr_union sa
= {
625 .un
.sun_family
= AF_UNIX
,
626 .un
.sun_path
= "/run/systemd/import/notify",
632 m
= new0(Manager
, 1);
636 r
= sd_event_default(&m
->event
);
640 sd_event_set_watchdog(m
->event
, true);
642 r
= sd_bus_default_system(&m
->bus
);
646 m
->notify_fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
647 if (m
->notify_fd
< 0)
650 (void) mkdir_parents_label(sa
.un
.sun_path
, 0755);
651 (void) sockaddr_un_unlink(&sa
.un
);
653 if (bind(m
->notify_fd
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
)) < 0)
656 r
= setsockopt_int(m
->notify_fd
, SOL_SOCKET
, SO_PASSCRED
, true);
660 r
= sd_event_add_io(m
->event
, &m
->notify_event_source
,
661 m
->notify_fd
, EPOLLIN
, manager_on_notify
, m
);
670 static Transfer
*manager_find(Manager
*m
, TransferType type
, const char *remote
) {
675 assert(type
< _TRANSFER_TYPE_MAX
);
677 HASHMAP_FOREACH(t
, m
->transfers
)
678 if (t
->type
== type
&& streq_ptr(t
->remote
, remote
))
684 static int method_import_tar_or_raw(sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
685 _cleanup_(transfer_unrefp
) Transfer
*t
= NULL
;
686 int fd
, force
, read_only
, r
;
687 const char *local
, *object
;
688 Manager
*m
= ASSERT_PTR(userdata
);
695 r
= bus_verify_polkit_async(
698 "org.freedesktop.import1.import",
707 return 1; /* Will call us back */
709 r
= sd_bus_message_read(msg
, "hsbb", &fd
, &local
, &force
, &read_only
);
713 if (fstat(fd
, &st
) < 0)
716 if (!S_ISREG(st
.st_mode
) && !S_ISFIFO(st
.st_mode
))
719 if (!hostname_is_valid(local
, 0))
720 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
,
721 "Local name %s is invalid", local
);
723 r
= setup_machine_directory(error
);
727 type
= streq_ptr(sd_bus_message_get_member(msg
), "ImportTar") ?
728 TRANSFER_IMPORT_TAR
: TRANSFER_IMPORT_RAW
;
730 r
= transfer_new(m
, &t
);
735 t
->force_local
= force
;
736 t
->read_only
= read_only
;
738 t
->local
= strdup(local
);
742 t
->stdin_fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
746 r
= transfer_start(t
);
750 object
= t
->object_path
;
754 return sd_bus_reply_method_return(msg
, "uo", id
, object
);
757 static int method_import_fs(sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
758 _cleanup_(transfer_unrefp
) Transfer
*t
= NULL
;
759 int fd
, force
, read_only
, r
;
760 const char *local
, *object
;
761 Manager
*m
= ASSERT_PTR(userdata
);
766 r
= bus_verify_polkit_async(
769 "org.freedesktop.import1.import",
778 return 1; /* Will call us back */
780 r
= sd_bus_message_read(msg
, "hsbb", &fd
, &local
, &force
, &read_only
);
784 r
= fd_verify_directory(fd
);
788 if (!hostname_is_valid(local
, 0))
789 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
,
790 "Local name %s is invalid", local
);
792 r
= setup_machine_directory(error
);
796 r
= transfer_new(m
, &t
);
800 t
->type
= TRANSFER_IMPORT_FS
;
801 t
->force_local
= force
;
802 t
->read_only
= read_only
;
804 t
->local
= strdup(local
);
808 t
->stdin_fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
812 r
= transfer_start(t
);
816 object
= t
->object_path
;
820 return sd_bus_reply_method_return(msg
, "uo", id
, object
);
823 static int method_export_tar_or_raw(sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
824 _cleanup_(transfer_unrefp
) Transfer
*t
= NULL
;
826 const char *local
, *object
, *format
;
827 Manager
*m
= ASSERT_PTR(userdata
);
834 r
= bus_verify_polkit_async(
837 "org.freedesktop.import1.export",
846 return 1; /* Will call us back */
848 r
= sd_bus_message_read(msg
, "shs", &local
, &fd
, &format
);
852 if (!hostname_is_valid(local
, 0))
853 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
,
854 "Local name %s is invalid", local
);
856 if (fstat(fd
, &st
) < 0)
859 if (!S_ISREG(st
.st_mode
) && !S_ISFIFO(st
.st_mode
))
862 type
= streq_ptr(sd_bus_message_get_member(msg
), "ExportTar") ?
863 TRANSFER_EXPORT_TAR
: TRANSFER_EXPORT_RAW
;
865 r
= transfer_new(m
, &t
);
871 if (!isempty(format
)) {
872 t
->format
= strdup(format
);
877 t
->local
= strdup(local
);
881 t
->stdout_fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
882 if (t
->stdout_fd
< 0)
885 r
= transfer_start(t
);
889 object
= t
->object_path
;
893 return sd_bus_reply_method_return(msg
, "uo", id
, object
);
896 static int method_pull_tar_or_raw(sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
897 _cleanup_(transfer_unrefp
) Transfer
*t
= NULL
;
898 const char *remote
, *local
, *verify
, *object
;
899 Manager
*m
= ASSERT_PTR(userdata
);
907 r
= bus_verify_polkit_async(
910 "org.freedesktop.import1.pull",
919 return 1; /* Will call us back */
921 r
= sd_bus_message_read(msg
, "sssb", &remote
, &local
, &verify
, &force
);
925 if (!http_url_is_valid(remote
) && !file_url_is_valid(remote
))
926 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
,
927 "URL %s is invalid", remote
);
931 else if (!hostname_is_valid(local
, 0))
932 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
,
933 "Local name %s is invalid", local
);
936 v
= IMPORT_VERIFY_SIGNATURE
;
938 v
= import_verify_from_string(verify
);
940 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
,
941 "Unknown verification mode %s", verify
);
943 r
= setup_machine_directory(error
);
947 type
= streq_ptr(sd_bus_message_get_member(msg
), "PullTar") ?
948 TRANSFER_PULL_TAR
: TRANSFER_PULL_RAW
;
950 if (manager_find(m
, type
, remote
))
951 return sd_bus_error_setf(error
, BUS_ERROR_TRANSFER_IN_PROGRESS
,
952 "Transfer for %s already in progress.", remote
);
954 r
= transfer_new(m
, &t
);
960 t
->force_local
= force
;
962 t
->remote
= strdup(remote
);
967 t
->local
= strdup(local
);
972 r
= transfer_start(t
);
976 object
= t
->object_path
;
980 return sd_bus_reply_method_return(msg
, "uo", id
, object
);
983 static int method_list_transfers(sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
984 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
985 Manager
*m
= ASSERT_PTR(userdata
);
991 r
= sd_bus_message_new_method_return(msg
, &reply
);
995 r
= sd_bus_message_open_container(reply
, 'a', "(usssdo)");
999 HASHMAP_FOREACH(t
, m
->transfers
) {
1001 r
= sd_bus_message_append(
1005 transfer_type_to_string(t
->type
),
1008 transfer_percent_as_double(t
),
1014 r
= sd_bus_message_close_container(reply
);
1018 return sd_bus_send(NULL
, reply
, NULL
);
1021 static int method_cancel(sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
1022 Transfer
*t
= ASSERT_PTR(userdata
);
1027 r
= bus_verify_polkit_async(
1030 "org.freedesktop.import1.pull",
1034 &t
->manager
->polkit_registry
,
1039 return 1; /* Will call us back */
1041 r
= transfer_cancel(t
);
1045 return sd_bus_reply_method_return(msg
, NULL
);
1048 static int method_cancel_transfer(sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
1049 Manager
*m
= ASSERT_PTR(userdata
);
1056 r
= bus_verify_polkit_async(
1059 "org.freedesktop.import1.pull",
1063 &m
->polkit_registry
,
1068 return 1; /* Will call us back */
1070 r
= sd_bus_message_read(msg
, "u", &id
);
1074 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid transfer id");
1076 t
= hashmap_get(m
->transfers
, UINT32_TO_PTR(id
));
1078 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_TRANSFER
, "No transfer by id %" PRIu32
, id
);
1080 r
= transfer_cancel(t
);
1084 return sd_bus_reply_method_return(msg
, NULL
);
1087 static int property_get_progress(
1090 const char *interface
,
1091 const char *property
,
1092 sd_bus_message
*reply
,
1094 sd_bus_error
*error
) {
1096 Transfer
*t
= ASSERT_PTR(userdata
);
1101 return sd_bus_message_append(reply
, "d", transfer_percent_as_double(t
));
1104 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type
, transfer_type
, TransferType
);
1105 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_verify
, import_verify
, ImportVerify
);
1107 static int transfer_object_find(
1110 const char *interface
,
1113 sd_bus_error
*error
) {
1115 Manager
*m
= ASSERT_PTR(userdata
);
1126 p
= startswith(path
, "/org/freedesktop/import1/transfer/_");
1130 r
= safe_atou32(p
, &id
);
1131 if (r
< 0 || id
== 0)
1134 t
= hashmap_get(m
->transfers
, UINT32_TO_PTR(id
));
1142 static int transfer_node_enumerator(
1147 sd_bus_error
*error
) {
1149 _cleanup_strv_free_
char **l
= NULL
;
1150 Manager
*m
= userdata
;
1154 l
= new0(char*, hashmap_size(m
->transfers
) + 1);
1158 HASHMAP_FOREACH(t
, m
->transfers
) {
1160 l
[k
] = strdup(t
->object_path
);
1167 *nodes
= TAKE_PTR(l
);
1172 static const sd_bus_vtable transfer_vtable
[] = {
1173 SD_BUS_VTABLE_START(0),
1175 SD_BUS_PROPERTY("Id", "u", NULL
, offsetof(Transfer
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
1176 SD_BUS_PROPERTY("Local", "s", NULL
, offsetof(Transfer
, local
), SD_BUS_VTABLE_PROPERTY_CONST
),
1177 SD_BUS_PROPERTY("Remote", "s", NULL
, offsetof(Transfer
, remote
), SD_BUS_VTABLE_PROPERTY_CONST
),
1178 SD_BUS_PROPERTY("Type", "s", property_get_type
, offsetof(Transfer
, type
), SD_BUS_VTABLE_PROPERTY_CONST
),
1179 SD_BUS_PROPERTY("Verify", "s", property_get_verify
, offsetof(Transfer
, verify
), SD_BUS_VTABLE_PROPERTY_CONST
),
1180 SD_BUS_PROPERTY("Progress", "d", property_get_progress
, 0, 0),
1182 SD_BUS_METHOD("Cancel", NULL
, NULL
, method_cancel
, SD_BUS_VTABLE_UNPRIVILEGED
),
1184 SD_BUS_SIGNAL_WITH_NAMES("LogMessage",
1186 SD_BUS_PARAM(priority
)
1193 static const BusObjectImplementation transfer_object
= {
1194 "/org/freedesktop/import1/transfer",
1195 "org.freedesktop.import1.Transfer",
1196 .fallback_vtables
= BUS_FALLBACK_VTABLES({transfer_vtable
, transfer_object_find
}),
1197 .node_enumerator
= transfer_node_enumerator
,
1200 static const sd_bus_vtable manager_vtable
[] = {
1201 SD_BUS_VTABLE_START(0),
1203 SD_BUS_METHOD_WITH_NAMES("ImportTar",
1206 SD_BUS_PARAM(local_name
)
1208 SD_BUS_PARAM(read_only
),
1210 SD_BUS_PARAM(transfer_id
)
1211 SD_BUS_PARAM(transfer_path
),
1212 method_import_tar_or_raw
,
1213 SD_BUS_VTABLE_UNPRIVILEGED
),
1214 SD_BUS_METHOD_WITH_NAMES("ImportRaw",
1217 SD_BUS_PARAM(local_name
)
1219 SD_BUS_PARAM(read_only
),
1221 SD_BUS_PARAM(transfer_id
)
1222 SD_BUS_PARAM(transfer_path
),
1223 method_import_tar_or_raw
,
1224 SD_BUS_VTABLE_UNPRIVILEGED
),
1225 SD_BUS_METHOD_WITH_NAMES("ImportFileSystem",
1228 SD_BUS_PARAM(local_name
)
1230 SD_BUS_PARAM(read_only
),
1232 SD_BUS_PARAM(transfer_id
)
1233 SD_BUS_PARAM(transfer_path
),
1235 SD_BUS_VTABLE_UNPRIVILEGED
),
1236 SD_BUS_METHOD_WITH_NAMES("ExportTar",
1238 SD_BUS_PARAM(local_name
)
1240 SD_BUS_PARAM(format
),
1242 SD_BUS_PARAM(transfer_id
)
1243 SD_BUS_PARAM(transfer_path
),
1244 method_export_tar_or_raw
,
1245 SD_BUS_VTABLE_UNPRIVILEGED
),
1246 SD_BUS_METHOD_WITH_NAMES("ExportRaw",
1248 SD_BUS_PARAM(local_name
)
1250 SD_BUS_PARAM(format
),
1252 SD_BUS_PARAM(transfer_id
)
1253 SD_BUS_PARAM(transfer_path
),
1254 method_export_tar_or_raw
,
1255 SD_BUS_VTABLE_UNPRIVILEGED
),
1256 SD_BUS_METHOD_WITH_NAMES("PullTar",
1259 SD_BUS_PARAM(local_name
)
1260 SD_BUS_PARAM(verify_mode
)
1261 SD_BUS_PARAM(force
),
1263 SD_BUS_PARAM(transfer_id
)
1264 SD_BUS_PARAM(transfer_path
),
1265 method_pull_tar_or_raw
,
1266 SD_BUS_VTABLE_UNPRIVILEGED
),
1267 SD_BUS_METHOD_WITH_NAMES("PullRaw",
1270 SD_BUS_PARAM(local_name
)
1271 SD_BUS_PARAM(verify_mode
)
1272 SD_BUS_PARAM(force
),
1274 SD_BUS_PARAM(transfer_id
)
1275 SD_BUS_PARAM(transfer_path
),
1276 method_pull_tar_or_raw
,
1277 SD_BUS_VTABLE_UNPRIVILEGED
),
1278 SD_BUS_METHOD_WITH_NAMES("ListTransfers",
1281 SD_BUS_PARAM(transfers
),
1282 method_list_transfers
,
1283 SD_BUS_VTABLE_UNPRIVILEGED
),
1284 SD_BUS_METHOD_WITH_NAMES("CancelTransfer",
1286 SD_BUS_PARAM(transfer_id
),
1288 method_cancel_transfer
,
1289 SD_BUS_VTABLE_UNPRIVILEGED
),
1291 SD_BUS_SIGNAL_WITH_NAMES("TransferNew",
1293 SD_BUS_PARAM(transfer_id
)
1294 SD_BUS_PARAM(transfer_path
),
1296 SD_BUS_SIGNAL_WITH_NAMES("TransferRemoved",
1298 SD_BUS_PARAM(transfer_id
)
1299 SD_BUS_PARAM(transfer_path
)
1300 SD_BUS_PARAM(result
),
1306 static const BusObjectImplementation manager_object
= {
1307 "/org/freedesktop/import1",
1308 "org.freedesktop.import1.Manager",
1309 .vtables
= BUS_VTABLES(manager_vtable
),
1310 .children
= BUS_IMPLEMENTATIONS(&transfer_object
),
1313 static int manager_add_bus_objects(Manager
*m
) {
1318 r
= bus_add_implementation(m
->bus
, &manager_object
, m
);
1322 r
= bus_log_control_api_register(m
->bus
);
1326 r
= sd_bus_request_name_async(m
->bus
, NULL
, "org.freedesktop.import1", 0, NULL
, NULL
);
1328 return log_error_errno(r
, "Failed to request name: %m");
1330 r
= sd_bus_attach_event(m
->bus
, m
->event
, 0);
1332 return log_error_errno(r
, "Failed to attach bus to event loop: %m");
1337 static bool manager_check_idle(void *userdata
) {
1338 Manager
*m
= userdata
;
1340 return hashmap_isempty(m
->transfers
);
1343 static int manager_run(Manager
*m
) {
1346 return bus_event_loop_with_idle(
1349 "org.freedesktop.import1",
1355 static int run(int argc
, char *argv
[]) {
1356 _cleanup_(manager_unrefp
) Manager
*m
= NULL
;
1361 r
= service_parse_argv("systemd-importd.service",
1362 "VM and container image import and export service.",
1363 BUS_IMPLEMENTATIONS(&manager_object
,
1364 &log_control_object
),
1371 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGCHLD
, -1) >= 0);
1373 r
= manager_new(&m
);
1375 return log_error_errno(r
, "Failed to allocate manager object: %m");
1377 r
= manager_add_bus_objects(m
);
1383 return log_error_errno(r
, "Failed to run event loop: %m");
1388 DEFINE_MAIN_FUNCTION(run
);