]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/import/import.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.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 2015 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
26 #include "event-util.h"
27 #include "hostname-util.h"
28 #include "import-raw.h"
29 #include "import-tar.h"
30 #include "import-util.h"
31 #include "machine-image.h"
32 #include "signal-util.h"
33 #include "string-util.h"
34 #include "verbs.h"
35
36 static bool arg_force = false;
37 static bool arg_read_only = false;
38 static const char *arg_image_root = "/var/lib/machines";
39
40 static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
41 log_notice("Transfer aborted.");
42 sd_event_exit(sd_event_source_get_event(s), EINTR);
43 return 0;
44 }
45
46 static void on_tar_finished(TarImport *import, int error, void *userdata) {
47 sd_event *event = userdata;
48 assert(import);
49
50 if (error == 0)
51 log_info("Operation completed successfully.");
52
53 sd_event_exit(event, abs(error));
54 }
55
56 static int import_tar(int argc, char *argv[], void *userdata) {
57 _cleanup_(tar_import_unrefp) TarImport *import = NULL;
58 _cleanup_event_unref_ sd_event *event = NULL;
59 const char *path = NULL, *local = NULL;
60 _cleanup_free_ char *ll = NULL;
61 _cleanup_close_ int open_fd = -1;
62 int r, fd;
63
64 if (argc >= 2)
65 path = argv[1];
66 if (isempty(path) || streq(path, "-"))
67 path = NULL;
68
69 if (argc >= 3)
70 local = argv[2];
71 else if (path)
72 local = basename(path);
73 if (isempty(local) || streq(local, "-"))
74 local = NULL;
75
76 if (local) {
77 r = tar_strip_suffixes(local, &ll);
78 if (r < 0)
79 return log_oom();
80
81 local = ll;
82
83 if (!machine_name_is_valid(local)) {
84 log_error("Local image name '%s' is not valid.", local);
85 return -EINVAL;
86 }
87
88 if (!arg_force) {
89 r = image_find(local, NULL);
90 if (r < 0)
91 return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
92 else if (r > 0) {
93 log_error_errno(EEXIST, "Image '%s' already exists.", local);
94 return -EEXIST;
95 }
96 }
97 } else
98 local = "imported";
99
100 if (path) {
101 open_fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
102 if (open_fd < 0)
103 return log_error_errno(errno, "Failed to open tar image to import: %m");
104
105 fd = open_fd;
106
107 log_info("Importing '%s', saving as '%s'.", path, local);
108 } else {
109 _cleanup_free_ char *pretty = NULL;
110
111 fd = STDIN_FILENO;
112
113 (void) readlink_malloc("/proc/self/fd/0", &pretty);
114 log_info("Importing '%s', saving as '%s'.", strna(pretty), local);
115 }
116
117 r = sd_event_default(&event);
118 if (r < 0)
119 return log_error_errno(r, "Failed to allocate event loop: %m");
120
121 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
122 (void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
123 (void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
124
125 r = tar_import_new(&import, event, arg_image_root, on_tar_finished, event);
126 if (r < 0)
127 return log_error_errno(r, "Failed to allocate importer: %m");
128
129 r = tar_import_start(import, fd, local, arg_force, arg_read_only);
130 if (r < 0)
131 return log_error_errno(r, "Failed to import image: %m");
132
133 r = sd_event_loop(event);
134 if (r < 0)
135 return log_error_errno(r, "Failed to run event loop: %m");
136
137 log_info("Exiting.");
138 return -r;
139 }
140
141 static void on_raw_finished(RawImport *import, int error, void *userdata) {
142 sd_event *event = userdata;
143 assert(import);
144
145 if (error == 0)
146 log_info("Operation completed successfully.");
147
148 sd_event_exit(event, abs(error));
149 }
150
151 static int import_raw(int argc, char *argv[], void *userdata) {
152 _cleanup_(raw_import_unrefp) RawImport *import = NULL;
153 _cleanup_event_unref_ sd_event *event = NULL;
154 const char *path = NULL, *local = NULL;
155 _cleanup_free_ char *ll = NULL;
156 _cleanup_close_ int open_fd = -1;
157 int r, fd;
158
159 if (argc >= 2)
160 path = argv[1];
161 if (isempty(path) || streq(path, "-"))
162 path = NULL;
163
164 if (argc >= 3)
165 local = argv[2];
166 else if (path)
167 local = basename(path);
168 if (isempty(local) || streq(local, "-"))
169 local = NULL;
170
171 if (local) {
172 r = raw_strip_suffixes(local, &ll);
173 if (r < 0)
174 return log_oom();
175
176 local = ll;
177
178 if (!machine_name_is_valid(local)) {
179 log_error("Local image name '%s' is not valid.", local);
180 return -EINVAL;
181 }
182
183 if (!arg_force) {
184 r = image_find(local, NULL);
185 if (r < 0)
186 return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
187 else if (r > 0) {
188 log_error_errno(EEXIST, "Image '%s' already exists.", local);
189 return -EEXIST;
190 }
191 }
192 } else
193 local = "imported";
194
195 if (path) {
196 open_fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
197 if (open_fd < 0)
198 return log_error_errno(errno, "Failed to open raw image to import: %m");
199
200 fd = open_fd;
201
202 log_info("Importing '%s', saving as '%s'.", path, local);
203 } else {
204 _cleanup_free_ char *pretty = NULL;
205
206 fd = STDIN_FILENO;
207
208 (void) readlink_malloc("/proc/self/fd/0", &pretty);
209 log_info("Importing '%s', saving as '%s'.", pretty, local);
210 }
211
212 r = sd_event_default(&event);
213 if (r < 0)
214 return log_error_errno(r, "Failed to allocate event loop: %m");
215
216 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
217 (void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
218 (void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
219
220 r = raw_import_new(&import, event, arg_image_root, on_raw_finished, event);
221 if (r < 0)
222 return log_error_errno(r, "Failed to allocate importer: %m");
223
224 r = raw_import_start(import, fd, local, arg_force, arg_read_only);
225 if (r < 0)
226 return log_error_errno(r, "Failed to import image: %m");
227
228 r = sd_event_loop(event);
229 if (r < 0)
230 return log_error_errno(r, "Failed to run event loop: %m");
231
232 log_info("Exiting.");
233 return -r;
234 }
235
236 static int help(int argc, char *argv[], void *userdata) {
237
238 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
239 "Import container or virtual machine images.\n\n"
240 " -h --help Show this help\n"
241 " --version Show package version\n"
242 " --force Force creation of image\n"
243 " --image-root=PATH Image root directory\n"
244 " --read-only Create a read-only image\n\n"
245 "Commands:\n"
246 " tar FILE [NAME] Import a TAR image\n"
247 " raw FILE [NAME] Import a RAW image\n",
248 program_invocation_short_name);
249
250 return 0;
251 }
252
253 static int parse_argv(int argc, char *argv[]) {
254
255 enum {
256 ARG_VERSION = 0x100,
257 ARG_FORCE,
258 ARG_IMAGE_ROOT,
259 ARG_READ_ONLY,
260 };
261
262 static const struct option options[] = {
263 { "help", no_argument, NULL, 'h' },
264 { "version", no_argument, NULL, ARG_VERSION },
265 { "force", no_argument, NULL, ARG_FORCE },
266 { "image-root", required_argument, NULL, ARG_IMAGE_ROOT },
267 { "read-only", no_argument, NULL, ARG_READ_ONLY },
268 {}
269 };
270
271 int c;
272
273 assert(argc >= 0);
274 assert(argv);
275
276 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
277
278 switch (c) {
279
280 case 'h':
281 return help(0, NULL, NULL);
282
283 case ARG_VERSION:
284 return version();
285
286 case ARG_FORCE:
287 arg_force = true;
288 break;
289
290 case ARG_IMAGE_ROOT:
291 arg_image_root = optarg;
292 break;
293
294 case ARG_READ_ONLY:
295 arg_read_only = true;
296 break;
297
298 case '?':
299 return -EINVAL;
300
301 default:
302 assert_not_reached("Unhandled option");
303 }
304
305 return 1;
306 }
307
308 static int import_main(int argc, char *argv[]) {
309
310 static const Verb verbs[] = {
311 { "help", VERB_ANY, VERB_ANY, 0, help },
312 { "tar", 2, 3, 0, import_tar },
313 { "raw", 2, 3, 0, import_raw },
314 {}
315 };
316
317 return dispatch_verb(argc, argv, verbs, NULL);
318 }
319
320 int main(int argc, char *argv[]) {
321 int r;
322
323 setlocale(LC_ALL, "");
324 log_parse_environment();
325 log_open();
326
327 r = parse_argv(argc, argv);
328 if (r <= 0)
329 goto finish;
330
331 (void) ignore_signals(SIGPIPE, -1);
332
333 r = import_main(argc, argv);
334
335 finish:
336 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
337 }