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