1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "alloc-util.h"
9 #include "btrfs-util.h"
12 #include "format-util.h"
14 #include "hostname-util.h"
15 #include "import-common.h"
16 #include "import-compress.h"
17 #include "import-raw.h"
18 #include "install-file.h"
20 #include "machine-pool.h"
21 #include "mkdir-label.h"
22 #include "path-util.h"
23 #include "qcow2-util.h"
24 #include "ratelimit.h"
26 #include "string-util.h"
27 #include "tmpfile-util.h"
35 RawImportFinished on_finished
;
47 ImportCompress compress
;
49 sd_event_source
*input_event_source
;
51 uint8_t buffer
[16*1024];
54 uint64_t written_compressed
;
55 uint64_t written_uncompressed
;
57 struct stat input_stat
;
58 struct stat output_stat
;
60 unsigned last_percent
;
61 RateLimit progress_ratelimit
;
67 RawImport
* raw_import_unref(RawImport
*i
) {
71 sd_event_source_unref(i
->input_event_source
);
73 unlink_and_free(i
->temp_path
);
75 import_compress_free(&i
->compress
);
77 sd_event_unref(i
->event
);
79 safe_close(i
->output_fd
);
90 const char *image_root
,
91 RawImportFinished on_finished
,
94 _cleanup_(raw_import_unrefp
) RawImport
*i
= NULL
;
95 _cleanup_free_
char *root
= NULL
;
100 root
= strdup(image_root
?: "/var/lib/machines");
104 i
= new(RawImport
, 1);
111 .on_finished
= on_finished
,
112 .userdata
= userdata
,
113 .last_percent
= UINT_MAX
,
114 .image_root
= TAKE_PTR(root
),
115 .progress_ratelimit
= { 100 * USEC_PER_MSEC
, 1 },
116 .offset
= UINT64_MAX
,
117 .size_max
= UINT64_MAX
,
121 i
->event
= sd_event_ref(event
);
123 r
= sd_event_default(&i
->event
);
132 static void raw_import_report_progress(RawImport
*i
) {
136 /* We have no size information, unless the source is a regular file */
137 if (!S_ISREG(i
->input_stat
.st_mode
))
140 if (i
->written_compressed
>= (uint64_t) i
->input_stat
.st_size
)
143 percent
= (unsigned) ((i
->written_compressed
* UINT64_C(100)) / (uint64_t) i
->input_stat
.st_size
);
145 if (percent
== i
->last_percent
)
148 if (!ratelimit_below(&i
->progress_ratelimit
))
151 sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent
);
152 log_info("Imported %u%%.", percent
);
154 i
->last_percent
= percent
;
157 static int raw_import_maybe_convert_qcow2(RawImport
*i
) {
158 _cleanup_close_
int converted_fd
= -1;
159 _cleanup_(unlink_and_freep
) char *t
= NULL
;
160 _cleanup_free_
char *f
= NULL
;
165 /* Do QCOW2 conversion if enabled and not in direct mode */
166 if ((i
->flags
& (IMPORT_CONVERT_QCOW2
|IMPORT_DIRECT
)) != IMPORT_CONVERT_QCOW2
)
169 assert(i
->final_path
);
171 r
= qcow2_detect(i
->output_fd
);
173 return log_error_errno(r
, "Failed to detect whether this is a QCOW2 image: %m");
177 /* This is a QCOW2 image, let's convert it */
178 r
= tempfn_random(i
->final_path
, NULL
, &f
);
182 converted_fd
= open(f
, O_RDWR
|O_CREAT
|O_EXCL
|O_NOCTTY
|O_CLOEXEC
, 0664);
183 if (converted_fd
< 0)
184 return log_error_errno(errno
, "Failed to create %s: %m", f
);
188 (void) import_set_nocow_and_log(converted_fd
, t
);
190 log_info("Unpacking QCOW2 file.");
192 r
= qcow2_convert(i
->output_fd
, converted_fd
);
194 return log_error_errno(r
, "Failed to convert qcow2 image: %m");
196 unlink_and_free(i
->temp_path
);
197 i
->temp_path
= TAKE_PTR(t
);
198 CLOSE_AND_REPLACE(i
->output_fd
, converted_fd
);
203 static int raw_import_finish(RawImport
*i
) {
207 assert(i
->output_fd
>= 0);
209 /* Nothing of what is below applies to block devices */
210 if (S_ISBLK(i
->output_stat
.st_mode
)) {
212 if (i
->flags
& IMPORT_SYNC
) {
213 if (fsync(i
->output_fd
) < 0)
214 return log_error_errno(errno
, "Failed to synchronize block device: %m");
220 assert(S_ISREG(i
->output_stat
.st_mode
));
222 /* If an offset is specified we only are supposed to affect part of an existing output file or block
223 * device, thus don't manipulate file properties in that case */
225 if (i
->offset
== UINT64_MAX
) {
226 /* In case this was a sparse file, make sure the file size is right */
227 if (i
->written_uncompressed
> 0) {
228 if (ftruncate(i
->output_fd
, i
->written_uncompressed
) < 0)
229 return log_error_errno(errno
, "Failed to truncate file: %m");
232 r
= raw_import_maybe_convert_qcow2(i
);
236 if (S_ISREG(i
->input_stat
.st_mode
)) {
237 (void) copy_times(i
->input_fd
, i
->output_fd
, COPY_CRTIME
);
238 (void) copy_xattr(i
->input_fd
, i
->output_fd
, 0);
242 r
= install_file(AT_FDCWD
, i
->temp_path
?: i
->local
,
243 AT_FDCWD
, i
->final_path
,
244 (i
->flags
& IMPORT_FORCE
? INSTALL_REPLACE
: 0) |
245 (i
->flags
& IMPORT_READ_ONLY
? INSTALL_READ_ONLY
: 0) |
246 (i
->flags
& IMPORT_SYNC
? INSTALL_FSYNC_FULL
: 0));
248 return log_error_errno(r
, "Failed to move image into place: %m");
250 i
->temp_path
= mfree(i
->temp_path
);
252 log_info("Wrote %s.", FORMAT_BYTES(i
->written_uncompressed
));
257 static int raw_import_open_disk(RawImport
*i
) {
262 assert(!i
->final_path
);
263 assert(!i
->temp_path
);
264 assert(i
->output_fd
< 0);
266 if (i
->flags
& IMPORT_DIRECT
) {
267 (void) mkdir_parents_label(i
->local
, 0700);
269 /* In direct mode we just open/create the local path and truncate it (like shell >
270 * redirection would do it) — except if an offset was passed, in which case we are supposed
271 * to operate on a section of the file only, in which case we apparently work on an some
272 * existing thing (i.e. are not the sole thing stored in the file), in which case we will
273 * neither truncate nor create. */
275 i
->output_fd
= open(i
->local
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
|(i
->offset
== UINT64_MAX
? O_TRUNC
|O_CREAT
: 0), 0664);
276 if (i
->output_fd
< 0)
277 return log_error_errno(errno
, "Failed to open destination '%s': %m", i
->local
);
279 if (i
->offset
== UINT64_MAX
)
280 (void) import_set_nocow_and_log(i
->output_fd
, i
->local
);
282 i
->final_path
= strjoin(i
->image_root
, "/", i
->local
, ".raw");
286 r
= tempfn_random(i
->final_path
, NULL
, &i
->temp_path
);
290 (void) mkdir_parents_label(i
->temp_path
, 0700);
292 i
->output_fd
= open(i
->temp_path
, O_RDWR
|O_CREAT
|O_EXCL
|O_NOCTTY
|O_CLOEXEC
, 0664);
293 if (i
->output_fd
< 0)
294 return log_error_errno(errno
, "Failed to open destination '%s': %m", i
->temp_path
);
296 (void) import_set_nocow_and_log(i
->output_fd
, i
->temp_path
);
299 if (fstat(i
->output_fd
, &i
->output_stat
) < 0)
300 return log_error_errno(errno
, "Failed to stat() output file: %m");
302 if (!S_ISREG(i
->output_stat
.st_mode
) && !S_ISBLK(i
->output_stat
.st_mode
))
303 return log_error_errno(SYNTHETIC_ERRNO(EBADFD
),
304 "Target file is not a regular file or block device");
306 if (i
->offset
!= UINT64_MAX
) {
307 if (lseek(i
->output_fd
, i
->offset
, SEEK_SET
) == (off_t
) -1)
308 return log_error_errno(errno
, "Failed to seek to offset: %m");
314 static int raw_import_try_reflink(RawImport
*i
) {
319 assert(i
->input_fd
>= 0);
320 assert(i
->output_fd
>= 0);
322 if (i
->compress
.type
!= IMPORT_COMPRESS_UNCOMPRESSED
)
325 if (i
->offset
!= UINT64_MAX
|| i
->size_max
!= UINT64_MAX
)
328 if (!S_ISREG(i
->input_stat
.st_mode
) || !S_ISREG(i
->output_stat
.st_mode
))
331 p
= lseek(i
->input_fd
, 0, SEEK_CUR
);
333 return log_error_errno(errno
, "Failed to read file offset of input file: %m");
335 /* Let's only try a btrfs reflink, if we are reading from the beginning of the file */
336 if ((uint64_t) p
!= (uint64_t) i
->buffer_size
)
339 r
= btrfs_reflink(i
->input_fd
, i
->output_fd
);
343 log_debug_errno(r
, "Couldn't establish reflink, using copy: %m");
347 static int raw_import_write(const void *p
, size_t sz
, void *userdata
) {
348 RawImport
*i
= ASSERT_PTR(userdata
);
349 bool too_much
= false;
355 if (i
->written_uncompressed
>= UINT64_MAX
- sz
)
356 return log_error_errno(SYNTHETIC_ERRNO(EOVERFLOW
), "File too large, overflow");
358 if (i
->size_max
!= UINT64_MAX
) {
359 if (i
->written_uncompressed
>= i
->size_max
) {
364 if (i
->written_uncompressed
+ sz
> i
->size_max
) {
366 sz
= i
->size_max
- i
->written_uncompressed
; /* since we have the data in memory
367 * already, we might as well write it to
372 /* Generate sparse file if we created/truncated the file */
373 if (S_ISREG(i
->output_stat
.st_mode
) && i
->offset
== UINT64_MAX
) {
376 n
= sparse_write(i
->output_fd
, p
, sz
, 64);
378 return log_error_errno((int) n
, "Failed to write file: %m");
380 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Short write");
382 r
= loop_write(i
->output_fd
, p
, sz
, false);
384 return log_error_errno(r
, "Failed to write file: %m");
387 i
->written_uncompressed
+= sz
;
391 return log_error_errno(SYNTHETIC_ERRNO(E2BIG
), "File too large");
396 static int raw_import_process(RawImport
*i
) {
401 assert(i
->buffer_size
< sizeof(i
->buffer
));
403 l
= read(i
->input_fd
, i
->buffer
+ i
->buffer_size
, sizeof(i
->buffer
) - i
->buffer_size
);
408 r
= log_error_errno(errno
, "Failed to read input file: %m");
414 if (i
->compress
.type
== IMPORT_COMPRESS_UNKNOWN
) {
416 if (l
== 0) { /* EOF */
417 log_debug("File too short to be compressed, as no compression signature fits in, thus assuming uncompressed.");
418 import_uncompress_force_off(&i
->compress
);
420 r
= import_uncompress_detect(&i
->compress
, i
->buffer
, i
->buffer_size
);
422 log_error_errno(r
, "Failed to detect file compression: %m");
425 if (r
== 0) /* Need more data */
429 r
= raw_import_open_disk(i
);
433 r
= raw_import_try_reflink(i
);
440 r
= import_uncompress(&i
->compress
, i
->buffer
, i
->buffer_size
, raw_import_write
, i
);
442 log_error_errno(r
, "Failed to decode and write: %m");
446 i
->written_compressed
+= i
->buffer_size
;
449 if (l
== 0) /* EOF */
452 raw_import_report_progress(i
);
457 r
= raw_import_finish(i
);
461 i
->on_finished(i
, r
, i
->userdata
);
463 sd_event_exit(i
->event
, r
);
468 static int raw_import_on_input(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
469 RawImport
*i
= userdata
;
471 return raw_import_process(i
);
474 static int raw_import_on_defer(sd_event_source
*s
, void *userdata
) {
475 RawImport
*i
= userdata
;
477 return raw_import_process(i
);
480 int raw_import_start(
492 assert(!(flags
& ~IMPORT_FLAGS_MASK_RAW
));
493 assert(offset
== UINT64_MAX
|| FLAGS_SET(flags
, IMPORT_DIRECT
));
495 if (!import_validate_local(local
, flags
))
498 if (i
->input_fd
>= 0)
501 r
= fd_nonblock(fd
, true);
505 r
= free_and_strdup(&i
->local
, local
);
511 i
->size_max
= size_max
;
513 if (fstat(fd
, &i
->input_stat
) < 0)
516 r
= sd_event_add_io(i
->event
, &i
->input_event_source
, fd
, EPOLLIN
, raw_import_on_input
, i
);
518 /* This fd does not support epoll, for example because it is a regular file. Busy read in that case */
519 r
= sd_event_add_defer(i
->event
, &i
->input_event_source
, raw_import_on_defer
, i
);
523 r
= sd_event_source_set_enabled(i
->input_event_source
, SD_EVENT_ON
);