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