Beispiel #1
0
static int check(int sk, CriuOpts *req)
{
	int pid, status;
	CriuResp resp = CRIU_RESP__INIT;

	resp.type = CRIU_REQ_TYPE__CHECK;

	pid = fork();
	if (pid < 0) {
		pr_perror("Can't fork");
		goto out;
	}

	if (pid == 0) {
		setproctitle("check --rpc");

		if (setup_opts_from_req(sk, req))
			exit(1);

		exit(!!cr_check());
	}
	if (waitpid(pid, &status, 0) != pid) {
		pr_perror("Unable to wait %d", pid);
		goto out;
	}
	if (status)
		goto out;

	resp.success = true;
out:
	return send_criu_msg(sk, &resp);
}
Beispiel #2
0
static int start_page_server_req(int sk, CriuOpts *req)
{
	int ret;
	bool success = false;
	CriuResp resp = CRIU_RESP__INIT;
	CriuPageServerInfo ps = CRIU_PAGE_SERVER_INFO__INIT;

	if (!req->ps) {
		pr_err("No page server info in message\n");
		goto out;
	}

	if (setup_opts_from_req(sk, req))
		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);
}
Beispiel #3
0
/*
 * Return the version information, depending on the information
 * available in version.h
 */
static int handle_version(int sk, CriuReq * msg)
{
	CriuResp resp = CRIU_RESP__INIT;
	CriuVersion version = CRIU_VERSION__INIT;

	/* This assumes we will always have a major and minor version */
	version.major = CRIU_VERSION_MAJOR;
	version.minor = CRIU_VERSION_MINOR;
	if (strcmp(CRIU_GITID, "0")) {
		version.gitid = CRIU_GITID;
	}
#ifdef CRIU_VERSION_SUBLEVEL
	version.has_sublevel = 1;
	version.sublevel = CRIU_VERSION_SUBLEVEL;
#endif
#ifdef CRIU_VERSION_EXTRA
	version.has_extra = 1;
	version.extra = CRIU_VERSION_EXTRA;
#endif
#ifdef CRIU_VERSION_NAME
	/* This is not actually exported in version.h */
	version.name = CRIU_VERSION_NAME;
#endif
	resp.type = msg->type;
	resp.success = true;
	resp.version = &version;
	return send_criu_msg(sk, &resp);
}
Beispiel #4
0
static int handle_cpuinfo(int sk, CriuReq *msg)
{
	CriuResp resp = CRIU_RESP__INIT;
	bool success = false;
	int pid, status;

	pid = fork();
	if (pid < 0) {
		pr_perror("Can't fork");
		goto out;
	}

	if (pid == 0) {
		int ret = 1;

		if (setup_opts_from_req(sk, msg->opts))
			goto cout;

		setproctitle("cpuinfo %s --rpc -D %s",
			     msg->type == CRIU_REQ_TYPE__CPUINFO_DUMP ?
			     "dump" : "check",
			     images_dir);

		if (msg->type == CRIU_REQ_TYPE__CPUINFO_DUMP)
			ret = cpuinfo_dump();
		else
			ret = cpuinfo_check();
cout:
		exit(ret);
	}

	if (waitpid(pid, &status, 0) != pid) {
		pr_perror("Unable to wait %d", pid);
		goto out;
	}
	if (!WIFEXITED(status))
		goto out;
	switch (WEXITSTATUS(status)) {
	case (-ENOTSUP & 0xff):
		resp.has_cr_errno = 1;
		/*
		 * Let's return the actual error code and
		 * not just (-ENOTSUP & 0xff)
		 */
		resp.cr_errno = ENOTSUP;
		break;
	case 0:
		success = true;
		break;
	default:
		break;
	}

out:
	resp.type = msg->type;
	resp.success = success;

	return send_criu_msg(sk, &resp);
}
Beispiel #5
0
static int start_page_server_req(int sk, CriuOpts *req)
{
	int ret, pid, start_pipe[2];
	ssize_t count;
	bool success = false;
	CriuResp resp = CRIU_RESP__INIT;
	CriuPageServerInfo ps = CRIU_PAGE_SERVER_INFO__INIT;

	if (!req->ps) {
		pr_err("No page server info in message\n");
		goto out;
	}

	if (pipe(start_pipe)) {
		pr_perror("No start pipe");
		goto out;
	}

	pid = fork();
	if (pid == 0) {
		close(start_pipe[0]);

		if (setup_opts_from_req(sk, req))
			goto out_ch;

		setproctitle("page-server --rpc --address %s --port %hu", opts.addr, opts.ps_port);

		pr_debug("Starting page server\n");

		ret = cr_page_server(true, start_pipe[1]);
out_ch:
		count = write(start_pipe[1], &ret, sizeof(ret));
		close(start_pipe[1]);
		if (count != sizeof(ret))
			exit(1);
		exit(0);
	}

	close(start_pipe[1]);
	wait(NULL);
	ret = -1;
	count = read(start_pipe[0], &ret, sizeof(ret));
	if (count != sizeof(ret))
		success = false;
	else 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);
}
Beispiel #6
0
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);
}
Beispiel #7
0
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;
	set_resp_err(&resp);

	send_criu_msg(sk, &resp);
}
Beispiel #8
0
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);
}
static int check(int sk)
{
	CriuResp resp = CRIU_RESP__INIT;

	resp.type = CRIU_REQ_TYPE__CHECK;

	setproctitle("check --rpc");

	if (!cr_check())
		resp.success = true;

	return send_criu_msg(sk, &resp);
}
Beispiel #10
0
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);
}
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;
	if (get_cr_errno()) {
		msg.has_cr_errno = true;
		msg.cr_errno = get_cr_errno();
	}

	return send_criu_msg(socket_fd, &msg);
}
Beispiel #12
0
int send_criu_dump_resp(int socket_fd, bool success, bool restored)
{
	CriuResp msg = CRIU_RESP__INIT;
	CriuDumpResp resp = CRIU_DUMP_RESP__INIT;

	msg.type = CRIU_REQ_TYPE__DUMP;
	msg.success = success;
	msg.dump = &resp;

	resp.has_restored = true;
	resp.restored = restored;

	return send_criu_msg(socket_fd, &msg);
}
Beispiel #13
0
static int check(int sk)
{
	CriuResp resp = CRIU_RESP__INIT;

	resp.type = CRIU_REQ_TYPE__CHECK;

	/* Check only minimal kernel support */
	opts.check_ms_kernel = true;

	if (!cr_check())
		resp.success = true;

	return send_criu_msg(sk, &resp);
}
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;
	if (get_cr_errno()) {
		resp.has_cr_errno = true;
		resp.cr_errno = get_cr_errno();
	}

	send_criu_msg(sk, &resp);
}
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;
	if (get_cr_errno()) {
		msg.has_cr_errno = true;
		msg.cr_errno = get_cr_errno();
	}
	msg.restore = &resp;

	resp.pid = pid;

	return send_criu_msg(socket_fd, &msg);
}
int send_criu_rpc_script(enum script_actions act, char *name, 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 = name;

	switch (act) {
	case ACT_SETUP_NS:
	case ACT_POST_RESTORE:
		/*
		 * 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;
		break;
	default:
		break;
	}

	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;
}
Beispiel #17
0
static int handle_cpuinfo(int sk, CriuReq *msg)
{
	CriuResp resp = CRIU_RESP__INIT;
	bool success = false;
	int pid, status;

	pid = fork();
	if (pid < 0) {
		pr_perror("Can't fork");
		goto out;
	}

	if (pid == 0) {
		int ret = 1;

		if (setup_opts_from_req(sk, msg->opts))
			goto cout;

		setproctitle("cpuinfo %s --rpc -D %s",
			     msg->type == CRIU_REQ_TYPE__CPUINFO_DUMP ?
			     "dump" : "check",
			     images_dir);

		if (msg->type == CRIU_REQ_TYPE__CPUINFO_DUMP)
			ret = cpuinfo_dump();
		else
			ret = cpuinfo_check();
cout:
		exit(ret);
	}

	wait(&status);
	if (!WIFEXITED(status) || WEXITSTATUS(status))
		goto out;

	success = true;
out:
	resp.type = msg->type;
	resp.success = success;

	return send_criu_msg(sk, &resp);
}
Beispiel #18
0
static int handle_wait_pid(int sk, int pid)
{
	CriuResp resp = CRIU_RESP__INIT;
	bool success = false;
	int status;

	if (waitpid(pid, &status, 0) == -1) {
		resp.cr_errno = errno;
		pr_perror("Unable to wait %d", pid);
		goto out;
	}

	resp.status = status;
	resp.has_status = true;

	success = true;
out:
	resp.type = CRIU_REQ_TYPE__WAIT_PID;
	resp.success = success;

	return send_criu_msg(sk, &resp);
}
Beispiel #19
0
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;

	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;
	}

	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;
}
Beispiel #20
0
static int cr_service_work(int sk)
{
	CriuReq *msg = 0;

	init_opts();

	if (recv_criu_msg(sk, &msg) == -1) {
		pr_perror("Can't recv request");
		goto err;
	}

	switch (msg->type) {
	case CRIU_REQ_TYPE__DUMP:
		return dump_using_req(sk, msg->opts);
	case CRIU_REQ_TYPE__RESTORE:
		return restore_using_req(sk, msg->opts);
	case CRIU_REQ_TYPE__CHECK:
		return check(sk);

	default: {
		CriuResp resp = CRIU_RESP__INIT;

		resp.type = CRIU_REQ_TYPE__EMPTY;
		resp.success = false;
		/* XXX -- add optional error code to CriuResp */

		pr_perror("Invalid request");
		send_criu_msg(sk, &resp);

		goto err;
	}
	}

err:
	return -1;
}
static int start_page_server_req(int sk, CriuOpts *req)
{
	int ret = -1, pid, start_pipe[2];
	ssize_t count;
	bool success = false;
	CriuResp resp = CRIU_RESP__INIT;
	CriuPageServerInfo ps = CRIU_PAGE_SERVER_INFO__INIT;
	struct ps_info info;

	if (pipe(start_pipe)) {
		pr_perror("No start pipe");
		goto out;
	}

	pid = fork();
	if (pid == 0) {
		close(start_pipe[0]);

		if (setup_opts_from_req(sk, req))
			goto out_ch;

		setproctitle("page-server --rpc --address %s --port %hu", opts.addr, opts.port);

		pr_debug("Starting page server\n");

		pid = cr_page_server(true, start_pipe[1]);
		if (pid <= 0)
			goto out_ch;

		info.pid = pid;
		info.port = opts.port;

		count = write(start_pipe[1], &info, sizeof(info));
		if (count != sizeof(info))
			goto out_ch;

		ret = 0;
out_ch:
		if (ret < 0 && pid > 0)
			kill(pid, SIGKILL);
		close(start_pipe[1]);
		exit(ret);
	}

	close(start_pipe[1]);
	wait(&ret);
	if (WIFEXITED(ret)) {
		if (WEXITSTATUS(ret)) {
			pr_err("Child exited with an error\n");
			goto out;
		}
	} else {
		pr_err("Child wasn't terminated normally\n");
		goto out;
	}

	count = read(start_pipe[0], &info, sizeof(info));
	close(start_pipe[0]);
	if (count != sizeof(info))
		goto out;

	success = true;
	ps.has_pid = true;
	ps.pid = info.pid;
	ps.has_port = true;
	ps.port = info.port;
	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);
}
/*
 * Generic function to handle CRIU_REQ_TYPE__FEATURE_CHECK.
 *
 * The function will have resp.sucess = true for most cases
 * and the actual result will be in resp.features.
 *
 * For each feature which has been requested in msg->features
 * the corresponding parameter will be set in resp.features.
 */
static int handle_feature_check(int sk, CriuReq * msg)
{
	CriuResp resp = CRIU_RESP__INIT;
	CriuFeatures feat = CRIU_FEATURES__INIT;
	bool success = false;
	int pid, status;

	/* enable setting of an optional message */
	feat.has_mem_track = 1;
	feat.mem_track = false;

	/*
	 * Check if the requested feature check can be answered.
	 *
	 * This function is right now hard-coded to memory
	 * tracking detection and needs other/better logic to
	 * handle multiple feature checks.
	 */
	if (msg->features->has_mem_track != 1) {
		pr_warn("Feature checking for unknown feature.\n");
		goto out;
	}

	/*
	 * From this point on the function will always
	 * 'succeed'. If the requested features are supported
	 * can be seen if the requested optional parameters are
	 * set in the message 'criu_features'.
	 */
	success = true;

	pid = fork();
	if (pid < 0) {
		pr_perror("Can't fork");
		goto out;
	}

	if (pid == 0) {
		int ret = 1;

		if (setup_opts_from_req(sk, msg->opts))
			goto cout;

		setproctitle("feature-check --rpc -D %s", images_dir);

		kerndat_get_dirty_track();

		if (kdat.has_dirty_track)
			ret = 0;
cout:
		exit(ret);
	}

	wait(&status);
	if (!WIFEXITED(status) || WEXITSTATUS(status))
		goto out;

	feat.mem_track = true;
out:
	resp.features = &feat;
	resp.type = msg->type;
	resp.success = success;

	return send_criu_msg(sk, &resp);
}
Beispiel #23
0
/*
 * Generic function to handle CRIU_REQ_TYPE__FEATURE_CHECK.
 *
 * The function will have resp.success = true for most cases
 * and the actual result will be in resp.features.
 *
 * For each feature which has been requested in msg->features
 * the corresponding parameter will be set in resp.features.
 */
static int handle_feature_check(int sk, CriuReq * msg)
{
	CriuResp resp = CRIU_RESP__INIT;
	CriuFeatures feat = CRIU_FEATURES__INIT;
	int pid, status;
	int ret;

	/* enable setting of an optional message */
	feat.has_mem_track = 1;
	feat.mem_track = false;
	feat.has_lazy_pages = 1;
	feat.lazy_pages = false;

	pid = fork();
	if (pid < 0) {
		pr_perror("Can't fork");
		goto out;
	}

	if (pid == 0) {

		setproctitle("feature-check --rpc");

		if ((msg->features->has_mem_track == 1) &&
		    (msg->features->mem_track == true))
			feat.mem_track = kdat.has_dirty_track;

		if ((msg->features->has_lazy_pages == 1) &&
		    (msg->features->lazy_pages == true))
			feat.lazy_pages = kdat.has_uffd && uffd_noncooperative();

		resp.features = &feat;
		resp.type = msg->type;
		/* The feature check is working, actual results are in resp.features */
		resp.success = true;

		/*
		 * If this point is reached the information about the features
		 * is transmitted from the forked CRIU process (here).
		 * If an error occurred earlier, the feature check response will be
		 * be send from the parent process.
		 */
		ret = send_criu_msg(sk, &resp);

		exit(ret);
	}

	ret = waitpid(pid, &status,  0);
	if (ret == -1)
		goto out;

	if (WIFEXITED(status) && !WEXITSTATUS(status))
		/*
		 * The child process exited was able to send the answer.
		 * Nothing more to do here.
		 */
		return 0;

	/*
	 * The child process was not able to send an answer. Tell
	 * the RPC client that something did not work as expected.
	 */
out:
	resp.type = msg->type;
	resp.success = false;

	return send_criu_msg(sk, &resp);
}