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