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 "process-util.h"
36 #include "hostname-util.h"
37 #include "import-util.h"
38 #include "import-common.h"
39 #include "curl-util.h"
41 #include "pull-common.h"
44 typedef enum TarProgress
{
58 PullJob
*checksum_job
;
59 PullJob
*signature_job
;
61 TarPullFinished on_finished
;
66 bool grow_machine_directory
;
76 TarPull
* tar_pull_unref(TarPull
*i
) {
81 (void) kill_and_sigcont(i
->tar_pid
, SIGKILL
);
82 (void) wait_for_terminate(i
->tar_pid
, NULL
);
85 pull_job_unref(i
->tar_job
);
86 pull_job_unref(i
->checksum_job
);
87 pull_job_unref(i
->signature_job
);
89 curl_glue_unref(i
->glue
);
90 sd_event_unref(i
->event
);
93 (void) rm_rf(i
->temp_path
, REMOVE_ROOT
|REMOVE_PHYSICAL
|REMOVE_SUBVOLUME
);
108 const char *image_root
,
109 TarPullFinished on_finished
,
112 _cleanup_(tar_pull_unrefp
) TarPull
*i
= NULL
;
118 i
= new0(TarPull
, 1);
122 i
->on_finished
= on_finished
;
123 i
->userdata
= userdata
;
125 i
->image_root
= strdup(image_root
?: "/var/lib/machines");
129 i
->grow_machine_directory
= path_startswith(i
->image_root
, "/var/lib/machines");
131 i
->event
= sd_event_ref(event
);
133 r
= curl_glue_new(&i
->glue
, i
->event
);
137 i
->glue
->on_finished
= pull_job_curl_on_finished
;
138 i
->glue
->userdata
= i
;
146 static void tar_pull_report_progress(TarPull
*i
, TarProgress p
) {
153 case TAR_DOWNLOADING
: {
154 unsigned remain
= 85;
158 if (i
->checksum_job
) {
159 percent
+= i
->checksum_job
->progress_percent
* 5 / 100;
163 if (i
->signature_job
) {
164 percent
+= i
->signature_job
->progress_percent
* 5 / 100;
169 percent
+= i
->tar_job
->progress_percent
* remain
/ 100;
186 assert_not_reached("Unknown progress state");
189 sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent
);
190 log_debug("Combined progress %u%%", percent
);
193 static int tar_pull_make_local_copy(TarPull
*i
) {
202 if (!i
->final_path
) {
203 r
= pull_make_path(i
->tar_job
->url
, i
->tar_job
->etag
, i
->image_root
, ".tar-", NULL
, &i
->final_path
);
208 r
= pull_make_local_copy(i
->final_path
, i
->image_root
, i
->local
, i
->force_local
);
215 static bool tar_pull_is_done(TarPull
*i
) {
219 if (i
->tar_job
->state
!= PULL_JOB_DONE
)
221 if (i
->checksum_job
&& i
->checksum_job
->state
!= PULL_JOB_DONE
)
223 if (i
->signature_job
&& i
->signature_job
->state
!= PULL_JOB_DONE
)
229 static void tar_pull_job_on_finished(PullJob
*j
) {
238 if (j
== i
->checksum_job
)
239 log_error_errno(j
->error
, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)");
240 else if (j
== i
->signature_job
)
241 log_error_errno(j
->error
, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
243 log_error_errno(j
->error
, "Failed to retrieve image file. (Wrong URL?)");
249 /* This is invoked if either the download completed
250 * successfully, or the download was skipped because we
251 * already have the etag. */
253 if (!tar_pull_is_done(i
))
256 j
->disk_fd
= safe_close(i
->tar_job
->disk_fd
);
258 if (i
->tar_pid
> 0) {
259 r
= wait_for_terminate_and_warn("tar", i
->tar_pid
, true);
265 if (!i
->tar_job
->etag_exists
) {
266 /* This is a new download, verify it, and move it into place */
268 tar_pull_report_progress(i
, TAR_VERIFYING
);
270 r
= pull_verify(i
->tar_job
, i
->checksum_job
, i
->signature_job
);
274 tar_pull_report_progress(i
, TAR_FINALIZING
);
276 r
= import_make_read_only(i
->temp_path
);
280 r
= rename_noreplace(AT_FDCWD
, i
->temp_path
, AT_FDCWD
, i
->final_path
);
282 log_error_errno(r
, "Failed to rename to final image name: %m");
290 tar_pull_report_progress(i
, TAR_COPYING
);
292 r
= tar_pull_make_local_copy(i
);
300 i
->on_finished(i
, r
, i
->userdata
);
302 sd_event_exit(i
->event
, r
);
305 static int tar_pull_job_on_open_disk(PullJob
*j
) {
313 assert(i
->tar_job
== j
);
314 assert(!i
->final_path
);
315 assert(!i
->temp_path
);
316 assert(i
->tar_pid
<= 0);
318 r
= pull_make_path(j
->url
, j
->etag
, i
->image_root
, ".tar-", NULL
, &i
->final_path
);
322 r
= tempfn_random(i
->final_path
, NULL
, &i
->temp_path
);
326 mkdir_parents_label(i
->temp_path
, 0700);
328 r
= btrfs_subvol_make(i
->temp_path
);
330 if (mkdir(i
->temp_path
, 0755) < 0)
331 return log_error_errno(errno
, "Failed to create directory %s: %m", i
->temp_path
);
333 return log_error_errno(errno
, "Failed to create subvolume %s: %m", i
->temp_path
);
335 j
->disk_fd
= import_fork_tar_x(i
->temp_path
, &i
->tar_pid
);
342 static void tar_pull_job_on_progress(PullJob
*j
) {
350 tar_pull_report_progress(i
, TAR_DOWNLOADING
);
353 int tar_pull_start(TarPull
*i
, const char *url
, const char *local
, bool force_local
, ImportVerify verify
) {
358 if (!http_url_is_valid(url
))
361 if (local
&& !machine_name_is_valid(local
))
367 r
= free_and_strdup(&i
->local
, local
);
370 i
->force_local
= force_local
;
373 r
= pull_job_new(&i
->tar_job
, url
, i
->glue
, i
);
377 i
->tar_job
->on_finished
= tar_pull_job_on_finished
;
378 i
->tar_job
->on_open_disk
= tar_pull_job_on_open_disk
;
379 i
->tar_job
->on_progress
= tar_pull_job_on_progress
;
380 i
->tar_job
->calc_checksum
= verify
!= IMPORT_VERIFY_NO
;
381 i
->tar_job
->grow_machine_directory
= i
->grow_machine_directory
;
383 r
= pull_find_old_etags(url
, i
->image_root
, DT_DIR
, ".tar-", NULL
, &i
->tar_job
->old_etags
);
387 r
= pull_make_verification_jobs(&i
->checksum_job
, &i
->signature_job
, verify
, url
, i
->glue
, tar_pull_job_on_finished
, i
);
391 r
= pull_job_begin(i
->tar_job
);
395 if (i
->checksum_job
) {
396 i
->checksum_job
->on_progress
= tar_pull_job_on_progress
;
398 r
= pull_job_begin(i
->checksum_job
);
403 if (i
->signature_job
) {
404 i
->signature_job
->on_progress
= tar_pull_job_on_progress
;
406 r
= pull_job_begin(i
->signature_job
);