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