1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2015 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/prctl.h>
23 #include <curl/curl.h>
28 #include "btrfs-util.h"
32 #include "import-util.h"
33 #include "curl-util.h"
34 #include "import-job.h"
35 #include "import-common.h"
36 #include "import-tar.h"
45 ImportJob *checksum_job;
46 ImportJob *signature_job;
48 TarImportFinished on_finished;
62 TarImport* tar_import_unref(TarImport *i) {
67 (void) kill_and_sigcont(i->tar_pid, SIGKILL);
68 (void) wait_for_terminate(i->tar_pid, NULL);
71 import_job_unref(i->tar_job);
72 import_job_unref(i->checksum_job);
73 import_job_unref(i->signature_job);
75 curl_glue_unref(i->glue);
76 sd_event_unref(i->event);
79 (void) btrfs_subvol_remove(i->temp_path);
80 (void) rm_rf_dangerous(i->temp_path, false, true, false);
95 const char *image_root,
96 TarImportFinished on_finished,
99 _cleanup_(tar_import_unrefp) TarImport *i = NULL;
105 i = new0(TarImport, 1);
109 i->on_finished = on_finished;
110 i->userdata = userdata;
112 i->image_root = strdup(image_root ?: "/var/lib/machines");
117 i->event = sd_event_ref(event);
119 r = sd_event_default(&i->event);
124 r = curl_glue_new(&i->glue, i->event);
128 i->glue->on_finished = import_job_curl_on_finished;
129 i->glue->userdata = i;
137 static int tar_import_make_local_copy(TarImport *i) {
146 if (!i->final_path) {
147 r = import_make_path(i->tar_job->url, i->tar_job->etag, i->image_root, ".tar-", NULL, &i->final_path);
152 r = import_make_local_copy(i->final_path, i->image_root, i->local, i->force_local);
159 static bool tar_import_is_done(TarImport *i) {
163 if (i->tar_job->state != IMPORT_JOB_DONE)
165 if (i->checksum_job && i->checksum_job->state != IMPORT_JOB_DONE)
167 if (i->signature_job && i->signature_job->state != IMPORT_JOB_DONE)
173 static void tar_import_job_on_finished(ImportJob *j) {
182 if (j == i->checksum_job)
183 log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)");
184 else if (j == i->signature_job)
185 log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
187 log_error_errno(j->error, "Failed to retrieve image file. (Wrong URL?)");
193 /* This is invoked if either the download completed
194 * successfully, or the download was skipped because we
195 * already have the etag. */
197 if (!tar_import_is_done(i))
200 j->disk_fd = safe_close(i->tar_job->disk_fd);
202 if (i->tar_pid > 0) {
203 r = wait_for_terminate_and_warn("tar", i->tar_pid, true);
209 if (!i->tar_job->etag_exists) {
210 /* This is a new download, verify it, and move it into place */
212 r = import_verify(i->tar_job, i->checksum_job, i->signature_job);
216 r = import_make_read_only(i->temp_path);
220 if (rename(i->temp_path, i->final_path) < 0) {
221 r = log_error_errno(errno, "Failed to rename to final image name: %m");
229 r = tar_import_make_local_copy(i);
237 i->on_finished(i, r, i->userdata);
239 sd_event_exit(i->event, r);
242 static int tar_import_job_on_open_disk(ImportJob *j) {
243 _cleanup_close_pair_ int pipefd[2] = { -1 , -1 };
251 assert(i->tar_job == j);
252 assert(!i->final_path);
253 assert(!i->temp_path);
254 assert(i->tar_pid <= 0);
256 r = import_make_path(j->url, j->etag, i->image_root, ".tar-", NULL, &i->final_path);
260 r = tempfn_random(i->final_path, &i->temp_path);
264 mkdir_parents_label(i->temp_path, 0700);
266 r = btrfs_subvol_make(i->temp_path);
268 if (mkdir(i->temp_path, 0755) < 0)
269 return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
271 return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
273 if (pipe2(pipefd, O_CLOEXEC) < 0)
274 return log_error_errno(errno, "Failed to create pipe for tar: %m");
278 return log_error_errno(errno, "Failed to fork off tar: %m");
279 if (i->tar_pid == 0) {
284 reset_all_signal_handlers();
286 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
288 pipefd[1] = safe_close(pipefd[1]);
290 if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
291 log_error_errno(errno, "Failed to dup2() fd: %m");
295 if (pipefd[0] != STDIN_FILENO)
296 pipefd[0] = safe_close(pipefd[0]);
298 null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
300 log_error_errno(errno, "Failed to open /dev/null: %m");
304 if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
305 log_error_errno(errno, "Failed to dup2() fd: %m");
309 if (null_fd != STDOUT_FILENO)
310 null_fd = safe_close(null_fd);
312 fd_cloexec(STDIN_FILENO, false);
313 fd_cloexec(STDOUT_FILENO, false);
314 fd_cloexec(STDERR_FILENO, false);
316 execlp("tar", "tar", "--numeric-owner", "-C", i->temp_path, "-px", NULL);
317 log_error_errno(errno, "Failed to execute tar: %m");
321 pipefd[0] = safe_close(pipefd[0]);
323 j->disk_fd = pipefd[1];
329 int tar_import_pull(TarImport *i, const char *url, const char *local, bool force_local, ImportVerify verify) {
334 if (!http_url_is_valid(url))
337 if (local && !machine_name_is_valid(local))
343 r = free_and_strdup(&i->local, local);
346 i->force_local = force_local;
349 r = import_job_new(&i->tar_job, url, i->glue, i);
353 i->tar_job->on_finished = tar_import_job_on_finished;
354 i->tar_job->on_open_disk = tar_import_job_on_open_disk;
355 i->tar_job->calc_checksum = verify != IMPORT_VERIFY_NO;
357 r = import_find_old_etags(url, i->image_root, DT_DIR, ".tar-", NULL, &i->tar_job->old_etags);
361 r = import_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, tar_import_job_on_finished, i);
365 r = import_job_begin(i->tar_job);
369 if (i->checksum_job) {
370 r = import_job_begin(i->checksum_job);
375 if (i->signature_job) {
376 r = import_job_begin(i->signature_job);