]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/import/import.c
log: minimize includes in log.h
[thirdparty/systemd.git] / src / import / import.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
b6e676ce
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2015 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <getopt.h>
22
23#include "sd-event.h"
dccca82b 24#include "sd-id128.h"
3f6fd1ba 25
b5efdb8a 26#include "alloc-util.h"
3ffd4af2 27#include "fd-util.h"
f4f15635 28#include "fs-util.h"
25300b5a 29#include "hostname-util.h"
b6e676ce 30#include "import-raw.h"
3f6fd1ba
LP
31#include "import-tar.h"
32#include "import-util.h"
33#include "machine-image.h"
34#include "signal-util.h"
07630cea 35#include "string-util.h"
3f6fd1ba 36#include "verbs.h"
b6e676ce
LP
37
38static bool arg_force = false;
39static bool arg_read_only = false;
40static const char *arg_image_root = "/var/lib/machines";
41
42static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
43 log_notice("Transfer aborted.");
44 sd_event_exit(sd_event_source_get_event(s), EINTR);
45 return 0;
46}
47
48static void on_tar_finished(TarImport *import, int error, void *userdata) {
49 sd_event *event = userdata;
50 assert(import);
51
52 if (error == 0)
53 log_info("Operation completed successfully.");
54
55 sd_event_exit(event, abs(error));
56}
57
58static int import_tar(int argc, char *argv[], void *userdata) {
59 _cleanup_(tar_import_unrefp) TarImport *import = NULL;
4afd3348 60 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
b6e676ce
LP
61 const char *path = NULL, *local = NULL;
62 _cleanup_free_ char *ll = NULL;
63 _cleanup_close_ int open_fd = -1;
64 int r, fd;
65
66 if (argc >= 2)
67 path = argv[1];
68 if (isempty(path) || streq(path, "-"))
69 path = NULL;
70
71 if (argc >= 3)
72 local = argv[2];
73 else if (path)
74 local = basename(path);
75 if (isempty(local) || streq(local, "-"))
76 local = NULL;
77
78 if (local) {
79 r = tar_strip_suffixes(local, &ll);
80 if (r < 0)
81 return log_oom();
82
83 local = ll;
84
85 if (!machine_name_is_valid(local)) {
86 log_error("Local image name '%s' is not valid.", local);
87 return -EINVAL;
88 }
89
90 if (!arg_force) {
91 r = image_find(local, NULL);
92 if (r < 0)
93 return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
94 else if (r > 0) {
92dfd88b 95 log_error("Image '%s' already exists.", local);
b6e676ce
LP
96 return -EEXIST;
97 }
98 }
99 } else
100 local = "imported";
101
102 if (path) {
103 open_fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
104 if (open_fd < 0)
105 return log_error_errno(errno, "Failed to open tar image to import: %m");
106
107 fd = open_fd;
108
109 log_info("Importing '%s', saving as '%s'.", path, local);
110 } else {
111 _cleanup_free_ char *pretty = NULL;
112
113 fd = STDIN_FILENO;
114
115 (void) readlink_malloc("/proc/self/fd/0", &pretty);
116 log_info("Importing '%s', saving as '%s'.", strna(pretty), local);
117 }
118
119 r = sd_event_default(&event);
120 if (r < 0)
121 return log_error_errno(r, "Failed to allocate event loop: %m");
122
72c0a2c2
LP
123 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
124 (void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
125 (void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
b6e676ce
LP
126
127 r = tar_import_new(&import, event, arg_image_root, on_tar_finished, event);
128 if (r < 0)
129 return log_error_errno(r, "Failed to allocate importer: %m");
130
131 r = tar_import_start(import, fd, local, arg_force, arg_read_only);
132 if (r < 0)
133 return log_error_errno(r, "Failed to import image: %m");
134
135 r = sd_event_loop(event);
136 if (r < 0)
137 return log_error_errno(r, "Failed to run event loop: %m");
138
139 log_info("Exiting.");
140 return -r;
141}
142
143static void on_raw_finished(RawImport *import, int error, void *userdata) {
144 sd_event *event = userdata;
145 assert(import);
146
147 if (error == 0)
148 log_info("Operation completed successfully.");
149
150 sd_event_exit(event, abs(error));
151}
152
153static int import_raw(int argc, char *argv[], void *userdata) {
154 _cleanup_(raw_import_unrefp) RawImport *import = NULL;
4afd3348 155 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
b6e676ce
LP
156 const char *path = NULL, *local = NULL;
157 _cleanup_free_ char *ll = NULL;
158 _cleanup_close_ int open_fd = -1;
159 int r, fd;
160
161 if (argc >= 2)
162 path = argv[1];
163 if (isempty(path) || streq(path, "-"))
164 path = NULL;
165
166 if (argc >= 3)
167 local = argv[2];
168 else if (path)
169 local = basename(path);
170 if (isempty(local) || streq(local, "-"))
171 local = NULL;
172
173 if (local) {
174 r = raw_strip_suffixes(local, &ll);
175 if (r < 0)
176 return log_oom();
177
178 local = ll;
179
180 if (!machine_name_is_valid(local)) {
181 log_error("Local image name '%s' is not valid.", local);
182 return -EINVAL;
183 }
184
185 if (!arg_force) {
186 r = image_find(local, NULL);
187 if (r < 0)
188 return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
189 else if (r > 0) {
92dfd88b 190 log_error("Image '%s' already exists.", local);
b6e676ce
LP
191 return -EEXIST;
192 }
193 }
194 } else
195 local = "imported";
196
197 if (path) {
198 open_fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
199 if (open_fd < 0)
200 return log_error_errno(errno, "Failed to open raw image to import: %m");
201
202 fd = open_fd;
203
204 log_info("Importing '%s', saving as '%s'.", path, local);
205 } else {
206 _cleanup_free_ char *pretty = NULL;
207
208 fd = STDIN_FILENO;
209
210 (void) readlink_malloc("/proc/self/fd/0", &pretty);
211 log_info("Importing '%s', saving as '%s'.", pretty, local);
212 }
213
214 r = sd_event_default(&event);
215 if (r < 0)
216 return log_error_errno(r, "Failed to allocate event loop: %m");
217
72c0a2c2
LP
218 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
219 (void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
220 (void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
b6e676ce
LP
221
222 r = raw_import_new(&import, event, arg_image_root, on_raw_finished, event);
223 if (r < 0)
224 return log_error_errno(r, "Failed to allocate importer: %m");
225
226 r = raw_import_start(import, fd, local, arg_force, arg_read_only);
227 if (r < 0)
228 return log_error_errno(r, "Failed to import image: %m");
229
230 r = sd_event_loop(event);
231 if (r < 0)
232 return log_error_errno(r, "Failed to run event loop: %m");
233
234 log_info("Exiting.");
235 return -r;
236}
237
238static int help(int argc, char *argv[], void *userdata) {
239
240 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
587fec42 241 "Import container or virtual machine images.\n\n"
b6e676ce
LP
242 " -h --help Show this help\n"
243 " --version Show package version\n"
244 " --force Force creation of image\n"
245 " --image-root=PATH Image root directory\n"
246 " --read-only Create a read-only image\n\n"
247 "Commands:\n"
587fec42
LP
248 " tar FILE [NAME] Import a TAR image\n"
249 " raw FILE [NAME] Import a RAW image\n",
b6e676ce
LP
250 program_invocation_short_name);
251
252 return 0;
253}
254
255static int parse_argv(int argc, char *argv[]) {
256
257 enum {
258 ARG_VERSION = 0x100,
259 ARG_FORCE,
260 ARG_IMAGE_ROOT,
261 ARG_READ_ONLY,
262 };
263
264 static const struct option options[] = {
265 { "help", no_argument, NULL, 'h' },
266 { "version", no_argument, NULL, ARG_VERSION },
267 { "force", no_argument, NULL, ARG_FORCE },
268 { "image-root", required_argument, NULL, ARG_IMAGE_ROOT },
269 { "read-only", no_argument, NULL, ARG_READ_ONLY },
270 {}
271 };
272
273 int c;
274
275 assert(argc >= 0);
276 assert(argv);
277
278 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
279
280 switch (c) {
281
282 case 'h':
283 return help(0, NULL, NULL);
284
285 case ARG_VERSION:
3f6fd1ba 286 return version();
b6e676ce
LP
287
288 case ARG_FORCE:
289 arg_force = true;
290 break;
291
292 case ARG_IMAGE_ROOT:
293 arg_image_root = optarg;
294 break;
295
296 case ARG_READ_ONLY:
297 arg_read_only = true;
298 break;
299
300 case '?':
301 return -EINVAL;
302
303 default:
304 assert_not_reached("Unhandled option");
305 }
306
307 return 1;
308}
309
310static int import_main(int argc, char *argv[]) {
311
312 static const Verb verbs[] = {
313 { "help", VERB_ANY, VERB_ANY, 0, help },
314 { "tar", 2, 3, 0, import_tar },
315 { "raw", 2, 3, 0, import_raw },
316 {}
317 };
318
319 return dispatch_verb(argc, argv, verbs, NULL);
320}
321
322int main(int argc, char *argv[]) {
323 int r;
324
325 setlocale(LC_ALL, "");
326 log_parse_environment();
327 log_open();
328
329 r = parse_argv(argc, argv);
330 if (r <= 0)
331 goto finish;
332
ce30c8dc 333 (void) ignore_signals(SIGPIPE, -1);
b6e676ce
LP
334
335 r = import_main(argc, argv);
336
337finish:
338 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
339}