1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 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/>.
25 #include "event-util.h"
28 #include "import-raw.h"
29 #include "import-dkr.h"
31 static bool arg_force = false;
32 static const char *arg_image_root = "/var/lib/machines";
34 static const char* arg_dkr_index_url = DEFAULT_DKR_INDEX_URL;
36 static void on_raw_finished(RawImport *import, int error, void *userdata) {
37 sd_event *event = userdata;
41 log_info("Operation completed successfully.");
43 log_info_errno(error, "Operation failed: %m");
45 sd_event_exit(event, error);
48 static int strip_raw_suffixes(const char *p, char **ret) {
49 static const char suffixes[] =
55 _cleanup_free_ char *q = NULL;
65 NULSTR_FOREACH(sfx, suffixes) {
85 static int pull_raw(int argc, char *argv[], void *userdata) {
86 _cleanup_(raw_import_unrefp) RawImport *import = NULL;
87 _cleanup_event_unref_ sd_event *event = NULL;
88 const char *url, *local;
89 _cleanup_free_ char *l = NULL;
93 if (!http_url_is_valid(url)) {
94 log_error("URL '%s' is not valid.", url);
103 e = url + strlen(url);
104 while (e > url && e[-1] == '/')
108 while (p > url && p[-1] != '/')
111 local = strndupa(p, e - p);
114 if (isempty(local) || streq(local, "-"))
120 r = strip_raw_suffixes(local, &l);
126 if (!machine_name_is_valid(local)) {
127 log_error("Local image name '%s' is not valid.", local);
131 p = strappenda(arg_image_root, "/", local, ".raw");
132 if (laccess(p, F_OK) >= 0) {
134 log_info("Image '%s' already exists.", local);
137 } else if (errno != ENOENT)
138 return log_error_errno(errno, "Can't check if image '%s' already exists: %m", local);
140 log_info("Pulling '%s', saving as '%s'.", url, local);
142 log_info("Pulling '%s'.", url);
144 r = sd_event_default(&event);
146 return log_error_errno(r, "Failed to allocate event loop: %m");
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);
152 r = raw_import_new(&import, event, arg_image_root, on_raw_finished, event);
154 return log_error_errno(r, "Failed to allocate importer: %m");
156 r = raw_import_pull(import, url, local, arg_force);
158 return log_error_errno(r, "Failed to pull image: %m");
160 r = sd_event_loop(event);
162 return log_error_errno(r, "Failed to run event loop: %m");
164 log_info("Exiting.");
169 static void on_dkr_finished(DkrImport *import, int error, void *userdata) {
170 sd_event *event = userdata;
174 log_info("Operation completed successfully.");
176 log_info_errno(error, "Operation failed: %m");
178 sd_event_exit(event, error);
181 static int pull_dkr(int argc, char *argv[], void *userdata) {
182 _cleanup_(dkr_import_unrefp) DkrImport *import = NULL;
183 _cleanup_event_unref_ sd_event *event = NULL;
184 const char *name, *tag, *local;
187 if (!arg_dkr_index_url) {
188 log_error("Please specify an index URL with --dkr-index-url=");
192 tag = strchr(argv[1], ':');
194 name = strndupa(argv[1], tag - argv[1]);
201 if (!dkr_name_is_valid(name)) {
202 log_error("Remote name '%s' is not valid.", name);
206 if (!dkr_tag_is_valid(tag)) {
207 log_error("Tag name '%s' is not valid.", tag);
214 local = strchr(name, '/');
221 if (isempty(local) || streq(local, "-"))
227 if (!machine_name_is_valid(local)) {
228 log_error("Local image name '%s' is not valid.", local);
232 p = strappenda(arg_image_root, "/", local);
233 if (laccess(p, F_OK) >= 0) {
235 log_info("Image '%s' already exists.", local);
238 } else if (errno != ENOENT)
239 return log_error_errno(errno, "Can't check if image '%s' already exists: %m", local);
241 log_info("Pulling '%s' with tag '%s', saving as '%s'.", name, tag, local);
243 log_info("Pulling '%s' with tag '%s'.", name, tag);
245 r = sd_event_default(&event);
247 return log_error_errno(r, "Failed to allocate event loop: %m");
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);
253 r = dkr_import_new(&import, event, arg_dkr_index_url, arg_image_root, on_dkr_finished, event);
255 return log_error_errno(r, "Failed to allocate importer: %m");
257 r = dkr_import_pull(import, name, tag, local, arg_force);
259 return log_error_errno(r, "Failed to pull image: %m");
261 r = sd_event_loop(event);
263 return log_error_errno(r, "Failed to run event loop: %m");
265 log_info("Exiting.");
270 static int help(int argc, char *argv[], void *userdata) {
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"
276 " --force Force creation of image\n"
277 " --image-root= Image root directory\n"
278 " --dkr-index-url=URL Specify index URL to use for downloads\n\n"
280 " pull-dkr REMOTE [NAME] Download a DKR image\n"
281 " pull-raw URL [NAME] Download a RAW image\n",
282 program_invocation_short_name);
287 static int parse_argv(int argc, char *argv[]) {
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 },
300 { "dkr-index-url", required_argument, NULL, ARG_DKR_INDEX_URL },
301 { "image-root", required_argument, NULL, ARG_IMAGE_ROOT },
310 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
315 return help(0, NULL, NULL);
318 puts(PACKAGE_STRING);
319 puts(SYSTEMD_FEATURES);
326 case ARG_DKR_INDEX_URL:
327 if (!dkr_url_is_valid(optarg)) {
328 log_error("Index URL is not valid: %s", optarg);
332 arg_dkr_index_url = optarg;
336 arg_image_root = optarg;
343 assert_not_reached("Unhandled option");
349 static int import_main(int argc, char *argv[]) {
351 static const Verb verbs[] = {
352 { "help", VERB_ANY, VERB_ANY, 0, help },
353 { "pull-dkr", 2, 3, 0, pull_dkr },
354 { "pull-raw", 2, 3, 0, pull_raw },
358 return dispatch_verb(argc, argv, verbs, NULL);
361 int main(int argc, char *argv[]) {
364 setlocale(LC_ALL, "");
365 log_parse_environment();
368 r = parse_argv(argc, argv);
372 r = import_main(argc, argv);
375 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;