2013-07-18 21:47:11 +04:00
|
|
|
#include "version.h"
|
2014-06-17 21:10:46 +04:00
|
|
|
#include <sys/prctl.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <sys/types.h>
|
2013-12-18 01:04:40 +04:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
2014-06-17 21:10:46 +04:00
|
|
|
#include <signal.h>
|
2013-12-18 01:04:40 +04:00
|
|
|
|
|
|
|
#include "criu.h"
|
|
|
|
#include "rpc.pb-c.h"
|
|
|
|
#include "cr-service-const.h"
|
2013-07-18 21:47:11 +04:00
|
|
|
|
2015-07-30 16:40:22 -04:00
|
|
|
#define CR_DEFAULT_SERVICE_BIN "criu"
|
|
|
|
|
2013-09-14 15:00:17 +04:00
|
|
|
const char *criu_lib_version = CRIU_VERSION;
|
2013-12-18 01:04:40 +04:00
|
|
|
|
2015-07-31 15:57:00 +03:00
|
|
|
struct criu_opts {
|
|
|
|
CriuOpts *rpc;
|
|
|
|
int (*notify)(char *action, criu_notify_arg_t na);
|
|
|
|
enum criu_service_comm service_comm;
|
|
|
|
union {
|
|
|
|
char *service_address;
|
|
|
|
int service_fd;
|
|
|
|
char *service_binary;
|
|
|
|
};
|
|
|
|
int swrk_pid;
|
|
|
|
};
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
static criu_opts *global_opts;
|
2013-12-18 01:04:40 +04:00
|
|
|
static int saved_errno;
|
|
|
|
|
2015-07-16 15:42:00 +03:00
|
|
|
void criu_local_set_service_comm(criu_opts *opts, enum criu_service_comm comm)
|
|
|
|
{
|
|
|
|
opts->service_comm = comm;
|
|
|
|
}
|
|
|
|
|
|
|
|
void criu_set_service_comm(enum criu_service_comm comm)
|
|
|
|
{
|
|
|
|
criu_local_set_service_comm(global_opts, comm);
|
|
|
|
}
|
|
|
|
|
|
|
|
void criu_local_set_service_address(criu_opts *opts, char *path)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
|
|
|
if (path)
|
2015-07-16 15:42:00 +03:00
|
|
|
opts->service_address = path;
|
2013-12-18 01:04:40 +04:00
|
|
|
else
|
2015-07-16 15:42:00 +03:00
|
|
|
opts->service_address = CR_DEFAULT_SERVICE_ADDRESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
void criu_set_service_address(char *path)
|
|
|
|
{
|
|
|
|
criu_local_set_service_address(global_opts, path);
|
|
|
|
}
|
|
|
|
|
|
|
|
void criu_local_set_service_fd(criu_opts *opts, int fd)
|
|
|
|
{
|
|
|
|
opts->service_fd = fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
void criu_set_service_fd(int fd)
|
|
|
|
{
|
|
|
|
criu_local_set_service_fd(global_opts, fd);
|
2013-12-18 01:04:40 +04:00
|
|
|
}
|
|
|
|
|
2015-07-30 16:40:22 -04:00
|
|
|
void criu_local_set_service_binary(criu_opts *opts, char *path)
|
|
|
|
{
|
|
|
|
if (path)
|
|
|
|
opts->service_binary = path;
|
|
|
|
else
|
|
|
|
opts->service_binary = CR_DEFAULT_SERVICE_BIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
void criu_set_service_binary(char *path)
|
|
|
|
{
|
|
|
|
criu_local_set_service_binary(global_opts, path);
|
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
int criu_local_init_opts(criu_opts **o)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_opts *opts = NULL;
|
|
|
|
CriuOpts *rpc = NULL;
|
|
|
|
|
|
|
|
opts = *o;
|
|
|
|
|
2015-07-21 13:27:00 +03:00
|
|
|
if (opts) {
|
|
|
|
if (opts->rpc)
|
|
|
|
criu_opts__free_unpacked(opts->rpc, NULL);
|
|
|
|
|
|
|
|
free(opts);
|
|
|
|
opts = NULL;
|
|
|
|
}
|
2015-07-15 04:45:02 +03:00
|
|
|
|
|
|
|
rpc = malloc(sizeof(CriuOpts));
|
|
|
|
if (rpc == NULL) {
|
|
|
|
perror("Can't allocate memory for criu RPC opts");
|
|
|
|
return -1;
|
2014-06-25 19:22:21 +04:00
|
|
|
}
|
2013-12-18 01:04:40 +04:00
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_opts__init(rpc);
|
|
|
|
|
|
|
|
opts = malloc(sizeof(criu_opts));
|
|
|
|
if (opts == NULL) {
|
2013-12-18 01:04:40 +04:00
|
|
|
perror("Can't allocate memory for criu opts");
|
2015-07-21 13:27:00 +03:00
|
|
|
criu_opts__free_unpacked(rpc, NULL);
|
2013-12-18 01:04:40 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc = rpc;
|
|
|
|
opts->notify = NULL;
|
|
|
|
|
2015-10-12 12:50:04 +03:00
|
|
|
opts->service_comm = CRIU_COMM_BIN;
|
|
|
|
opts->service_address = CR_DEFAULT_SERVICE_BIN;
|
2015-07-16 15:42:00 +03:00
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
*o = opts;
|
|
|
|
|
2013-12-18 01:04:40 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
int criu_init_opts(void)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
return criu_local_init_opts(&global_opts);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_notify_cb(criu_opts *opts, int (*cb)(char *action, criu_notify_arg_t na))
|
2014-06-25 19:22:21 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->notify = cb;
|
|
|
|
opts->rpc->has_notify_scripts = true;
|
|
|
|
opts->rpc->notify_scripts = true;
|
2014-06-25 19:22:21 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_notify_cb(int (*cb)(char *action, criu_notify_arg_t na))
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_notify_cb(global_opts, cb);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2014-06-26 13:58:53 +04:00
|
|
|
int criu_notify_pid(criu_notify_arg_t na)
|
|
|
|
{
|
|
|
|
return na->has_pid ? na->pid : 0;
|
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_pid(criu_opts *opts, int pid)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_pid = true;
|
|
|
|
opts->rpc->pid = pid;
|
2013-12-18 01:04:40 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_pid(int pid)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_pid(global_opts, pid);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_images_dir_fd(criu_opts *opts, int fd)
|
2015-07-13 14:55:00 +03:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->images_dir_fd = fd;
|
2013-12-18 01:04:40 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_images_dir_fd(int fd)
|
2014-06-25 17:15:57 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_images_dir_fd(global_opts, fd);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_parent_images(criu_opts *opts, char *path)
|
2015-07-13 14:55:00 +03:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->parent_img = strdup(path);
|
2014-06-25 17:15:57 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_parent_images(char *path)
|
2014-06-25 17:15:57 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_parent_images(global_opts, path);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_track_mem(criu_opts *opts, bool track_mem)
|
2015-07-13 14:55:00 +03:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_track_mem = true;
|
|
|
|
opts->rpc->track_mem = track_mem;
|
2014-06-25 17:15:57 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_track_mem(bool track_mem)
|
2014-06-25 17:15:57 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_track_mem(global_opts, track_mem);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_auto_dedup(criu_opts *opts, bool auto_dedup)
|
2015-07-13 14:55:00 +03:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_auto_dedup = true;
|
|
|
|
opts->rpc->auto_dedup = auto_dedup;
|
2014-06-25 17:15:57 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_auto_dedup(bool auto_dedup)
|
2014-06-25 17:15:57 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_auto_dedup(global_opts, auto_dedup);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_force_irmap(criu_opts *opts, bool force_irmap)
|
2015-07-13 14:55:00 +03:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_force_irmap = true;
|
|
|
|
opts->rpc->force_irmap = force_irmap;
|
2014-06-25 17:15:57 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_force_irmap(bool force_irmap)
|
2014-06-25 17:15:57 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_force_irmap(global_opts, force_irmap);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_link_remap(criu_opts *opts, bool link_remap)
|
2015-07-13 14:55:00 +03:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_link_remap = true;
|
|
|
|
opts->rpc->link_remap = link_remap;
|
2014-06-25 17:15:57 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_link_remap(bool link_remap)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_link_remap(global_opts, link_remap);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_work_dir_fd(criu_opts *opts, int fd)
|
2014-02-04 18:27:20 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_work_dir_fd = true;
|
|
|
|
opts->rpc->work_dir_fd = fd;
|
2014-02-04 18:27:20 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_work_dir_fd(int fd)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_work_dir_fd(global_opts, fd);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_leave_running(criu_opts *opts, bool leave_running)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_leave_running = true;
|
|
|
|
opts->rpc->leave_running = leave_running;
|
2013-12-18 01:04:40 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_leave_running(bool leave_running)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_leave_running(global_opts, leave_running);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_ext_unix_sk(criu_opts *opts, bool ext_unix_sk)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_ext_unix_sk = true;
|
|
|
|
opts->rpc->ext_unix_sk = ext_unix_sk;
|
2013-12-18 01:04:40 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_ext_unix_sk(bool ext_unix_sk)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_ext_unix_sk(global_opts, ext_unix_sk);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-29 14:05:50 +03:00
|
|
|
int criu_local_add_unix_sk(criu_opts *opts, unsigned int inode)
|
|
|
|
{
|
|
|
|
int nr;
|
|
|
|
UnixSk **a, *u;
|
|
|
|
|
|
|
|
/*if caller forgot enable ext_unix_sk option we do it*/
|
|
|
|
if (!opts->rpc->has_ext_unix_sk) {
|
|
|
|
criu_local_set_ext_unix_sk(opts, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*if user disabled ext_unix_sk and try to add unixsk inode after that*/
|
|
|
|
if (opts->rpc->has_ext_unix_sk && !opts->rpc->ext_unix_sk) {
|
|
|
|
if (opts->rpc->n_unix_sk_ino > 0) {
|
|
|
|
free(opts->rpc->unix_sk_ino);
|
|
|
|
opts->rpc->n_unix_sk_ino = 0;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
u = malloc(sizeof(*u));
|
|
|
|
if (!u)
|
|
|
|
goto er;
|
|
|
|
unix_sk__init(u);
|
|
|
|
|
|
|
|
u->inode = inode;
|
|
|
|
|
|
|
|
nr = opts->rpc->n_unix_sk_ino + 1;
|
|
|
|
a = realloc(opts->rpc->unix_sk_ino, nr * sizeof(u));
|
|
|
|
if (!a)
|
|
|
|
goto er_u;
|
|
|
|
|
|
|
|
a[nr - 1] = u;
|
|
|
|
opts->rpc->unix_sk_ino = a;
|
|
|
|
opts->rpc->n_unix_sk_ino = nr;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
er_u:
|
|
|
|
free(u);
|
|
|
|
er:
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
int criu_add_unix_sk(unsigned int inode)
|
|
|
|
{
|
|
|
|
return criu_local_add_unix_sk(global_opts, inode);
|
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_tcp_established(criu_opts *opts, bool tcp_established)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_tcp_established = true;
|
|
|
|
opts->rpc->tcp_established = tcp_established;
|
2013-12-18 01:04:40 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_tcp_established(bool tcp_established)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_tcp_established(global_opts, tcp_established);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2016-06-20 23:15:00 +03:00
|
|
|
void criu_local_set_tcp_skip_in_flight(criu_opts *opts, bool tcp_skip_in_flight)
|
|
|
|
{
|
|
|
|
opts->rpc->has_tcp_skip_in_flight = true;
|
|
|
|
opts->rpc->tcp_skip_in_flight = tcp_skip_in_flight;
|
|
|
|
}
|
|
|
|
|
|
|
|
void criu_set_tcp_skip_in_flight(bool tcp_skip_in_flight)
|
|
|
|
{
|
|
|
|
criu_local_set_tcp_skip_in_flight(global_opts, tcp_skip_in_flight);
|
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_evasive_devices(criu_opts *opts, bool evasive_devices)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_evasive_devices = true;
|
|
|
|
opts->rpc->evasive_devices = evasive_devices;
|
2013-12-18 01:04:40 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_evasive_devices(bool evasive_devices)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_evasive_devices(global_opts, evasive_devices);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_shell_job(criu_opts *opts, bool shell_job)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_shell_job = true;
|
|
|
|
opts->rpc->shell_job = shell_job;
|
2013-12-18 01:04:40 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_shell_job(bool shell_job)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_shell_job(global_opts, shell_job);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_file_locks(criu_opts *opts, bool file_locks)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_file_locks = true;
|
|
|
|
opts->rpc->file_locks = file_locks;
|
2013-12-18 01:04:40 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_file_locks(bool file_locks)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_file_locks(global_opts, file_locks);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_log_level(criu_opts *opts, int log_level)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_log_level = true;
|
|
|
|
opts->rpc->log_level = log_level;
|
2013-12-18 01:04:40 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_log_level(int log_level)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_log_level(global_opts, log_level);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_root(criu_opts *opts, char *root)
|
2014-03-19 21:59:00 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->root = strdup(root);
|
2014-03-19 21:59:00 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_root(char *root)
|
2014-08-06 22:23:00 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_root(global_opts, root);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_manage_cgroups(criu_opts *opts, bool manage)
|
2015-07-13 14:55:00 +03:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_manage_cgroups = true;
|
|
|
|
opts->rpc->manage_cgroups = manage;
|
2014-08-06 22:23:00 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_manage_cgroups(bool manage)
|
2015-04-21 10:33:55 -06:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_manage_cgroups(global_opts, manage);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-08-06 15:39:00 +03:00
|
|
|
void criu_local_set_manage_cgroups_mode(criu_opts *opts, enum criu_cg_mode mode)
|
2015-08-05 21:02:00 +03:00
|
|
|
{
|
|
|
|
opts->rpc->has_manage_cgroups_mode = true;
|
2015-08-06 15:39:00 +03:00
|
|
|
opts->rpc->manage_cgroups_mode = (CriuCgMode)mode;
|
2015-08-05 21:02:00 +03:00
|
|
|
}
|
|
|
|
|
2015-08-06 15:39:00 +03:00
|
|
|
void criu_set_manage_cgroups_mode(enum criu_cg_mode mode)
|
2015-08-05 21:02:00 +03:00
|
|
|
{
|
|
|
|
criu_local_set_manage_cgroups_mode(global_opts, mode);
|
|
|
|
}
|
|
|
|
|
2016-06-10 18:53:00 +03:00
|
|
|
void criu_local_set_freeze_cgroup(criu_opts *opts, char *name)
|
|
|
|
{
|
|
|
|
opts->rpc->freeze_cgroup = name;
|
|
|
|
}
|
|
|
|
|
|
|
|
void criu_set_freeze_cgroup(char *name)
|
|
|
|
{
|
|
|
|
criu_local_set_freeze_cgroup(global_opts, name);
|
|
|
|
}
|
|
|
|
|
2016-06-17 14:22:00 +03:00
|
|
|
void criu_local_set_timeout(criu_opts *opts, unsigned int timeout)
|
|
|
|
{
|
|
|
|
opts->rpc->timeout = timeout;
|
|
|
|
}
|
|
|
|
|
|
|
|
void criu_set_timeout(unsigned int timeout)
|
|
|
|
{
|
|
|
|
criu_local_set_timeout(global_opts, timeout);
|
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_auto_ext_mnt(criu_opts *opts, bool val)
|
2015-07-13 14:55:00 +03:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_auto_ext_mnt = true;
|
|
|
|
opts->rpc->auto_ext_mnt = val;
|
2015-04-21 10:33:55 -06:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_auto_ext_mnt(bool val)
|
2015-04-21 10:33:55 -06:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_auto_ext_mnt(global_opts, val);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_ext_sharing(criu_opts *opts, bool val)
|
2015-07-13 14:55:00 +03:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_ext_sharing = true;
|
|
|
|
opts->rpc->ext_sharing = val;
|
2015-04-21 10:33:55 -06:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_ext_sharing(bool val)
|
2015-04-21 10:33:55 -06:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_ext_sharing(global_opts, val);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_ext_masters(criu_opts *opts, bool val)
|
2015-07-13 14:55:00 +03:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_ext_masters = true;
|
|
|
|
opts->rpc->ext_masters = val;
|
2015-04-21 10:33:55 -06:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_ext_masters(bool val)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_ext_masters(global_opts, val);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_log_file(criu_opts *opts, char *log_file)
|
2015-07-13 14:55:00 +03:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->log_file = strdup(log_file);
|
2013-12-18 01:04:40 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_log_file(char *log_file)
|
2014-02-28 18:59:55 +04:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_log_file(global_opts, log_file);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
void criu_local_set_cpu_cap(criu_opts *opts, unsigned int cap)
|
2015-07-13 14:55:00 +03:00
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->has_cpu_cap = true;
|
|
|
|
opts->rpc->cpu_cap = cap;
|
2014-02-28 18:59:55 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
void criu_set_cpu_cap(unsigned int cap)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
criu_local_set_cpu_cap(global_opts, cap);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
int criu_local_set_exec_cmd(criu_opts *opts, int argc, char *argv[])
|
2014-03-22 20:14:00 +04:00
|
|
|
{
|
|
|
|
int i;
|
2014-03-27 16:43:00 +04:00
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->n_exec_cmd = argc;
|
|
|
|
opts->rpc->exec_cmd = malloc((argc) * sizeof(char *));
|
2014-03-27 16:43:00 +04:00
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
if (opts->rpc->exec_cmd) {
|
2014-03-27 16:43:00 +04:00
|
|
|
for (i = 0; i < argc; i++) {
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->exec_cmd[i] = strdup(argv[i]);
|
|
|
|
if (!opts->rpc->exec_cmd[i]) {
|
2014-03-27 16:43:00 +04:00
|
|
|
while (i > 0)
|
2015-07-15 04:45:02 +03:00
|
|
|
free(opts->rpc->exec_cmd[i--]);
|
|
|
|
free(opts->rpc->exec_cmd);
|
|
|
|
opts->rpc->n_exec_cmd = 0;
|
|
|
|
opts->rpc->exec_cmd = NULL;
|
2014-03-27 16:43:00 +04:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
return -ENOMEM;
|
2014-03-22 20:14:00 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
int criu_set_exec_cmd(int argc, char *argv[])
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
return criu_local_set_exec_cmd(global_opts, argc, argv);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
int criu_local_add_ext_mount(criu_opts *opts, char *key, char *val)
|
2014-06-25 17:34:17 +04:00
|
|
|
{
|
|
|
|
int nr;
|
|
|
|
ExtMountMap **a, *m;
|
|
|
|
|
|
|
|
m = malloc(sizeof(*m));
|
|
|
|
if (!m)
|
|
|
|
goto er;
|
2014-07-31 19:51:00 +04:00
|
|
|
ext_mount_map__init(m);
|
|
|
|
|
2014-06-25 17:34:17 +04:00
|
|
|
m->key = strdup(key);
|
|
|
|
if (!m->key)
|
|
|
|
goto er_n;
|
|
|
|
m->val = strdup(val);
|
|
|
|
if (!m->val)
|
|
|
|
goto er_k;
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
nr = opts->rpc->n_ext_mnt + 1;
|
|
|
|
a = realloc(opts->rpc->ext_mnt, nr * sizeof(m));
|
2014-06-25 17:34:17 +04:00
|
|
|
if (!a)
|
|
|
|
goto er_v;
|
|
|
|
|
|
|
|
a[nr - 1] = m;
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->ext_mnt = a;
|
|
|
|
opts->rpc->n_ext_mnt = nr;
|
2014-06-25 17:34:17 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
er_v:
|
|
|
|
free(m->val);
|
|
|
|
er_k:
|
|
|
|
free(m->key);
|
|
|
|
er_n:
|
|
|
|
free(m);
|
|
|
|
er:
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
int criu_add_ext_mount(char *key, char *val)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
return criu_local_add_ext_mount(global_opts, key, val);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
int criu_local_add_cg_root(criu_opts *opts, char *ctrl, char *path)
|
2014-08-22 16:12:05 +04:00
|
|
|
{
|
|
|
|
int nr;
|
|
|
|
CgroupRoot **a, *root;
|
|
|
|
|
|
|
|
root = malloc(sizeof(*root));
|
|
|
|
if (!root)
|
|
|
|
goto er;
|
|
|
|
cgroup_root__init(root);
|
|
|
|
|
|
|
|
if (ctrl) {
|
|
|
|
root->ctrl = strdup(ctrl);
|
|
|
|
if (!root->ctrl)
|
|
|
|
goto er_r;
|
|
|
|
}
|
|
|
|
|
|
|
|
root->path = strdup(path);
|
|
|
|
if (!root->path)
|
|
|
|
goto er_c;
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
nr = opts->rpc->n_cg_root + 1;
|
|
|
|
a = realloc(opts->rpc->cg_root, nr * sizeof(root));
|
2014-08-22 16:12:05 +04:00
|
|
|
if (!a)
|
|
|
|
goto er_p;
|
|
|
|
|
|
|
|
a[nr - 1] = root;
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->cg_root = a;
|
|
|
|
opts->rpc->n_cg_root = nr;
|
2014-08-22 16:12:05 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
er_p:
|
|
|
|
free(root->path);
|
|
|
|
er_c:
|
|
|
|
if (root->ctrl)
|
|
|
|
free(root->ctrl);
|
|
|
|
er_r:
|
|
|
|
free(root);
|
|
|
|
er:
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2015-07-13 14:55:00 +03:00
|
|
|
|
|
|
|
int criu_add_cg_root(char *ctrl, char *path)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
return criu_local_add_cg_root(global_opts, ctrl, path);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
int criu_local_add_veth_pair(criu_opts *opts, char *in, char *out)
|
2014-06-25 17:37:50 +04:00
|
|
|
{
|
|
|
|
int nr;
|
|
|
|
CriuVethPair **a, *p;
|
|
|
|
|
|
|
|
p = malloc(sizeof(*p));
|
|
|
|
if (!p)
|
|
|
|
goto er;
|
2014-07-31 19:51:00 +04:00
|
|
|
criu_veth_pair__init(p);
|
|
|
|
|
2014-06-25 17:37:50 +04:00
|
|
|
p->if_in = strdup(in);
|
|
|
|
if (!p->if_in)
|
|
|
|
goto er_p;
|
|
|
|
p->if_out = strdup(out);
|
|
|
|
if (!p->if_out)
|
|
|
|
goto er_i;
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
nr = opts->rpc->n_veths + 1;
|
|
|
|
a = realloc(opts->rpc->veths, nr * sizeof(p));
|
2014-06-25 17:37:50 +04:00
|
|
|
if (!a)
|
|
|
|
goto er_o;
|
|
|
|
|
|
|
|
a[nr - 1] = p;
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->veths = a;
|
|
|
|
opts->rpc->n_veths = nr;
|
2014-06-25 17:37:50 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
er_o:
|
|
|
|
free(p->if_out);
|
|
|
|
er_i:
|
|
|
|
free(p->if_in);
|
|
|
|
er_p:
|
|
|
|
free(p);
|
|
|
|
er:
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
int criu_add_veth_pair(char *in, char *out)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
return criu_local_add_veth_pair(global_opts, in, out);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
int criu_local_add_enable_fs(criu_opts *opts, char *fs)
|
2015-05-06 12:22:00 +03:00
|
|
|
{
|
|
|
|
int nr;
|
|
|
|
char *str = NULL;
|
|
|
|
char **ptr = NULL;
|
|
|
|
|
|
|
|
str = strdup(fs);
|
|
|
|
if (!str)
|
|
|
|
goto err;
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
nr = opts->rpc->n_enable_fs + 1;
|
|
|
|
ptr = realloc(opts->rpc->enable_fs, nr * sizeof(*ptr));
|
2015-05-06 12:22:00 +03:00
|
|
|
if (!ptr)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
ptr[nr - 1] = str;
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->n_enable_fs = nr;
|
|
|
|
opts->rpc->enable_fs = ptr;
|
2015-05-06 12:22:00 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (str)
|
|
|
|
free(str);
|
|
|
|
if (ptr)
|
|
|
|
free(ptr);
|
|
|
|
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
int criu_add_enable_fs(char *fs)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
return criu_local_add_enable_fs(global_opts, fs);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
int criu_local_add_skip_mnt(criu_opts *opts, char *mnt)
|
2015-05-06 12:22:00 +03:00
|
|
|
{
|
|
|
|
int nr;
|
|
|
|
char *str = NULL;
|
|
|
|
char **ptr = NULL;
|
|
|
|
|
|
|
|
str = strdup(mnt);
|
|
|
|
if (!str)
|
|
|
|
goto err;
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
nr = opts->rpc->n_skip_mnt + 1;
|
|
|
|
ptr = realloc(opts->rpc->skip_mnt, nr * sizeof(*ptr));
|
2015-05-06 12:22:00 +03:00
|
|
|
if (!ptr)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
ptr[nr - 1] = str;
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
opts->rpc->n_skip_mnt = nr;
|
|
|
|
opts->rpc->skip_mnt = ptr;
|
2015-05-06 12:22:00 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (str)
|
|
|
|
free(str);
|
|
|
|
if (ptr)
|
|
|
|
free(ptr);
|
|
|
|
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2015-09-16 07:27:00 +03:00
|
|
|
int criu_local_add_irmap_path(criu_opts *opts, char *path)
|
|
|
|
{
|
|
|
|
int nr;
|
|
|
|
char *my_path;
|
|
|
|
char **m;
|
|
|
|
|
|
|
|
if (!opts)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
my_path = strdup(path);
|
|
|
|
if (!my_path)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
nr = opts->rpc->n_irmap_scan_paths + 1;
|
|
|
|
m = realloc(opts->rpc->irmap_scan_paths, nr * sizeof(*m));
|
|
|
|
if (!m)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
m[nr - 1] = my_path;
|
|
|
|
|
|
|
|
opts->rpc->n_irmap_scan_paths = nr;
|
|
|
|
opts->rpc->irmap_scan_paths = m;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (my_path)
|
|
|
|
free(my_path);
|
|
|
|
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2016-05-30 18:49:00 +03:00
|
|
|
int criu_local_add_cg_props(criu_opts *opts, char *stream)
|
|
|
|
{
|
|
|
|
char *new;
|
|
|
|
|
|
|
|
new = strdup(stream);
|
|
|
|
if (!new)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
free(opts->rpc->cgroup_props);
|
|
|
|
opts->rpc->cgroup_props = new;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int criu_local_add_cg_props_file(criu_opts *opts, char *path)
|
|
|
|
{
|
|
|
|
char *new;
|
|
|
|
|
|
|
|
new = strdup(path);
|
|
|
|
if (!new)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
free(opts->rpc->cgroup_props_file);
|
|
|
|
opts->rpc->cgroup_props_file = new;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int criu_local_add_cg_dump_controller(criu_opts *opts, char *name)
|
|
|
|
{
|
|
|
|
char **new;
|
|
|
|
size_t nr;
|
|
|
|
|
2016-06-01 15:22:00 +03:00
|
|
|
nr = opts->rpc->n_cgroup_dump_controller + 1;
|
|
|
|
new = realloc(opts->rpc->cgroup_dump_controller, nr * sizeof(char *));
|
2016-05-30 18:49:00 +03:00
|
|
|
if (!new)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-06-01 15:22:00 +03:00
|
|
|
new[opts->rpc->n_cgroup_dump_controller] = strdup(name);
|
|
|
|
if (!new[opts->rpc->n_cgroup_dump_controller])
|
2016-05-30 18:49:00 +03:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-06-01 15:22:00 +03:00
|
|
|
opts->rpc->n_cgroup_dump_controller = nr;
|
|
|
|
opts->rpc->cgroup_dump_controller = new;
|
2016-05-30 18:49:00 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
int criu_add_skip_mnt(char *mnt)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
return criu_local_add_skip_mnt(global_opts, mnt);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-08-10 17:20:50 +03:00
|
|
|
void criu_local_set_ghost_limit(criu_opts *opts, unsigned int limit)
|
|
|
|
{
|
|
|
|
opts->rpc->has_ghost_limit = true;
|
|
|
|
opts->rpc->ghost_limit = limit;
|
|
|
|
}
|
|
|
|
|
|
|
|
void criu_set_ghost_limit(unsigned int limit)
|
|
|
|
{
|
|
|
|
criu_local_set_ghost_limit(global_opts, limit);
|
|
|
|
}
|
|
|
|
|
2015-09-16 07:27:00 +03:00
|
|
|
int criu_add_irmap_path(char *path)
|
|
|
|
{
|
|
|
|
return criu_local_add_irmap_path(global_opts, path);
|
|
|
|
}
|
|
|
|
|
2013-12-18 01:04:40 +04:00
|
|
|
static CriuResp *recv_resp(int socket_fd)
|
|
|
|
{
|
2015-11-13 17:10:08 +03:00
|
|
|
unsigned char *buf = NULL;
|
2013-12-18 01:04:40 +04:00
|
|
|
int len;
|
|
|
|
CriuResp *msg = 0;
|
|
|
|
|
2015-04-21 16:09:09 +03:00
|
|
|
len = recv(socket_fd, NULL, 0, MSG_TRUNC | MSG_PEEK);
|
2013-12-18 01:04:40 +04:00
|
|
|
if (len == -1) {
|
2015-04-21 16:09:09 +03:00
|
|
|
perror("Can't read request");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2015-11-13 17:10:08 +03:00
|
|
|
buf = malloc(len);
|
|
|
|
if (!buf) {
|
|
|
|
errno = ENOMEM;
|
|
|
|
perror("Can't receive response");
|
|
|
|
goto err;
|
|
|
|
}
|
2015-04-21 16:09:09 +03:00
|
|
|
|
|
|
|
len = recv(socket_fd, buf, len, MSG_TRUNC);
|
|
|
|
if (len == -1) {
|
|
|
|
perror("Can't read request");
|
2013-12-18 01:04:40 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
msg = criu_resp__unpack(NULL, len, buf);
|
|
|
|
if (!msg) {
|
|
|
|
perror("Failed unpacking response");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2015-11-13 17:10:08 +03:00
|
|
|
free(buf);
|
2013-12-18 01:04:40 +04:00
|
|
|
return msg;
|
|
|
|
err:
|
2015-11-13 17:10:08 +03:00
|
|
|
free(buf);
|
2013-12-18 01:04:40 +04:00
|
|
|
saved_errno = errno;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int send_req(int socket_fd, CriuReq *req)
|
|
|
|
{
|
2015-04-21 16:09:09 +03:00
|
|
|
unsigned char *buf;
|
2013-12-18 01:04:40 +04:00
|
|
|
int len;
|
|
|
|
|
|
|
|
len = criu_req__get_packed_size(req);
|
|
|
|
|
2015-11-13 17:10:08 +03:00
|
|
|
buf = malloc(len);
|
|
|
|
if (!buf) {
|
|
|
|
errno = ENOMEM;
|
|
|
|
perror("Can't send request");
|
|
|
|
goto err;
|
|
|
|
}
|
2015-04-21 16:09:09 +03:00
|
|
|
|
2013-12-18 01:04:40 +04:00
|
|
|
if (criu_req__pack(req, buf) != len) {
|
|
|
|
perror("Failed packing request");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (write(socket_fd, buf, len) == -1) {
|
|
|
|
perror("Can't send request");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2015-11-13 17:10:08 +03:00
|
|
|
free(buf);
|
2013-12-18 01:04:40 +04:00
|
|
|
return 0;
|
|
|
|
err:
|
2015-11-13 17:10:08 +03:00
|
|
|
free(buf);
|
2013-12-18 01:04:40 +04:00
|
|
|
saved_errno = errno;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-06-25 19:22:21 +04:00
|
|
|
static int send_notify_ack(int socket_fd, int ret)
|
|
|
|
{
|
|
|
|
int send_ret;
|
|
|
|
CriuReq req = CRIU_REQ__INIT;
|
|
|
|
|
|
|
|
req.type = CRIU_REQ_TYPE__NOTIFY;
|
|
|
|
req.has_notify_success = true;
|
|
|
|
req.notify_success = (ret == 0);
|
|
|
|
|
|
|
|
send_ret = send_req(socket_fd, &req);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we're failing the notification then report
|
|
|
|
* back the original error code (and it will be
|
|
|
|
* propagated back to user).
|
|
|
|
*
|
|
|
|
* If the notification was OK, then report the
|
|
|
|
* result of acking it.
|
|
|
|
*/
|
|
|
|
|
|
|
|
return ret ? : send_ret;
|
|
|
|
}
|
|
|
|
|
2015-07-30 16:40:21 -04:00
|
|
|
static void swrk_wait(criu_opts *opts)
|
|
|
|
{
|
2015-07-30 16:40:22 -04:00
|
|
|
if (opts->service_comm == CRIU_COMM_BIN)
|
|
|
|
waitpid(opts->swrk_pid, NULL, 0);
|
2015-07-30 16:40:21 -04:00
|
|
|
}
|
|
|
|
|
2015-10-12 12:50:04 +03:00
|
|
|
static int swrk_connect(criu_opts *opts, bool d)
|
2015-07-30 16:40:21 -04:00
|
|
|
{
|
|
|
|
int sks[2], pid, ret = -1;
|
|
|
|
|
|
|
|
if (socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sks))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
pid = fork();
|
|
|
|
if (pid < 0)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (pid == 0) {
|
|
|
|
sigset_t mask;
|
|
|
|
char fds[11];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Unblock SIGCHLD.
|
|
|
|
*
|
|
|
|
* The caller of this function is supposed to have
|
|
|
|
* this signal blocked. Otherwise it risks to get
|
|
|
|
* into situation, when this routine is not yet
|
|
|
|
* returned, but the restore subtree exits and
|
|
|
|
* emits the SIGCHLD.
|
|
|
|
*
|
|
|
|
* In turn, unblocked SIGCHLD is required to make
|
|
|
|
* criu restoration process work -- it catches
|
|
|
|
* subtasks restore errors in this handler.
|
|
|
|
*/
|
|
|
|
|
|
|
|
sigemptyset(&mask);
|
|
|
|
sigaddset(&mask, SIGCHLD);
|
|
|
|
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
|
|
|
|
|
|
|
close(sks[0]);
|
|
|
|
sprintf(fds, "%d", sks[1]);
|
|
|
|
|
2015-10-12 12:50:04 +03:00
|
|
|
if (d)
|
|
|
|
if (daemon(0, 1)) {
|
|
|
|
perror("Can't detach for a self-dump");
|
|
|
|
goto child_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
pid = getpid();
|
|
|
|
if (write(sks[1], &pid, sizeof(pid)) != sizeof(pid)) {
|
|
|
|
perror("Can't write swrk pid");
|
|
|
|
goto child_err;
|
|
|
|
}
|
|
|
|
|
2015-07-30 16:40:22 -04:00
|
|
|
execlp(opts->service_binary, opts->service_binary, "swrk", fds, NULL);
|
2015-07-30 16:40:21 -04:00
|
|
|
perror("Can't exec criu swrk");
|
2015-10-12 12:50:04 +03:00
|
|
|
child_err:
|
|
|
|
close(sks[1]);
|
2015-07-30 16:40:21 -04:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
close(sks[1]);
|
2015-10-12 12:50:04 +03:00
|
|
|
|
|
|
|
if (read(sks[0], &pid, sizeof(pid)) != sizeof(pid)) {
|
|
|
|
perror("Can't read swrk pid");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2015-07-30 16:40:21 -04:00
|
|
|
opts->swrk_pid = pid;
|
|
|
|
ret = sks[0];
|
2015-10-12 12:50:04 +03:00
|
|
|
|
2015-07-30 16:40:21 -04:00
|
|
|
out:
|
|
|
|
return ret;
|
2015-10-12 12:50:04 +03:00
|
|
|
|
2015-07-30 16:40:21 -04:00
|
|
|
err:
|
|
|
|
close(sks[0]);
|
|
|
|
close(sks[1]);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2015-10-12 12:50:04 +03:00
|
|
|
static int criu_connect(criu_opts *opts, bool d)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
|
|
|
int fd, ret;
|
|
|
|
struct sockaddr_un addr;
|
|
|
|
socklen_t addr_len;
|
|
|
|
|
2015-07-16 15:42:00 +03:00
|
|
|
if (opts->service_comm == CRIU_COMM_FD)
|
|
|
|
return opts->service_fd;
|
2015-07-30 16:40:22 -04:00
|
|
|
else if (opts->service_comm == CRIU_COMM_BIN)
|
2015-10-12 12:50:04 +03:00
|
|
|
return swrk_connect(opts, d);
|
2015-07-16 15:42:00 +03:00
|
|
|
|
2013-12-18 01:04:40 +04:00
|
|
|
fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
|
|
|
|
if (fd < 0) {
|
|
|
|
saved_errno = errno;
|
|
|
|
perror("Can't create socket");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
addr.sun_family = AF_LOCAL;
|
|
|
|
|
2015-10-09 11:11:00 +03:00
|
|
|
strncpy(addr.sun_path, opts->service_address, sizeof(addr.sun_path));
|
2013-12-18 01:04:40 +04:00
|
|
|
|
2015-10-09 11:11:00 +03:00
|
|
|
addr_len = strlen(opts->service_address) + sizeof(addr.sun_family);
|
2013-12-18 01:04:40 +04:00
|
|
|
|
|
|
|
ret = connect(fd, (struct sockaddr *) &addr, addr_len);
|
|
|
|
if (ret < 0) {
|
|
|
|
saved_errno = errno;
|
|
|
|
perror("Can't connect to socket");
|
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
static int send_req_and_recv_resp_sk(int fd, criu_opts *opts, CriuReq *req, CriuResp **resp)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
2014-06-17 21:09:25 +04:00
|
|
|
int ret = 0;
|
2013-12-18 01:04:40 +04:00
|
|
|
|
|
|
|
if (send_req(fd, req) < 0) {
|
2014-06-25 19:22:21 +04:00
|
|
|
ret = -ECOMM;
|
2013-12-18 01:04:40 +04:00
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2014-06-25 19:22:21 +04:00
|
|
|
again:
|
2013-12-18 01:04:40 +04:00
|
|
|
*resp = recv_resp(fd);
|
|
|
|
if (!*resp) {
|
|
|
|
perror("Can't receive response");
|
2014-06-25 19:22:21 +04:00
|
|
|
ret = -ECOMM;
|
2013-12-18 01:04:40 +04:00
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2014-06-25 19:22:21 +04:00
|
|
|
if ((*resp)->type == CRIU_REQ_TYPE__NOTIFY) {
|
2015-07-15 04:45:02 +03:00
|
|
|
if (opts->notify)
|
|
|
|
ret = opts->notify((*resp)->notify->script, (*resp)->notify);
|
2014-06-25 19:22:21 +04:00
|
|
|
|
|
|
|
ret = send_notify_ack(fd, ret);
|
|
|
|
if (!ret)
|
|
|
|
goto again;
|
|
|
|
else
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2013-12-18 01:04:40 +04:00
|
|
|
if ((*resp)->type != req->type) {
|
|
|
|
if ((*resp)->type == CRIU_REQ_TYPE__EMPTY &&
|
|
|
|
(*resp)->success == false)
|
2014-06-25 19:22:21 +04:00
|
|
|
ret = -EINVAL;
|
2013-12-18 01:04:40 +04:00
|
|
|
else {
|
|
|
|
perror("Unexpected response type");
|
2014-06-25 19:22:21 +04:00
|
|
|
ret = -EBADMSG;
|
2013-12-18 01:04:40 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-11 22:55:17 +02:00
|
|
|
if ((*resp)->has_cr_errno)
|
|
|
|
saved_errno = (*resp)->cr_errno;
|
|
|
|
|
2013-12-18 01:04:40 +04:00
|
|
|
exit:
|
2014-06-25 19:22:21 +04:00
|
|
|
return ret;
|
2014-06-17 21:09:25 +04:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
static int send_req_and_recv_resp(criu_opts *opts, CriuReq *req, CriuResp **resp)
|
2014-06-17 21:09:25 +04:00
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
int ret = 0;
|
2015-10-12 12:50:04 +03:00
|
|
|
bool d = false;
|
|
|
|
|
|
|
|
if (req->type == CRIU_REQ_TYPE__DUMP && req->opts->has_pid == false)
|
|
|
|
d = true;
|
2014-06-17 21:09:25 +04:00
|
|
|
|
2015-10-12 12:50:04 +03:00
|
|
|
fd = criu_connect(opts, d);
|
2014-06-17 21:09:25 +04:00
|
|
|
if (fd < 0) {
|
|
|
|
perror("Can't connect to criu");
|
2014-07-29 21:06:00 +04:00
|
|
|
ret = -ECONNREFUSED;
|
2014-06-17 21:09:25 +04:00
|
|
|
} else {
|
2015-07-15 04:45:02 +03:00
|
|
|
ret = send_req_and_recv_resp_sk(fd, opts, req, resp);
|
2013-12-18 01:04:40 +04:00
|
|
|
close(fd);
|
2014-06-17 21:09:25 +04:00
|
|
|
}
|
2013-12-18 01:04:40 +04:00
|
|
|
|
2014-06-17 21:09:25 +04:00
|
|
|
return ret;
|
2013-12-18 01:04:40 +04:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
int criu_local_check(criu_opts *opts)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
CriuReq req = CRIU_REQ__INIT;
|
|
|
|
CriuResp *resp = NULL;
|
|
|
|
|
|
|
|
saved_errno = 0;
|
|
|
|
|
|
|
|
req.type = CRIU_REQ_TYPE__CHECK;
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
ret = send_req_and_recv_resp(opts, &req, &resp);
|
2013-12-18 01:04:40 +04:00
|
|
|
if (ret)
|
|
|
|
goto exit;
|
|
|
|
|
2013-12-18 15:50:27 +04:00
|
|
|
ret = resp->success ? 0 : -EBADE;
|
2013-12-18 01:04:40 +04:00
|
|
|
|
|
|
|
exit:
|
|
|
|
if (resp)
|
|
|
|
criu_resp__free_unpacked(resp, NULL);
|
|
|
|
|
2015-07-30 16:40:22 -04:00
|
|
|
swrk_wait(opts);
|
|
|
|
|
2013-12-18 01:04:40 +04:00
|
|
|
errno = saved_errno;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
int criu_check(void)
|
|
|
|
{
|
|
|
|
return criu_local_check(global_opts);
|
|
|
|
}
|
|
|
|
|
|
|
|
int criu_local_dump(criu_opts *opts)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
CriuReq req = CRIU_REQ__INIT;
|
|
|
|
CriuResp *resp = NULL;
|
|
|
|
|
|
|
|
saved_errno = 0;
|
|
|
|
|
|
|
|
req.type = CRIU_REQ_TYPE__DUMP;
|
2015-07-15 04:45:02 +03:00
|
|
|
req.opts = opts->rpc;
|
2013-12-18 01:04:40 +04:00
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
ret = send_req_and_recv_resp(opts, &req, &resp);
|
2013-12-18 01:04:40 +04:00
|
|
|
if (ret)
|
|
|
|
goto exit;
|
|
|
|
|
|
|
|
if (resp->success) {
|
|
|
|
if (resp->dump->has_restored && resp->dump->restored)
|
|
|
|
ret = 1;
|
|
|
|
else
|
|
|
|
ret = 0;
|
|
|
|
} else
|
2013-12-18 15:50:27 +04:00
|
|
|
ret = -EBADE;
|
2013-12-18 01:04:40 +04:00
|
|
|
|
|
|
|
exit:
|
|
|
|
if (resp)
|
|
|
|
criu_resp__free_unpacked(resp, NULL);
|
|
|
|
|
2015-07-30 16:40:22 -04:00
|
|
|
swrk_wait(opts);
|
|
|
|
|
2013-12-18 01:04:40 +04:00
|
|
|
errno = saved_errno;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
int criu_dump(void)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
return criu_local_dump(global_opts);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
int criu_local_dump_iters(criu_opts *opts, int (*more)(criu_predump_info pi))
|
2014-06-26 18:52:34 +04:00
|
|
|
{
|
|
|
|
int ret = -1, fd = -1, uret;
|
|
|
|
CriuReq req = CRIU_REQ__INIT;
|
|
|
|
CriuResp *resp = NULL;
|
|
|
|
|
|
|
|
saved_errno = 0;
|
|
|
|
|
|
|
|
req.type = CRIU_REQ_TYPE__PRE_DUMP;
|
2015-07-15 04:45:02 +03:00
|
|
|
req.opts = opts->rpc;
|
2014-06-26 18:52:34 +04:00
|
|
|
|
|
|
|
ret = -EINVAL;
|
|
|
|
/*
|
|
|
|
* Self-dump in iterable manner is tricky and
|
|
|
|
* not supported for the moment.
|
|
|
|
*
|
|
|
|
* Calls w/o iteration callback is, well, not
|
|
|
|
* allowed either.
|
|
|
|
*/
|
2015-07-15 04:45:02 +03:00
|
|
|
if (!opts->rpc->has_pid || !more)
|
2014-06-26 18:52:34 +04:00
|
|
|
goto exit;
|
|
|
|
|
|
|
|
ret = -ECONNREFUSED;
|
2015-10-12 12:50:04 +03:00
|
|
|
fd = criu_connect(opts, false);
|
2014-06-26 18:52:34 +04:00
|
|
|
if (fd < 0)
|
|
|
|
goto exit;
|
|
|
|
|
|
|
|
while (1) {
|
2015-07-15 04:45:02 +03:00
|
|
|
ret = send_req_and_recv_resp_sk(fd, opts, &req, &resp);
|
2014-06-26 18:52:34 +04:00
|
|
|
if (ret)
|
|
|
|
goto exit;
|
|
|
|
|
|
|
|
if (!resp->success) {
|
|
|
|
ret = -EBADE;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
uret = more(NULL);
|
|
|
|
if (uret < 0) {
|
|
|
|
ret = uret;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
criu_resp__free_unpacked(resp, NULL);
|
|
|
|
|
|
|
|
if (uret == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
req.type = CRIU_REQ_TYPE__DUMP;
|
2015-07-15 04:45:02 +03:00
|
|
|
ret = send_req_and_recv_resp_sk(fd, opts, &req, &resp);
|
2014-06-26 18:52:34 +04:00
|
|
|
if (!ret)
|
|
|
|
ret = (resp->success ? 0 : -EBADE);
|
|
|
|
exit:
|
|
|
|
if (fd >= 0)
|
|
|
|
close(fd);
|
|
|
|
if (resp)
|
|
|
|
criu_resp__free_unpacked(resp, NULL);
|
|
|
|
|
2015-07-30 16:40:22 -04:00
|
|
|
swrk_wait(opts);
|
|
|
|
|
2014-06-26 18:52:34 +04:00
|
|
|
errno = saved_errno;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
int criu_dump_iters(int (*more)(criu_predump_info pi))
|
|
|
|
{
|
|
|
|
return criu_local_dump_iters((void *)global_opts, more);
|
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
int criu_local_restore(criu_opts *opts)
|
2013-12-18 01:04:40 +04:00
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
CriuReq req = CRIU_REQ__INIT;
|
|
|
|
CriuResp *resp = NULL;
|
|
|
|
|
|
|
|
saved_errno = 0;
|
|
|
|
|
|
|
|
req.type = CRIU_REQ_TYPE__RESTORE;
|
2015-07-15 04:45:02 +03:00
|
|
|
req.opts = opts->rpc;
|
2013-12-18 01:04:40 +04:00
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
ret = send_req_and_recv_resp(opts, &req, &resp);
|
2013-12-18 01:04:40 +04:00
|
|
|
if (ret)
|
|
|
|
goto exit;
|
|
|
|
|
|
|
|
if (resp->success)
|
|
|
|
ret = resp->restore->pid;
|
|
|
|
else
|
2013-12-18 15:50:27 +04:00
|
|
|
ret = -EBADE;
|
2013-12-18 01:04:40 +04:00
|
|
|
|
|
|
|
exit:
|
|
|
|
if (resp)
|
|
|
|
criu_resp__free_unpacked(resp, NULL);
|
|
|
|
|
2015-07-30 16:40:22 -04:00
|
|
|
swrk_wait(opts);
|
|
|
|
|
2013-12-18 01:04:40 +04:00
|
|
|
errno = saved_errno;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2014-06-17 21:10:46 +04:00
|
|
|
|
2015-07-13 14:55:00 +03:00
|
|
|
int criu_restore(void)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
return criu_local_restore(global_opts);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|
|
|
|
|
2015-07-15 04:45:02 +03:00
|
|
|
int criu_local_restore_child(criu_opts *opts)
|
2014-06-17 21:10:46 +04:00
|
|
|
{
|
2015-07-30 16:40:21 -04:00
|
|
|
int sk, ret = -1;
|
2015-07-30 16:40:22 -04:00
|
|
|
enum criu_service_comm saved_comm;
|
|
|
|
char *saved_comm_data;
|
|
|
|
bool save_comm;
|
2014-06-17 21:10:46 +04:00
|
|
|
CriuReq req = CRIU_REQ__INIT;
|
|
|
|
CriuResp *resp = NULL;
|
|
|
|
|
2015-07-30 16:40:22 -04:00
|
|
|
/*
|
|
|
|
* restore_child is not possible with criu running as a system
|
|
|
|
* service, so we need to switch comm method to CRIU_COMM_BIN.
|
|
|
|
* We're doing so because of the backward compatibility, and we
|
|
|
|
* should probably consider requiring CRIU_COMM_BIN to be set by
|
|
|
|
* user at some point.
|
|
|
|
*/
|
|
|
|
save_comm = (opts->service_comm != CRIU_COMM_BIN);
|
|
|
|
if (save_comm) {
|
|
|
|
/* Save comm */
|
|
|
|
saved_comm = opts->service_comm;
|
|
|
|
saved_comm_data = opts->service_address;
|
|
|
|
|
|
|
|
opts->service_comm = CRIU_COMM_BIN;
|
|
|
|
opts->service_binary = CR_DEFAULT_SERVICE_BIN;
|
|
|
|
}
|
|
|
|
|
2015-10-12 12:50:04 +03:00
|
|
|
sk = swrk_connect(opts, false);
|
2015-07-30 16:40:22 -04:00
|
|
|
if (save_comm) {
|
|
|
|
/* Restore comm */
|
|
|
|
opts->service_comm = saved_comm;
|
|
|
|
opts->service_address = saved_comm_data;
|
|
|
|
}
|
|
|
|
|
2015-07-30 16:40:21 -04:00
|
|
|
if (sk < 0)
|
|
|
|
return -1;
|
2014-06-17 21:10:46 +04:00
|
|
|
|
2015-07-30 16:40:20 -04:00
|
|
|
saved_errno = 0;
|
|
|
|
|
2014-06-17 21:10:46 +04:00
|
|
|
req.type = CRIU_REQ_TYPE__RESTORE;
|
2015-07-15 04:45:02 +03:00
|
|
|
req.opts = opts->rpc;
|
2014-06-17 21:10:46 +04:00
|
|
|
|
2014-09-10 15:46:06 +04:00
|
|
|
req.opts->has_rst_sibling = true;
|
|
|
|
req.opts->rst_sibling = true;
|
|
|
|
|
2015-07-30 16:40:21 -04:00
|
|
|
ret = send_req_and_recv_resp_sk(sk, opts, &req, &resp);
|
2014-06-17 21:10:46 +04:00
|
|
|
|
2015-07-30 16:40:21 -04:00
|
|
|
swrk_wait(opts);
|
2014-06-17 21:10:46 +04:00
|
|
|
|
|
|
|
if (!ret) {
|
|
|
|
ret = resp->success ? resp->restore->pid : -EBADE;
|
|
|
|
criu_resp__free_unpacked(resp, NULL);
|
|
|
|
}
|
|
|
|
|
2015-07-30 16:40:21 -04:00
|
|
|
close(sk);
|
2015-07-30 16:40:20 -04:00
|
|
|
errno = saved_errno;
|
2014-06-17 21:10:46 +04:00
|
|
|
return ret;
|
|
|
|
}
|
2015-07-13 14:55:00 +03:00
|
|
|
|
|
|
|
int criu_restore_child(void)
|
|
|
|
{
|
2015-07-15 04:45:02 +03:00
|
|
|
return criu_local_restore_child(global_opts);
|
2015-07-13 14:55:00 +03:00
|
|
|
}
|