[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