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);
}
static int dump_using_req(int sk, CriuOpts *req)
{
	bool success = false;
	bool self_dump = !req->pid;
	
	//hijacked by xichen @0707
	req->parent_img = "../pre";
        req->has_track_mem =true;
	req->track_mem = true;

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

	setproctitle("dump --rpc -t %d -D %s", req->pid, images_dir);

	/*
	 * 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.
	 */
	if (cr_dump_tasks(req->pid))
		goto exit;

	success = true;
exit:
	if (req->leave_running  || !self_dump || !success) {
		if (send_criu_dump_resp(sk, success, false) == -1) {
			pr_perror("Can't send response");
			success = false;
		}
	}

	return success ? 0 : 1;
}
Beispiel #3
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 #4
0
static int dump_using_req(int sk, CriuOpts *req)
{
	bool success = false;
	bool self_dump = !req->pid;

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

	/*
	 * 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.
	 */
	if (cr_dump_tasks(req->pid))
		goto exit;

	success = true;
exit:
	if (req->leave_running  || !self_dump || !success) {
		if (send_criu_dump_resp(sk, success, false) == -1) {
			pr_perror("Can't send response");
			success = false;
		}
	}

	return success ? 0 : 1;
}
Beispiel #5
0
static int restore_using_req(int sk, CriuOpts *req)
{
	bool success = false;

	/*
	 * We can't restore processes under arbitrary task yet.
	 * Thus for now we force the detached restore under the
	 * cr service task.
	 */

	opts.restore_detach = true;

	if (setup_opts_from_req(sk, req) == -1) {
		pr_perror("Arguments treating fail");
		goto exit;
	}

	if (cr_restore_tasks())
		goto exit;

	success = true;
exit:
	if (send_criu_restore_resp(sk, success,
				   root_item ? root_item->pid.real : -1) == -1) {
		pr_perror("Can't send response");
		success = false;
	}

	return success ? 0 : 1;
}
Beispiel #6
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 #7
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);
}
static int restore_using_req(int sk, CriuOpts *req)
{
	bool success = false;

	/*
	 * We can't restore processes under arbitrary task yet.
	 * Thus for now we force the detached restore under the
	 * cr service task.
	 */

	opts.restore_detach = true;

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

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

	if (cr_restore_tasks())
		goto exit;

	success = true;
exit:
	if (send_criu_restore_resp(sk, success,
				   root_item ? root_item->pid.real : -1) == -1) {
		pr_perror("Can't send response");
		success = false;
	}

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

	return success ? 0 : 1;
}
Beispiel #9
0
static int pre_dump_using_req(int sk, CriuOpts *req)
{
	int pid, status;
	bool success = false;

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

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

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

		setproctitle("pre-dump --rpc -t %d -D %s", req->pid, images_dir);

		if (cr_pre_dump_tasks(req->pid))
			goto cout;

		ret = 0;
cout:
		exit(ret);
	}

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

	success = true;
out:
	if (send_criu_pre_dump_resp(sk, success) == -1) {
		pr_perror("Can't send pre-dump resp");
		success = false;
	}

	return success ? 0 : -1;
}
Beispiel #10
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 #11
0
static int pre_dump_using_req(int sk, CriuOpts *req)
{
	int pid, status;
	bool success = false;

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

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

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

		if (cr_pre_dump_tasks(req->pid))
			goto cout;

		ret = 0;
cout:
		exit(ret);
	}

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

	success = true;
out:
	if (send_criu_pre_dump_resp(sk, success) == -1) {
		pr_perror("Can't send pre-dump resp");
		success = false;
	}

	return success ? 0 : -1;
}
/*
 * 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);
}
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);
}
Beispiel #14
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) {
		/* kerndat_init() is called from setup_opts_from_req() */
		if (setup_opts_from_req(sk, msg->opts))
			exit(1);

		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);
	}
	if (waitpid(pid, &status, 0) != pid) {
		pr_perror("Unable to wait %d", pid);
		goto out;
	}
	if (status != 0)
		goto out;

	/*
	 * 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);
}