[CRIU] [PATCHv3 4/4] crtools: cr_service() and fixes for it
Ruslan Kuprieiev
kupruser at gmail.com
Mon Sep 2 11:19:26 EDT 2013
On 09/02/2013 07:18 PM, Ruslan Kuprieiev wrote:
> On 09/02/2013 07:15 PM, Ruslan Kuprieiev wrote:
>> 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.
>
Sorry for spamming...
-------------- 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