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