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-gpt.h"
29 #include "import-dkr.h"
31 static bool arg_force = false;
32 static const char *arg_image_root = "/var/lib/container";
34 static const char* arg_dkr_index_url = DEFAULT_DKR_INDEX_URL;
36 static void on_gpt_finished(GptImport *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_gpt(int argc, char *argv[], void *userdata) {
49 _cleanup_(gpt_import_unrefp) GptImport *import = NULL;
50 _cleanup_event_unref_ sd_event *event = NULL;
51 const char *url, *local, *suffix;
55 if (!gpt_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, ".gpt");
84 local = strndupa(local, suffix - local);
86 if (!machine_name_is_valid(local)) {
87 log_error("Local image name '%s' is not valid.", local);
91 p = strappenda(arg_image_root, "/", local, ".gpt");
92 if (laccess(p, F_OK) >= 0) {
94 log_info("Image '%s' already exists.", local);
97 } else if (errno != ENOENT)
98 return log_error_errno(errno, "Can't check if image '%s' already exists: %m", local);
100 log_info("Pulling '%s', saving as '%s'.", url, local);
102 log_info("Pulling '%s'.", url);
104 r = sd_event_default(&event);
106 return log_error_errno(r, "Failed to allocate event loop: %m");
108 assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0);
109 sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
110 sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
112 r = gpt_import_new(&import, event, arg_image_root, on_gpt_finished, event);
114 return log_error_errno(r, "Failed to allocate importer: %m");
116 r = gpt_import_pull(import, url, local, arg_force);
118 return log_error_errno(r, "Failed to pull image: %m");
120 r = sd_event_loop(event);
122 return log_error_errno(r, "Failed to run event loop: %m");
124 log_info("Exiting.");
129 static void on_dkr_finished(DkrImport *import, int error, void *userdata) {
130 sd_event *event = userdata;
134 log_info("Operation completed successfully.");
136 log_info_errno(error, "Operation failed: %m");
138 sd_event_exit(event, error);
141 static int pull_dkr(int argc, char *argv[], void *userdata) {
142 _cleanup_(dkr_import_unrefp) DkrImport *import = NULL;
143 _cleanup_event_unref_ sd_event *event = NULL;
144 const char *name, *tag, *local;
147 if (!arg_dkr_index_url) {
148 log_error("Please specify an index URL with --dkr-index-url=");
152 tag = strchr(argv[1], ':');
154 name = strndupa(argv[1], tag - argv[1]);
161 if (!dkr_name_is_valid(name)) {
162 log_error("Remote name '%s' is not valid.", name);
166 if (!dkr_tag_is_valid(tag)) {
167 log_error("Tag name '%s' is not valid.", tag);
174 local = strchr(name, '/');
181 if (isempty(local) || streq(local, "-"))
187 if (!machine_name_is_valid(local)) {
188 log_error("Local image name '%s' is not valid.", local);
192 p = strappenda(arg_image_root, "/", local);
193 if (laccess(p, F_OK) >= 0) {
195 log_info("Image '%s' already exists.", local);
198 } else if (errno != ENOENT)
199 return log_error_errno(errno, "Can't check if image '%s' already exists: %m", local);
201 log_info("Pulling '%s' with tag '%s', saving as '%s'.", name, tag, local);
203 log_info("Pulling '%s' with tag '%s'.", name, tag);
205 r = sd_event_default(&event);
207 return log_error_errno(r, "Failed to allocate event loop: %m");
209 assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0);
210 sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
211 sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
213 r = dkr_import_new(&import, event, arg_dkr_index_url, arg_image_root, on_dkr_finished, event);
215 return log_error_errno(r, "Failed to allocate importer: %m");
217 r = dkr_import_pull(import, name, tag, local, arg_force);
219 return log_error_errno(r, "Failed to pull image: %m");
221 r = sd_event_loop(event);
223 return log_error_errno(r, "Failed to run event loop: %m");
225 log_info("Exiting.");
230 static int help(int argc, char *argv[], void *userdata) {
232 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
233 "Import container or virtual machine image.\n\n"
234 " -h --help Show this help\n"
235 " --version Show package version\n"
236 " --force Force creation of image\n"
237 " --image-root= Image root directory\n"
238 " --dkr-index-url=URL Specify index URL to use for downloads\n\n"
240 " pull-dkr REMOTE [NAME] Download a DKR image\n"
241 " pull-gpt URL [NAME] Download a GPT image\n",
242 program_invocation_short_name);
247 static int parse_argv(int argc, char *argv[]) {
256 static const struct option options[] = {
257 { "help", no_argument, NULL, 'h' },
258 { "version", no_argument, NULL, ARG_VERSION },
259 { "force", no_argument, NULL, ARG_FORCE },
260 { "dkr-index-url", required_argument, NULL, ARG_DKR_INDEX_URL },
261 { "image-root", required_argument, NULL, ARG_IMAGE_ROOT },
270 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
275 return help(0, NULL, NULL);
278 puts(PACKAGE_STRING);
279 puts(SYSTEMD_FEATURES);
286 case ARG_DKR_INDEX_URL:
287 if (!dkr_url_is_valid(optarg)) {
288 log_error("Index URL is not valid: %s", optarg);
292 arg_dkr_index_url = optarg;
296 arg_image_root = optarg;
303 assert_not_reached("Unhandled option");
309 static int import_main(int argc, char *argv[]) {
311 static const Verb verbs[] = {
312 { "help", VERB_ANY, VERB_ANY, 0, help },
313 { "pull-dkr", 2, 3, 0, pull_dkr },
314 { "pull-gpt", 2, 3, 0, pull_gpt },
318 return dispatch_verb(argc, argv, verbs, NULL);
321 int main(int argc, char *argv[]) {
324 setlocale(LC_ALL, "");
325 log_parse_environment();
328 r = parse_argv(argc, argv);
332 r = import_main(argc, argv);
335 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;