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

Pavel Emelyanov xemul at parallels.com
Thu Aug 29 14:08:54 EDT 2013


On 08/29/2013 09:28 PM, Ruslan Kuprieiev wrote:
> 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
> 


This patch should be splitted. First adds cr-service skeleton -- help
text, option parsing and empty cr_service() function. The 2nd one -- all the "meat".

> +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;

No variables in the middle of the function.

> +
> +	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 */

Put "FIXME" word in the comment.

> +	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");

log_init() works OK with relative paths.

> +
> +			if (open_image_dir() < 0) {
> +				pr_perror("Can't open current directory.");
> +				goto child_err;
> +			}
> +
> +			log_set_loglevel(log_get_loglevel());

Isn't it "such" already?

> +			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) {

The cr_dump_tasks() should be patched not to dump children and below whose
uid or gid doesn't match the original task's (unless it's 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;
> +}



More information about the CRIU mailing list