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>
25 #include "sd-daemon.h"
29 #include "btrfs-util.h"
34 #include "path-util.h"
35 #include "import-util.h"
36 #include "import-common.h"
37 #include "curl-util.h"
39 #include "pull-common.h"
41 #include "process-util.h"
43 typedef enum TarProgress
{
57 PullJob
*checksum_job
;
58 PullJob
*signature_job
;
60 TarPullFinished on_finished
;
65 bool grow_machine_directory
;
75 TarPull
* tar_pull_unref(TarPull
*i
) {
80 (void) kill_and_sigcont(i
->tar_pid
, SIGKILL
);
81 (void) wait_for_terminate(i
->tar_pid
, NULL
);
84 pull_job_unref(i
->tar_job
);
85 pull_job_unref(i
->checksum_job
);
86 pull_job_unref(i
->signature_job
);
88 curl_glue_unref(i
->glue
);
89 sd_event_unref(i
->event
);
92 (void) rm_rf(i
->temp_path
, REMOVE_ROOT
|REMOVE_PHYSICAL
|REMOVE_SUBVOLUME
);
107 const char *image_root
,
108 TarPullFinished on_finished
,
111 _cleanup_(tar_pull_unrefp
) TarPull
*i
= NULL
;
117 i
= new0(TarPull
, 1);
121 i
->on_finished
= on_finished
;
122 i
->userdata
= userdata
;
124 i
->image_root
= strdup(image_root
?: "/var/lib/machines");
128 i
->grow_machine_directory
= path_startswith(i
->image_root
, "/var/lib/machines");
131 i
->event
= sd_event_ref(event
);
133 r
= sd_event_default(&i
->event
);
138 r
= curl_glue_new(&i
->glue
, i
->event
);
142 i
->glue
->on_finished
= pull_job_curl_on_finished
;
143 i
->glue
->userdata
= i
;
151 static void tar_pull_report_progress(TarPull
*i
, TarProgress p
) {
158 case TAR_DOWNLOADING
: {
159 unsigned remain
= 85;
163 if (i
->checksum_job
) {
164 percent
+= i
->checksum_job
->progress_percent
* 5 / 100;
168 if (i
->signature_job
) {
169 percent
+= i
->signature_job
->progress_percent
* 5 / 100;
174 percent
+= i
->tar_job
->progress_percent
* remain
/ 100;
191 assert_not_reached("Unknown progress state");
194 sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent
);
195 log_debug("Combined progress %u%%", percent
);
198 static int tar_pull_make_local_copy(TarPull
*i
) {
207 if (!i
->final_path
) {
208 r
= pull_make_path(i
->tar_job
->url
, i
->tar_job
->etag
, i
->image_root
, ".tar-", NULL
, &i
->final_path
);
213 r
= pull_make_local_copy(i
->final_path
, i
->image_root
, i
->local
, i
->force_local
);
220 static bool tar_pull_is_done(TarPull
*i
) {
224 if (i
->tar_job
->state
!= PULL_JOB_DONE
)
226 if (i
->checksum_job
&& i
->checksum_job
->state
!= PULL_JOB_DONE
)
228 if (i
->signature_job
&& i
->signature_job
->state
!= PULL_JOB_DONE
)
234 static void tar_pull_job_on_finished(PullJob
*j
) {
243 if (j
== i
->checksum_job
)
244 log_error_errno(j
->error
, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)");
245 else if (j
== i
->signature_job
)
246 log_error_errno(j
->error
, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
248 log_error_errno(j
->error
, "Failed to retrieve image file. (Wrong URL?)");
254 /* This is invoked if either the download completed
255 * successfully, or the download was skipped because we
256 * already have the etag. */
258 if (!tar_pull_is_done(i
))
261 j
->disk_fd
= safe_close(i
->tar_job
->disk_fd
);
263 if (i
->tar_pid
> 0) {
264 r
= wait_for_terminate_and_warn("tar", i
->tar_pid
, true);
270 if (!i
->tar_job
->etag_exists
) {
271 /* This is a new download, verify it, and move it into place */
273 tar_pull_report_progress(i
, TAR_VERIFYING
);
275 r
= pull_verify(i
->tar_job
, i
->checksum_job
, i
->signature_job
);
279 tar_pull_report_progress(i
, TAR_FINALIZING
);
281 r
= import_make_read_only(i
->temp_path
);
285 r
= rename_noreplace(AT_FDCWD
, i
->temp_path
, AT_FDCWD
, i
->final_path
);
287 log_error_errno(r
, "Failed to rename to final image name: %m");
295 tar_pull_report_progress(i
, TAR_COPYING
);
297 r
= tar_pull_make_local_copy(i
);
305 i
->on_finished(i
, r
, i
->userdata
);
307 sd_event_exit(i
->event
, r
);
310 static int tar_pull_job_on_open_disk(PullJob
*j
) {
318 assert(i
->tar_job
== j
);
319 assert(!i
->final_path
);
320 assert(!i
->temp_path
);
321 assert(i
->tar_pid
<= 0);
323 r
= pull_make_path(j
->url
, j
->etag
, i
->image_root
, ".tar-", NULL
, &i
->final_path
);
327 r
= tempfn_random(i
->final_path
, &i
->temp_path
);
331 mkdir_parents_label(i
->temp_path
, 0700);
333 r
= btrfs_subvol_make(i
->temp_path
);
335 if (mkdir(i
->temp_path
, 0755) < 0)
336 return log_error_errno(errno
, "Failed to create directory %s: %m", i
->temp_path
);
338 return log_error_errno(errno
, "Failed to create subvolume %s: %m", i
->temp_path
);
340 j
->disk_fd
= import_fork_tar_x(i
->temp_path
, &i
->tar_pid
);
347 static void tar_pull_job_on_progress(PullJob
*j
) {
355 tar_pull_report_progress(i
, TAR_DOWNLOADING
);
358 int tar_pull_start(TarPull
*i
, const char *url
, const char *local
, bool force_local
, ImportVerify verify
) {
363 if (!http_url_is_valid(url
))
366 if (local
&& !machine_name_is_valid(local
))
372 r
= free_and_strdup(&i
->local
, local
);
375 i
->force_local
= force_local
;
378 r
= pull_job_new(&i
->tar_job
, url
, i
->glue
, i
);
382 i
->tar_job
->on_finished
= tar_pull_job_on_finished
;
383 i
->tar_job
->on_open_disk
= tar_pull_job_on_open_disk
;
384 i
->tar_job
->on_progress
= tar_pull_job_on_progress
;
385 i
->tar_job
->calc_checksum
= verify
!= IMPORT_VERIFY_NO
;
386 i
->tar_job
->grow_machine_directory
= i
->grow_machine_directory
;
388 r
= pull_find_old_etags(url
, i
->image_root
, DT_DIR
, ".tar-", NULL
, &i
->tar_job
->old_etags
);
392 r
= pull_make_verification_jobs(&i
->checksum_job
, &i
->signature_job
, verify
, url
, i
->glue
, tar_pull_job_on_finished
, i
);
396 r
= pull_job_begin(i
->tar_job
);
400 if (i
->checksum_job
) {
401 i
->checksum_job
->on_progress
= tar_pull_job_on_progress
;
403 r
= pull_job_begin(i
->checksum_job
);
408 if (i
->signature_job
) {
409 i
->signature_job
->on_progress
= tar_pull_job_on_progress
;
411 r
= pull_job_begin(i
->signature_job
);