2 This file is part of systemd.
4 Copyright 2015 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include <sys/prctl.h>
24 #include "alloc-util.h"
25 #include "bus-common-errors.h"
29 #include "hostname-util.h"
30 #include "import-util.h"
31 #include "machine-pool.h"
34 #include "parse-util.h"
35 #include "path-util.h"
36 #include "process-util.h"
37 #include "signal-util.h"
38 #include "socket-util.h"
39 #include "string-table.h"
41 #include "syslog-util.h"
42 #include "user-util.h"
46 typedef struct Transfer Transfer
;
47 typedef struct Manager Manager
;
49 typedef enum TransferType
{
57 _TRANSFER_TYPE_INVALID
= -1,
80 char log_message
[LINE_MAX
];
81 size_t log_message_size
;
83 sd_event_source
*pid_event_source
;
84 sd_event_source
*log_event_source
;
87 unsigned progress_percent
;
97 uint32_t current_transfer_id
;
100 Hashmap
*polkit_registry
;
104 sd_event_source
*notify_event_source
;
107 #define TRANSFERS_MAX 64
109 static const char* const transfer_type_table
[_TRANSFER_TYPE_MAX
] = {
110 [TRANSFER_IMPORT_TAR
] = "import-tar",
111 [TRANSFER_IMPORT_RAW
] = "import-raw",
112 [TRANSFER_EXPORT_TAR
] = "export-tar",
113 [TRANSFER_EXPORT_RAW
] = "export-raw",
114 [TRANSFER_PULL_TAR
] = "pull-tar",
115 [TRANSFER_PULL_RAW
] = "pull-raw",
118 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(transfer_type
, TransferType
);
120 static Transfer
*transfer_unref(Transfer
*t
) {
125 hashmap_remove(t
->manager
->transfers
, UINT32_TO_PTR(t
->id
));
127 sd_event_source_unref(t
->pid_event_source
);
128 sd_event_source_unref(t
->log_event_source
);
133 free(t
->object_path
);
136 (void) kill_and_sigcont(t
->pid
, SIGKILL
);
137 (void) wait_for_terminate(t
->pid
, NULL
);
140 safe_close(t
->log_fd
);
141 safe_close(t
->stdin_fd
);
142 safe_close(t
->stdout_fd
);
148 DEFINE_TRIVIAL_CLEANUP_FUNC(Transfer
*, transfer_unref
);
150 static int transfer_new(Manager
*m
, Transfer
**ret
) {
151 _cleanup_(transfer_unrefp
) Transfer
*t
= NULL
;
158 if (hashmap_size(m
->transfers
) >= TRANSFERS_MAX
)
161 r
= hashmap_ensure_allocated(&m
->transfers
, &trivial_hash_ops
);
165 t
= new0(Transfer
, 1);
169 t
->type
= _TRANSFER_TYPE_INVALID
;
173 t
->verify
= _IMPORT_VERIFY_INVALID
;
175 id
= m
->current_transfer_id
+ 1;
177 if (asprintf(&t
->object_path
, "/org/freedesktop/import1/transfer/_%" PRIu32
, id
) < 0)
180 r
= hashmap_put(m
->transfers
, UINT32_TO_PTR(id
), t
);
184 m
->current_transfer_id
= id
;
195 static void transfer_send_log_line(Transfer
*t
, const char *line
) {
196 int r
, priority
= LOG_INFO
;
201 syslog_parse_priority(&line
, &priority
, true);
203 log_full(priority
, "(transfer%" PRIu32
") %s", t
->id
, line
);
205 r
= sd_bus_emit_signal(
208 "org.freedesktop.import1.Transfer",
214 log_error_errno(r
, "Cannot emit message: %m");
217 static void transfer_send_logs(Transfer
*t
, bool flush
) {
220 /* Try to send out all log messages, if we can. But if we
221 * can't we remove the messages from the buffer, but don't
224 while (t
->log_message_size
> 0) {
225 _cleanup_free_
char *n
= NULL
;
228 if (t
->log_message_size
>= sizeof(t
->log_message
))
229 e
= t
->log_message
+ sizeof(t
->log_message
);
233 a
= memchr(t
->log_message
, 0, t
->log_message_size
);
234 b
= memchr(t
->log_message
, '\n', t
->log_message_size
);
248 e
= t
->log_message
+ t
->log_message_size
;
251 n
= strndup(t
->log_message
, e
- t
->log_message
);
253 /* Skip over NUL and newlines */
254 while ((e
< t
->log_message
+ t
->log_message_size
) && (*e
== 0 || *e
== '\n'))
257 memmove(t
->log_message
, e
, t
->log_message
+ sizeof(t
->log_message
) - e
);
258 t
->log_message_size
-= e
- t
->log_message
;
268 transfer_send_log_line(t
, n
);
272 static int transfer_finalize(Transfer
*t
, bool success
) {
277 transfer_send_logs(t
, true);
279 r
= sd_bus_emit_signal(
281 "/org/freedesktop/import1",
282 "org.freedesktop.import1.Manager",
288 t
->n_canceled
> 0 ? "canceled" : "failed");
291 log_error_errno(r
, "Cannot emit message: %m");
297 static int transfer_cancel(Transfer
*t
) {
302 r
= kill_and_sigcont(t
->pid
, t
->n_canceled
< 3 ? SIGTERM
: SIGKILL
);
310 static int transfer_on_pid(sd_event_source
*s
, const siginfo_t
*si
, void *userdata
) {
311 Transfer
*t
= userdata
;
312 bool success
= false;
317 if (si
->si_code
== CLD_EXITED
) {
318 if (si
->si_status
!= 0)
319 log_error("Import process failed with exit code %i.", si
->si_status
);
321 log_debug("Import process succeeded.");
325 } else if (si
->si_code
== CLD_KILLED
||
326 si
->si_code
== CLD_DUMPED
)
328 log_error("Import process terminated by signal %s.", signal_to_string(si
->si_status
));
330 log_error("Import process failed due to unknown reason.");
334 return transfer_finalize(t
, success
);
337 static int transfer_on_log(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
338 Transfer
*t
= userdata
;
344 l
= read(fd
, t
->log_message
+ t
->log_message_size
, sizeof(t
->log_message
) - t
->log_message_size
);
346 /* EOF/read error. We just close the pipe here, and
347 * close the watch, waiting for the SIGCHLD to arrive,
348 * before we do anything else. */
351 log_error_errno(errno
, "Failed to read log message: %m");
353 t
->log_event_source
= sd_event_source_unref(t
->log_event_source
);
357 t
->log_message_size
+= l
;
359 transfer_send_logs(t
, false);
364 static int transfer_start(Transfer
*t
) {
365 _cleanup_close_pair_
int pipefd
[2] = { -1, -1 };
371 if (pipe2(pipefd
, O_CLOEXEC
) < 0)
378 const char *cmd
[] = {
379 NULL
, /* systemd-import, systemd-export or systemd-pull */
381 NULL
, /* --verify= */
382 NULL
, /* verify argument */
383 NULL
, /* maybe --force */
384 NULL
, /* maybe --read-only */
385 NULL
, /* if so: the actual URL */
386 NULL
, /* maybe --format= */
387 NULL
, /* if so: the actual format */
396 (void) reset_all_signal_handlers();
397 (void) reset_signal_mask();
398 assert_se(prctl(PR_SET_PDEATHSIG
, SIGTERM
) == 0);
400 pipefd
[0] = safe_close(pipefd
[0]);
402 if (dup2(pipefd
[1], STDERR_FILENO
) != STDERR_FILENO
) {
403 log_error_errno(errno
, "Failed to dup2() fd: %m");
407 if (t
->stdout_fd
>= 0) {
408 if (dup2(t
->stdout_fd
, STDOUT_FILENO
) != STDOUT_FILENO
) {
409 log_error_errno(errno
, "Failed to dup2() fd: %m");
413 if (t
->stdout_fd
!= STDOUT_FILENO
)
414 safe_close(t
->stdout_fd
);
416 if (dup2(pipefd
[1], STDOUT_FILENO
) != STDOUT_FILENO
) {
417 log_error_errno(errno
, "Failed to dup2() fd: %m");
422 if (pipefd
[1] != STDOUT_FILENO
&& pipefd
[1] != STDERR_FILENO
)
423 pipefd
[1] = safe_close(pipefd
[1]);
425 if (t
->stdin_fd
>= 0) {
426 if (dup2(t
->stdin_fd
, STDIN_FILENO
) != STDIN_FILENO
) {
427 log_error_errno(errno
, "Failed to dup2() fd: %m");
431 if (t
->stdin_fd
!= STDIN_FILENO
)
432 safe_close(t
->stdin_fd
);
436 null_fd
= open("/dev/null", O_RDONLY
|O_NOCTTY
);
438 log_error_errno(errno
, "Failed to open /dev/null: %m");
442 if (dup2(null_fd
, STDIN_FILENO
) != STDIN_FILENO
) {
443 log_error_errno(errno
, "Failed to dup2() fd: %m");
447 if (null_fd
!= STDIN_FILENO
)
451 fd_cloexec(STDIN_FILENO
, false);
452 fd_cloexec(STDOUT_FILENO
, false);
453 fd_cloexec(STDERR_FILENO
, false);
455 setenv("SYSTEMD_LOG_TARGET", "console-prefixed", 1);
456 setenv("NOTIFY_SOCKET", "/run/systemd/import/notify", 1);
458 if (IN_SET(t
->type
, TRANSFER_IMPORT_TAR
, TRANSFER_IMPORT_RAW
))
459 cmd
[k
++] = SYSTEMD_IMPORT_PATH
;
460 else if (IN_SET(t
->type
, TRANSFER_EXPORT_TAR
, TRANSFER_EXPORT_RAW
))
461 cmd
[k
++] = SYSTEMD_EXPORT_PATH
;
463 cmd
[k
++] = SYSTEMD_PULL_PATH
;
465 if (IN_SET(t
->type
, TRANSFER_IMPORT_TAR
, TRANSFER_EXPORT_TAR
, TRANSFER_PULL_TAR
))
470 if (t
->verify
!= _IMPORT_VERIFY_INVALID
) {
471 cmd
[k
++] = "--verify";
472 cmd
[k
++] = import_verify_to_string(t
->verify
);
476 cmd
[k
++] = "--force";
478 cmd
[k
++] = "--read-only";
481 cmd
[k
++] = "--format";
482 cmd
[k
++] = t
->format
;
485 if (!IN_SET(t
->type
, TRANSFER_EXPORT_TAR
, TRANSFER_EXPORT_RAW
)) {
487 cmd
[k
++] = t
->remote
;
496 execv(cmd
[0], (char * const *) cmd
);
497 log_error_errno(errno
, "Failed to execute %s tool: %m", cmd
[0]);
501 pipefd
[1] = safe_close(pipefd
[1]);
502 t
->log_fd
= pipefd
[0];
505 t
->stdin_fd
= safe_close(t
->stdin_fd
);
507 r
= sd_event_add_child(t
->manager
->event
, &t
->pid_event_source
, t
->pid
, WEXITED
, transfer_on_pid
, t
);
511 r
= sd_event_add_io(t
->manager
->event
, &t
->log_event_source
, t
->log_fd
, EPOLLIN
, transfer_on_log
, t
);
515 /* Make sure always process logging before SIGCHLD */
516 r
= sd_event_source_set_priority(t
->log_event_source
, SD_EVENT_PRIORITY_NORMAL
-5);
520 r
= sd_bus_emit_signal(
522 "/org/freedesktop/import1",
523 "org.freedesktop.import1.Manager",
534 static Manager
*manager_unref(Manager
*m
) {
540 sd_event_source_unref(m
->notify_event_source
);
541 safe_close(m
->notify_fd
);
543 while ((t
= hashmap_first(m
->transfers
)))
546 hashmap_free(m
->transfers
);
548 bus_verify_polkit_async_registry_free(m
->polkit_registry
);
550 m
->bus
= sd_bus_flush_close_unref(m
->bus
);
551 sd_event_unref(m
->event
);
557 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager
*, manager_unref
);
559 static int manager_on_notify(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
561 char buf
[NOTIFY_BUFFER_MAX
+1];
562 struct iovec iovec
= {
564 .iov_len
= sizeof(buf
)-1,
567 struct cmsghdr cmsghdr
;
568 uint8_t buf
[CMSG_SPACE(sizeof(struct ucred
)) +
569 CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX
)];
571 struct msghdr msghdr
= {
574 .msg_control
= &control
,
575 .msg_controllen
= sizeof(control
),
577 struct ucred
*ucred
= NULL
;
578 Manager
*m
= userdata
;
579 struct cmsghdr
*cmsg
;
587 n
= recvmsg(fd
, &msghdr
, MSG_DONTWAIT
|MSG_CMSG_CLOEXEC
);
589 if (errno
== EAGAIN
|| errno
== EINTR
)
595 cmsg_close_all(&msghdr
);
597 CMSG_FOREACH(cmsg
, &msghdr
)
598 if (cmsg
->cmsg_level
== SOL_SOCKET
&&
599 cmsg
->cmsg_type
== SCM_CREDENTIALS
&&
600 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct ucred
)))
601 ucred
= (struct ucred
*) CMSG_DATA(cmsg
);
603 if (msghdr
.msg_flags
& MSG_TRUNC
) {
604 log_warning("Got overly long notification datagram, ignoring.");
608 if (!ucred
|| ucred
->pid
<= 0) {
609 log_warning("Got notification datagram lacking credential information, ignoring.");
613 HASHMAP_FOREACH(t
, m
->transfers
, i
)
614 if (ucred
->pid
== t
->pid
)
618 log_warning("Got notification datagram from unexpected peer, ignoring.");
624 p
= startswith(buf
, "X_IMPORT_PROGRESS=");
626 p
= strstr(buf
, "\nX_IMPORT_PROGRESS=");
633 e
= strchrnul(p
, '\n');
636 r
= safe_atou(p
, &percent
);
637 if (r
< 0 || percent
> 100) {
638 log_warning("Got invalid percent value, ignoring.");
642 t
->progress_percent
= percent
;
644 log_debug("Got percentage from client: %u%%", percent
);
648 static int manager_new(Manager
**ret
) {
649 _cleanup_(manager_unrefp
) Manager
*m
= NULL
;
650 static const union sockaddr_union sa
= {
651 .un
.sun_family
= AF_UNIX
,
652 .un
.sun_path
= "/run/systemd/import/notify",
654 static const int one
= 1;
659 m
= new0(Manager
, 1);
663 r
= sd_event_default(&m
->event
);
667 sd_event_set_watchdog(m
->event
, true);
669 r
= sd_bus_default_system(&m
->bus
);
673 m
->notify_fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
674 if (m
->notify_fd
< 0)
677 (void) mkdir_parents_label(sa
.un
.sun_path
, 0755);
678 (void) unlink(sa
.un
.sun_path
);
680 if (bind(m
->notify_fd
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
)) < 0)
683 if (setsockopt(m
->notify_fd
, SOL_SOCKET
, SO_PASSCRED
, &one
, sizeof(one
)) < 0)
686 r
= sd_event_add_io(m
->event
, &m
->notify_event_source
, m
->notify_fd
, EPOLLIN
, manager_on_notify
, m
);
696 static Transfer
*manager_find(Manager
*m
, TransferType type
, const char *remote
) {
702 assert(type
< _TRANSFER_TYPE_MAX
);
704 HASHMAP_FOREACH(t
, m
->transfers
, i
) {
706 if (t
->type
== type
&&
707 streq_ptr(t
->remote
, remote
))
714 static int method_import_tar_or_raw(sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
715 _cleanup_(transfer_unrefp
) Transfer
*t
= NULL
;
716 int fd
, force
, read_only
, r
;
717 const char *local
, *object
;
718 Manager
*m
= userdata
;
725 r
= bus_verify_polkit_async(
728 "org.freedesktop.import1.import",
737 return 1; /* Will call us back */
739 r
= sd_bus_message_read(msg
, "hsbb", &fd
, &local
, &force
, &read_only
);
743 if (!machine_name_is_valid(local
))
744 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Local name %s is invalid", local
);
746 r
= setup_machine_directory((uint64_t) -1, error
);
750 type
= streq_ptr(sd_bus_message_get_member(msg
), "ImportTar") ? TRANSFER_IMPORT_TAR
: TRANSFER_IMPORT_RAW
;
752 r
= transfer_new(m
, &t
);
757 t
->force_local
= force
;
758 t
->read_only
= read_only
;
760 t
->local
= strdup(local
);
764 t
->stdin_fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
768 r
= transfer_start(t
);
772 object
= t
->object_path
;
776 return sd_bus_reply_method_return(msg
, "uo", id
, object
);
779 static int method_export_tar_or_raw(sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
780 _cleanup_(transfer_unrefp
) Transfer
*t
= NULL
;
782 const char *local
, *object
, *format
;
783 Manager
*m
= userdata
;
790 r
= bus_verify_polkit_async(
793 "org.freedesktop.import1.export",
802 return 1; /* Will call us back */
804 r
= sd_bus_message_read(msg
, "shs", &local
, &fd
, &format
);
808 if (!machine_name_is_valid(local
))
809 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Local name %s is invalid", local
);
811 type
= streq_ptr(sd_bus_message_get_member(msg
), "ExportTar") ? TRANSFER_EXPORT_TAR
: TRANSFER_EXPORT_RAW
;
813 r
= transfer_new(m
, &t
);
819 if (!isempty(format
)) {
820 t
->format
= strdup(format
);
825 t
->local
= strdup(local
);
829 t
->stdout_fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
830 if (t
->stdout_fd
< 0)
833 r
= transfer_start(t
);
837 object
= t
->object_path
;
841 return sd_bus_reply_method_return(msg
, "uo", id
, object
);
844 static int method_pull_tar_or_raw(sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
845 _cleanup_(transfer_unrefp
) Transfer
*t
= NULL
;
846 const char *remote
, *local
, *verify
, *object
;
847 Manager
*m
= userdata
;
856 r
= bus_verify_polkit_async(
859 "org.freedesktop.import1.pull",
868 return 1; /* Will call us back */
870 r
= sd_bus_message_read(msg
, "sssb", &remote
, &local
, &verify
, &force
);
874 if (!http_url_is_valid(remote
))
875 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "URL %s is invalid", remote
);
879 else if (!machine_name_is_valid(local
))
880 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Local name %s is invalid", local
);
883 v
= IMPORT_VERIFY_SIGNATURE
;
885 v
= import_verify_from_string(verify
);
887 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unknown verification mode %s", verify
);
889 r
= setup_machine_directory((uint64_t) -1, error
);
893 type
= streq_ptr(sd_bus_message_get_member(msg
), "PullTar") ? TRANSFER_PULL_TAR
: TRANSFER_PULL_RAW
;
895 if (manager_find(m
, type
, remote
))
896 return sd_bus_error_setf(error
, BUS_ERROR_TRANSFER_IN_PROGRESS
, "Transfer for %s already in progress.", remote
);
898 r
= transfer_new(m
, &t
);
904 t
->force_local
= force
;
906 t
->remote
= strdup(remote
);
911 t
->local
= strdup(local
);
916 r
= transfer_start(t
);
920 object
= t
->object_path
;
924 return sd_bus_reply_method_return(msg
, "uo", id
, object
);
927 static int method_list_transfers(sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
928 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
929 Manager
*m
= userdata
;
937 r
= sd_bus_message_new_method_return(msg
, &reply
);
941 r
= sd_bus_message_open_container(reply
, 'a', "(usssdo)");
945 HASHMAP_FOREACH(t
, m
->transfers
, i
) {
947 r
= sd_bus_message_append(
951 transfer_type_to_string(t
->type
),
954 (double) t
->progress_percent
/ 100.0,
960 r
= sd_bus_message_close_container(reply
);
964 return sd_bus_send(NULL
, reply
, NULL
);
967 static int method_cancel(sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
968 Transfer
*t
= userdata
;
974 r
= bus_verify_polkit_async(
977 "org.freedesktop.import1.pull",
981 &t
->manager
->polkit_registry
,
986 return 1; /* Will call us back */
988 r
= transfer_cancel(t
);
992 return sd_bus_reply_method_return(msg
, NULL
);
995 static int method_cancel_transfer(sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
996 Manager
*m
= userdata
;
1004 r
= bus_verify_polkit_async(
1007 "org.freedesktop.import1.pull",
1011 &m
->polkit_registry
,
1016 return 1; /* Will call us back */
1018 r
= sd_bus_message_read(msg
, "u", &id
);
1022 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid transfer id");
1024 t
= hashmap_get(m
->transfers
, UINT32_TO_PTR(id
));
1026 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_TRANSFER
, "No transfer by id %" PRIu32
, id
);
1028 r
= transfer_cancel(t
);
1032 return sd_bus_reply_method_return(msg
, NULL
);
1035 static int property_get_progress(
1038 const char *interface
,
1039 const char *property
,
1040 sd_bus_message
*reply
,
1042 sd_bus_error
*error
) {
1044 Transfer
*t
= userdata
;
1050 return sd_bus_message_append(reply
, "d", (double) t
->progress_percent
/ 100.0);
1053 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type
, transfer_type
, TransferType
);
1054 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_verify
, import_verify
, ImportVerify
);
1056 static const sd_bus_vtable transfer_vtable
[] = {
1057 SD_BUS_VTABLE_START(0),
1058 SD_BUS_PROPERTY("Id", "u", NULL
, offsetof(Transfer
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
1059 SD_BUS_PROPERTY("Local", "s", NULL
, offsetof(Transfer
, local
), SD_BUS_VTABLE_PROPERTY_CONST
),
1060 SD_BUS_PROPERTY("Remote", "s", NULL
, offsetof(Transfer
, remote
), SD_BUS_VTABLE_PROPERTY_CONST
),
1061 SD_BUS_PROPERTY("Type", "s", property_get_type
, offsetof(Transfer
, type
), SD_BUS_VTABLE_PROPERTY_CONST
),
1062 SD_BUS_PROPERTY("Verify", "s", property_get_verify
, offsetof(Transfer
, verify
), SD_BUS_VTABLE_PROPERTY_CONST
),
1063 SD_BUS_PROPERTY("Progress", "d", property_get_progress
, 0, 0),
1064 SD_BUS_METHOD("Cancel", NULL
, NULL
, method_cancel
, SD_BUS_VTABLE_UNPRIVILEGED
),
1065 SD_BUS_SIGNAL("LogMessage", "us", 0),
1069 static const sd_bus_vtable manager_vtable
[] = {
1070 SD_BUS_VTABLE_START(0),
1071 SD_BUS_METHOD("ImportTar", "hsbb", "uo", method_import_tar_or_raw
, SD_BUS_VTABLE_UNPRIVILEGED
),
1072 SD_BUS_METHOD("ImportRaw", "hsbb", "uo", method_import_tar_or_raw
, SD_BUS_VTABLE_UNPRIVILEGED
),
1073 SD_BUS_METHOD("ExportTar", "shs", "uo", method_export_tar_or_raw
, SD_BUS_VTABLE_UNPRIVILEGED
),
1074 SD_BUS_METHOD("ExportRaw", "shs", "uo", method_export_tar_or_raw
, SD_BUS_VTABLE_UNPRIVILEGED
),
1075 SD_BUS_METHOD("PullTar", "sssb", "uo", method_pull_tar_or_raw
, SD_BUS_VTABLE_UNPRIVILEGED
),
1076 SD_BUS_METHOD("PullRaw", "sssb", "uo", method_pull_tar_or_raw
, SD_BUS_VTABLE_UNPRIVILEGED
),
1077 SD_BUS_METHOD("ListTransfers", NULL
, "a(usssdo)", method_list_transfers
, SD_BUS_VTABLE_UNPRIVILEGED
),
1078 SD_BUS_METHOD("CancelTransfer", "u", NULL
, method_cancel_transfer
, SD_BUS_VTABLE_UNPRIVILEGED
),
1079 SD_BUS_SIGNAL("TransferNew", "uo", 0),
1080 SD_BUS_SIGNAL("TransferRemoved", "uos", 0),
1084 static int transfer_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
1085 Manager
*m
= userdata
;
1097 p
= startswith(path
, "/org/freedesktop/import1/transfer/_");
1101 r
= safe_atou32(p
, &id
);
1102 if (r
< 0 || id
== 0)
1105 t
= hashmap_get(m
->transfers
, UINT32_TO_PTR(id
));
1113 static int transfer_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
1114 _cleanup_strv_free_
char **l
= NULL
;
1115 Manager
*m
= userdata
;
1120 l
= new0(char*, hashmap_size(m
->transfers
) + 1);
1124 HASHMAP_FOREACH(t
, m
->transfers
, i
) {
1126 l
[k
] = strdup(t
->object_path
);
1139 static int manager_add_bus_objects(Manager
*m
) {
1144 r
= sd_bus_add_object_vtable(m
->bus
, NULL
, "/org/freedesktop/import1", "org.freedesktop.import1.Manager", manager_vtable
, m
);
1146 return log_error_errno(r
, "Failed to register object: %m");
1148 r
= sd_bus_add_fallback_vtable(m
->bus
, NULL
, "/org/freedesktop/import1/transfer", "org.freedesktop.import1.Transfer", transfer_vtable
, transfer_object_find
, m
);
1150 return log_error_errno(r
, "Failed to register object: %m");
1152 r
= sd_bus_add_node_enumerator(m
->bus
, NULL
, "/org/freedesktop/import1/transfer", transfer_node_enumerator
, m
);
1154 return log_error_errno(r
, "Failed to add transfer enumerator: %m");
1156 r
= sd_bus_request_name(m
->bus
, "org.freedesktop.import1", 0);
1158 return log_error_errno(r
, "Failed to register name: %m");
1160 r
= sd_bus_attach_event(m
->bus
, m
->event
, 0);
1162 return log_error_errno(r
, "Failed to attach bus to event loop: %m");
1167 static bool manager_check_idle(void *userdata
) {
1168 Manager
*m
= userdata
;
1170 return hashmap_isempty(m
->transfers
);
1173 static int manager_run(Manager
*m
) {
1176 return bus_event_loop_with_idle(
1179 "org.freedesktop.import1",
1185 int main(int argc
, char *argv
[]) {
1186 _cleanup_(manager_unrefp
) Manager
*m
= NULL
;
1189 log_set_target(LOG_TARGET_AUTO
);
1190 log_parse_environment();
1196 log_error("This program takes no arguments.");
1201 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGCHLD
, -1) >= 0);
1203 r
= manager_new(&m
);
1205 log_error_errno(r
, "Failed to allocate manager object: %m");
1209 r
= manager_add_bus_objects(m
);
1215 log_error_errno(r
, "Failed to run event loop: %m");
1220 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;