Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <sys/prctl.h>
4 : : #include <sys/wait.h>
5 : :
6 : : #include "sd-bus.h"
7 : :
8 : : #include "alloc-util.h"
9 : : #include "bus-common-errors.h"
10 : : #include "bus-util.h"
11 : : #include "def.h"
12 : : #include "fd-util.h"
13 : : #include "float.h"
14 : : #include "hostname-util.h"
15 : : #include "import-util.h"
16 : : #include "machine-pool.h"
17 : : #include "main-func.h"
18 : : #include "missing.h"
19 : : #include "mkdir.h"
20 : : #include "parse-util.h"
21 : : #include "path-util.h"
22 : : #include "process-util.h"
23 : : #include "signal-util.h"
24 : : #include "socket-util.h"
25 : : #include "stat-util.h"
26 : : #include "string-table.h"
27 : : #include "strv.h"
28 : : #include "syslog-util.h"
29 : : #include "user-util.h"
30 : : #include "util.h"
31 : : #include "web-util.h"
32 : :
33 : : typedef struct Transfer Transfer;
34 : : typedef struct Manager Manager;
35 : :
36 : : typedef enum TransferType {
37 : : TRANSFER_IMPORT_TAR,
38 : : TRANSFER_IMPORT_RAW,
39 : : TRANSFER_IMPORT_FS,
40 : : TRANSFER_EXPORT_TAR,
41 : : TRANSFER_EXPORT_RAW,
42 : : TRANSFER_PULL_TAR,
43 : : TRANSFER_PULL_RAW,
44 : : _TRANSFER_TYPE_MAX,
45 : : _TRANSFER_TYPE_INVALID = -1,
46 : : } TransferType;
47 : :
48 : : struct Transfer {
49 : : Manager *manager;
50 : :
51 : : uint32_t id;
52 : : char *object_path;
53 : :
54 : : TransferType type;
55 : : ImportVerify verify;
56 : :
57 : : char *remote;
58 : : char *local;
59 : : bool force_local;
60 : : bool read_only;
61 : :
62 : : char *format;
63 : :
64 : : pid_t pid;
65 : :
66 : : int log_fd;
67 : :
68 : : char log_message[LINE_MAX];
69 : : size_t log_message_size;
70 : :
71 : : sd_event_source *pid_event_source;
72 : : sd_event_source *log_event_source;
73 : :
74 : : unsigned n_canceled;
75 : : unsigned progress_percent;
76 : :
77 : : int stdin_fd;
78 : : int stdout_fd;
79 : : };
80 : :
81 : : struct Manager {
82 : : sd_event *event;
83 : : sd_bus *bus;
84 : :
85 : : uint32_t current_transfer_id;
86 : : Hashmap *transfers;
87 : :
88 : : Hashmap *polkit_registry;
89 : :
90 : : int notify_fd;
91 : :
92 : : sd_event_source *notify_event_source;
93 : : };
94 : :
95 : : #define TRANSFERS_MAX 64
96 : :
97 : : static const char* const transfer_type_table[_TRANSFER_TYPE_MAX] = {
98 : : [TRANSFER_IMPORT_TAR] = "import-tar",
99 : : [TRANSFER_IMPORT_RAW] = "import-raw",
100 : : [TRANSFER_IMPORT_FS] = "import-fs",
101 : : [TRANSFER_EXPORT_TAR] = "export-tar",
102 : : [TRANSFER_EXPORT_RAW] = "export-raw",
103 : : [TRANSFER_PULL_TAR] = "pull-tar",
104 : : [TRANSFER_PULL_RAW] = "pull-raw",
105 : : };
106 : :
107 [ # # # # ]: 0 : DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(transfer_type, TransferType);
108 : :
109 : 0 : static Transfer *transfer_unref(Transfer *t) {
110 [ # # ]: 0 : if (!t)
111 : 0 : return NULL;
112 : :
113 [ # # ]: 0 : if (t->manager)
114 : 0 : hashmap_remove(t->manager->transfers, UINT32_TO_PTR(t->id));
115 : :
116 : 0 : sd_event_source_unref(t->pid_event_source);
117 : 0 : sd_event_source_unref(t->log_event_source);
118 : :
119 : 0 : free(t->remote);
120 : 0 : free(t->local);
121 : 0 : free(t->format);
122 : 0 : free(t->object_path);
123 : :
124 [ # # ]: 0 : if (t->pid > 0) {
125 : 0 : (void) kill_and_sigcont(t->pid, SIGKILL);
126 : 0 : (void) wait_for_terminate(t->pid, NULL);
127 : : }
128 : :
129 : 0 : safe_close(t->log_fd);
130 : 0 : safe_close(t->stdin_fd);
131 : 0 : safe_close(t->stdout_fd);
132 : :
133 : 0 : return mfree(t);
134 : : }
135 : :
136 [ # # ]: 0 : DEFINE_TRIVIAL_CLEANUP_FUNC(Transfer*, transfer_unref);
137 : :
138 : 0 : static int transfer_new(Manager *m, Transfer **ret) {
139 : 0 : _cleanup_(transfer_unrefp) Transfer *t = NULL;
140 : : uint32_t id;
141 : : int r;
142 : :
143 [ # # ]: 0 : assert(m);
144 [ # # ]: 0 : assert(ret);
145 : :
146 [ # # ]: 0 : if (hashmap_size(m->transfers) >= TRANSFERS_MAX)
147 : 0 : return -E2BIG;
148 : :
149 : 0 : r = hashmap_ensure_allocated(&m->transfers, &trivial_hash_ops);
150 [ # # ]: 0 : if (r < 0)
151 : 0 : return r;
152 : :
153 : 0 : t = new(Transfer, 1);
154 [ # # ]: 0 : if (!t)
155 : 0 : return -ENOMEM;
156 : :
157 : 0 : *t = (Transfer) {
158 : : .type = _TRANSFER_TYPE_INVALID,
159 : : .log_fd = -1,
160 : : .stdin_fd = -1,
161 : : .stdout_fd = -1,
162 : : .verify = _IMPORT_VERIFY_INVALID,
163 : : .progress_percent= (unsigned) -1,
164 : : };
165 : :
166 : 0 : id = m->current_transfer_id + 1;
167 : :
168 [ # # ]: 0 : if (asprintf(&t->object_path, "/org/freedesktop/import1/transfer/_%" PRIu32, id) < 0)
169 : 0 : return -ENOMEM;
170 : :
171 : 0 : r = hashmap_put(m->transfers, UINT32_TO_PTR(id), t);
172 [ # # ]: 0 : if (r < 0)
173 : 0 : return r;
174 : :
175 : 0 : m->current_transfer_id = id;
176 : :
177 : 0 : t->manager = m;
178 : 0 : t->id = id;
179 : :
180 : 0 : *ret = TAKE_PTR(t);
181 : :
182 : 0 : return 0;
183 : : }
184 : :
185 : 0 : static double transfer_percent_as_double(Transfer *t) {
186 [ # # ]: 0 : assert(t);
187 : :
188 [ # # ]: 0 : if (t->progress_percent == (unsigned) -1)
189 : 0 : return -DBL_MAX;
190 : :
191 : 0 : return (double) t->progress_percent / 100.0;
192 : : }
193 : :
194 : 0 : static void transfer_send_log_line(Transfer *t, const char *line) {
195 : 0 : int r, priority = LOG_INFO;
196 : :
197 [ # # ]: 0 : assert(t);
198 [ # # ]: 0 : assert(line);
199 : :
200 : 0 : syslog_parse_priority(&line, &priority, true);
201 : :
202 [ # # ]: 0 : log_full(priority, "(transfer%" PRIu32 ") %s", t->id, line);
203 : :
204 : 0 : r = sd_bus_emit_signal(
205 : 0 : t->manager->bus,
206 : 0 : t->object_path,
207 : : "org.freedesktop.import1.Transfer",
208 : : "LogMessage",
209 : : "us",
210 : : priority,
211 : : line);
212 [ # # ]: 0 : if (r < 0)
213 [ # # ]: 0 : log_warning_errno(r, "Cannot emit log message signal, ignoring: %m");
214 : 0 : }
215 : :
216 : 0 : static void transfer_send_logs(Transfer *t, bool flush) {
217 [ # # ]: 0 : assert(t);
218 : :
219 : : /* Try to send out all log messages, if we can. But if we
220 : : * can't we remove the messages from the buffer, but don't
221 : : * fail */
222 : :
223 [ # # ]: 0 : while (t->log_message_size > 0) {
224 [ # # # ]: 0 : _cleanup_free_ char *n = NULL;
225 : : char *e;
226 : :
227 [ # # ]: 0 : if (t->log_message_size >= sizeof(t->log_message))
228 : 0 : e = t->log_message + sizeof(t->log_message);
229 : : else {
230 : : char *a, *b;
231 : :
232 : 0 : a = memchr(t->log_message, 0, t->log_message_size);
233 : 0 : b = memchr(t->log_message, '\n', t->log_message_size);
234 : :
235 [ # # # # ]: 0 : if (a && b)
236 : 0 : e = a < b ? a : b;
237 [ # # ]: 0 : else if (a)
238 : 0 : e = a;
239 : : else
240 : 0 : e = b;
241 : : }
242 : :
243 [ # # ]: 0 : if (!e) {
244 [ # # ]: 0 : if (!flush)
245 : 0 : return;
246 : :
247 : 0 : e = t->log_message + t->log_message_size;
248 : : }
249 : :
250 : 0 : n = strndup(t->log_message, e - t->log_message);
251 : :
252 : : /* Skip over NUL and newlines */
253 [ # # # # : 0 : while (e < t->log_message + t->log_message_size && IN_SET(*e, 0, '\n'))
# # ]
254 : 0 : e++;
255 : :
256 : 0 : memmove(t->log_message, e, t->log_message + sizeof(t->log_message) - e);
257 : 0 : t->log_message_size -= e - t->log_message;
258 : :
259 [ # # ]: 0 : if (!n) {
260 : 0 : log_oom();
261 : 0 : continue;
262 : : }
263 : :
264 [ # # ]: 0 : if (isempty(n))
265 : 0 : continue;
266 : :
267 : 0 : transfer_send_log_line(t, n);
268 : : }
269 : : }
270 : :
271 : 0 : static int transfer_finalize(Transfer *t, bool success) {
272 : : int r;
273 : :
274 [ # # ]: 0 : assert(t);
275 : :
276 : 0 : transfer_send_logs(t, true);
277 : :
278 [ # # ]: 0 : r = sd_bus_emit_signal(
279 : 0 : t->manager->bus,
280 : : "/org/freedesktop/import1",
281 : : "org.freedesktop.import1.Manager",
282 : : "TransferRemoved",
283 : : "uos",
284 : : t->id,
285 : : t->object_path,
286 : : success ? "done" :
287 [ # # ]: 0 : t->n_canceled > 0 ? "canceled" : "failed");
288 : :
289 [ # # ]: 0 : if (r < 0)
290 [ # # ]: 0 : log_error_errno(r, "Cannot emit message: %m");
291 : :
292 : 0 : transfer_unref(t);
293 : 0 : return 0;
294 : : }
295 : :
296 : 0 : static int transfer_cancel(Transfer *t) {
297 : : int r;
298 : :
299 [ # # ]: 0 : assert(t);
300 : :
301 [ # # ]: 0 : r = kill_and_sigcont(t->pid, t->n_canceled < 3 ? SIGTERM : SIGKILL);
302 [ # # ]: 0 : if (r < 0)
303 : 0 : return r;
304 : :
305 : 0 : t->n_canceled++;
306 : 0 : return 0;
307 : : }
308 : :
309 : 0 : static int transfer_on_pid(sd_event_source *s, const siginfo_t *si, void *userdata) {
310 : 0 : Transfer *t = userdata;
311 : 0 : bool success = false;
312 : :
313 [ # # ]: 0 : assert(s);
314 [ # # ]: 0 : assert(t);
315 : :
316 [ # # ]: 0 : if (si->si_code == CLD_EXITED) {
317 [ # # ]: 0 : if (si->si_status != 0)
318 [ # # ]: 0 : log_error("Transfer process failed with exit code %i.", si->si_status);
319 : : else {
320 [ # # ]: 0 : log_debug("Transfer process succeeded.");
321 : 0 : success = true;
322 : : }
323 : :
324 [ # # # # ]: 0 : } else if (IN_SET(si->si_code, CLD_KILLED, CLD_DUMPED))
325 [ # # ]: 0 : log_error("Transfer process terminated by signal %s.", signal_to_string(si->si_status));
326 : : else
327 [ # # ]: 0 : log_error("Transfer process failed due to unknown reason.");
328 : :
329 : 0 : t->pid = 0;
330 : :
331 : 0 : return transfer_finalize(t, success);
332 : : }
333 : :
334 : 0 : static int transfer_on_log(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
335 : 0 : Transfer *t = userdata;
336 : : ssize_t l;
337 : :
338 [ # # ]: 0 : assert(s);
339 [ # # ]: 0 : assert(t);
340 : :
341 : 0 : l = read(fd, t->log_message + t->log_message_size, sizeof(t->log_message) - t->log_message_size);
342 [ # # ]: 0 : if (l < 0)
343 [ # # ]: 0 : log_error_errno(errno, "Failed to read log message: %m");
344 [ # # ]: 0 : if (l <= 0) {
345 : : /* EOF/read error. We just close the pipe here, and
346 : : * close the watch, waiting for the SIGCHLD to arrive,
347 : : * before we do anything else. */
348 : 0 : t->log_event_source = sd_event_source_unref(t->log_event_source);
349 : 0 : return 0;
350 : : }
351 : :
352 : 0 : t->log_message_size += l;
353 : :
354 : 0 : transfer_send_logs(t, false);
355 : :
356 : 0 : return 0;
357 : : }
358 : :
359 : 0 : static int transfer_start(Transfer *t) {
360 : 0 : _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
361 : : int r;
362 : :
363 [ # # ]: 0 : assert(t);
364 [ # # ]: 0 : assert(t->pid <= 0);
365 : :
366 [ # # ]: 0 : if (pipe2(pipefd, O_CLOEXEC) < 0)
367 : 0 : return -errno;
368 : :
369 : 0 : r = safe_fork("(sd-transfer)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &t->pid);
370 [ # # ]: 0 : if (r < 0)
371 : 0 : return r;
372 [ # # ]: 0 : if (r == 0) {
373 : 0 : const char *cmd[] = {
374 : : NULL, /* systemd-import, systemd-import-fs, systemd-export or systemd-pull */
375 : : NULL, /* tar, raw */
376 : : NULL, /* --verify= */
377 : : NULL, /* verify argument */
378 : : NULL, /* maybe --force */
379 : : NULL, /* maybe --read-only */
380 : : NULL, /* if so: the actual URL */
381 : : NULL, /* maybe --format= */
382 : : NULL, /* if so: the actual format */
383 : : NULL, /* remote */
384 : : NULL, /* local */
385 : : NULL
386 : : };
387 : 0 : unsigned k = 0;
388 : :
389 : : /* Child */
390 : :
391 : 0 : pipefd[0] = safe_close(pipefd[0]);
392 : :
393 : 0 : r = rearrange_stdio(t->stdin_fd,
394 [ # # ]: 0 : t->stdout_fd < 0 ? pipefd[1] : t->stdout_fd,
395 : : pipefd[1]);
396 [ # # ]: 0 : if (r < 0) {
397 [ # # ]: 0 : log_error_errno(r, "Failed to set stdin/stdout/stderr: %m");
398 : 0 : _exit(EXIT_FAILURE);
399 : : }
400 : :
401 [ # # # # ]: 0 : if (setenv("SYSTEMD_LOG_TARGET", "console-prefixed", 1) < 0 ||
402 : 0 : setenv("NOTIFY_SOCKET", "/run/systemd/import/notify", 1) < 0) {
403 [ # # ]: 0 : log_error_errno(errno, "setenv() failed: %m");
404 : 0 : _exit(EXIT_FAILURE);
405 : : }
406 : :
407 [ # # # # : 0 : switch (t->type) {
# ]
408 : :
409 : 0 : case TRANSFER_IMPORT_TAR:
410 : : case TRANSFER_IMPORT_RAW:
411 : 0 : cmd[k++] = SYSTEMD_IMPORT_PATH;
412 : 0 : break;
413 : :
414 : 0 : case TRANSFER_IMPORT_FS:
415 : 0 : cmd[k++] = SYSTEMD_IMPORT_FS_PATH;
416 : 0 : break;
417 : :
418 : 0 : case TRANSFER_EXPORT_TAR:
419 : : case TRANSFER_EXPORT_RAW:
420 : 0 : cmd[k++] = SYSTEMD_EXPORT_PATH;
421 : 0 : break;
422 : :
423 : 0 : case TRANSFER_PULL_TAR:
424 : : case TRANSFER_PULL_RAW:
425 : 0 : cmd[k++] = SYSTEMD_PULL_PATH;
426 : 0 : break;
427 : :
428 : 0 : default:
429 : 0 : assert_not_reached("Unexpected transfer type");
430 : : }
431 : :
432 [ # # # # ]: 0 : switch (t->type) {
433 : :
434 : 0 : case TRANSFER_IMPORT_TAR:
435 : : case TRANSFER_EXPORT_TAR:
436 : : case TRANSFER_PULL_TAR:
437 : 0 : cmd[k++] = "tar";
438 : 0 : break;
439 : :
440 : 0 : case TRANSFER_IMPORT_RAW:
441 : : case TRANSFER_EXPORT_RAW:
442 : : case TRANSFER_PULL_RAW:
443 : 0 : cmd[k++] = "raw";
444 : 0 : break;
445 : :
446 : 0 : case TRANSFER_IMPORT_FS:
447 : 0 : cmd[k++] = "run";
448 : 0 : break;
449 : :
450 : 0 : default:
451 : 0 : break;
452 : : }
453 : :
454 [ # # ]: 0 : if (t->verify != _IMPORT_VERIFY_INVALID) {
455 : 0 : cmd[k++] = "--verify";
456 : 0 : cmd[k++] = import_verify_to_string(t->verify);
457 : : }
458 : :
459 [ # # ]: 0 : if (t->force_local)
460 : 0 : cmd[k++] = "--force";
461 [ # # ]: 0 : if (t->read_only)
462 : 0 : cmd[k++] = "--read-only";
463 : :
464 [ # # ]: 0 : if (t->format) {
465 : 0 : cmd[k++] = "--format";
466 : 0 : cmd[k++] = t->format;
467 : : }
468 : :
469 [ # # # # ]: 0 : if (!IN_SET(t->type, TRANSFER_EXPORT_TAR, TRANSFER_EXPORT_RAW)) {
470 [ # # ]: 0 : if (t->remote)
471 : 0 : cmd[k++] = t->remote;
472 : : else
473 : 0 : cmd[k++] = "-";
474 : : }
475 : :
476 [ # # ]: 0 : if (t->local)
477 : 0 : cmd[k++] = t->local;
478 : 0 : cmd[k] = NULL;
479 : :
480 : 0 : execv(cmd[0], (char * const *) cmd);
481 [ # # ]: 0 : log_error_errno(errno, "Failed to execute %s tool: %m", cmd[0]);
482 : 0 : _exit(EXIT_FAILURE);
483 : : }
484 : :
485 : 0 : pipefd[1] = safe_close(pipefd[1]);
486 : 0 : t->log_fd = TAKE_FD(pipefd[0]);
487 : :
488 : 0 : t->stdin_fd = safe_close(t->stdin_fd);
489 : :
490 : 0 : r = sd_event_add_child(t->manager->event, &t->pid_event_source, t->pid, WEXITED, transfer_on_pid, t);
491 [ # # ]: 0 : if (r < 0)
492 : 0 : return r;
493 : :
494 : 0 : r = sd_event_add_io(t->manager->event, &t->log_event_source, t->log_fd, EPOLLIN, transfer_on_log, t);
495 [ # # ]: 0 : if (r < 0)
496 : 0 : return r;
497 : :
498 : : /* Make sure always process logging before SIGCHLD */
499 : 0 : r = sd_event_source_set_priority(t->log_event_source, SD_EVENT_PRIORITY_NORMAL -5);
500 [ # # ]: 0 : if (r < 0)
501 : 0 : return r;
502 : :
503 : 0 : r = sd_bus_emit_signal(
504 : 0 : t->manager->bus,
505 : : "/org/freedesktop/import1",
506 : : "org.freedesktop.import1.Manager",
507 : : "TransferNew",
508 : : "uo",
509 : : t->id,
510 : : t->object_path);
511 [ # # ]: 0 : if (r < 0)
512 : 0 : return r;
513 : :
514 : 0 : return 0;
515 : : }
516 : :
517 : 0 : static Manager *manager_unref(Manager *m) {
518 : : Transfer *t;
519 : :
520 [ # # ]: 0 : if (!m)
521 : 0 : return NULL;
522 : :
523 : 0 : sd_event_source_unref(m->notify_event_source);
524 : 0 : safe_close(m->notify_fd);
525 : :
526 [ # # ]: 0 : while ((t = hashmap_first(m->transfers)))
527 : 0 : transfer_unref(t);
528 : :
529 : 0 : hashmap_free(m->transfers);
530 : :
531 : 0 : bus_verify_polkit_async_registry_free(m->polkit_registry);
532 : :
533 : 0 : m->bus = sd_bus_flush_close_unref(m->bus);
534 : 0 : sd_event_unref(m->event);
535 : :
536 : 0 : return mfree(m);
537 : : }
538 : :
539 [ # # ]: 0 : DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_unref);
540 : :
541 : 0 : static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
542 : :
543 : : char buf[NOTIFY_BUFFER_MAX+1];
544 : 0 : struct iovec iovec = {
545 : : .iov_base = buf,
546 : : .iov_len = sizeof(buf)-1,
547 : : };
548 : : union {
549 : : struct cmsghdr cmsghdr;
550 : : uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
551 : : CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
552 : 0 : } control = {};
553 : 0 : struct msghdr msghdr = {
554 : : .msg_iov = &iovec,
555 : : .msg_iovlen = 1,
556 : : .msg_control = &control,
557 : : .msg_controllen = sizeof(control),
558 : : };
559 : 0 : struct ucred *ucred = NULL;
560 : 0 : Manager *m = userdata;
561 : : struct cmsghdr *cmsg;
562 : : char *p, *e;
563 : : Transfer *t;
564 : : Iterator i;
565 : : ssize_t n;
566 : : int r;
567 : :
568 : 0 : n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
569 [ # # ]: 0 : if (n < 0) {
570 [ # # # # ]: 0 : if (IN_SET(errno, EAGAIN, EINTR))
571 : 0 : return 0;
572 : :
573 : 0 : return -errno;
574 : : }
575 : :
576 : 0 : cmsg_close_all(&msghdr);
577 : :
578 [ # # # # ]: 0 : CMSG_FOREACH(cmsg, &msghdr)
579 [ # # ]: 0 : if (cmsg->cmsg_level == SOL_SOCKET &&
580 [ # # ]: 0 : cmsg->cmsg_type == SCM_CREDENTIALS &&
581 [ # # ]: 0 : cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
582 : 0 : ucred = (struct ucred*) CMSG_DATA(cmsg);
583 : :
584 [ # # ]: 0 : if (msghdr.msg_flags & MSG_TRUNC) {
585 [ # # ]: 0 : log_warning("Got overly long notification datagram, ignoring.");
586 : 0 : return 0;
587 : : }
588 : :
589 [ # # # # ]: 0 : if (!ucred || ucred->pid <= 0) {
590 [ # # ]: 0 : log_warning("Got notification datagram lacking credential information, ignoring.");
591 : 0 : return 0;
592 : : }
593 : :
594 [ # # ]: 0 : HASHMAP_FOREACH(t, m->transfers, i)
595 [ # # ]: 0 : if (ucred->pid == t->pid)
596 : 0 : break;
597 : :
598 [ # # ]: 0 : if (!t) {
599 [ # # ]: 0 : log_warning("Got notification datagram from unexpected peer, ignoring.");
600 : 0 : return 0;
601 : : }
602 : :
603 : 0 : buf[n] = 0;
604 : :
605 : 0 : p = startswith(buf, "X_IMPORT_PROGRESS=");
606 [ # # ]: 0 : if (!p) {
607 : 0 : p = strstr(buf, "\nX_IMPORT_PROGRESS=");
608 [ # # ]: 0 : if (!p)
609 : 0 : return 0;
610 : :
611 : 0 : p += 19;
612 : : }
613 : :
614 : 0 : e = strchrnul(p, '\n');
615 : 0 : *e = 0;
616 : :
617 : 0 : r = parse_percent(p);
618 [ # # ]: 0 : if (r < 0) {
619 [ # # ]: 0 : log_warning("Got invalid percent value, ignoring.");
620 : 0 : return 0;
621 : : }
622 : :
623 : 0 : t->progress_percent = (unsigned) r;
624 : :
625 [ # # ]: 0 : log_debug("Got percentage from client: %u%%", t->progress_percent);
626 : 0 : return 0;
627 : : }
628 : :
629 : 0 : static int manager_new(Manager **ret) {
630 : 0 : _cleanup_(manager_unrefp) Manager *m = NULL;
631 : : static const union sockaddr_union sa = {
632 : : .un.sun_family = AF_UNIX,
633 : : .un.sun_path = "/run/systemd/import/notify",
634 : : };
635 : : int r;
636 : :
637 [ # # ]: 0 : assert(ret);
638 : :
639 : 0 : m = new0(Manager, 1);
640 [ # # ]: 0 : if (!m)
641 : 0 : return -ENOMEM;
642 : :
643 : 0 : r = sd_event_default(&m->event);
644 [ # # ]: 0 : if (r < 0)
645 : 0 : return r;
646 : :
647 : 0 : sd_event_set_watchdog(m->event, true);
648 : :
649 : 0 : r = sd_bus_default_system(&m->bus);
650 [ # # ]: 0 : if (r < 0)
651 : 0 : return r;
652 : :
653 : 0 : m->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
654 [ # # ]: 0 : if (m->notify_fd < 0)
655 : 0 : return -errno;
656 : :
657 : 0 : (void) mkdir_parents_label(sa.un.sun_path, 0755);
658 : 0 : (void) sockaddr_un_unlink(&sa.un);
659 : :
660 [ # # # # : 0 : if (bind(m->notify_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
# # ]
661 : 0 : return -errno;
662 : :
663 : 0 : r = setsockopt_int(m->notify_fd, SOL_SOCKET, SO_PASSCRED, true);
664 [ # # ]: 0 : if (r < 0)
665 : 0 : return r;
666 : :
667 : 0 : r = sd_event_add_io(m->event, &m->notify_event_source, m->notify_fd, EPOLLIN, manager_on_notify, m);
668 [ # # ]: 0 : if (r < 0)
669 : 0 : return r;
670 : :
671 : 0 : *ret = TAKE_PTR(m);
672 : :
673 : 0 : return 0;
674 : : }
675 : :
676 : 0 : static Transfer *manager_find(Manager *m, TransferType type, const char *remote) {
677 : : Transfer *t;
678 : : Iterator i;
679 : :
680 [ # # ]: 0 : assert(m);
681 [ # # ]: 0 : assert(type >= 0);
682 [ # # ]: 0 : assert(type < _TRANSFER_TYPE_MAX);
683 : :
684 [ # # ]: 0 : HASHMAP_FOREACH(t, m->transfers, i)
685 [ # # # # ]: 0 : if (t->type == type && streq_ptr(t->remote, remote))
686 : 0 : return t;
687 : :
688 : 0 : return NULL;
689 : : }
690 : :
691 : 0 : static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
692 : 0 : _cleanup_(transfer_unrefp) Transfer *t = NULL;
693 : : int fd, force, read_only, r;
694 : : const char *local, *object;
695 : 0 : Manager *m = userdata;
696 : : TransferType type;
697 : : uint32_t id;
698 : :
699 [ # # ]: 0 : assert(msg);
700 [ # # ]: 0 : assert(m);
701 : :
702 : 0 : r = bus_verify_polkit_async(
703 : : msg,
704 : : CAP_SYS_ADMIN,
705 : : "org.freedesktop.import1.import",
706 : : NULL,
707 : : false,
708 : : UID_INVALID,
709 : : &m->polkit_registry,
710 : : error);
711 [ # # ]: 0 : if (r < 0)
712 : 0 : return r;
713 [ # # ]: 0 : if (r == 0)
714 : 0 : return 1; /* Will call us back */
715 : :
716 : 0 : r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only);
717 [ # # ]: 0 : if (r < 0)
718 : 0 : return r;
719 : :
720 : 0 : r = fd_verify_regular(fd);
721 [ # # ]: 0 : if (r < 0)
722 : 0 : return r;
723 : :
724 [ # # ]: 0 : if (!machine_name_is_valid(local))
725 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
726 : :
727 : 0 : r = setup_machine_directory(error);
728 [ # # ]: 0 : if (r < 0)
729 : 0 : return r;
730 : :
731 : 0 : type = streq_ptr(sd_bus_message_get_member(msg), "ImportTar") ? TRANSFER_IMPORT_TAR : TRANSFER_IMPORT_RAW;
732 : :
733 : 0 : r = transfer_new(m, &t);
734 [ # # ]: 0 : if (r < 0)
735 : 0 : return r;
736 : :
737 : 0 : t->type = type;
738 : 0 : t->force_local = force;
739 : 0 : t->read_only = read_only;
740 : :
741 : 0 : t->local = strdup(local);
742 [ # # ]: 0 : if (!t->local)
743 : 0 : return -ENOMEM;
744 : :
745 : 0 : t->stdin_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
746 [ # # ]: 0 : if (t->stdin_fd < 0)
747 : 0 : return -errno;
748 : :
749 : 0 : r = transfer_start(t);
750 [ # # ]: 0 : if (r < 0)
751 : 0 : return r;
752 : :
753 : 0 : object = t->object_path;
754 : 0 : id = t->id;
755 : 0 : t = NULL;
756 : :
757 : 0 : return sd_bus_reply_method_return(msg, "uo", id, object);
758 : : }
759 : :
760 : 0 : static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
761 : 0 : _cleanup_(transfer_unrefp) Transfer *t = NULL;
762 : : int fd, force, read_only, r;
763 : : const char *local, *object;
764 : 0 : Manager *m = userdata;
765 : : uint32_t id;
766 : :
767 [ # # ]: 0 : assert(msg);
768 [ # # ]: 0 : assert(m);
769 : :
770 : 0 : r = bus_verify_polkit_async(
771 : : msg,
772 : : CAP_SYS_ADMIN,
773 : : "org.freedesktop.import1.import",
774 : : NULL,
775 : : false,
776 : : UID_INVALID,
777 : : &m->polkit_registry,
778 : : error);
779 [ # # ]: 0 : if (r < 0)
780 : 0 : return r;
781 [ # # ]: 0 : if (r == 0)
782 : 0 : return 1; /* Will call us back */
783 : :
784 : 0 : r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only);
785 [ # # ]: 0 : if (r < 0)
786 : 0 : return r;
787 : :
788 : 0 : r = fd_verify_directory(fd);
789 [ # # ]: 0 : if (r < 0)
790 : 0 : return r;
791 : :
792 [ # # ]: 0 : if (!machine_name_is_valid(local))
793 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
794 : :
795 : 0 : r = setup_machine_directory(error);
796 [ # # ]: 0 : if (r < 0)
797 : 0 : return r;
798 : :
799 : 0 : r = transfer_new(m, &t);
800 [ # # ]: 0 : if (r < 0)
801 : 0 : return r;
802 : :
803 : 0 : t->type = TRANSFER_IMPORT_FS;
804 : 0 : t->force_local = force;
805 : 0 : t->read_only = read_only;
806 : :
807 : 0 : t->local = strdup(local);
808 [ # # ]: 0 : if (!t->local)
809 : 0 : return -ENOMEM;
810 : :
811 : 0 : t->stdin_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
812 [ # # ]: 0 : if (t->stdin_fd < 0)
813 : 0 : return -errno;
814 : :
815 : 0 : r = transfer_start(t);
816 [ # # ]: 0 : if (r < 0)
817 : 0 : return r;
818 : :
819 : 0 : object = t->object_path;
820 : 0 : id = t->id;
821 : 0 : t = NULL;
822 : :
823 : 0 : return sd_bus_reply_method_return(msg, "uo", id, object);
824 : : }
825 : :
826 : 0 : static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
827 : 0 : _cleanup_(transfer_unrefp) Transfer *t = NULL;
828 : : int fd, r;
829 : : const char *local, *object, *format;
830 : 0 : Manager *m = userdata;
831 : : TransferType type;
832 : : uint32_t id;
833 : :
834 [ # # ]: 0 : assert(msg);
835 [ # # ]: 0 : assert(m);
836 : :
837 : 0 : r = bus_verify_polkit_async(
838 : : msg,
839 : : CAP_SYS_ADMIN,
840 : : "org.freedesktop.import1.export",
841 : : NULL,
842 : : false,
843 : : UID_INVALID,
844 : : &m->polkit_registry,
845 : : error);
846 [ # # ]: 0 : if (r < 0)
847 : 0 : return r;
848 [ # # ]: 0 : if (r == 0)
849 : 0 : return 1; /* Will call us back */
850 : :
851 : 0 : r = sd_bus_message_read(msg, "shs", &local, &fd, &format);
852 [ # # ]: 0 : if (r < 0)
853 : 0 : return r;
854 : :
855 [ # # ]: 0 : if (!machine_name_is_valid(local))
856 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
857 : :
858 : 0 : r = fd_verify_regular(fd);
859 [ # # ]: 0 : if (r < 0)
860 : 0 : return r;
861 : :
862 [ # # ]: 0 : type = streq_ptr(sd_bus_message_get_member(msg), "ExportTar") ? TRANSFER_EXPORT_TAR : TRANSFER_EXPORT_RAW;
863 : :
864 : 0 : r = transfer_new(m, &t);
865 [ # # ]: 0 : if (r < 0)
866 : 0 : return r;
867 : :
868 : 0 : t->type = type;
869 : :
870 [ # # ]: 0 : if (!isempty(format)) {
871 : 0 : t->format = strdup(format);
872 [ # # ]: 0 : if (!t->format)
873 : 0 : return -ENOMEM;
874 : : }
875 : :
876 : 0 : t->local = strdup(local);
877 [ # # ]: 0 : if (!t->local)
878 : 0 : return -ENOMEM;
879 : :
880 : 0 : t->stdout_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
881 [ # # ]: 0 : if (t->stdout_fd < 0)
882 : 0 : return -errno;
883 : :
884 : 0 : r = transfer_start(t);
885 [ # # ]: 0 : if (r < 0)
886 : 0 : return r;
887 : :
888 : 0 : object = t->object_path;
889 : 0 : id = t->id;
890 : 0 : t = NULL;
891 : :
892 : 0 : return sd_bus_reply_method_return(msg, "uo", id, object);
893 : : }
894 : :
895 : 0 : static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
896 : 0 : _cleanup_(transfer_unrefp) Transfer *t = NULL;
897 : : const char *remote, *local, *verify, *object;
898 : 0 : Manager *m = userdata;
899 : : ImportVerify v;
900 : : TransferType type;
901 : : int force, r;
902 : : uint32_t id;
903 : :
904 [ # # ]: 0 : assert(msg);
905 [ # # ]: 0 : assert(m);
906 : :
907 : 0 : r = bus_verify_polkit_async(
908 : : msg,
909 : : CAP_SYS_ADMIN,
910 : : "org.freedesktop.import1.pull",
911 : : NULL,
912 : : false,
913 : : UID_INVALID,
914 : : &m->polkit_registry,
915 : : error);
916 [ # # ]: 0 : if (r < 0)
917 : 0 : return r;
918 [ # # ]: 0 : if (r == 0)
919 : 0 : return 1; /* Will call us back */
920 : :
921 : 0 : r = sd_bus_message_read(msg, "sssb", &remote, &local, &verify, &force);
922 [ # # ]: 0 : if (r < 0)
923 : 0 : return r;
924 : :
925 [ # # ]: 0 : if (!http_url_is_valid(remote))
926 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "URL %s is invalid", remote);
927 : :
928 [ # # ]: 0 : if (isempty(local))
929 : 0 : local = NULL;
930 [ # # ]: 0 : else if (!machine_name_is_valid(local))
931 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
932 : :
933 [ # # ]: 0 : if (isempty(verify))
934 : 0 : v = IMPORT_VERIFY_SIGNATURE;
935 : : else
936 : 0 : v = import_verify_from_string(verify);
937 [ # # ]: 0 : if (v < 0)
938 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown verification mode %s", verify);
939 : :
940 : 0 : r = setup_machine_directory(error);
941 [ # # ]: 0 : if (r < 0)
942 : 0 : return r;
943 : :
944 [ # # ]: 0 : type = streq_ptr(sd_bus_message_get_member(msg), "PullTar") ? TRANSFER_PULL_TAR : TRANSFER_PULL_RAW;
945 : :
946 [ # # ]: 0 : if (manager_find(m, type, remote))
947 : 0 : return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS, "Transfer for %s already in progress.", remote);
948 : :
949 : 0 : r = transfer_new(m, &t);
950 [ # # ]: 0 : if (r < 0)
951 : 0 : return r;
952 : :
953 : 0 : t->type = type;
954 : 0 : t->verify = v;
955 : 0 : t->force_local = force;
956 : :
957 : 0 : t->remote = strdup(remote);
958 [ # # ]: 0 : if (!t->remote)
959 : 0 : return -ENOMEM;
960 : :
961 [ # # ]: 0 : if (local) {
962 : 0 : t->local = strdup(local);
963 [ # # ]: 0 : if (!t->local)
964 : 0 : return -ENOMEM;
965 : : }
966 : :
967 : 0 : r = transfer_start(t);
968 [ # # ]: 0 : if (r < 0)
969 : 0 : return r;
970 : :
971 : 0 : object = t->object_path;
972 : 0 : id = t->id;
973 : 0 : t = NULL;
974 : :
975 : 0 : return sd_bus_reply_method_return(msg, "uo", id, object);
976 : : }
977 : :
978 : 0 : static int method_list_transfers(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
979 : 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
980 : 0 : Manager *m = userdata;
981 : : Transfer *t;
982 : : Iterator i;
983 : : int r;
984 : :
985 [ # # ]: 0 : assert(msg);
986 [ # # ]: 0 : assert(m);
987 : :
988 : 0 : r = sd_bus_message_new_method_return(msg, &reply);
989 [ # # ]: 0 : if (r < 0)
990 : 0 : return r;
991 : :
992 : 0 : r = sd_bus_message_open_container(reply, 'a', "(usssdo)");
993 [ # # ]: 0 : if (r < 0)
994 : 0 : return r;
995 : :
996 [ # # ]: 0 : HASHMAP_FOREACH(t, m->transfers, i) {
997 : :
998 : 0 : r = sd_bus_message_append(
999 : : reply,
1000 : : "(usssdo)",
1001 : 0 : t->id,
1002 : 0 : transfer_type_to_string(t->type),
1003 : 0 : t->remote,
1004 : 0 : t->local,
1005 : : transfer_percent_as_double(t),
1006 : 0 : t->object_path);
1007 [ # # ]: 0 : if (r < 0)
1008 : 0 : return r;
1009 : : }
1010 : :
1011 : 0 : r = sd_bus_message_close_container(reply);
1012 [ # # ]: 0 : if (r < 0)
1013 : 0 : return r;
1014 : :
1015 : 0 : return sd_bus_send(NULL, reply, NULL);
1016 : : }
1017 : :
1018 : 0 : static int method_cancel(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
1019 : 0 : Transfer *t = userdata;
1020 : : int r;
1021 : :
1022 [ # # ]: 0 : assert(msg);
1023 [ # # ]: 0 : assert(t);
1024 : :
1025 : 0 : r = bus_verify_polkit_async(
1026 : : msg,
1027 : : CAP_SYS_ADMIN,
1028 : : "org.freedesktop.import1.pull",
1029 : : NULL,
1030 : : false,
1031 : : UID_INVALID,
1032 : 0 : &t->manager->polkit_registry,
1033 : : error);
1034 [ # # ]: 0 : if (r < 0)
1035 : 0 : return r;
1036 [ # # ]: 0 : if (r == 0)
1037 : 0 : return 1; /* Will call us back */
1038 : :
1039 : 0 : r = transfer_cancel(t);
1040 [ # # ]: 0 : if (r < 0)
1041 : 0 : return r;
1042 : :
1043 : 0 : return sd_bus_reply_method_return(msg, NULL);
1044 : : }
1045 : :
1046 : 0 : static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
1047 : 0 : Manager *m = userdata;
1048 : : Transfer *t;
1049 : : uint32_t id;
1050 : : int r;
1051 : :
1052 [ # # ]: 0 : assert(msg);
1053 [ # # ]: 0 : assert(m);
1054 : :
1055 : 0 : r = bus_verify_polkit_async(
1056 : : msg,
1057 : : CAP_SYS_ADMIN,
1058 : : "org.freedesktop.import1.pull",
1059 : : NULL,
1060 : : false,
1061 : : UID_INVALID,
1062 : : &m->polkit_registry,
1063 : : error);
1064 [ # # ]: 0 : if (r < 0)
1065 : 0 : return r;
1066 [ # # ]: 0 : if (r == 0)
1067 : 0 : return 1; /* Will call us back */
1068 : :
1069 : 0 : r = sd_bus_message_read(msg, "u", &id);
1070 [ # # ]: 0 : if (r < 0)
1071 : 0 : return r;
1072 [ # # ]: 0 : if (id <= 0)
1073 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid transfer id");
1074 : :
1075 : 0 : t = hashmap_get(m->transfers, UINT32_TO_PTR(id));
1076 [ # # ]: 0 : if (!t)
1077 : 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_TRANSFER, "No transfer by id %" PRIu32, id);
1078 : :
1079 : 0 : r = transfer_cancel(t);
1080 [ # # ]: 0 : if (r < 0)
1081 : 0 : return r;
1082 : :
1083 : 0 : return sd_bus_reply_method_return(msg, NULL);
1084 : : }
1085 : :
1086 : 0 : static int property_get_progress(
1087 : : sd_bus *bus,
1088 : : const char *path,
1089 : : const char *interface,
1090 : : const char *property,
1091 : : sd_bus_message *reply,
1092 : : void *userdata,
1093 : : sd_bus_error *error) {
1094 : :
1095 : 0 : Transfer *t = userdata;
1096 : :
1097 [ # # ]: 0 : assert(bus);
1098 [ # # ]: 0 : assert(reply);
1099 [ # # ]: 0 : assert(t);
1100 : :
1101 : 0 : return sd_bus_message_append(reply, "d", transfer_percent_as_double(t));
1102 : : }
1103 : :
1104 [ # # # # : 0 : static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, transfer_type, TransferType);
# # ]
1105 [ # # # # : 0 : static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_verify, import_verify, ImportVerify);
# # ]
1106 : :
1107 : : static const sd_bus_vtable transfer_vtable[] = {
1108 : : SD_BUS_VTABLE_START(0),
1109 : : SD_BUS_PROPERTY("Id", "u", NULL, offsetof(Transfer, id), SD_BUS_VTABLE_PROPERTY_CONST),
1110 : : SD_BUS_PROPERTY("Local", "s", NULL, offsetof(Transfer, local), SD_BUS_VTABLE_PROPERTY_CONST),
1111 : : SD_BUS_PROPERTY("Remote", "s", NULL, offsetof(Transfer, remote), SD_BUS_VTABLE_PROPERTY_CONST),
1112 : : SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Transfer, type), SD_BUS_VTABLE_PROPERTY_CONST),
1113 : : SD_BUS_PROPERTY("Verify", "s", property_get_verify, offsetof(Transfer, verify), SD_BUS_VTABLE_PROPERTY_CONST),
1114 : : SD_BUS_PROPERTY("Progress", "d", property_get_progress, 0, 0),
1115 : : SD_BUS_METHOD("Cancel", NULL, NULL, method_cancel, SD_BUS_VTABLE_UNPRIVILEGED),
1116 : : SD_BUS_SIGNAL("LogMessage", "us", 0),
1117 : : SD_BUS_VTABLE_END,
1118 : : };
1119 : :
1120 : : static const sd_bus_vtable manager_vtable[] = {
1121 : : SD_BUS_VTABLE_START(0),
1122 : : SD_BUS_METHOD("ImportTar", "hsbb", "uo", method_import_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
1123 : : SD_BUS_METHOD("ImportRaw", "hsbb", "uo", method_import_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
1124 : : SD_BUS_METHOD("ImportFileSystem", "hsbb", "uo", method_import_fs, SD_BUS_VTABLE_UNPRIVILEGED),
1125 : : SD_BUS_METHOD("ExportTar", "shs", "uo", method_export_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
1126 : : SD_BUS_METHOD("ExportRaw", "shs", "uo", method_export_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
1127 : : SD_BUS_METHOD("PullTar", "sssb", "uo", method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
1128 : : SD_BUS_METHOD("PullRaw", "sssb", "uo", method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
1129 : : SD_BUS_METHOD("ListTransfers", NULL, "a(usssdo)", method_list_transfers, SD_BUS_VTABLE_UNPRIVILEGED),
1130 : : SD_BUS_METHOD("CancelTransfer", "u", NULL, method_cancel_transfer, SD_BUS_VTABLE_UNPRIVILEGED),
1131 : : SD_BUS_SIGNAL("TransferNew", "uo", 0),
1132 : : SD_BUS_SIGNAL("TransferRemoved", "uos", 0),
1133 : : SD_BUS_VTABLE_END,
1134 : : };
1135 : :
1136 : 0 : static int transfer_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
1137 : 0 : Manager *m = userdata;
1138 : : Transfer *t;
1139 : : const char *p;
1140 : : uint32_t id;
1141 : : int r;
1142 : :
1143 [ # # ]: 0 : assert(bus);
1144 [ # # ]: 0 : assert(path);
1145 [ # # ]: 0 : assert(interface);
1146 [ # # ]: 0 : assert(found);
1147 [ # # ]: 0 : assert(m);
1148 : :
1149 : 0 : p = startswith(path, "/org/freedesktop/import1/transfer/_");
1150 [ # # ]: 0 : if (!p)
1151 : 0 : return 0;
1152 : :
1153 : 0 : r = safe_atou32(p, &id);
1154 [ # # # # ]: 0 : if (r < 0 || id == 0)
1155 : 0 : return 0;
1156 : :
1157 : 0 : t = hashmap_get(m->transfers, UINT32_TO_PTR(id));
1158 [ # # ]: 0 : if (!t)
1159 : 0 : return 0;
1160 : :
1161 : 0 : *found = t;
1162 : 0 : return 1;
1163 : : }
1164 : :
1165 : 0 : static int transfer_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
1166 : 0 : _cleanup_strv_free_ char **l = NULL;
1167 : 0 : Manager *m = userdata;
1168 : : Transfer *t;
1169 : 0 : unsigned k = 0;
1170 : : Iterator i;
1171 : :
1172 [ # # ]: 0 : l = new0(char*, hashmap_size(m->transfers) + 1);
1173 [ # # ]: 0 : if (!l)
1174 : 0 : return -ENOMEM;
1175 : :
1176 [ # # ]: 0 : HASHMAP_FOREACH(t, m->transfers, i) {
1177 : :
1178 : 0 : l[k] = strdup(t->object_path);
1179 [ # # ]: 0 : if (!l[k])
1180 : 0 : return -ENOMEM;
1181 : :
1182 : 0 : k++;
1183 : : }
1184 : :
1185 : 0 : *nodes = TAKE_PTR(l);
1186 : :
1187 : 0 : return 1;
1188 : : }
1189 : :
1190 : 0 : static int manager_add_bus_objects(Manager *m) {
1191 : : int r;
1192 : :
1193 [ # # ]: 0 : assert(m);
1194 : :
1195 : 0 : r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/import1", "org.freedesktop.import1.Manager", manager_vtable, m);
1196 [ # # ]: 0 : if (r < 0)
1197 [ # # ]: 0 : return log_error_errno(r, "Failed to register object: %m");
1198 : :
1199 : 0 : r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/import1/transfer", "org.freedesktop.import1.Transfer", transfer_vtable, transfer_object_find, m);
1200 [ # # ]: 0 : if (r < 0)
1201 [ # # ]: 0 : return log_error_errno(r, "Failed to register object: %m");
1202 : :
1203 : 0 : r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/import1/transfer", transfer_node_enumerator, m);
1204 [ # # ]: 0 : if (r < 0)
1205 [ # # ]: 0 : return log_error_errno(r, "Failed to add transfer enumerator: %m");
1206 : :
1207 : 0 : r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.import1", 0, NULL, NULL);
1208 [ # # ]: 0 : if (r < 0)
1209 [ # # ]: 0 : return log_error_errno(r, "Failed to request name: %m");
1210 : :
1211 : 0 : r = sd_bus_attach_event(m->bus, m->event, 0);
1212 [ # # ]: 0 : if (r < 0)
1213 [ # # ]: 0 : return log_error_errno(r, "Failed to attach bus to event loop: %m");
1214 : :
1215 : 0 : return 0;
1216 : : }
1217 : :
1218 : 0 : static bool manager_check_idle(void *userdata) {
1219 : 0 : Manager *m = userdata;
1220 : :
1221 : 0 : return hashmap_isempty(m->transfers);
1222 : : }
1223 : :
1224 : 0 : static int manager_run(Manager *m) {
1225 [ # # ]: 0 : assert(m);
1226 : :
1227 : 0 : return bus_event_loop_with_idle(
1228 : : m->event,
1229 : : m->bus,
1230 : : "org.freedesktop.import1",
1231 : : DEFAULT_EXIT_USEC,
1232 : : manager_check_idle,
1233 : : m);
1234 : : }
1235 : :
1236 : 0 : static int run(int argc, char *argv[]) {
1237 : 0 : _cleanup_(manager_unrefp) Manager *m = NULL;
1238 : : int r;
1239 : :
1240 : 0 : log_setup_service();
1241 : :
1242 : 0 : umask(0022);
1243 : :
1244 [ # # ]: 0 : if (argc != 1) {
1245 [ # # ]: 0 : log_error("This program takes no arguments.");
1246 : 0 : return -EINVAL;
1247 : : }
1248 : :
1249 [ # # ]: 0 : assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
1250 : :
1251 : 0 : r = manager_new(&m);
1252 [ # # ]: 0 : if (r < 0)
1253 [ # # ]: 0 : return log_error_errno(r, "Failed to allocate manager object: %m");
1254 : :
1255 : 0 : r = manager_add_bus_objects(m);
1256 [ # # ]: 0 : if (r < 0)
1257 : 0 : return r;
1258 : :
1259 : 0 : r = manager_run(m);
1260 [ # # ]: 0 : if (r < 0)
1261 [ # # ]: 0 : return log_error_errno(r, "Failed to run event loop: %m");
1262 : :
1263 : 0 : return 0;
1264 : : }
1265 : :
1266 : 0 : DEFINE_MAIN_FUNCTION(run);
|