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 "curl-util.h"
33 #include "import-job.h"
34 #include "import-util.h"
35 #include "import-tar.h"
44 ImportJob *checksum_job;
45 ImportJob *signature_job;
47 TarImportFinished on_finished;
61 TarImport* tar_import_unref(TarImport *i) {
66 (void) kill_and_sigcont(i->tar_pid, SIGKILL);
67 (void) wait_for_terminate(i->tar_pid, NULL);
70 import_job_unref(i->tar_job);
71 import_job_unref(i->checksum_job);
72 import_job_unref(i->signature_job);
74 curl_glue_unref(i->glue);
75 sd_event_unref(i->event);
78 (void) btrfs_subvol_remove(i->temp_path);
79 (void) rm_rf_dangerous(i->temp_path, false, true, false);
94 const char *image_root,
95 TarImportFinished on_finished,
98 _cleanup_(tar_import_unrefp) TarImport *i = NULL;
104 i = new0(TarImport, 1);
108 i->on_finished = on_finished;
109 i->userdata = userdata;
111 i->image_root = strdup(image_root ?: "/var/lib/machines");
116 i->event = sd_event_ref(event);
118 r = sd_event_default(&i->event);
123 r = curl_glue_new(&i->glue, i->event);
127 i->glue->on_finished = import_job_curl_on_finished;
128 i->glue->userdata = i;
136 static int tar_import_make_local_copy(TarImport *i) {
145 if (!i->final_path) {
146 r = import_make_path(i->tar_job->url, i->tar_job->etag, i->image_root, ".tar-", NULL, &i->final_path);
151 r = import_make_local_copy(i->final_path, i->image_root, i->local, i->force_local);
158 static bool tar_import_is_done(TarImport *i) {
162 if (i->tar_job->state != IMPORT_JOB_DONE)
164 if (i->checksum_job && i->checksum_job->state != IMPORT_JOB_DONE)
166 if (i->signature_job && i->signature_job->state != IMPORT_JOB_DONE)
172 static void tar_import_job_on_finished(ImportJob *j) {
181 if (j == i->checksum_job)
182 log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)");
183 else if (j == i->signature_job)
184 log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
186 log_error_errno(j->error, "Failed to retrieve image file. (Wrong URL?)");
192 /* This is invoked if either the download completed
193 * successfully, or the download was skipped because we
194 * already have the etag. */
196 if (!tar_import_is_done(i))
199 j->disk_fd = safe_close(i->tar_job->disk_fd);
201 if (i->tar_pid > 0) {
202 r = wait_for_terminate_and_warn("tar", i->tar_pid, true);
208 if (!i->tar_job->etag_exists) {
209 /* This is a new download, verify it, and move it into place */
211 r = import_verify(i->tar_job, i->checksum_job, i->signature_job);
215 r = import_make_read_only(i->temp_path);
219 if (rename(i->temp_path, i->final_path) < 0) {
220 r = log_error_errno(errno, "Failed to rename to final image name: %m");
228 r = tar_import_make_local_copy(i);
236 i->on_finished(i, r, i->userdata);
238 sd_event_exit(i->event, r);
241 static int tar_import_job_on_open_disk(ImportJob *j) {
242 _cleanup_close_pair_ int pipefd[2] = { -1 , -1 };
250 assert(i->tar_job == j);
251 assert(!i->final_path);
252 assert(!i->temp_path);
253 assert(i->tar_pid <= 0);
255 r = import_make_path(j->url, j->etag, i->image_root, ".tar-", NULL, &i->final_path);
259 r = tempfn_random(i->final_path, &i->temp_path);
263 mkdir_parents_label(i->temp_path, 0700);
265 r = btrfs_subvol_make(i->temp_path);
267 if (mkdir(i->temp_path, 0755) < 0)
268 return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
270 return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
272 if (pipe2(pipefd, O_CLOEXEC) < 0)
273 return log_error_errno(errno, "Failed to create pipe for tar: %m");
277 return log_error_errno(errno, "Failed to fork off tar: %m");
278 if (i->tar_pid == 0) {
283 reset_all_signal_handlers();
285 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
287 pipefd[1] = safe_close(pipefd[1]);
289 if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
290 log_error_errno(errno, "Failed to dup2() fd: %m");
294 if (pipefd[0] != STDIN_FILENO)
295 pipefd[0] = safe_close(pipefd[0]);
297 null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
299 log_error_errno(errno, "Failed to open /dev/null: %m");
303 if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
304 log_error_errno(errno, "Failed to dup2() fd: %m");
308 if (null_fd != STDOUT_FILENO)
309 null_fd = safe_close(null_fd);
311 fd_cloexec(STDIN_FILENO, false);
312 fd_cloexec(STDOUT_FILENO, false);
313 fd_cloexec(STDERR_FILENO, false);
315 execlp("tar", "tar", "--numeric-owner", "-C", i->temp_path, "-px", NULL);
316 log_error_errno(errno, "Failed to execute tar: %m");
320 pipefd[0] = safe_close(pipefd[0]);
322 j->disk_fd = pipefd[1];
328 int tar_import_pull(TarImport *i, const char *url, const char *local, bool force_local, ImportVerify verify) {
333 if (!http_url_is_valid(url))
336 if (local && !machine_name_is_valid(local))
342 r = free_and_strdup(&i->local, local);
345 i->force_local = force_local;
348 r = import_job_new(&i->tar_job, url, i->glue, i);
352 i->tar_job->on_finished = tar_import_job_on_finished;
353 i->tar_job->on_open_disk = tar_import_job_on_open_disk;
354 i->tar_job->calc_checksum = verify != IMPORT_VERIFY_NO;
356 r = import_find_old_etags(url, i->image_root, DT_DIR, ".tar-", NULL, &i->tar_job->old_etags);
360 r = import_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, tar_import_job_on_finished, i);
364 r = import_job_begin(i->tar_job);
368 if (i->checksum_job) {
369 r = import_job_begin(i->checksum_job);
374 if (i->signature_job) {
375 r = import_job_begin(i->signature_job);