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