chiark / gitweb /
f315212685c5b5bb67fca025791d567df0056b63
[elogind.git] / src / import / importd.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2015 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/prctl.h>
23 #include <sys/vfs.h>
24 #include <sys/statvfs.h>
25 #include <sys/mount.h>
26
27 #include "sd-bus.h"
28 #include "util.h"
29 #include "strv.h"
30 #include "bus-util.h"
31 #include "bus-common-errors.h"
32 #include "def.h"
33 #include "socket-util.h"
34 #include "mkdir.h"
35 #include "def.h"
36 #include "missing.h"
37 #include "btrfs-util.h"
38 #include "path-util.h"
39 #include "import-util.h"
40
41 #define VAR_LIB_MACHINES_SIZE_START (1024UL*1024UL*500UL)
42 #define VAR_LIB_MACHINES_FREE_MIN (1024UL*1024UL*750UL)
43
44 typedef struct Transfer Transfer;
45 typedef struct Manager Manager;
46
47 typedef enum TransferType {
48         TRANSFER_TAR,
49         TRANSFER_RAW,
50         TRANSFER_DKR,
51         _TRANSFER_TYPE_MAX,
52         _TRANSFER_TYPE_INVALID = -1,
53 } TransferType;
54
55 struct 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;
67
68         char *dkr_index_url;
69
70         pid_t pid;
71
72         int log_fd;
73
74         char log_message[LINE_MAX];
75         size_t log_message_size;
76
77         sd_event_source *pid_event_source;
78         sd_event_source *log_event_source;
79
80         unsigned n_canceled;
81         unsigned progress_percent;
82 };
83
84 struct Manager {
85         sd_event *event;
86         sd_bus *bus;
87
88         uint32_t current_transfer_id;
89         Hashmap *transfers;
90
91         Hashmap *polkit_registry;
92
93         int notify_fd;
94
95         sd_event_source *notify_event_source;
96 };
97
98 #define TRANSFERS_MAX 64
99
100 static const char* const transfer_type_table[_TRANSFER_TYPE_MAX] = {
101         [TRANSFER_TAR] = "tar",
102         [TRANSFER_RAW] = "raw",
103         [TRANSFER_DKR] = "dkr",
104 };
105
106 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(transfer_type, TransferType);
107
108 static Transfer *transfer_unref(Transfer *t) {
109         if (!t)
110                 return NULL;
111
112         if (t->manager)
113                 hashmap_remove(t->manager->transfers, UINT32_TO_PTR(t->id));
114
115         sd_event_source_unref(t->pid_event_source);
116         sd_event_source_unref(t->log_event_source);
117
118         free(t->remote);
119         free(t->local);
120         free(t->dkr_index_url);
121         free(t->object_path);
122
123         if (t->pid > 0) {
124                 (void) kill_and_sigcont(t->pid, SIGKILL);
125                 (void) wait_for_terminate(t->pid, NULL);
126         }
127
128         safe_close(t->log_fd);
129
130         free(t);
131         return NULL;
132 }
133
134 DEFINE_TRIVIAL_CLEANUP_FUNC(Transfer*, transfer_unref);
135
136 static int transfer_new(Manager *m, Transfer **ret) {
137         _cleanup_(transfer_unrefp) Transfer *t = NULL;
138         uint32_t id;
139         int r;
140
141         assert(m);
142         assert(ret);
143
144         if (hashmap_size(m->transfers) >= TRANSFERS_MAX)
145                 return -E2BIG;
146
147         r = hashmap_ensure_allocated(&m->transfers, &trivial_hash_ops);
148         if (r < 0)
149                 return r;
150
151         t = new0(Transfer, 1);
152         if (!t)
153                 return -ENOMEM;
154
155         t->type = _TRANSFER_TYPE_INVALID;
156         t->log_fd = -1;
157
158         id = m->current_transfer_id + 1;
159
160         if (asprintf(&t->object_path, "/org/freedesktop/import1/transfer/_%" PRIu32, id) < 0)
161                 return -ENOMEM;
162
163         r = hashmap_put(m->transfers, UINT32_TO_PTR(id), t);
164         if (r < 0)
165                 return r;
166
167         m->current_transfer_id = id;
168
169         t->manager = m;
170         t->id = id;
171
172         *ret = t;
173         t = NULL;
174
175         return 0;
176 }
177
178 static void transfer_send_log_line(Transfer *t, const char *line) {
179         int r, priority = LOG_INFO;
180
181         assert(t);
182         assert(line);
183
184         syslog_parse_priority(&line, &priority, true);
185
186         log_full(priority, "(transfer%" PRIu32 ") %s", t->id, line);
187
188         r = sd_bus_emit_signal(
189                         t->manager->bus,
190                         t->object_path,
191                         "org.freedesktop.import1.Transfer",
192                         "LogMessage",
193                         "us",
194                         priority,
195                         line);
196         if (r < 0)
197                 log_error_errno(r, "Cannot emit message: %m");
198  }
199
200 static void transfer_send_logs(Transfer *t, bool flush) {
201         assert(t);
202
203         /* Try to send out all log messages, if we can. But if we
204          * can't we remove the messages from the buffer, but don't
205          * fail */
206
207         while (t->log_message_size > 0) {
208                 _cleanup_free_ char *n = NULL;
209                 char *e;
210
211                 if (t->log_message_size >= sizeof(t->log_message))
212                         e = t->log_message + sizeof(t->log_message);
213                 else {
214                         char *a, *b;
215
216                         a = memchr(t->log_message, 0, t->log_message_size);
217                         b = memchr(t->log_message, '\n', t->log_message_size);
218
219                         if (a && b)
220                                 e = a < b ? a : b;
221                         else if (a)
222                                 e = a;
223                         else
224                                 e = b;
225                 }
226
227                 if (!e) {
228                         if (!flush)
229                                 return;
230
231                         e = t->log_message + t->log_message_size;
232                 }
233
234                 n = strndup(t->log_message, e - t->log_message);
235
236                 /* Skip over NUL and newlines */
237                 while (e < t->log_message + t->log_message_size && (*e == 0 || *e == '\n'))
238                         e++;
239
240                 memmove(t->log_message, e, t->log_message + sizeof(t->log_message) - e);
241                 t->log_message_size -= e - t->log_message;
242
243                 if (!n) {
244                         log_oom();
245                         continue;
246                 }
247
248                 if (isempty(n))
249                         continue;
250
251                 transfer_send_log_line(t, n);
252         }
253 }
254
255 static int transfer_finalize(Transfer *t, bool success) {
256         int r;
257
258         assert(t);
259
260         transfer_send_logs(t, true);
261
262         r = sd_bus_emit_signal(
263                         t->manager->bus,
264                         "/org/freedesktop/import1",
265                         "org.freedesktop.import1.Manager",
266                         "TransferRemoved",
267                         "uos",
268                         t->id,
269                         t->object_path,
270                         success ? "done" :
271                         t->n_canceled > 0 ? "canceled" : "failed");
272
273         if (r < 0)
274                 log_error_errno(r, "Cannot emit message: %m");
275
276         transfer_unref(t);
277         return 0;
278 }
279
280 static int transfer_cancel(Transfer *t) {
281         int r;
282
283         assert(t);
284
285         r = kill_and_sigcont(t->pid, t->n_canceled < 3 ? SIGTERM : SIGKILL);
286         if (r < 0)
287                 return r;
288
289         t->n_canceled++;
290         return 0;
291 }
292
293 static int transfer_on_pid(sd_event_source *s, const siginfo_t *si, void *userdata) {
294         Transfer *t = userdata;
295         bool success = false;
296
297         assert(s);
298         assert(t);
299
300         if (si->si_code == CLD_EXITED) {
301                 if (si->si_status != 0)
302                         log_error("Import process failed with exit code %i.", si->si_status);
303                 else {
304                         log_debug("Import process succeeded.");
305                         success = true;
306                 }
307
308         } else if (si->si_code == CLD_KILLED ||
309                    si->si_code == CLD_DUMPED)
310
311                 log_error("Import process terminated by signal %s.", signal_to_string(si->si_status));
312         else
313                 log_error("Import process failed due to unknown reason.");
314
315         t->pid = 0;
316
317         return transfer_finalize(t, success);
318 }
319
320 static int transfer_on_log(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
321         Transfer *t = userdata;
322         ssize_t l;
323
324         assert(s);
325         assert(t);
326
327         l = read(fd, t->log_message + t->log_message_size, sizeof(t->log_message) - t->log_message_size);
328         if (l <= 0) {
329                 /* EOF/read error. We just close the pipe here, and
330                  * close the watch, waiting for the SIGCHLD to arrive,
331                  * before we do anything else. */
332
333                 if (l < 0)
334                         log_error_errno(errno, "Failed to read log message: %m");
335
336                 t->log_event_source = sd_event_source_unref(t->log_event_source);
337                 return 0;
338         }
339
340         t->log_message_size += l;
341
342         transfer_send_logs(t, false);
343
344         return 0;
345 }
346
347 static int transfer_start(Transfer *t) {
348         _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
349         int r;
350
351         assert(t);
352         assert(t->pid <= 0);
353
354         if (pipe2(pipefd, O_CLOEXEC) < 0)
355                 return -errno;
356
357         t->pid = fork();
358         if (t->pid < 0)
359                 return -errno;
360         if (t->pid == 0) {
361                 const char *cmd[] = {
362                         "systemd-pull",
363                         transfer_type_to_string(t->type),
364                         "--verify",
365                         NULL, /* verify argument */
366                         NULL, /* maybe --force */
367                         NULL, /* maybe --dkr-index-url */
368                         NULL, /* the actual URL */
369                         NULL, /* remote */
370                         NULL, /* local */
371                         NULL
372                 };
373                 int null_fd;
374                 unsigned k = 3;
375
376                 /* Child */
377
378                 reset_all_signal_handlers();
379                 reset_signal_mask();
380                 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
381
382                 pipefd[0] = safe_close(pipefd[0]);
383
384                 if (dup2(pipefd[1], STDOUT_FILENO) != STDOUT_FILENO) {
385                         log_error_errno(errno, "Failed to dup2() fd: %m");
386                         _exit(EXIT_FAILURE);
387                 }
388
389                 if (dup2(pipefd[1], STDERR_FILENO) != STDERR_FILENO) {
390                         log_error_errno(errno, "Failed to dup2() fd: %m");
391                         _exit(EXIT_FAILURE);
392                 }
393
394                 if (pipefd[1] != STDOUT_FILENO && pipefd[1] != STDERR_FILENO)
395                         pipefd[1] = safe_close(pipefd[1]);
396
397                 null_fd = open("/dev/null", O_RDONLY|O_NOCTTY);
398                 if (null_fd < 0) {
399                         log_error_errno(errno, "Failed to open /dev/null: %m");
400                         _exit(EXIT_FAILURE);
401                 }
402
403                 if (dup2(null_fd, STDIN_FILENO) != STDIN_FILENO) {
404                         log_error_errno(errno, "Failed to dup2() fd: %m");
405                         _exit(EXIT_FAILURE);
406                 }
407
408                 if (null_fd != STDIN_FILENO)
409                         safe_close(null_fd);
410
411                 fd_cloexec(STDIN_FILENO, false);
412                 fd_cloexec(STDOUT_FILENO, false);
413                 fd_cloexec(STDERR_FILENO, false);
414
415                 setenv("SYSTEMD_LOG_TARGET", "console-prefixed", 1);
416                 setenv("NOTIFY_SOCKET", "/run/systemd/import/notify", 1);
417
418                 cmd[k++] = import_verify_to_string(t->verify);
419                 if (t->force_local)
420                         cmd[k++] = "--force";
421
422                 if (t->dkr_index_url) {
423                         cmd[k++] = "--dkr-index-url";
424                         cmd[k++] = t->dkr_index_url;
425                 }
426
427                 cmd[k++] = t->remote;
428                 if (t->local)
429                         cmd[k++] = t->local;
430                 cmd[k] = NULL;
431
432                 execv(SYSTEMD_PULL_PATH, (char * const *) cmd);
433                 log_error_errno(errno, "Failed to execute import tool: %m");
434                 _exit(EXIT_FAILURE);
435         }
436
437         pipefd[1] = safe_close(pipefd[1]);
438         t->log_fd = pipefd[0];
439         pipefd[0] = -1;
440
441         r = sd_event_add_child(t->manager->event, &t->pid_event_source, t->pid, WEXITED, transfer_on_pid, t);
442         if (r < 0)
443                 return r;
444
445         r = sd_event_add_io(t->manager->event, &t->log_event_source, t->log_fd, EPOLLIN, transfer_on_log, t);
446         if (r < 0)
447                 return r;
448
449         /* Make sure always process logging before SIGCHLD */
450         r = sd_event_source_set_priority(t->log_event_source, SD_EVENT_PRIORITY_NORMAL -5);
451         if (r < 0)
452                 return r;
453
454         r = sd_bus_emit_signal(
455                         t->manager->bus,
456                         "/org/freedesktop/import1",
457                         "org.freedesktop.import1.Manager",
458                         "TransferNew",
459                         "uo",
460                         t->id,
461                         t->object_path);
462         if (r < 0)
463                 return r;
464
465         return 0;
466 }
467
468 static Manager *manager_unref(Manager *m) {
469         Transfer *t;
470
471         if (!m)
472                 return NULL;
473
474         sd_event_source_unref(m->notify_event_source);
475         safe_close(m->notify_fd);
476
477         while ((t = hashmap_first(m->transfers)))
478                 transfer_unref(t);
479
480         hashmap_free(m->transfers);
481
482         bus_verify_polkit_async_registry_free(m->polkit_registry);
483
484         sd_bus_close(m->bus);
485         sd_bus_unref(m->bus);
486         sd_event_unref(m->event);
487
488         free(m);
489         return NULL;
490 }
491
492 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_unref);
493
494 static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
495
496         char buf[NOTIFY_BUFFER_MAX+1];
497         struct iovec iovec = {
498                 .iov_base = buf,
499                 .iov_len = sizeof(buf)-1,
500         };
501         union {
502                 struct cmsghdr cmsghdr;
503                 uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
504                             CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
505         } control = {};
506         struct msghdr msghdr = {
507                 .msg_iov = &iovec,
508                 .msg_iovlen = 1,
509                 .msg_control = &control,
510                 .msg_controllen = sizeof(control),
511         };
512         struct ucred *ucred = NULL;
513         Manager *m = userdata;
514         struct cmsghdr *cmsg;
515         unsigned percent;
516         char *p, *e;
517         Transfer *t;
518         Iterator i;
519         ssize_t n;
520         int r;
521
522         n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
523         if (n < 0) {
524                 if (errno == EAGAIN || errno == EINTR)
525                         return 0;
526
527                 return -errno;
528         }
529
530         cmsg_close_all(&msghdr);
531
532         for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
533                 if (cmsg->cmsg_level == SOL_SOCKET &&
534                            cmsg->cmsg_type == SCM_CREDENTIALS &&
535                            cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
536
537                         ucred = (struct ucred*) CMSG_DATA(cmsg);
538                 }
539         }
540
541         if (msghdr.msg_flags & MSG_TRUNC) {
542                 log_warning("Got overly long notification datagram, ignoring.");
543                 return 0;
544         }
545
546         if (!ucred || ucred->pid <= 0) {
547                 log_warning("Got notification datagram lacking credential information, ignoring.");
548                 return 0;
549         }
550
551         HASHMAP_FOREACH(t, m->transfers, i)
552                 if (ucred->pid == t->pid)
553                         break;
554
555         if (!t) {
556                 log_warning("Got notification datagram from unexpected peer, ignoring.");
557                 return 0;
558         }
559
560         buf[n] = 0;
561
562         p = startswith(buf, "X_IMPORT_PROGRESS=");
563         if (!p) {
564                 p = strstr(buf, "\nX_IMPORT_PROGRESS=");
565                 if (!p)
566                         return 0;
567
568                 p += 19;
569         }
570
571         e = strchrnul(p, '\n');
572         *e = 0;
573
574         r = safe_atou(p, &percent);
575         if (r < 0 || percent > 100) {
576                 log_warning("Got invalid percent value, ignoring.");
577                 return 0;
578         }
579
580         t->progress_percent = percent;
581
582         log_debug("Got percentage from client: %u%%", percent);
583         return 0;
584 }
585
586 static int manager_new(Manager **ret) {
587         _cleanup_(manager_unrefp) Manager *m = NULL;
588         static const union sockaddr_union sa = {
589                 .un.sun_family = AF_UNIX,
590                 .un.sun_path = "/run/systemd/import/notify",
591         };
592         static const int one = 1;
593         int r;
594
595         assert(ret);
596
597         m = new0(Manager, 1);
598         if (!m)
599                 return -ENOMEM;
600
601         r = sd_event_default(&m->event);
602         if (r < 0)
603                 return r;
604
605         sd_event_set_watchdog(m->event, true);
606
607         r = sd_bus_default_system(&m->bus);
608         if (r < 0)
609                 return r;
610
611         m->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
612         if (m->notify_fd < 0)
613                 return -errno;
614
615         (void) mkdir_parents_label(sa.un.sun_path, 0755);
616         (void) unlink(sa.un.sun_path);
617
618         if (bind(m->notify_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)) < 0)
619                 return -errno;
620
621         if (setsockopt(m->notify_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
622                 return -errno;
623
624         r = sd_event_add_io(m->event, &m->notify_event_source, m->notify_fd, EPOLLIN, manager_on_notify, m);
625         if (r < 0)
626                 return r;
627
628         *ret = m;
629         m = NULL;
630
631         return 0;
632 }
633
634 static Transfer *manager_find(Manager *m, TransferType type, const char *dkr_index_url, const char *remote) {
635         Transfer *t;
636         Iterator i;
637
638         assert(m);
639         assert(type >= 0);
640         assert(type < _TRANSFER_TYPE_MAX);
641
642         HASHMAP_FOREACH(t, m->transfers, i) {
643
644                 if (t->type == type &&
645                     streq_ptr(t->remote, remote) &&
646                     streq_ptr(t->dkr_index_url, dkr_index_url))
647                         return t;
648         }
649
650         return NULL;
651 }
652
653 static int check_btrfs(void) {
654         struct statfs sfs;
655
656         if (statfs("/var/lib/machines", &sfs) < 0) {
657                 if (errno != ENOENT)
658                         return -errno;
659
660                 if (statfs("/var/lib", &sfs) < 0)
661                         return -errno;
662         }
663
664         return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
665 }
666
667 static int setup_machine_raw(sd_bus_error *error) {
668         _cleanup_free_ char *tmp = NULL;
669         _cleanup_close_ int fd = -1;
670         struct statvfs ss;
671         pid_t pid = 0;
672         siginfo_t si;
673         int r;
674
675         /* We want to be able to make use of btrfs-specific file
676          * system features, in particular subvolumes, reflinks and
677          * quota. Hence, if we detect that /var/lib/machines.raw is
678          * not located on btrfs, let's create a loopback file, place a
679          * btrfs file system into it, and mount it to
680          * /var/lib/machines. */
681
682         fd = open("/var/lib/machines.raw", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
683         if (fd >= 0) {
684                 r = fd;
685                 fd = -1;
686                 return r;
687         }
688
689         if (errno != ENOENT)
690                 return sd_bus_error_set_errnof(error, errno, "Failed to open /var/lib/machines.raw: %m");
691
692         r = tempfn_xxxxxx("/var/lib/machines.raw", &tmp);
693         if (r < 0)
694                 return r;
695
696         (void) mkdir_p_label("/var/lib", 0755);
697         fd = open(tmp, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0600);
698         if (fd < 0)
699                 return sd_bus_error_set_errnof(error, errno, "Failed to create /var/lib/machines.raw: %m");
700
701         if (fstatvfs(fd, &ss) < 0) {
702                 r = sd_bus_error_set_errnof(error, errno, "Failed to determine free space on /var/lib/machines.raw: %m");
703                 goto fail;
704         }
705
706         if (ss.f_bsize * ss.f_bavail < VAR_LIB_MACHINES_FREE_MIN) {
707                 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Not enough free disk space to set up /var/lib/machines.");
708                 goto fail;
709         }
710
711         if (ftruncate(fd, VAR_LIB_MACHINES_SIZE_START) < 0) {
712                 r = sd_bus_error_set_errnof(error, errno, "Failed to enlarge /var/lib/machines.raw: %m");
713                 goto fail;
714         }
715
716         pid = fork();
717         if (pid < 0) {
718                 r = sd_bus_error_set_errnof(error, errno, "Failed to fork mkfs.btrfs: %m");
719                 goto fail;
720         }
721
722         if (pid == 0) {
723
724                 /* Child */
725
726                 reset_all_signal_handlers();
727                 reset_signal_mask();
728                 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
729
730                 fd = safe_close(fd);
731
732                 execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL);
733                 if (errno == ENOENT)
734                         return 99;
735
736                 _exit(EXIT_FAILURE);
737         }
738
739         r = wait_for_terminate(pid, &si);
740         if (r < 0) {
741                 sd_bus_error_set_errnof(error, r, "Failed to wait for mkfs.btrfs: %m");
742                 goto fail;
743         }
744
745         pid = 0;
746
747         if (si.si_code != CLD_EXITED) {
748                 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs died abnormally.");
749                 goto fail;
750         }
751         if (si.si_status == 99) {
752                 r = sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing");
753                 goto fail;
754         }
755         if (si.si_status != 0) {
756                 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs failed with error code %i", si.si_status);
757                 goto fail;
758         }
759
760         if (renameat2(AT_FDCWD, tmp, AT_FDCWD, "/var/lib/machines.raw", RENAME_NOREPLACE) < 0) {
761                 r = sd_bus_error_set_errnof(error, errno, "Failed to move /var/lib/machines.raw into place: %m");
762                 goto fail;
763         }
764
765         r = fd;
766         fd = -1;
767
768         return r;
769
770 fail:
771         if (tmp)
772                 unlink_noerrno(tmp);
773
774         if (pid > 1)
775                 kill_and_sigcont(pid, SIGKILL);
776
777         return r;
778 }
779
780 static int setup_machine_directory(sd_bus_error *error) {
781         struct loop_info64 info = {
782                 .lo_flags = LO_FLAGS_AUTOCLEAR,
783         };
784         _cleanup_close_ int fd = -1, control = -1, loop = -1;
785         _cleanup_free_ char* loopdev = NULL;
786         char tmpdir[] = "/tmp/import-mount.XXXXXX", *mntdir = NULL;
787         bool tmpdir_made = false, mntdir_made = false, mntdir_mounted = false;
788         int r, nr = -1;
789
790         r = check_btrfs();
791         if (r < 0)
792                 return sd_bus_error_set_errnof(error, r, "Failed to determine whether /var/lib/machines is located on btrfs: %m");
793         if (r > 0) {
794                 (void) btrfs_subvol_make_label("/var/lib/machines");
795
796                 r = btrfs_quota_enable("/var/lib/machines", true);
797                 if (r < 0)
798                         log_warning_errno(r, "Failed to enable quota, ignoring: %m");
799
800                 return 0;
801         }
802
803         if (path_is_mount_point("/var/lib/machines", true) > 0 ||
804             dir_is_empty("/var/lib/machines") == 0)
805                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "/var/lib/machines is not a btrfs file system. Operation is not supported on legacy file systems.");
806
807         fd = setup_machine_raw(error);
808         if (fd < 0)
809                 return fd;
810
811         control = open("/dev/loop-control", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
812         if (control < 0)
813                 return sd_bus_error_set_errnof(error, errno, "Failed to open /dev/loop-control: %m");
814
815         nr = ioctl(control, LOOP_CTL_GET_FREE);
816         if (nr < 0)
817                 return sd_bus_error_set_errnof(error, errno, "Failed to allocate loop device: %m");
818
819         if (asprintf(&loopdev, "/dev/loop%i", nr) < 0) {
820                 r = -ENOMEM;
821                 goto fail;
822         }
823
824         loop = open(loopdev, O_CLOEXEC|O_RDWR|O_NOCTTY|O_NONBLOCK);
825         if (loop < 0) {
826                 r = sd_bus_error_set_errnof(error, errno, "Failed to open loopback device: %m");
827                 goto fail;
828         }
829
830         if (ioctl(loop, LOOP_SET_FD, fd) < 0) {
831                 r = sd_bus_error_set_errnof(error, errno, "Failed to bind loopback device: %m");
832                 goto fail;
833         }
834
835         if (ioctl(loop, LOOP_SET_STATUS64, &info) < 0) {
836                 r = sd_bus_error_set_errnof(error, errno, "Failed to enable auto-clear for loopback device: %m");
837                 goto fail;
838         }
839
840         /* We need to make sure the new /var/lib/machines directory
841          * has an access mode of 0700 at the time it is first made
842          * available. mkfs will create it with 0755 however. Hence,
843          * let's mount the directory into an inaccessible directory
844          * below /tmp first, fix the access mode, and move it to the
845          * public place then. */
846
847         if (!mkdtemp(tmpdir)) {
848                 r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount parent directory: %m");
849                 goto fail;
850         }
851         tmpdir_made = true;
852
853         mntdir = strjoina(tmpdir, "/mnt");
854         if (mkdir(mntdir, 0700) < 0) {
855                 r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount directory: %m");
856                 goto fail;
857         }
858         mntdir_made = true;
859
860         if (mount(loopdev, mntdir, "btrfs", 0, NULL) < 0) {
861                 r = sd_bus_error_set_errnof(error, errno, "Failed to mount loopback device: %m");
862                 goto fail;
863         }
864         mntdir_mounted = true;
865
866         r = btrfs_quota_enable(mntdir, true);
867         if (r < 0)
868                 log_warning_errno(r, "Failed to enable quota, ignoring: %m");
869
870         if (chmod(mntdir, 0700) < 0) {
871                 r = sd_bus_error_set_errnof(error, errno, "Failed to fix owner: %m");
872                 goto fail;
873         }
874
875         (void) mkdir_p_label("/var/lib/machines", 0700);
876
877         if (mount(mntdir, "/var/lib/machines", NULL, MS_BIND, NULL) < 0) {
878                 r = sd_bus_error_set_errnof(error, errno, "Failed to mount directory into right place: %m");
879                 goto fail;
880         }
881
882         (void) umount2(mntdir, MNT_DETACH);
883         (void) rmdir(mntdir);
884         (void) rmdir(tmpdir);
885
886         return 0;
887
888 fail:
889         if (mntdir_mounted)
890                 (void) umount2(mntdir, MNT_DETACH);
891
892         if (mntdir_made)
893                 (void) rmdir(mntdir);
894         if (tmpdir_made)
895                 (void) rmdir(tmpdir);
896
897         if (loop >= 0) {
898                 (void) ioctl(loop, LOOP_CLR_FD);
899                 loop = safe_close(loop);
900         }
901
902         if (control >= 0 && nr >= 0)
903                 (void) ioctl(control, LOOP_CTL_REMOVE, nr);
904
905         return r;
906 }
907
908 static int method_pull_tar_or_raw(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bus_error *error) {
909         _cleanup_(transfer_unrefp) Transfer *t = NULL;
910         const char *remote, *local, *verify, *object;
911         Manager *m = userdata;
912         ImportVerify v;
913         TransferType type;
914         int force, r;
915         uint32_t id;
916
917         assert(bus);
918         assert(msg);
919         assert(m);
920
921         r = bus_verify_polkit_async(
922                         msg,
923                         CAP_SYS_ADMIN,
924                         "org.freedesktop.import1.pull",
925                         false,
926                         UID_INVALID,
927                         &m->polkit_registry,
928                         error);
929         if (r < 0)
930                 return r;
931         if (r == 0)
932                 return 1; /* Will call us back */
933
934         r = sd_bus_message_read(msg, "sssb", &remote, &local, &verify, &force);
935         if (r < 0)
936                 return r;
937
938         if (!http_url_is_valid(remote))
939                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "URL %s is invalid", remote);
940
941         if (isempty(local))
942                 local = NULL;
943         else if (!machine_name_is_valid(local))
944                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
945
946         if (isempty(verify))
947                 v = IMPORT_VERIFY_SIGNATURE;
948         else
949                 v = import_verify_from_string(verify);
950         if (v < 0)
951                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown verification mode %s", verify);
952
953         r = setup_machine_directory(error);
954         if (r < 0)
955                 return r;
956
957         type = streq_ptr(sd_bus_message_get_member(msg), "PullTar") ? TRANSFER_TAR : TRANSFER_RAW;
958
959         if (manager_find(m, type, NULL, remote))
960                 return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS, "Transfer for %s already in progress.", remote);
961
962         r = transfer_new(m, &t);
963         if (r < 0)
964                 return r;
965
966         t->type = type;
967         t->verify = v;
968         t->force_local = force;
969
970         t->remote = strdup(remote);
971         if (!t->remote)
972                 return -ENOMEM;
973
974         t->local = strdup(local);
975         if (!t->local)
976                 return -ENOMEM;
977
978         r = transfer_start(t);
979         if (r < 0)
980                 return r;
981
982         object = t->object_path;
983         id = t->id;
984         t = NULL;
985
986         return sd_bus_reply_method_return(msg, "uo", id, object);
987 }
988
989 static int method_pull_dkr(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bus_error *error) {
990         _cleanup_(transfer_unrefp) Transfer *t = NULL;
991         const char *index_url, *remote, *tag, *local, *verify, *object;
992         Manager *m = userdata;
993         ImportVerify v;
994         int force, r;
995         uint32_t id;
996
997         assert(bus);
998         assert(msg);
999         assert(m);
1000
1001         r = bus_verify_polkit_async(
1002                         msg,
1003                         CAP_SYS_ADMIN,
1004                         "org.freedesktop.import1.pull",
1005                         false,
1006                         UID_INVALID,
1007                         &m->polkit_registry,
1008                         error);
1009         if (r < 0)
1010                 return r;
1011         if (r == 0)
1012                 return 1; /* Will call us back */
1013
1014         r = sd_bus_message_read(msg, "sssssb", &index_url, &remote, &tag, &local, &verify, &force);
1015         if (r < 0)
1016                 return r;
1017
1018         if (isempty(index_url))
1019                 index_url = DEFAULT_DKR_INDEX_URL;
1020         if (!index_url)
1021                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Index URL must be specified.");
1022         if (!http_url_is_valid(index_url))
1023                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Index URL %s is invalid", index_url);
1024
1025         if (!dkr_name_is_valid(remote))
1026                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Remote name %s is not valid", remote);
1027
1028         if (isempty(tag))
1029                 tag = "latest";
1030         else if (!dkr_tag_is_valid(tag))
1031                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Tag %s is not valid", tag);
1032
1033         if (isempty(local))
1034                 local = NULL;
1035         else if (!machine_name_is_valid(local))
1036                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
1037
1038         if (isempty(verify))
1039                 v = IMPORT_VERIFY_SIGNATURE;
1040         else
1041                 v = import_verify_from_string(verify);
1042         if (v < 0)
1043                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown verification mode %s", verify);
1044
1045         if (v != IMPORT_VERIFY_NO)
1046                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "DKR does not support verification.");
1047
1048         r = setup_machine_directory(error);
1049         if (r < 0)
1050                 return r;
1051
1052         if (manager_find(m, TRANSFER_DKR, index_url, remote))
1053                 return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS, "Transfer for %s already in progress.", remote);
1054
1055         r = transfer_new(m, &t);
1056         if (r < 0)
1057                 return r;
1058
1059         t->type = TRANSFER_DKR;
1060         t->verify = v;
1061         t->force_local = force;
1062
1063         t->dkr_index_url = strdup(index_url);
1064         if (!t->dkr_index_url)
1065                 return -ENOMEM;
1066
1067         t->remote = strjoin(remote, ":", tag, NULL);
1068         if (!t->remote)
1069                 return -ENOMEM;
1070
1071         t->local = strdup(local);
1072         if (!t->local)
1073                 return -ENOMEM;
1074
1075         r = transfer_start(t);
1076         if (r < 0)
1077                 return r;
1078
1079         object = t->object_path;
1080         id = t->id;
1081         t = NULL;
1082
1083         return sd_bus_reply_method_return(msg, "uo", id, object);
1084 }
1085
1086 static int method_list_transfers(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bus_error *error) {
1087         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1088         Manager *m = userdata;
1089         Transfer *t;
1090         Iterator i;
1091         int r;
1092
1093         assert(bus);
1094         assert(msg);
1095         assert(m);
1096
1097         r = sd_bus_message_new_method_return(msg, &reply);
1098         if (r < 0)
1099                 return r;
1100
1101         r = sd_bus_message_open_container(reply, 'a', "(usssdo)");
1102         if (r < 0)
1103                 return r;
1104
1105         HASHMAP_FOREACH(t, m->transfers, i) {
1106
1107                 r = sd_bus_message_append(
1108                                 reply,
1109                                 "(usssdo)",
1110                                 t->id,
1111                                 transfer_type_to_string(t->type),
1112                                 t->remote,
1113                                 t->local,
1114                                 (double) t->progress_percent / 100.0,
1115                                 t->object_path);
1116                 if (r < 0)
1117                         return r;
1118         }
1119
1120         r = sd_bus_message_close_container(reply);
1121         if (r < 0)
1122                 return r;
1123
1124         return sd_bus_send(bus, reply, NULL);
1125 }
1126
1127 static int method_cancel(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bus_error *error) {
1128         Transfer *t = userdata;
1129         int r;
1130
1131         assert(bus);
1132         assert(msg);
1133         assert(t);
1134
1135         r = bus_verify_polkit_async(
1136                         msg,
1137                         CAP_SYS_ADMIN,
1138                         "org.freedesktop.import1.pull",
1139                         false,
1140                         UID_INVALID,
1141                         &t->manager->polkit_registry,
1142                         error);
1143         if (r < 0)
1144                 return r;
1145         if (r == 0)
1146                 return 1; /* Will call us back */
1147
1148         r = transfer_cancel(t);
1149         if (r < 0)
1150                 return r;
1151
1152         return sd_bus_reply_method_return(msg, NULL);
1153 }
1154
1155 static int method_cancel_transfer(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bus_error *error) {
1156         Manager *m = userdata;
1157         Transfer *t;
1158         uint32_t id;
1159         int r;
1160
1161         assert(bus);
1162         assert(msg);
1163         assert(m);
1164
1165         r = bus_verify_polkit_async(
1166                         msg,
1167                         CAP_SYS_ADMIN,
1168                         "org.freedesktop.import1.pull",
1169                         false,
1170                         UID_INVALID,
1171                         &m->polkit_registry,
1172                         error);
1173         if (r < 0)
1174                 return r;
1175         if (r == 0)
1176                 return 1; /* Will call us back */
1177
1178         r = sd_bus_message_read(msg, "u", &id);
1179         if (r < 0)
1180                 return r;
1181         if (id <= 0)
1182                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid transfer id");
1183
1184         t = hashmap_get(m->transfers, UINT32_TO_PTR(id));
1185         if (!t)
1186                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_TRANSFER, "No transfer by id %" PRIu32, id);
1187
1188         r = transfer_cancel(t);
1189         if (r < 0)
1190                 return r;
1191
1192         return sd_bus_reply_method_return(msg, NULL);
1193 }
1194
1195 static int property_get_progress(
1196                 sd_bus *bus,
1197                 const char *path,
1198                 const char *interface,
1199                 const char *property,
1200                 sd_bus_message *reply,
1201                 void *userdata,
1202                 sd_bus_error *error) {
1203
1204         Transfer *t = userdata;
1205
1206         assert(bus);
1207         assert(reply);
1208         assert(t);
1209
1210         return sd_bus_message_append(reply, "d", (double) t->progress_percent / 100.0);
1211 }
1212
1213 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, transfer_type, TransferType);
1214 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_verify, import_verify, ImportVerify);
1215
1216 static const sd_bus_vtable transfer_vtable[] = {
1217         SD_BUS_VTABLE_START(0),
1218         SD_BUS_PROPERTY("Id", "u", NULL, offsetof(Transfer, id), SD_BUS_VTABLE_PROPERTY_CONST),
1219         SD_BUS_PROPERTY("Local", "s", NULL, offsetof(Transfer, local), SD_BUS_VTABLE_PROPERTY_CONST),
1220         SD_BUS_PROPERTY("Remote", "s", NULL, offsetof(Transfer, remote), SD_BUS_VTABLE_PROPERTY_CONST),
1221         SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Transfer, type), SD_BUS_VTABLE_PROPERTY_CONST),
1222         SD_BUS_PROPERTY("Verify", "s", property_get_verify, offsetof(Transfer, verify), SD_BUS_VTABLE_PROPERTY_CONST),
1223         SD_BUS_PROPERTY("Progress", "d", property_get_progress, 0, 0),
1224         SD_BUS_METHOD("Cancel", NULL, NULL, method_cancel, SD_BUS_VTABLE_UNPRIVILEGED),
1225         SD_BUS_SIGNAL("LogMessage", "us", 0),
1226         SD_BUS_VTABLE_END,
1227 };
1228
1229 static const sd_bus_vtable manager_vtable[] = {
1230         SD_BUS_VTABLE_START(0),
1231         SD_BUS_METHOD("PullTar", "sssb", "uo", method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
1232         SD_BUS_METHOD("PullRaw", "sssb", "uo", method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
1233         SD_BUS_METHOD("PullDkr", "sssssb", "uo", method_pull_dkr, SD_BUS_VTABLE_UNPRIVILEGED),
1234         SD_BUS_METHOD("ListTransfers", NULL, "a(usssdo)", method_list_transfers, SD_BUS_VTABLE_UNPRIVILEGED),
1235         SD_BUS_METHOD("CancelTransfer", "u", NULL, method_cancel_transfer, SD_BUS_VTABLE_UNPRIVILEGED),
1236         SD_BUS_SIGNAL("TransferNew", "uo", 0),
1237         SD_BUS_SIGNAL("TransferRemoved", "uos", 0),
1238         SD_BUS_VTABLE_END,
1239 };
1240
1241 static int transfer_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
1242         Manager *m = userdata;
1243         Transfer *t;
1244         const char *p;
1245         uint32_t id;
1246         int r;
1247
1248         assert(bus);
1249         assert(path);
1250         assert(interface);
1251         assert(found);
1252         assert(m);
1253
1254         p = startswith(path, "/org/freedesktop/import1/transfer/_");
1255         if (!p)
1256                 return 0;
1257
1258         r = safe_atou32(p, &id);
1259         if (r < 0 || id == 0)
1260                 return 0;
1261
1262         t = hashmap_get(m->transfers, UINT32_TO_PTR(id));
1263         if (!t)
1264                 return 0;
1265
1266         *found = t;
1267         return 1;
1268 }
1269
1270 static int transfer_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
1271         _cleanup_strv_free_ char **l = NULL;
1272         Manager *m = userdata;
1273         Transfer *t;
1274         unsigned k = 0;
1275         Iterator i;
1276
1277         l = new0(char*, hashmap_size(m->transfers) + 1);
1278         if (!l)
1279                 return -ENOMEM;
1280
1281         HASHMAP_FOREACH(t, m->transfers, i) {
1282
1283                 l[k] = strdup(t->object_path);
1284                 if (!l[k])
1285                         return -ENOMEM;
1286
1287                 k++;
1288         }
1289
1290         *nodes = l;
1291         l = NULL;
1292
1293         return 1;
1294 }
1295
1296 static int manager_add_bus_objects(Manager *m) {
1297         int r;
1298
1299         assert(m);
1300
1301         r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/import1", "org.freedesktop.import1.Manager", manager_vtable, m);
1302         if (r < 0)
1303                 return log_error_errno(r, "Failed to register object: %m");
1304
1305         r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/import1/transfer", "org.freedesktop.import1.Transfer", transfer_vtable, transfer_object_find, m);
1306         if (r < 0)
1307                 return log_error_errno(r, "Failed to register object: %m");
1308
1309         r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/import1/transfer", transfer_node_enumerator, m);
1310         if (r < 0)
1311                 return log_error_errno(r, "Failed to add transfer enumerator: %m");
1312
1313         r = sd_bus_request_name(m->bus, "org.freedesktop.import1", 0);
1314         if (r < 0)
1315                 return log_error_errno(r, "Failed to register name: %m");
1316
1317         r = sd_bus_attach_event(m->bus, m->event, 0);
1318         if (r < 0)
1319                 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1320
1321         return 0;
1322 }
1323
1324 static bool manager_check_idle(void *userdata) {
1325         Manager *m = userdata;
1326
1327         return hashmap_isempty(m->transfers);
1328 }
1329
1330 static int manager_run(Manager *m) {
1331         assert(m);
1332
1333         return bus_event_loop_with_idle(
1334                         m->event,
1335                         m->bus,
1336                         "org.freedesktop.import1",
1337                         DEFAULT_EXIT_USEC,
1338                         manager_check_idle,
1339                         m);
1340 }
1341
1342 int main(int argc, char *argv[]) {
1343         _cleanup_(manager_unrefp) Manager *m = NULL;
1344         int r;
1345
1346         log_set_target(LOG_TARGET_AUTO);
1347         log_parse_environment();
1348         log_open();
1349
1350         umask(0022);
1351
1352         if (argc != 1) {
1353                 log_error("This program takes no arguments.");
1354                 r = -EINVAL;
1355                 goto finish;
1356         }
1357
1358         assert_se(sigprocmask_many(SIG_BLOCK, SIGCHLD, -1) >= 0);
1359
1360         r = manager_new(&m);
1361         if (r < 0) {
1362                 log_error_errno(r, "Failed to allocate manager object: %m");
1363                 goto finish;
1364         }
1365
1366         r = manager_add_bus_objects(m);
1367         if (r < 0)
1368                 goto finish;
1369
1370         r = manager_run(m);
1371         if (r < 0) {
1372                 log_error_errno(r, "Failed to run event loop: %m");
1373                 goto finish;
1374         }
1375
1376 finish:
1377         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1378 }