]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/tools/lxc_checkpoint.c
tree-wide: priority -> level
[mirror_lxc.git] / src / lxc / tools / lxc_checkpoint.c
CommitLineData
735f2c6e
TA
1/*
2 *
3 * Copyright © 2014 Tycho Andersen <tycho.andersen@canonical.com>.
4 * Copyright © 2014 Canonical Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#include <stdio.h>
21#include <errno.h>
22#include <unistd.h>
c9d8f2ee
TA
23#include <sys/types.h>
24#include <sys/wait.h>
735f2c6e
TA
25
26#include <lxc/lxccontainer.h>
27
28#include "log.h"
29#include "config.h"
30#include "lxc.h"
31#include "arguments.h"
c9d8f2ee 32#include "utils.h"
735f2c6e
TA
33
34static char *checkpoint_dir = NULL;
35static bool stop = false;
36static bool verbose = false;
37static bool do_restore = false;
38static bool daemonize_set = false;
9f99a33f
AR
39static bool pre_dump = false;
40static char *predump_dir = NULL;
41
eab15c1e 42#define OPT_PREDUMP_DIR OPT_USAGE + 1
735f2c6e
TA
43
44static const struct option my_longopts[] = {
45 {"checkpoint-dir", required_argument, 0, 'D'},
46 {"stop", no_argument, 0, 's'},
47 {"verbose", no_argument, 0, 'v'},
48 {"restore", no_argument, 0, 'r'},
49 {"daemon", no_argument, 0, 'd'},
50 {"foreground", no_argument, 0, 'F'},
9f99a33f
AR
51 {"pre-dump", no_argument, 0, 'p'},
52 {"predump-dir", required_argument, 0, OPT_PREDUMP_DIR},
735f2c6e
TA
53 LXC_COMMON_OPTIONS
54};
55
56static int my_checker(const struct lxc_arguments *args)
57{
58 if (do_restore && stop) {
59 lxc_error(args, "-s not compatible with -r.");
60 return -1;
61
62 } else if (!do_restore && daemonize_set) {
63 lxc_error(args, "-d/-F not compatible with -r.");
64 return -1;
65 }
66
67 if (checkpoint_dir == NULL) {
68 lxc_error(args, "-D is required.");
69 return -1;
70 }
71
9f99a33f
AR
72 if (pre_dump && do_restore) {
73 lxc_error(args, "-p not compatible with -r.");
74 return -1;
75 }
76
735f2c6e
TA
77 return 0;
78}
79
80static int my_parser(struct lxc_arguments *args, int c, char *arg)
81{
82 switch (c) {
83 case 'D':
84 checkpoint_dir = strdup(arg);
85 if (!checkpoint_dir)
86 return -1;
87 break;
88 case 's':
89 stop = true;
90 break;
91 case 'v':
92 verbose = true;
93 break;
94 case 'r':
95 do_restore = true;
96 break;
97 case 'd':
98 args->daemonize = 1;
99 daemonize_set = true;
100 break;
101 case 'F':
102 args->daemonize = 0;
103 daemonize_set = true;
104 break;
9f99a33f
AR
105 case 'p':
106 pre_dump = true;
107 break;
108 case OPT_PREDUMP_DIR:
109 predump_dir = strdup(arg);
110 if (!predump_dir)
111 return -1;
112 break;
735f2c6e
TA
113 }
114 return 0;
115}
116
117static struct lxc_arguments my_args = {
118 .progname = "lxc-checkpoint",
119 .help = "\
120--name=NAME\n\
121\n\
122lxc-checkpoint checkpoints and restores a container\n\
123 Serializes a container's running state to disk to allow restoring it in\n\
124 its running state at a later time.\n\
125\n\
126Options :\n\
5e8757ed 127 -n, --name=NAME NAME of the container\n\
735f2c6e
TA
128 -r, --restore Restore container\n\
129 -D, --checkpoint-dir=DIR directory to save the checkpoint in\n\
130 -v, --verbose Enable verbose criu logs\n\
131 Checkpoint options:\n\
132 -s, --stop Stop the container after checkpointing.\n\
9f99a33f
AR
133 -p, --pre-dump Only pre-dump the memory of the container.\n\
134 Container keeps on running and following\n\
135 checkpoints will only dump the changes.\n\
136 --predump-dir=DIR path to images from previous dump (relative to -D)\n\
735f2c6e
TA
137 Restore options:\n\
138 -d, --daemon Daemonize the container (default)\n\
139 -F, --foreground Start with the current tty attached to /dev/console\n\
50b737a3 140 --rcfile=FILE Load configuration file FILE\n\
735f2c6e
TA
141",
142 .options = my_longopts,
143 .parser = my_parser,
144 .daemonize = 1,
145 .checker = my_checker,
146};
147
fa25c39a 148static bool checkpoint(struct lxc_container *c)
735f2c6e 149{
9f99a33f 150 struct migrate_opts opts;
735f2c6e 151 bool ret;
9f99a33f 152 int mode;
735f2c6e
TA
153
154 if (!c->is_running(c)) {
155 fprintf(stderr, "%s not running, not checkpointing.\n", my_args.name);
156 lxc_container_put(c);
157 return false;
158 }
159
9f99a33f
AR
160 memset(&opts, 0, sizeof(opts));
161
162 opts.directory = checkpoint_dir;
163 opts.stop = stop;
164 opts.verbose = verbose;
165 opts.predump_dir = predump_dir;
166
167 if (pre_dump)
168 mode = MIGRATE_PRE_DUMP;
169 else
170 mode = MIGRATE_DUMP;
171
172 ret = c->migrate(c, mode, &opts, sizeof(opts));
735f2c6e
TA
173 lxc_container_put(c);
174
9f99a33f
AR
175 /* the migrate() API does not negate the return code like
176 * checkpoint() and restore() does. */
177 if (ret) {
735f2c6e
TA
178 fprintf(stderr, "Checkpointing %s failed.\n", my_args.name);
179 return false;
180 }
181
182 return true;
183}
184
fa25c39a 185static bool restore_finalize(struct lxc_container *c)
735f2c6e 186{
c9d8f2ee
TA
187 bool ret = c->restore(c, checkpoint_dir, verbose);
188 if (!ret) {
189 fprintf(stderr, "Restoring %s failed.\n", my_args.name);
190 }
735f2c6e 191
c9d8f2ee
TA
192 lxc_container_put(c);
193 return ret;
194}
195
fa25c39a 196static bool restore(struct lxc_container *c)
c9d8f2ee 197{
735f2c6e
TA
198 if (c->is_running(c)) {
199 fprintf(stderr, "%s is running, not restoring.\n", my_args.name);
200 lxc_container_put(c);
201 return false;
202 }
203
c9d8f2ee
TA
204 if (my_args.daemonize) {
205 pid_t pid;
206
735f2c6e 207 pid = fork();
c9d8f2ee
TA
208 if (pid < 0) {
209 perror("fork");
210 return false;
211 }
735f2c6e 212
c9d8f2ee 213 if (pid == 0) {
7943ec56
TA
214 close(0);
215 close(1);
7943ec56 216
c9d8f2ee
TA
217 exit(!restore_finalize(c));
218 } else {
219 return wait_for_pid(pid) == 0;
735f2c6e 220 }
c9d8f2ee
TA
221 } else {
222 int status;
735f2c6e 223
c9d8f2ee
TA
224 if (!restore_finalize(c))
225 return false;
735f2c6e 226
c9d8f2ee
TA
227 if (waitpid(-1, &status, 0) < 0)
228 return false;
229
230 return WIFEXITED(status) && WEXITSTATUS(status) == 0;
231 }
735f2c6e
TA
232}
233
234int main(int argc, char *argv[])
235{
236 struct lxc_container *c;
73b910a3 237 struct lxc_log log;
735f2c6e
TA
238 bool ret;
239
240 if (lxc_arguments_parse(&my_args, argc, argv))
b52b0595 241 exit(EXIT_FAILURE);
735f2c6e 242
b56d64e0
TA
243 if (!my_args.log_file)
244 my_args.log_file = "none";
245
73b910a3 246 log.name = my_args.name;
247 log.file = my_args.log_file;
4b73005c 248 log.level = my_args.log_priority;
73b910a3 249 log.prefix = my_args.progname;
250 log.quiet = my_args.quiet;
251 log.lxcpath = my_args.lxcpath[0];
252
253 if (lxc_log_init(&log))
b52b0595 254 exit(EXIT_FAILURE);
b56d64e0
TA
255
256 lxc_log_options_no_override();
257
735f2c6e
TA
258 c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
259 if (!c) {
260 fprintf(stderr, "System error loading %s\n", my_args.name);
b52b0595 261 exit(EXIT_FAILURE);
735f2c6e
TA
262 }
263
50b737a3
WB
264 if (my_args.rcfile) {
265 c->clear_config(c);
266 if (!c->load_config(c, my_args.rcfile)) {
267 fprintf(stderr, "Failed to load rcfile\n");
268 lxc_container_put(c);
b52b0595 269 exit(EXIT_FAILURE);
50b737a3 270 }
6118210e
WB
271 c->configfile = strdup(my_args.rcfile);
272 if (!c->configfile) {
273 fprintf(stderr, "Out of memory setting new config filename\n");
274 lxc_container_put(c);
b52b0595 275 exit(EXIT_FAILURE);
6118210e 276 }
50b737a3
WB
277 }
278
735f2c6e
TA
279 if (!c->may_control(c)) {
280 fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name);
281 lxc_container_put(c);
b52b0595 282 exit(EXIT_FAILURE);
735f2c6e
TA
283 }
284
285 if (!c->is_defined(c)) {
286 fprintf(stderr, "%s is not defined\n", my_args.name);
287 lxc_container_put(c);
b52b0595 288 exit(EXIT_FAILURE);
735f2c6e
TA
289 }
290
291
292 if (do_restore)
293 ret = restore(c);
294 else
295 ret = checkpoint(c);
296
b52b0595
CB
297 if (!ret)
298 exit(EXIT_FAILURE);
299
300 exit(EXIT_SUCCESS);
735f2c6e 301}