File: | build-scan/../src/import/pull-job.c |
Warning: | line 564, column 25 Potential leak of memory pointed to by 'j' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
2 | ||||
3 | #include <sys/xattr.h> | |||
4 | ||||
5 | #include "alloc-util.h" | |||
6 | #include "fd-util.h" | |||
7 | #include "hexdecoct.h" | |||
8 | #include "import-util.h" | |||
9 | #include "io-util.h" | |||
10 | #include "machine-pool.h" | |||
11 | #include "parse-util.h" | |||
12 | #include "pull-common.h" | |||
13 | #include "pull-job.h" | |||
14 | #include "string-util.h" | |||
15 | #include "strv.h" | |||
16 | #include "xattr-util.h" | |||
17 | ||||
18 | PullJob* pull_job_unref(PullJob *j) { | |||
19 | if (!j) | |||
20 | return NULL((void*)0); | |||
21 | ||||
22 | curl_glue_remove_and_free(j->glue, j->curl); | |||
23 | curl_slist_free_all(j->request_header); | |||
24 | ||||
25 | safe_close(j->disk_fd); | |||
26 | ||||
27 | import_compress_free(&j->compress); | |||
28 | ||||
29 | if (j->checksum_context) | |||
30 | gcry_md_close(j->checksum_context); | |||
31 | ||||
32 | free(j->url); | |||
33 | free(j->etag); | |||
34 | strv_free(j->old_etags); | |||
35 | free(j->payload); | |||
36 | free(j->checksum); | |||
37 | ||||
38 | return mfree(j); | |||
39 | } | |||
40 | ||||
41 | static void pull_job_finish(PullJob *j, int ret) { | |||
42 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/import/pull-job.c", 42, __PRETTY_FUNCTION__ ); } while (0); | |||
43 | ||||
44 | if (IN_SET(j->state, PULL_JOB_DONE, PULL_JOB_FAILED)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){PULL_JOB_DONE, PULL_JOB_FAILED})/sizeof( int)]; switch(j->state) { case PULL_JOB_DONE: case PULL_JOB_FAILED : _found = 1; break; default: break; } _found; })) | |||
45 | return; | |||
46 | ||||
47 | if (ret == 0) { | |||
48 | j->state = PULL_JOB_DONE; | |||
49 | j->progress_percent = 100; | |||
50 | log_info("Download of %s complete.", j->url)({ 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/pull-job.c", 50, __func__, "Download of %s complete." , j->url) : -abs(_e); }); | |||
51 | } else { | |||
52 | j->state = PULL_JOB_FAILED; | |||
53 | j->error = ret; | |||
54 | } | |||
55 | ||||
56 | if (j->on_finished) | |||
57 | j->on_finished(j); | |||
58 | } | |||
59 | ||||
60 | static int pull_job_restart(PullJob *j) { | |||
61 | int r; | |||
62 | char *chksum_url = NULL((void*)0); | |||
63 | ||||
64 | r = import_url_change_last_component(j->url, "SHA256SUMS", &chksum_url); | |||
65 | if (r < 0) | |||
66 | return r; | |||
67 | ||||
68 | free(j->url); | |||
69 | j->url = chksum_url; | |||
70 | j->state = PULL_JOB_INIT; | |||
71 | j->payload = mfree(j->payload); | |||
72 | j->payload_size = 0; | |||
73 | j->payload_allocated = 0; | |||
74 | j->written_compressed = 0; | |||
75 | j->written_uncompressed = 0; | |||
76 | j->written_since_last_grow = 0; | |||
77 | ||||
78 | r = pull_job_begin(j); | |||
79 | if (r < 0) | |||
80 | return r; | |||
81 | ||||
82 | return 0; | |||
83 | } | |||
84 | ||||
85 | void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) { | |||
86 | PullJob *j = NULL((void*)0); | |||
87 | CURLcode code; | |||
88 | long status; | |||
89 | int r; | |||
90 | ||||
91 | if (curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&j)curl_easy_getinfo(curl,CURLINFO_PRIVATE,(char **)&j) != CURLE_OK) | |||
92 | return; | |||
93 | ||||
94 | if (!j || IN_SET(j->state, PULL_JOB_DONE, PULL_JOB_FAILED)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){PULL_JOB_DONE, PULL_JOB_FAILED})/sizeof( int)]; switch(j->state) { case PULL_JOB_DONE: case PULL_JOB_FAILED : _found = 1; break; default: break; } _found; })) | |||
95 | return; | |||
96 | ||||
97 | if (result != CURLE_OK) { | |||
98 | log_error("Transfer failed: %s", curl_easy_strerror(result))({ 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/pull-job.c", 98, __func__, "Transfer failed: %s" , curl_easy_strerror(result)) : -abs(_e); }); | |||
99 | r = -EIO5; | |||
100 | goto finish; | |||
101 | } | |||
102 | ||||
103 | code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status)curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&status); | |||
104 | if (code != CURLE_OK) { | |||
105 | log_error("Failed to retrieve response code: %s", curl_easy_strerror(code))({ 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/pull-job.c", 105, __func__, "Failed to retrieve response code: %s" , curl_easy_strerror(code)) : -abs(_e); }); | |||
106 | r = -EIO5; | |||
107 | goto finish; | |||
108 | } else if (status == 304) { | |||
109 | log_info("Image already downloaded. Skipping download.")({ 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/pull-job.c", 109, __func__, "Image already downloaded. Skipping download." ) : -abs(_e); }); | |||
110 | j->etag_exists = true1; | |||
111 | r = 0; | |||
112 | goto finish; | |||
113 | } else if (status >= 300) { | |||
114 | if (status == 404 && j->style == VERIFICATION_PER_FILE) { | |||
115 | ||||
116 | /* retry pull job with SHA256SUMS file */ | |||
117 | r = pull_job_restart(j); | |||
118 | if (r < 0) | |||
119 | goto finish; | |||
120 | ||||
121 | code = curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status)curl_easy_getinfo(j->curl,CURLINFO_RESPONSE_CODE,&status ); | |||
122 | if (code != CURLE_OK) { | |||
123 | log_error("Failed to retrieve response code: %s", curl_easy_strerror(code))({ 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/pull-job.c", 123, __func__, "Failed to retrieve response code: %s" , curl_easy_strerror(code)) : -abs(_e); }); | |||
124 | r = -EIO5; | |||
125 | goto finish; | |||
126 | } | |||
127 | ||||
128 | if (status == 0) { | |||
129 | j->style = VERIFICATION_PER_DIRECTORY; | |||
130 | return; | |||
131 | } | |||
132 | } | |||
133 | ||||
134 | log_error("HTTP request to %s failed with code %li.", j->url, status)({ 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/pull-job.c", 134, __func__, "HTTP request to %s failed with code %li." , j->url, status) : -abs(_e); }); | |||
135 | r = -EIO5; | |||
136 | goto finish; | |||
137 | } else if (status < 200) { | |||
138 | log_error("HTTP request to %s finished with unexpected code %li.", j->url, status)({ 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/pull-job.c", 138, __func__, "HTTP request to %s finished with unexpected code %li." , j->url, status) : -abs(_e); }); | |||
139 | r = -EIO5; | |||
140 | goto finish; | |||
141 | } | |||
142 | ||||
143 | if (j->state != PULL_JOB_RUNNING) { | |||
144 | log_error("Premature connection termination.")({ 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/pull-job.c", 144, __func__, "Premature connection termination." ) : -abs(_e); }); | |||
145 | r = -EIO5; | |||
146 | goto finish; | |||
147 | } | |||
148 | ||||
149 | if (j->content_length != (uint64_t) -1 && | |||
150 | j->content_length != j->written_compressed) { | |||
151 | log_error("Download truncated.")({ 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/pull-job.c", 151, __func__, "Download truncated." ) : -abs(_e); }); | |||
152 | r = -EIO5; | |||
153 | goto finish; | |||
154 | } | |||
155 | ||||
156 | if (j->checksum_context) { | |||
157 | uint8_t *k; | |||
158 | ||||
159 | k = gcry_md_read(j->checksum_context, GCRY_MD_SHA256); | |||
160 | if (!k) { | |||
161 | log_error("Failed to get checksum.")({ 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/pull-job.c", 161, __func__, "Failed to get checksum." ) : -abs(_e); }); | |||
162 | r = -EIO5; | |||
163 | goto finish; | |||
164 | } | |||
165 | ||||
166 | j->checksum = hexmem(k, gcry_md_get_algo_dlen(GCRY_MD_SHA256)); | |||
167 | if (!j->checksum) { | |||
168 | r = log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/import/pull-job.c" , 168, __func__); | |||
169 | goto finish; | |||
170 | } | |||
171 | ||||
172 | log_debug("SHA256 of %s is %s.", j->url, j->checksum)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/import/pull-job.c", 172, __func__, "SHA256 of %s is %s." , j->url, j->checksum) : -abs(_e); }); | |||
173 | } | |||
174 | ||||
175 | if (j->disk_fd >= 0 && j->allow_sparse) { | |||
176 | /* Make sure the file size is right, in case the file was | |||
177 | * sparse and we just seeked for the last part */ | |||
178 | ||||
179 | if (ftruncate(j->disk_fd, j->written_uncompressed) < 0) { | |||
180 | r = log_error_errno(errno, "Failed to truncate 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/pull-job.c", 180, __func__ , "Failed to truncate file: %m") : -abs(_e); }); | |||
181 | goto finish; | |||
182 | } | |||
183 | ||||
184 | if (j->etag) | |||
185 | (void) fsetxattr(j->disk_fd, "user.source_etag", j->etag, strlen(j->etag), 0); | |||
186 | if (j->url) | |||
187 | (void) fsetxattr(j->disk_fd, "user.source_url", j->url, strlen(j->url), 0); | |||
188 | ||||
189 | if (j->mtime != 0) { | |||
190 | struct timespec ut[2]; | |||
191 | ||||
192 | timespec_store(&ut[0], j->mtime); | |||
193 | ut[1] = ut[0]; | |||
194 | (void) futimens(j->disk_fd, ut); | |||
195 | ||||
196 | (void) fd_setcrtime(j->disk_fd, j->mtime); | |||
197 | } | |||
198 | } | |||
199 | ||||
200 | r = 0; | |||
201 | ||||
202 | finish: | |||
203 | pull_job_finish(j, r); | |||
204 | } | |||
205 | ||||
206 | static int pull_job_write_uncompressed(const void *p, size_t sz, void *userdata) { | |||
207 | PullJob *j = userdata; | |||
208 | ssize_t n; | |||
209 | ||||
210 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/import/pull-job.c", 210, __PRETTY_FUNCTION__ ); } while (0); | |||
211 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/import/pull-job.c", 211, __PRETTY_FUNCTION__ ); } while (0); | |||
212 | ||||
213 | if (sz <= 0) | |||
214 | return 0; | |||
215 | ||||
216 | if (j->written_uncompressed + sz < j->written_uncompressed) { | |||
217 | log_error("File too large, overflow")({ 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/pull-job.c", 217, __func__, "File too large, overflow" ) : -abs(_e); }); | |||
218 | return -EOVERFLOW75; | |||
219 | } | |||
220 | ||||
221 | if (j->written_uncompressed + sz > j->uncompressed_max) { | |||
222 | log_error("File overly large, refusing")({ 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/pull-job.c", 222, __func__, "File overly large, refusing" ) : -abs(_e); }); | |||
223 | return -EFBIG27; | |||
224 | } | |||
225 | ||||
226 | if (j->disk_fd >= 0) { | |||
227 | ||||
228 | if (j->grow_machine_directory && j->written_since_last_grow >= GROW_INTERVAL_BYTES(10UL * 1024UL * 1024UL)) { | |||
229 | j->written_since_last_grow = 0; | |||
230 | grow_machine_directory(); | |||
231 | } | |||
232 | ||||
233 | if (j->allow_sparse) | |||
234 | n = sparse_write(j->disk_fd, p, sz, 64); | |||
235 | else | |||
236 | n = write(j->disk_fd, p, sz); | |||
237 | if (n < 0) | |||
238 | return log_error_errno(errno, "Failed to write 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/pull-job.c", 238, __func__ , "Failed to write file: %m") : -abs(_e); }); | |||
239 | if ((size_t) n < sz) { | |||
240 | log_error("Short write")({ 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/pull-job.c", 240, __func__, "Short write") : -abs(_e); }); | |||
241 | return -EIO5; | |||
242 | } | |||
243 | } else { | |||
244 | ||||
245 | if (!GREEDY_REALLOC(j->payload, j->payload_allocated, j->payload_size + sz)greedy_realloc((void**) &(j->payload), &(j->payload_allocated ), (j->payload_size + sz), sizeof((j->payload)[0]))) | |||
246 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/import/pull-job.c" , 246, __func__); | |||
247 | ||||
248 | memcpy(j->payload + j->payload_size, p, sz); | |||
249 | j->payload_size += sz; | |||
250 | } | |||
251 | ||||
252 | j->written_uncompressed += sz; | |||
253 | j->written_since_last_grow += sz; | |||
254 | ||||
255 | return 0; | |||
256 | } | |||
257 | ||||
258 | static int pull_job_write_compressed(PullJob *j, void *p, size_t sz) { | |||
259 | int r; | |||
260 | ||||
261 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/import/pull-job.c", 261, __PRETTY_FUNCTION__ ); } while (0); | |||
262 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/import/pull-job.c", 262, __PRETTY_FUNCTION__ ); } while (0); | |||
263 | ||||
264 | if (sz <= 0) | |||
265 | return 0; | |||
266 | ||||
267 | if (j->written_compressed + sz < j->written_compressed) { | |||
268 | log_error("File too large, overflow")({ 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/pull-job.c", 268, __func__, "File too large, overflow" ) : -abs(_e); }); | |||
269 | return -EOVERFLOW75; | |||
270 | } | |||
271 | ||||
272 | if (j->written_compressed + sz > j->compressed_max) { | |||
273 | log_error("File overly large, refusing.")({ 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/pull-job.c", 273, __func__, "File overly large, refusing." ) : -abs(_e); }); | |||
274 | return -EFBIG27; | |||
275 | } | |||
276 | ||||
277 | if (j->content_length != (uint64_t) -1 && | |||
278 | j->written_compressed + sz > j->content_length) { | |||
279 | log_error("Content length incorrect.")({ 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/pull-job.c", 279, __func__, "Content length incorrect." ) : -abs(_e); }); | |||
280 | return -EFBIG27; | |||
281 | } | |||
282 | ||||
283 | if (j->checksum_context) | |||
284 | gcry_md_write(j->checksum_context, p, sz); | |||
285 | ||||
286 | r = import_uncompress(&j->compress, p, sz, pull_job_write_uncompressed, j); | |||
287 | if (r < 0) | |||
288 | return r; | |||
289 | ||||
290 | j->written_compressed += sz; | |||
291 | ||||
292 | return 0; | |||
293 | } | |||
294 | ||||
295 | static int pull_job_open_disk(PullJob *j) { | |||
296 | int r; | |||
297 | ||||
298 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/import/pull-job.c", 298, __PRETTY_FUNCTION__ ); } while (0); | |||
299 | ||||
300 | if (j->on_open_disk) { | |||
301 | r = j->on_open_disk(j); | |||
302 | if (r < 0) | |||
303 | return r; | |||
304 | } | |||
305 | ||||
306 | if (j->disk_fd >= 0) { | |||
307 | /* Check if we can do sparse files */ | |||
308 | ||||
309 | if (lseek(j->disk_fd, SEEK_SET0, 0) == 0) | |||
310 | j->allow_sparse = true1; | |||
311 | else { | |||
312 | if (errno(*__errno_location ()) != ESPIPE29) | |||
313 | return log_error_errno(errno, "Failed to seek on file descriptor: %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/pull-job.c", 313, __func__ , "Failed to seek on file descriptor: %m") : -abs(_e); }); | |||
314 | ||||
315 | j->allow_sparse = false0; | |||
316 | } | |||
317 | } | |||
318 | ||||
319 | if (j->calc_checksum) { | |||
320 | if (gcry_md_open(&j->checksum_context, GCRY_MD_SHA256, 0) != 0) { | |||
321 | log_error("Failed to initialize hash context.")({ 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/pull-job.c", 321, __func__, "Failed to initialize hash context." ) : -abs(_e); }); | |||
322 | return -EIO5; | |||
323 | } | |||
324 | } | |||
325 | ||||
326 | return 0; | |||
327 | } | |||
328 | ||||
329 | static int pull_job_detect_compression(PullJob *j) { | |||
330 | _cleanup_free___attribute__((cleanup(freep))) uint8_t *stub = NULL((void*)0); | |||
331 | size_t stub_size; | |||
332 | ||||
333 | int r; | |||
334 | ||||
335 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/import/pull-job.c", 335, __PRETTY_FUNCTION__ ); } while (0); | |||
336 | ||||
337 | r = import_uncompress_detect(&j->compress, j->payload, j->payload_size); | |||
338 | if (r < 0) | |||
339 | return log_error_errno(r, "Failed to initialize compressor: %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/pull-job.c", 339, __func__, "Failed to initialize compressor: %m" ) : -abs(_e); }); | |||
340 | if (r == 0) | |||
341 | return 0; | |||
342 | ||||
343 | log_debug("Stream is compressed: %s", import_compress_type_to_string(j->compress.type))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/import/pull-job.c", 343, __func__, "Stream is compressed: %s" , import_compress_type_to_string(j->compress.type)) : -abs (_e); }); | |||
344 | ||||
345 | r = pull_job_open_disk(j); | |||
346 | if (r < 0) | |||
347 | return r; | |||
348 | ||||
349 | /* Now, take the payload we read so far, and decompress it */ | |||
350 | stub = j->payload; | |||
351 | stub_size = j->payload_size; | |||
352 | ||||
353 | j->payload = NULL((void*)0); | |||
354 | j->payload_size = 0; | |||
355 | j->payload_allocated = 0; | |||
356 | ||||
357 | j->state = PULL_JOB_RUNNING; | |||
358 | ||||
359 | r = pull_job_write_compressed(j, stub, stub_size); | |||
360 | if (r < 0) | |||
361 | return r; | |||
362 | ||||
363 | return 0; | |||
364 | } | |||
365 | ||||
366 | static size_t pull_job_write_callback(void *contents, size_t size, size_t nmemb, void *userdata) { | |||
367 | PullJob *j = userdata; | |||
368 | size_t sz = size * nmemb; | |||
369 | int r; | |||
370 | ||||
371 | assert(contents)do { if ((__builtin_expect(!!(!(contents)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("contents"), "../src/import/pull-job.c", 371, __PRETTY_FUNCTION__); } while (0); | |||
372 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/import/pull-job.c", 372, __PRETTY_FUNCTION__ ); } while (0); | |||
373 | ||||
374 | switch (j->state) { | |||
375 | ||||
376 | case PULL_JOB_ANALYZING: | |||
377 | /* Let's first check what it actually is */ | |||
378 | ||||
379 | if (!GREEDY_REALLOC(j->payload, j->payload_allocated, j->payload_size + sz)greedy_realloc((void**) &(j->payload), &(j->payload_allocated ), (j->payload_size + sz), sizeof((j->payload)[0]))) { | |||
380 | r = log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/import/pull-job.c" , 380, __func__); | |||
381 | goto fail; | |||
382 | } | |||
383 | ||||
384 | memcpy(j->payload + j->payload_size, contents, sz); | |||
385 | j->payload_size += sz; | |||
386 | ||||
387 | r = pull_job_detect_compression(j); | |||
388 | if (r < 0) | |||
389 | goto fail; | |||
390 | ||||
391 | break; | |||
392 | ||||
393 | case PULL_JOB_RUNNING: | |||
394 | ||||
395 | r = pull_job_write_compressed(j, contents, sz); | |||
396 | if (r < 0) | |||
397 | goto fail; | |||
398 | ||||
399 | break; | |||
400 | ||||
401 | case PULL_JOB_DONE: | |||
402 | case PULL_JOB_FAILED: | |||
403 | r = -ESTALE116; | |||
404 | goto fail; | |||
405 | ||||
406 | default: | |||
407 | assert_not_reached("Impossible state.")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, ( "Impossible state."), "../src/import/pull-job.c", 407, __PRETTY_FUNCTION__ ); } while (0); | |||
408 | } | |||
409 | ||||
410 | return sz; | |||
411 | ||||
412 | fail: | |||
413 | pull_job_finish(j, r); | |||
414 | return 0; | |||
415 | } | |||
416 | ||||
417 | static size_t pull_job_header_callback(void *contents, size_t size, size_t nmemb, void *userdata) { | |||
418 | PullJob *j = userdata; | |||
419 | size_t sz = size * nmemb; | |||
420 | _cleanup_free___attribute__((cleanup(freep))) char *length = NULL((void*)0), *last_modified = NULL((void*)0); | |||
421 | char *etag; | |||
422 | int r; | |||
423 | ||||
424 | assert(contents)do { if ((__builtin_expect(!!(!(contents)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("contents"), "../src/import/pull-job.c", 424, __PRETTY_FUNCTION__); } while (0); | |||
425 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/import/pull-job.c", 425, __PRETTY_FUNCTION__ ); } while (0); | |||
426 | ||||
427 | if (IN_SET(j->state, PULL_JOB_DONE, PULL_JOB_FAILED)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){PULL_JOB_DONE, PULL_JOB_FAILED})/sizeof( int)]; switch(j->state) { case PULL_JOB_DONE: case PULL_JOB_FAILED : _found = 1; break; default: break; } _found; })) { | |||
428 | r = -ESTALE116; | |||
429 | goto fail; | |||
430 | } | |||
431 | ||||
432 | assert(j->state == PULL_JOB_ANALYZING)do { if ((__builtin_expect(!!(!(j->state == PULL_JOB_ANALYZING )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("j->state == PULL_JOB_ANALYZING" ), "../src/import/pull-job.c", 432, __PRETTY_FUNCTION__); } while (0); | |||
433 | ||||
434 | r = curl_header_strdup(contents, sz, "ETag:", &etag); | |||
435 | if (r < 0) { | |||
436 | log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/import/pull-job.c" , 436, __func__); | |||
437 | goto fail; | |||
438 | } | |||
439 | if (r > 0) { | |||
440 | free(j->etag); | |||
441 | j->etag = etag; | |||
442 | ||||
443 | if (strv_contains(j->old_etags, j->etag)(!!strv_find((j->old_etags), (j->etag)))) { | |||
444 | log_info("Image already downloaded. Skipping download.")({ 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/pull-job.c", 444, __func__, "Image already downloaded. Skipping download." ) : -abs(_e); }); | |||
445 | j->etag_exists = true1; | |||
446 | pull_job_finish(j, 0); | |||
447 | return sz; | |||
448 | } | |||
449 | ||||
450 | return sz; | |||
451 | } | |||
452 | ||||
453 | r = curl_header_strdup(contents, sz, "Content-Length:", &length); | |||
454 | if (r < 0) { | |||
455 | log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/import/pull-job.c" , 455, __func__); | |||
456 | goto fail; | |||
457 | } | |||
458 | if (r > 0) { | |||
459 | (void) safe_atou64(length, &j->content_length); | |||
460 | ||||
461 | if (j->content_length != (uint64_t) -1) { | |||
462 | char bytes[FORMAT_BYTES_MAX8]; | |||
463 | ||||
464 | if (j->content_length > j->compressed_max) { | |||
465 | log_error("Content too large.")({ 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/pull-job.c", 465, __func__, "Content too large." ) : -abs(_e); }); | |||
466 | r = -EFBIG27; | |||
467 | goto fail; | |||
468 | } | |||
469 | ||||
470 | log_info("Downloading %s for %s.", format_bytes(bytes, sizeof(bytes), j->content_length), j->url)({ 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/pull-job.c", 470, __func__, "Downloading %s for %s." , format_bytes(bytes, sizeof(bytes), j->content_length), j ->url) : -abs(_e); }); | |||
471 | } | |||
472 | ||||
473 | return sz; | |||
474 | } | |||
475 | ||||
476 | r = curl_header_strdup(contents, sz, "Last-Modified:", &last_modified); | |||
477 | if (r < 0) { | |||
478 | log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/import/pull-job.c" , 478, __func__); | |||
479 | goto fail; | |||
480 | } | |||
481 | if (r > 0) { | |||
482 | (void) curl_parse_http_time(last_modified, &j->mtime); | |||
483 | return sz; | |||
484 | } | |||
485 | ||||
486 | if (j->on_header) { | |||
487 | r = j->on_header(j, contents, sz); | |||
488 | if (r < 0) | |||
489 | goto fail; | |||
490 | } | |||
491 | ||||
492 | return sz; | |||
493 | ||||
494 | fail: | |||
495 | pull_job_finish(j, r); | |||
496 | return 0; | |||
497 | } | |||
498 | ||||
499 | static int pull_job_progress_callback(void *userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { | |||
500 | PullJob *j = userdata; | |||
501 | unsigned percent; | |||
502 | usec_t n; | |||
503 | ||||
504 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/import/pull-job.c", 504, __PRETTY_FUNCTION__ ); } while (0); | |||
505 | ||||
506 | if (dltotal <= 0) | |||
507 | return 0; | |||
508 | ||||
509 | percent = ((100 * dlnow) / dltotal); | |||
510 | n = now(CLOCK_MONOTONIC1); | |||
511 | ||||
512 | if (n > j->last_status_usec + USEC_PER_SEC((usec_t) 1000000ULL) && | |||
513 | percent != j->progress_percent && | |||
514 | dlnow < dltotal) { | |||
515 | char buf[FORMAT_TIMESPAN_MAX64]; | |||
516 | ||||
517 | if (n - j->start_usec > USEC_PER_SEC((usec_t) 1000000ULL) && dlnow > 0) { | |||
518 | char y[FORMAT_BYTES_MAX8]; | |||
519 | usec_t left, done; | |||
520 | ||||
521 | done = n - j->start_usec; | |||
522 | left = (usec_t) (((double) done * (double) dltotal) / dlnow) - done; | |||
523 | ||||
524 | log_info("Got %u%% of %s. %s left at %s/s.",({ 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/pull-job.c", 528, __func__, "Got %u%% of %s. %s left at %s/s." , percent, j->url, format_timespan(buf, sizeof(buf), left, ((usec_t) 1000000ULL)), format_bytes(y, sizeof(y), (uint64_t ) ((double) dlnow / ((double) done / (double) ((usec_t) 1000000ULL ))))) : -abs(_e); }) | |||
525 | 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/pull-job.c", 528, __func__, "Got %u%% of %s. %s left at %s/s." , percent, j->url, format_timespan(buf, sizeof(buf), left, ((usec_t) 1000000ULL)), format_bytes(y, sizeof(y), (uint64_t ) ((double) dlnow / ((double) done / (double) ((usec_t) 1000000ULL ))))) : -abs(_e); }) | |||
526 | j->url,({ 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/pull-job.c", 528, __func__, "Got %u%% of %s. %s left at %s/s." , percent, j->url, format_timespan(buf, sizeof(buf), left, ((usec_t) 1000000ULL)), format_bytes(y, sizeof(y), (uint64_t ) ((double) dlnow / ((double) done / (double) ((usec_t) 1000000ULL ))))) : -abs(_e); }) | |||
527 | format_timespan(buf, sizeof(buf), left, USEC_PER_SEC),({ 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/pull-job.c", 528, __func__, "Got %u%% of %s. %s left at %s/s." , percent, j->url, format_timespan(buf, sizeof(buf), left, ((usec_t) 1000000ULL)), format_bytes(y, sizeof(y), (uint64_t ) ((double) dlnow / ((double) done / (double) ((usec_t) 1000000ULL ))))) : -abs(_e); }) | |||
528 | format_bytes(y, sizeof(y), (uint64_t) ((double) dlnow / ((double) done / (double) USEC_PER_SEC))))({ 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/pull-job.c", 528, __func__, "Got %u%% of %s. %s left at %s/s." , percent, j->url, format_timespan(buf, sizeof(buf), left, ((usec_t) 1000000ULL)), format_bytes(y, sizeof(y), (uint64_t ) ((double) dlnow / ((double) done / (double) ((usec_t) 1000000ULL ))))) : -abs(_e); }); | |||
529 | } else | |||
530 | log_info("Got %u%% of %s.", percent, j->url)({ 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/pull-job.c", 530, __func__, "Got %u%% of %s." , percent, j->url) : -abs(_e); }); | |||
531 | ||||
532 | j->progress_percent = percent; | |||
533 | j->last_status_usec = n; | |||
534 | ||||
535 | if (j->on_progress) | |||
536 | j->on_progress(j); | |||
537 | } | |||
538 | ||||
539 | return 0; | |||
540 | } | |||
541 | ||||
542 | int pull_job_new(PullJob **ret, const char *url, CurlGlue *glue, void *userdata) { | |||
543 | _cleanup_(pull_job_unrefp)__attribute__((cleanup(pull_job_unrefp))) PullJob *j = NULL((void*)0); | |||
544 | ||||
545 | assert(url)do { if ((__builtin_expect(!!(!(url)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("url"), "../src/import/pull-job.c", 545, __PRETTY_FUNCTION__); } while (0); | |||
| ||||
546 | assert(glue)do { if ((__builtin_expect(!!(!(glue)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("glue"), "../src/import/pull-job.c", 546 , __PRETTY_FUNCTION__); } while (0); | |||
547 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/import/pull-job.c", 547, __PRETTY_FUNCTION__); } while (0); | |||
548 | ||||
549 | j = new0(PullJob, 1)((PullJob*) calloc((1), sizeof(PullJob))); | |||
550 | if (!j) | |||
551 | return -ENOMEM12; | |||
552 | ||||
553 | j->state = PULL_JOB_INIT; | |||
554 | j->disk_fd = -1; | |||
555 | j->userdata = userdata; | |||
556 | j->glue = glue; | |||
557 | j->content_length = (uint64_t) -1; | |||
558 | j->start_usec = now(CLOCK_MONOTONIC1); | |||
559 | j->compressed_max = j->uncompressed_max = 64LLU * 1024LLU * 1024LLU * 1024LLU; /* 64GB safety limit */ | |||
560 | j->style = VERIFICATION_STYLE_UNSET; | |||
561 | ||||
562 | j->url = strdup(url); | |||
563 | if (!j->url) | |||
564 | return -ENOMEM12; | |||
| ||||
565 | ||||
566 | *ret = TAKE_PTR(j)({ typeof(j) _ptr_ = (j); (j) = ((void*)0); _ptr_; }); | |||
567 | ||||
568 | return 0; | |||
569 | } | |||
570 | ||||
571 | int pull_job_begin(PullJob *j) { | |||
572 | int r; | |||
573 | ||||
574 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/import/pull-job.c", 574, __PRETTY_FUNCTION__ ); } while (0); | |||
575 | ||||
576 | if (j->state != PULL_JOB_INIT) | |||
577 | return -EBUSY16; | |||
578 | ||||
579 | if (j->grow_machine_directory) | |||
580 | grow_machine_directory(); | |||
581 | ||||
582 | r = curl_glue_make(&j->curl, j->url, j); | |||
583 | if (r < 0) | |||
584 | return r; | |||
585 | ||||
586 | if (!strv_isempty(j->old_etags)) { | |||
587 | _cleanup_free___attribute__((cleanup(freep))) char *cc = NULL((void*)0), *hdr = NULL((void*)0); | |||
588 | ||||
589 | cc = strv_join(j->old_etags, ", "); | |||
590 | if (!cc) | |||
591 | return -ENOMEM12; | |||
592 | ||||
593 | hdr = strappend("If-None-Match: ", cc); | |||
594 | if (!hdr) | |||
595 | return -ENOMEM12; | |||
596 | ||||
597 | if (!j->request_header) { | |||
598 | j->request_header = curl_slist_new(hdr, NULL((void*)0)); | |||
599 | if (!j->request_header) | |||
600 | return -ENOMEM12; | |||
601 | } else { | |||
602 | struct curl_slist *l; | |||
603 | ||||
604 | l = curl_slist_append(j->request_header, hdr); | |||
605 | if (!l) | |||
606 | return -ENOMEM12; | |||
607 | ||||
608 | j->request_header = l; | |||
609 | } | |||
610 | } | |||
611 | ||||
612 | if (j->request_header) { | |||
613 | if (curl_easy_setopt(j->curl, CURLOPT_HTTPHEADER, j->request_header)curl_easy_setopt(j->curl,CURLOPT_HTTPHEADER,j->request_header ) != CURLE_OK) | |||
614 | return -EIO5; | |||
615 | } | |||
616 | ||||
617 | if (curl_easy_setopt(j->curl, CURLOPT_WRITEFUNCTION, pull_job_write_callback)curl_easy_setopt(j->curl,CURLOPT_WRITEFUNCTION,pull_job_write_callback ) != CURLE_OK) | |||
618 | return -EIO5; | |||
619 | ||||
620 | if (curl_easy_setopt(j->curl, CURLOPT_WRITEDATA, j)curl_easy_setopt(j->curl,CURLOPT_WRITEDATA,j) != CURLE_OK) | |||
621 | return -EIO5; | |||
622 | ||||
623 | if (curl_easy_setopt(j->curl, CURLOPT_HEADERFUNCTION, pull_job_header_callback)curl_easy_setopt(j->curl,CURLOPT_HEADERFUNCTION,pull_job_header_callback ) != CURLE_OK) | |||
624 | return -EIO5; | |||
625 | ||||
626 | if (curl_easy_setopt(j->curl, CURLOPT_HEADERDATA, j)curl_easy_setopt(j->curl,CURLOPT_HEADERDATA,j) != CURLE_OK) | |||
627 | return -EIO5; | |||
628 | ||||
629 | if (curl_easy_setopt(j->curl, CURLOPT_XFERINFOFUNCTION, pull_job_progress_callback)curl_easy_setopt(j->curl,CURLOPT_XFERINFOFUNCTION,pull_job_progress_callback ) != CURLE_OK) | |||
630 | return -EIO5; | |||
631 | ||||
632 | if (curl_easy_setopt(j->curl, CURLOPT_XFERINFODATA, j)curl_easy_setopt(j->curl,CURLOPT_XFERINFODATA,j) != CURLE_OK) | |||
633 | return -EIO5; | |||
634 | ||||
635 | if (curl_easy_setopt(j->curl, CURLOPT_NOPROGRESS, 0)curl_easy_setopt(j->curl,CURLOPT_NOPROGRESS,0) != CURLE_OK) | |||
636 | return -EIO5; | |||
637 | ||||
638 | r = curl_glue_add(j->glue, j->curl); | |||
639 | if (r < 0) | |||
640 | return r; | |||
641 | ||||
642 | j->state = PULL_JOB_ANALYZING; | |||
643 | ||||
644 | return 0; | |||
645 | } |