Commit 8fddfd2f authored by Ruslan Kuprieiev's avatar Ruslan Kuprieiev Committed by Pavel Emelyanov

crtools: Add cr_service meat

The need in service is described at http://criu.org/Self_dumpSigned-off-by: 's avatarRuslan Kuprieiev <kupruser@gmail.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 2b147235
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include "crtools.h"
#include "util-pie.h"
#include "log.h"
#include "cr-service.h" #include "cr-service.h"
int cr_service() struct _cr_service_client *cr_service_client;
static int recv_criu_msg(int socket_fd, CriuMsg **msg)
{
unsigned char buf[MAX_MSG_SIZE];
int len;
len = read(socket_fd, buf, MAX_MSG_SIZE);
if (len == -1) {
puts("Can't read request");
return -1;
}
*msg = criu_msg__unpack(NULL, len, buf);
if (!*msg) {
puts("Failed unpacking request");
return -1;
}
return 0;
}
static int send_criu_msg(int socket_fd, CriuMsg *msg)
{ {
unsigned char buf[MAX_MSG_SIZE];
int len;
len = criu_msg__get_packed_size(msg);
if (criu_msg__pack(msg, buf) != len) {
pr_perror("Failed packing response");
return -1;
}
if (write(socket_fd, buf, len) == -1) {
pr_perror("Can't send response");
return -1;
}
return 0;
}
int send_criu_dump_resp(int socket_fd, CriuDumpResp *resp)
{
CriuMsg msg = CRIU_MSG__INIT;
msg.type = CRIU_MSG__TYPE__DUMPRESP;
msg.dump_resp = resp;
return send_criu_msg(socket_fd, &msg);
}
static int setup_dump_from_req(CriuDumpReq *req)
{
struct ucred ids;
struct stat st;
socklen_t ids_len = sizeof(struct ucred);
char images_dir_path[PATH_MAX];
if (getsockopt(cr_service_client->sk_fd, SOL_SOCKET, SO_PEERCRED,
&ids, &ids_len)) {
pr_perror("Can't get socket options.");
return -1;
}
cr_service_client->pid = ids.pid;
cr_service_client->uid = ids.uid;
if (req->pid == 0)
req->pid = ids.pid;
if (fstat(cr_service_client->sk_fd, &st)) {
pr_perror("Can't get socket stat");
return -1;
}
cr_service_client->sk_ino = st.st_ino;
/* going to dir, where to place images*/
sprintf(images_dir_path, "/proc/%d/fd/%d",
cr_service_client->pid, req->images_dir_fd);
if (chdir(images_dir_path)) {
pr_perror("Can't chdir to images directory");
return -1;
}
if (open_image_dir() < 0)
return -1;
log_closedir();
/* initiate log file in imgs dir */
opts.output = "./dump.log";
log_set_loglevel(req->log_level);
if (log_init(opts.output) == -1) {
pr_perror("Can't initiate log.");
return -1;
}
/* checking dump flags from client */
if (req->leave_running)
opts.final_state = TASK_ALIVE;
opts.ext_unix_sk = req->ext_unix_sk;
opts.tcp_established_ok = req->tcp_established;
opts.evasive_devices = req->evasive_devices;
opts.shell_job = req->shell_job;
opts.handle_file_locks = req->file_locks;
return 0;
}
static int dump_using_req(CriuDumpReq *req)
{
CriuDumpResp resp = CRIU_DUMP_RESP__INIT;
if (setup_dump_from_req(req) == -1) {
pr_perror("Arguments treating fail");
goto exit;
}
if (cr_dump_tasks(req->pid) == -1) {
pr_perror("Dump fail");
goto exit;
}
resp.success = true;
exit:
if (req->leave_running) {
if (send_criu_dump_resp(cr_service_client->sk_fd,
&resp) == -1) {
pr_perror("Can't send response");
resp.success = false;
}
}
close(cr_service_client->sk_fd);
return resp.success ? 0 : 1;
}
int cr_service(bool daemon_mode)
{
int server_fd;
int child_pid;
struct sockaddr_un server_addr;
struct sockaddr_un client_addr;
socklen_t server_addr_len;
socklen_t client_addr_len;
CriuMsg *msg = 0;
CriuDumpResp resp = CRIU_DUMP_RESP__INIT;
cr_service_client = malloc(sizeof(struct _cr_service_client));
server_fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
if (server_fd == -1) {
pr_perror("Can't initialize service socket.");
return -1;
}
memset(&server_addr, 0, sizeof(server_addr));
memset(&client_addr, 0, sizeof(client_addr));
server_addr.sun_family = AF_LOCAL;
if (opts.addr == NULL)
opts.addr = CR_DEFAULT_SERVICE_ADDRESS;
strcpy(server_addr.sun_path, opts.addr);
server_addr_len = strlen(server_addr.sun_path)
+ sizeof(server_addr.sun_family);
client_addr_len = sizeof(client_addr);
unlink(server_addr.sun_path);
if (bind(server_fd, (struct sockaddr *) &server_addr,
server_addr_len) == -1) {
pr_perror("Can't bind.");
return -1;
}
pr_info("The service socket is bound to %s\n", server_addr.sun_path);
/* change service socket permissions, so anyone can connect to it */
if (chmod(server_addr.sun_path, 0666)) {
pr_perror("Can't change permissions of the service socket.");
return -1;
}
if (listen(server_fd, 16) == -1) {
pr_perror("Can't listen for socket connections.");
return -1;
}
if (daemon_mode) {
if (daemon(0, 0) == -1) {
pr_perror("Can't run service server in the background");
return -errno;
}
}
/* FIXME Do not ignore children's return values */
signal(SIGCHLD, SIG_IGN);
while (1) {
pr_info("Waiting for connection...\n");
cr_service_client->sk_fd = accept(server_fd,
&client_addr,
&client_addr_len);
if (cr_service_client->sk_fd == -1) {
pr_perror("Can't accept connection.");
continue;
}
pr_info("Connected.\n");
switch (child_pid = fork()) {
case -1:
pr_perror("Can't fork a child.");
continue;
case 0:
if (recv_criu_msg(cr_service_client->sk_fd,
&msg) == -1) {
pr_perror("Can't recv request");
goto err;
}
switch (msg->type) {
case CRIU_MSG__TYPE__EMPTY:
pr_perror("Empty msg");
goto err;
case CRIU_MSG__TYPE__DUMPREQ:
exit(dump_using_req(msg->dump_req));
default:
pr_perror("Invalid request");
goto err;
}
err:
/*
* FIXME We're using CriuDumpResp here for now,
* but, when more requests will be added,
* they might require some special response,
* so we will need to use here some atomic resp,
* and extend it where needed.
*/
if (send_criu_dump_resp(cr_service_client->sk_fd,
&resp) == -1)
pr_perror("Can't send responce");
close(cr_service_client->sk_fd);
exit(-1);
default:
close(cr_service_client->sk_fd);
}
}
return 0; return 0;
} }
...@@ -336,7 +336,7 @@ int main(int argc, char *argv[]) ...@@ -336,7 +336,7 @@ int main(int argc, char *argv[])
return cr_page_server(opts.restore_detach); return cr_page_server(opts.restore_detach);
if (!strcmp(argv[optind], "service")) if (!strcmp(argv[optind], "service"))
return cr_service(); return cr_service(opts.restore_detach);
pr_msg("Unknown command \"%s\"\n", argv[optind]); pr_msg("Unknown command \"%s\"\n", argv[optind]);
usage: usage:
...@@ -348,6 +348,7 @@ usage: ...@@ -348,6 +348,7 @@ usage:
" criu check [--ms]\n" " criu check [--ms]\n"
" criu exec -p PID <syscall-string>\n" " criu exec -p PID <syscall-string>\n"
" criu page-server\n" " criu page-server\n"
" criu service [<options>]\n"
"\n" "\n"
"Commands:\n" "Commands:\n"
" dump checkpoint a process/tree identified by pid\n" " dump checkpoint a process/tree identified by pid\n"
...@@ -357,6 +358,7 @@ usage: ...@@ -357,6 +358,7 @@ usage:
" check checks whether the kernel support is up-to-date\n" " check checks whether the kernel support is up-to-date\n"
" exec execute a system call by other task\n" " exec execute a system call by other task\n"
" page-server launch page server\n" " page-server launch page server\n"
" service launch service\n"
); );
if (argc < 2) { if (argc < 2) {
...@@ -402,8 +404,8 @@ usage: ...@@ -402,8 +404,8 @@ usage:
" --prev-images-dir DIR path to images from previous dump (relative to -D)\n" " --prev-images-dir DIR path to images from previous dump (relative to -D)\n"
" --page-server send pages to page server (see options below as well)\n" " --page-server send pages to page server (see options below as well)\n"
"\n" "\n"
"Page server options\n" "Page/Service server options\n"
" --address ADDR address of page server\n" " --address ADDR address of server or service\n"
" --port PORT port of page server\n" " --port PORT port of page server\n"
" -d|--daemon run in the background after creating socket\n" " -d|--daemon run in the background after creating socket\n"
"\n" "\n"
......
#ifndef __CR_SERVICE_H__ #ifndef __CR_SERVICE_H__
#define __CR_SERVICE_H__ #define __CR_SERVICE_H__
int cr_service(void); #include "protobuf/rpc.pb-c.h"
#define CR_DEFAULT_SERVICE_ADDRESS "/tmp/criu_service.socket"
#define MAX_MSG_SIZE 1024
int cr_service(bool deamon_mode);
int send_criu_dump_resp(int socket_fd, CriuDumpResp *resp);
struct _cr_service_client {
int sk_ino;
int uid;
int pid;
int sk_fd;
};
extern struct _cr_service_client *cr_service_client;
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment