int criu_restore(void) { int ret = -1; CriuReq req = CRIU_REQ__INIT; CriuResp *resp = NULL; saved_errno = 0; req.type = CRIU_REQ_TYPE__RESTORE; req.opts = opts; ret = send_req_and_recv_resp(&req, &resp); if (ret) goto exit; if (resp->success) ret = resp->restore->pid; else ret = -EBADE; exit: if (resp) criu_resp__free_unpacked(resp, NULL); errno = saved_errno; return ret; }
int criu_dump(void) { int ret = -1; CriuReq req = CRIU_REQ__INIT; CriuResp *resp = NULL; saved_errno = 0; req.type = CRIU_REQ_TYPE__DUMP; req.opts = opts; ret = send_req_and_recv_resp(&req, &resp); if (ret) goto exit; if (resp->success) { if (resp->dump->has_restored && resp->dump->restored) ret = 1; else ret = 0; } else ret = -EBADE; exit: if (resp) criu_resp__free_unpacked(resp, NULL); errno = saved_errno; return ret; }
int criu_check(void) { int ret = -1; CriuReq req = CRIU_REQ__INIT; CriuResp *resp = NULL; saved_errno = 0; req.type = CRIU_REQ_TYPE__CHECK; ret = send_req_and_recv_resp(&req, &resp); if (ret) goto exit; ret = resp->success ? 0 : -EBADE; exit: if (resp) criu_resp__free_unpacked(resp, NULL); errno = saved_errno; return ret; }
int criu_restore_child(void) { int sks[2], pid, ret = -1; CriuReq req = CRIU_REQ__INIT; CriuResp *resp = NULL; if (socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sks)) goto out; pid = fork(); if (pid < 0) goto err; if (pid == 0) { sigset_t mask; char fds[11]; /* * Unblock SIGCHLD. * * The caller of this function is supposed to have * this signal blocked. Otherwise it risks to get * into situation, when this routine is not yet * returned, but the restore subtree exits and * emits the SIGCHLD. * * In turn, unblocked SIGCHLD is required to make * criu restoration process work -- it catches * subtasks restore errors in this handler. */ sigemptyset(&mask); sigaddset(&mask, SIGCHLD); sigprocmask(SIG_UNBLOCK, &mask, NULL); close(sks[0]); sprintf(fds, "%d", sks[1]); execlp("criu", "criu", "swrk", fds, NULL); exit(1); } close(sks[1]); req.type = CRIU_REQ_TYPE__RESTORE; req.opts = opts; req.opts->has_rst_sibling = true; req.opts->rst_sibling = true; ret = send_req_and_recv_resp_sk(sks[0], &req, &resp); close(sks[0]); waitpid(pid, NULL, 0); if (!ret) { ret = resp->success ? resp->restore->pid : -EBADE; criu_resp__free_unpacked(resp, NULL); } out: return ret; err: close(sks[1]); close(sks[0]); goto out; }
int criu_dump_iters(int (*more)(criu_predump_info pi)) { int ret = -1, fd = -1, uret; CriuReq req = CRIU_REQ__INIT; CriuResp *resp = NULL; saved_errno = 0; req.type = CRIU_REQ_TYPE__PRE_DUMP; req.opts = opts; ret = -EINVAL; /* * Self-dump in iterable manner is tricky and * not supported for the moment. * * Calls w/o iteration callback is, well, not * allowed either. */ if (!opts->has_pid || !more) goto exit; ret = -ECONNREFUSED; fd = criu_connect(); if (fd < 0) goto exit; while (1) { ret = send_req_and_recv_resp_sk(fd, &req, &resp); if (ret) goto exit; if (!resp->success) { ret = -EBADE; goto exit; } uret = more(NULL); if (uret < 0) { ret = uret; goto exit; } criu_resp__free_unpacked(resp, NULL); if (uret == 0) break; } req.type = CRIU_REQ_TYPE__DUMP; ret = send_req_and_recv_resp_sk(fd, &req, &resp); if (!ret) ret = (resp->success ? 0 : -EBADE); exit: if (fd >= 0) close(fd); if (resp) criu_resp__free_unpacked(resp, NULL); errno = saved_errno; return ret; }
int main(int argc, char *argv[]) { CriuReq req = CRIU_REQ__INIT; CriuResp *resp = NULL; int fd, dir_fd; int ret = 0; struct sockaddr_un addr; socklen_t addr_len; if (argc != 3) { fprintf(stderr, "Usage: test-c criu-service.socket imgs_dir"); return -1; } /* * Open a directory, in which criu will * put images */ puts(argv[2]); dir_fd = open(argv[2], O_DIRECTORY); if (dir_fd == -1) { perror("Can't open imgs dir"); return -1; } /* * Set "DUMP" type of request. * Allocate CriuDumpReq. */ req.type = CRIU_REQ_TYPE__DUMP; req.opts = malloc(sizeof(CriuOpts)); if (!req.opts) { perror("Can't allocate memory for dump request"); return -1; } criu_opts__init(req.opts); /* * Set dump options. * Checkout more in protobuf/rpc.proto. */ req.opts->has_leave_running = true; req.opts->leave_running = true; req.opts->images_dir_fd = dir_fd; req.opts->has_log_level = true; req.opts->log_level = 4; /* * Connect to service socket */ fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0); if (fd == -1) { perror("Can't create socket"); return -1; } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_LOCAL; strcpy(addr.sun_path, argv[1]); addr_len = strlen(addr.sun_path) + sizeof(addr.sun_family); ret = connect(fd, (struct sockaddr *) &addr, addr_len); if (ret == -1) { perror("Cant connect to socket"); goto exit; } /* * Send request */ ret = send_req(fd, &req); if (ret == -1) { perror("Can't send request"); goto exit; } /* * Recv response */ resp = recv_resp(fd); if (!resp) { perror("Can't recv response"); ret = -1; goto exit; } if (resp->type != CRIU_REQ_TYPE__DUMP) { perror("Unexpected response type"); ret = -1; goto exit; } /* * Check response. */ if (resp->success) puts("Success"); else { puts("Fail"); ret = -1; goto exit; } if (resp->dump->has_restored && resp->dump->restored) puts("Restored"); exit: close(fd); close(dir_fd); if (resp) criu_resp__free_unpacked(resp, NULL); return ret; }