[CRIU] [PATCHv4 4/4] crtools: cr_service() and fixes for it
Andrew Vagin
avagin at parallels.com
Fri Sep 6 00:47:07 EDT 2013
On Tue, Sep 03, 2013 at 06:44:35PM +0400, 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.
> diff --git a/cr-service.c b/cr-service.c
> index e921828..7ac1a04 100644
> --- a/cr-service.c
> +++ b/cr-service.c
> @@ -1,4 +1,260 @@
> +#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);
Use xmallo/xfree
> + if (buf == NULL) {
> + pr_perror("Can't allocate memory");
> + return -1;
> + }
> +
> + errno = 0;
isn't required
> + 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");
Usually such messages is printed from criu_dump_args__unpack
> + 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");
recv_fd prints a similar error message
> + 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 on start of 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;
> + args->flags &= CRIU_DUMP_AND_CONTINUE;
> + ret = CRIU_DUMP_SUCCESS; /* pre set */
> + }
> +
> + if (args->flags != 0) {
> + /*
> + * FIXME add flag for bad args to libcriu.h
> + */
> + pr_perror("Bad flags");
> + goto child_err;
> + }
> +
> + /* 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");
I think we will use a protobuf message here too.
> +
> + 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;
> + }
Should this service daemonizes here? Look at page-server for example.
> +
> + 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) {
>
> _______________________________________________
> CRIU mailing list
> CRIU at openvz.org
> https://lists.openvz.org/mailman/listinfo/criu
More information about the CRIU
mailing list