1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2015 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/prctl.h>
28 #include "bus-common-errors.h"
30 #include "socket-util.h"
32 #include "import-util.h"
34 typedef struct Transfer Transfer
;
35 typedef struct Manager Manager
;
37 typedef enum TransferType
{
42 _TRANSFER_TYPE_INVALID
= -1,
64 char log_message
[LINE_MAX
];
65 size_t log_message_size
;
67 sd_event_source
*pid_event_source
;
68 sd_event_source
*log_event_source
;
71 unsigned progress_percent
;
78 uint32_t current_transfer_id
;
81 Hashmap
*polkit_registry
;
85 sd_event_source
*notify_event_source
;
88 #define TRANSFERS_MAX 64
90 static const char* const transfer_type_table
[_TRANSFER_TYPE_MAX
] = {
91 [TRANSFER_TAR
] = "tar",
92 [TRANSFER_RAW
] = "raw",
93 [TRANSFER_DKR
] = "dkr",
96 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(transfer_type
, TransferType
);
98 static Transfer
*transfer_unref(Transfer
*t
) {
103 hashmap_remove(t
->manager
->transfers
, UINT32_TO_PTR(t
->id
));
105 sd_event_source_unref(t
->pid_event_source
);
106 sd_event_source_unref(t
->log_event_source
);
110 free(t
->dkr_index_url
);
111 free(t
->object_path
);
114 (void) kill_and_sigcont(t
->pid
, SIGKILL
);
115 (void) wait_for_terminate(t
->pid
, NULL
);
118 safe_close(t
->log_fd
);
124 DEFINE_TRIVIAL_CLEANUP_FUNC(Transfer
*, transfer_unref
);
126 static int transfer_new(Manager
*m
, Transfer
**ret
) {
127 _cleanup_(transfer_unrefp
) Transfer
*t
= NULL
;
134 if (hashmap_size(m
->transfers
) >= TRANSFERS_MAX
)
137 r
= hashmap_ensure_allocated(&m
->transfers
, &trivial_hash_ops
);
141 t
= new0(Transfer
, 1);
145 t
->type
= _TRANSFER_TYPE_INVALID
;
148 id
= m
->current_transfer_id
+ 1;
150 if (asprintf(&t
->object_path
, "/org/freedesktop/import1/transfer/_%" PRIu32
, id
) < 0)
153 r
= hashmap_put(m
->transfers
, UINT32_TO_PTR(id
), t
);
157 m
->current_transfer_id
= id
;
168 static void transfer_send_log_line(Transfer
*t
, const char *line
) {
169 int r
, priority
= LOG_INFO
;
174 syslog_parse_priority(&line
, &priority
, true);
176 log_full(priority
, "(transfer%" PRIu32
") %s", t
->id
, line
);
178 r
= sd_bus_emit_signal(
181 "org.freedesktop.import1.Transfer",
187 log_error_errno(r
, "Cannot emit message: %m");
190 static void transfer_send_logs(Transfer
*t
, bool flush
) {
193 /* Try to send out all log messages, if we can. But if we
194 * can't we remove the messages from the buffer, but don't
197 while (t
->log_message_size
> 0) {
198 _cleanup_free_
char *n
= NULL
;
201 if (t
->log_message_size
>= sizeof(t
->log_message
))
202 e
= t
->log_message
+ sizeof(t
->log_message
);
206 a
= memchr(t
->log_message
, 0, t
->log_message_size
);
207 b
= memchr(t
->log_message
, '\n', t
->log_message_size
);
221 e
= t
->log_message
+ t
->log_message_size
;
224 n
= strndup(t
->log_message
, e
- t
->log_message
);
226 /* Skip over NUL and newlines */
227 while (e
< t
->log_message
+ t
->log_message_size
&& (*e
== 0 || *e
== '\n'))
230 memmove(t
->log_message
, e
, t
->log_message
+ sizeof(t
->log_message
) - e
);
231 t
->log_message_size
-= e
- t
->log_message
;
241 transfer_send_log_line(t
, n
);
245 static int transfer_finalize(Transfer
*t
, bool success
) {
250 transfer_send_logs(t
, true);
252 r
= sd_bus_emit_signal(
254 "/org/freedesktop/import1",
255 "org.freedesktop.import1.Manager",
261 t
->n_canceled
> 0 ? "canceled" : "failed");
264 log_error_errno(r
, "Cannot emit message: %m");
270 static int transfer_cancel(Transfer
*t
) {
275 r
= kill_and_sigcont(t
->pid
, t
->n_canceled
< 3 ? SIGTERM
: SIGKILL
);
283 static int transfer_on_pid(sd_event_source
*s
, const siginfo_t
*si
, void *userdata
) {
284 Transfer
*t
= userdata
;
285 bool success
= false;
290 if (si
->si_code
== CLD_EXITED
) {
291 if (si
->si_status
!= 0)
292 log_error("Import process failed with exit code %i.", si
->si_status
);
294 log_debug("Import process succeeded.");
298 } else if (si
->si_code
== CLD_KILLED
||
299 si
->si_code
== CLD_DUMPED
)
301 log_error("Import process terminated by signal %s.", signal_to_string(si
->si_status
));
303 log_error("Import process failed due to unknown reason.");
307 return transfer_finalize(t
, success
);
310 static int transfer_on_log(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
311 Transfer
*t
= userdata
;
317 l
= read(fd
, t
->log_message
+ t
->log_message_size
, sizeof(t
->log_message
) - t
->log_message_size
);
319 /* EOF/read error. We just close the pipe here, and
320 * close the watch, waiting for the SIGCHLD to arrive,
321 * before we do anything else. */
324 log_error_errno(errno
, "Failed to read log message: %m");
326 t
->log_event_source
= sd_event_source_unref(t
->log_event_source
);
330 t
->log_message_size
+= l
;
332 transfer_send_logs(t
, false);
337 static int transfer_start(Transfer
*t
) {
338 _cleanup_close_pair_
int pipefd
[2] = { -1, -1 };
344 if (pipe2(pipefd
, O_CLOEXEC
) < 0)
351 const char *cmd
[] = {
353 transfer_type_to_string(t
->type
),
355 NULL
, /* verify argument */
356 NULL
, /* maybe --force */
357 NULL
, /* maybe --dkr-index-url */
358 NULL
, /* the actual URL */
368 reset_all_signal_handlers();
370 assert_se(prctl(PR_SET_PDEATHSIG
, SIGTERM
) == 0);
372 pipefd
[0] = safe_close(pipefd
[0]);
374 if (dup2(pipefd
[1], STDOUT_FILENO
) != STDOUT_FILENO
) {
375 log_error_errno(errno
, "Failed to dup2() fd: %m");
379 if (dup2(pipefd
[1], STDERR_FILENO
) != STDERR_FILENO
) {
380 log_error_errno(errno
, "Failed to dup2() fd: %m");
384 if (pipefd
[1] != STDOUT_FILENO
&& pipefd
[1] != STDERR_FILENO
)
385 pipefd
[1] = safe_close(pipefd
[1]);
387 null_fd
= open("/dev/null", O_RDONLY
|O_NOCTTY
);
389 log_error_errno(errno
, "Failed to open /dev/null: %m");
393 if (dup2(null_fd
, STDIN_FILENO
) != STDIN_FILENO
) {
394 log_error_errno(errno
, "Failed to dup2() fd: %m");
398 if (null_fd
!= STDIN_FILENO
)
401 fd_cloexec(STDIN_FILENO
, false);
402 fd_cloexec(STDOUT_FILENO
, false);
403 fd_cloexec(STDERR_FILENO
, false);
405 setenv("SYSTEMD_LOG_TARGET", "console-prefixed", 1);
406 setenv("NOTIFY_SOCKET", "/run/systemd/import/notify", 1);
408 cmd
[k
++] = import_verify_to_string(t
->verify
);
410 cmd
[k
++] = "--force";
412 if (t
->dkr_index_url
) {
413 cmd
[k
++] = "--dkr-index-url";
414 cmd
[k
++] = t
->dkr_index_url
;
417 cmd
[k
++] = t
->remote
;
422 execv(SYSTEMD_PULL_PATH
, (char * const *) cmd
);
423 log_error_errno(errno
, "Failed to execute import tool: %m");
427 pipefd
[1] = safe_close(pipefd
[1]);
428 t
->log_fd
= pipefd
[0];
431 r
= sd_event_add_child(t
->manager
->event
, &t
->pid_event_source
, t
->pid
, WEXITED
, transfer_on_pid
, t
);
435 r
= sd_event_add_io(t
->manager
->event
, &t
->log_event_source
, t
->log_fd
, EPOLLIN
, transfer_on_log
, t
);
439 /* Make sure always process logging before SIGCHLD */
440 r
= sd_event_source_set_priority(t
->log_event_source
, SD_EVENT_PRIORITY_NORMAL
-5);
444 r
= sd_bus_emit_signal(
446 "/org/freedesktop/import1",
447 "org.freedesktop.import1.Manager",
458 static Manager
*manager_unref(Manager
*m
) {
464 sd_event_source_unref(m
->notify_event_source
);
465 safe_close(m
->notify_fd
);
467 while ((t
= hashmap_first(m
->transfers
)))
470 hashmap_free(m
->transfers
);
472 bus_verify_polkit_async_registry_free(m
->polkit_registry
);
474 sd_bus_close(m
->bus
);
475 sd_bus_unref(m
->bus
);
476 sd_event_unref(m
->event
);
482 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager
*, manager_unref
);
484 static int manager_on_notify(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
486 char buf
[NOTIFY_BUFFER_MAX
+1];
487 struct iovec iovec
= {
489 .iov_len
= sizeof(buf
)-1,
492 struct cmsghdr cmsghdr
;
493 uint8_t buf
[CMSG_SPACE(sizeof(struct ucred
)) +
494 CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX
)];
496 struct msghdr msghdr
= {
499 .msg_control
= &control
,
500 .msg_controllen
= sizeof(control
),
502 struct ucred
*ucred
= NULL
;
503 Manager
*m
= userdata
;
504 struct cmsghdr
*cmsg
;
512 n
= recvmsg(fd
, &msghdr
, MSG_DONTWAIT
|MSG_CMSG_CLOEXEC
);
514 if (errno
== EAGAIN
|| errno
== EINTR
)
520 for (cmsg
= CMSG_FIRSTHDR(&msghdr
); cmsg
; cmsg
= CMSG_NXTHDR(&msghdr
, cmsg
)) {
521 if (cmsg
->cmsg_level
== SOL_SOCKET
&& cmsg
->cmsg_type
== SCM_RIGHTS
) {
522 close_many((int*) CMSG_DATA(cmsg
), (cmsg
->cmsg_len
- CMSG_LEN(0)) / sizeof(int));
523 log_warning("Somebody sent us unexpected fds, ignoring.");
525 } else if (cmsg
->cmsg_level
== SOL_SOCKET
&&
526 cmsg
->cmsg_type
== SCM_CREDENTIALS
&&
527 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct ucred
))) {
529 ucred
= (struct ucred
*) CMSG_DATA(cmsg
);
533 if (msghdr
.msg_flags
& MSG_TRUNC
) {
534 log_warning("Got overly long notification datagram, ignoring.");
538 if (!ucred
|| ucred
->pid
<= 0) {
539 log_warning("Got notification datagram lacking credential information, ignoring.");
543 HASHMAP_FOREACH(t
, m
->transfers
, i
)
544 if (ucred
->pid
== t
->pid
)
548 log_warning("Got notification datagram from unexpected peer, ignoring.");
554 p
= startswith(buf
, "X_IMPORT_PROGRESS=");
556 p
= strstr(buf
, "\nX_IMPORT_PROGRESS=");
563 e
= strchrnul(p
, '\n');
566 r
= safe_atou(p
, &percent
);
567 if (r
< 0 || percent
> 100) {
568 log_warning("Got invalid percent value, ignoring.");
572 t
->progress_percent
= percent
;
574 log_debug("Got percentage from client: %u%%", percent
);
578 static int manager_new(Manager
**ret
) {
579 _cleanup_(manager_unrefp
) Manager
*m
= NULL
;
580 static const union sockaddr_union sa
= {
581 .un
.sun_family
= AF_UNIX
,
582 .un
.sun_path
= "/run/systemd/import/notify",
584 static const int one
= 1;
589 m
= new0(Manager
, 1);
593 r
= sd_event_default(&m
->event
);
597 sd_event_set_watchdog(m
->event
, true);
599 r
= sd_bus_default_system(&m
->bus
);
603 m
->notify_fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
604 if (m
->notify_fd
< 0)
607 (void) mkdir_parents_label(sa
.un
.sun_path
, 0755);
608 (void) unlink(sa
.un
.sun_path
);
610 if (bind(m
->notify_fd
, &sa
.sa
, offsetof(union sockaddr_union
, un
.sun_path
) + strlen(sa
.un
.sun_path
)) < 0)
613 if (setsockopt(m
->notify_fd
, SOL_SOCKET
, SO_PASSCRED
, &one
, sizeof(one
)) < 0)
616 r
= sd_event_add_io(m
->event
, &m
->notify_event_source
, m
->notify_fd
, EPOLLIN
, manager_on_notify
, m
);
626 static Transfer
*manager_find(Manager
*m
, TransferType type
, const char *dkr_index_url
, const char *remote
) {
632 assert(type
< _TRANSFER_TYPE_MAX
);
634 HASHMAP_FOREACH(t
, m
->transfers
, i
) {
636 if (t
->type
== type
&&
637 streq_ptr(t
->remote
, remote
) &&
638 streq_ptr(t
->dkr_index_url
, dkr_index_url
))
645 static int method_pull_tar_or_raw(sd_bus
*bus
, sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
646 _cleanup_(transfer_unrefp
) Transfer
*t
= NULL
;
647 const char *remote
, *local
, *verify
, *object
;
648 Manager
*m
= userdata
;
658 r
= bus_verify_polkit_async(
661 "org.freedesktop.import1.pull",
668 return 1; /* Will call us back */
670 r
= sd_bus_message_read(msg
, "sssb", &remote
, &local
, &verify
, &force
);
674 if (!http_url_is_valid(remote
))
675 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "URL %s is invalid", remote
);
679 else if (!machine_name_is_valid(local
))
680 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Local name %s is invalid", local
);
683 v
= IMPORT_VERIFY_SIGNATURE
;
685 v
= import_verify_from_string(verify
);
687 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unknown verification mode %s", verify
);
689 type
= streq_ptr(sd_bus_message_get_member(msg
), "PullTar") ? TRANSFER_TAR
: TRANSFER_RAW
;
691 if (manager_find(m
, type
, NULL
, remote
))
692 return sd_bus_error_setf(error
, BUS_ERROR_TRANSFER_IN_PROGRESS
, "Transfer for %s already in progress.", remote
);
694 r
= transfer_new(m
, &t
);
700 t
->force_local
= force
;
702 t
->remote
= strdup(remote
);
706 t
->local
= strdup(local
);
710 r
= transfer_start(t
);
714 object
= t
->object_path
;
718 return sd_bus_reply_method_return(msg
, "uo", id
, object
);
721 static int method_pull_dkr(sd_bus
*bus
, sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
722 _cleanup_(transfer_unrefp
) Transfer
*t
= NULL
;
723 const char *index_url
, *remote
, *tag
, *local
, *verify
, *object
;
724 Manager
*m
= userdata
;
733 r
= bus_verify_polkit_async(
736 "org.freedesktop.import1.pull",
743 return 1; /* Will call us back */
745 r
= sd_bus_message_read(msg
, "sssssb", &index_url
, &remote
, &tag
, &local
, &verify
, &force
);
749 if (isempty(index_url
))
750 index_url
= DEFAULT_DKR_INDEX_URL
;
752 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Index URL must be specified.");
753 if (!http_url_is_valid(index_url
))
754 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Index URL %s is invalid", index_url
);
756 if (!dkr_name_is_valid(remote
))
757 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Remote name %s is not valid", remote
);
761 else if (!dkr_tag_is_valid(tag
))
762 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Tag %s is not valid", tag
);
766 else if (!machine_name_is_valid(local
))
767 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Local name %s is invalid", local
);
770 v
= IMPORT_VERIFY_SIGNATURE
;
772 v
= import_verify_from_string(verify
);
774 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unknown verification mode %s", verify
);
776 if (v
!= IMPORT_VERIFY_NO
)
777 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "DKR does not support verification.");
779 if (manager_find(m
, TRANSFER_DKR
, index_url
, remote
))
780 return sd_bus_error_setf(error
, BUS_ERROR_TRANSFER_IN_PROGRESS
, "Transfer for %s already in progress.", remote
);
782 r
= transfer_new(m
, &t
);
786 t
->type
= TRANSFER_DKR
;
788 t
->force_local
= force
;
790 t
->dkr_index_url
= strdup(index_url
);
791 if (!t
->dkr_index_url
)
794 t
->remote
= strjoin(remote
, ":", tag
, NULL
);
798 t
->local
= strdup(local
);
802 r
= transfer_start(t
);
806 object
= t
->object_path
;
810 return sd_bus_reply_method_return(msg
, "uo", id
, object
);
813 static int method_list_transfers(sd_bus
*bus
, sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
814 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
815 Manager
*m
= userdata
;
824 r
= sd_bus_message_new_method_return(msg
, &reply
);
828 r
= sd_bus_message_open_container(reply
, 'a', "(usssdo)");
832 HASHMAP_FOREACH(t
, m
->transfers
, i
) {
834 r
= sd_bus_message_append(
838 transfer_type_to_string(t
->type
),
841 (double) t
->progress_percent
/ 100.0,
847 r
= sd_bus_message_close_container(reply
);
851 return sd_bus_send(bus
, reply
, NULL
);
854 static int method_cancel(sd_bus
*bus
, sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
855 Transfer
*t
= userdata
;
862 r
= bus_verify_polkit_async(
865 "org.freedesktop.import1.pull",
867 &t
->manager
->polkit_registry
,
872 return 1; /* Will call us back */
874 r
= transfer_cancel(t
);
878 return sd_bus_reply_method_return(msg
, NULL
);
881 static int method_cancel_transfer(sd_bus
*bus
, sd_bus_message
*msg
, void *userdata
, sd_bus_error
*error
) {
882 Manager
*m
= userdata
;
891 r
= bus_verify_polkit_async(
894 "org.freedesktop.import1.pull",
901 return 1; /* Will call us back */
903 r
= sd_bus_message_read(msg
, "u", &id
);
907 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid transfer id");
909 t
= hashmap_get(m
->transfers
, UINT32_TO_PTR(id
));
911 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_TRANSFER
, "No transfer by id %" PRIu32
, id
);
913 r
= transfer_cancel(t
);
917 return sd_bus_reply_method_return(msg
, NULL
);
920 static int property_get_progress(
923 const char *interface
,
924 const char *property
,
925 sd_bus_message
*reply
,
927 sd_bus_error
*error
) {
929 Transfer
*t
= userdata
;
935 return sd_bus_message_append(reply
, "d", (double) t
->progress_percent
/ 100.0);
938 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type
, transfer_type
, TransferType
);
939 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_verify
, import_verify
, ImportVerify
);
941 static const sd_bus_vtable transfer_vtable
[] = {
942 SD_BUS_VTABLE_START(0),
943 SD_BUS_PROPERTY("Id", "u", NULL
, offsetof(Transfer
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
944 SD_BUS_PROPERTY("Local", "s", NULL
, offsetof(Transfer
, local
), SD_BUS_VTABLE_PROPERTY_CONST
),
945 SD_BUS_PROPERTY("Remote", "s", NULL
, offsetof(Transfer
, remote
), SD_BUS_VTABLE_PROPERTY_CONST
),
946 SD_BUS_PROPERTY("Type", "s", property_get_type
, offsetof(Transfer
, type
), SD_BUS_VTABLE_PROPERTY_CONST
),
947 SD_BUS_PROPERTY("Verify", "s", property_get_verify
, offsetof(Transfer
, verify
), SD_BUS_VTABLE_PROPERTY_CONST
),
948 SD_BUS_PROPERTY("Progress", "d", property_get_progress
, 0, 0),
949 SD_BUS_METHOD("Cancel", NULL
, NULL
, method_cancel
, SD_BUS_VTABLE_UNPRIVILEGED
),
950 SD_BUS_SIGNAL("LogMessage", "us", 0),
954 static const sd_bus_vtable manager_vtable
[] = {
955 SD_BUS_VTABLE_START(0),
956 SD_BUS_METHOD("PullTar", "sssb", "uo", method_pull_tar_or_raw
, SD_BUS_VTABLE_UNPRIVILEGED
),
957 SD_BUS_METHOD("PullRaw", "sssb", "uo", method_pull_tar_or_raw
, SD_BUS_VTABLE_UNPRIVILEGED
),
958 SD_BUS_METHOD("PullDkr", "sssssb", "uo", method_pull_dkr
, SD_BUS_VTABLE_UNPRIVILEGED
),
959 SD_BUS_METHOD("ListTransfers", NULL
, "a(usssdo)", method_list_transfers
, SD_BUS_VTABLE_UNPRIVILEGED
),
960 SD_BUS_METHOD("CancelTransfer", "u", NULL
, method_cancel_transfer
, SD_BUS_VTABLE_UNPRIVILEGED
),
961 SD_BUS_SIGNAL("TransferNew", "uo", 0),
962 SD_BUS_SIGNAL("TransferRemoved", "uos", 0),
966 static int transfer_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
967 Manager
*m
= userdata
;
979 p
= startswith(path
, "/org/freedesktop/import1/transfer/_");
983 r
= safe_atou32(p
, &id
);
984 if (r
< 0 || id
== 0)
987 t
= hashmap_get(m
->transfers
, UINT32_TO_PTR(id
));
995 static int transfer_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
996 _cleanup_strv_free_
char **l
= NULL
;
997 Manager
*m
= userdata
;
1002 l
= new0(char*, hashmap_size(m
->transfers
) + 1);
1006 HASHMAP_FOREACH(t
, m
->transfers
, i
) {
1008 l
[k
] = strdup(t
->object_path
);
1021 static int manager_add_bus_objects(Manager
*m
) {
1026 r
= sd_bus_add_object_vtable(m
->bus
, NULL
, "/org/freedesktop/import1", "org.freedesktop.import1.Manager", manager_vtable
, m
);
1028 return log_error_errno(r
, "Failed to register object: %m");
1030 r
= sd_bus_add_fallback_vtable(m
->bus
, NULL
, "/org/freedesktop/import1/transfer", "org.freedesktop.import1.Transfer", transfer_vtable
, transfer_object_find
, m
);
1032 return log_error_errno(r
, "Failed to register object: %m");
1034 r
= sd_bus_add_node_enumerator(m
->bus
, NULL
, "/org/freedesktop/import1/transfer", transfer_node_enumerator
, m
);
1036 return log_error_errno(r
, "Failed to add transfer enumerator: %m");
1038 r
= sd_bus_request_name(m
->bus
, "org.freedesktop.import1", 0);
1040 return log_error_errno(r
, "Failed to register name: %m");
1042 r
= sd_bus_attach_event(m
->bus
, m
->event
, 0);
1044 return log_error_errno(r
, "Failed to attach bus to event loop: %m");
1049 static bool manager_check_idle(void *userdata
) {
1050 Manager
*m
= userdata
;
1052 return hashmap_isempty(m
->transfers
);
1055 static int manager_run(Manager
*m
) {
1058 return bus_event_loop_with_idle(
1061 "org.freedesktop.import1",
1067 int main(int argc
, char *argv
[]) {
1068 _cleanup_(manager_unrefp
) Manager
*m
= NULL
;
1071 log_set_target(LOG_TARGET_AUTO
);
1072 log_parse_environment();
1078 log_error("This program takes no arguments.");
1083 assert_se(sigprocmask_many(SIG_BLOCK
, SIGCHLD
, -1) >= 0);
1085 r
= manager_new(&m
);
1087 log_error_errno(r
, "Failed to allocate manager object: %m");
1091 r
= manager_add_bus_objects(m
);
1097 log_error_errno(r
, "Failed to run event loop: %m");
1102 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;