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"
45 TarImportFinished on_finished;
57 TarImport* tar_import_unref(TarImport *i) {
62 kill(i->tar_pid, SIGKILL);
63 wait_for_terminate(i->tar_pid, NULL);
66 import_job_unref(i->tar_job);
68 curl_glue_unref(i->glue);
69 sd_event_unref(i->event);
72 (void) btrfs_subvol_remove(i->temp_path);
73 (void) rm_rf_dangerous(i->temp_path, false, true, false);
86 int tar_import_new(TarImport **ret, sd_event *event, const char *image_root, TarImportFinished on_finished, void *userdata) {
87 _cleanup_(tar_import_unrefp) TarImport *i = NULL;
93 i = new0(TarImport, 1);
97 i->on_finished = on_finished;
98 i->userdata = userdata;
100 i->image_root = strdup(image_root ?: "/var/lib/machines");
105 i->event = sd_event_ref(event);
107 r = sd_event_default(&i->event);
112 r = curl_glue_new(&i->glue, i->event);
116 i->glue->on_finished = import_job_curl_on_finished;
117 i->glue->userdata = i;
125 static int tar_import_make_local_copy(TarImport *i) {
134 if (!i->final_path) {
135 r = import_make_path(i->tar_job->url, i->tar_job->etag, i->image_root, ".tar-", NULL, &i->final_path);
139 r = import_make_local_copy(i->final_path, i->image_root, i->local, i->force_local);
147 static void tar_import_job_on_finished(ImportJob *j) {
160 /* This is invoked if either the download completed
161 * successfully, or the download was skipped because we
162 * already have the etag. */
164 j->disk_fd = safe_close(j->disk_fd);
166 if (i->tar_pid > 0) {
167 r = wait_for_terminate_and_warn("tar", i->tar_pid, true);
174 r = import_make_read_only(i->temp_path);
178 if (rename(i->temp_path, i->final_path) < 0) {
179 r = log_error_errno(errno, "Failed to rename to final image name: %m");
187 r = tar_import_make_local_copy(i);
195 i->on_finished(i, r, i->userdata);
197 sd_event_exit(i->event, r);
200 static int tar_import_job_on_open_disk(ImportJob *j) {
201 _cleanup_close_pair_ int pipefd[2] = { -1 , -1 };
210 r = import_make_path(j->url, j->etag, i->image_root, ".tar-", NULL, &i->final_path);
214 r = tempfn_random(i->final_path, &i->temp_path);
218 mkdir_parents_label(i->temp_path, 0700);
220 r = btrfs_subvol_make(i->temp_path);
222 if (mkdir(i->temp_path, 0755) < 0)
223 return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
225 return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
227 if (pipe2(pipefd, O_CLOEXEC) < 0)
228 return log_error_errno(errno, "Failed to create pipe for tar: %m");
232 return log_error_errno(errno, "Failed to fork off tar: %m");
233 if (i->tar_pid == 0) {
236 reset_all_signal_handlers();
238 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
240 pipefd[1] = safe_close(pipefd[1]);
242 if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
243 log_error_errno(errno, "Failed to dup2() fd: %m");
247 if (pipefd[0] != STDIN_FILENO)
248 safe_close(pipefd[0]);
250 null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
252 log_error_errno(errno, "Failed to open /dev/null: %m");
256 if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
257 log_error_errno(errno, "Failed to dup2() fd: %m");
261 if (null_fd != STDOUT_FILENO)
264 execlp("tar", "tar", "--numeric-owner", "-C", i->temp_path, "-px", NULL);
268 pipefd[0] = safe_close(pipefd[0]);
270 j->disk_fd = pipefd[1];
276 int tar_import_pull(TarImport *i, const char *url, const char *local, bool force_local) {
284 if (!http_url_is_valid(url))
287 if (local && !machine_name_is_valid(local))
290 r = free_and_strdup(&i->local, local);
294 i->force_local = force_local;
296 r = import_job_new(&i->tar_job, url, i->glue, i);
300 i->tar_job->on_finished = tar_import_job_on_finished;
301 i->tar_job->on_open_disk = tar_import_job_on_open_disk;
303 r = import_find_old_etags(url, i->image_root, DT_DIR, ".tar-", NULL, &i->tar_job->old_etags);
307 return import_job_begin(i->tar_job);