chiark / gitweb /
sd-dhcp6-client: delay setting the DUID and don't fail constructor
[elogind.git] / src / import / import-dkr.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 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 <curl/curl.h>
23 #include <sys/prctl.h>
24
25 #include "sd-daemon.h"
26 #include "json.h"
27 #include "strv.h"
28 #include "btrfs-util.h"
29 #include "utf8.h"
30 #include "mkdir.h"
31 #include "path-util.h"
32 #include "import-util.h"
33 #include "curl-util.h"
34 #include "aufs-util.h"
35 #include "import-job.h"
36 #include "import-common.h"
37 #include "import-dkr.h"
38
39 typedef enum DkrProgress {
40         DKR_SEARCHING,
41         DKR_RESOLVING,
42         DKR_METADATA,
43         DKR_DOWNLOADING,
44         DKR_COPYING,
45 } DkrProgress;
46
47 struct DkrImport {
48         sd_event *event;
49         CurlGlue *glue;
50
51         char *index_url;
52         char *image_root;
53
54         ImportJob *images_job;
55         ImportJob *tags_job;
56         ImportJob *ancestry_job;
57         ImportJob *json_job;
58         ImportJob *layer_job;
59
60         char *name;
61         char *tag;
62         char *id;
63
64         char *response_token;
65         char **response_registries;
66
67         char **ancestry;
68         unsigned n_ancestry;
69         unsigned current_ancestry;
70
71         DkrImportFinished on_finished;
72         void *userdata;
73
74         char *local;
75         bool force_local;
76         bool grow_machine_directory;
77
78         char *temp_path;
79         char *final_path;
80
81         pid_t tar_pid;
82 };
83
84 #define PROTOCOL_PREFIX "https://"
85
86 #define HEADER_TOKEN "X-Do" /* the HTTP header for the auth token */ "cker-Token:"
87 #define HEADER_REGISTRY "X-Do" /*the HTTP header for the registry */ "cker-Endpoints:"
88
89 #define LAYERS_MAX 2048
90
91 static void dkr_import_job_on_finished(ImportJob *j);
92
93 DkrImport* dkr_import_unref(DkrImport *i) {
94         if (!i)
95                 return NULL;
96
97         if (i->tar_pid > 1) {
98                 (void) kill_and_sigcont(i->tar_pid, SIGKILL);
99                 (void) wait_for_terminate(i->tar_pid, NULL);
100         }
101
102         import_job_unref(i->images_job);
103         import_job_unref(i->tags_job);
104         import_job_unref(i->ancestry_job);
105         import_job_unref(i->json_job);
106         import_job_unref(i->layer_job);
107
108         curl_glue_unref(i->glue);
109         sd_event_unref(i->event);
110
111         if (i->temp_path) {
112                 (void) btrfs_subvol_remove(i->temp_path);
113                 (void) rm_rf_dangerous(i->temp_path, false, true, false);
114                 free(i->temp_path);
115         }
116
117         free(i->name);
118         free(i->tag);
119         free(i->id);
120         free(i->response_token);
121         free(i->response_registries);
122         strv_free(i->ancestry);
123         free(i->final_path);
124         free(i->index_url);
125         free(i->image_root);
126         free(i->local);
127         free(i);
128
129         return NULL;
130 }
131
132 int dkr_import_new(
133                 DkrImport **ret,
134                 sd_event *event,
135                 const char *index_url,
136                 const char *image_root,
137                 DkrImportFinished on_finished,
138                 void *userdata) {
139
140         _cleanup_(dkr_import_unrefp) DkrImport *i = NULL;
141         char *e;
142         int r;
143
144         assert(ret);
145         assert(index_url);
146
147         if (!http_url_is_valid(index_url))
148                 return -EINVAL;
149
150         i = new0(DkrImport, 1);
151         if (!i)
152                 return -ENOMEM;
153
154         i->on_finished = on_finished;
155         i->userdata = userdata;
156
157         i->image_root = strdup(image_root ?: "/var/lib/machines");
158         if (!i->image_root)
159                 return -ENOMEM;
160
161         i->grow_machine_directory = path_startswith(i->image_root, "/var/lib/machines");
162
163         i->index_url = strdup(index_url);
164         if (!i->index_url)
165                 return -ENOMEM;
166
167         e = endswith(i->index_url, "/");
168         if (e)
169                 *e = 0;
170
171         if (event)
172                 i->event = sd_event_ref(event);
173         else {
174                 r = sd_event_default(&i->event);
175                 if (r < 0)
176                         return r;
177         }
178
179         r = curl_glue_new(&i->glue, i->event);
180         if (r < 0)
181                 return r;
182
183         i->glue->on_finished = import_job_curl_on_finished;
184         i->glue->userdata = i;
185
186         *ret = i;
187         i = NULL;
188
189         return 0;
190 }
191
192 static void dkr_import_report_progress(DkrImport *i, DkrProgress p) {
193         unsigned percent;
194
195         assert(i);
196
197         switch (p) {
198
199         case DKR_SEARCHING:
200                 percent = 0;
201                 if (i->images_job)
202                         percent += i->images_job->progress_percent * 5 / 100;
203                 break;
204
205         case DKR_RESOLVING:
206                 percent = 5;
207                 if (i->tags_job)
208                         percent += i->tags_job->progress_percent * 5 / 100;
209                 break;
210
211         case DKR_METADATA:
212                 percent = 10;
213                 if (i->ancestry_job)
214                         percent += i->ancestry_job->progress_percent * 5 / 100;
215                 if (i->json_job)
216                         percent += i->json_job->progress_percent * 5 / 100;
217                 break;
218
219         case DKR_DOWNLOADING:
220                 percent = 20;
221                 percent += 75 * i->current_ancestry / MAX(1U, i->n_ancestry);
222                 if (i->layer_job)
223                         percent += i->layer_job->progress_percent * 75 / MAX(1U, i->n_ancestry) / 100;
224
225                 break;
226
227         case DKR_COPYING:
228                 percent = 95;
229                 break;
230
231         default:
232                 assert_not_reached("Unknown progress state");
233         }
234
235         sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent);
236         log_debug("Combined progress %u%%", percent);
237 }
238
239 static int parse_id(const void *payload, size_t size, char **ret) {
240         _cleanup_free_ char *buf = NULL, *id = NULL, *other = NULL;
241         union json_value v = {};
242         void *json_state = NULL;
243         const char *p;
244         int t;
245
246         assert(payload);
247         assert(ret);
248
249         if (size <= 0)
250                 return -EBADMSG;
251
252         if (memchr(payload, 0, size))
253                 return -EBADMSG;
254
255         buf = strndup(payload, size);
256         if (!buf)
257                 return -ENOMEM;
258
259         p = buf;
260         t = json_tokenize(&p, &id, &v, &json_state, NULL);
261         if (t < 0)
262                 return t;
263         if (t != JSON_STRING)
264                 return -EBADMSG;
265
266         t = json_tokenize(&p, &other, &v, &json_state, NULL);
267         if (t < 0)
268                 return t;
269         if (t != JSON_END)
270                 return -EBADMSG;
271
272         if (!dkr_id_is_valid(id))
273                 return -EBADMSG;
274
275         *ret = id;
276         id = NULL;
277
278         return 0;
279 }
280
281 static int parse_ancestry(const void *payload, size_t size, char ***ret) {
282         _cleanup_free_ char *buf = NULL;
283         void *json_state = NULL;
284         const char *p;
285         enum {
286                 STATE_BEGIN,
287                 STATE_ITEM,
288                 STATE_COMMA,
289                 STATE_END,
290         } state = STATE_BEGIN;
291         _cleanup_strv_free_ char **l = NULL;
292         size_t n = 0, allocated = 0;
293
294         if (size <= 0)
295                 return -EBADMSG;
296
297         if (memchr(payload, 0, size))
298                 return -EBADMSG;
299
300         buf = strndup(payload, size);
301         if (!buf)
302                 return -ENOMEM;
303
304         p = buf;
305         for (;;) {
306                 _cleanup_free_ char *str;
307                 union json_value v = {};
308                 int t;
309
310                 t = json_tokenize(&p, &str, &v, &json_state, NULL);
311                 if (t < 0)
312                         return t;
313
314                 switch (state) {
315
316                 case STATE_BEGIN:
317                         if (t == JSON_ARRAY_OPEN)
318                                 state = STATE_ITEM;
319                         else
320                                 return -EBADMSG;
321
322                         break;
323
324                 case STATE_ITEM:
325                         if (t == JSON_STRING) {
326                                 if (!dkr_id_is_valid(str))
327                                         return -EBADMSG;
328
329                                 if (n+1 > LAYERS_MAX)
330                                         return -EFBIG;
331
332                                 if (!GREEDY_REALLOC(l, allocated, n + 2))
333                                         return -ENOMEM;
334
335                                 l[n++] = str;
336                                 str = NULL;
337                                 l[n] = NULL;
338
339                                 state = STATE_COMMA;
340
341                         } else if (t == JSON_ARRAY_CLOSE)
342                                 state = STATE_END;
343                         else
344                                 return -EBADMSG;
345
346                         break;
347
348                 case STATE_COMMA:
349                         if (t == JSON_COMMA)
350                                 state = STATE_ITEM;
351                         else if (t == JSON_ARRAY_CLOSE)
352                                 state = STATE_END;
353                         else
354                                 return -EBADMSG;
355                         break;
356
357                 case STATE_END:
358                         if (t == JSON_END) {
359
360                                 if (strv_isempty(l))
361                                         return -EBADMSG;
362
363                                 if (!strv_is_uniq(l))
364                                         return -EBADMSG;
365
366                                 l = strv_reverse(l);
367
368                                 *ret = l;
369                                 l = NULL;
370                                 return 0;
371                         } else
372                                 return -EBADMSG;
373                 }
374
375         }
376 }
377
378 static const char *dkr_import_current_layer(DkrImport *i) {
379         assert(i);
380
381         if (strv_isempty(i->ancestry))
382                 return NULL;
383
384         return i->ancestry[i->current_ancestry];
385 }
386
387 static const char *dkr_import_current_base_layer(DkrImport *i) {
388         assert(i);
389
390         if (strv_isempty(i->ancestry))
391                 return NULL;
392
393         if (i->current_ancestry <= 0)
394                 return NULL;
395
396         return i->ancestry[i->current_ancestry-1];
397 }
398
399 static int dkr_import_add_token(DkrImport *i, ImportJob *j) {
400         const char *t;
401
402         assert(i);
403         assert(j);
404
405         if (i->response_token)
406                 t = strjoina("Authorization: Token ", i->response_token);
407         else
408                 t = HEADER_TOKEN " true";
409
410         j->request_header = curl_slist_new("Accept: application/json", t, NULL);
411         if (!j->request_header)
412                 return -ENOMEM;
413
414         return 0;
415 }
416
417 static bool dkr_import_is_done(DkrImport *i) {
418         assert(i);
419         assert(i->images_job);
420
421         if (i->images_job->state != IMPORT_JOB_DONE)
422                 return false;
423
424         if (!i->tags_job || i->tags_job->state != IMPORT_JOB_DONE)
425                 return false;
426
427         if (!i->ancestry_job || i->ancestry_job->state != IMPORT_JOB_DONE)
428                 return false;
429
430         if (!i->json_job || i->json_job->state != IMPORT_JOB_DONE)
431                 return false;
432
433         if (i->layer_job && i->layer_job->state != IMPORT_JOB_DONE)
434                 return false;
435
436         if (dkr_import_current_layer(i))
437                 return false;
438
439         return true;
440 }
441
442 static int dkr_import_make_local_copy(DkrImport *i) {
443         int r;
444
445         assert(i);
446
447         if (!i->local)
448                 return 0;
449
450         if (!i->final_path) {
451                 i->final_path = strjoin(i->image_root, "/.dkr-", i->id, NULL);
452                 if (!i->final_path)
453                         return log_oom();
454         }
455
456         r = import_make_local_copy(i->final_path, i->image_root, i->local, i->force_local);
457         if (r < 0)
458                 return r;
459
460         return 0;
461 }
462
463 static int dkr_import_job_on_open_disk(ImportJob *j) {
464         const char *base;
465         DkrImport *i;
466         int r;
467
468         assert(j);
469         assert(j->userdata);
470
471         i = j->userdata;
472         assert(i->layer_job == j);
473         assert(i->final_path);
474         assert(!i->temp_path);
475         assert(i->tar_pid <= 0);
476
477         r = tempfn_random(i->final_path, &i->temp_path);
478         if (r < 0)
479                 return log_oom();
480
481         mkdir_parents_label(i->temp_path, 0700);
482
483         base = dkr_import_current_base_layer(i);
484         if (base) {
485                 const char *base_path;
486
487                 base_path = strjoina(i->image_root, "/.dkr-", base);
488                 r = btrfs_subvol_snapshot(base_path, i->temp_path, false, true);
489         } else
490                 r = btrfs_subvol_make(i->temp_path);
491         if (r < 0)
492                 return log_error_errno(r, "Failed to make btrfs subvolume %s: %m", i->temp_path);
493
494         j->disk_fd = import_fork_tar(i->temp_path, &i->tar_pid);
495         if (j->disk_fd < 0)
496                 return j->disk_fd;
497
498         return 0;
499 }
500
501 static void dkr_import_job_on_progress(ImportJob *j) {
502         DkrImport *i;
503
504         assert(j);
505         assert(j->userdata);
506
507         i = j->userdata;
508
509         dkr_import_report_progress(
510                         i,
511                         j == i->images_job                       ? DKR_SEARCHING :
512                         j == i->tags_job                         ? DKR_RESOLVING :
513                         j == i->ancestry_job || j == i->json_job ? DKR_METADATA :
514                                                                    DKR_DOWNLOADING);
515 }
516
517 static int dkr_import_pull_layer(DkrImport *i) {
518         _cleanup_free_ char *path = NULL;
519         const char *url, *layer = NULL;
520         int r;
521
522         assert(i);
523         assert(!i->layer_job);
524         assert(!i->temp_path);
525         assert(!i->final_path);
526
527         for (;;) {
528                 layer = dkr_import_current_layer(i);
529                 if (!layer)
530                         return 0; /* no more layers */
531
532                 path = strjoin(i->image_root, "/.dkr-", layer, NULL);
533                 if (!path)
534                         return log_oom();
535
536                 if (laccess(path, F_OK) < 0) {
537                         if (errno == ENOENT)
538                                 break;
539
540                         return log_error_errno(errno, "Failed to check for container: %m");
541                 }
542
543                 log_info("Layer %s already exists, skipping.", layer);
544
545                 i->current_ancestry++;
546
547                 free(path);
548                 path = NULL;
549         }
550
551         log_info("Pulling layer %s...", layer);
552
553         i->final_path = path;
554         path = NULL;
555
556         url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", layer, "/layer");
557         r = import_job_new(&i->layer_job, url, i->glue, i);
558         if (r < 0)
559                 return log_error_errno(r, "Failed to allocate layer job: %m");
560
561         r = dkr_import_add_token(i, i->layer_job);
562         if (r < 0)
563                 return log_oom();
564
565         i->layer_job->on_finished = dkr_import_job_on_finished;
566         i->layer_job->on_open_disk = dkr_import_job_on_open_disk;
567         i->layer_job->on_progress = dkr_import_job_on_progress;
568         i->layer_job->grow_machine_directory = i->grow_machine_directory;
569
570         r = import_job_begin(i->layer_job);
571         if (r < 0)
572                 return log_error_errno(r, "Failed to start layer job: %m");
573
574         return 0;
575 }
576
577 static void dkr_import_job_on_finished(ImportJob *j) {
578         DkrImport *i;
579         int r;
580
581         assert(j);
582         assert(j->userdata);
583
584         i = j->userdata;
585         if (j->error != 0) {
586                 if (j == i->images_job)
587                         log_error_errno(j->error, "Failed to retrieve images list. (Wrong index URL?)");
588                 else if (j == i->tags_job)
589                         log_error_errno(j->error, "Failed to retrieve tags list.");
590                 else if (j == i->ancestry_job)
591                         log_error_errno(j->error, "Failed to retrieve ancestry list.");
592                 else if (j == i->json_job)
593                         log_error_errno(j->error, "Failed to retrieve json data.");
594                 else
595                         log_error_errno(j->error, "Failed to retrieve layer data.");
596
597                 r = j->error;
598                 goto finish;
599         }
600
601         if (i->images_job == j) {
602                 const char *url;
603
604                 assert(!i->tags_job);
605                 assert(!i->ancestry_job);
606                 assert(!i->json_job);
607                 assert(!i->layer_job);
608
609                 if (strv_isempty(i->response_registries)) {
610                         r = -EBADMSG;
611                         log_error("Didn't get registry information.");
612                         goto finish;
613                 }
614
615                 log_info("Index lookup succeeded, directed to registry %s.", i->response_registries[0]);
616                 dkr_import_report_progress(i, DKR_RESOLVING);
617
618                 url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/repositories/", i->name, "/tags/", i->tag);
619                 r = import_job_new(&i->tags_job, url, i->glue, i);
620                 if (r < 0) {
621                         log_error_errno(r, "Failed to allocate tags job: %m");
622                         goto finish;
623                 }
624
625                 r = dkr_import_add_token(i, i->tags_job);
626                 if (r < 0) {
627                         log_oom();
628                         goto finish;
629                 }
630
631                 i->tags_job->on_finished = dkr_import_job_on_finished;
632                 i->tags_job->on_progress = dkr_import_job_on_progress;
633
634                 r = import_job_begin(i->tags_job);
635                 if (r < 0) {
636                         log_error_errno(r, "Failed to start tags job: %m");
637                         goto finish;
638                 }
639
640         } else if (i->tags_job == j) {
641                 const char *url;
642                 char *id = NULL;
643
644                 assert(!i->ancestry_job);
645                 assert(!i->json_job);
646                 assert(!i->layer_job);
647
648                 r = parse_id(j->payload, j->payload_size, &id);
649                 if (r < 0) {
650                         log_error_errno(r, "Failed to parse JSON id.");
651                         goto finish;
652                 }
653
654                 free(i->id);
655                 i->id = id;
656
657                 log_info("Tag lookup succeeded, resolved to layer %s.", i->id);
658                 dkr_import_report_progress(i, DKR_METADATA);
659
660                 url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", i->id, "/ancestry");
661                 r = import_job_new(&i->ancestry_job, url, i->glue, i);
662                 if (r < 0) {
663                         log_error_errno(r, "Failed to allocate ancestry job: %m");
664                         goto finish;
665                 }
666
667                 r = dkr_import_add_token(i, i->ancestry_job);
668                 if (r < 0) {
669                         log_oom();
670                         goto finish;
671                 }
672
673                 i->ancestry_job->on_finished = dkr_import_job_on_finished;
674                 i->ancestry_job->on_progress = dkr_import_job_on_progress;
675
676                 url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", i->id, "/json");
677                 r = import_job_new(&i->json_job, url, i->glue, i);
678                 if (r < 0) {
679                         log_error_errno(r, "Failed to allocate json job: %m");
680                         goto finish;
681                 }
682
683                 r = dkr_import_add_token(i, i->json_job);
684                 if (r < 0) {
685                         log_oom();
686                         goto finish;
687                 }
688
689                 i->json_job->on_finished = dkr_import_job_on_finished;
690                 i->json_job->on_progress = dkr_import_job_on_progress;
691
692                 r = import_job_begin(i->ancestry_job);
693                 if (r < 0) {
694                         log_error_errno(r, "Failed to start ancestry job: %m");
695                         goto finish;
696                 }
697
698                 r = import_job_begin(i->json_job);
699                 if (r < 0) {
700                         log_error_errno(r, "Failed to start json job: %m");
701                         goto finish;
702                 }
703
704         } else if (i->ancestry_job == j) {
705                 char **ancestry = NULL, **k;
706                 unsigned n;
707
708                 assert(!i->layer_job);
709
710                 r = parse_ancestry(j->payload, j->payload_size, &ancestry);
711                 if (r < 0) {
712                         log_error_errno(r, "Failed to parse JSON id.");
713                         goto finish;
714                 }
715
716                 n = strv_length(ancestry);
717                 if (n <= 0 || !streq(ancestry[n-1], i->id)) {
718                         log_error("Ancestry doesn't end in main layer.");
719                         strv_free(ancestry);
720                         r = -EBADMSG;
721                         goto finish;
722                 }
723
724                 log_info("Ancestor lookup succeeded, requires layers:\n");
725                 STRV_FOREACH(k, ancestry)
726                         log_info("\t%s", *k);
727
728                 strv_free(i->ancestry);
729                 i->ancestry = ancestry;
730                 i->n_ancestry = n;
731                 i->current_ancestry = 0;
732
733                 dkr_import_report_progress(i, DKR_DOWNLOADING);
734
735                 r = dkr_import_pull_layer(i);
736                 if (r < 0)
737                         goto finish;
738
739         } else if (i->layer_job == j) {
740                 assert(i->temp_path);
741                 assert(i->final_path);
742
743                 j->disk_fd = safe_close(j->disk_fd);
744
745                 if (i->tar_pid > 0) {
746                         r = wait_for_terminate_and_warn("tar", i->tar_pid, true);
747                         i->tar_pid = 0;
748                         if (r < 0)
749                                 goto finish;
750                 }
751
752                 r = aufs_resolve(i->temp_path);
753                 if (r < 0) {
754                         log_error_errno(r, "Failed to resolve aufs whiteouts: %m");
755                         goto finish;
756                 }
757
758                 r = btrfs_subvol_set_read_only(i->temp_path, true);
759                 if (r < 0) {
760                         log_error_errno(r, "Failed to mark snapshot read-only: %m");
761                         goto finish;
762                 }
763
764                 if (rename(i->temp_path, i->final_path) < 0) {
765                         log_error_errno(errno, "Failed to rename snaphsot: %m");
766                         goto finish;
767                 }
768
769                 log_info("Completed writing to layer %s.", i->final_path);
770
771                 i->layer_job = import_job_unref(i->layer_job);
772                 free(i->temp_path);
773                 i->temp_path = NULL;
774                 free(i->final_path);
775                 i->final_path = NULL;
776
777                 i->current_ancestry ++;
778                 r = dkr_import_pull_layer(i);
779                 if (r < 0)
780                         goto finish;
781
782         } else if (i->json_job != j)
783                 assert_not_reached("Got finished event for unknown curl object");
784
785         if (!dkr_import_is_done(i))
786                 return;
787
788         dkr_import_report_progress(i, DKR_COPYING);
789
790         r = dkr_import_make_local_copy(i);
791         if (r < 0)
792                 goto finish;
793
794         r = 0;
795
796 finish:
797         if (i->on_finished)
798                 i->on_finished(i, r, i->userdata);
799         else
800                 sd_event_exit(i->event, r);
801 }
802
803 static int dkr_import_job_on_header(ImportJob *j, const char *header, size_t sz)  {
804         _cleanup_free_ char *registry = NULL;
805         char *token;
806         DkrImport *i;
807         int r;
808
809         assert(j);
810         assert(j->userdata);
811
812         i = j->userdata;
813
814         r = curl_header_strdup(header, sz, HEADER_TOKEN, &token);
815         if (r < 0)
816                 return log_oom();
817         if (r > 0) {
818                 free(i->response_token);
819                 i->response_token = token;
820                 return 0;
821         }
822
823         r = curl_header_strdup(header, sz, HEADER_REGISTRY, &registry);
824         if (r < 0)
825                 return log_oom();
826         if (r > 0) {
827                 char **l, **k;
828
829                 l = strv_split(registry, ",");
830                 if (!l)
831                         return log_oom();
832
833                 STRV_FOREACH(k, l) {
834                         if (!hostname_is_valid(*k)) {
835                                 log_error("Registry hostname is not valid.");
836                                 strv_free(l);
837                                 return -EBADMSG;
838                         }
839                 }
840
841                 strv_free(i->response_registries);
842                 i->response_registries = l;
843         }
844
845         return 0;
846 }
847
848 int dkr_import_pull(DkrImport *i, const char *name, const char *tag, const char *local, bool force_local) {
849         const char *url;
850         int r;
851
852         assert(i);
853
854         if (!dkr_name_is_valid(name))
855                 return -EINVAL;
856
857         if (tag && !dkr_tag_is_valid(tag))
858                 return -EINVAL;
859
860         if (local && !machine_name_is_valid(local))
861                 return -EINVAL;
862
863         if (i->images_job)
864                 return -EBUSY;
865
866         if (!tag)
867                 tag = "latest";
868
869         r = free_and_strdup(&i->local, local);
870         if (r < 0)
871                 return r;
872         i->force_local = force_local;
873
874         r = free_and_strdup(&i->name, name);
875         if (r < 0)
876                 return r;
877         r = free_and_strdup(&i->tag, tag);
878         if (r < 0)
879                 return r;
880
881         url = strjoina(i->index_url, "/v1/repositories/", name, "/images");
882
883         r = import_job_new(&i->images_job, url, i->glue, i);
884         if (r < 0)
885                 return r;
886
887         r = dkr_import_add_token(i, i->images_job);
888         if (r < 0)
889                 return r;
890
891         i->images_job->on_finished = dkr_import_job_on_finished;
892         i->images_job->on_header = dkr_import_job_on_header;
893         i->images_job->on_progress = dkr_import_job_on_progress;
894
895         return import_job_begin(i->images_job);
896 }