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(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);
91 int tar_import_new(TarImport **ret, sd_event *event, const char *image_root, TarImportFinished on_finished, void *userdata) {
92 _cleanup_(tar_import_unrefp) TarImport *i = NULL;
98 i = new0(TarImport, 1);
102 i->on_finished = on_finished;
103 i->userdata = userdata;
105 i->image_root = strdup(image_root ?: "/var/lib/machines");
110 i->event = sd_event_ref(event);
112 r = sd_event_default(&i->event);
117 r = curl_glue_new(&i->glue, i->event);
121 i->glue->on_finished = import_job_curl_on_finished;
122 i->glue->userdata = i;
130 static int tar_import_make_local_copy(TarImport *i) {
139 if (!i->final_path) {
140 r = import_make_path(i->tar_job->url, i->tar_job->etag, i->image_root, ".tar-", NULL, &i->final_path);
145 r = import_make_local_copy(i->final_path, i->image_root, i->local, i->force_local);
152 static void tar_import_job_on_finished(ImportJob *j) {
161 if (j == i->checksum_job)
162 log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)");
163 else if (j == i->signature_job)
164 log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
166 log_error_errno(j->error, "Failed to retrieve image file. (Wrong URL?)");
172 /* This is invoked if either the download completed
173 * successfully, or the download was skipped because we
174 * already have the etag. */
176 if (i->tar_job->state != IMPORT_JOB_DONE)
178 if (i->checksum_job && i->checksum_job->state != IMPORT_JOB_DONE)
180 if (i->signature_job && i->signature_job->state != IMPORT_JOB_DONE)
183 j->disk_fd = safe_close(i->tar_job->disk_fd);
185 if (i->tar_pid > 0) {
186 r = wait_for_terminate_and_warn("tar", i->tar_pid, true);
192 if (!i->tar_job->etag_exists) {
193 /* This is a new download, verify it, and move it into place */
195 r = import_verify(i->tar_job, i->checksum_job, i->signature_job);
199 r = import_make_read_only(i->temp_path);
203 if (rename(i->temp_path, i->final_path) < 0) {
204 r = log_error_errno(errno, "Failed to rename to final image name: %m");
212 r = tar_import_make_local_copy(i);
220 i->on_finished(i, r, i->userdata);
222 sd_event_exit(i->event, r);
225 static int tar_import_job_on_open_disk(ImportJob *j) {
226 _cleanup_close_pair_ int pipefd[2] = { -1 , -1 };
235 r = import_make_path(j->url, j->etag, i->image_root, ".tar-", NULL, &i->final_path);
239 r = tempfn_random(i->final_path, &i->temp_path);
243 mkdir_parents_label(i->temp_path, 0700);
245 r = btrfs_subvol_make(i->temp_path);
247 if (mkdir(i->temp_path, 0755) < 0)
248 return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
250 return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
252 if (pipe2(pipefd, O_CLOEXEC) < 0)
253 return log_error_errno(errno, "Failed to create pipe for tar: %m");
257 return log_error_errno(errno, "Failed to fork off tar: %m");
258 if (i->tar_pid == 0) {
263 reset_all_signal_handlers();
265 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
267 pipefd[1] = safe_close(pipefd[1]);
269 if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
270 log_error_errno(errno, "Failed to dup2() fd: %m");
274 if (pipefd[0] != STDIN_FILENO)
275 safe_close(pipefd[0]);
277 null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
279 log_error_errno(errno, "Failed to open /dev/null: %m");
283 if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
284 log_error_errno(errno, "Failed to dup2() fd: %m");
288 if (null_fd != STDOUT_FILENO)
291 execlp("tar", "tar", "--numeric-owner", "-C", i->temp_path, "-px", NULL);
292 log_error_errno(errno, "Failed to execute tar: %m");
296 pipefd[0] = safe_close(pipefd[0]);
298 j->disk_fd = pipefd[1];
304 int tar_import_pull(TarImport *i, const char *url, const char *local, bool force_local, ImportVerify verify) {
312 if (!http_url_is_valid(url))
315 if (local && !machine_name_is_valid(local))
318 r = free_and_strdup(&i->local, local);
321 i->force_local = force_local;
324 r = import_job_new(&i->tar_job, url, i->glue, i);
328 i->tar_job->on_finished = tar_import_job_on_finished;
329 i->tar_job->on_open_disk = tar_import_job_on_open_disk;
330 i->tar_job->calc_checksum = verify != IMPORT_VERIFY_NO;
332 r = import_find_old_etags(url, i->image_root, DT_DIR, ".tar-", NULL, &i->tar_job->old_etags);
336 r = import_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, tar_import_job_on_finished, i);
340 r = import_job_begin(i->tar_job);
344 if (i->checksum_job) {
345 r = import_job_begin(i->checksum_job);
350 if (i->signature_job) {
351 r = import_job_begin(i->signature_job);