]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/import/import.c
import: support downloading .xz compressed images
[thirdparty/systemd.git] / src / import / import.c
CommitLineData
72648326
LP
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 <getopt.h>
23
24#include "sd-event.h"
25#include "event-util.h"
26#include "verbs.h"
27#include "build.h"
aceac2f0 28#include "import-raw.h"
91f4347e 29#include "import-dkr.h"
72648326
LP
30
31static bool arg_force = false;
5f129649 32static const char *arg_image_root = "/var/lib/machines";
72648326 33
91f4347e
LP
34static const char* arg_dkr_index_url = DEFAULT_DKR_INDEX_URL;
35
aceac2f0 36static void on_raw_finished(RawImport *import, int error, void *userdata) {
90199220
LP
37 sd_event *event = userdata;
38 assert(import);
39
40 if (error == 0)
41 log_info("Operation completed successfully.");
42 else
43 log_info_errno(error, "Operation failed: %m");
44
45 sd_event_exit(event, error);
46}
47
aceac2f0
LP
48static int pull_raw(int argc, char *argv[], void *userdata) {
49 _cleanup_(raw_import_unrefp) RawImport *import = NULL;
90199220 50 _cleanup_event_unref_ sd_event *event = NULL;
90199220
LP
51 const char *url, *local, *suffix;
52 int r;
53
54 url = argv[1];
aceac2f0 55 if (!raw_url_is_valid(url)) {
90199220
LP
56 log_error("URL '%s' is not valid.", url);
57 return -EINVAL;
58 }
59
8620a9a3
LP
60 if (argc >= 3)
61 local = argv[2];
62 else {
90199220
LP
63 const char *e, *p;
64
65 e = url + strlen(url);
66 while (e > url && e[-1] == '/')
67 e--;
68
69 p = e;
70 while (p > url && p[-1] != '/')
71 p--;
72
8620a9a3 73 local = strndupa(p, e - p);
90199220
LP
74 }
75
8620a9a3
LP
76 if (isempty(local) || streq(local, "-"))
77 local = NULL;
90199220 78
8620a9a3
LP
79 if (local) {
80 const char *p;
90199220 81
49bb233b
LP
82 suffix = endswith(local, ".raw.xz");
83 if (!suffix)
84 suffix = endswith(local, ".raw");
85 if (!suffix)
86 suffix = endswith(local, ".xz");
8620a9a3
LP
87 if (suffix)
88 local = strndupa(local, suffix - local);
89
90 if (!machine_name_is_valid(local)) {
91 log_error("Local image name '%s' is not valid.", local);
92 return -EINVAL;
93 }
94
aceac2f0 95 p = strappenda(arg_image_root, "/", local, ".raw");
8620a9a3
LP
96 if (laccess(p, F_OK) >= 0) {
97 if (!arg_force) {
98 log_info("Image '%s' already exists.", local);
99 return 0;
100 }
101 } else if (errno != ENOENT)
102 return log_error_errno(errno, "Can't check if image '%s' already exists: %m", local);
90199220 103
8620a9a3
LP
104 log_info("Pulling '%s', saving as '%s'.", url, local);
105 } else
106 log_info("Pulling '%s'.", url);
90199220
LP
107
108 r = sd_event_default(&event);
109 if (r < 0)
110 return log_error_errno(r, "Failed to allocate event loop: %m");
111
112 assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0);
113 sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
114 sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
115
aceac2f0 116 r = raw_import_new(&import, event, arg_image_root, on_raw_finished, event);
90199220
LP
117 if (r < 0)
118 return log_error_errno(r, "Failed to allocate importer: %m");
119
aceac2f0 120 r = raw_import_pull(import, url, local, arg_force);
90199220
LP
121 if (r < 0)
122 return log_error_errno(r, "Failed to pull image: %m");
123
124 r = sd_event_loop(event);
125 if (r < 0)
126 return log_error_errno(r, "Failed to run event loop: %m");
127
128 log_info("Exiting.");
129
130 return 0;
131}
132
133static void on_dkr_finished(DkrImport *import, int error, void *userdata) {
72648326
LP
134 sd_event *event = userdata;
135 assert(import);
136
137 if (error == 0)
138 log_info("Operation completed successfully.");
139 else
140 log_info_errno(error, "Operation failed: %m");
141
142 sd_event_exit(event, error);
143}
144
91f4347e
LP
145static int pull_dkr(int argc, char *argv[], void *userdata) {
146 _cleanup_(dkr_import_unrefp) DkrImport *import = NULL;
72648326
LP
147 _cleanup_event_unref_ sd_event *event = NULL;
148 const char *name, *tag, *local;
149 int r;
150
91f4347e
LP
151 if (!arg_dkr_index_url) {
152 log_error("Please specify an index URL with --dkr-index-url=");
153 return -EINVAL;
154 }
155
72648326
LP
156 tag = strchr(argv[1], ':');
157 if (tag) {
158 name = strndupa(argv[1], tag - argv[1]);
159 tag++;
160 } else {
161 name = argv[1];
162 tag = "latest";
163 }
164
8620a9a3
LP
165 if (!dkr_name_is_valid(name)) {
166 log_error("Remote name '%s' is not valid.", name);
167 return -EINVAL;
168 }
169
170 if (!dkr_tag_is_valid(tag)) {
171 log_error("Tag name '%s' is not valid.", tag);
172 return -EINVAL;
173 }
174
72648326
LP
175 if (argc >= 3)
176 local = argv[2];
177 else {
178 local = strchr(name, '/');
179 if (local)
180 local++;
181 else
182 local = name;
183 }
184
0c7bf33a 185 if (isempty(local) || streq(local, "-"))
72648326
LP
186 local = NULL;
187
72648326
LP
188 if (local) {
189 const char *p;
190
0c7bf33a 191 if (!machine_name_is_valid(local)) {
72648326
LP
192 log_error("Local image name '%s' is not valid.", local);
193 return -EINVAL;
194 }
195
087682d1 196 p = strappenda(arg_image_root, "/", local);
72648326
LP
197 if (laccess(p, F_OK) >= 0) {
198 if (!arg_force) {
199 log_info("Image '%s' already exists.", local);
200 return 0;
201 }
202 } else if (errno != ENOENT)
203 return log_error_errno(errno, "Can't check if image '%s' already exists: %m", local);
204
205 log_info("Pulling '%s' with tag '%s', saving as '%s'.", name, tag, local);
206 } else
207 log_info("Pulling '%s' with tag '%s'.", name, tag);
208
209 r = sd_event_default(&event);
210 if (r < 0)
211 return log_error_errno(r, "Failed to allocate event loop: %m");
212
213 assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0);
214 sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
215 sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
216
087682d1 217 r = dkr_import_new(&import, event, arg_dkr_index_url, arg_image_root, on_dkr_finished, event);
72648326
LP
218 if (r < 0)
219 return log_error_errno(r, "Failed to allocate importer: %m");
220
ea1ae8c3 221 r = dkr_import_pull(import, name, tag, local, arg_force);
72648326
LP
222 if (r < 0)
223 return log_error_errno(r, "Failed to pull image: %m");
224
225 r = sd_event_loop(event);
226 if (r < 0)
227 return log_error_errno(r, "Failed to run event loop: %m");
228
229 log_info("Exiting.");
230
231 return 0;
232}
233
234static int help(int argc, char *argv[], void *userdata) {
235
236 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
237 "Import container or virtual machine image.\n\n"
238 " -h --help Show this help\n"
239 " --version Show package version\n"
91f4347e 240 " --force Force creation of image\n"
087682d1 241 " --image-root= Image root directory\n"
91f4347e 242 " --dkr-index-url=URL Specify index URL to use for downloads\n\n"
72648326 243 "Commands:\n"
90199220 244 " pull-dkr REMOTE [NAME] Download a DKR image\n"
aceac2f0 245 " pull-raw URL [NAME] Download a RAW image\n",
72648326
LP
246 program_invocation_short_name);
247
248 return 0;
249}
250
251static int parse_argv(int argc, char *argv[]) {
252
253 enum {
254 ARG_VERSION = 0x100,
255 ARG_FORCE,
91f4347e 256 ARG_DKR_INDEX_URL,
087682d1 257 ARG_IMAGE_ROOT,
72648326
LP
258 };
259
260 static const struct option options[] = {
261 { "help", no_argument, NULL, 'h' },
262 { "version", no_argument, NULL, ARG_VERSION },
263 { "force", no_argument, NULL, ARG_FORCE },
91f4347e 264 { "dkr-index-url", required_argument, NULL, ARG_DKR_INDEX_URL },
087682d1 265 { "image-root", required_argument, NULL, ARG_IMAGE_ROOT },
72648326
LP
266 {}
267 };
268
269 int c;
270
271 assert(argc >= 0);
272 assert(argv);
273
274 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
275
276 switch (c) {
277
278 case 'h':
7eeeb28e 279 return help(0, NULL, NULL);
72648326
LP
280
281 case ARG_VERSION:
282 puts(PACKAGE_STRING);
283 puts(SYSTEMD_FEATURES);
284 return 0;
285
286 case ARG_FORCE:
287 arg_force = true;
288 break;
289
91f4347e
LP
290 case ARG_DKR_INDEX_URL:
291 if (!dkr_url_is_valid(optarg)) {
292 log_error("Index URL is not valid: %s", optarg);
293 return -EINVAL;
294 }
295
296 arg_dkr_index_url = optarg;
297 break;
298
087682d1
LP
299 case ARG_IMAGE_ROOT:
300 arg_image_root = optarg;
301 break;
302
72648326
LP
303 case '?':
304 return -EINVAL;
305
306 default:
307 assert_not_reached("Unhandled option");
308 }
309
310 return 1;
311}
312
313static int import_main(int argc, char *argv[]) {
314
7eeeb28e 315 static const Verb verbs[] = {
72648326 316 { "help", VERB_ANY, VERB_ANY, 0, help },
91f4347e 317 { "pull-dkr", 2, 3, 0, pull_dkr },
aceac2f0 318 { "pull-raw", 2, 3, 0, pull_raw },
72648326
LP
319 {}
320 };
321
322 return dispatch_verb(argc, argv, verbs, NULL);
323}
324
325int main(int argc, char *argv[]) {
326 int r;
327
328 setlocale(LC_ALL, "");
329 log_parse_environment();
330 log_open();
331
332 r = parse_argv(argc, argv);
333 if (r <= 0)
334 goto finish;
335
336 r = import_main(argc, argv);
337
338finish:
339 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
340}