Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <curl/curl.h>
4 : #include <linux/fs.h>
5 : #include <sys/xattr.h>
6 :
7 : #include "sd-daemon.h"
8 :
9 : #include "alloc-util.h"
10 : #include "btrfs-util.h"
11 : #include "chattr-util.h"
12 : #include "copy.h"
13 : #include "curl-util.h"
14 : #include "fd-util.h"
15 : #include "fs-util.h"
16 : #include "hostname-util.h"
17 : #include "import-common.h"
18 : #include "import-util.h"
19 : #include "macro.h"
20 : #include "mkdir.h"
21 : #include "path-util.h"
22 : #include "pull-common.h"
23 : #include "pull-job.h"
24 : #include "pull-raw.h"
25 : #include "qcow2-util.h"
26 : #include "rm-rf.h"
27 : #include "string-util.h"
28 : #include "strv.h"
29 : #include "tmpfile-util.h"
30 : #include "utf8.h"
31 : #include "util.h"
32 : #include "web-util.h"
33 :
34 : typedef enum RawProgress {
35 : RAW_DOWNLOADING,
36 : RAW_VERIFYING,
37 : RAW_UNPACKING,
38 : RAW_FINALIZING,
39 : RAW_COPYING,
40 : } RawProgress;
41 :
42 : struct RawPull {
43 : sd_event *event;
44 : CurlGlue *glue;
45 :
46 : char *image_root;
47 :
48 : PullJob *raw_job;
49 : PullJob *roothash_job;
50 : PullJob *settings_job;
51 : PullJob *checksum_job;
52 : PullJob *signature_job;
53 :
54 : RawPullFinished on_finished;
55 : void *userdata;
56 :
57 : char *local;
58 : bool force_local;
59 : bool settings;
60 : bool roothash;
61 :
62 : char *final_path;
63 : char *temp_path;
64 :
65 : char *settings_path;
66 : char *settings_temp_path;
67 :
68 : char *roothash_path;
69 : char *roothash_temp_path;
70 :
71 : ImportVerify verify;
72 : };
73 :
74 0 : RawPull* raw_pull_unref(RawPull *i) {
75 0 : if (!i)
76 0 : return NULL;
77 :
78 0 : pull_job_unref(i->raw_job);
79 0 : pull_job_unref(i->settings_job);
80 0 : pull_job_unref(i->roothash_job);
81 0 : pull_job_unref(i->checksum_job);
82 0 : pull_job_unref(i->signature_job);
83 :
84 0 : curl_glue_unref(i->glue);
85 0 : sd_event_unref(i->event);
86 :
87 0 : if (i->temp_path) {
88 0 : (void) unlink(i->temp_path);
89 0 : free(i->temp_path);
90 : }
91 :
92 0 : if (i->roothash_temp_path) {
93 0 : (void) unlink(i->roothash_temp_path);
94 0 : free(i->roothash_temp_path);
95 : }
96 :
97 0 : if (i->settings_temp_path) {
98 0 : (void) unlink(i->settings_temp_path);
99 0 : free(i->settings_temp_path);
100 : }
101 :
102 0 : free(i->final_path);
103 0 : free(i->roothash_path);
104 0 : free(i->settings_path);
105 0 : free(i->image_root);
106 0 : free(i->local);
107 0 : return mfree(i);
108 : }
109 :
110 0 : int raw_pull_new(
111 : RawPull **ret,
112 : sd_event *event,
113 : const char *image_root,
114 : RawPullFinished on_finished,
115 : void *userdata) {
116 :
117 0 : _cleanup_(curl_glue_unrefp) CurlGlue *g = NULL;
118 0 : _cleanup_(sd_event_unrefp) sd_event *e = NULL;
119 0 : _cleanup_(raw_pull_unrefp) RawPull *i = NULL;
120 0 : _cleanup_free_ char *root = NULL;
121 : int r;
122 :
123 0 : assert(ret);
124 :
125 0 : root = strdup(image_root ?: "/var/lib/machines");
126 0 : if (!root)
127 0 : return -ENOMEM;
128 :
129 0 : if (event)
130 0 : e = sd_event_ref(event);
131 : else {
132 0 : r = sd_event_default(&e);
133 0 : if (r < 0)
134 0 : return r;
135 : }
136 :
137 0 : r = curl_glue_new(&g, e);
138 0 : if (r < 0)
139 0 : return r;
140 :
141 0 : i = new(RawPull, 1);
142 0 : if (!i)
143 0 : return -ENOMEM;
144 :
145 0 : *i = (RawPull) {
146 : .on_finished = on_finished,
147 : .userdata = userdata,
148 0 : .image_root = TAKE_PTR(root),
149 0 : .event = TAKE_PTR(e),
150 0 : .glue = TAKE_PTR(g),
151 : };
152 :
153 0 : i->glue->on_finished = pull_job_curl_on_finished;
154 0 : i->glue->userdata = i;
155 :
156 0 : *ret = TAKE_PTR(i);
157 :
158 0 : return 0;
159 : }
160 :
161 0 : static void raw_pull_report_progress(RawPull *i, RawProgress p) {
162 : unsigned percent;
163 :
164 0 : assert(i);
165 :
166 0 : switch (p) {
167 :
168 0 : case RAW_DOWNLOADING: {
169 0 : unsigned remain = 80;
170 :
171 0 : percent = 0;
172 :
173 0 : if (i->settings_job) {
174 0 : percent += i->settings_job->progress_percent * 5 / 100;
175 0 : remain -= 5;
176 : }
177 :
178 0 : if (i->roothash_job) {
179 0 : percent += i->roothash_job->progress_percent * 5 / 100;
180 0 : remain -= 5;
181 : }
182 :
183 0 : if (i->checksum_job) {
184 0 : percent += i->checksum_job->progress_percent * 5 / 100;
185 0 : remain -= 5;
186 : }
187 :
188 0 : if (i->signature_job) {
189 0 : percent += i->signature_job->progress_percent * 5 / 100;
190 0 : remain -= 5;
191 : }
192 :
193 0 : if (i->raw_job)
194 0 : percent += i->raw_job->progress_percent * remain / 100;
195 0 : break;
196 : }
197 :
198 0 : case RAW_VERIFYING:
199 0 : percent = 80;
200 0 : break;
201 :
202 0 : case RAW_UNPACKING:
203 0 : percent = 85;
204 0 : break;
205 :
206 0 : case RAW_FINALIZING:
207 0 : percent = 90;
208 0 : break;
209 :
210 0 : case RAW_COPYING:
211 0 : percent = 95;
212 0 : break;
213 :
214 0 : default:
215 0 : assert_not_reached("Unknown progress state");
216 : }
217 :
218 0 : sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent);
219 0 : log_debug("Combined progress %u%%", percent);
220 0 : }
221 :
222 0 : static int raw_pull_maybe_convert_qcow2(RawPull *i) {
223 0 : _cleanup_close_ int converted_fd = -1;
224 0 : _cleanup_free_ char *t = NULL;
225 : int r;
226 :
227 0 : assert(i);
228 0 : assert(i->raw_job);
229 :
230 0 : r = qcow2_detect(i->raw_job->disk_fd);
231 0 : if (r < 0)
232 0 : return log_error_errno(r, "Failed to detect whether this is a QCOW2 image: %m");
233 0 : if (r == 0)
234 0 : return 0;
235 :
236 : /* This is a QCOW2 image, let's convert it */
237 0 : r = tempfn_random(i->final_path, NULL, &t);
238 0 : if (r < 0)
239 0 : return log_oom();
240 :
241 0 : converted_fd = open(t, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
242 0 : if (converted_fd < 0)
243 0 : return log_error_errno(errno, "Failed to create %s: %m", t);
244 :
245 0 : r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
246 0 : if (r < 0)
247 0 : log_warning_errno(r, "Failed to set file attributes on %s: %m", t);
248 :
249 0 : log_info("Unpacking QCOW2 file.");
250 :
251 0 : r = qcow2_convert(i->raw_job->disk_fd, converted_fd);
252 0 : if (r < 0) {
253 0 : (void) unlink(t);
254 0 : return log_error_errno(r, "Failed to convert qcow2 image: %m");
255 : }
256 :
257 0 : (void) unlink(i->temp_path);
258 0 : free_and_replace(i->temp_path, t);
259 :
260 0 : safe_close(i->raw_job->disk_fd);
261 0 : i->raw_job->disk_fd = TAKE_FD(converted_fd);
262 :
263 0 : return 1;
264 : }
265 :
266 0 : static int raw_pull_determine_path(RawPull *i, const char *suffix, char **field) {
267 : int r;
268 :
269 0 : assert(i);
270 0 : assert(field);
271 :
272 0 : if (*field)
273 0 : return 0;
274 :
275 0 : assert(i->raw_job);
276 :
277 0 : r = pull_make_path(i->raw_job->url, i->raw_job->etag, i->image_root, ".raw-", suffix, field);
278 0 : if (r < 0)
279 0 : return log_oom();
280 :
281 0 : return 1;
282 : }
283 :
284 0 : static int raw_pull_copy_auxiliary_file(
285 : RawPull *i,
286 : const char *suffix,
287 : char **path) {
288 :
289 : const char *local;
290 : int r;
291 :
292 0 : assert(i);
293 0 : assert(suffix);
294 0 : assert(path);
295 :
296 0 : r = raw_pull_determine_path(i, suffix, path);
297 0 : if (r < 0)
298 0 : return r;
299 :
300 0 : local = strjoina(i->image_root, "/", i->local, suffix);
301 :
302 0 : r = copy_file_atomic(*path, local, 0644, 0, 0, COPY_REFLINK | (i->force_local ? COPY_REPLACE : 0));
303 0 : if (r == -EEXIST)
304 0 : log_warning_errno(r, "File %s already exists, not replacing.", local);
305 0 : else if (r == -ENOENT)
306 0 : log_debug_errno(r, "Skipping creation of auxiliary file, since none was found.");
307 0 : else if (r < 0)
308 0 : log_warning_errno(r, "Failed to copy file %s, ignoring: %m", local);
309 : else
310 0 : log_info("Created new file %s.", local);
311 :
312 0 : return 0;
313 : }
314 :
315 0 : static int raw_pull_make_local_copy(RawPull *i) {
316 0 : _cleanup_free_ char *tp = NULL;
317 0 : _cleanup_close_ int dfd = -1;
318 : const char *p;
319 : int r;
320 :
321 0 : assert(i);
322 0 : assert(i->raw_job);
323 :
324 0 : if (!i->local)
325 0 : return 0;
326 :
327 0 : if (i->raw_job->etag_exists) {
328 : /* We have downloaded this one previously, reopen it */
329 :
330 0 : assert(i->raw_job->disk_fd < 0);
331 :
332 0 : i->raw_job->disk_fd = open(i->final_path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
333 0 : if (i->raw_job->disk_fd < 0)
334 0 : return log_error_errno(errno, "Failed to open vendor image: %m");
335 : } else {
336 : /* We freshly downloaded the image, use it */
337 :
338 0 : assert(i->raw_job->disk_fd >= 0);
339 :
340 0 : if (lseek(i->raw_job->disk_fd, SEEK_SET, 0) == (off_t) -1)
341 0 : return log_error_errno(errno, "Failed to seek to beginning of vendor image: %m");
342 : }
343 :
344 0 : p = strjoina(i->image_root, "/", i->local, ".raw");
345 :
346 0 : if (i->force_local)
347 0 : (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
348 :
349 0 : r = tempfn_random(p, NULL, &tp);
350 0 : if (r < 0)
351 0 : return log_oom();
352 :
353 0 : dfd = open(tp, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
354 0 : if (dfd < 0)
355 0 : return log_error_errno(errno, "Failed to create writable copy of image: %m");
356 :
357 : /* Turn off COW writing. This should greatly improve
358 : * performance on COW file systems like btrfs, since it
359 : * reduces fragmentation caused by not allowing in-place
360 : * writes. */
361 0 : r = chattr_fd(dfd, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
362 0 : if (r < 0)
363 0 : log_warning_errno(r, "Failed to set file attributes on %s: %m", tp);
364 :
365 0 : r = copy_bytes(i->raw_job->disk_fd, dfd, (uint64_t) -1, COPY_REFLINK);
366 0 : if (r < 0) {
367 0 : (void) unlink(tp);
368 0 : return log_error_errno(r, "Failed to make writable copy of image: %m");
369 : }
370 :
371 0 : (void) copy_times(i->raw_job->disk_fd, dfd, COPY_CRTIME);
372 0 : (void) copy_xattr(i->raw_job->disk_fd, dfd);
373 :
374 0 : dfd = safe_close(dfd);
375 :
376 0 : r = rename(tp, p);
377 0 : if (r < 0) {
378 0 : r = log_error_errno(errno, "Failed to move writable image into place: %m");
379 0 : (void) unlink(tp);
380 0 : return r;
381 : }
382 :
383 0 : log_info("Created new local image '%s'.", i->local);
384 :
385 0 : if (i->roothash) {
386 0 : r = raw_pull_copy_auxiliary_file(i, ".roothash", &i->roothash_path);
387 0 : if (r < 0)
388 0 : return r;
389 : }
390 :
391 0 : if (i->settings) {
392 0 : r = raw_pull_copy_auxiliary_file(i, ".nspawn", &i->settings_path);
393 0 : if (r < 0)
394 0 : return r;
395 : }
396 :
397 0 : return 0;
398 : }
399 :
400 0 : static bool raw_pull_is_done(RawPull *i) {
401 0 : assert(i);
402 0 : assert(i->raw_job);
403 :
404 0 : if (!PULL_JOB_IS_COMPLETE(i->raw_job))
405 0 : return false;
406 0 : if (i->roothash_job && !PULL_JOB_IS_COMPLETE(i->roothash_job))
407 0 : return false;
408 0 : if (i->settings_job && !PULL_JOB_IS_COMPLETE(i->settings_job))
409 0 : return false;
410 0 : if (i->checksum_job && !PULL_JOB_IS_COMPLETE(i->checksum_job))
411 0 : return false;
412 0 : if (i->signature_job && !PULL_JOB_IS_COMPLETE(i->signature_job))
413 0 : return false;
414 :
415 0 : return true;
416 : }
417 :
418 0 : static int raw_pull_rename_auxiliary_file(
419 : RawPull *i,
420 : const char *suffix,
421 : char **temp_path,
422 : char **path) {
423 :
424 : int r;
425 :
426 0 : assert(i);
427 0 : assert(temp_path);
428 0 : assert(suffix);
429 0 : assert(path);
430 :
431 : /* Regenerate final name for this auxiliary file, we might know the etag of the file now, and we should
432 : * incorporate it in the file name if we can */
433 0 : *path = mfree(*path);
434 0 : r = raw_pull_determine_path(i, suffix, path);
435 0 : if (r < 0)
436 0 : return r;
437 :
438 0 : r = import_make_read_only(*temp_path);
439 0 : if (r < 0)
440 0 : return r;
441 :
442 0 : r = rename_noreplace(AT_FDCWD, *temp_path, AT_FDCWD, *path);
443 0 : if (r < 0)
444 0 : return log_error_errno(r, "Failed to rename file %s to %s: %m", *temp_path, *path);
445 :
446 0 : *temp_path = mfree(*temp_path);
447 :
448 0 : return 1;
449 : }
450 :
451 0 : static void raw_pull_job_on_finished(PullJob *j) {
452 : RawPull *i;
453 : int r;
454 :
455 0 : assert(j);
456 0 : assert(j->userdata);
457 :
458 0 : i = j->userdata;
459 0 : if (j == i->roothash_job) {
460 0 : if (j->error != 0)
461 0 : log_info_errno(j->error, "Root hash file could not be retrieved, proceeding without.");
462 0 : } else if (j == i->settings_job) {
463 0 : if (j->error != 0)
464 0 : log_info_errno(j->error, "Settings file could not be retrieved, proceeding without.");
465 0 : } else if (j->error != 0 && j != i->signature_job) {
466 0 : if (j == i->checksum_job)
467 0 : log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)");
468 : else
469 0 : log_error_errno(j->error, "Failed to retrieve image file. (Wrong URL?)");
470 :
471 0 : r = j->error;
472 0 : goto finish;
473 : }
474 :
475 : /* This is invoked if either the download completed
476 : * successfully, or the download was skipped because we
477 : * already have the etag. In this case ->etag_exists is
478 : * true.
479 : *
480 : * We only do something when we got all three files */
481 :
482 0 : if (!raw_pull_is_done(i))
483 0 : return;
484 :
485 0 : if (i->signature_job && i->checksum_job->style == VERIFICATION_PER_DIRECTORY && i->signature_job->error != 0) {
486 0 : log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
487 :
488 0 : r = i->signature_job->error;
489 0 : goto finish;
490 : }
491 :
492 0 : if (i->roothash_job)
493 0 : i->roothash_job->disk_fd = safe_close(i->roothash_job->disk_fd);
494 0 : if (i->settings_job)
495 0 : i->settings_job->disk_fd = safe_close(i->settings_job->disk_fd);
496 :
497 0 : r = raw_pull_determine_path(i, ".raw", &i->final_path);
498 0 : if (r < 0)
499 0 : goto finish;
500 :
501 0 : if (!i->raw_job->etag_exists) {
502 : /* This is a new download, verify it, and move it into place */
503 0 : assert(i->raw_job->disk_fd >= 0);
504 :
505 0 : raw_pull_report_progress(i, RAW_VERIFYING);
506 :
507 0 : r = pull_verify(i->raw_job, i->roothash_job, i->settings_job, i->checksum_job, i->signature_job);
508 0 : if (r < 0)
509 0 : goto finish;
510 :
511 0 : raw_pull_report_progress(i, RAW_UNPACKING);
512 :
513 0 : r = raw_pull_maybe_convert_qcow2(i);
514 0 : if (r < 0)
515 0 : goto finish;
516 :
517 0 : raw_pull_report_progress(i, RAW_FINALIZING);
518 :
519 0 : r = import_make_read_only_fd(i->raw_job->disk_fd);
520 0 : if (r < 0)
521 0 : goto finish;
522 :
523 0 : r = rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path);
524 0 : if (r < 0) {
525 0 : log_error_errno(r, "Failed to rename raw file to %s: %m", i->final_path);
526 0 : goto finish;
527 : }
528 :
529 0 : i->temp_path = mfree(i->temp_path);
530 :
531 0 : if (i->roothash_job &&
532 0 : i->roothash_job->error == 0) {
533 0 : r = raw_pull_rename_auxiliary_file(i, ".roothash", &i->roothash_temp_path, &i->roothash_path);
534 0 : if (r < 0)
535 0 : goto finish;
536 : }
537 :
538 0 : if (i->settings_job &&
539 0 : i->settings_job->error == 0) {
540 0 : r = raw_pull_rename_auxiliary_file(i, ".nspawn", &i->settings_temp_path, &i->settings_path);
541 0 : if (r < 0)
542 0 : goto finish;
543 : }
544 : }
545 :
546 0 : raw_pull_report_progress(i, RAW_COPYING);
547 :
548 0 : r = raw_pull_make_local_copy(i);
549 0 : if (r < 0)
550 0 : goto finish;
551 :
552 0 : r = 0;
553 :
554 0 : finish:
555 0 : if (i->on_finished)
556 0 : i->on_finished(i, r, i->userdata);
557 : else
558 0 : sd_event_exit(i->event, r);
559 : }
560 :
561 0 : static int raw_pull_job_on_open_disk_generic(
562 : RawPull *i,
563 : PullJob *j,
564 : const char *extra,
565 : char **temp_path) {
566 :
567 : int r;
568 :
569 0 : assert(i);
570 0 : assert(j);
571 0 : assert(extra);
572 0 : assert(temp_path);
573 :
574 0 : if (!*temp_path) {
575 0 : r = tempfn_random_child(i->image_root, extra, temp_path);
576 0 : if (r < 0)
577 0 : return log_oom();
578 : }
579 :
580 0 : (void) mkdir_parents_label(*temp_path, 0700);
581 :
582 0 : j->disk_fd = open(*temp_path, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
583 0 : if (j->disk_fd < 0)
584 0 : return log_error_errno(errno, "Failed to create %s: %m", *temp_path);
585 :
586 0 : return 0;
587 : }
588 :
589 0 : static int raw_pull_job_on_open_disk_raw(PullJob *j) {
590 : RawPull *i;
591 : int r;
592 :
593 0 : assert(j);
594 0 : assert(j->userdata);
595 :
596 0 : i = j->userdata;
597 0 : assert(i->raw_job == j);
598 :
599 0 : r = raw_pull_job_on_open_disk_generic(i, j, "raw", &i->temp_path);
600 0 : if (r < 0)
601 0 : return r;
602 :
603 0 : r = chattr_fd(j->disk_fd, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
604 0 : if (r < 0)
605 0 : log_warning_errno(r, "Failed to set file attributes on %s, ignoring: %m", i->temp_path);
606 :
607 0 : return 0;
608 : }
609 :
610 0 : static int raw_pull_job_on_open_disk_roothash(PullJob *j) {
611 : RawPull *i;
612 :
613 0 : assert(j);
614 0 : assert(j->userdata);
615 :
616 0 : i = j->userdata;
617 0 : assert(i->roothash_job == j);
618 :
619 0 : return raw_pull_job_on_open_disk_generic(i, j, "roothash", &i->roothash_temp_path);
620 : }
621 :
622 0 : static int raw_pull_job_on_open_disk_settings(PullJob *j) {
623 : RawPull *i;
624 :
625 0 : assert(j);
626 0 : assert(j->userdata);
627 :
628 0 : i = j->userdata;
629 0 : assert(i->settings_job == j);
630 :
631 0 : return raw_pull_job_on_open_disk_generic(i, j, "settings", &i->settings_temp_path);
632 : }
633 :
634 0 : static void raw_pull_job_on_progress(PullJob *j) {
635 : RawPull *i;
636 :
637 0 : assert(j);
638 0 : assert(j->userdata);
639 :
640 0 : i = j->userdata;
641 :
642 0 : raw_pull_report_progress(i, RAW_DOWNLOADING);
643 0 : }
644 :
645 0 : int raw_pull_start(
646 : RawPull *i,
647 : const char *url,
648 : const char *local,
649 : bool force_local,
650 : ImportVerify verify,
651 : bool settings,
652 : bool roothash) {
653 :
654 : int r;
655 :
656 0 : assert(i);
657 0 : assert(verify < _IMPORT_VERIFY_MAX);
658 0 : assert(verify >= 0);
659 :
660 0 : if (!http_url_is_valid(url))
661 0 : return -EINVAL;
662 :
663 0 : if (local && !machine_name_is_valid(local))
664 0 : return -EINVAL;
665 :
666 0 : if (i->raw_job)
667 0 : return -EBUSY;
668 :
669 0 : r = free_and_strdup(&i->local, local);
670 0 : if (r < 0)
671 0 : return r;
672 :
673 0 : i->force_local = force_local;
674 0 : i->verify = verify;
675 0 : i->settings = settings;
676 0 : i->roothash = roothash;
677 :
678 : /* Queue job for the image itself */
679 0 : r = pull_job_new(&i->raw_job, url, i->glue, i);
680 0 : if (r < 0)
681 0 : return r;
682 :
683 0 : i->raw_job->on_finished = raw_pull_job_on_finished;
684 0 : i->raw_job->on_open_disk = raw_pull_job_on_open_disk_raw;
685 0 : i->raw_job->on_progress = raw_pull_job_on_progress;
686 0 : i->raw_job->calc_checksum = verify != IMPORT_VERIFY_NO;
687 :
688 0 : r = pull_find_old_etags(url, i->image_root, DT_REG, ".raw-", ".raw", &i->raw_job->old_etags);
689 0 : if (r < 0)
690 0 : return r;
691 :
692 0 : if (roothash) {
693 0 : r = pull_make_auxiliary_job(&i->roothash_job, url, raw_strip_suffixes, ".roothash", i->glue, raw_pull_job_on_finished, i);
694 0 : if (r < 0)
695 0 : return r;
696 :
697 0 : i->roothash_job->on_open_disk = raw_pull_job_on_open_disk_roothash;
698 0 : i->roothash_job->on_progress = raw_pull_job_on_progress;
699 0 : i->roothash_job->calc_checksum = verify != IMPORT_VERIFY_NO;
700 : }
701 :
702 0 : if (settings) {
703 0 : r = pull_make_auxiliary_job(&i->settings_job, url, raw_strip_suffixes, ".nspawn", i->glue, raw_pull_job_on_finished, i);
704 0 : if (r < 0)
705 0 : return r;
706 :
707 0 : i->settings_job->on_open_disk = raw_pull_job_on_open_disk_settings;
708 0 : i->settings_job->on_progress = raw_pull_job_on_progress;
709 0 : i->settings_job->calc_checksum = verify != IMPORT_VERIFY_NO;
710 : }
711 :
712 0 : r = pull_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, raw_pull_job_on_finished, i);
713 0 : if (r < 0)
714 0 : return r;
715 :
716 0 : r = pull_job_begin(i->raw_job);
717 0 : if (r < 0)
718 0 : return r;
719 :
720 0 : if (i->roothash_job) {
721 0 : r = pull_job_begin(i->roothash_job);
722 0 : if (r < 0)
723 0 : return r;
724 : }
725 :
726 0 : if (i->settings_job) {
727 0 : r = pull_job_begin(i->settings_job);
728 0 : if (r < 0)
729 0 : return r;
730 : }
731 :
732 0 : if (i->checksum_job) {
733 0 : i->checksum_job->on_progress = raw_pull_job_on_progress;
734 0 : i->checksum_job->style = VERIFICATION_PER_FILE;
735 :
736 0 : r = pull_job_begin(i->checksum_job);
737 0 : if (r < 0)
738 0 : return r;
739 : }
740 :
741 0 : if (i->signature_job) {
742 0 : i->signature_job->on_progress = raw_pull_job_on_progress;
743 :
744 0 : r = pull_job_begin(i->signature_job);
745 0 : if (r < 0)
746 0 : return r;
747 : }
748 :
749 0 : return 0;
750 : }
|