Branch data Line data Source code
1 : : #include <stdio.h>
2 : : #include <stdlib.h>
3 : : #include <limits.h>
4 : : #include <unistd.h>
5 : : #include <errno.h>
6 : : #include <getopt.h>
7 : : #include <string.h>
8 : : #include <ctype.h>
9 : :
10 : : #include <fcntl.h>
11 : :
12 : : #include <sys/types.h>
13 : : #include <sys/stat.h>
14 : :
15 : : #include "types.h"
16 : :
17 : : #include "compiler.h"
18 : : #include "crtools.h"
19 : : #include "sockets.h"
20 : : #include "syscall.h"
21 : : #include "files.h"
22 : : #include "sk-inet.h"
23 : : #include "net.h"
24 : :
25 : : struct cr_options opts;
26 : :
27 : 1164 : static int parse_ns_string(const char *ptr)
28 : : {
29 : 1164 : const char *end = ptr + strlen(ptr);
30 : :
31 : : do {
32 [ + - ]: 1164 : if (ptr[3] != ',' && ptr[3] != '\0')
33 : : goto bad_ns;
34 [ + + ]: 1164 : if (!strncmp(ptr, "uts", 3))
35 : 231 : opts.namespaces_flags |= CLONE_NEWUTS;
36 [ + + ]: 933 : else if (!strncmp(ptr, "ipc", 3))
37 : 246 : opts.namespaces_flags |= CLONE_NEWIPC;
38 [ + + ]: 687 : else if (!strncmp(ptr, "mnt", 3))
39 : 231 : opts.namespaces_flags |= CLONE_NEWNS;
40 [ + + ]: 456 : else if (!strncmp(ptr, "pid", 3))
41 : 228 : opts.namespaces_flags |= CLONE_NEWPID;
42 [ + - ]: 228 : else if (!strncmp(ptr, "net", 3))
43 : 228 : opts.namespaces_flags |= CLONE_NEWNET;
44 : : else
45 : : goto bad_ns;
46 : 1164 : ptr += 4;
47 [ - + ]: 1164 : } while (ptr < end);
48 : : return 0;
49 : :
50 : : bad_ns:
51 : 0 : pr_err("Unknown namespace '%s'\n", ptr);
52 : 1164 : return -1;
53 : : }
54 : :
55 : 547 : int main(int argc, char *argv[])
56 : : {
57 : 547 : pid_t pid = 0;
58 : 547 : int ret = -1;
59 : : int opt, idx;
60 : 547 : int log_inited = 0;
61 : 547 : int log_level = 0;
62 : :
63 : : static const char short_opts[] = "dsf:t:hcD:o:n:vxVr:j";
64 : :
65 : : BUILD_BUG_ON(PAGE_SIZE != PAGE_IMAGE_SIZE);
66 : :
67 : 547 : cr_pb_init();
68 : :
69 [ + - ]: 547 : if (argc < 2)
70 : : goto usage;
71 : :
72 : : /* Default options */
73 : 547 : opts.final_state = TASK_DEAD;
74 : : INIT_LIST_HEAD(&opts.veth_pairs);
75 : : INIT_LIST_HEAD(&opts.scripts);
76 : :
77 [ + - ]: 547 : if (init_service_fd())
78 : : return -1;
79 : :
80 : : while (1) {
81 : : static struct option long_opts[] = {
82 : : { "tree", required_argument, 0, 't' },
83 : : { "leave-stopped", no_argument, 0, 's' },
84 : : { "restore-detached", no_argument, 0, 'd' },
85 : : { "contents", no_argument, 0, 'c' },
86 : : { "file", required_argument, 0, 'f' },
87 : : { "images-dir", required_argument, 0, 'D' },
88 : : { "log-file", required_argument, 0, 'o' },
89 : : { "namespaces", required_argument, 0, 'n' },
90 : : { "root", required_argument, 0, 'r' },
91 : : { "ext-unix-sk", no_argument, 0, 'x' },
92 : : { "help", no_argument, 0, 'h' },
93 : : { SK_EST_PARAM, no_argument, 0, 42 },
94 : : { "close", required_argument, 0, 43 },
95 : : { "log-pid", no_argument, 0, 44},
96 : : { "version", no_argument, 0, 'V'},
97 : : { "evasive-devices", no_argument, 0, 45},
98 : : { "pidfile", required_argument, 0, 46},
99 : : { "veth-pair", required_argument, 0, 47},
100 : : { "action-script", required_argument, 0, 49},
101 : : { LREMAP_PARAM, no_argument, 0, 41},
102 : : { "shell-job", no_argument, 0, 'j'},
103 : : { },
104 : : };
105 : :
106 : 6155 : opt = getopt_long(argc, argv, short_opts, long_opts, &idx);
107 [ + + ]: 6155 : if (opt == -1)
108 : : break;
109 : :
110 [ - + + - : 5608 : switch (opt) {
- + + + +
+ + + + -
- + + - -
- - - ]
111 : : case 's':
112 : 0 : opts.final_state = TASK_STOPPED;
113 : 0 : break;
114 : : case 'x':
115 : 546 : opts.ext_unix_sk = true;
116 : 546 : break;
117 : : case 't':
118 : 1092 : pid = atoi(optarg);
119 : 546 : break;
120 : : case 'c':
121 : 0 : opts.show_pages_content = true;
122 : 0 : break;
123 : : case 'f':
124 : 0 : opts.show_dump_file = optarg;
125 : 0 : break;
126 : : case 'r':
127 : 228 : opts.root = optarg;
128 : 228 : break;
129 : : case 'd':
130 : 380 : opts.restore_detach = true;
131 : 380 : break;
132 : : case 'D':
133 [ + - ]: 546 : if (chdir(optarg)) {
134 : 0 : pr_perror("Can't change directory to %s",
135 : : optarg);
136 : : return -1;
137 : : }
138 : : break;
139 : : case 'o':
140 : 546 : opts.output = strdup(optarg);
141 [ + - ]: 546 : if (log_init(optarg))
142 : : return -1;
143 : : log_inited = 1;
144 : : break;
145 : : case 'n':
146 [ + - ]: 1164 : if (parse_ns_string(optarg))
147 : : return -1;
148 : : break;
149 : : case 'v':
150 [ + - ]: 546 : if (optind < argc) {
151 : 546 : char *opt = argv[optind];
152 : :
153 [ + - ]: 546 : if (isdigit(*opt)) {
154 : 546 : log_level = -atoi(opt);
155 : 546 : optind++;
156 : : } else {
157 [ # # ]: 0 : if (log_level >= 0)
158 : 0 : log_level++;
159 : : }
160 : : } else {
161 [ # # ]: 0 : if (log_level >= 0)
162 : 0 : log_level++;
163 : : }
164 : : break;
165 : : case 41:
166 : 166 : pr_info("Will allow link remaps on FS\n");
167 : 166 : opts.link_remap_ok = true;
168 : 166 : break;
169 : : case 42:
170 : 546 : pr_info("Will dump TCP connections\n");
171 : 546 : opts.tcp_established_ok = true;
172 : 546 : break;
173 : : case 43: {
174 : : int fd;
175 : :
176 : 0 : fd = atoi(optarg);
177 : 0 : pr_info("Closing fd %d\n", fd);
178 : 0 : close(fd);
179 : 5608 : break;
180 : : }
181 : : case 44:
182 : 0 : opts.log_file_per_pid = 1;
183 : 0 : break;
184 : : case 45:
185 : 166 : opts.evasive_devices = true;
186 : 166 : break;
187 : : case 46:
188 : 228 : opts.pidfile = optarg;
189 : 228 : break;
190 : : case 47:
191 : : {
192 : : struct veth_pair *n;
193 : :
194 [ # # ]: 0 : n = xmalloc(sizeof(*n));
195 [ # # ]: 0 : if (n == NULL)
196 : : return -1;
197 : 0 : n->outside = strchr(optarg, '=');
198 [ # # ]: 0 : if (n->outside == NULL) {
199 [ # # ]: 0 : xfree(n);
200 : 0 : pr_err("Invalid agument for --veth-pair\n");
201 : 0 : goto usage;
202 : : }
203 : :
204 : 0 : *n->outside++ = '\0';
205 : 0 : n->inside = optarg;
206 : 0 : list_add(&n->node, &opts.veth_pairs);
207 : : }
208 : : break;
209 : : case 49:
210 : : {
211 : : struct script *script;
212 : :
213 [ # # ]: 0 : script = xmalloc(sizeof(struct script));
214 [ # # ]: 0 : if (script == NULL)
215 : : return -1;
216 : :
217 : 0 : script->path = optarg;
218 : 0 : list_add(&script->node, &opts.scripts);
219 : : }
220 : : break;
221 : : case 'j':
222 : 0 : opts.shell_job = true;
223 : 0 : break;
224 : : case 'V':
225 : 0 : pr_msg("Version: %d.%d\n", CRIU_VERSION_MAJOR, CRIU_VERSION_MINOR);
226 : : return 0;
227 : : case 'h':
228 : : default:
229 : : goto usage;
230 : : }
231 : : }
232 : :
233 [ + + ]: 547 : if (log_level < 0)
234 : 546 : log_level = -log_level;
235 : 547 : log_set_loglevel(log_level);
236 : :
237 [ + + ]: 547 : if (!log_inited) {
238 : 1 : ret = log_init(NULL);
239 [ + - ]: 1 : if (ret)
240 : : return ret;
241 : : }
242 : :
243 : 547 : ret = open_image_dir();
244 [ - + ]: 547 : if (ret < 0) {
245 : 0 : pr_perror("can't open currect directory");
246 : : return -1;
247 : : }
248 : :
249 [ + - ]: 547 : if (optind >= argc)
250 : : goto usage;
251 : :
252 [ + + ][ + + ]: 547 : if (strcmp(argv[optind], "dump") &&
253 [ + - ]: 1 : strcmp(argv[optind], "restore") &&
254 [ - + ]: 1 : strcmp(argv[optind], "show") &&
255 [ # # ]: 0 : strcmp(argv[optind], "check") &&
256 : 0 : strcmp(argv[optind], "exec")) {
257 : 0 : pr_err("Unknown command %s\n", argv[optind]);
258 : 0 : goto usage;
259 : : }
260 : :
261 [ + + - + : 547 : switch (argv[optind][0]) {
- - ]
262 : : case 'd':
263 [ + - ]: 166 : if (!pid)
264 : : goto opt_pid_missing;
265 : 166 : ret = cr_dump_tasks(pid, &opts);
266 : 166 : break;
267 : : case 'r':
268 [ + - ]: 380 : if (!pid)
269 : : goto opt_pid_missing;
270 : 380 : ret = cr_restore_tasks(pid, &opts);
271 : 166 : break;
272 : : case 's':
273 : 0 : ret = cr_show(&opts);
274 : 0 : break;
275 : : case 'c':
276 : 1 : ret = cr_check();
277 : 1 : break;
278 : : case 'e':
279 [ # # ]: 0 : if (!pid)
280 : : goto opt_pid_missing;
281 : 0 : ret = cr_exec(pid, argv + optind + 1);
282 : 333 : break;
283 : : default:
284 : : goto usage;
285 : : break;
286 : : }
287 : :
288 : : return ret;
289 : :
290 : : usage:
291 : 0 : pr_msg("\nUsage:\n");
292 : 0 : pr_msg(" %s dump -t pid [<options>]\n", argv[0]);
293 : 0 : pr_msg(" %s restore -t pid [<options>]\n", argv[0]);
294 : 0 : pr_msg(" %s show (-D dir)|(-f file) [<options>]\n", argv[0]);
295 : 0 : pr_msg(" %s check\n", argv[0]);
296 : 0 : pr_msg(" %s exec -t pid <syscall-string>\n", argv[0]);
297 : :
298 : 0 : pr_msg("\nCommands:\n");
299 : 0 : pr_msg(" dump checkpoint a process/tree identified by pid\n");
300 : 0 : pr_msg(" restore restore a process/tree identified by pid\n");
301 : 0 : pr_msg(" show show dump file(s) contents\n");
302 : 0 : pr_msg(" check checks whether the kernel support is up-to-date\n");
303 : 0 : pr_msg(" exec execute a system call by other task\n");
304 : :
305 [ # # ]: 0 : if (argc < 2) {
306 : 0 : pr_msg("\nTry -h|--help for more info\n");
307 : : return -1;
308 : : }
309 : :
310 : 0 : pr_msg("\nDump/Restore options:\n");
311 : :
312 : 0 : pr_msg("\n* Generic:\n");
313 : 0 : pr_msg(" -t|--tree checkpoint/restore the whole process tree identified by pid\n");
314 : 0 : pr_msg(" -d|--restore-detached detach after restore\n");
315 : 0 : pr_msg(" -s|--leave-stopped leave tasks in stopped state after checkpoint instead of killing them\n");
316 : 0 : pr_msg(" -D|--images-dir directory where to put images to\n");
317 : 0 : pr_msg(" --pidfile [FILE] write a pid of a root task in this file\n");
318 : :
319 : 0 : pr_msg("\n* Special resources support:\n");
320 : 0 : pr_msg(" -n|--namespaces checkpoint/restore namespaces - values must be separated by comma\n");
321 : 0 : pr_msg(" supported: uts, ipc, mnt, pid, net\n");
322 : 0 : pr_msg(" -x|--ext-unix-sk allow external unix connections\n");
323 : 0 : pr_msg(" --%s checkpoint/restore established TCP connections\n", SK_EST_PARAM);
324 : 0 : pr_msg(" -r|--root [PATH] change the root filesystem (when run in mount namespace)\n");
325 : 0 : pr_msg(" --evasive-devices use any path to a device file if the original one is inaccessible\n");
326 : 0 : pr_msg(" --veth-pair [IN=OUT] correspondence between outside and inside names of veth devices\n");
327 : 0 : pr_msg(" --link-remap allow to link unlinked files back when possible (modifies FS till restore)\n");
328 : 0 : pr_msg(" --action-script [SCR] add an external action script\n");
329 : 0 : pr_msg(" The environment variable CRTOOL_SCRIPT_ACTION contains one of the actions:\n");
330 : 0 : pr_msg(" * network-lock - lock network in a target network namespace\n");
331 : 0 : pr_msg(" * network-unlock - unlock network in a target network namespace\n");
332 : 0 : pr_msg(" -j|--shell-job allow to dump and restore shell jobs\n");
333 : :
334 : 0 : pr_msg("\n* Logging:\n");
335 : 0 : pr_msg(" -o|--log-file [NAME] log file name (relative path is relative to --images-dir)\n");
336 : 0 : pr_msg(" --log-pid if the -o option is in effect, each restored processes is\n");
337 : 0 : pr_msg(" written to the [NAME].pid file\n");
338 : 0 : pr_msg(" -v [num] set logging level\n");
339 : 0 : pr_msg(" 0 - messages regardless of log level\n");
340 : 0 : pr_msg(" 1 - errors, when we are in trouble\n");
341 : 0 : pr_msg(" 2 - warnings (default)\n");
342 : 0 : pr_msg(" 3 - informative, everything is fine\n");
343 : 0 : pr_msg(" 4 - debug only\n");
344 : 0 : pr_msg(" -v same as -v 1\n");
345 : 0 : pr_msg(" -vv same as -v 2\n");
346 : 0 : pr_msg(" -vvv same as -v 3\n");
347 : 0 : pr_msg(" -vvvv same as -v 4\n");
348 : :
349 : 0 : pr_msg("\nShow options:\n");
350 : 0 : pr_msg(" -f|--file show contents of a checkpoint file\n");
351 : 0 : pr_msg(" -D|--images-dir directory where to get images from\n");
352 : 0 : pr_msg(" -c|--contents show contents of pages dumped in hexdump format\n");
353 : :
354 : 0 : pr_msg("\nOther options:\n");
355 : 0 : pr_msg(" -h|--help show this text\n");
356 : 0 : pr_msg(" -V|--version show version\n");
357 : :
358 : : return -1;
359 : :
360 : : opt_pid_missing:
361 : 333 : pr_msg("No pid specified (-t option missing)\n");
362 : : return -1;
363 : : }
|