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