]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/import/pull-tar.c
shared: add process-util.[ch]
[thirdparty/systemd.git] / src / import / pull-tar.c
CommitLineData
56ebfaf1
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2015 Lennart Poettering
7
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.
12
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.
17
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/>.
20***/
21
22#include <sys/prctl.h>
23#include <curl/curl.h>
24
7079cfef 25#include "sd-daemon.h"
56ebfaf1
LP
26#include "utf8.h"
27#include "strv.h"
28#include "copy.h"
29#include "btrfs-util.h"
30#include "util.h"
31#include "macro.h"
32#include "mkdir.h"
c6878637 33#include "rm-rf.h"
26166c88 34#include "path-util.h"
3d7415f4 35#include "import-util.h"
b6e676ce 36#include "import-common.h"
56ebfaf1 37#include "curl-util.h"
dc2c282b
LP
38#include "pull-job.h"
39#include "pull-common.h"
40#include "pull-tar.h"
0b452006 41#include "process-util.h"
56ebfaf1 42
7079cfef
LP
43typedef enum TarProgress {
44 TAR_DOWNLOADING,
45 TAR_VERIFYING,
46 TAR_FINALIZING,
47 TAR_COPYING,
48} TarProgress;
49
dc2c282b 50struct TarPull {
56ebfaf1
LP
51 sd_event *event;
52 CurlGlue *glue;
53
54 char *image_root;
55
dc2c282b
LP
56 PullJob *tar_job;
57 PullJob *checksum_job;
58 PullJob *signature_job;
56ebfaf1 59
dc2c282b 60 TarPullFinished on_finished;
56ebfaf1
LP
61 void *userdata;
62
56ebfaf1
LP
63 char *local;
64 bool force_local;
26166c88 65 bool grow_machine_directory;
56ebfaf1
LP
66
67 pid_t tar_pid;
68
69 char *temp_path;
70 char *final_path;
0100b6e1
LP
71
72 ImportVerify verify;
56ebfaf1
LP
73};
74
dc2c282b 75TarPull* tar_pull_unref(TarPull *i) {
56ebfaf1
LP
76 if (!i)
77 return NULL;
78
0100b6e1 79 if (i->tar_pid > 1) {
8b71fce8 80 (void) kill_and_sigcont(i->tar_pid, SIGKILL);
0100b6e1 81 (void) wait_for_terminate(i->tar_pid, NULL);
56ebfaf1
LP
82 }
83
dc2c282b
LP
84 pull_job_unref(i->tar_job);
85 pull_job_unref(i->checksum_job);
86 pull_job_unref(i->signature_job);
56ebfaf1
LP
87
88 curl_glue_unref(i->glue);
89 sd_event_unref(i->event);
90
91 if (i->temp_path) {
d9e2daaf 92 (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
0d6e763b 93 free(i->temp_path);
56ebfaf1
LP
94 }
95
96 free(i->final_path);
97 free(i->image_root);
98 free(i->local);
56ebfaf1
LP
99 free(i);
100
101 return NULL;
102}
103
dc2c282b
LP
104int tar_pull_new(
105 TarPull **ret,
8b71fce8
LP
106 sd_event *event,
107 const char *image_root,
dc2c282b 108 TarPullFinished on_finished,
8b71fce8
LP
109 void *userdata) {
110
dc2c282b 111 _cleanup_(tar_pull_unrefp) TarPull *i = NULL;
56ebfaf1
LP
112 int r;
113
114 assert(ret);
115 assert(event);
116
dc2c282b 117 i = new0(TarPull, 1);
56ebfaf1
LP
118 if (!i)
119 return -ENOMEM;
120
121 i->on_finished = on_finished;
122 i->userdata = userdata;
123
124 i->image_root = strdup(image_root ?: "/var/lib/machines");
125 if (!i->image_root)
126 return -ENOMEM;
127
26166c88
LP
128 i->grow_machine_directory = path_startswith(i->image_root, "/var/lib/machines");
129
56ebfaf1
LP
130 if (event)
131 i->event = sd_event_ref(event);
132 else {
133 r = sd_event_default(&i->event);
134 if (r < 0)
135 return r;
136 }
137
138 r = curl_glue_new(&i->glue, i->event);
139 if (r < 0)
140 return r;
141
dc2c282b 142 i->glue->on_finished = pull_job_curl_on_finished;
56ebfaf1
LP
143 i->glue->userdata = i;
144
145 *ret = i;
146 i = NULL;
147
148 return 0;
149}
150
dc2c282b 151static void tar_pull_report_progress(TarPull *i, TarProgress p) {
7079cfef
LP
152 unsigned percent;
153
154 assert(i);
155
156 switch (p) {
157
158 case TAR_DOWNLOADING: {
159 unsigned remain = 85;
160
161 percent = 0;
162
163 if (i->checksum_job) {
164 percent += i->checksum_job->progress_percent * 5 / 100;
165 remain -= 5;
166 }
167
168 if (i->signature_job) {
169 percent += i->signature_job->progress_percent * 5 / 100;
170 remain -= 5;
171 }
172
173 if (i->tar_job)
174 percent += i->tar_job->progress_percent * remain / 100;
175 break;
176 }
177
178 case TAR_VERIFYING:
179 percent = 85;
180 break;
181
182 case TAR_FINALIZING:
183 percent = 90;
184 break;
185
186 case TAR_COPYING:
187 percent = 95;
188 break;
189
190 default:
191 assert_not_reached("Unknown progress state");
192 }
193
194 sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent);
195 log_debug("Combined progress %u%%", percent);
196}
197
dc2c282b 198static int tar_pull_make_local_copy(TarPull *i) {
0d6e763b
LP
199 int r;
200
201 assert(i);
202 assert(i->tar_job);
203
204 if (!i->local)
205 return 0;
206
207 if (!i->final_path) {
dc2c282b 208 r = pull_make_path(i->tar_job->url, i->tar_job->etag, i->image_root, ".tar-", NULL, &i->final_path);
0d6e763b
LP
209 if (r < 0)
210 return log_oom();
0d6e763b
LP
211 }
212
dc2c282b 213 r = pull_make_local_copy(i->final_path, i->image_root, i->local, i->force_local);
0100b6e1
LP
214 if (r < 0)
215 return r;
216
0d6e763b
LP
217 return 0;
218}
219
dc2c282b 220static bool tar_pull_is_done(TarPull *i) {
8b71fce8
LP
221 assert(i);
222 assert(i->tar_job);
223
dc2c282b 224 if (i->tar_job->state != PULL_JOB_DONE)
8b71fce8 225 return false;
dc2c282b 226 if (i->checksum_job && i->checksum_job->state != PULL_JOB_DONE)
8b71fce8 227 return false;
dc2c282b 228 if (i->signature_job && i->signature_job->state != PULL_JOB_DONE)
8b71fce8
LP
229 return false;
230
231 return true;
232}
233
dc2c282b
LP
234static void tar_pull_job_on_finished(PullJob *j) {
235 TarPull *i;
56ebfaf1
LP
236 int r;
237
238 assert(j);
239 assert(j->userdata);
240
241 i = j->userdata;
56ebfaf1 242 if (j->error != 0) {
0100b6e1
LP
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?)");
247 else
248 log_error_errno(j->error, "Failed to retrieve image file. (Wrong URL?)");
249
56ebfaf1
LP
250 r = j->error;
251 goto finish;
252 }
253
254 /* This is invoked if either the download completed
255 * successfully, or the download was skipped because we
256 * already have the etag. */
257
dc2c282b 258 if (!tar_pull_is_done(i))
0100b6e1
LP
259 return;
260
261 j->disk_fd = safe_close(i->tar_job->disk_fd);
56ebfaf1
LP
262
263 if (i->tar_pid > 0) {
264 r = wait_for_terminate_and_warn("tar", i->tar_pid, true);
265 i->tar_pid = 0;
266 if (r < 0)
267 goto finish;
268 }
269
0100b6e1
LP
270 if (!i->tar_job->etag_exists) {
271 /* This is a new download, verify it, and move it into place */
272
dc2c282b 273 tar_pull_report_progress(i, TAR_VERIFYING);
7079cfef 274
dc2c282b 275 r = pull_verify(i->tar_job, i->checksum_job, i->signature_job);
0100b6e1
LP
276 if (r < 0)
277 goto finish;
278
dc2c282b 279 tar_pull_report_progress(i, TAR_FINALIZING);
7079cfef 280
b6e676ce 281 r = import_make_read_only(i->temp_path);
56ebfaf1
LP
282 if (r < 0)
283 goto finish;
284
f85ef957
AC
285 r = rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path);
286 if (r < 0) {
287 log_error_errno(r, "Failed to rename to final image name: %m");
56ebfaf1
LP
288 goto finish;
289 }
56ebfaf1 290
0d6e763b
LP
291 free(i->temp_path);
292 i->temp_path = NULL;
56ebfaf1
LP
293 }
294
dc2c282b 295 tar_pull_report_progress(i, TAR_COPYING);
7079cfef 296
dc2c282b 297 r = tar_pull_make_local_copy(i);
0d6e763b
LP
298 if (r < 0)
299 goto finish;
300
56ebfaf1
LP
301 r = 0;
302
303finish:
56ebfaf1
LP
304 if (i->on_finished)
305 i->on_finished(i, r, i->userdata);
306 else
307 sd_event_exit(i->event, r);
308}
309
dc2c282b
LP
310static int tar_pull_job_on_open_disk(PullJob *j) {
311 TarPull *i;
56ebfaf1
LP
312 int r;
313
314 assert(j);
315 assert(j->userdata);
316
317 i = j->userdata;
8b71fce8
LP
318 assert(i->tar_job == j);
319 assert(!i->final_path);
320 assert(!i->temp_path);
321 assert(i->tar_pid <= 0);
56ebfaf1 322
dc2c282b 323 r = pull_make_path(j->url, j->etag, i->image_root, ".tar-", NULL, &i->final_path);
56ebfaf1
LP
324 if (r < 0)
325 return log_oom();
326
327 r = tempfn_random(i->final_path, &i->temp_path);
328 if (r < 0)
329 return log_oom();
330
331 mkdir_parents_label(i->temp_path, 0700);
332
333 r = btrfs_subvol_make(i->temp_path);
334 if (r == -ENOTTY) {
335 if (mkdir(i->temp_path, 0755) < 0)
336 return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
337 } else if (r < 0)
338 return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
339
587fec42 340 j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
2c140ded
LP
341 if (j->disk_fd < 0)
342 return j->disk_fd;
56ebfaf1
LP
343
344 return 0;
345}
346
dc2c282b
LP
347static void tar_pull_job_on_progress(PullJob *j) {
348 TarPull *i;
7079cfef
LP
349
350 assert(j);
351 assert(j->userdata);
352
353 i = j->userdata;
354
dc2c282b 355 tar_pull_report_progress(i, TAR_DOWNLOADING);
7079cfef
LP
356}
357
dc2c282b 358int tar_pull_start(TarPull *i, const char *url, const char *local, bool force_local, ImportVerify verify) {
56ebfaf1
LP
359 int r;
360
361 assert(i);
362
56ebfaf1
LP
363 if (!http_url_is_valid(url))
364 return -EINVAL;
365
366 if (local && !machine_name_is_valid(local))
367 return -EINVAL;
368
8b71fce8
LP
369 if (i->tar_job)
370 return -EBUSY;
371
56ebfaf1
LP
372 r = free_and_strdup(&i->local, local);
373 if (r < 0)
374 return r;
56ebfaf1 375 i->force_local = force_local;
0100b6e1 376 i->verify = verify;
56ebfaf1 377
dc2c282b 378 r = pull_job_new(&i->tar_job, url, i->glue, i);
56ebfaf1
LP
379 if (r < 0)
380 return r;
381
dc2c282b
LP
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;
0100b6e1 385 i->tar_job->calc_checksum = verify != IMPORT_VERIFY_NO;
26166c88 386 i->tar_job->grow_machine_directory = i->grow_machine_directory;
56ebfaf1 387
dc2c282b 388 r = pull_find_old_etags(url, i->image_root, DT_DIR, ".tar-", NULL, &i->tar_job->old_etags);
56ebfaf1
LP
389 if (r < 0)
390 return r;
391
dc2c282b 392 r = pull_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, tar_pull_job_on_finished, i);
0100b6e1
LP
393 if (r < 0)
394 return r;
395
dc2c282b 396 r = pull_job_begin(i->tar_job);
0100b6e1
LP
397 if (r < 0)
398 return r;
399
400 if (i->checksum_job) {
dc2c282b 401 i->checksum_job->on_progress = tar_pull_job_on_progress;
7079cfef 402
dc2c282b 403 r = pull_job_begin(i->checksum_job);
0100b6e1
LP
404 if (r < 0)
405 return r;
406 }
407
408 if (i->signature_job) {
dc2c282b 409 i->signature_job->on_progress = tar_pull_job_on_progress;
7079cfef 410
dc2c282b 411 r = pull_job_begin(i->signature_job);
0100b6e1
LP
412 if (r < 0)
413 return r;
414 }
415
416 return 0;
56ebfaf1 417}