pull-job.c revision 3e2cda698f05d7290a8b9444d2c7d5c2599b2a27
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen/***
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen This file is part of systemd.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen Copyright 2015 Lennart Poettering
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen systemd is free software; you can redistribute it and/or modify it
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen under the terms of the GNU Lesser General Public License as published by
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen (at your option) any later version.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen systemd is distributed in the hope that it will be useful, but
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen Lesser General Public License for more details.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen You should have received a copy of the GNU Lesser General Public License
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen***/
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen#include <sys/xattr.h>
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen#include "strv.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "machine-pool.h"
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen#include "pull-job.h"
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen/* Grow the /var/lib/machines directory after each 10MiB written */
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen#define PULL_GROW_INTERVAL_BYTES (UINT64_C(10) * UINT64_C(1024) * UINT64_C(1024))
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom GundersenPullJob* pull_job_unref(PullJob *j) {
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering if (!j)
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering return NULL;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen curl_glue_remove_and_free(j->glue, j->curl);
99634696183dfabae20104e58157c69029a11594Tom Gundersen curl_slist_free_all(j->request_header);
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen safe_close(j->disk_fd);
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen import_compress_free(&j->compress);
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen if (j->checksum_context)
99634696183dfabae20104e58157c69029a11594Tom Gundersen gcry_md_close(j->checksum_context);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen free(j->url);
99634696183dfabae20104e58157c69029a11594Tom Gundersen free(j->etag);
99634696183dfabae20104e58157c69029a11594Tom Gundersen strv_free(j->old_etags);
99634696183dfabae20104e58157c69029a11594Tom Gundersen free(j->payload);
99634696183dfabae20104e58157c69029a11594Tom Gundersen free(j->checksum);
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen free(j);
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen return NULL;
99634696183dfabae20104e58157c69029a11594Tom Gundersen}
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersenstatic void pull_job_finish(PullJob *j, int ret) {
99634696183dfabae20104e58157c69029a11594Tom Gundersen assert(j);
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen if (j->state == PULL_JOB_DONE ||
99634696183dfabae20104e58157c69029a11594Tom Gundersen j->state == PULL_JOB_FAILED)
99634696183dfabae20104e58157c69029a11594Tom Gundersen return;
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen if (ret == 0) {
99634696183dfabae20104e58157c69029a11594Tom Gundersen j->state = PULL_JOB_DONE;
99634696183dfabae20104e58157c69029a11594Tom Gundersen j->progress_percent = 100;
99634696183dfabae20104e58157c69029a11594Tom Gundersen log_info("Download of %s complete.", j->url);
99634696183dfabae20104e58157c69029a11594Tom Gundersen } else {
99634696183dfabae20104e58157c69029a11594Tom Gundersen j->state = PULL_JOB_FAILED;
99634696183dfabae20104e58157c69029a11594Tom Gundersen j->error = ret;
99634696183dfabae20104e58157c69029a11594Tom Gundersen }
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen if (j->on_finished)
99634696183dfabae20104e58157c69029a11594Tom Gundersen j->on_finished(j);
99634696183dfabae20104e58157c69029a11594Tom Gundersen}
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersenvoid pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
99634696183dfabae20104e58157c69029a11594Tom Gundersen PullJob *j = NULL;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen CURLcode code;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen long status;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen int r;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (curl_easy_getinfo(curl, CURLINFO_PRIVATE, &j) != CURLE_OK)
99634696183dfabae20104e58157c69029a11594Tom Gundersen return;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (!j || j->state == PULL_JOB_DONE || j->state == PULL_JOB_FAILED)
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen return;
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen if (result != CURLE_OK) {
99634696183dfabae20104e58157c69029a11594Tom Gundersen log_error("Transfer failed: %s", curl_easy_strerror(result));
99634696183dfabae20104e58157c69029a11594Tom Gundersen r = -EIO;
99634696183dfabae20104e58157c69029a11594Tom Gundersen goto finish;
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen }
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen if (code != CURLE_OK) {
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen log_error("Failed to retrieve response code: %s", curl_easy_strerror(code));
756775814cf69471f74ce853745bba69f2ba94efThomas Hindoe Paaboel Andersen r = -EIO;
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen goto finish;
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen } else if (status == 304) {
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen log_info("Image already downloaded. Skipping download.");
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen j->etag_exists = true;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen r = 0;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering goto finish;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering } else if (status >= 300) {
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering log_error("HTTP request to %s failed with code %li.", j->url, status);
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering r = -EIO;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering goto finish;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering } else if (status < 200) {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen log_error("HTTP request to %s finished with unexpected code %li.", j->url, status);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen r = -EIO;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen goto finish;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen }
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (j->state != PULL_JOB_RUNNING) {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen log_error("Premature connection termination.");
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen r = -EIO;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen goto finish;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen }
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen if (j->content_length != (uint64_t) -1 &&
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen j->content_length != j->written_compressed) {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen log_error("Download truncated.");
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen r = -EIO;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen goto finish;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen }
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (j->checksum_context) {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen uint8_t *k;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen k = gcry_md_read(j->checksum_context, GCRY_MD_SHA256);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (!k) {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen log_error("Failed to get checksum.");
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen r = -EIO;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen goto finish;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen }
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen j->checksum = hexmem(k, gcry_md_get_algo_dlen(GCRY_MD_SHA256));
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt if (!j->checksum) {
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt r = log_oom();
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt goto finish;
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt }
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen log_debug("SHA256 of %s is %s.", j->url, j->checksum);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen }
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (j->disk_fd >= 0 && j->allow_sparse) {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen /* Make sure the file size is right, in case the file was
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen * sparse and we just seeked for the last part */
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (ftruncate(j->disk_fd, j->written_uncompressed) < 0) {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen log_error_errno(errno, "Failed to truncate file: %m");
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering r = -errno;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen goto finish;
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering }
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (j->etag)
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering (void) fsetxattr(j->disk_fd, "user.source_etag", j->etag, strlen(j->etag), 0);
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering if (j->url)
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering (void) fsetxattr(j->disk_fd, "user.source_url", j->url, strlen(j->url), 0);
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering if (j->mtime != 0) {
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen struct timespec ut[2];
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen timespec_store(&ut[0], j->mtime);
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering ut[1] = ut[0];
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen (void) futimens(j->disk_fd, ut);
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering (void) fd_setcrtime(j->disk_fd, j->mtime);
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering }
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering }
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering r = 0;
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poetteringfinish:
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering pull_job_finish(j, r);
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering}
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poetteringstatic int pull_job_write_uncompressed(const void *p, size_t sz, void *userdata) {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen PullJob *j = userdata;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen ssize_t n;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert(j);
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen assert(p);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (sz <= 0)
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return 0;
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (j->written_uncompressed + sz < j->written_uncompressed) {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen log_error("File too large, overflow");
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return -EOVERFLOW;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen }
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering if (j->written_uncompressed + sz > j->uncompressed_max) {
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen log_error("File overly large, refusing");
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen return -EFBIG;
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen }
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering if (j->disk_fd >= 0) {
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering if (j->grow_machine_directory && j->written_since_last_grow >= PULL_GROW_INTERVAL_BYTES) {
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering j->written_since_last_grow = 0;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen grow_machine_directory();
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen }
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (j->allow_sparse)
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen n = sparse_write(j->disk_fd, p, sz, 64);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen else
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen n = write(j->disk_fd, p, sz);
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen if (n < 0) {
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen log_error_errno(errno, "Failed to write file: %m");
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return -errno;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen }
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if ((size_t) n < sz) {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen log_error("Short write");
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return -EIO;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen }
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen } else {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (!GREEDY_REALLOC(j->payload, j->payload_allocated, j->payload_size + sz))
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return log_oom();
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen memcpy(j->payload + j->payload_size, p, sz);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen j->payload_size += sz;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen }
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen j->written_uncompressed += sz;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen j->written_since_last_grow += sz;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return 0;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen}
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersenstatic int pull_job_write_compressed(PullJob *j, void *p, size_t sz) {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen int r;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert(j);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert(p);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (sz <= 0)
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return 0;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (j->written_compressed + sz < j->written_compressed) {
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen log_error("File too large, overflow");
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen return -EOVERFLOW;
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen }
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen if (j->written_compressed + sz > j->compressed_max) {
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen log_error("File overly large, refusing.");
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen return -EFBIG;
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen }
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen if (j->content_length != (uint64_t) -1 &&
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen j->written_compressed + sz > j->content_length) {
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen log_error("Content length incorrect.");
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen return -EFBIG;
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen }
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen if (j->checksum_context)
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen gcry_md_write(j->checksum_context, p, sz);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = import_uncompress(&j->compress, p, sz, pull_job_write_uncompressed, j);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (r < 0)
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering return r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen j->written_compressed += sz;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return 0;
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering}
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic int pull_job_open_disk(PullJob *j) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen int r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert(j);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (j->on_open_disk) {
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen r = j->on_open_disk(j);
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen if (r < 0)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return r;
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (j->disk_fd >= 0) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen /* Check if we can do sparse files */
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (lseek(j->disk_fd, SEEK_SET, 0) == 0)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen j->allow_sparse = true;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen else {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (errno != ESPIPE)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return log_error_errno(errno, "Failed to seek on file descriptor: %m");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen j->allow_sparse = false;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (j->calc_checksum) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (gcry_md_open(&j->checksum_context, GCRY_MD_SHA256, 0) != 0) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("Failed to initialize hash context.");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return -EIO;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return 0;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen}
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic int pull_job_detect_compression(PullJob *j) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen _cleanup_free_ uint8_t *stub = NULL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen size_t stub_size;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen int r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert(j);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = import_uncompress_detect(&j->compress, j->payload, j->payload_size);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (r < 0)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return log_error_errno(r, "Failed to initialize compressor: %m");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (r == 0)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return 0;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_debug("Stream is compressed: %s", import_compress_type_to_string(j->compress.type));
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = pull_job_open_disk(j);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (r < 0)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen /* Now, take the payload we read so far, and decompress it */
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering stub = j->payload;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen stub_size = j->payload_size;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen j->payload = NULL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen j->payload_size = 0;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen j->payload_allocated = 0;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen j->state = PULL_JOB_RUNNING;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = pull_job_write_compressed(j, stub, stub_size);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (r < 0)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return 0;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen}
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic size_t pull_job_write_callback(void *contents, size_t size, size_t nmemb, void *userdata) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen PullJob *j = userdata;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen size_t sz = size * nmemb;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen int r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert(contents);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert(j);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen switch (j->state) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen case PULL_JOB_ANALYZING:
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen /* Let's first check what it actually is */
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (!GREEDY_REALLOC(j->payload, j->payload_allocated, j->payload_size + sz)) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = log_oom();
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen goto fail;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen memcpy(j->payload + j->payload_size, contents, sz);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen j->payload_size += sz;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = pull_job_detect_compression(j);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (r < 0)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen goto fail;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen break;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen case PULL_JOB_RUNNING:
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = pull_job_write_compressed(j, contents, sz);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (r < 0)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen goto fail;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen break;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen case PULL_JOB_DONE:
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen case PULL_JOB_FAILED:
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = -ESTALE;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen goto fail;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen default:
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert_not_reached("Impossible state.");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return sz;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenfail:
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen pull_job_finish(j, r);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return 0;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen}
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic size_t pull_job_header_callback(void *contents, size_t size, size_t nmemb, void *userdata) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen PullJob *j = userdata;
d6bd972d061af306ede2affd2c9340a1660f7996Tom Gundersen size_t sz = size * nmemb;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen _cleanup_free_ char *length = NULL, *last_modified = NULL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen char *etag;
d6bd972d061af306ede2affd2c9340a1660f7996Tom Gundersen int r;
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen assert(contents);
d6bd972d061af306ede2affd2c9340a1660f7996Tom Gundersen assert(j);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen if (j->state == PULL_JOB_DONE || j->state == PULL_JOB_FAILED) {
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen r = -ESTALE;
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen goto fail;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert(j->state == PULL_JOB_ANALYZING);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen r = curl_header_strdup(contents, sz, "ETag:", &etag);
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen if (r < 0) {
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen log_oom();
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen goto fail;
1231c4d238844e77018caf5b5852f01d96373c47Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (r > 0) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen free(j->etag);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen j->etag = etag;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (strv_contains(j->old_etags, j->etag)) {
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen log_info("Image already downloaded. Skipping download.");
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen j->etag_exists = true;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen pull_job_finish(j, 0);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen return sz;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen return sz;
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams }
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen r = curl_header_strdup(contents, sz, "Content-Length:", &length);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (r < 0) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_oom();
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen goto fail;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (r > 0) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen (void) safe_atou64(length, &j->content_length);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (j->content_length != (uint64_t) -1) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen char bytes[FORMAT_BYTES_MAX];
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (j->content_length > j->compressed_max) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_error("Content too large.");
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen r = -EFBIG;
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen goto fail;
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_info("Downloading %s for %s.", format_bytes(bytes, sizeof(bytes), j->content_length), j->url);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen return sz;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen r = curl_header_strdup(contents, sz, "Last-Modified:", &last_modified);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (r < 0) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen log_oom();
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen goto fail;
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (r > 0) {
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen (void) curl_parse_http_time(last_modified, &j->mtime);
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen return sz;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (j->on_header) {
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen r = j->on_header(j, contents, sz);
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen if (r < 0)
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen goto fail;
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen }
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen return sz;
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersenfail:
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen pull_job_finish(j, r);
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen return 0;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen}
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersenstatic int pull_job_progress_callback(void *userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen PullJob *j = userdata;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen unsigned percent;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen usec_t n;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen assert(j);
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (dltotal <= 0)
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen return 0;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen percent = ((100 * dlnow) / dltotal);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen n = now(CLOCK_MONOTONIC);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (n > j->last_status_usec + USEC_PER_SEC &&
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen percent != j->progress_percent &&
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen dlnow < dltotal) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen char buf[FORMAT_TIMESPAN_MAX];
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen if (n - j->start_usec > USEC_PER_SEC && dlnow > 0) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen char y[FORMAT_BYTES_MAX];
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen usec_t left, done;
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen done = n - j->start_usec;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen left = (usec_t) (((double) done * (double) dltotal) / dlnow) - done;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen log_info("Got %u%% of %s. %s left at %s/s.",
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen percent,
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen j->url,
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen format_timespan(buf, sizeof(buf), left, USEC_PER_SEC),
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen format_bytes(y, sizeof(y), (uint64_t) ((double) dlnow / ((double) done / (double) USEC_PER_SEC))));
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen } else
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen log_info("Got %u%% of %s.", percent, j->url);
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen j->progress_percent = percent;
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen j->last_status_usec = n;
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering if (j->on_progress)
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering j->on_progress(j);
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering }
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering return 0;
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering}
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poetteringint pull_job_new(PullJob **ret, const char *url, CurlGlue *glue, void *userdata) {
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering _cleanup_(pull_job_unrefp) PullJob *j = NULL;
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering assert(url);
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering assert(glue);
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering assert(ret);
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering j = new0(PullJob, 1);
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering if (!j)
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering return -ENOMEM;
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering j->state = PULL_JOB_INIT;
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering j->disk_fd = -1;
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering j->userdata = userdata;
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering j->glue = glue;
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering j->content_length = (uint64_t) -1;
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering j->start_usec = now(CLOCK_MONOTONIC);
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering j->compressed_max = j->uncompressed_max = 8LLU * 1024LLU * 1024LLU * 1024LLU; /* 8GB */
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen j->url = strdup(url);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (!j->url)
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen return -ENOMEM;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen *ret = j;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen j = NULL;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen return 0;
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen}
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersenint pull_job_begin(PullJob *j) {
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen int r;
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen assert(j);
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen if (j->state != PULL_JOB_INIT)
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering return -EBUSY;
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen if (j->grow_machine_directory)
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen grow_machine_directory();
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen r = curl_glue_make(&j->curl, j->url, j);
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (r < 0)
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen return r;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (!strv_isempty(j->old_etags)) {
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen _cleanup_free_ char *cc = NULL, *hdr = NULL;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen cc = strv_join(j->old_etags, ", ");
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (!cc)
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen return -ENOMEM;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen hdr = strappend("If-None-Match: ", cc);
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (!hdr)
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams return -ENOMEM;
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (!j->request_header) {
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen j->request_header = curl_slist_new(hdr, NULL);
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (!j->request_header)
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen return -ENOMEM;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen } else {
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen struct curl_slist *l;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen l = curl_slist_append(j->request_header, hdr);
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (!l)
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen return -ENOMEM;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen j->request_header = l;
c15fb62a731f1a457af94e60ac6a4d23f219a8f6Thomas Hindoe Paaboel Andersen }
c15fb62a731f1a457af94e60ac6a4d23f219a8f6Thomas Hindoe Paaboel Andersen }
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (j->request_header) {
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (curl_easy_setopt(j->curl, CURLOPT_HTTPHEADER, j->request_header) != CURLE_OK)
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen return -EIO;
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering }
89ca10c6a61309d84d54c5dc5a295387ce39e610Lennart Poettering
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen if (curl_easy_setopt(j->curl, CURLOPT_WRITEFUNCTION, pull_job_write_callback) != CURLE_OK)
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen return -EIO;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen if (curl_easy_setopt(j->curl, CURLOPT_WRITEDATA, j) != CURLE_OK)
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen return -EIO;
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen if (curl_easy_setopt(j->curl, CURLOPT_HEADERFUNCTION, pull_job_header_callback) != CURLE_OK)
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen return -EIO;
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (curl_easy_setopt(j->curl, CURLOPT_HEADERDATA, j) != CURLE_OK)
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen return -EIO;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (curl_easy_setopt(j->curl, CURLOPT_XFERINFOFUNCTION, pull_job_progress_callback) != CURLE_OK)
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen return -EIO;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen if (curl_easy_setopt(j->curl, CURLOPT_XFERINFODATA, j) != CURLE_OK)
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen return -EIO;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen if (curl_easy_setopt(j->curl, CURLOPT_NOPROGRESS, 0) != CURLE_OK)
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen return -EIO;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen r = curl_glue_add(j->glue, j->curl);
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen if (r < 0)
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen return r;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen j->state = PULL_JOB_ANALYZING;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen return 0;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen}
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen