LCOV - code coverage report
Current view: top level - home/snorch/criu - cr-service.c (source / functions) Hit Total Coverage
Test: coverage3.info Lines: 0 318 0.0 %
Date: 2014-04-22 Functions: 0 19 0.0 %
Branches: 0 198 0.0 %

           Branch data     Line data    Source code
       1                 :            : #ifndef _GNU_SOURCE
       2                 :            : #define _GNU_SOURCE
       3                 :            : #endif
       4                 :            : 
       5                 :            : #include <unistd.h>
       6                 :            : #include <stdio.h>
       7                 :            : #include <stdlib.h>
       8                 :            : #include <errno.h>
       9                 :            : #include <string.h>
      10                 :            : #include <sys/types.h>
      11                 :            : #include <sys/socket.h>
      12                 :            : #include <sys/un.h>
      13                 :            : #include <sys/wait.h>
      14                 :            : #include <sys/stat.h>
      15                 :            : 
      16                 :            : #include "crtools.h"
      17                 :            : #include "cr_options.h"
      18                 :            : #include "util.h"
      19                 :            : #include "log.h"
      20                 :            : #include "pstree.h"
      21                 :            : #include "cr-service.h"
      22                 :            : #include "cr-service-const.h"
      23                 :            : #include "sd-daemon.h"
      24                 :            : #include "page-xfer.h"
      25                 :            : #include "net.h"
      26                 :            : 
      27                 :            : unsigned int service_sk_ino = -1;
      28                 :            : 
      29                 :          0 : static int recv_criu_msg(int socket_fd, CriuReq **msg)
      30                 :            : {
      31                 :            :         unsigned char buf[CR_MAX_MSG_SIZE];
      32                 :            :         int len;
      33                 :            : 
      34                 :          0 :         len = read(socket_fd, buf, CR_MAX_MSG_SIZE);
      35         [ #  # ]:          0 :         if (len == -1) {
      36                 :          0 :                 pr_perror("Can't read request");
      37                 :          0 :                 return -1;
      38                 :            :         }
      39                 :            : 
      40         [ #  # ]:          0 :         if (len == 0) {
      41                 :          0 :                 pr_info("Client exited unexpectedly\n");
      42                 :          0 :                 errno = ECONNRESET;
      43                 :          0 :                 return -1;
      44                 :            :         }
      45                 :            : 
      46                 :          0 :         *msg = criu_req__unpack(NULL, len, buf);
      47         [ #  # ]:          0 :         if (!*msg) {
      48                 :          0 :                 pr_perror("Failed unpacking request");
      49                 :          0 :                 return -1;
      50                 :            :         }
      51                 :            : 
      52                 :            :         return 0;
      53                 :            : }
      54                 :            : 
      55                 :          0 : static int send_criu_msg(int socket_fd, CriuResp *msg)
      56                 :            : {
      57                 :            :         unsigned char buf[CR_MAX_MSG_SIZE];
      58                 :            :         int len;
      59                 :            : 
      60                 :          0 :         len = criu_resp__get_packed_size(msg);
      61                 :            : 
      62         [ #  # ]:          0 :         if (criu_resp__pack(msg, buf) != len) {
      63                 :          0 :                 pr_perror("Failed packing response");
      64                 :          0 :                 return -1;
      65                 :            :         }
      66                 :            : 
      67         [ #  # ]:          0 :         if (write(socket_fd, buf, len)  == -1) {
      68                 :          0 :                 pr_perror("Can't send response");
      69                 :          0 :                 return -1;
      70                 :            :         }
      71                 :            : 
      72                 :            :         return 0;
      73                 :            : }
      74                 :            : 
      75                 :          0 : static void send_criu_err(int sk, char *msg)
      76                 :            : {
      77                 :          0 :         CriuResp resp = CRIU_RESP__INIT;
      78                 :            : 
      79                 :          0 :         pr_perror("RPC error: %s", msg);
      80                 :            : 
      81                 :          0 :         resp.type = CRIU_REQ_TYPE__EMPTY;
      82                 :          0 :         resp.success = false;
      83                 :            :         /* XXX -- add optional error code to CriuResp */
      84                 :            : 
      85                 :          0 :         send_criu_msg(sk, &resp);
      86                 :          0 : }
      87                 :            : 
      88                 :          0 : int send_criu_dump_resp(int socket_fd, bool success, bool restored)
      89                 :            : {
      90                 :          0 :         CriuResp msg = CRIU_RESP__INIT;
      91                 :          0 :         CriuDumpResp resp = CRIU_DUMP_RESP__INIT;
      92                 :            : 
      93                 :          0 :         msg.type = CRIU_REQ_TYPE__DUMP;
      94                 :          0 :         msg.success = success;
      95                 :          0 :         msg.dump = &resp;
      96                 :            : 
      97                 :          0 :         resp.has_restored = true;
      98                 :          0 :         resp.restored = restored;
      99                 :            : 
     100                 :          0 :         return send_criu_msg(socket_fd, &msg);
     101                 :            : }
     102                 :            : 
     103                 :          0 : static int send_criu_pre_dump_resp(int socket_fd, bool success)
     104                 :            : {
     105                 :          0 :         CriuResp msg = CRIU_RESP__INIT;
     106                 :            : 
     107                 :          0 :         msg.type = CRIU_REQ_TYPE__PRE_DUMP;
     108                 :          0 :         msg.success = success;
     109                 :            : 
     110                 :          0 :         return send_criu_msg(socket_fd, &msg);
     111                 :            : }
     112                 :            : 
     113                 :          0 : int send_criu_restore_resp(int socket_fd, bool success, int pid)
     114                 :            : {
     115                 :          0 :         CriuResp msg = CRIU_RESP__INIT;
     116                 :          0 :         CriuRestoreResp resp = CRIU_RESTORE_RESP__INIT;
     117                 :            : 
     118                 :          0 :         msg.type = CRIU_REQ_TYPE__RESTORE;
     119                 :          0 :         msg.success = success;
     120                 :          0 :         msg.restore = &resp;
     121                 :            : 
     122                 :          0 :         resp.pid = pid;
     123                 :            : 
     124                 :          0 :         return send_criu_msg(socket_fd, &msg);
     125                 :            : }
     126                 :            : 
     127                 :          0 : int send_criu_rpc_script(char *script, int fd)
     128                 :            : {
     129                 :            :         int ret;
     130                 :          0 :         CriuResp msg = CRIU_RESP__INIT;
     131                 :            :         CriuReq *req;
     132                 :          0 :         CriuNotify cn = CRIU_NOTIFY__INIT;
     133                 :            : 
     134                 :          0 :         msg.type = CRIU_REQ_TYPE__NOTIFY;
     135                 :          0 :         msg.success = true;
     136                 :          0 :         msg.notify = &cn;
     137                 :          0 :         cn.script = script;
     138                 :            : 
     139         [ #  # ]:          0 :         if (!strcmp(script, "setup-namespaces")) {
     140                 :            :                 /*
     141                 :            :                  * FIXME pid is required only once on
     142                 :            :                  * restore. Need some more sane way of
     143                 :            :                  * checking this.
     144                 :            :                  */
     145                 :          0 :                 cn.has_pid = true;
     146                 :          0 :                 cn.pid = root_item->pid.real;
     147                 :            :         }
     148                 :            : 
     149                 :          0 :         ret = send_criu_msg(fd, &msg);
     150         [ #  # ]:          0 :         if (ret < 0)
     151                 :            :                 return ret;
     152                 :            : 
     153                 :          0 :         ret = recv_criu_msg(fd, &req);
     154         [ #  # ]:          0 :         if (ret < 0)
     155                 :            :                 return ret;
     156                 :            : 
     157 [ #  # ][ #  # ]:          0 :         if (req->type != CRIU_REQ_TYPE__NOTIFY || !req->notify_success) {
     158                 :          0 :                 pr_err("RPC client reported script error\n");
     159                 :          0 :                 return -1;
     160                 :            :         }
     161                 :            : 
     162                 :          0 :         criu_req__free_unpacked(req, NULL);
     163                 :          0 :         return 0;
     164                 :            : }
     165                 :            : 
     166                 :          0 : static int setup_opts_from_req(int sk, CriuOpts *req)
     167                 :            : {
     168                 :            :         struct ucred ids;
     169                 :            :         struct stat st;
     170                 :          0 :         socklen_t ids_len = sizeof(struct ucred);
     171                 :            :         char images_dir_path[PATH_MAX];
     172                 :            :         char work_dir_path[PATH_MAX];
     173                 :            :         int i;
     174                 :            : 
     175         [ #  # ]:          0 :         if (getsockopt(sk, SOL_SOCKET, SO_PEERCRED, &ids, &ids_len)) {
     176                 :          0 :                 pr_perror("Can't get socket options");
     177                 :          0 :                 return -1;
     178                 :            :         }
     179                 :            : 
     180                 :          0 :         restrict_uid(ids.uid, ids.gid);
     181                 :            : 
     182         [ #  # ]:          0 :         if (fstat(sk, &st)) {
     183                 :          0 :                 pr_perror("Can't get socket stat");
     184                 :          0 :                 return -1;
     185                 :            :         }
     186                 :            : 
     187         [ #  # ]:          0 :         BUG_ON(st.st_ino == -1);
     188                 :          0 :         service_sk_ino = st.st_ino;
     189                 :            : 
     190                 :            :         /* open images_dir */
     191                 :          0 :         sprintf(images_dir_path, "/proc/%d/fd/%d", ids.pid, req->images_dir_fd);
     192                 :            : 
     193         [ #  # ]:          0 :         if (req->parent_img)
     194                 :          0 :                 opts.img_parent = req->parent_img;
     195                 :            : 
     196         [ #  # ]:          0 :         if (open_image_dir(images_dir_path) < 0) {
     197                 :          0 :                 pr_perror("Can't open images directory");
     198                 :          0 :                 return -1;
     199                 :            :         }
     200                 :            : 
     201                 :            :         /* chdir to work dir */
     202         [ #  # ]:          0 :         if (req->has_work_dir_fd)
     203                 :          0 :                 sprintf(work_dir_path, "/proc/%d/fd/%d", ids.pid, req->work_dir_fd);
     204                 :            :         else
     205                 :            :                 strcpy(work_dir_path, images_dir_path);
     206                 :            : 
     207         [ #  # ]:          0 :         if (chdir(work_dir_path)) {
     208                 :          0 :                 pr_perror("Can't chdir to work_dir");
     209                 :          0 :                 return -1;
     210                 :            :         }
     211                 :            : 
     212                 :            :         /* initiate log file in work dir */
     213         [ #  # ]:          0 :         if (req->log_file) {
     214         [ #  # ]:          0 :                 if (strchr(req->log_file, '/')) {
     215                 :          0 :                         pr_perror("No subdirs are allowed in log_file name");
     216                 :          0 :                         return -1;
     217                 :            :                 }
     218                 :            : 
     219                 :          0 :                 opts.output = req->log_file;
     220                 :            :         } else
     221                 :          0 :                 opts.output = DEFAULT_LOG_FILENAME;
     222                 :            : 
     223                 :          0 :         log_set_loglevel(req->log_level);
     224         [ #  # ]:          0 :         if (log_init(opts.output) == -1) {
     225                 :          0 :                 pr_perror("Can't initiate log");
     226                 :          0 :                 return -1;
     227                 :            :         }
     228                 :            : 
     229                 :            :         /* checking flags from client */
     230 [ #  # ][ #  # ]:          0 :         if (req->has_leave_running && req->leave_running)
     231                 :          0 :                 opts.final_state = TASK_ALIVE;
     232                 :            : 
     233         [ #  # ]:          0 :         if (!req->has_pid) {
     234                 :          0 :                 req->has_pid = true;
     235                 :          0 :                 req->pid = ids.pid;
     236                 :            :         }
     237                 :            : 
     238         [ #  # ]:          0 :         if (req->has_ext_unix_sk)
     239                 :          0 :                 opts.ext_unix_sk = req->ext_unix_sk;
     240                 :            : 
     241         [ #  # ]:          0 :         if (req->root)
     242                 :          0 :                 opts.root = req->root;
     243                 :            : 
     244         [ #  # ]:          0 :         if (req->has_tcp_established)
     245                 :          0 :                 opts.tcp_established_ok = req->tcp_established;
     246                 :            : 
     247         [ #  # ]:          0 :         if (req->has_evasive_devices)
     248                 :          0 :                 opts.evasive_devices = req->evasive_devices;
     249                 :            : 
     250         [ #  # ]:          0 :         if (req->has_shell_job)
     251                 :          0 :                 opts.shell_job = req->shell_job;
     252                 :            : 
     253         [ #  # ]:          0 :         if (req->has_file_locks)
     254                 :          0 :                 opts.handle_file_locks = req->file_locks;
     255                 :            : 
     256         [ #  # ]:          0 :         if (req->has_track_mem)
     257                 :          0 :                 opts.track_mem = req->track_mem;
     258                 :            : 
     259         [ #  # ]:          0 :         if (req->has_link_remap)
     260                 :          0 :                 opts.link_remap_ok = req->link_remap;
     261                 :            : 
     262         [ #  # ]:          0 :         if (req->has_auto_dedup)
     263                 :          0 :                 opts.auto_dedup = req->auto_dedup;
     264                 :            : 
     265         [ #  # ]:          0 :         if (req->has_force_irmap)
     266                 :          0 :                 opts.force_irmap = req->force_irmap;
     267                 :            : 
     268         [ #  # ]:          0 :         if (req->n_exec_cmd > 0) {
     269         [ #  # ]:          0 :                 opts.exec_cmd = xmalloc((req->n_exec_cmd + 1) * sizeof(char *));
     270                 :          0 :                 memcpy(opts.exec_cmd, req->exec_cmd, req->n_exec_cmd * sizeof(char *));
     271                 :          0 :                 opts.exec_cmd[req->n_exec_cmd] = NULL;
     272                 :            :         }
     273                 :            : 
     274         [ #  # ]:          0 :         if (req->ps) {
     275                 :          0 :                 opts.use_page_server = true;
     276                 :          0 :                 opts.addr = req->ps->address;
     277         [ #  # ]:          0 :                 opts.ps_port = htons((short)req->ps->port);
     278                 :            :         }
     279                 :            : 
     280         [ #  # ]:          0 :         if (req->notify_scripts) {
     281                 :            :                 struct script *script;
     282                 :            : 
     283         [ #  # ]:          0 :                 script = xmalloc(sizeof(struct script));
     284         [ #  # ]:          0 :                 if (script == NULL)
     285                 :            :                         return -1;
     286                 :            : 
     287                 :          0 :                 script->path = SCRIPT_RPC_NOTIFY;
     288                 :          0 :                 script->arg = sk;
     289                 :          0 :                 list_add(&script->node, &opts.scripts);
     290                 :            :         }
     291                 :            : 
     292         [ #  # ]:          0 :         for (i = 0; i < req->n_veths; i++) {
     293         [ #  # ]:          0 :                 if (veth_pair_add(req->veths[i]->if_in, req->veths[i]->if_out))
     294                 :            :                         return -1;
     295                 :            :         }
     296                 :            : 
     297         [ #  # ]:          0 :         if (req->has_cpu_cap)
     298                 :          0 :                 opts.cpu_cap = req->cpu_cap;
     299                 :            : 
     300                 :            :         return 0;
     301                 :            : }
     302                 :            : 
     303                 :          0 : static int dump_using_req(int sk, CriuOpts *req)
     304                 :            : {
     305                 :            :         bool success = false;
     306                 :          0 :         bool self_dump = !req->pid;
     307                 :            : 
     308         [ #  # ]:          0 :         if (setup_opts_from_req(sk, req))
     309                 :            :                 goto exit;
     310                 :            : 
     311                 :            :         /*
     312                 :            :          * FIXME -- cr_dump_tasks() may return code from custom
     313                 :            :          * scripts, that can be positive. However, right now we
     314                 :            :          * don't have ability to push scripts via RPC, so psitive
     315                 :            :          * ret values are impossible here.
     316                 :            :          */
     317         [ #  # ]:          0 :         if (cr_dump_tasks(req->pid))
     318                 :            :                 goto exit;
     319                 :            : 
     320                 :            :         success = true;
     321                 :            : exit:
     322 [ #  # ][ #  # ]:          0 :         if (req->leave_running  || !self_dump || !success) {
     323         [ #  # ]:          0 :                 if (send_criu_dump_resp(sk, success, false) == -1) {
     324                 :          0 :                         pr_perror("Can't send response");
     325                 :            :                         success = false;
     326                 :            :                 }
     327                 :            :         }
     328                 :            : 
     329         [ #  # ]:          0 :         return success ? 0 : 1;
     330                 :            : }
     331                 :            : 
     332                 :          0 : static int restore_using_req(int sk, CriuOpts *req)
     333                 :            : {
     334                 :            :         bool success = false;
     335                 :            : 
     336                 :            :         /*
     337                 :            :          * We can't restore processes under arbitrary task yet.
     338                 :            :          * Thus for now we force the detached restore under the
     339                 :            :          * cr service task.
     340                 :            :          */
     341                 :            : 
     342                 :          0 :         opts.restore_detach = true;
     343                 :            : 
     344         [ #  # ]:          0 :         if (setup_opts_from_req(sk, req))
     345                 :            :                 goto exit;
     346                 :            : 
     347         [ #  # ]:          0 :         if (cr_restore_tasks())
     348                 :            :                 goto exit;
     349                 :            : 
     350                 :            :         success = true;
     351                 :            : exit:
     352 [ #  # ][ #  # ]:          0 :         if (send_criu_restore_resp(sk, success,
     353                 :          0 :                                    root_item ? root_item->pid.real : -1) == -1) {
     354                 :          0 :                 pr_perror("Can't send response");
     355                 :            :                 success = false;
     356                 :            :         }
     357                 :            : 
     358 [ #  # ][ #  # ]:          0 :         if (success && opts.exec_cmd) {
     359                 :            :                 int logfd;
     360                 :            : 
     361                 :          0 :                 logfd = log_get_fd();
     362 [ #  # ][ #  # ]:          0 :                 if (dup2(logfd, STDOUT_FILENO) == -1 || dup2(logfd, STDERR_FILENO) == -1) {
     363                 :          0 :                         pr_perror("Failed to redirect stdout and stderr to the logfile");
     364                 :          0 :                         return 1;
     365                 :            :                 }
     366                 :            : 
     367                 :          0 :                 close_pid_proc();
     368                 :          0 :                 close(sk);
     369                 :            : 
     370                 :          0 :                 execvp(opts.exec_cmd[0], opts.exec_cmd);
     371                 :          0 :                 pr_perror("Failed to exec cmd %s", opts.exec_cmd[0]);
     372                 :            :                 success = false;
     373                 :            :         }
     374                 :            : 
     375         [ #  # ]:          0 :         return success ? 0 : 1;
     376                 :            : }
     377                 :            : 
     378                 :          0 : static int check(int sk)
     379                 :            : {
     380                 :          0 :         CriuResp resp = CRIU_RESP__INIT;
     381                 :            : 
     382                 :          0 :         resp.type = CRIU_REQ_TYPE__CHECK;
     383                 :            : 
     384                 :            :         /* Check only minimal kernel support */
     385                 :          0 :         opts.check_ms_kernel = true;
     386                 :            : 
     387         [ #  # ]:          0 :         if (!cr_check())
     388                 :          0 :                 resp.success = true;
     389                 :            : 
     390                 :          0 :         return send_criu_msg(sk, &resp);
     391                 :            : }
     392                 :            : 
     393                 :          0 : static int pre_dump_using_req(int sk, CriuOpts *req)
     394                 :            : {
     395                 :            :         int pid, status;
     396                 :            :         bool success = false;
     397                 :            : 
     398                 :          0 :         pid = fork();
     399         [ #  # ]:          0 :         if (pid < 0) {
     400                 :          0 :                 pr_perror("Can't fork");
     401                 :          0 :                 goto out;
     402                 :            :         }
     403                 :            : 
     404         [ #  # ]:          0 :         if (pid == 0) {
     405                 :            :                 int ret = 1;
     406                 :            : 
     407         [ #  # ]:          0 :                 if (setup_opts_from_req(sk, req))
     408                 :            :                         goto cout;
     409                 :            : 
     410         [ #  # ]:          0 :                 if (cr_pre_dump_tasks(req->pid))
     411                 :            :                         goto cout;
     412                 :            : 
     413                 :            :                 ret = 0;
     414                 :            : cout:
     415                 :          0 :                 exit(ret);
     416                 :            :         }
     417                 :            : 
     418                 :          0 :         wait(&status);
     419         [ #  # ]:          0 :         if (!WIFEXITED(status))
     420                 :            :                 goto out;
     421         [ #  # ]:          0 :         if (WEXITSTATUS(status) != 0)
     422                 :            :                 goto out;
     423                 :            : 
     424                 :            :         success = true;
     425                 :            : out:
     426         [ #  # ]:          0 :         if (send_criu_pre_dump_resp(sk, success) == -1) {
     427                 :          0 :                 pr_perror("Can't send pre-dump resp");
     428                 :            :                 success = false;
     429                 :            :         }
     430                 :            : 
     431         [ #  # ]:          0 :         return success ? 0 : -1;
     432                 :            : }
     433                 :            : 
     434                 :          0 : static int pre_dump_loop(int sk, CriuReq *msg)
     435                 :            : {
     436                 :            :         int ret;
     437                 :            : 
     438                 :            :         do {
     439                 :          0 :                 ret = pre_dump_using_req(sk, msg->opts);
     440         [ #  # ]:          0 :                 if (ret < 0)
     441                 :            :                         return ret;
     442                 :            : 
     443                 :          0 :                 criu_req__free_unpacked(msg, NULL);
     444         [ #  # ]:          0 :                 if (recv_criu_msg(sk, &msg) == -1) {
     445                 :          0 :                         pr_perror("Can't recv request");
     446                 :          0 :                         return -1;
     447                 :            :                 }
     448         [ #  # ]:          0 :         } while (msg->type == CRIU_REQ_TYPE__PRE_DUMP);
     449                 :            : 
     450         [ #  # ]:          0 :         if (msg->type != CRIU_REQ_TYPE__DUMP) {
     451                 :          0 :                 send_criu_err(sk, "Bad req seq");
     452                 :          0 :                 return -1;
     453                 :            :         }
     454                 :            : 
     455                 :          0 :         return dump_using_req(sk, msg->opts);
     456                 :            : }
     457                 :            : 
     458                 :          0 : static int start_page_server_req(int sk, CriuOpts *req)
     459                 :            : {
     460                 :            :         int ret;
     461                 :            :         bool success = false;
     462                 :          0 :         CriuResp resp = CRIU_RESP__INIT;
     463                 :          0 :         CriuPageServerInfo ps = CRIU_PAGE_SERVER_INFO__INIT;
     464                 :            : 
     465         [ #  # ]:          0 :         if (!req->ps) {
     466                 :          0 :                 pr_err("No page server info in message\n");
     467                 :          0 :                 goto out;
     468                 :            :         }
     469                 :            : 
     470         [ #  # ]:          0 :         if (setup_opts_from_req(sk, req))
     471                 :            :                 goto out;
     472                 :            : 
     473                 :          0 :         pr_debug("Starting page server\n");
     474                 :            : 
     475                 :          0 :         ret = cr_page_server(true);
     476         [ #  # ]:          0 :         if (ret > 0) {
     477                 :            :                 success = true;
     478                 :          0 :                 ps.has_pid = true;
     479                 :          0 :                 ps.pid = ret;
     480                 :          0 :                 resp.ps = &ps;
     481                 :            :         }
     482                 :            : 
     483                 :          0 :         pr_debug("Page server started\n");
     484                 :            : out:
     485                 :          0 :         resp.type = CRIU_REQ_TYPE__PAGE_SERVER;
     486                 :          0 :         resp.success = success;
     487                 :          0 :         return send_criu_msg(sk, &resp);
     488                 :            : }
     489                 :            : 
     490                 :          0 : static int cr_service_work(int sk)
     491                 :            : {
     492                 :          0 :         CriuReq *msg = 0;
     493                 :            : 
     494                 :          0 :         init_opts();
     495                 :            : 
     496         [ #  # ]:          0 :         if (recv_criu_msg(sk, &msg) == -1) {
     497                 :          0 :                 pr_perror("Can't recv request");
     498                 :          0 :                 goto err;
     499                 :            :         }
     500                 :            : 
     501   [ #  #  #  #  :          0 :         switch (msg->type) {
                   #  # ]
     502                 :            :         case CRIU_REQ_TYPE__DUMP:
     503                 :          0 :                 return dump_using_req(sk, msg->opts);
     504                 :            :         case CRIU_REQ_TYPE__RESTORE:
     505                 :          0 :                 return restore_using_req(sk, msg->opts);
     506                 :            :         case CRIU_REQ_TYPE__CHECK:
     507                 :          0 :                 return check(sk);
     508                 :            :         case CRIU_REQ_TYPE__PRE_DUMP:
     509                 :          0 :                 return pre_dump_loop(sk, msg);
     510                 :            :         case CRIU_REQ_TYPE__PAGE_SERVER:
     511                 :          0 :                 return start_page_server_req(sk, msg->opts);
     512                 :            : 
     513                 :            :         default:
     514                 :          0 :                 send_criu_err(sk, "Invalid req");
     515                 :          0 :                 goto err;
     516                 :            :         }
     517                 :            : 
     518                 :            : err:
     519                 :            :         return -1;
     520                 :            : }
     521                 :            : 
     522                 :          0 : static void reap_worker(int signo)
     523                 :            : {
     524                 :            :         int saved_errno;
     525                 :            :         int status;
     526                 :            :         pid_t pid;
     527                 :            : 
     528                 :          0 :         saved_errno = errno;
     529                 :            : 
     530                 :            :         /*
     531                 :            :          * As we block SIGCHLD, lets wait for every child that has
     532                 :            :          * already changed state.
     533                 :            :          */
     534                 :            :         while (1) {
     535                 :          0 :                 pid = waitpid(-1, &status, WNOHANG);
     536                 :            : 
     537         [ #  # ]:          0 :                 if (pid <= 0) {
     538                 :          0 :                         errno = saved_errno;
     539                 :          0 :                         return;
     540                 :            :                 }
     541                 :            : 
     542         [ #  # ]:          0 :                 if (WIFEXITED(status))
     543                 :          0 :                         pr_info("Worker(pid %d) exited with %d\n",
     544                 :            :                                 pid, WEXITSTATUS(status));
     545         [ #  # ]:          0 :                 else if (WIFSIGNALED(status))
     546                 :          0 :                         pr_info("Worker(pid %d) was killed by %d\n",
     547                 :            :                                 pid, WTERMSIG(status));
     548                 :            :         }
     549                 :            : }
     550                 :            : 
     551                 :          0 : static int setup_sigchld_handler()
     552                 :            : {
     553                 :            :         struct sigaction action;
     554                 :            : 
     555                 :          0 :         sigemptyset(&action.sa_mask);
     556                 :          0 :         sigaddset(&action.sa_mask, SIGCHLD);
     557                 :          0 :         action.sa_handler       = reap_worker;
     558                 :          0 :         action.sa_flags         = SA_RESTART;
     559                 :            : 
     560         [ #  # ]:          0 :         if (sigaction(SIGCHLD, &action, NULL)) {
     561                 :          0 :                 pr_perror("Can't setup SIGCHLD handler");
     562                 :          0 :                 return -1;
     563                 :            :         }
     564                 :            : 
     565                 :            :         return 0;
     566                 :            : }
     567                 :            : 
     568                 :          0 : static int restore_sigchld_handler()
     569                 :            : {
     570                 :            :         struct sigaction action;
     571                 :            : 
     572                 :          0 :         sigemptyset(&action.sa_mask);
     573                 :          0 :         sigaddset(&action.sa_mask, SIGCHLD);
     574                 :          0 :         action.sa_handler       = SIG_DFL;
     575                 :          0 :         action.sa_flags         = SA_RESTART;
     576                 :            : 
     577         [ #  # ]:          0 :         if (sigaction(SIGCHLD, &action, NULL)) {
     578                 :          0 :                 pr_perror("Can't restore SIGCHLD handler");
     579                 :          0 :                 return -1;
     580                 :            :         }
     581                 :            : 
     582                 :            :         return 0;
     583                 :            : }
     584                 :            : 
     585                 :          0 : int cr_service(bool daemon_mode)
     586                 :            : {
     587                 :          0 :         int server_fd = -1, n;
     588                 :            :         int child_pid;
     589                 :            : 
     590                 :            :         struct sockaddr_un client_addr;
     591                 :            :         socklen_t client_addr_len;
     592                 :            : 
     593                 :          0 :         n = sd_listen_fds(0);
     594         [ #  # ]:          0 :         if (n > 1) {
     595                 :          0 :                 pr_err("Too many file descriptors (%d) recieved", n);
     596                 :          0 :                 goto err;
     597         [ #  # ]:          0 :         } else if (n == 1)
     598                 :          0 :                 server_fd = SD_LISTEN_FDS_START + 0;
     599                 :            :         else {
     600                 :            :                 struct sockaddr_un server_addr;
     601                 :            :                 socklen_t server_addr_len;
     602                 :            : 
     603                 :          0 :                 server_fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
     604         [ #  # ]:          0 :                 if (server_fd == -1) {
     605                 :          0 :                         pr_perror("Can't initialize service socket");
     606                 :          0 :                         goto err;
     607                 :            :                 }
     608                 :            : 
     609                 :            :                 memset(&server_addr, 0, sizeof(server_addr));
     610                 :            :                 memset(&client_addr, 0, sizeof(client_addr));
     611                 :          0 :                 server_addr.sun_family = AF_LOCAL;
     612                 :            : 
     613         [ #  # ]:          0 :                 if (opts.addr == NULL)
     614                 :          0 :                         opts.addr = CR_DEFAULT_SERVICE_ADDRESS;
     615                 :            : 
     616                 :          0 :                 strcpy(server_addr.sun_path, opts.addr);
     617                 :            : 
     618                 :          0 :                 server_addr_len = strlen(server_addr.sun_path)
     619                 :            :                                 + sizeof(server_addr.sun_family);
     620                 :          0 :                 client_addr_len = sizeof(client_addr);
     621                 :            : 
     622                 :          0 :                 unlink(server_addr.sun_path);
     623                 :            : 
     624         [ #  # ]:          0 :                 if (bind(server_fd, (struct sockaddr *) &server_addr,
     625                 :            :                                                 server_addr_len) == -1) {
     626                 :          0 :                         pr_perror("Can't bind");
     627                 :          0 :                         goto err;
     628                 :            :                 }
     629                 :            : 
     630                 :          0 :                 pr_info("The service socket is bound to %s\n", server_addr.sun_path);
     631                 :            : 
     632                 :            :                 /* change service socket permissions, so anyone can connect to it */
     633         [ #  # ]:          0 :                 if (chmod(server_addr.sun_path, 0666)) {
     634                 :          0 :                         pr_perror("Can't change permissions of the service socket");
     635                 :          0 :                         goto err;
     636                 :            :                 }
     637                 :            : 
     638         [ #  # ]:          0 :                 if (listen(server_fd, 16) == -1) {
     639                 :          0 :                         pr_perror("Can't listen for socket connections");
     640                 :          0 :                         goto err;
     641                 :            :                 }
     642                 :            :         }
     643                 :            : 
     644         [ #  # ]:          0 :         if (daemon_mode) {
     645         [ #  # ]:          0 :                 if (daemon(1, 0) == -1) {
     646                 :          0 :                         pr_perror("Can't run service server in the background");
     647                 :          0 :                         goto err;
     648                 :            :                 }
     649                 :            :         }
     650                 :            : 
     651         [ #  # ]:          0 :         if (opts.pidfile) {
     652         [ #  # ]:          0 :                 if (write_pidfile(getpid()) == -1) {
     653                 :          0 :                         pr_perror("Can't write pidfile");
     654                 :          0 :                         goto err;
     655                 :            :                 }
     656                 :            :         }
     657                 :            : 
     658         [ #  # ]:          0 :         if (setup_sigchld_handler())
     659                 :            :                 goto err;
     660                 :            : 
     661                 :            :         while (1) {
     662                 :            :                 int sk;
     663                 :            : 
     664                 :          0 :                 pr_info("Waiting for connection...\n");
     665                 :            : 
     666                 :          0 :                 sk = accept(server_fd, &client_addr, &client_addr_len);
     667         [ #  # ]:          0 :                 if (sk == -1) {
     668                 :          0 :                         pr_perror("Can't accept connection");
     669                 :          0 :                         goto err;
     670                 :            :                 }
     671                 :            : 
     672                 :          0 :                 pr_info("Connected.\n");
     673                 :          0 :                 child_pid = fork();
     674         [ #  # ]:          0 :                 if (child_pid == 0) {
     675                 :            :                         int ret;
     676                 :            : 
     677         [ #  # ]:          0 :                         if (restore_sigchld_handler())
     678                 :          0 :                                 exit(1);
     679                 :            : 
     680                 :          0 :                         close(server_fd);
     681                 :          0 :                         ret = cr_service_work(sk);
     682                 :          0 :                         close(sk);
     683                 :          0 :                         exit(ret != 0);
     684                 :            :                 }
     685                 :            : 
     686         [ #  # ]:          0 :                 if (child_pid < 0)
     687                 :          0 :                         pr_perror("Can't fork a child");
     688                 :            : 
     689                 :          0 :                 close(sk);
     690                 :          0 :         }
     691                 :            : 
     692                 :            : err:
     693                 :          0 :         close_safe(&server_fd);
     694                 :            : 
     695                 :          0 :         return 1;
     696                 :            : }

Generated by: LCOV version 1.9