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