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