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