importd: automatically download .roothash in addition to .nspawn for raw downloads
authorLennart Poettering <lennart@poettering.net>
Tue, 20 Dec 2016 16:49:35 +0000 (17:49 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 21 Dec 2016 18:09:31 +0000 (19:09 +0100)
Now that nspawn looks for these files, and mkosi generates them, we
should also make sure importd downloads them if it can.

src/import/pull-common.c
src/import/pull-common.h
src/import/pull-raw.c
src/import/pull-raw.h
src/import/pull-tar.c
src/import/pull.c

index 5ddc0c5..62a9195 100644 (file)
@@ -218,37 +218,40 @@ int pull_make_path(const char *url, const char *etag, const char *image_root, co
         return 0;
 }
 
-int pull_make_settings_job(
+int pull_make_auxiliary_job(
                 PullJob **ret,
                 const char *url,
+                int (*strip_suffixes)(const char *name, char **ret),
+                const char *suffix,
                 CurlGlue *glue,
                 PullJobFinished on_finished,
                 void *userdata) {
 
-        _cleanup_free_ char *last_component = NULL, *ll = NULL, *settings_url = NULL;
+        _cleanup_free_ char *last_component = NULL, *ll = NULL, *auxiliary_url = NULL;
         _cleanup_(pull_job_unrefp) PullJob *job = NULL;
         const char *q;
         int r;
 
         assert(ret);
         assert(url);
+        assert(strip_suffixes);
         assert(glue);
 
         r = import_url_last_component(url, &last_component);
         if (r < 0)
                 return r;
 
-        r = tar_strip_suffixes(last_component, &ll);
+        r = strip_suffixes(last_component, &ll);
         if (r < 0)
                 return r;
 
-        q = strjoina(ll, ".nspawn");
+        q = strjoina(ll, suffix);
 
-        r = import_url_change_last_component(url, q, &settings_url);
+        r = import_url_change_last_component(url, q, &auxiliary_url);
         if (r < 0)
                 return r;
 
-        r = pull_job_new(&job, settings_url, glue, userdata);
+        r = pull_job_new(&job, auxiliary_url, glue, userdata);
         if (r < 0)
                 return r;
 
@@ -320,45 +323,39 @@ int pull_make_verification_jobs(
         return 0;
 }
 
-int pull_verify(PullJob *main_job,
-                PullJob *settings_job,
-                PullJob *checksum_job,
-                PullJob *signature_job) {
-
-        _cleanup_close_pair_ int gpg_pipe[2] = { -1, -1 };
+static int verify_one(PullJob *checksum_job, PullJob *job) {
         _cleanup_free_ char *fn = NULL;
-        _cleanup_close_ int sig_file = -1;
-        const char *p, *line;
-        char sig_file_path[] = "/tmp/sigXXXXXX", gpg_home[] = "/tmp/gpghomeXXXXXX";
-        _cleanup_(sigkill_waitp) pid_t pid = 0;
-        bool gpg_home_created = false;
+        const char *line, *p;
         int r;
 
-        assert(main_job);
-        assert(main_job->state == PULL_JOB_DONE);
+        assert(checksum_job);
 
-        if (!checksum_job)
+        if (!job)
                 return 0;
 
-        assert(main_job->calc_checksum);
-        assert(main_job->checksum);
-        assert(checksum_job->state == PULL_JOB_DONE);
+        assert(IN_SET(job->state, PULL_JOB_DONE, PULL_JOB_FAILED));
 
-        if (!checksum_job->payload || checksum_job->payload_size <= 0) {
-                log_error("Checksum is empty, cannot verify.");
-                return -EBADMSG;
-        }
+        /* Don't verify the checksum if we didn't actually successfully download something new */
+        if (job->state != PULL_JOB_DONE)
+                return 0;
+        if (job->error != 0)
+                return 0;
+        if (job->etag_exists)
+                return 0;
 
-        r = import_url_last_component(main_job->url, &fn);
+        assert(job->calc_checksum);
+        assert(job->checksum);
+
+        r = import_url_last_component(job->url, &fn);
         if (r < 0)
                 return log_oom();
 
         if (!filename_is_valid(fn)) {
-                log_error("Cannot verify checksum, could not determine valid server-side file name.");
+                log_error("Cannot verify checksum, could not determine server-side file name.");
                 return -EBADMSG;
         }
 
-        line = strjoina(main_job->checksum, " *", fn, "\n");
+        line = strjoina(job->checksum, " *", fn, "\n");
 
         p = memmem(checksum_job->payload,
                    checksum_job->payload_size,
@@ -366,47 +363,55 @@ int pull_verify(PullJob *main_job,
                    strlen(line));
 
         if (!p || (p != (char*) checksum_job->payload && p[-1] != '\n')) {
-                log_error("DOWNLOAD INVALID: Checksum did not check out, payload has been tampered with.");
+                log_error("DOWNLOAD INVALID: Checksum of %s file did not checkout, file has been tampered with.", fn);
                 return -EBADMSG;
         }
 
-        log_info("SHA256 checksum of %s is valid.", main_job->url);
+        log_info("SHA256 checksum of %s is valid.", job->url);
+        return 1;
+}
 
-        assert(!settings_job || IN_SET(settings_job->state, PULL_JOB_DONE, PULL_JOB_FAILED));
+int pull_verify(PullJob *main_job,
+                PullJob *roothash_job,
+                PullJob *settings_job,
+                PullJob *checksum_job,
+                PullJob *signature_job) {
 
-        if (settings_job &&
-            settings_job->state == PULL_JOB_DONE &&
-            settings_job->error == 0 &&
-            !settings_job->etag_exists) {
+        _cleanup_close_pair_ int gpg_pipe[2] = { -1, -1 };
+        _cleanup_free_ char *fn = NULL;
+        _cleanup_close_ int sig_file = -1;
+        char sig_file_path[] = "/tmp/sigXXXXXX", gpg_home[] = "/tmp/gpghomeXXXXXX";
+        _cleanup_(sigkill_waitp) pid_t pid = 0;
+        bool gpg_home_created = false;
+        int r;
 
-                _cleanup_free_ char *settings_fn = NULL;
+        assert(main_job);
+        assert(main_job->state == PULL_JOB_DONE);
 
-                assert(settings_job->calc_checksum);
-                assert(settings_job->checksum);
+        if (!checksum_job)
+                return 0;
 
-                r = import_url_last_component(settings_job->url, &settings_fn);
-                if (r < 0)
-                        return log_oom();
+        assert(main_job->calc_checksum);
+        assert(main_job->checksum);
 
-                if (!filename_is_valid(settings_fn)) {
-                        log_error("Cannot verify checksum, could not determine server-side settings file name.");
-                        return -EBADMSG;
-                }
+        assert(checksum_job->state == PULL_JOB_DONE);
 
-                line = strjoina(settings_job->checksum, " *", settings_fn, "\n");
+        if (!checksum_job->payload || checksum_job->payload_size <= 0) {
+                log_error("Checksum is empty, cannot verify.");
+                return -EBADMSG;
+        }
 
-                p = memmem(checksum_job->payload,
-                           checksum_job->payload_size,
-                           line,
-                           strlen(line));
+        r = verify_one(checksum_job, main_job);
+        if (r < 0)
+                return r;
 
-                if (!p || (p != (char*) checksum_job->payload && p[-1] != '\n')) {
-                        log_error("DOWNLOAD INVALID: Checksum of settings file did not checkout, settings file has been tampered with.");
-                        return -EBADMSG;
-                }
+        r = verify_one(checksum_job, roothash_job);
+        if (r < 0)
+                return r;
 
-                log_info("SHA256 checksum of %s is valid.", settings_job->url);
-        }
+        r = verify_one(checksum_job, settings_job);
+        if (r < 0)
+                return r;
 
         if (!signature_job)
                 return 0;
index 929a131..f1f1a17 100644 (file)
@@ -30,7 +30,7 @@ int pull_find_old_etags(const char *url, const char *root, int dt, const char *p
 
 int pull_make_path(const char *url, const char *etag, const char *image_root, const char *prefix, const char *suffix, char **ret);
 
-int pull_make_settings_job(PullJob **ret, const char *url, CurlGlue *glue, PullJobFinished on_finished, void *userdata);
+int pull_make_auxiliary_job(PullJob **ret, const char *url, int (*strip_suffixes)(const char *name, char **ret), const char *suffix, CurlGlue *glue, PullJobFinished on_finished, void *userdata);
 int pull_make_verification_jobs(PullJob **ret_checksum_job, PullJob **ret_signature_job, ImportVerify verify, const char *url, CurlGlue *glue, PullJobFinished on_finished, void *userdata);
 
-int pull_verify(PullJob *main_job, PullJob *settings_job, PullJob *checksum_job, PullJob *signature_job);
+int pull_verify(PullJob *main_job, PullJob *roothash_job, PullJob *settings_job, PullJob *checksum_job, PullJob *signature_job);
index 0cf410a..ef7fb6a 100644 (file)
@@ -63,6 +63,7 @@ struct RawPull {
         char *image_root;
 
         PullJob *raw_job;
+        PullJob *roothash_job;
         PullJob *settings_job;
         PullJob *checksum_job;
         PullJob *signature_job;
@@ -74,6 +75,7 @@ struct RawPull {
         bool force_local;
         bool grow_machine_directory;
         bool settings;
+        bool roothash;
 
         char *final_path;
         char *temp_path;
@@ -81,6 +83,9 @@ struct RawPull {
         char *settings_path;
         char *settings_temp_path;
 
+        char *roothash_path;
+        char *roothash_temp_path;
+
         ImportVerify verify;
 };
 
@@ -90,6 +95,7 @@ RawPull* raw_pull_unref(RawPull *i) {
 
         pull_job_unref(i->raw_job);
         pull_job_unref(i->settings_job);
+        pull_job_unref(i->roothash_job);
         pull_job_unref(i->checksum_job);
         pull_job_unref(i->signature_job);
 
@@ -101,12 +107,18 @@ RawPull* raw_pull_unref(RawPull *i) {
                 free(i->temp_path);
         }
 
+        if (i->roothash_temp_path) {
+                (void) unlink(i->roothash_temp_path);
+                free(i->roothash_temp_path);
+        }
+
         if (i->settings_temp_path) {
                 (void) unlink(i->settings_temp_path);
                 free(i->settings_temp_path);
         }
 
         free(i->final_path);
+        free(i->roothash_path);
         free(i->settings_path);
         free(i->image_root);
         free(i->local);
@@ -176,6 +188,11 @@ static void raw_pull_report_progress(RawPull *i, RawProgress p) {
                         remain -= 5;
                 }
 
+                if (i->roothash_job) {
+                        percent += i->roothash_job->progress_percent * 5 / 100;
+                        remain -= 5;
+                }
+
                 if (i->checksum_job) {
                         percent += i->checksum_job->progress_percent * 5 / 100;
                         remain -= 5;
@@ -262,6 +279,55 @@ static int raw_pull_maybe_convert_qcow2(RawPull *i) {
         return 1;
 }
 
+static int raw_pull_determine_path(RawPull *i, const char *suffix, char **field) {
+        int r;
+
+        assert(i);
+        assert(field);
+
+        if (*field)
+                return 0;
+
+        assert(i->raw_job);
+
+        r = pull_make_path(i->raw_job->url, i->raw_job->etag, i->image_root, ".raw-", suffix, field);
+        if (r < 0)
+                return log_oom();
+
+        return 1;
+}
+
+static int raw_pull_copy_auxiliary_file(
+                RawPull *i,
+                const char *suffix,
+                char **path) {
+
+        const char *local;
+        int r;
+
+        assert(i);
+        assert(suffix);
+        assert(path);
+
+        r = raw_pull_determine_path(i, suffix, path);
+        if (r < 0)
+                return r;
+
+        local = strjoina(i->image_root, "/", i->local, suffix);
+
+        r = copy_file_atomic(*path, local, 0644, i->force_local, 0);
+        if (r == -EEXIST)
+                log_warning_errno(r, "File %s already exists, not replacing.", local);
+        else if (r == -ENOENT)
+                log_debug_errno(r, "Skipping creation of auxiliary file, since none was found.");
+        else if (r < 0)
+                log_warning_errno(r, "Failed to copy file %s, ignoring: %m", local);
+        else
+                log_info("Created new file %s.", local);
+
+        return 0;
+}
+
 static int raw_pull_make_local_copy(RawPull *i) {
         _cleanup_free_ char *tp = NULL;
         _cleanup_close_ int dfd = -1;
@@ -274,12 +340,6 @@ static int raw_pull_make_local_copy(RawPull *i) {
         if (!i->local)
                 return 0;
 
-        if (!i->final_path) {
-                r = pull_make_path(i->raw_job->url, i->raw_job->etag, i->image_root, ".raw-", ".raw", &i->final_path);
-                if (r < 0)
-                        return log_oom();
-        }
-
         if (i->raw_job->etag_exists) {
                 /* We have downloaded this one previously, reopen it */
 
@@ -338,27 +398,16 @@ static int raw_pull_make_local_copy(RawPull *i) {
 
         log_info("Created new local image '%s'.", i->local);
 
-        if (i->settings) {
-                const char *local_settings;
-                assert(i->settings_job);
-
-                if (!i->settings_path) {
-                        r = pull_make_path(i->settings_job->url, i->settings_job->etag, i->image_root, ".settings-", NULL, &i->settings_path);
-                        if (r < 0)
-                                return log_oom();
-                }
-
-                local_settings = strjoina(i->image_root, "/", i->local, ".nspawn");
+        if (i->roothash) {
+                r = raw_pull_copy_auxiliary_file(i, ".roothash", &i->roothash_path);
+                if (r < 0)
+                        return r;
+        }
 
-                r = copy_file_atomic(i->settings_path, local_settings, 0644, i->force_local, 0);
-                if (r == -EEXIST)
-                        log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
-                else if (r == -ENOENT)
-                        log_debug_errno(r, "Skipping creation of settings file, since none was found.");
-                else if (r < 0)
-                        log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings);
-                else
-                        log_info("Created new settings file %s.", local_settings);
+        if (i->settings) {
+                r = raw_pull_copy_auxiliary_file(i, ".nspawn", &i->settings_path);
+                if (r < 0)
+                        return r;
         }
 
         return 0;
@@ -370,6 +419,8 @@ static bool raw_pull_is_done(RawPull *i) {
 
         if (!PULL_JOB_IS_COMPLETE(i->raw_job))
                 return false;
+        if (i->roothash_job && !PULL_JOB_IS_COMPLETE(i->roothash_job))
+                return false;
         if (i->settings_job && !PULL_JOB_IS_COMPLETE(i->settings_job))
                 return false;
         if (i->checksum_job && !PULL_JOB_IS_COMPLETE(i->checksum_job))
@@ -380,6 +431,39 @@ static bool raw_pull_is_done(RawPull *i) {
         return true;
 }
 
+static int raw_pull_rename_auxiliary_file(
+                RawPull *i,
+                const char *suffix,
+                char **temp_path,
+                char **path) {
+
+        int r;
+
+        assert(i);
+        assert(temp_path);
+        assert(suffix);
+        assert(path);
+
+        /* Regenerate final name for this auxiliary file, we might know the etag of the raw file now, and we shoud
+         * incorporate it in the file name if we can */
+        *path = mfree(*path);
+        r = raw_pull_determine_path(i, suffix, path);
+        if (r < 0)
+                return r;
+
+        r = import_make_read_only(*temp_path);
+        if (r < 0)
+                return r;
+
+        r = rename_noreplace(AT_FDCWD, *temp_path, AT_FDCWD, *path);
+        if (r < 0)
+                return log_error_errno(r, "Failed to rename file %s to %s: %m", *temp_path, *path);
+
+        *temp_path = mfree(*temp_path);
+
+        return 1;
+}
+
 static void raw_pull_job_on_finished(PullJob *j) {
         RawPull *i;
         int r;
@@ -388,7 +472,10 @@ static void raw_pull_job_on_finished(PullJob *j) {
         assert(j->userdata);
 
         i = j->userdata;
-        if (j == i->settings_job) {
+        if (j == i->roothash_job) {
+                if (j->error != 0)
+                        log_info_errno(j->error, "Root hash file could not be retrieved, proceeding without.");
+        } else if (j == i->settings_job) {
                 if (j->error != 0)
                         log_info_errno(j->error, "Settings file could not be retrieved, proceeding without.");
         } else if (j->error != 0) {
@@ -413,16 +500,22 @@ static void raw_pull_job_on_finished(PullJob *j) {
         if (!raw_pull_is_done(i))
                 return;
 
+        if (i->roothash_job)
+                i->roothash_job->disk_fd = safe_close(i->roothash_job->disk_fd);
         if (i->settings_job)
                 i->settings_job->disk_fd = safe_close(i->settings_job->disk_fd);
 
+        r = raw_pull_determine_path(i, ".raw", &i->final_path);
+        if (r < 0)
+                goto finish;
+
         if (!i->raw_job->etag_exists) {
                 /* This is a new download, verify it, and move it into place */
                 assert(i->raw_job->disk_fd >= 0);
 
                 raw_pull_report_progress(i, RAW_VERIFYING);
 
-                r = pull_verify(i->raw_job, i->settings_job, i->checksum_job, i->signature_job);
+                r = pull_verify(i->raw_job, i->roothash_job, i->settings_job, i->checksum_job, i->signature_job);
                 if (r < 0)
                         goto finish;
 
@@ -446,24 +539,18 @@ static void raw_pull_job_on_finished(PullJob *j) {
 
                 i->temp_path = mfree(i->temp_path);
 
-                if (i->settings_job &&
-                    i->settings_job->error == 0 &&
-                    !i->settings_job->etag_exists) {
-
-                        assert(i->settings_temp_path);
-                        assert(i->settings_path);
-
-                        r = import_make_read_only(i->settings_temp_path);
+                if (i->roothash_job &&
+                    i->roothash_job->error == 0) {
+                        r = raw_pull_rename_auxiliary_file(i, ".roothash", &i->roothash_temp_path, &i->roothash_path);
                         if (r < 0)
                                 goto finish;
+                }
 
-                        r = rename_noreplace(AT_FDCWD, i->settings_temp_path, AT_FDCWD, i->settings_path);
-                        if (r < 0) {
-                                log_error_errno(r, "Failed to rename settings file: %m");
+                if (i->settings_job &&
+                    i->settings_job->error == 0) {
+                        r = raw_pull_rename_auxiliary_file(i, ".nspawn", &i->settings_temp_path, &i->settings_path);
+                        if (r < 0)
                                 goto finish;
-                        }
-
-                        i->settings_temp_path = mfree(i->settings_temp_path);
                 }
         }
 
@@ -482,6 +569,35 @@ finish:
                 sd_event_exit(i->event, r);
 }
 
+static int raw_pull_job_on_open_disk_generic(
+                RawPull *i,
+                PullJob *j,
+                const char *extra,
+                char **temp_path) {
+
+        _cleanup_free_ char *p = NULL;
+        int r;
+
+        assert(i);
+        assert(j);
+        assert(extra);
+        assert(temp_path);
+
+        if (!*temp_path) {
+                r = tempfn_random_child(i->image_root, extra, temp_path);
+                if (r < 0)
+                        return log_oom();
+        }
+
+        (void) mkdir_parents_label(*temp_path, 0700);
+
+        j->disk_fd = open(*temp_path, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
+        if (j->disk_fd < 0)
+                return log_error_errno(errno, "Failed to create %s: %m", *temp_path);
+
+        return 0;
+}
+
 static int raw_pull_job_on_open_disk_raw(PullJob *j) {
         RawPull *i;
         int r;
@@ -491,57 +607,40 @@ static int raw_pull_job_on_open_disk_raw(PullJob *j) {
 
         i = j->userdata;
         assert(i->raw_job == j);
-        assert(!i->final_path);
-        assert(!i->temp_path);
-
-        r = pull_make_path(j->url, j->etag, i->image_root, ".raw-", ".raw", &i->final_path);
-        if (r < 0)
-                return log_oom();
 
-        r = tempfn_random(i->final_path, NULL, &i->temp_path);
+        r = raw_pull_job_on_open_disk_generic(i, j, "raw", &i->temp_path);
         if (r < 0)
-                return log_oom();
-
-        (void) mkdir_parents_label(i->temp_path, 0700);
-
-        j->disk_fd = open(i->temp_path, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
-        if (j->disk_fd < 0)
-                return log_error_errno(errno, "Failed to create %s: %m", i->temp_path);
+                return r;
 
         r = chattr_fd(j->disk_fd, FS_NOCOW_FL, FS_NOCOW_FL);
         if (r < 0)
-                log_warning_errno(r, "Failed to set file attributes on %s: %m", i->temp_path);
+                log_warning_errno(r, "Failed to set file attributes on %s, ignoring: %m", i->temp_path);
 
         return 0;
 }
 
-static int raw_pull_job_on_open_disk_settings(PullJob *j) {
+static int raw_pull_job_on_open_disk_roothash(PullJob *j) {
         RawPull *i;
-        int r;
 
         assert(j);
         assert(j->userdata);
 
         i = j->userdata;
-        assert(i->settings_job == j);
-        assert(!i->settings_path);
-        assert(!i->settings_temp_path);
+        assert(i->roothash_job == j);
 
-        r = pull_make_path(j->url, j->etag, i->image_root, ".settings-", NULL, &i->settings_path);
-        if (r < 0)
-                return log_oom();
+        return raw_pull_job_on_open_disk_generic(i, j, "roothash", &i->roothash_temp_path);
+}
 
-        r = tempfn_random(i->settings_path, NULL, &i->settings_temp_path);
-        if (r < 0)
-                return log_oom();
+static int raw_pull_job_on_open_disk_settings(PullJob *j) {
+        RawPull *i;
 
-        mkdir_parents_label(i->settings_temp_path, 0700);
+        assert(j);
+        assert(j->userdata);
 
-        j->disk_fd = open(i->settings_temp_path, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
-        if (j->disk_fd < 0)
-                return log_error_errno(errno, "Failed to create %s: %m", i->settings_temp_path);
+        i = j->userdata;
+        assert(i->settings_job == j);
 
-        return 0;
+        return raw_pull_job_on_open_disk_generic(i, j, "settings", &i->settings_temp_path);
 }
 
 static void raw_pull_job_on_progress(PullJob *j) {
@@ -561,7 +660,8 @@ int raw_pull_start(
                 const char *local,
                 bool force_local,
                 ImportVerify verify,
-                bool settings) {
+                bool settings,
+                bool roothash) {
 
         int r;
 
@@ -585,6 +685,7 @@ int raw_pull_start(
         i->force_local = force_local;
         i->verify = verify;
         i->settings = settings;
+        i->roothash = roothash;
 
         /* Queue job for the image itself */
         r = pull_job_new(&i->raw_job, url, i->glue, i);
@@ -601,18 +702,24 @@ int raw_pull_start(
         if (r < 0)
                 return r;
 
+        if (roothash) {
+                r = pull_make_auxiliary_job(&i->roothash_job, url, raw_strip_suffixes, ".roothash", i->glue, raw_pull_job_on_finished, i);
+                if (r < 0)
+                        return r;
+
+                i->roothash_job->on_open_disk = raw_pull_job_on_open_disk_roothash;
+                i->roothash_job->on_progress = raw_pull_job_on_progress;
+                i->roothash_job->calc_checksum = verify != IMPORT_VERIFY_NO;
+        }
+
         if (settings) {
-                r = pull_make_settings_job(&i->settings_job, url, i->glue, raw_pull_job_on_finished, i);
+                r = pull_make_auxiliary_job(&i->settings_job, url, raw_strip_suffixes, ".nspawn", i->glue, raw_pull_job_on_finished, i);
                 if (r < 0)
                         return r;
 
                 i->settings_job->on_open_disk = raw_pull_job_on_open_disk_settings;
                 i->settings_job->on_progress = raw_pull_job_on_progress;
                 i->settings_job->calc_checksum = verify != IMPORT_VERIFY_NO;
-
-                r = pull_find_old_etags(i->settings_job->url, i->image_root, DT_REG, ".settings-", NULL, &i->settings_job->old_etags);
-                if (r < 0)
-                        return r;
         }
 
         r = pull_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, raw_pull_job_on_finished, i);
@@ -623,6 +730,12 @@ int raw_pull_start(
         if (r < 0)
                 return r;
 
+        if (i->roothash_job) {
+                r = pull_job_begin(i->roothash_job);
+                if (r < 0)
+                        return r;
+        }
+
         if (i->settings_job) {
                 r = pull_job_begin(i->settings_job);
                 if (r < 0)
index 8f6d16e..6954d98 100644 (file)
@@ -33,4 +33,4 @@ RawPull* raw_pull_unref(RawPull *pull);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(RawPull*, raw_pull_unref);
 
-int raw_pull_start(RawPull *pull, const char *url, const char *local, bool force_local, ImportVerify verify, bool settings);
+int raw_pull_start(RawPull *pull, const char *url, const char *local, bool force_local, ImportVerify verify, bool settings, bool roothash);
index 68e2397..375ee77 100644 (file)
@@ -215,6 +215,24 @@ static void tar_pull_report_progress(TarPull *i, TarProgress p) {
         log_debug("Combined progress %u%%", percent);
 }
 
+static int tar_pull_determine_path(TarPull *i, const char *suffix, char **field) {
+        int r;
+
+        assert(i);
+        assert(field);
+
+        if (*field)
+                return 0;
+
+        assert(i->tar_job);
+
+        r = pull_make_path(i->tar_job->url, i->tar_job->etag, i->image_root, ".tar-", suffix, field);
+        if (r < 0)
+                return log_oom();
+
+        return 1;
+}
+
 static int tar_pull_make_local_copy(TarPull *i) {
         int r;
 
@@ -224,12 +242,6 @@ static int tar_pull_make_local_copy(TarPull *i) {
         if (!i->local)
                 return 0;
 
-        if (!i->final_path) {
-                r = pull_make_path(i->tar_job->url, i->tar_job->etag, i->image_root, ".tar-", NULL, &i->final_path);
-                if (r < 0)
-                        return log_oom();
-        }
-
         r = pull_make_local_copy(i->final_path, i->image_root, i->local, i->force_local);
         if (r < 0)
                 return r;
@@ -238,11 +250,9 @@ static int tar_pull_make_local_copy(TarPull *i) {
                 const char *local_settings;
                 assert(i->settings_job);
 
-                if (!i->settings_path) {
-                        r = pull_make_path(i->settings_job->url, i->settings_job->etag, i->image_root, ".settings-", NULL, &i->settings_path);
-                        if (r < 0)
-                                return log_oom();
-                }
+                r = tar_pull_determine_path(i, ".nspawn", &i->settings_path);
+                if (r < 0)
+                        return r;
 
                 local_settings = strjoina(i->image_root, "/", i->local, ".nspawn");
 
@@ -311,6 +321,10 @@ static void tar_pull_job_on_finished(PullJob *j) {
         if (i->settings_job)
                 i->settings_job->disk_fd = safe_close(i->settings_job->disk_fd);
 
+        r = tar_pull_determine_path(i, NULL, &i->final_path);
+        if (r < 0)
+                goto finish;
+
         if (i->tar_pid > 0) {
                 r = wait_for_terminate_and_warn("tar", i->tar_pid, true);
                 i->tar_pid = 0;
@@ -327,7 +341,7 @@ static void tar_pull_job_on_finished(PullJob *j) {
 
                 tar_pull_report_progress(i, TAR_VERIFYING);
 
-                r = pull_verify(i->tar_job, i->settings_job, i->checksum_job, i->signature_job);
+                r = pull_verify(i->tar_job, NULL, i->settings_job, i->checksum_job, i->signature_job);
                 if (r < 0)
                         goto finish;
 
@@ -346,16 +360,18 @@ static void tar_pull_job_on_finished(PullJob *j) {
                 i->temp_path = mfree(i->temp_path);
 
                 if (i->settings_job &&
-                    i->settings_job->error == 0 &&
-                    !i->settings_job->etag_exists) {
+                    i->settings_job->error == 0) {
 
                         assert(i->settings_temp_path);
                         assert(i->settings_path);
 
-                        /* Also move the settings file into place, if
-                         * it exist. Note that we do so only if we
-                         * also moved the tar file in place, to keep
-                         * things strictly in sync. */
+                        /* Also move the settings file into place, if it exist. Note that we do so only if we also
+                         * moved the tar file in place, to keep things strictly in sync. */
+
+                        i->settings_path = mfree(i->settings_path);
+                        r = tar_pull_determine_path(i, ".nspawn", &i->settings_path);
+                        if (r < 0)
+                                goto finish;
 
                         r = import_make_read_only(i->settings_temp_path);
                         if (r < 0)
@@ -395,17 +411,13 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
 
         i = j->userdata;
         assert(i->tar_job == j);
-        assert(!i->final_path);
-        assert(!i->temp_path);
         assert(i->tar_pid <= 0);
 
-        r = pull_make_path(j->url, j->etag, i->image_root, ".tar-", NULL, &i->final_path);
-        if (r < 0)
-                return log_oom();
-
-        r = tempfn_random(i->final_path, NULL, &i->temp_path);
-        if (r < 0)
-                return log_oom();
+        if (!i->temp_path) {
+                r = tempfn_random_child(i->image_root, "tar", &i->temp_path);
+                if (r < 0)
+                        return log_oom();
+        }
 
         mkdir_parents_label(i->temp_path, 0700);
 
@@ -434,16 +446,12 @@ static int tar_pull_job_on_open_disk_settings(PullJob *j) {
 
         i = j->userdata;
         assert(i->settings_job == j);
-        assert(!i->settings_path);
-        assert(!i->settings_temp_path);
 
-        r = pull_make_path(j->url, j->etag, i->image_root, ".settings-", NULL, &i->settings_path);
-        if (r < 0)
-                return log_oom();
-
-        r = tempfn_random(i->settings_path, NULL, &i->settings_temp_path);
-        if (r < 0)
-                return log_oom();
+        if (!i->settings_temp_path) {
+                r = tempfn_random_child(i->image_root, "settings", &i->settings_temp_path);
+                if (r < 0)
+                        return log_oom();
+        }
 
         mkdir_parents_label(i->settings_temp_path, 0700);
 
@@ -513,17 +521,13 @@ int tar_pull_start(
 
         /* Set up download job for the settings file (.nspawn) */
         if (settings) {
-                r = pull_make_settings_job(&i->settings_job, url, i->glue, tar_pull_job_on_finished, i);
+                r = pull_make_auxiliary_job(&i->settings_job, url, tar_strip_suffixes, ".nspawn", i->glue, tar_pull_job_on_finished, i);
                 if (r < 0)
                         return r;
 
                 i->settings_job->on_open_disk = tar_pull_job_on_open_disk_settings;
                 i->settings_job->on_progress = tar_pull_job_on_progress;
                 i->settings_job->calc_checksum = verify != IMPORT_VERIFY_NO;
-
-                r = pull_find_old_etags(i->settings_job->url, i->image_root, DT_REG, ".settings-", NULL, &i->settings_job->old_etags);
-                if (r < 0)
-                        return r;
         }
 
         /* Set up download of checksum/signature files */
index 53b1211..4af5d9c 100644 (file)
@@ -37,6 +37,7 @@ static bool arg_force = false;
 static const char *arg_image_root = "/var/lib/machines";
 static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
 static bool arg_settings = true;
+static bool arg_roothash = true;
 
 static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
         log_notice("Transfer aborted.");
@@ -204,7 +205,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Failed to allocate puller: %m");
 
-        r = raw_pull_start(pull, url, local, arg_force, arg_verify, arg_settings);
+        r = raw_pull_start(pull, url, local, arg_force, arg_verify, arg_settings, arg_roothash);
         if (r < 0)
                 return log_error_errno(r, "Failed to pull image: %m");
 
@@ -226,6 +227,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "     --verify=MODE            Verify downloaded image, one of: 'no',\n"
                "                              'checksum', 'signature'\n"
                "     --settings=BOOL          Download settings file with image\n"
+               "     --roothash=BOOL          Download root hash file with image\n"
                "     --image-root=PATH        Image root directory\n\n"
                "Commands:\n"
                "  tar URL [NAME]              Download a TAR image\n"
@@ -243,6 +245,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_IMAGE_ROOT,
                 ARG_VERIFY,
                 ARG_SETTINGS,
+                ARG_ROOTHASH,
         };
 
         static const struct option options[] = {
@@ -252,6 +255,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "image-root",      required_argument, NULL, ARG_IMAGE_ROOT      },
                 { "verify",          required_argument, NULL, ARG_VERIFY          },
                 { "settings",        required_argument, NULL, ARG_SETTINGS        },
+                { "roothash",        required_argument, NULL, ARG_ROOTHASH        },
                 {}
         };
 
@@ -295,6 +299,14 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_settings = r;
                         break;
 
+                case ARG_ROOTHASH:
+                        r = parse_boolean(optarg);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse --roothash= parameter '%s'", optarg);
+
+                        arg_roothash = r;
+                        break;
+
                 case '?':
                         return -EINVAL;