1 /* SPDX-License-Identifier: LGPL-2.1+ */
8 #include "alloc-util.h"
9 #include "btrfs-util.h"
14 #include "hostname-util.h"
15 #include "import-common.h"
16 #include "import-compress.h"
17 #include "import-tar.h"
19 #include "machine-pool.h"
21 #include "path-util.h"
22 #include "process-util.h"
23 #include "qcow2-util.h"
24 #include "ratelimit.h"
26 #include "string-util.h"
34 TarImportFinished on_finished
;
40 bool grow_machine_directory
;
48 ImportCompress compress
;
50 uint64_t written_since_last_grow
;
52 sd_event_source
*input_event_source
;
54 uint8_t buffer
[16*1024];
57 uint64_t written_compressed
;
58 uint64_t written_uncompressed
;
64 unsigned last_percent
;
65 RateLimit progress_rate_limit
;
68 TarImport
* tar_import_unref(TarImport
*i
) {
72 sd_event_source_unref(i
->input_event_source
);
75 (void) kill_and_sigcont(i
->tar_pid
, SIGKILL
);
76 (void) wait_for_terminate(i
->tar_pid
, NULL
);
80 (void) rm_rf(i
->temp_path
, REMOVE_ROOT
|REMOVE_PHYSICAL
|REMOVE_SUBVOLUME
);
84 import_compress_free(&i
->compress
);
86 sd_event_unref(i
->event
);
88 safe_close(i
->tar_fd
);
99 const char *image_root
,
100 TarImportFinished on_finished
,
103 _cleanup_(tar_import_unrefp
) TarImport
*i
= NULL
;
108 i
= new0(TarImport
, 1);
112 i
->input_fd
= i
->tar_fd
= -1;
113 i
->on_finished
= on_finished
;
114 i
->userdata
= userdata
;
116 RATELIMIT_INIT(i
->progress_rate_limit
, 100 * USEC_PER_MSEC
, 1);
117 i
->last_percent
= (unsigned) -1;
119 i
->image_root
= strdup(image_root
?: "/var/lib/machines");
123 i
->grow_machine_directory
= path_startswith(i
->image_root
, "/var/lib/machines");
126 i
->event
= sd_event_ref(event
);
128 r
= sd_event_default(&i
->event
);
138 static void tar_import_report_progress(TarImport
*i
) {
142 /* We have no size information, unless the source is a regular file */
143 if (!S_ISREG(i
->st
.st_mode
))
146 if (i
->written_compressed
>= (uint64_t) i
->st
.st_size
)
149 percent
= (unsigned) ((i
->written_compressed
* UINT64_C(100)) / (uint64_t) i
->st
.st_size
);
151 if (percent
== i
->last_percent
)
154 if (!ratelimit_below(&i
->progress_rate_limit
))
157 sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent
);
158 log_info("Imported %u%%.", percent
);
160 i
->last_percent
= percent
;
163 static int tar_import_finish(TarImport
*i
) {
167 assert(i
->tar_fd
>= 0);
168 assert(i
->temp_path
);
169 assert(i
->final_path
);
171 i
->tar_fd
= safe_close(i
->tar_fd
);
173 if (i
->tar_pid
> 0) {
174 r
= wait_for_terminate_and_check("tar", i
->tar_pid
, WAIT_LOG
);
181 r
= import_make_read_only(i
->temp_path
);
187 (void) rm_rf(i
->final_path
, REMOVE_ROOT
|REMOVE_PHYSICAL
|REMOVE_SUBVOLUME
);
189 r
= rename_noreplace(AT_FDCWD
, i
->temp_path
, AT_FDCWD
, i
->final_path
);
191 return log_error_errno(r
, "Failed to move image into place: %m");
193 i
->temp_path
= mfree(i
->temp_path
);
198 static int tar_import_fork_tar(TarImport
*i
) {
203 assert(!i
->final_path
);
204 assert(!i
->temp_path
);
205 assert(i
->tar_fd
< 0);
207 i
->final_path
= strjoin(i
->image_root
, "/", i
->local
);
211 r
= tempfn_random(i
->final_path
, NULL
, &i
->temp_path
);
215 (void) mkdir_parents_label(i
->temp_path
, 0700);
217 r
= btrfs_subvol_make(i
->temp_path
);
219 if (mkdir(i
->temp_path
, 0755) < 0)
220 return log_error_errno(errno
, "Failed to create directory %s: %m", i
->temp_path
);
222 return log_error_errno(r
, "Failed to create subvolume %s: %m", i
->temp_path
);
224 (void) import_assign_pool_quota_and_warn(i
->temp_path
);
226 i
->tar_fd
= import_fork_tar_x(i
->temp_path
, &i
->tar_pid
);
233 static int tar_import_write(const void *p
, size_t sz
, void *userdata
) {
234 TarImport
*i
= userdata
;
237 if (i
->grow_machine_directory
&& i
->written_since_last_grow
>= GROW_INTERVAL_BYTES
) {
238 i
->written_since_last_grow
= 0;
239 grow_machine_directory();
242 r
= loop_write(i
->tar_fd
, p
, sz
, false);
246 i
->written_uncompressed
+= sz
;
247 i
->written_since_last_grow
+= sz
;
252 static int tar_import_process(TarImport
*i
) {
257 assert(i
->buffer_size
< sizeof(i
->buffer
));
259 l
= read(i
->input_fd
, i
->buffer
+ i
->buffer_size
, sizeof(i
->buffer
) - i
->buffer_size
);
264 r
= log_error_errno(errno
, "Failed to read input file: %m");
268 if (i
->compress
.type
== IMPORT_COMPRESS_UNKNOWN
) {
269 log_error("Premature end of file.");
274 r
= tar_import_finish(i
);
280 if (i
->compress
.type
== IMPORT_COMPRESS_UNKNOWN
) {
281 r
= import_uncompress_detect(&i
->compress
, i
->buffer
, i
->buffer_size
);
283 log_error_errno(r
, "Failed to detect file compression: %m");
286 if (r
== 0) /* Need more data */
289 r
= tar_import_fork_tar(i
);
294 r
= import_uncompress(&i
->compress
, i
->buffer
, i
->buffer_size
, tar_import_write
, i
);
296 log_error_errno(r
, "Failed to decode and write: %m");
300 i
->written_compressed
+= i
->buffer_size
;
303 tar_import_report_progress(i
);
309 i
->on_finished(i
, r
, i
->userdata
);
311 sd_event_exit(i
->event
, r
);
316 static int tar_import_on_input(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
317 TarImport
*i
= userdata
;
319 return tar_import_process(i
);
322 static int tar_import_on_defer(sd_event_source
*s
, void *userdata
) {
323 TarImport
*i
= userdata
;
325 return tar_import_process(i
);
328 int tar_import_start(TarImport
*i
, int fd
, const char *local
, bool force_local
, bool read_only
) {
335 if (!machine_name_is_valid(local
))
338 if (i
->input_fd
>= 0)
341 r
= fd_nonblock(fd
, true);
345 r
= free_and_strdup(&i
->local
, local
);
348 i
->force_local
= force_local
;
349 i
->read_only
= read_only
;
351 if (fstat(fd
, &i
->st
) < 0)
354 r
= sd_event_add_io(i
->event
, &i
->input_event_source
, fd
, EPOLLIN
, tar_import_on_input
, i
);
356 /* This fd does not support epoll, for example because it is a regular file. Busy read in that case */
357 r
= sd_event_add_defer(i
->event
, &i
->input_event_source
, tar_import_on_defer
, i
);
361 r
= sd_event_source_set_enabled(i
->input_event_source
, SD_EVENT_ON
);