]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/import/import.c
verbs: when invoking the default verb, pass a faked argv array, with just the verb...
[thirdparty/systemd.git] / src / import / import.c
CommitLineData
72648326
LP
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
30static bool arg_force = false;
31
32static 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
44static 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
128static 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
142static 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
187static 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
198int 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
211finish:
212 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
213}