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 pull_raw(int argc, char *argv[], void *userdata) {
49 _cleanup_(raw_import_unrefp) RawImport *import = NULL;
50 _cleanup_event_unref_ sd_event *event = NULL;
51 const char *url, *local, *suffix;
55 if (!raw_url_is_valid(url)) {
56 log_error("URL '%s' is not valid.", url);
65 e = url + strlen(url);
66 while (e > url && e[-1] == '/')
70 while (p > url && p[-1] != '/')
73 local = strndupa(p, e - p);
76 if (isempty(local) || streq(local, "-"))
82 suffix = endswith(local, ".raw.xz");
84 suffix = endswith(local, ".raw");
86 suffix = endswith(local, ".xz");
88 local = strndupa(local, suffix - local);
90 if (!machine_name_is_valid(local)) {
91 log_error("Local image name '%s' is not valid.", local);
95 p = strappenda(arg_image_root, "/", local, ".raw");
96 if (laccess(p, F_OK) >= 0) {
98 log_info("Image '%s' already exists.", local);
101 } else if (errno != ENOENT)
102 return log_error_errno(errno, "Can't check if image '%s' already exists: %m", local);
104 log_info("Pulling '%s', saving as '%s'.", url, local);
106 log_info("Pulling '%s'.", url);
108 r = sd_event_default(&event);
110 return log_error_errno(r, "Failed to allocate event loop: %m");
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);
116 r = raw_import_new(&import, event, arg_image_root, on_raw_finished, event);
118 return log_error_errno(r, "Failed to allocate importer: %m");
120 r = raw_import_pull(import, url, local, arg_force);
122 return log_error_errno(r, "Failed to pull image: %m");
124 r = sd_event_loop(event);
126 return log_error_errno(r, "Failed to run event loop: %m");
128 log_info("Exiting.");
133 static void on_dkr_finished(DkrImport *import, int error, void *userdata) {
134 sd_event *event = userdata;
138 log_info("Operation completed successfully.");
140 log_info_errno(error, "Operation failed: %m");
142 sd_event_exit(event, error);
145 static int pull_dkr(int argc, char *argv[], void *userdata) {
146 _cleanup_(dkr_import_unrefp) DkrImport *import = NULL;
147 _cleanup_event_unref_ sd_event *event = NULL;
148 const char *name, *tag, *local;
151 if (!arg_dkr_index_url) {
152 log_error("Please specify an index URL with --dkr-index-url=");
156 tag = strchr(argv[1], ':');
158 name = strndupa(argv[1], tag - argv[1]);
165 if (!dkr_name_is_valid(name)) {
166 log_error("Remote name '%s' is not valid.", name);
170 if (!dkr_tag_is_valid(tag)) {
171 log_error("Tag name '%s' is not valid.", tag);
178 local = strchr(name, '/');
185 if (isempty(local) || streq(local, "-"))
191 if (!machine_name_is_valid(local)) {
192 log_error("Local image name '%s' is not valid.", local);
196 p = strappenda(arg_image_root, "/", local);
197 if (laccess(p, F_OK) >= 0) {
199 log_info("Image '%s' already exists.", local);
202 } else if (errno != ENOENT)
203 return log_error_errno(errno, "Can't check if image '%s' already exists: %m", local);
205 log_info("Pulling '%s' with tag '%s', saving as '%s'.", name, tag, local);
207 log_info("Pulling '%s' with tag '%s'.", name, tag);
209 r = sd_event_default(&event);
211 return log_error_errno(r, "Failed to allocate event loop: %m");
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);
217 r = dkr_import_new(&import, event, arg_dkr_index_url, arg_image_root, on_dkr_finished, event);
219 return log_error_errno(r, "Failed to allocate importer: %m");
221 r = dkr_import_pull(import, name, tag, local, arg_force);
223 return log_error_errno(r, "Failed to pull image: %m");
225 r = sd_event_loop(event);
227 return log_error_errno(r, "Failed to run event loop: %m");
229 log_info("Exiting.");
234 static int help(int argc, char *argv[], void *userdata) {
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"
240 " --force Force creation of image\n"
241 " --image-root= Image root directory\n"
242 " --dkr-index-url=URL Specify index URL to use for downloads\n\n"
244 " pull-dkr REMOTE [NAME] Download a DKR image\n"
245 " pull-raw URL [NAME] Download a RAW image\n",
246 program_invocation_short_name);
251 static int parse_argv(int argc, char *argv[]) {
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 },
264 { "dkr-index-url", required_argument, NULL, ARG_DKR_INDEX_URL },
265 { "image-root", required_argument, NULL, ARG_IMAGE_ROOT },
274 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
279 return help(0, NULL, NULL);
282 puts(PACKAGE_STRING);
283 puts(SYSTEMD_FEATURES);
290 case ARG_DKR_INDEX_URL:
291 if (!dkr_url_is_valid(optarg)) {
292 log_error("Index URL is not valid: %s", optarg);
296 arg_dkr_index_url = optarg;
300 arg_image_root = optarg;
307 assert_not_reached("Unhandled option");
313 static int import_main(int argc, char *argv[]) {
315 static const Verb verbs[] = {
316 { "help", VERB_ANY, VERB_ANY, 0, help },
317 { "pull-dkr", 2, 3, 0, pull_dkr },
318 { "pull-raw", 2, 3, 0, pull_raw },
322 return dispatch_verb(argc, argv, verbs, NULL);
325 int main(int argc, char *argv[]) {
328 setlocale(LC_ALL, "");
329 log_parse_environment();
332 r = parse_argv(argc, argv);
336 r = import_main(argc, argv);
339 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;