2
0
mirror of https://github.com/checkpoint-restore/criu synced 2025-09-05 08:45:49 +00:00
Files
criu/lib/criu.c
Pavel Emelyanov 8f05162bb4 libcriu: Add add_veth_pair call
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2014-06-27 14:22:34 +04:00

447 lines
7.0 KiB
C

#include "version.h"
#include <sys/socket.h>
#include <sys/un.h>
#include <limits.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include "criu.h"
#include "rpc.pb-c.h"
#include "cr-service-const.h"
const char *criu_lib_version = CRIU_VERSION;
static char *service_address = CR_DEFAULT_SERVICE_ADDRESS;
static CriuOpts *opts;
static int saved_errno;
void criu_set_service_address(char *path)
{
if (path)
service_address = path;
else
service_address = CR_DEFAULT_SERVICE_ADDRESS;
}
int criu_init_opts(void)
{
if (opts)
criu_opts__free_unpacked(opts, NULL);
opts = malloc(sizeof(CriuOpts));
if (opts == NULL) {
perror("Can't allocate memory for criu opts");
return -1;
}
criu_opts__init(opts);
return 0;
}
void criu_set_pid(int pid)
{
opts->has_pid = true;
opts->pid = pid;
}
void criu_set_images_dir_fd(int fd)
{
opts->images_dir_fd = fd;
}
void criu_set_parent_images(char *path)
{
opts->parent_img = strdup(path);
}
void criu_set_track_mem(bool track_mem)
{
opts->has_track_mem = true;
opts->track_mem = track_mem;
}
void criu_set_auto_dedup(bool auto_dedup)
{
opts->has_auto_dedup = true;
opts->auto_dedup = auto_dedup;
}
void criu_set_force_irmap(bool force_irmap)
{
opts->has_force_irmap = true;
opts->force_irmap = force_irmap;
}
void criu_set_link_remap(bool link_remap)
{
opts->has_link_remap = true;
opts->link_remap = link_remap;
}
void criu_set_work_dir_fd(int fd)
{
opts->has_work_dir_fd = true;
opts->work_dir_fd = fd;
}
void criu_set_leave_running(bool leave_running)
{
opts->has_leave_running = true;
opts->leave_running = leave_running;
}
void criu_set_ext_unix_sk(bool ext_unix_sk)
{
opts->has_ext_unix_sk = true;
opts->ext_unix_sk = ext_unix_sk;
}
void criu_set_tcp_established(bool tcp_established)
{
opts->has_tcp_established = true;
opts->tcp_established = tcp_established;
}
void criu_set_evasive_devices(bool evasive_devices)
{
opts->has_evasive_devices = true;
opts->evasive_devices = evasive_devices;
}
void criu_set_shell_job(bool shell_job)
{
opts->has_shell_job = true;
opts->shell_job = shell_job;
}
void criu_set_file_locks(bool file_locks)
{
opts->has_file_locks = true;
opts->file_locks = file_locks;
}
void criu_set_log_level(int log_level)
{
opts->has_log_level = true;
opts->log_level = log_level;
}
void criu_set_root(char *root)
{
opts->root = strdup(root);
}
void criu_set_log_file(char *log_file)
{
opts->log_file = strdup(log_file);
}
void criu_set_cpu_cap(unsigned int cap)
{
opts->has_cpu_cap = true;
opts->cpu_cap = cap;
}
int criu_set_exec_cmd(int argc, char *argv[])
{
int i;
opts->n_exec_cmd = argc;
opts->exec_cmd = malloc((argc) * sizeof(char *));
if (opts->exec_cmd) {
for (i = 0; i < argc; i++) {
opts->exec_cmd[i] = strdup(argv[i]);
if (!opts->exec_cmd[i]) {
while (i > 0)
free(opts->exec_cmd[i--]);
free(opts->exec_cmd);
opts->n_exec_cmd = 0;
opts->exec_cmd = NULL;
goto out;
}
}
return 0;
}
out:
return -ENOMEM;
}
int criu_add_ext_mount(char *key, char *val)
{
int nr;
ExtMountMap **a, *m;
m = malloc(sizeof(*m));
if (!m)
goto er;
m->key = strdup(key);
if (!m->key)
goto er_n;
m->val = strdup(val);
if (!m->val)
goto er_k;
nr = opts->n_ext_mnt + 1;
a = realloc(opts->ext_mnt, nr * sizeof(m));
if (!a)
goto er_v;
a[nr - 1] = m;
opts->ext_mnt = a;
opts->n_ext_mnt = nr;
return 0;
er_v:
free(m->val);
er_k:
free(m->key);
er_n:
free(m);
er:
return -ENOMEM;
}
int criu_add_veth_pair(char *in, char *out)
{
int nr;
CriuVethPair **a, *p;
p = malloc(sizeof(*p));
if (!p)
goto er;
p->if_in = strdup(in);
if (!p->if_in)
goto er_p;
p->if_out = strdup(out);
if (!p->if_out)
goto er_i;
nr = opts->n_veths + 1;
a = realloc(opts->veths, nr * sizeof(p));
if (!a)
goto er_o;
a[nr - 1] = p;
opts->veths = a;
opts->n_veths = nr;
return 0;
er_o:
free(p->if_out);
er_i:
free(p->if_in);
er_p:
free(p);
er:
return -ENOMEM;
}
static CriuResp *recv_resp(int socket_fd)
{
unsigned char buf[CR_MAX_MSG_SIZE];
int len;
CriuResp *msg = 0;
len = read(socket_fd, buf, CR_MAX_MSG_SIZE);
if (len == -1) {
perror("Can't read response");
goto err;
}
msg = criu_resp__unpack(NULL, len, buf);
if (!msg) {
perror("Failed unpacking response");
goto err;
}
return msg;
err:
saved_errno = errno;
return NULL;
}
static int send_req(int socket_fd, CriuReq *req)
{
unsigned char buf[CR_MAX_MSG_SIZE];
int len;
len = criu_req__get_packed_size(req);
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;
}
return 0;
err:
saved_errno = errno;
return -1;
}
static int criu_connect(void)
{
int fd, ret;
struct sockaddr_un addr;
socklen_t addr_len;
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;
strncpy(addr.sun_path, service_address, sizeof(addr.sun_path));
addr_len = strlen(addr.sun_path) + sizeof(addr.sun_family);
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;
}
static int send_req_and_recv_resp(CriuReq *req, CriuResp **resp)
{
int fd;
int ret = 0;
fd = criu_connect();
if (fd < 0) {
perror("Can't connect to criu");
ret = ECONNREFUSED;
goto exit;
}
if (send_req(fd, req) < 0) {
ret = ECOMM;
goto exit;
}
*resp = recv_resp(fd);
if (!*resp) {
perror("Can't receive response");
ret = ECOMM;
goto exit;
}
if ((*resp)->type != req->type) {
if ((*resp)->type == CRIU_REQ_TYPE__EMPTY &&
(*resp)->success == false)
ret = EINVAL;
else {
perror("Unexpected response type");
ret = EBADMSG;
}
}
exit:
if (fd >= 0)
close(fd);
return -ret;
}
int criu_check(void)
{
int ret = -1;
CriuReq req = CRIU_REQ__INIT;
CriuResp *resp = NULL;
saved_errno = 0;
req.type = CRIU_REQ_TYPE__CHECK;
ret = send_req_and_recv_resp(&req, &resp);
if (ret)
goto exit;
ret = resp->success ? 0 : -EBADE;
exit:
if (resp)
criu_resp__free_unpacked(resp, NULL);
errno = saved_errno;
return ret;
}
int criu_dump(void)
{
int ret = -1;
CriuReq req = CRIU_REQ__INIT;
CriuResp *resp = NULL;
saved_errno = 0;
req.type = CRIU_REQ_TYPE__DUMP;
req.opts = opts;
ret = send_req_and_recv_resp(&req, &resp);
if (ret)
goto exit;
if (resp->success) {
if (resp->dump->has_restored && resp->dump->restored)
ret = 1;
else
ret = 0;
} else
ret = -EBADE;
exit:
if (resp)
criu_resp__free_unpacked(resp, NULL);
errno = saved_errno;
return ret;
}
int criu_restore(void)
{
int ret = -1;
CriuReq req = CRIU_REQ__INIT;
CriuResp *resp = NULL;
saved_errno = 0;
req.type = CRIU_REQ_TYPE__RESTORE;
req.opts = opts;
ret = send_req_and_recv_resp(&req, &resp);
if (ret)
goto exit;
if (resp->success)
ret = resp->restore->pid;
else
ret = -EBADE;
exit:
if (resp)
criu_resp__free_unpacked(resp, NULL);
errno = saved_errno;
return ret;
}