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