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