[CRIU] [PATCH 2/2] libcriu: crtools:cr_service() for crtools and a few changes to handle service socket

Ruslan Kuprieiev kupruser at gmail.com
Thu Aug 29 13:28:30 EDT 2013


Hi!

Patch 2\2 contains cr_service() for crtools and a few changes to handle 
service socket:
         * cr_service() is used to handle criu library requests through 
socket.
            It creates unix domain socket and listens to connections on 
it. After request
             it fork()-s a child, which gets pid through SO_PEERCRED, 
receives and processes
             dump arguments, dumps program and sends flag back through 
socket to library.
         * adding USK_LIB_CTRL macro and handling library socket when 
dumping and restoring.
            On dump, if library socket is detected, it will be marked 
with USK_LIB_CTRL and dumped like closed one.
            On restore, we will send CRIU_RESUME to it.

Signed-off-by: Ruslan Kuprieiev kupruser at gmail.com

-------------- next part --------------
diff --git a/Makefile.crtools b/Makefile.crtools
index 33a9c70..d1c37e8 100644
--- a/Makefile.crtools
+++ b/Makefile.crtools
@@ -53,6 +53,7 @@ obj-y	+= stats.o
 obj-y	+= string.o
 obj-y	+= sigframe.o
 obj-y	+= arch/$(ARCH)/vdso.o
+obj-y	+= cr-service.o
 
 ifneq ($(MAKECMDGOALS),clean)
 incdeps := y
diff --git a/cr-service.c b/cr-service.c
new file mode 100644
index 0000000..45eaf3d
--- /dev/null
+++ b/cr-service.c
@@ -0,0 +1,206 @@
+#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 "libcriu.h"
+
+static int criu_recv_dump_arg(int socket_fd, struct criu_dump_args *arg)
+{
+	int ret;
+	arg->images_dir_fd = recv_fd(socket_fd);
+	if (arg->images_dir_fd == -1) {
+		pr_perror("Can't recv file descriptor");
+		return -1;
+	}
+
+	ret = recv(socket_fd, &(arg->flags), sizeof(arg->flags), 0);
+	if (ret == -1) {
+		pr_perror("Can't recv flags");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int client_fd;
+
+int get_lib_sk_ino(void)
+{
+	struct stat st;
+	if (fstat(client_fd, &st)) {
+		pr_perror("Can't get library socket stat");
+		return -1;
+	}
+
+	return st.st_ino;
+}
+
+int cr_service(void)
+{
+	/* create sockets */
+	int server_fd;
+
+	server_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+	if (server_fd == -1) {
+		pr_perror("Can't initialize service socket.");
+		return -1;
+	}
+
+	struct sockaddr_un server_addr;
+	struct sockaddr_un client_addr;
+
+	memset(&server_addr, 0, sizeof(server_addr));
+	memset(&client_addr, 0, sizeof(client_addr));
+	server_addr.sun_family = AF_LOCAL;
+
+	socklen_t server_addr_len;
+	socklen_t client_addr_len;
+
+	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;
+	}
+
+	/* 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;
+	}
+
+	struct criu_dump_args *criu_arg;
+	criu_arg = malloc(sizeof(*criu_arg));
+
+	pid_t child_pid;
+
+	int ret;
+
+	/* structure for credentials */
+	struct ucred ids;
+	socklen_t ids_len;
+	ids_len = sizeof(struct ucred);
+
+	/* ignore children's return values */
+	signal(SIGCHLD, SIG_IGN);
+
+	while (1) {
+		pr_info("Waiting for connection...\n");
+
+		client_fd = accept(server_fd, &client_addr, &client_addr_len);
+		if (client_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:
+			/* getting socket credentials */
+			if (getsockopt(client_fd, SOL_SOCKET,
+						SO_PEERCRED, &ids, &ids_len)) {
+				pr_perror("Can't get socket options.");
+				goto child_err;
+			}
+
+			/* recovering dump argument */
+			client_addr_len = criu_recv_dump_arg(client_fd,
+								criu_arg);
+			if (client_addr_len == -1) {
+				pr_perror("Can't recover argument");
+				goto child_err;
+			}
+
+			/* going to dir, where to place images*/
+			if (fchdir(criu_arg->images_dir_fd)) {
+				pr_perror("Can't change directory.");
+				goto child_err;
+			}
+
+			/* initiate log file in imgs dir*/
+			opts.output = malloc(sizeof(char)*PATH_MAX);
+			strcpy(opts.output, getcwd(NULL, PATH_MAX));
+			strcat(opts.output, "/dump.log");
+
+			if (open_image_dir() < 0) {
+				pr_perror("Can't open current directory.");
+				goto child_err;
+			}
+
+			log_set_loglevel(log_get_loglevel());
+			if (log_init(opts.output) == -1) {
+				pr_perror("Can't initiate log.");
+				goto child_err;
+			}
+
+			/* checking dump flags from client */
+			if (criu_arg->flags & CRIU_DUMP_AND_CONTINUE)
+				opts.final_state = TASK_ALIVE;
+
+			/* dump */
+			if (cr_dump_tasks(ids.pid) < 0) {
+				pr_perror("Dump failed.");
+				goto child_err;
+			}
+
+			/* send msg that dump was successful */
+			if (opts.final_state == TASK_ALIVE) {
+				ret = CRIU_DUMP_SUCCESS;
+				if (send(client_fd, &ret,
+					   sizeof(ret), 0) == -1) {
+					pr_perror("Can't send msg to lib");
+					close(client_fd);
+					exit(1);
+				}
+			}
+
+			close(client_fd);
+			exit(0);
+
+child_err:		ret = CRIU_DUMP_FAIL;
+			if (send(client_fd, &ret, sizeof(ret), 0) == -1)
+				pr_perror("Can't send msg to lib");
+
+			close(client_fd);
+			exit(1);
+
+		default:
+			close(client_fd);
+		}
+	}
+
+	return 0;
+}
diff --git a/crtools.c b/crtools.c
index c7bc8b4..6642dde 100644
--- a/crtools.c
+++ b/crtools.c
@@ -334,6 +334,9 @@ int main(int argc, char *argv[])
 	if (!strcmp(argv[optind], "page-server"))
 		return cr_page_server(opts.restore_detach);
 
+	if (!strcmp(argv[optind], "service"))
+		return cr_service();
+
 	pr_msg("Unknown command \"%s\"\n", argv[optind]);
 usage:
 	pr_msg("\n"
@@ -344,6 +347,7 @@ usage:
 "  criu check [--ms]\n"
 "  criu exec -p PID <syscall-string>\n"
 "  criu page-server\n"
+"  criu service [<options>]\n"
 "\n"
 "Commands:\n"
 "  dump           checkpoint a process/tree identified by pid\n"
@@ -353,6 +357,7 @@ usage:
 "  check          checks whether the kernel support is up-to-date\n"
 "  exec           execute a system call by other task\n"
 "  page-server    launch page server\n"
+"  service        launch service server\n"
 	);
 
 	if (argc < 2) {
@@ -403,6 +408,9 @@ usage:
 "  --port PORT           port of page server\n"
 "  -d|--daemon           run in the background after creating socket\n"
 "\n"
+"Service server options\n"
+"  --address ADDR        address, where to put service socket\n"
+"\n"
 "Show options:\n"
 "  -f|--file FILE        show contents of a checkpoint file\n"
 "  -D|--images-dir DIR   directory where to get images from\n"
diff --git a/include/crtools.h b/include/crtools.h
index 7319992..f4bb06e 100644
--- a/include/crtools.h
+++ b/include/crtools.h
@@ -119,6 +119,9 @@ int cr_show(int pid);
 int convert_to_elf(char *elf_path, int fd_core);
 int cr_check(void);
 int cr_exec(int pid, char **opts);
+int cr_service(void);
+
+int get_lib_sk_ino(void);
 
 #define O_DUMP	(O_RDWR | O_CREAT | O_EXCL)
 #define O_SHOW	(O_RDONLY)
diff --git a/include/image.h b/include/image.h
index 5cd7741..b201226 100644
--- a/include/image.h
+++ b/include/image.h
@@ -18,6 +18,7 @@
 #define REMAP_GHOST	(1 << 31)
 
 #define USK_EXTERN	(1 << 0)
+#define USK_LIB_CTRL	(1 << 1)
 
 #define VMA_AREA_NONE		(0 <<  0)
 #define VMA_AREA_REGULAR	(1 <<  0)	/* Dumpable area */
diff --git a/sk-unix.c b/sk-unix.c
index cf024a5..365c5ac 100644
--- a/sk-unix.c
+++ b/sk-unix.c
@@ -21,6 +21,7 @@
 #include "sockets.h"
 #include "sk-queue.h"
 #include "mount.h"
+#include "libcriu.h"
 
 #include "protobuf.h"
 #include "protobuf/sk-unix.pb-c.h"
@@ -138,6 +139,17 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p)
 	ue.opts		= &skopts;
 	ue.uflags	= 0;
 
+	/*
+	 * Check if this is library socket,
+	 * that is connected to criu service.
+	 * Dump it like closed one and mark it for restore.
+	 */
+	if (ue.peer == get_lib_sk_ino()) {
+		ue.state = TCP_CLOSE;
+		ue.peer = 0;
+		ue.uflags |= USK_LIB_CTRL;
+	}
+
 	if (sk->namelen && *sk->name) {
 		ue.file_perms = &perms;
 
@@ -716,7 +728,23 @@ static int open_unixsk_standalone(struct unix_sk_info *ui)
 	pr_info("Opening standalone socket (id %#x ino %#x peer %#x)\n",
 			ui->ue->id, ui->ue->ino, ui->ue->peer);
 
-	if ((ui->ue->state == TCP_ESTABLISHED) && !ui->ue->peer) {
+	if (ui->ue->uflags & USK_LIB_CTRL) {
+		int sks[2];
+
+		if (socketpair(PF_UNIX, ui->ue->type, 0, sks)) {
+			pr_perror("Can't create socketpair");
+			return -1;
+		}
+
+		int msg = CRIU_RESUME;
+		if (write(sks[1], &msg, sizeof(msg)) != sizeof(msg)) {
+			pr_perror("Can't write msg for lib to socket");
+			return -1;
+		}
+
+		close(sks[1]);
+		sk = sks[0];
+	} else if ((ui->ue->state == TCP_ESTABLISHED) && !ui->ue->peer) {
 		int ret, sks[2];
 
 		if (ui->ue->type != SOCK_STREAM) {



More information about the CRIU mailing list