[CRIU] [PATCH 0/4] crtools: cr_service() and fixes for it

Ruslan Kuprieiev kupruser at gmail.com
Mon Sep 2 11:15:04 EDT 2013


cr_service() is function to start daemon, that will create unix domain 
socket and will listen for requests from libcriu on it. If request is 
obtained, it will fork() child, that will recv, process arguments and 
dump program.

P.S. scripts/checkpatch.pl reports a warning "quoted string split across 
lines" on this:
pr_perror("Looks like criu (version %s) is out-of-date. "
                 "Please, upgrade criu.", version);
What is the problem here?

P.P.S.I googled and still don't get what is wrong.Sorry for stupid 
questions, i'm noob.
-------------- next part --------------
diff --git a/cr-service.c b/cr-service.c
index e921828..6a79cdd 100644
--- a/cr-service.c
+++ b/cr-service.c
@@ -1,4 +1,251 @@
+#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"
+#include "version.h"
+#include "protobuf/criu-dump-args.pb-c.h"
+
+
+static CriuDumpArgs *args;
+static int client_fd;
+
+static int criu_recv_dump_args(int socket_fd)
+{
+	int len;
+	unsigned char *buf;
+	/*
+	 * Recv the size of args and then
+	 * recv args.
+	 */
+	if (recv(socket_fd, &len, sizeof(len), 0) == -1) {
+		pr_perror("Can't recv size of args");
+		return -1;
+	}
+
+	buf = malloc(len);
+	if (buf == NULL) {
+		pr_perror("Can't allocate memory");
+		return -1;
+	}
+
+	errno = 0;
+	if (recv(socket_fd, buf, len, MSG_WAITALL) == -1) {
+		if (errno == EAGAIN || errno == EWOULDBLOCK)
+			pr_perror("Recv timeout");
+		pr_perror("Can't recv args");
+		return -1;
+	}
+
+	args = criu_dump_args__unpack(NULL, len, buf);
+	if (args == NULL) {
+		pr_perror("Can't unpack msg");
+		return -1;
+	}
+
+	/*
+	 * Recv opened dir fd, where to put images
+	 */
+	args->images_dir_fd = recv_fd(socket_fd);
+	if (args->images_dir_fd == -1) {
+		pr_perror("Can't recv file descriptor");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * This function is needed in sk-unix.c,
+ * to recognize connection to service socket
+ * and dump it properly.
+ */
+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;
+}
+
+static int get_client_pid(void)
+{
+	struct ucred ids;
+	socklen_t ids_len;
+	ids_len = sizeof(struct ucred);
+
+	if (getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED, &ids, &ids_len)) {
+		pr_perror("Can't get socket options.");
+		return -1;
+	}
+
+	return ids.pid;
+}
+
+static int child_work(void)
+{
+	int pid;
+	int ret;
+
+	if (criu_recv_dump_args(client_fd) == -1) {
+		pr_perror("Can't recv args");
+		goto child_err;
+	}
+
+	/* check version */
+	if (args->version_major != CRIU_VERSION_MAJOR ||
+	    args->version_minor != CRIU_VERSION_MINOR) {
+		pr_perror("Looks like criu (version %s) is out-of-date. "
+			  "Please, upgrade criu.", version);
+		ret = CRIU_OLD_VERSION;
+		goto child_out;
+	}
+
+	pid = get_client_pid();
+	if (pid == -1) {
+		pr_perror("Can't get pid");
+		goto child_err;
+	}
+
+	/* going to dir, where to place images*/
+	if (fchdir(args->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;
+	}
+
+	/* FIXME: log level of dump.log is the same as log level,
+	 * which was set when running criu service. Add log level
+	 * to args.
+	 */
+	if (log_init(opts.output) == -1) {
+		pr_perror("Can't initiate log.");
+		goto child_err;
+	}
+
+	/* checking dump flags from client */
+	if (args->flags & CRIU_DUMP_AND_CONTINUE) {
+		opts.final_state = TASK_ALIVE;
+		ret = CRIU_DUMP_SUCCESS; /* pre set */
+	}
+
+	/* dump */
+	if (cr_dump_tasks(pid) < 0) {
+		pr_perror("Dump failed.");
+		goto child_err;
+	}
+
+	close(client_fd);
+	exit(0);
+
+child_err:
+	ret = CRIU_DUMP_FAIL;
+child_out:
+	if (send(client_fd, &ret, sizeof(ret), 0) == -1)
+		pr_perror("Can't send msg to lib");
+
+	close(client_fd);
+	exit(1);
+}
+
 int cr_service(void)
 {
+	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;
+
+	server_fd = socket(AF_LOCAL, SOCK_STREAM, 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;
+	}
+
+	/* 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;
+	}
+
+	/* FIXME Do not 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:
+			exit(child_work());
+		default:
+			close(client_fd);
+		}
+	}
+
 	return 0;
 }
diff --git a/include/crtools.h b/include/crtools.h
index d867522..ce7466d 100644
--- a/include/crtools.h
+++ b/include/crtools.h
@@ -121,6 +121,8 @@ 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)
 #define O_RSTR	(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