chiark / gitweb /
import: rename 'poll-dck' to 'pull-dkr'
[elogind.git] / src / import / import.c
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"
28 #include "import-dkr.h"
29
30 static bool arg_force = false;
31
32 static const char* arg_dkr_index_url = DEFAULT_DKR_INDEX_URL;
33
34 static void on_finished(DkrImport *import, int error, void *userdata) {
35         sd_event *event = userdata;
36         assert(import);
37
38         if (error == 0)
39                 log_info("Operation completed successfully.");
40         else
41                 log_info_errno(error, "Operation failed: %m");
42
43         sd_event_exit(event, error);
44 }
45
46 static int pull_dkr(int argc, char *argv[], void *userdata) {
47         _cleanup_(dkr_import_unrefp) DkrImport *import = NULL;
48         _cleanup_event_unref_ sd_event *event = NULL;
49         const char *name, *tag, *local;
50         int r;
51
52         if (!arg_dkr_index_url) {
53                 log_error("Please specify an index URL with --dkr-index-url=");
54                 return -EINVAL;
55         }
56
57         tag = strchr(argv[1], ':');
58         if (tag) {
59                 name = strndupa(argv[1], tag - argv[1]);
60                 tag++;
61         } else {
62                 name = argv[1];
63                 tag = "latest";
64         }
65
66         if (argc >= 3)
67                 local = argv[2];
68         else {
69                 local = strchr(name, '/');
70                 if (local)
71                         local++;
72                 else
73                         local = name;
74         }
75
76         if (streq(local, "-") || isempty(local))
77                 local = NULL;
78
79         if (!dkr_name_is_valid(name)) {
80                 log_error("Remote name '%s' is not valid.", name);
81                 return -EINVAL;
82         }
83
84         if (!dkr_tag_is_valid(tag)) {
85                 log_error("Tag name '%s' is not valid.", tag);
86                 return -EINVAL;
87         }
88
89         if (local) {
90                 const char *p;
91
92                 if (!machine_name_is_valid(tag)) {
93                         log_error("Local image name '%s' is not valid.", local);
94                         return -EINVAL;
95                 }
96
97                 p = strappenda("/var/lib/container/", local);
98                 if (laccess(p, F_OK) >= 0) {
99                         if (!arg_force) {
100                                 log_info("Image '%s' already exists.", local);
101                                 return 0;
102                         }
103                 } else if (errno != ENOENT)
104                         return log_error_errno(errno, "Can't check if image '%s' already exists: %m", local);
105
106                 log_info("Pulling '%s' with tag '%s', saving as '%s'.", name, tag, local);
107         } else
108                 log_info("Pulling '%s' with tag '%s'.", name, tag);
109
110         r = sd_event_default(&event);
111         if (r < 0)
112                 return log_error_errno(r, "Failed to allocate event loop: %m");
113
114         assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0);
115         sd_event_add_signal(event, NULL, SIGTERM, NULL,  NULL);
116         sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
117
118         r = dkr_import_new(&import, event, on_finished, event);
119         if (r < 0)
120                 return log_error_errno(r, "Failed to allocate importer: %m");
121
122         r = dkr_import_pull(import, arg_dkr_index_url, name, tag, local, arg_force);
123         if (r < 0)
124                 return log_error_errno(r, "Failed to pull image: %m");
125
126         r = sd_event_loop(event);
127         if (r < 0)
128                 return log_error_errno(r, "Failed to run event loop: %m");
129
130         log_info("Exiting.");
131
132         return 0;
133 }
134
135 static int help(int argc, char *argv[], void *userdata) {
136
137         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
138                "Import container or virtual machine image.\n\n"
139                "  -h --help                   Show this help\n"
140                "     --version                Show package version\n"
141                "     --force                  Force creation of image\n"
142                "     --dkr-index-url=URL      Specify index URL to use for downloads\n\n"
143                "Commands:\n"
144                "  pull-dkr REMOTE [NAME]      Download an image\n",
145                program_invocation_short_name);
146
147         return 0;
148 }
149
150 static int parse_argv(int argc, char *argv[]) {
151
152         enum {
153                 ARG_VERSION = 0x100,
154                 ARG_FORCE,
155                 ARG_DKR_INDEX_URL,
156         };
157
158         static const struct option options[] = {
159                 { "help",            no_argument,       NULL, 'h'                 },
160                 { "version",         no_argument,       NULL, ARG_VERSION         },
161                 { "force",           no_argument,       NULL, ARG_FORCE           },
162                 { "dkr-index-url",   required_argument, NULL, ARG_DKR_INDEX_URL   },
163                 {}
164         };
165
166         int c;
167
168         assert(argc >= 0);
169         assert(argv);
170
171         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
172
173                 switch (c) {
174
175                 case 'h':
176                         return help(0, NULL, NULL);
177
178                 case ARG_VERSION:
179                         puts(PACKAGE_STRING);
180                         puts(SYSTEMD_FEATURES);
181                         return 0;
182
183                 case ARG_FORCE:
184                         arg_force = true;
185                         break;
186
187                 case ARG_DKR_INDEX_URL:
188                         if (!dkr_url_is_valid(optarg)) {
189                                 log_error("Index URL is not valid: %s", optarg);
190                                 return -EINVAL;
191                         }
192
193                         arg_dkr_index_url = optarg;
194                         break;
195
196                 case '?':
197                         return -EINVAL;
198
199                 default:
200                         assert_not_reached("Unhandled option");
201                 }
202
203         return 1;
204 }
205
206 static int import_main(int argc, char *argv[]) {
207
208         static const Verb verbs[] = {
209                 { "help",     VERB_ANY, VERB_ANY, 0, help     },
210                 { "pull-dkr", 2,        3,        0, pull_dkr },
211                 {}
212         };
213
214         return dispatch_verb(argc, argv, verbs, NULL);
215 }
216
217 int main(int argc, char *argv[]) {
218         int r;
219
220         setlocale(LC_ALL, "");
221         log_parse_environment();
222         log_open();
223
224         r = parse_argv(argc, argv);
225         if (r <= 0)
226                 goto finish;
227
228         r = import_main(argc, argv);
229
230 finish:
231         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
232 }