File: | build-scan/../src/import/import-tar.c |
Warning: | line 121, column 25 Potential leak of memory pointed to by 'i' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
2 | ||||
3 | #include <linux1/fs.h> | |||
4 | ||||
5 | #include "sd-daemon.h" | |||
6 | #include "sd-event.h" | |||
7 | ||||
8 | #include "alloc-util.h" | |||
9 | #include "btrfs-util.h" | |||
10 | #include "copy.h" | |||
11 | #include "fd-util.h" | |||
12 | #include "fileio.h" | |||
13 | #include "fs-util.h" | |||
14 | #include "hostname-util.h" | |||
15 | #include "import-common.h" | |||
16 | #include "import-compress.h" | |||
17 | #include "import-tar.h" | |||
18 | #include "io-util.h" | |||
19 | #include "machine-pool.h" | |||
20 | #include "mkdir.h" | |||
21 | #include "path-util.h" | |||
22 | #include "process-util.h" | |||
23 | #include "qcow2-util.h" | |||
24 | #include "ratelimit.h" | |||
25 | #include "rm-rf.h" | |||
26 | #include "string-util.h" | |||
27 | #include "util.h" | |||
28 | ||||
29 | struct TarImport { | |||
30 | sd_event *event; | |||
31 | ||||
32 | char *image_root; | |||
33 | ||||
34 | TarImportFinished on_finished; | |||
35 | void *userdata; | |||
36 | ||||
37 | char *local; | |||
38 | bool_Bool force_local; | |||
39 | bool_Bool read_only; | |||
40 | bool_Bool grow_machine_directory; | |||
41 | ||||
42 | char *temp_path; | |||
43 | char *final_path; | |||
44 | ||||
45 | int input_fd; | |||
46 | int tar_fd; | |||
47 | ||||
48 | ImportCompress compress; | |||
49 | ||||
50 | uint64_t written_since_last_grow; | |||
51 | ||||
52 | sd_event_source *input_event_source; | |||
53 | ||||
54 | uint8_t buffer[16*1024]; | |||
55 | size_t buffer_size; | |||
56 | ||||
57 | uint64_t written_compressed; | |||
58 | uint64_t written_uncompressed; | |||
59 | ||||
60 | struct stat st; | |||
61 | ||||
62 | pid_t tar_pid; | |||
63 | ||||
64 | unsigned last_percent; | |||
65 | RateLimit progress_rate_limit; | |||
66 | }; | |||
67 | ||||
68 | TarImport* tar_import_unref(TarImport *i) { | |||
69 | if (!i) | |||
70 | return NULL((void*)0); | |||
71 | ||||
72 | sd_event_source_unref(i->input_event_source); | |||
73 | ||||
74 | if (i->tar_pid > 1) { | |||
75 | (void) kill_and_sigcont(i->tar_pid, SIGKILL9); | |||
76 | (void) wait_for_terminate(i->tar_pid, NULL((void*)0)); | |||
77 | } | |||
78 | ||||
79 | if (i->temp_path) { | |||
80 | (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); | |||
81 | free(i->temp_path); | |||
82 | } | |||
83 | ||||
84 | import_compress_free(&i->compress); | |||
85 | ||||
86 | sd_event_unref(i->event); | |||
87 | ||||
88 | safe_close(i->tar_fd); | |||
89 | ||||
90 | free(i->final_path); | |||
91 | free(i->image_root); | |||
92 | free(i->local); | |||
93 | return mfree(i); | |||
94 | } | |||
95 | ||||
96 | int tar_import_new( | |||
97 | TarImport **ret, | |||
98 | sd_event *event, | |||
99 | const char *image_root, | |||
100 | TarImportFinished on_finished, | |||
101 | void *userdata) { | |||
102 | ||||
103 | _cleanup_(tar_import_unrefp)__attribute__((cleanup(tar_import_unrefp))) TarImport *i = NULL((void*)0); | |||
104 | int r; | |||
105 | ||||
106 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/import/import-tar.c", 106 , __PRETTY_FUNCTION__); } while (0); | |||
| ||||
107 | ||||
108 | i = new0(TarImport, 1)((TarImport*) calloc((1), sizeof(TarImport))); | |||
109 | if (!i) | |||
110 | return -ENOMEM12; | |||
111 | ||||
112 | i->input_fd = i->tar_fd = -1; | |||
113 | i->on_finished = on_finished; | |||
114 | i->userdata = userdata; | |||
115 | ||||
116 | RATELIMIT_INIT(i->progress_rate_limit, 100 * USEC_PER_MSEC, 1)do { RateLimit *_r = &(i->progress_rate_limit); _r-> interval = (100 * ((usec_t) 1000ULL)); _r->burst = (1); _r ->num = 0; _r->begin = 0; } while (0); | |||
117 | i->last_percent = (unsigned) -1; | |||
118 | ||||
119 | i->image_root = strdup(image_root ?: "/var/lib/machines"); | |||
120 | if (!i->image_root) | |||
121 | return -ENOMEM12; | |||
| ||||
122 | ||||
123 | i->grow_machine_directory = path_startswith(i->image_root, "/var/lib/machines"); | |||
124 | ||||
125 | if (event) | |||
126 | i->event = sd_event_ref(event); | |||
127 | else { | |||
128 | r = sd_event_default(&i->event); | |||
129 | if (r < 0) | |||
130 | return r; | |||
131 | } | |||
132 | ||||
133 | *ret = TAKE_PTR(i)({ typeof(i) _ptr_ = (i); (i) = ((void*)0); _ptr_; }); | |||
134 | ||||
135 | return 0; | |||
136 | } | |||
137 | ||||
138 | static void tar_import_report_progress(TarImport *i) { | |||
139 | unsigned percent; | |||
140 | assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("i"), "../src/import/import-tar.c", 140, __PRETTY_FUNCTION__); } while (0); | |||
141 | ||||
142 | /* We have no size information, unless the source is a regular file */ | |||
143 | if (!S_ISREG(i->st.st_mode)((((i->st.st_mode)) & 0170000) == (0100000))) | |||
144 | return; | |||
145 | ||||
146 | if (i->written_compressed >= (uint64_t) i->st.st_size) | |||
147 | percent = 100; | |||
148 | else | |||
149 | percent = (unsigned) ((i->written_compressed * UINT64_C(100)100UL) / (uint64_t) i->st.st_size); | |||
150 | ||||
151 | if (percent == i->last_percent) | |||
152 | return; | |||
153 | ||||
154 | if (!ratelimit_below(&i->progress_rate_limit)) | |||
155 | return; | |||
156 | ||||
157 | sd_notifyf(false0, "X_IMPORT_PROGRESS=%u", percent); | |||
158 | log_info("Imported %u%%.", percent)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/import/import-tar.c", 158, __func__, "Imported %u%%." , percent) : -abs(_e); }); | |||
159 | ||||
160 | i->last_percent = percent; | |||
161 | } | |||
162 | ||||
163 | static int tar_import_finish(TarImport *i) { | |||
164 | int r; | |||
165 | ||||
166 | assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("i"), "../src/import/import-tar.c", 166, __PRETTY_FUNCTION__); } while (0); | |||
167 | assert(i->tar_fd >= 0)do { if ((__builtin_expect(!!(!(i->tar_fd >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("i->tar_fd >= 0"), "../src/import/import-tar.c" , 167, __PRETTY_FUNCTION__); } while (0); | |||
168 | assert(i->temp_path)do { if ((__builtin_expect(!!(!(i->temp_path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("i->temp_path"), "../src/import/import-tar.c" , 168, __PRETTY_FUNCTION__); } while (0); | |||
169 | assert(i->final_path)do { if ((__builtin_expect(!!(!(i->final_path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("i->final_path"), "../src/import/import-tar.c" , 169, __PRETTY_FUNCTION__); } while (0); | |||
170 | ||||
171 | i->tar_fd = safe_close(i->tar_fd); | |||
172 | ||||
173 | if (i->tar_pid > 0) { | |||
174 | r = wait_for_terminate_and_check("tar", i->tar_pid, WAIT_LOG); | |||
175 | i->tar_pid = 0; | |||
176 | if (r < 0) | |||
177 | return r; | |||
178 | } | |||
179 | ||||
180 | if (i->read_only) { | |||
181 | r = import_make_read_only(i->temp_path); | |||
182 | if (r < 0) | |||
183 | return r; | |||
184 | } | |||
185 | ||||
186 | if (i->force_local) | |||
187 | (void) rm_rf(i->final_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); | |||
188 | ||||
189 | r = rename_noreplace(AT_FDCWD-100, i->temp_path, AT_FDCWD-100, i->final_path); | |||
190 | if (r < 0) | |||
191 | return log_error_errno(r, "Failed to move image into place: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/import/import-tar.c", 191, __func__, "Failed to move image into place: %m" ) : -abs(_e); }); | |||
192 | ||||
193 | i->temp_path = mfree(i->temp_path); | |||
194 | ||||
195 | return 0; | |||
196 | } | |||
197 | ||||
198 | static int tar_import_fork_tar(TarImport *i) { | |||
199 | int r; | |||
200 | ||||
201 | assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("i"), "../src/import/import-tar.c", 201, __PRETTY_FUNCTION__); } while (0); | |||
202 | ||||
203 | assert(!i->final_path)do { if ((__builtin_expect(!!(!(!i->final_path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("!i->final_path"), "../src/import/import-tar.c" , 203, __PRETTY_FUNCTION__); } while (0); | |||
204 | assert(!i->temp_path)do { if ((__builtin_expect(!!(!(!i->temp_path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("!i->temp_path"), "../src/import/import-tar.c" , 204, __PRETTY_FUNCTION__); } while (0); | |||
205 | assert(i->tar_fd < 0)do { if ((__builtin_expect(!!(!(i->tar_fd < 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("i->tar_fd < 0"), "../src/import/import-tar.c" , 205, __PRETTY_FUNCTION__); } while (0); | |||
206 | ||||
207 | i->final_path = strjoin(i->image_root, "/", i->local)strjoin_real((i->image_root), "/", i->local, ((void*)0) ); | |||
208 | if (!i->final_path) | |||
209 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/import/import-tar.c" , 209, __func__); | |||
210 | ||||
211 | r = tempfn_random(i->final_path, NULL((void*)0), &i->temp_path); | |||
212 | if (r < 0) | |||
213 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/import/import-tar.c" , 213, __func__); | |||
214 | ||||
215 | (void) mkdir_parents_label(i->temp_path, 0700); | |||
216 | ||||
217 | r = btrfs_subvol_make(i->temp_path); | |||
218 | if (r == -ENOTTY25) { | |||
219 | if (mkdir(i->temp_path, 0755) < 0) | |||
220 | return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/import/import-tar.c", 220, __func__ , "Failed to create directory %s: %m", i->temp_path) : -abs (_e); }); | |||
221 | } else if (r < 0) | |||
222 | return log_error_errno(r, "Failed to create subvolume %s: %m", i->temp_path)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/import/import-tar.c", 222, __func__, "Failed to create subvolume %s: %m" , i->temp_path) : -abs(_e); }); | |||
223 | else | |||
224 | (void) import_assign_pool_quota_and_warn(i->temp_path); | |||
225 | ||||
226 | i->tar_fd = import_fork_tar_x(i->temp_path, &i->tar_pid); | |||
227 | if (i->tar_fd < 0) | |||
228 | return i->tar_fd; | |||
229 | ||||
230 | return 0; | |||
231 | } | |||
232 | ||||
233 | static int tar_import_write(const void *p, size_t sz, void *userdata) { | |||
234 | TarImport *i = userdata; | |||
235 | int r; | |||
236 | ||||
237 | if (i->grow_machine_directory && i->written_since_last_grow >= GROW_INTERVAL_BYTES(10UL * 1024UL * 1024UL)) { | |||
238 | i->written_since_last_grow = 0; | |||
239 | grow_machine_directory(); | |||
240 | } | |||
241 | ||||
242 | r = loop_write(i->tar_fd, p, sz, false0); | |||
243 | if (r < 0) | |||
244 | return r; | |||
245 | ||||
246 | i->written_uncompressed += sz; | |||
247 | i->written_since_last_grow += sz; | |||
248 | ||||
249 | return 0; | |||
250 | } | |||
251 | ||||
252 | static int tar_import_process(TarImport *i) { | |||
253 | ssize_t l; | |||
254 | int r; | |||
255 | ||||
256 | assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("i"), "../src/import/import-tar.c", 256, __PRETTY_FUNCTION__); } while (0); | |||
257 | assert(i->buffer_size < sizeof(i->buffer))do { if ((__builtin_expect(!!(!(i->buffer_size < sizeof (i->buffer))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("i->buffer_size < sizeof(i->buffer)"), "../src/import/import-tar.c" , 257, __PRETTY_FUNCTION__); } while (0); | |||
258 | ||||
259 | l = read(i->input_fd, i->buffer + i->buffer_size, sizeof(i->buffer) - i->buffer_size); | |||
260 | if (l < 0) { | |||
261 | if (errno(*__errno_location ()) == EAGAIN11) | |||
262 | return 0; | |||
263 | ||||
264 | r = log_error_errno(errno, "Failed to read input file: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/import/import-tar.c", 264, __func__ , "Failed to read input file: %m") : -abs(_e); }); | |||
265 | goto finish; | |||
266 | } | |||
267 | if (l == 0) { | |||
268 | if (i->compress.type == IMPORT_COMPRESS_UNKNOWN) { | |||
269 | log_error("Premature end of file.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/import/import-tar.c", 269, __func__, "Premature end of file." ) : -abs(_e); }); | |||
270 | r = -EIO5; | |||
271 | goto finish; | |||
272 | } | |||
273 | ||||
274 | r = tar_import_finish(i); | |||
275 | goto finish; | |||
276 | } | |||
277 | ||||
278 | i->buffer_size += l; | |||
279 | ||||
280 | if (i->compress.type == IMPORT_COMPRESS_UNKNOWN) { | |||
281 | r = import_uncompress_detect(&i->compress, i->buffer, i->buffer_size); | |||
282 | if (r < 0) { | |||
283 | log_error_errno(r, "Failed to detect file compression: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/import/import-tar.c", 283, __func__, "Failed to detect file compression: %m" ) : -abs(_e); }); | |||
284 | goto finish; | |||
285 | } | |||
286 | if (r == 0) /* Need more data */ | |||
287 | return 0; | |||
288 | ||||
289 | r = tar_import_fork_tar(i); | |||
290 | if (r < 0) | |||
291 | goto finish; | |||
292 | } | |||
293 | ||||
294 | r = import_uncompress(&i->compress, i->buffer, i->buffer_size, tar_import_write, i); | |||
295 | if (r < 0) { | |||
296 | log_error_errno(r, "Failed to decode and write: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/import/import-tar.c", 296, __func__, "Failed to decode and write: %m" ) : -abs(_e); }); | |||
297 | goto finish; | |||
298 | } | |||
299 | ||||
300 | i->written_compressed += i->buffer_size; | |||
301 | i->buffer_size = 0; | |||
302 | ||||
303 | tar_import_report_progress(i); | |||
304 | ||||
305 | return 0; | |||
306 | ||||
307 | finish: | |||
308 | if (i->on_finished) | |||
309 | i->on_finished(i, r, i->userdata); | |||
310 | else | |||
311 | sd_event_exit(i->event, r); | |||
312 | ||||
313 | return 0; | |||
314 | } | |||
315 | ||||
316 | static int tar_import_on_input(sd_event_source *s, int fd, uint32_t revents, void *userdata) { | |||
317 | TarImport *i = userdata; | |||
318 | ||||
319 | return tar_import_process(i); | |||
320 | } | |||
321 | ||||
322 | static int tar_import_on_defer(sd_event_source *s, void *userdata) { | |||
323 | TarImport *i = userdata; | |||
324 | ||||
325 | return tar_import_process(i); | |||
326 | } | |||
327 | ||||
328 | int tar_import_start(TarImport *i, int fd, const char *local, bool_Bool force_local, bool_Bool read_only) { | |||
329 | int r; | |||
330 | ||||
331 | assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("i"), "../src/import/import-tar.c", 331, __PRETTY_FUNCTION__); } while (0); | |||
332 | assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/import/import-tar.c" , 332, __PRETTY_FUNCTION__); } while (0); | |||
333 | assert(local)do { if ((__builtin_expect(!!(!(local)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("local"), "../src/import/import-tar.c", 333 , __PRETTY_FUNCTION__); } while (0); | |||
334 | ||||
335 | if (!machine_name_is_valid(local)hostname_is_valid(local, 0)) | |||
336 | return -EINVAL22; | |||
337 | ||||
338 | if (i->input_fd >= 0) | |||
339 | return -EBUSY16; | |||
340 | ||||
341 | r = fd_nonblock(fd, true1); | |||
342 | if (r < 0) | |||
343 | return r; | |||
344 | ||||
345 | r = free_and_strdup(&i->local, local); | |||
346 | if (r < 0) | |||
347 | return r; | |||
348 | i->force_local = force_local; | |||
349 | i->read_only = read_only; | |||
350 | ||||
351 | if (fstat(fd, &i->st) < 0) | |||
352 | return -errno(*__errno_location ()); | |||
353 | ||||
354 | r = sd_event_add_io(i->event, &i->input_event_source, fd, EPOLLINEPOLLIN, tar_import_on_input, i); | |||
355 | if (r == -EPERM1) { | |||
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); | |||
358 | if (r < 0) | |||
359 | return r; | |||
360 | ||||
361 | r = sd_event_source_set_enabled(i->input_event_source, SD_EVENT_ON); | |||
362 | } | |||
363 | if (r < 0) | |||
364 | return r; | |||
365 | ||||
366 | i->input_fd = fd; | |||
367 | return r; | |||
368 | } |