2013-09-13 13:44:09 +04:00
|
|
|
#ifndef _GNU_SOURCE
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include "crtools.h"
|
2013-11-06 17:21:11 +04:00
|
|
|
#include "cr_options.h"
|
2013-11-06 14:34:32 +04:00
|
|
|
#include "util.h"
|
2013-09-13 13:44:09 +04:00
|
|
|
#include "log.h"
|
2013-10-02 23:44:42 +04:00
|
|
|
#include "pstree.h"
|
2013-09-13 13:43:56 +04:00
|
|
|
#include "cr-service.h"
|
2013-12-18 01:04:39 +04:00
|
|
|
#include "cr-service-const.h"
|
2013-12-12 02:54:00 +04:00
|
|
|
#include "sd-daemon.h"
|
2014-01-28 22:37:15 +04:00
|
|
|
#include "page-xfer.h"
|
2014-02-11 23:53:40 +04:00
|
|
|
#include "net.h"
|
2014-06-09 17:26:17 +04:00
|
|
|
#include "mount.h"
|
2013-09-13 13:43:56 +04:00
|
|
|
|
2013-09-28 09:44:29 +04:00
|
|
|
unsigned int service_sk_ino = -1;
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2013-09-16 15:36:12 +04:00
|
|
|
static int recv_criu_msg(int socket_fd, CriuReq **msg)
|
2013-09-13 13:44:09 +04:00
|
|
|
{
|
2013-12-18 01:04:39 +04:00
|
|
|
unsigned char buf[CR_MAX_MSG_SIZE];
|
2013-09-13 13:44:09 +04:00
|
|
|
int len;
|
|
|
|
|
2013-12-18 01:04:39 +04:00
|
|
|
len = read(socket_fd, buf, CR_MAX_MSG_SIZE);
|
2013-09-13 13:44:09 +04:00
|
|
|
if (len == -1) {
|
2013-09-23 14:31:29 +04:00
|
|
|
pr_perror("Can't read request");
|
2013-09-13 13:44:09 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-01-10 18:28:00 +04:00
|
|
|
if (len == 0) {
|
|
|
|
pr_info("Client exited unexpectedly\n");
|
|
|
|
errno = ECONNRESET;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-09-16 15:36:12 +04:00
|
|
|
*msg = criu_req__unpack(NULL, len, buf);
|
2013-09-13 13:44:09 +04:00
|
|
|
if (!*msg) {
|
2013-09-23 14:31:29 +04:00
|
|
|
pr_perror("Failed unpacking request");
|
2013-09-13 13:44:09 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-16 15:36:12 +04:00
|
|
|
static int send_criu_msg(int socket_fd, CriuResp *msg)
|
2013-09-13 13:43:56 +04:00
|
|
|
{
|
2013-12-18 01:04:39 +04:00
|
|
|
unsigned char buf[CR_MAX_MSG_SIZE];
|
2013-09-13 13:44:09 +04:00
|
|
|
int len;
|
|
|
|
|
2013-09-16 15:36:12 +04:00
|
|
|
len = criu_resp__get_packed_size(msg);
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2013-09-16 15:36:12 +04:00
|
|
|
if (criu_resp__pack(msg, buf) != len) {
|
2013-09-13 13:44:09 +04:00
|
|
|
pr_perror("Failed packing response");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (write(socket_fd, buf, len) == -1) {
|
|
|
|
pr_perror("Can't send response");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-28 22:35:25 +04:00
|
|
|
static void send_criu_err(int sk, char *msg)
|
|
|
|
{
|
|
|
|
CriuResp resp = CRIU_RESP__INIT;
|
|
|
|
|
|
|
|
pr_perror("RPC error: %s", msg);
|
|
|
|
|
|
|
|
resp.type = CRIU_REQ_TYPE__EMPTY;
|
|
|
|
resp.success = false;
|
|
|
|
/* XXX -- add optional error code to CriuResp */
|
|
|
|
|
|
|
|
send_criu_msg(sk, &resp);
|
|
|
|
}
|
|
|
|
|
2013-09-16 15:40:04 +04:00
|
|
|
int send_criu_dump_resp(int socket_fd, bool success, bool restored)
|
2013-09-13 13:44:09 +04:00
|
|
|
{
|
2013-09-16 15:36:12 +04:00
|
|
|
CriuResp msg = CRIU_RESP__INIT;
|
2013-09-16 15:40:04 +04:00
|
|
|
CriuDumpResp resp = CRIU_DUMP_RESP__INIT;
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2013-09-16 15:36:12 +04:00
|
|
|
msg.type = CRIU_REQ_TYPE__DUMP;
|
|
|
|
msg.success = success;
|
2013-09-16 15:40:04 +04:00
|
|
|
msg.dump = &resp;
|
|
|
|
|
2013-09-17 00:50:03 +04:00
|
|
|
resp.has_restored = true;
|
2013-09-16 15:40:04 +04:00
|
|
|
resp.restored = restored;
|
2013-09-13 13:44:09 +04:00
|
|
|
|
|
|
|
return send_criu_msg(socket_fd, &msg);
|
|
|
|
}
|
|
|
|
|
2014-02-21 11:37:00 +04:00
|
|
|
static int send_criu_pre_dump_resp(int socket_fd, bool success)
|
|
|
|
{
|
|
|
|
CriuResp msg = CRIU_RESP__INIT;
|
|
|
|
|
|
|
|
msg.type = CRIU_REQ_TYPE__PRE_DUMP;
|
|
|
|
msg.success = success;
|
|
|
|
|
|
|
|
return send_criu_msg(socket_fd, &msg);
|
|
|
|
}
|
|
|
|
|
2013-10-02 23:44:42 +04:00
|
|
|
int send_criu_restore_resp(int socket_fd, bool success, int pid)
|
|
|
|
{
|
|
|
|
CriuResp msg = CRIU_RESP__INIT;
|
|
|
|
CriuRestoreResp resp = CRIU_RESTORE_RESP__INIT;
|
|
|
|
|
|
|
|
msg.type = CRIU_REQ_TYPE__RESTORE;
|
|
|
|
msg.success = success;
|
|
|
|
msg.restore = &resp;
|
|
|
|
|
|
|
|
resp.pid = pid;
|
|
|
|
|
|
|
|
return send_criu_msg(socket_fd, &msg);
|
|
|
|
}
|
|
|
|
|
2014-01-28 22:36:53 +04:00
|
|
|
int send_criu_rpc_script(char *script, int fd)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
CriuResp msg = CRIU_RESP__INIT;
|
|
|
|
CriuReq *req;
|
|
|
|
CriuNotify cn = CRIU_NOTIFY__INIT;
|
|
|
|
|
|
|
|
msg.type = CRIU_REQ_TYPE__NOTIFY;
|
|
|
|
msg.success = true;
|
|
|
|
msg.notify = &cn;
|
|
|
|
cn.script = script;
|
|
|
|
|
2014-02-11 09:53:32 +04:00
|
|
|
if (!strcmp(script, "setup-namespaces")) {
|
|
|
|
/*
|
|
|
|
* FIXME pid is required only once on
|
|
|
|
* restore. Need some more sane way of
|
|
|
|
* checking this.
|
|
|
|
*/
|
|
|
|
cn.has_pid = true;
|
|
|
|
cn.pid = root_item->pid.real;
|
|
|
|
}
|
|
|
|
|
2014-01-28 22:36:53 +04:00
|
|
|
ret = send_criu_msg(fd, &msg);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = recv_criu_msg(fd, &req);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (req->type != CRIU_REQ_TYPE__NOTIFY || !req->notify_success) {
|
|
|
|
pr_err("RPC client reported script error\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
criu_req__free_unpacked(req, NULL);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-02 23:44:42 +04:00
|
|
|
static int setup_opts_from_req(int sk, CriuOpts *req)
|
2013-09-13 13:44:09 +04:00
|
|
|
{
|
|
|
|
struct ucred ids;
|
|
|
|
struct stat st;
|
|
|
|
socklen_t ids_len = sizeof(struct ucred);
|
|
|
|
char images_dir_path[PATH_MAX];
|
2014-02-04 12:31:26 +04:00
|
|
|
char work_dir_path[PATH_MAX];
|
2014-02-11 23:53:40 +04:00
|
|
|
int i;
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2013-09-28 05:54:50 +04:00
|
|
|
if (getsockopt(sk, SOL_SOCKET, SO_PEERCRED, &ids, &ids_len)) {
|
2013-12-12 22:15:00 +04:00
|
|
|
pr_perror("Can't get socket options");
|
2013-09-13 13:44:09 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-09-28 15:51:09 +04:00
|
|
|
restrict_uid(ids.uid, ids.gid);
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2013-09-28 05:54:50 +04:00
|
|
|
if (fstat(sk, &st)) {
|
2013-09-13 13:44:09 +04:00
|
|
|
pr_perror("Can't get socket stat");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-09-28 09:44:29 +04:00
|
|
|
BUG_ON(st.st_ino == -1);
|
2013-09-28 06:06:53 +04:00
|
|
|
service_sk_ino = st.st_ino;
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2014-02-04 12:31:26 +04:00
|
|
|
/* open images_dir */
|
2013-09-28 05:52:18 +04:00
|
|
|
sprintf(images_dir_path, "/proc/%d/fd/%d", ids.pid, req->images_dir_fd);
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2014-01-28 22:36:36 +04:00
|
|
|
if (req->parent_img)
|
|
|
|
opts.img_parent = req->parent_img;
|
|
|
|
|
2014-02-04 12:31:26 +04:00
|
|
|
if (open_image_dir(images_dir_path) < 0) {
|
|
|
|
pr_perror("Can't open images directory");
|
2013-09-13 13:44:09 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-02-04 12:31:26 +04:00
|
|
|
/* chdir to work dir */
|
|
|
|
if (req->has_work_dir_fd)
|
|
|
|
sprintf(work_dir_path, "/proc/%d/fd/%d", ids.pid, req->work_dir_fd);
|
|
|
|
else
|
|
|
|
strcpy(work_dir_path, images_dir_path);
|
|
|
|
|
|
|
|
if (chdir(work_dir_path)) {
|
|
|
|
pr_perror("Can't chdir to work_dir");
|
2013-09-13 13:44:09 +04:00
|
|
|
return -1;
|
2014-02-04 12:31:26 +04:00
|
|
|
}
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2014-02-04 12:31:26 +04:00
|
|
|
/* initiate log file in work dir */
|
2014-02-04 18:42:48 +04:00
|
|
|
if (req->log_file) {
|
|
|
|
if (strchr(req->log_file, '/')) {
|
|
|
|
pr_perror("No subdirs are allowed in log_file name");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-10-02 16:01:44 +04:00
|
|
|
opts.output = req->log_file;
|
2014-02-04 18:42:48 +04:00
|
|
|
} else
|
2013-10-02 23:43:51 +04:00
|
|
|
opts.output = DEFAULT_LOG_FILENAME;
|
2013-09-13 13:44:09 +04:00
|
|
|
|
|
|
|
log_set_loglevel(req->log_level);
|
|
|
|
if (log_init(opts.output) == -1) {
|
2013-12-12 22:15:00 +04:00
|
|
|
pr_perror("Can't initiate log");
|
2013-09-13 13:44:09 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-10-02 23:44:42 +04:00
|
|
|
/* checking flags from client */
|
2013-09-16 15:21:13 +04:00
|
|
|
if (req->has_leave_running && req->leave_running)
|
2013-09-13 13:44:09 +04:00
|
|
|
opts.final_state = TASK_ALIVE;
|
|
|
|
|
2013-09-16 15:21:13 +04:00
|
|
|
if (!req->has_pid) {
|
|
|
|
req->has_pid = true;
|
|
|
|
req->pid = ids.pid;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (req->has_ext_unix_sk)
|
|
|
|
opts.ext_unix_sk = req->ext_unix_sk;
|
|
|
|
|
2014-01-28 22:36:36 +04:00
|
|
|
if (req->root)
|
|
|
|
opts.root = req->root;
|
|
|
|
|
2013-09-16 15:21:13 +04:00
|
|
|
if (req->has_tcp_established)
|
|
|
|
opts.tcp_established_ok = req->tcp_established;
|
|
|
|
|
|
|
|
if (req->has_evasive_devices)
|
|
|
|
opts.evasive_devices = req->evasive_devices;
|
|
|
|
|
|
|
|
if (req->has_shell_job)
|
|
|
|
opts.shell_job = req->shell_job;
|
|
|
|
|
|
|
|
if (req->has_file_locks)
|
|
|
|
opts.handle_file_locks = req->file_locks;
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2014-01-28 22:36:36 +04:00
|
|
|
if (req->has_track_mem)
|
|
|
|
opts.track_mem = req->track_mem;
|
|
|
|
|
2014-02-07 16:24:37 +04:00
|
|
|
if (req->has_link_remap)
|
|
|
|
opts.link_remap_ok = req->link_remap;
|
|
|
|
|
2014-02-21 18:42:00 +04:00
|
|
|
if (req->has_auto_dedup)
|
|
|
|
opts.auto_dedup = req->auto_dedup;
|
|
|
|
|
2014-03-06 14:56:03 +04:00
|
|
|
if (req->has_force_irmap)
|
|
|
|
opts.force_irmap = req->force_irmap;
|
|
|
|
|
2014-03-22 20:14:00 +04:00
|
|
|
if (req->n_exec_cmd > 0) {
|
|
|
|
opts.exec_cmd = xmalloc((req->n_exec_cmd + 1) * sizeof(char *));
|
|
|
|
memcpy(opts.exec_cmd, req->exec_cmd, req->n_exec_cmd * sizeof(char *));
|
|
|
|
opts.exec_cmd[req->n_exec_cmd] = NULL;
|
|
|
|
}
|
|
|
|
|
2014-01-28 22:36:36 +04:00
|
|
|
if (req->ps) {
|
|
|
|
opts.use_page_server = true;
|
|
|
|
opts.addr = req->ps->address;
|
|
|
|
opts.ps_port = htons((short)req->ps->port);
|
|
|
|
}
|
|
|
|
|
2014-01-28 22:36:53 +04:00
|
|
|
if (req->notify_scripts) {
|
|
|
|
struct script *script;
|
|
|
|
|
|
|
|
script = xmalloc(sizeof(struct script));
|
|
|
|
if (script == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
script->path = SCRIPT_RPC_NOTIFY;
|
|
|
|
script->arg = sk;
|
|
|
|
list_add(&script->node, &opts.scripts);
|
|
|
|
}
|
|
|
|
|
2014-02-11 23:53:40 +04:00
|
|
|
for (i = 0; i < req->n_veths; i++) {
|
|
|
|
if (veth_pair_add(req->veths[i]->if_in, req->veths[i]->if_out))
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-06-09 17:26:17 +04:00
|
|
|
for (i = 0; i < req->n_ext_mnt; i++) {
|
|
|
|
if (ext_mount_add(req->ext_mnt[i]->key, req->ext_mnt[i]->val))
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-02-28 18:02:18 +04:00
|
|
|
if (req->has_cpu_cap)
|
|
|
|
opts.cpu_cap = req->cpu_cap;
|
|
|
|
|
2013-09-13 13:44:09 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-02 16:04:11 +04:00
|
|
|
static int dump_using_req(int sk, CriuOpts *req)
|
2013-09-13 13:44:09 +04:00
|
|
|
{
|
2013-09-16 15:36:12 +04:00
|
|
|
bool success = false;
|
2013-12-02 19:50:44 +04:00
|
|
|
bool self_dump = !req->pid;
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2014-02-05 20:54:00 +04:00
|
|
|
if (setup_opts_from_req(sk, req))
|
2013-09-13 13:44:09 +04:00
|
|
|
goto exit;
|
|
|
|
|
2013-12-18 21:24:52 +04:00
|
|
|
/*
|
|
|
|
* FIXME -- cr_dump_tasks() may return code from custom
|
|
|
|
* scripts, that can be positive. However, right now we
|
|
|
|
* don't have ability to push scripts via RPC, so psitive
|
|
|
|
* ret values are impossible here.
|
|
|
|
*/
|
2013-12-18 21:17:53 +04:00
|
|
|
if (cr_dump_tasks(req->pid))
|
2013-09-13 13:44:09 +04:00
|
|
|
goto exit;
|
|
|
|
|
2013-12-05 12:05:46 +04:00
|
|
|
success = true;
|
2013-09-16 15:41:37 +04:00
|
|
|
exit:
|
2014-01-10 15:36:00 +04:00
|
|
|
if (req->leave_running || !self_dump || !success) {
|
2013-09-28 05:54:50 +04:00
|
|
|
if (send_criu_dump_resp(sk, success, false) == -1) {
|
2013-09-13 13:44:09 +04:00
|
|
|
pr_perror("Can't send response");
|
2013-09-16 15:36:12 +04:00
|
|
|
success = false;
|
2013-09-13 13:44:09 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-16 15:36:12 +04:00
|
|
|
return success ? 0 : 1;
|
2013-09-13 13:44:09 +04:00
|
|
|
}
|
|
|
|
|
2013-10-02 23:44:42 +04:00
|
|
|
static int restore_using_req(int sk, CriuOpts *req)
|
|
|
|
{
|
|
|
|
bool success = false;
|
|
|
|
|
2013-10-02 23:20:33 +04:00
|
|
|
/*
|
|
|
|
* We can't restore processes under arbitrary task yet.
|
|
|
|
* Thus for now we force the detached restore under the
|
|
|
|
* cr service task.
|
|
|
|
*/
|
|
|
|
|
2013-10-02 23:44:42 +04:00
|
|
|
opts.restore_detach = true;
|
|
|
|
|
2014-02-05 20:54:00 +04:00
|
|
|
if (setup_opts_from_req(sk, req))
|
2013-10-02 23:44:42 +04:00
|
|
|
goto exit;
|
|
|
|
|
|
|
|
if (cr_restore_tasks())
|
|
|
|
goto exit;
|
|
|
|
|
|
|
|
success = true;
|
|
|
|
exit:
|
2013-12-18 21:18:00 +04:00
|
|
|
if (send_criu_restore_resp(sk, success,
|
|
|
|
root_item ? root_item->pid.real : -1) == -1) {
|
2013-10-02 23:44:42 +04:00
|
|
|
pr_perror("Can't send response");
|
|
|
|
success = false;
|
|
|
|
}
|
|
|
|
|
2014-03-22 20:14:00 +04:00
|
|
|
if (success && opts.exec_cmd) {
|
|
|
|
int logfd;
|
|
|
|
|
|
|
|
logfd = log_get_fd();
|
|
|
|
if (dup2(logfd, STDOUT_FILENO) == -1 || dup2(logfd, STDERR_FILENO) == -1) {
|
|
|
|
pr_perror("Failed to redirect stdout and stderr to the logfile");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
close_pid_proc();
|
|
|
|
close(sk);
|
|
|
|
|
|
|
|
execvp(opts.exec_cmd[0], opts.exec_cmd);
|
|
|
|
pr_perror("Failed to exec cmd %s", opts.exec_cmd[0]);
|
|
|
|
success = false;
|
|
|
|
}
|
|
|
|
|
2013-10-02 23:44:42 +04:00
|
|
|
return success ? 0 : 1;
|
|
|
|
}
|
|
|
|
|
2013-11-20 03:53:24 +04:00
|
|
|
static int check(int sk)
|
|
|
|
{
|
|
|
|
CriuResp resp = CRIU_RESP__INIT;
|
|
|
|
|
2013-11-22 09:29:12 +04:00
|
|
|
resp.type = CRIU_REQ_TYPE__CHECK;
|
|
|
|
|
2014-01-04 23:57:11 +04:00
|
|
|
/* Check only minimal kernel support */
|
|
|
|
opts.check_ms_kernel = true;
|
|
|
|
|
2013-11-20 03:53:24 +04:00
|
|
|
if (!cr_check())
|
|
|
|
resp.success = true;
|
|
|
|
|
|
|
|
return send_criu_msg(sk, &resp);
|
|
|
|
}
|
|
|
|
|
2014-02-20 17:45:00 +04:00
|
|
|
static int pre_dump_using_req(int sk, CriuOpts *req)
|
2014-01-28 22:37:35 +04:00
|
|
|
{
|
|
|
|
int pid, status;
|
|
|
|
bool success = false;
|
|
|
|
|
|
|
|
pid = fork();
|
|
|
|
if (pid < 0) {
|
|
|
|
pr_perror("Can't fork");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pid == 0) {
|
|
|
|
int ret = 1;
|
|
|
|
|
2014-02-20 17:45:00 +04:00
|
|
|
if (setup_opts_from_req(sk, req))
|
2014-01-28 22:37:35 +04:00
|
|
|
goto cout;
|
|
|
|
|
2014-02-20 17:45:00 +04:00
|
|
|
if (cr_pre_dump_tasks(req->pid))
|
2014-01-28 22:37:35 +04:00
|
|
|
goto cout;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cout:
|
|
|
|
exit(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
wait(&status);
|
|
|
|
if (!WIFEXITED(status))
|
|
|
|
goto out;
|
|
|
|
if (WEXITSTATUS(status) != 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
success = true;
|
|
|
|
out:
|
2014-02-21 11:37:00 +04:00
|
|
|
if (send_criu_pre_dump_resp(sk, success) == -1) {
|
2014-01-28 22:37:35 +04:00
|
|
|
pr_perror("Can't send pre-dump resp");
|
|
|
|
success = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return success ? 0 : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int pre_dump_loop(int sk, CriuReq *msg)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
do {
|
|
|
|
ret = pre_dump_using_req(sk, msg->opts);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
criu_req__free_unpacked(msg, NULL);
|
|
|
|
if (recv_criu_msg(sk, &msg) == -1) {
|
|
|
|
pr_perror("Can't recv request");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} while (msg->type == CRIU_REQ_TYPE__PRE_DUMP);
|
|
|
|
|
|
|
|
if (msg->type != CRIU_REQ_TYPE__DUMP) {
|
|
|
|
send_criu_err(sk, "Bad req seq");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dump_using_req(sk, msg->opts);
|
|
|
|
}
|
|
|
|
|
2014-02-20 17:45:00 +04:00
|
|
|
static int start_page_server_req(int sk, CriuOpts *req)
|
2014-01-28 22:37:15 +04:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
bool success = false;
|
|
|
|
CriuResp resp = CRIU_RESP__INIT;
|
|
|
|
CriuPageServerInfo ps = CRIU_PAGE_SERVER_INFO__INIT;
|
|
|
|
|
2014-02-20 17:45:00 +04:00
|
|
|
if (!req->ps) {
|
2014-01-28 22:37:15 +04:00
|
|
|
pr_err("No page server info in message\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2014-02-20 17:45:00 +04:00
|
|
|
if (setup_opts_from_req(sk, req))
|
2014-01-28 22:37:15 +04:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
pr_debug("Starting page server\n");
|
|
|
|
|
|
|
|
ret = cr_page_server(true);
|
|
|
|
if (ret > 0) {
|
|
|
|
success = true;
|
|
|
|
ps.has_pid = true;
|
|
|
|
ps.pid = ret;
|
|
|
|
resp.ps = &ps;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_debug("Page server started\n");
|
|
|
|
out:
|
|
|
|
resp.type = CRIU_REQ_TYPE__PAGE_SERVER;
|
|
|
|
resp.success = success;
|
|
|
|
return send_criu_msg(sk, &resp);
|
|
|
|
}
|
|
|
|
|
2014-06-17 21:08:49 +04:00
|
|
|
int cr_service_work(int sk)
|
2013-09-23 14:37:56 +04:00
|
|
|
{
|
|
|
|
CriuReq *msg = 0;
|
|
|
|
|
2013-09-28 05:54:50 +04:00
|
|
|
if (recv_criu_msg(sk, &msg) == -1) {
|
2013-09-23 14:37:56 +04:00
|
|
|
pr_perror("Can't recv request");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (msg->type) {
|
|
|
|
case CRIU_REQ_TYPE__DUMP:
|
2013-10-02 16:04:11 +04:00
|
|
|
return dump_using_req(sk, msg->opts);
|
2013-10-02 23:44:42 +04:00
|
|
|
case CRIU_REQ_TYPE__RESTORE:
|
|
|
|
return restore_using_req(sk, msg->opts);
|
2013-11-20 03:53:24 +04:00
|
|
|
case CRIU_REQ_TYPE__CHECK:
|
|
|
|
return check(sk);
|
2014-01-28 22:37:35 +04:00
|
|
|
case CRIU_REQ_TYPE__PRE_DUMP:
|
|
|
|
return pre_dump_loop(sk, msg);
|
2014-01-28 22:37:15 +04:00
|
|
|
case CRIU_REQ_TYPE__PAGE_SERVER:
|
|
|
|
return start_page_server_req(sk, msg->opts);
|
2013-09-23 14:37:56 +04:00
|
|
|
|
2014-01-28 22:35:25 +04:00
|
|
|
default:
|
|
|
|
send_criu_err(sk, "Invalid req");
|
2013-09-23 14:37:56 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-11-01 14:32:03 +04:00
|
|
|
static void reap_worker(int signo)
|
|
|
|
{
|
|
|
|
int saved_errno;
|
|
|
|
int status;
|
|
|
|
pid_t pid;
|
|
|
|
|
|
|
|
saved_errno = errno;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* As we block SIGCHLD, lets wait for every child that has
|
|
|
|
* already changed state.
|
|
|
|
*/
|
|
|
|
while (1) {
|
|
|
|
pid = waitpid(-1, &status, WNOHANG);
|
|
|
|
|
|
|
|
if (pid <= 0) {
|
|
|
|
errno = saved_errno;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (WIFEXITED(status))
|
|
|
|
pr_info("Worker(pid %d) exited with %d\n",
|
|
|
|
pid, WEXITSTATUS(status));
|
|
|
|
else if (WIFSIGNALED(status))
|
|
|
|
pr_info("Worker(pid %d) was killed by %d\n",
|
|
|
|
pid, WTERMSIG(status));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int setup_sigchld_handler()
|
|
|
|
{
|
|
|
|
struct sigaction action;
|
|
|
|
|
|
|
|
sigemptyset(&action.sa_mask);
|
|
|
|
sigaddset(&action.sa_mask, SIGCHLD);
|
|
|
|
action.sa_handler = reap_worker;
|
|
|
|
action.sa_flags = SA_RESTART;
|
|
|
|
|
|
|
|
if (sigaction(SIGCHLD, &action, NULL)) {
|
|
|
|
pr_perror("Can't setup SIGCHLD handler");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int restore_sigchld_handler()
|
|
|
|
{
|
|
|
|
struct sigaction action;
|
|
|
|
|
|
|
|
sigemptyset(&action.sa_mask);
|
|
|
|
sigaddset(&action.sa_mask, SIGCHLD);
|
|
|
|
action.sa_handler = SIG_DFL;
|
|
|
|
action.sa_flags = SA_RESTART;
|
|
|
|
|
|
|
|
if (sigaction(SIGCHLD, &action, NULL)) {
|
|
|
|
pr_perror("Can't restore SIGCHLD handler");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-13 13:44:09 +04:00
|
|
|
int cr_service(bool daemon_mode)
|
|
|
|
{
|
2013-12-12 02:54:00 +04:00
|
|
|
int server_fd = -1, n;
|
2013-09-13 13:44:09 +04:00
|
|
|
int child_pid;
|
|
|
|
|
|
|
|
struct sockaddr_un client_addr;
|
|
|
|
socklen_t client_addr_len;
|
|
|
|
|
2013-12-12 02:54:00 +04:00
|
|
|
n = sd_listen_fds(0);
|
|
|
|
if (n > 1) {
|
2013-12-20 16:08:21 +04:00
|
|
|
pr_err("Too many file descriptors (%d) recieved", n);
|
2013-09-24 11:11:56 +04:00
|
|
|
goto err;
|
2013-12-12 02:54:00 +04:00
|
|
|
} else if (n == 1)
|
|
|
|
server_fd = SD_LISTEN_FDS_START + 0;
|
|
|
|
else {
|
|
|
|
struct sockaddr_un server_addr;
|
|
|
|
socklen_t server_addr_len;
|
|
|
|
|
|
|
|
server_fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
|
|
|
|
if (server_fd == -1) {
|
2013-12-12 22:15:00 +04:00
|
|
|
pr_perror("Can't initialize service socket");
|
2013-12-12 02:54:00 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2013-12-12 02:54:00 +04:00
|
|
|
memset(&server_addr, 0, sizeof(server_addr));
|
|
|
|
memset(&client_addr, 0, sizeof(client_addr));
|
|
|
|
server_addr.sun_family = AF_LOCAL;
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2013-12-12 02:54:00 +04:00
|
|
|
if (opts.addr == NULL)
|
|
|
|
opts.addr = CR_DEFAULT_SERVICE_ADDRESS;
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2013-12-12 02:54:00 +04:00
|
|
|
strcpy(server_addr.sun_path, opts.addr);
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2013-12-12 02:54:00 +04:00
|
|
|
server_addr_len = strlen(server_addr.sun_path)
|
|
|
|
+ sizeof(server_addr.sun_family);
|
|
|
|
client_addr_len = sizeof(client_addr);
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2013-12-12 02:54:00 +04:00
|
|
|
unlink(server_addr.sun_path);
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2013-12-12 02:54:00 +04:00
|
|
|
if (bind(server_fd, (struct sockaddr *) &server_addr,
|
|
|
|
server_addr_len) == -1) {
|
2013-12-12 22:15:00 +04:00
|
|
|
pr_perror("Can't bind");
|
2013-12-12 02:54:00 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2013-12-12 02:54:00 +04:00
|
|
|
pr_info("The service socket is bound to %s\n", server_addr.sun_path);
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2013-12-12 02:54:00 +04:00
|
|
|
/* change service socket permissions, so anyone can connect to it */
|
|
|
|
if (chmod(server_addr.sun_path, 0666)) {
|
2013-12-12 22:15:00 +04:00
|
|
|
pr_perror("Can't change permissions of the service socket");
|
2013-12-12 02:54:00 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2013-12-12 02:54:00 +04:00
|
|
|
if (listen(server_fd, 16) == -1) {
|
2013-12-12 22:15:00 +04:00
|
|
|
pr_perror("Can't listen for socket connections");
|
2013-12-12 02:54:00 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2013-09-13 13:44:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (daemon_mode) {
|
2013-11-15 23:04:30 +04:00
|
|
|
if (daemon(1, 0) == -1) {
|
2013-09-13 13:44:09 +04:00
|
|
|
pr_perror("Can't run service server in the background");
|
2013-09-24 11:11:56 +04:00
|
|
|
goto err;
|
2013-09-13 13:44:09 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-16 15:45:01 +04:00
|
|
|
if (opts.pidfile) {
|
2013-11-20 14:26:41 +04:00
|
|
|
if (write_pidfile(getpid()) == -1) {
|
2013-09-16 15:45:01 +04:00
|
|
|
pr_perror("Can't write pidfile");
|
2013-12-12 10:02:25 -08:00
|
|
|
goto err;
|
2013-09-16 15:45:01 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-01 14:32:03 +04:00
|
|
|
if (setup_sigchld_handler())
|
|
|
|
goto err;
|
2013-09-13 13:44:09 +04:00
|
|
|
|
|
|
|
while (1) {
|
2013-09-28 05:54:50 +04:00
|
|
|
int sk;
|
|
|
|
|
2013-09-13 13:44:09 +04:00
|
|
|
pr_info("Waiting for connection...\n");
|
|
|
|
|
2013-09-28 05:54:50 +04:00
|
|
|
sk = accept(server_fd, &client_addr, &client_addr_len);
|
|
|
|
if (sk == -1) {
|
2013-12-12 22:15:00 +04:00
|
|
|
pr_perror("Can't accept connection");
|
2013-09-24 11:12:55 +04:00
|
|
|
goto err;
|
2013-09-13 13:44:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("Connected.\n");
|
2013-09-28 05:59:33 +04:00
|
|
|
child_pid = fork();
|
|
|
|
if (child_pid == 0) {
|
|
|
|
int ret;
|
2013-09-13 13:44:09 +04:00
|
|
|
|
2013-11-01 14:32:03 +04:00
|
|
|
if (restore_sigchld_handler())
|
|
|
|
exit(1);
|
|
|
|
|
2013-09-28 05:59:33 +04:00
|
|
|
close(server_fd);
|
2014-06-17 21:08:49 +04:00
|
|
|
init_opts();
|
2013-09-28 05:59:33 +04:00
|
|
|
ret = cr_service_work(sk);
|
2013-09-28 05:54:50 +04:00
|
|
|
close(sk);
|
2013-12-12 10:02:26 -08:00
|
|
|
exit(ret != 0);
|
2013-09-13 13:44:09 +04:00
|
|
|
}
|
2013-09-28 05:59:33 +04:00
|
|
|
|
|
|
|
if (child_pid < 0)
|
|
|
|
pr_perror("Can't fork a child");
|
|
|
|
|
|
|
|
close(sk);
|
2013-09-13 13:44:09 +04:00
|
|
|
}
|
|
|
|
|
2013-09-24 11:11:56 +04:00
|
|
|
err:
|
|
|
|
close_safe(&server_fd);
|
|
|
|
|
|
|
|
return 1;
|
2013-09-13 13:43:56 +04:00
|
|
|
}
|